浏览代码

wxGUI: initial vector legend support, currently needs d.legend.vect addon, author Adam Laza

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@69085 15284696-431f-4ddb-bdfa-cd5b030d7da7
Anna Petrášová 8 年之前
父节点
当前提交
d29112fd12

+ 9 - 3
display/d.mon/render_cmd.py

@@ -8,7 +8,7 @@ from grass.script import task as gtask
 
 
 # read environment variables from file
 # read environment variables from file
 def read_env_file(env_file):
 def read_env_file(env_file):
-    width = height = None
+    width = height = legfile = None
     fd = open(env_file, 'r')
     fd = open(env_file, 'r')
     if fd is None:
     if fd is None:
         grass.fatal("Unable to open file '{}'".format(env_file))
         grass.fatal("Unable to open file '{}'".format(env_file))
@@ -22,16 +22,19 @@ def read_env_file(env_file):
             width = int(v)
             width = int(v)
         if height is None and k == 'GRASS_RENDER_HEIGHT':
         if height is None and k == 'GRASS_RENDER_HEIGHT':
             height = int(v)
             height = int(v)
+        if legfile is None and k == 'GRASS_LEGEND_FILE':
+            legfile = v
     fd.close()
     fd.close()
 
 
     if width is None or height is None:
     if width is None or height is None:
         grass.fatal("Unknown monitor size")
         grass.fatal("Unknown monitor size")
 
 
-    return width, height
+    return width, height, legfile
 
 
 # run display command
 # run display command
 def render(cmd, mapfile):
 def render(cmd, mapfile):
     env = os.environ.copy()
     env = os.environ.copy()
+
     if mapfile:
     if mapfile:
         env['GRASS_RENDER_FILE'] = mapfile
         env['GRASS_RENDER_FILE'] = mapfile
     try:
     try:
@@ -101,7 +104,7 @@ if __name__ == "__main__":
     path = os.path.dirname(os.path.abspath(__file__))
     path = os.path.dirname(os.path.abspath(__file__))
     mon = os.path.split(path)[-1]
     mon = os.path.split(path)[-1]
 
 
-    width, height = read_env_file(os.path.join(path, 'env'))
+    width, height, legfile = read_env_file(os.path.join(path, 'env'))
     if mon.startswith('wx'):
     if mon.startswith('wx'):
         mapfile = tempfile.NamedTemporaryFile(dir=path).name
         mapfile = tempfile.NamedTemporaryFile(dir=path).name
         if cmd[0] in ('d.barscale', 'd.legend', 'd.northarrow'):
         if cmd[0] in ('d.barscale', 'd.legend', 'd.northarrow'):
@@ -114,5 +117,8 @@ if __name__ == "__main__":
 
 
     render(cmd, mapfile)
     render(cmd, mapfile)
     update_cmd_file(os.path.join(path, 'cmd'), cmd, mapfile)
     update_cmd_file(os.path.join(path, 'cmd'), cmd, mapfile)
+    if cmd[0] == 'd.erase':
+        os.remove(legfile)
+
 
 
     sys.exit(0)
     sys.exit(0)

+ 7 - 1
display/d.mon/start.c

@@ -133,7 +133,7 @@ int start_mon(const char *name, const char *output, int select,
 	      int truecolor, int x_only, int update)
 	      int truecolor, int x_only, int update)
 {
 {
     char *mon_path;
     char *mon_path;
-    char *out_file, *env_file, *cmd_file;
+    char *out_file, *env_file, *cmd_file, *leg_file;
     char  buf[1024];
     char  buf[1024];
     char file_path[GPATH_MAX], render_cmd_path[GPATH_MAX];
     char file_path[GPATH_MAX], render_cmd_path[GPATH_MAX];
     int  fd;
     int  fd;
@@ -158,6 +158,8 @@ int start_mon(const char *name, const char *output, int select,
     env_file = G_store(file_path);
     env_file = G_store(file_path);
     G_file_name(file_path, mon_path, "cmd", G_mapset());
     G_file_name(file_path, mon_path, "cmd", G_mapset());
     cmd_file = G_store(file_path);
     cmd_file = G_store(file_path);
+    G_file_name(file_path, mon_path, "leg", G_mapset());
+    leg_file = G_store(file_path);
 
 
     /* create py file (renderer) */
     /* create py file (renderer) */
     sprintf(render_cmd_path, "%s/etc/d.mon/render_cmd.py", getenv("GISBASE"));
     sprintf(render_cmd_path, "%s/etc/d.mon/render_cmd.py", getenv("GISBASE"));
@@ -199,6 +201,10 @@ int start_mon(const char *name, const char *output, int select,
     write(fd, buf, strlen(buf));
     write(fd, buf, strlen(buf));
     sprintf(buf, "GRASS_RENDER_HEIGHT=%d\n", height);
     sprintf(buf, "GRASS_RENDER_HEIGHT=%d\n", height);
     write(fd, buf, strlen(buf));
     write(fd, buf, strlen(buf));
+    sprintf(buf, "GRASS_LEGEND_FILE=%s\n", leg_file);
+    write(fd, buf, strlen(buf));
+
+
     if (bgcolor) {
     if (bgcolor) {
 	if (strcmp(bgcolor, "none") == 0)
 	if (strcmp(bgcolor, "none") == 0)
 	    sprintf(buf, "GRASS_RENDER_TRANSPARENT=TRUE\n");
 	    sprintf(buf, "GRASS_RENDER_TRANSPARENT=TRUE\n");

+ 112 - 0
display/d.vect/main.c

@@ -4,6 +4,7 @@
  * MODULE:       d.vect
  * MODULE:       d.vect
  * AUTHOR(S):    CERL, Radim Blazek, others
  * AUTHOR(S):    CERL, Radim Blazek, others
  *               Updated to GRASS7 by Martin Landa <landa.martin gmail.com>
  *               Updated to GRASS7 by Martin Landa <landa.martin gmail.com>
+ *               Support for vector legend by Adam Laza <ad.laza32 gmail.com >
  * PURPOSE:      Display the vector map in map display
  * PURPOSE:      Display the vector map in map display
  * COPYRIGHT:    (C) 2004-2014 by the GRASS Development Team
  * COPYRIGHT:    (C) 2004-2014 by the GRASS Development Team
  *
  *
@@ -52,8 +53,11 @@ int main(int argc, char **argv)
     struct Option *lsize_opt, *font_opt, *enc_opt, *xref_opt, *yref_opt;
     struct Option *lsize_opt, *font_opt, *enc_opt, *xref_opt, *yref_opt;
     struct Option *attrcol_opt, *maxreg_opt, *minreg_opt;
     struct Option *attrcol_opt, *maxreg_opt, *minreg_opt;
     struct Option *width_opt, *wcolumn_opt, *wscale_opt;
     struct Option *width_opt, *wcolumn_opt, *wscale_opt;
+    struct Option *leglab_opt;
+    struct Option *icon_line_opt, *icon_area_opt;
     struct Flag *id_flag, *cats_acolors_flag, *sqrt_flag;
     struct Flag *id_flag, *cats_acolors_flag, *sqrt_flag;
     char *desc;
     char *desc;
+    char *leg_file;
     
     
     struct cat_list *Clist;
     struct cat_list *Clist;
     LATTR lattr;
     LATTR lattr;
@@ -61,6 +65,9 @@ int main(int argc, char **argv)
     struct Cell_head window;
     struct Cell_head window;
     struct bound_box box;
     struct bound_box box;
     double overlap;
     double overlap;
+    int gv_point, gv_line, gv_boundary, gv_centroid;
+
+    FILE *fd;
 
 
     stat = 0;
     stat = 0;
     /* Initialize the GIS calls */
     /* Initialize the GIS calls */
@@ -189,6 +196,32 @@ int main(int argc, char **argv)
     rotcolumn_opt->description =
     rotcolumn_opt->description =
 	_("Measured in degrees CCW from east");
 	_("Measured in degrees CCW from east");
 
 
+    icon_area_opt = G_define_option();
+    icon_area_opt->key = "icon_area";
+    icon_area_opt->type = TYPE_STRING;
+    icon_area_opt->required = NO;
+    icon_area_opt->multiple = NO;
+    icon_area_opt->guisection = _("Legend");
+    icon_area_opt->answer = "legend/area";
+    icon_area_opt->options = icon_files();
+    icon_area_opt->description = _("Area/boundary symbol for legend");
+
+    icon_line_opt = G_define_option();
+    icon_line_opt->key = "icon_line";
+    icon_line_opt->type = TYPE_STRING;
+    icon_line_opt->required = NO;
+    icon_line_opt->multiple = NO;
+    icon_line_opt->guisection = _("Legend");
+    icon_line_opt->answer = "legend/line";
+    icon_line_opt->options = icon_files();
+    icon_line_opt->description = _("Line symbol for legend");
+
+    leglab_opt = G_define_option();
+    leglab_opt->key = "legend_label";
+    leglab_opt->type = TYPE_STRING;
+    leglab_opt->guisection = _("Legend");
+    leglab_opt->description = _("Label to display after symbol in vector legend");
+
     /* Labels */
     /* Labels */
     lfield_opt = G_define_standard_option(G_OPT_V_FIELD);
     lfield_opt = G_define_standard_option(G_OPT_V_FIELD);
     lfield_opt->key = "label_layer";
     lfield_opt->key = "label_layer";
@@ -424,6 +457,85 @@ int main(int argc, char **argv)
 		stat += display_dir(&Map, type, Clist, chcat, size);
 		stat += display_dir(&Map, type, Clist, chcat, size);
 	}
 	}
 
 
+        /* Write into legend file */
+        leg_file = getenv("GRASS_LEGEND_FILE");
+        if (leg_file) {
+            fd = fopen(leg_file, "a");
+            
+            /* Point */
+            if (strstr(type_opt->answer, "point") != NULL){
+                gv_point = Vect_get_num_primitives(&Map, GV_POINT);
+                if (gv_point > 0) {
+                    if (leglab_opt->answer)
+                        fprintf(fd, "%s|", leglab_opt->answer);
+                    else {
+                        char map[128];
+                        char *ptr;
+                        strcpy(map, map_opt->answer);
+                        strtok_r(map, "@", &ptr);
+                        fprintf(fd, "%s|", map);
+                    }
+                    fprintf(fd, "%s|%s|%s|%s|%s", icon_opt->answer, size_opt->answer, color_opt->answer, fcolor_opt->answer, width_opt->answer);
+                    fprintf(fd, "|%s|%d\n", "point", gv_point);
+                }
+            }
+            
+            /* Line */
+            if (strstr(type_opt->answer, "line") != NULL){
+                gv_line = Vect_get_num_primitives(&Map, GV_LINE);
+                if (gv_line > 0){
+                    if (leglab_opt->answer)
+                        fprintf(fd, "%s|", leglab_opt->answer);
+                    else {
+                        char map[128];
+                        char *ptr;
+                        strcpy(map, map_opt->answer);
+                        strtok_r(map, "@", &ptr);
+                        fprintf(fd, "%s|", map);
+                    }
+                    fprintf(fd, "%s|%s|%s|%s|%s", icon_line_opt->answer, size_opt->answer, color_opt->answer, fcolor_opt->answer, width_opt->answer);
+                    fprintf(fd, "|%s|%d\n", "line", gv_line);
+                }
+            }
+            
+            /* Area */
+            if (strstr(type_opt->answer, "area") != NULL){
+                gv_boundary = Vect_get_num_primitives(&Map, GV_BOUNDARY);
+                if (gv_boundary > 0) {
+                    if (leglab_opt->answer)
+                        fprintf(fd, "%s|", leglab_opt->answer);
+                    else {
+                        char map[128];
+                        char *ptr;
+                        strcpy(map, map_opt->answer);
+                        strtok_r(map, "@", &ptr);
+                        fprintf(fd, "%s|", map);
+                    }
+                    fprintf(fd, "%s|%s|%s|%s|%s", icon_area_opt->answer, size_opt->answer, color_opt->answer, fcolor_opt->answer, width_opt->answer);
+                    fprintf(fd, "|%s|%d\n", "area", gv_boundary);
+                }
+            }
+            /* Centroid */
+            if (strstr(type_opt->answer, "centroid") != NULL){
+                gv_centroid = Vect_get_num_primitives(&Map, GV_CENTROID);
+                if (gv_centroid > 0) {
+                    if (leglab_opt->answer)
+                        fprintf(fd, "%s|", leglab_opt->answer);
+                    else {
+                        char map[128];
+                        char *ptr;
+                        strcpy(map, map_opt->answer);
+                        strtok_r(map, "@", &ptr);
+                        fprintf(fd, "%s|", map);
+                    }
+                    fprintf(fd, "%s|%s|%s|%s|%s", icon_opt->answer, size_opt->answer, color_opt->answer, fcolor_opt->answer, width_opt->answer);
+                    fprintf(fd, "|%s|%d\n", "centroid", gv_centroid);
+                }
+            }
+            
+            fclose(fd);
+        }
+
 	/* reset line width: Do we need to get line width from display
 	/* reset line width: Do we need to get line width from display
 	 * driver (not implemented)?  It will help restore previous line
 	 * driver (not implemented)?  It will help restore previous line
 	 * width (not just 0) determined by another module (e.g.,
 	 * width (not just 0) determined by another module (e.g.,

+ 1 - 1
gui/images/Makefile

@@ -9,7 +9,7 @@ IMGSRC := $(wildcard *.png)
 IMGDST := $(patsubst %,$(DSTDIR)/%,$(IMGSRC))
 IMGDST := $(patsubst %,$(DSTDIR)/%,$(IMGSRC))
 
 
 # symbols
 # symbols
-CATEGORIES = basic demo extra geology n_arrows
+CATEGORIES = basic demo extra geology legend n_arrows
 SYMSRC := $(foreach dir,$(CATEGORIES),$(wildcard symbols/$(dir)/*.png))
 SYMSRC := $(foreach dir,$(CATEGORIES),$(wildcard symbols/$(dir)/*.png))
 SYMDST := $(patsubst symbols/%,$(DSTDIR)/symbols/%,$(SYMSRC))
 SYMDST := $(patsubst symbols/%,$(DSTDIR)/symbols/%,$(SYMSRC))
 
 

二进制
gui/images/symbols/legend/area.png


二进制
gui/images/symbols/legend/area_curved.png


二进制
gui/images/symbols/legend/line.png


二进制
gui/images/symbols/legend/line_crooked.png


+ 28 - 1
gui/wxpython/core/render.py

@@ -324,6 +324,7 @@ class MapLayer(Layer):
         """Represents map layer in the map canvas
         """Represents map layer in the map canvas
         """
         """
         Layer.__init__(self, *args, **kwargs)
         Layer.__init__(self, *args, **kwargs)
+        self.legrow = grass.tempfile(create=True)
 
 
     def GetMapset(self):
     def GetMapset(self):
         """Get mapset of map layer
         """Get mapset of map layer
@@ -384,6 +385,10 @@ class RenderLayerMgr(wx.EvtHandler):
         env_cmd = env.copy()
         env_cmd = env.copy()
         env_cmd.update(self._render_env)
         env_cmd.update(self._render_env)
         env_cmd['GRASS_RENDER_FILE'] = self.layer.mapfile
         env_cmd['GRASS_RENDER_FILE'] = self.layer.mapfile
+        if type(self.layer).__name__ == "MapLayer":
+            if os.path.isfile(self.layer.legrow):
+                os.remove(self.layer.legrow)
+            env_cmd['GRASS_LEGEND_FILE'] = self.layer.legrow
 
 
         cmd_render = copy.deepcopy(cmd)
         cmd_render = copy.deepcopy(cmd)
         cmd_render[1]['quiet'] = True  # be quiet
         cmd_render[1]['quiet'] = True  # be quiet
@@ -455,7 +460,9 @@ class RenderMapMgr(wx.EvtHandler):
         self._render_env = {"GRASS_RENDER_BACKGROUNDCOLOR": "000000",
         self._render_env = {"GRASS_RENDER_BACKGROUNDCOLOR": "000000",
                             "GRASS_RENDER_FILE_COMPRESSION": "0",
                             "GRASS_RENDER_FILE_COMPRESSION": "0",
                             "GRASS_RENDER_TRUECOLOR": "TRUE",
                             "GRASS_RENDER_TRUECOLOR": "TRUE",
-                            "GRASS_RENDER_TRANSPARENT": "TRUE"}
+                            "GRASS_RENDER_TRANSPARENT": "TRUE",
+                            "GRASS_LEGEND_FILE": self.Map.legfile
+                            }
 
 
         self._init()
         self._init()
         self._rendering = False
         self._rendering = False
@@ -516,6 +523,7 @@ class RenderMapMgr(wx.EvtHandler):
         env['GRASS_REGION'] = self.Map.SetRegion(windres)
         env['GRASS_REGION'] = self.Map.SetRegion(windres)
         env['GRASS_RENDER_WIDTH'] = str(self.Map.width)
         env['GRASS_RENDER_WIDTH'] = str(self.Map.width)
         env['GRASS_RENDER_HEIGHT'] = str(self.Map.height)
         env['GRASS_RENDER_HEIGHT'] = str(self.Map.height)
+
         if UserSettings.Get(group='display', key='driver',
         if UserSettings.Get(group='display', key='driver',
                             subkey='type') == 'png':
                             subkey='type') == 'png':
             env['GRASS_RENDER_IMMEDIATE'] = 'png'
             env['GRASS_RENDER_IMMEDIATE'] = 'png'
@@ -562,6 +570,7 @@ class RenderMapMgr(wx.EvtHandler):
         if self._renderLayers(env, force) == 0:
         if self._renderLayers(env, force) == 0:
             self.renderDone.emit()
             self.renderDone.emit()
 
 
+
     def OnRenderDone(self):
     def OnRenderDone(self):
         """Rendering process done
         """Rendering process done
 
 
@@ -608,6 +617,17 @@ class RenderMapMgr(wx.EvtHandler):
         Debug.msg(1, "RenderMapMgr.OnRenderDone() time=%f sec (comp: %f)" %
         Debug.msg(1, "RenderMapMgr.OnRenderDone() time=%f sec (comp: %f)" %
                   (stop - self._startTime, stop - startCompTime))
                   (stop - self._startTime, stop - startCompTime))
 
 
+        # Update legfile
+        with open(self.Map.legfile, "w") as outfile:
+            for layer in reversed(self.layers):
+                if layer.GetType() == 'overlay':
+                    continue
+
+                if os.path.isfile(layer.legrow) and layer.legrow[-1].isdigit() \
+                   and layer.hidden is False:
+                    with open(layer.legrow) as infile:
+                        outfile.write(infile.read())
+
         self._rendering = False
         self._rendering = False
         if wx.IsBusy():
         if wx.IsBusy():
             wx.EndBusyCursor()
             wx.EndBusyCursor()
@@ -704,8 +724,11 @@ class Map(object):
         self.gisrc = gisrc
         self.gisrc = gisrc
 
 
         # generated file for g.pnmcomp output for rendering the map
         # generated file for g.pnmcomp output for rendering the map
+        self.legfile = grass.tempfile(create=False) + '.leg'
+        self.tmpdir = os.path.dirname(self.legfile)
         self.mapfile = grass.tempfile(create=False) + '.ppm'
         self.mapfile = grass.tempfile(create=False) + '.ppm'
 
 
+
         # setting some initial env. variables
         # setting some initial env. variables
         if not self.GetWindow():
         if not self.GetWindow():
             sys.stderr.write(_("Trying to recover from default region..."))
             sys.stderr.write(_("Trying to recover from default region..."))
@@ -1276,6 +1299,10 @@ class Map(object):
                 basefile = os.path.join(base, tempbase) + r'.*'
                 basefile = os.path.join(base, tempbase) + r'.*'
                 for f in glob.glob(basefile):
                 for f in glob.glob(basefile):
                     os.remove(f)
                     os.remove(f)
+
+            if not overlay:
+                os.remove(layer.legrow)
+
             list.remove(layer)
             list.remove(layer)
 
 
             self.layerRemoved.emit(layer=layer)
             self.layerRemoved.emit(layer=layer)

+ 2 - 1
gui/wxpython/core/utils.py

@@ -1022,7 +1022,8 @@ command2ltype = {'d.rast': 'raster',
                  'd.to.rast': 'torast',
                  'd.to.rast': 'torast',
                  'd.text': 'text',
                  'd.text': 'text',
                  'd.northarrow': 'northarrow',
                  'd.northarrow': 'northarrow',
-                 'd.polar': 'polar'
+                 'd.polar': 'polar',
+                 'd.legend.vect': 'vectleg'
                  }
                  }
 ltype2command = {}
 ltype2command = {}
 for (cmd, ltype) in command2ltype.items():
 for (cmd, ltype) in command2ltype.items():

+ 2 - 2
gui/wxpython/gui_core/forms.py

@@ -873,7 +873,7 @@ class TaskFrame(wx.Frame):
                                           'MapWindow'):
                                           'MapWindow'):
             # display decorations and
             # display decorations and
             # pressing OK or cancel after setting layer properties
             # pressing OK or cancel after setting layer properties
-            if self.task.name in ['d.barscale', 'd.legend', 'd.northarrow', 'd.histogram', 'd.text'] \
+            if self.task.name in ['d.barscale', 'd.legend', 'd.northarrow', 'd.histogram', 'd.text', 'd.legend.vect'] \
                     or len(self.parent.GetLayerInfo(self.layer, key='cmd')) >= 1:
                     or len(self.parent.GetLayerInfo(self.layer, key='cmd')) >= 1:
                 self.Hide()
                 self.Hide()
             # canceled layer with nothing set
             # canceled layer with nothing set
@@ -1230,7 +1230,7 @@ class CmdPanel(wx.Panel):
                         title_txt.SetLabel(title + ':')
                         title_txt.SetLabel(title + ':')
                         value = self._getValue(p)
                         value = self._getValue(p)
 
 
-                        if p['name'] == 'icon':  # symbols
+                        if p['name'] in ('icon', 'icon_area', 'icon_line'):  # symbols
                             bitmap = wx.Bitmap(
                             bitmap = wx.Bitmap(
                                 os.path.join(
                                 os.path.join(
                                     globalvar.SYMBDIR,
                                     globalvar.SYMBDIR,

+ 7 - 0
gui/wxpython/lmgr/frame.py

@@ -757,6 +757,11 @@ class GMFrame(wx.Frame):
                 self.GetMapDisplay().AddLegend(cmd=command)
                 self.GetMapDisplay().AddLegend(cmd=command)
             else:
             else:
                 self.GetMapDisplay().AddLegend()
                 self.GetMapDisplay().AddLegend()
+        elif layertype == 'vectleg':
+            if len(command) > 1:
+                self.GetMapDisplay().AddLegendVect(cmd=command, showDialog=False)
+            else:
+                self.GetMapDisplay().AddLegendVect(showDialog=True)
         elif layertype == 'northarrow':
         elif layertype == 'northarrow':
             if len(command) > 1:
             if len(command) > 1:
                 self.GetMapDisplay().AddArrow(cmd=command)
                 self.GetMapDisplay().AddArrow(cmd=command)
@@ -1485,6 +1490,8 @@ class GMFrame(wx.Frame):
                 # overlay["cmd"][0] name of command e.g. d.barscale, d.legend
                 # overlay["cmd"][0] name of command e.g. d.barscale, d.legend
                 # overlay["cmd"][1:] parameters and flags
                 # overlay["cmd"][1:] parameters and flags
                 if overlay['display'] == i:
                 if overlay['display'] == i:
+                    if overlay['cmd'][0] == "d.legend.vect":
+                        mapdisplay[i].AddLegendVect(overlay['cmd'])
                     if overlay['cmd'][0] == "d.legend":
                     if overlay['cmd'][0] == "d.legend":
                         mapdisplay[i].AddLegend(overlay['cmd'])
                         mapdisplay[i].AddLegend(overlay['cmd'])
                     if overlay['cmd'][0] == "d.barscale":
                     if overlay['cmd'][0] == "d.barscale":

+ 19 - 1
gui/wxpython/mapdisp/frame.py

@@ -44,7 +44,7 @@ from mapwin.base import MapWindowProperties
 from gui_core.query import QueryDialog, PrepareQueryResults
 from gui_core.query import QueryDialog, PrepareQueryResults
 from mapwin.buffered import BufferedMapWindow
 from mapwin.buffered import BufferedMapWindow
 from mapwin.decorations import LegendController, BarscaleController, \
 from mapwin.decorations import LegendController, BarscaleController, \
-    ArrowController, DtextController
+    ArrowController, DtextController, LegendVectController
 from modules.histogram import HistogramFrame
 from modules.histogram import HistogramFrame
 from wxplot.histogram import HistogramPlotFrame
 from wxplot.histogram import HistogramPlotFrame
 from wxplot.profile import ProfileFrame
 from wxplot.profile import ProfileFrame
@@ -1247,6 +1247,22 @@ class MapFrame(SingleMapFrame):
 
 
         self.MapWindow.mouse['use'] = 'pointer'
         self.MapWindow.mouse['use'] = 'pointer'
 
 
+    def AddLegendVect(self, cmd=None, showDialog=None):
+        """Handler for legend map decoration menu selection."""
+
+        if cmd:
+            show = False
+        else:
+            show = True
+            cmd = ['d.legend.vect']
+            layers = self._giface.GetLayerList().GetSelectedLayers()
+
+        GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+            cmd, completed=(self.GetOptData, None, None))
+
+        self.MapWindow.mouse['use'] = 'pointer'
+
+
     def AddArrow(self, cmd=None):
     def AddArrow(self, cmd=None):
         """Handler for north arrow menu selection."""
         """Handler for north arrow menu selection."""
         if self.IsPaneShown('3d'):
         if self.IsPaneShown('3d'):
@@ -1303,6 +1319,8 @@ class MapFrame(SingleMapFrame):
                 overlay = BarscaleController(self.Map, self._giface)
                 overlay = BarscaleController(self.Map, self._giface)
             elif cmd == 'd.legend':
             elif cmd == 'd.legend':
                 overlay = LegendController(self.Map, self._giface)
                 overlay = LegendController(self.Map, self._giface)
+            elif cmd == 'd.legend.vect':
+                overlay = LegendVectController(self.Map, self._giface)
             elif cmd == 'd.text':
             elif cmd == 'd.text':
                 overlay = DtextController(self.Map, self._giface)
                 overlay = DtextController(self.Map, self._giface)
 
 

+ 4 - 0
gui/wxpython/mapdisp/toolbars.py

@@ -35,6 +35,8 @@ MapIcons = {
                             label=_('Add scale bar')),
                             label=_('Add scale bar')),
     'addLegend': MetaIcon(img='legend-add',
     'addLegend': MetaIcon(img='legend-add',
                           label=_('Add legend')),
                           label=_('Add legend')),
+    'addVectorLegend': MetaIcon(img='legend-add',
+                                label=_('Add vector legend')),
     'addNorthArrow': MetaIcon(img='north-arrow-add',
     'addNorthArrow': MetaIcon(img='north-arrow-add',
                               label=_('Add north arrow')),
                               label=_('Add north arrow')),
     'analyze': MetaIcon(img='layer-raster-analyze',
     'analyze': MetaIcon(img='layer-raster-analyze',
@@ -269,6 +271,8 @@ class MapToolbar(BaseToolbar):
         self._onMenu(
         self._onMenu(
             ((MapIcons["addLegend"],
             ((MapIcons["addLegend"],
               lambda evt: self.parent.AddLegend()),
               lambda evt: self.parent.AddLegend()),
+             (MapIcons["addVectorLegend"],
+              lambda evt: self.parent.AddLegendVect()),
              (MapIcons["addBarscale"],
              (MapIcons["addBarscale"],
               lambda evt: self.parent.AddBarscale()),
               lambda evt: self.parent.AddBarscale()),
              (MapIcons["addNorthArrow"],
              (MapIcons["addNorthArrow"],

+ 12 - 0
gui/wxpython/mapwin/decorations.py

@@ -236,6 +236,18 @@ class ArrowController(OverlayController):
         self._cmd = ['d.northarrow', self._defaultAt]
         self._cmd = ['d.northarrow', self._defaultAt]
 
 
 
 
+class LegendVectController(OverlayController):
+
+    def __init__(self, renderer, giface):
+        OverlayController.__init__(self, renderer, giface)
+        self._name = 'vectleg'
+        self._removeLabel = _("Remove vector legend")
+        # different from default because the reference point is not in the
+        # middle
+        self._defaultAt = 'at=20.0,80.0'
+        self._cmd = ['d.legend.vect', self._defaultAt]
+
+
 class LegendController(OverlayController):
 class LegendController(OverlayController):
 
 
     def __init__(self, renderer, giface):
     def __init__(self, renderer, giface):

+ 1 - 1
lib/symbol/Makefile

@@ -7,7 +7,7 @@ include $(MODULE_TOPDIR)/include/Make/Lib.make
 
 
 SYMBOL_SRC := $(wildcard symbol/*/*)
 SYMBOL_SRC := $(wildcard symbol/*/*)
 SYMBOL_DST := $(patsubst symbol/%,$(ETC)/symbol/%,$(SYMBOL_SRC))
 SYMBOL_DST := $(patsubst symbol/%,$(ETC)/symbol/%,$(SYMBOL_SRC))
-SYMBOL_DIRS := $(patsubst %,$(ETC)/symbol/%, demo basic extra geology n_arrows)
+SYMBOL_DIRS := $(patsubst %,$(ETC)/symbol/%, demo basic extra geology legend n_arrows)
 
 
 default: lib
 default: lib
 	$(MAKE) $(SYMBOL_DST)
 	$(MAKE) $(SYMBOL_DST)

+ 13 - 0
lib/symbol/symbol/legend/area

@@ -0,0 +1,13 @@
+VERSION 1.0
+BOX -1 -1 1 1
+POLYGON
+  RING
+    LINE
+      -1 -0.75
+      1 -0.75
+      1 0.75
+      -1 0.75
+    END
+  END
+END
+

+ 114 - 0
lib/symbol/symbol/legend/area_curved

@@ -0,0 +1,114 @@
+VERSION 1.0
+BOX -1 -1 1 1
+POLYGON
+  RING
+    LINE
+      -00.030 000.615
+      000.064 000.656
+      000.128 000.696
+      000.200 000.768
+      000.260 000.813
+      000.321 000.865
+      000.375 000.903
+      000.431 000.917
+      000.488 000.944
+      000.547 000.944
+      000.605 000.913
+      000.661 000.873
+      000.721 000.835
+      000.773 000.770
+      000.821 000.696
+      000.872 000.648
+      000.909 000.561
+      000.944 000.472
+      000.978 000.366
+      000.992 000.261
+      000.998 000.166
+      001.000 000.094
+      001.000 000.013
+      000.998 -00.071
+      000.976 -00.148
+      000.954 -00.223
+      000.932 -00.297
+      000.903 -00.376
+      000.876 -00.454
+      000.838 -00.527
+      000.804 -00.595
+      000.767 -00.660
+      000.727 -00.726
+      000.681 -00.801
+      000.644 -00.854
+      000.603 -00.903
+      000.551 -00.946
+      000.509 -00.976
+      000.471 -00.996
+      000.429 -01.000
+      000.388 -00.998
+      000.338 -00.996
+      000.289 -00.964
+      000.249 -00.923
+      000.204 -00.875
+      000.163 -00.825
+      000.126 -00.748
+      000.074 -00.670
+      000.038 -00.601
+      -00.008 -00.539
+      -00.051 -00.486
+      -00.095 -00.462
+      -00.144 -00.446
+      -00.194 -00.428
+      -00.242 -00.428
+      -00.286 -00.430
+      -00.337 -00.432
+      -00.377 -00.448
+      -00.420 -00.466
+      -00.461 -00.478
+      -00.509 -00.480
+      -00.552 -00.480
+      -00.595 -00.488
+      -00.642 -00.496
+      -00.687 -00.498
+      -00.731 -00.498
+      -00.779 -00.488
+      -00.822 -00.462
+      -00.864 -00.450
+      -00.925 -00.416
+      -00.953 -00.347
+      -00.984 -00.267
+      -00.995 -00.196
+      -01.000 -00.108
+      -01.000 -00.013
+      -01.000 000.078
+      -00.985 000.182
+      -00.972 000.273
+      -00.958 000.357
+      -00.941 000.431
+      -00.912 000.519
+      -00.892 000.599
+      -00.878 000.670
+      -00.852 000.728
+      -00.834 000.778
+      -00.800 000.839
+      -00.773 000.889
+      -00.739 000.942
+      -00.703 000.976
+      -00.667 000.994
+      -00.624 001.000
+      -00.586 000.992
+      -00.541 000.980
+      -00.495 000.956
+      -00.445 000.942
+      -00.403 000.919
+      -00.365 000.881
+      -00.332 000.835
+      -00.289 000.797
+      -00.239 000.760
+      -00.200 000.720
+      -00.157 000.672
+      -00.115 000.629
+      -00.075 000.617
+      000.023 000.629
+    END
+  END
+END
+

+ 8 - 0
lib/symbol/symbol/legend/line

@@ -0,0 +1,8 @@
+VERSION 1.0
+BOX -1 -1 1 1
+STRING
+  LINE
+    -1 0
+    1 0
+  END
+END

+ 13 - 0
lib/symbol/symbol/legend/line_crooked

@@ -0,0 +1,13 @@
+VERSION 1.0
+BOX -1 -1 1 1
+STRING
+  LINE
+    -1 -0.33
+    -0.33  0.33
+     0.33 -0.33
+     1  0.33
+	 0.33 -0.33
+	-0.33  0.33
+	-1 -0.33
+  END
+END