[GRASS-SVN] r69199 - in grass/branches/releasebranch_7_2: . display display/d.legend.vect display/d.mon display/d.vect gui/images gui/images/symbols gui/images/symbols/legend gui/wxpython/core gui/wxpython/gui_core gui/wxpython/lmgr gui/wxpython/mapdisp gui/wxpython/mapwin gui/wxpython/nviz include lib/symbol lib/symbol/symbol lib/symbol/symbol/legend
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Aug 21 15:54:25 PDT 2016
Author: annakrat
Date: 2016-08-21 15:54:25 -0700 (Sun, 21 Aug 2016)
New Revision: 69199
Added:
grass/branches/releasebranch_7_2/display/d.legend.vect/
grass/branches/releasebranch_7_2/display/d.vect/legend.c
grass/branches/releasebranch_7_2/gui/images/symbols/legend/
grass/branches/releasebranch_7_2/gui/images/symbols/legend/area.png
grass/branches/releasebranch_7_2/gui/images/symbols/legend/area_curved.png
grass/branches/releasebranch_7_2/gui/images/symbols/legend/line.png
grass/branches/releasebranch_7_2/gui/images/symbols/legend/line_crooked.png
grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/
grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area
grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area_curved
grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line
grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line_crooked
Modified:
grass/branches/releasebranch_7_2/
grass/branches/releasebranch_7_2/display/Makefile
grass/branches/releasebranch_7_2/display/d.legend.vect/Makefile
grass/branches/releasebranch_7_2/display/d.legend.vect/d.legend.vect.html
grass/branches/releasebranch_7_2/display/d.legend.vect/draw.c
grass/branches/releasebranch_7_2/display/d.legend.vect/local_proto.h
grass/branches/releasebranch_7_2/display/d.legend.vect/main.c
grass/branches/releasebranch_7_2/display/d.mon/render_cmd.py
grass/branches/releasebranch_7_2/display/d.mon/start.c
grass/branches/releasebranch_7_2/display/d.vect/local_proto.h
grass/branches/releasebranch_7_2/display/d.vect/main.c
grass/branches/releasebranch_7_2/gui/images/Makefile
grass/branches/releasebranch_7_2/gui/wxpython/core/giface.py
grass/branches/releasebranch_7_2/gui/wxpython/core/render.py
grass/branches/releasebranch_7_2/gui/wxpython/core/utils.py
grass/branches/releasebranch_7_2/gui/wxpython/core/workspace.py
grass/branches/releasebranch_7_2/gui/wxpython/gui_core/forms.py
grass/branches/releasebranch_7_2/gui/wxpython/gui_core/widgets.py
grass/branches/releasebranch_7_2/gui/wxpython/lmgr/frame.py
grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/frame.py
grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/main.py
grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/toolbars.py
grass/branches/releasebranch_7_2/gui/wxpython/mapwin/base.py
grass/branches/releasebranch_7_2/gui/wxpython/mapwin/buffered.py
grass/branches/releasebranch_7_2/gui/wxpython/mapwin/decorations.py
grass/branches/releasebranch_7_2/gui/wxpython/nviz/mapwindow.py
grass/branches/releasebranch_7_2/gui/wxpython/nviz/wxnviz.py
grass/branches/releasebranch_7_2/include/symbol.h
grass/branches/releasebranch_7_2/lib/symbol/Makefile
grass/branches/releasebranch_7_2/lib/symbol/read.c
Log:
wxGUI/vector legend: major backport of changes in overlays and Adam Laza's GSoC work related to vector legend
Property changes on: grass/branches/releasebranch_7_2
___________________________________________________________________
Added: svn:mergeinfo
+ /grass/trunk:68502,68507,68529,68570,68612,68671,68699-68702,68711,68753-68754,68758-68760,68947,68950,68953,68960,69000,69003,69005-69007,69036,69052,69069,69075,69100,69107,69116,69153,69169,69173,69191
Modified: grass/branches/releasebranch_7_2/display/Makefile
===================================================================
--- grass/branches/releasebranch_7_2/display/Makefile 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/display/Makefile 2016-08-21 22:54:25 UTC (rev 69199)
@@ -18,6 +18,7 @@
d.info \
d.labels \
d.legend \
+ d.legend.vect \
d.linegraph \
d.mon \
d.northarrow \
Property changes on: grass/branches/releasebranch_7_2/display/d.legend.vect/Makefile
___________________________________________________________________
Added: svn:mime-type
+ text/x-makefile
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_7_2/display/d.legend.vect/d.legend.vect.html
===================================================================
--- grass/trunk/display/d.legend.vect/d.legend.vect.html 2016-08-21 19:05:45 UTC (rev 69191)
+++ grass/branches/releasebranch_7_2/display/d.legend.vect/d.legend.vect.html 2016-08-21 22:54:25 UTC (rev 69199)
@@ -95,4 +95,4 @@
Mentors: Anna Petrasova, Vaclav Petras, Martin Landa
<p>
-<i>Last changed: $Date: 2015-08-11 23:06:03 +0200 (Út, 11 srp 2015) $</i>
+<i>Last changed: $Date$</i>
Property changes on: grass/branches/releasebranch_7_2/display/d.legend.vect/d.legend.vect.html
___________________________________________________________________
Added: svn:mime-type
+ text/html
Added: svn:keywords
+ Author Date Id
Added: svn:eol-style
+ native
Property changes on: grass/branches/releasebranch_7_2/display/d.legend.vect/draw.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Property changes on: grass/branches/releasebranch_7_2/display/d.legend.vect/local_proto.h
___________________________________________________________________
Added: svn:mime-type
+ text/x-chdr
Added: svn:eol-style
+ native
Property changes on: grass/branches/releasebranch_7_2/display/d.legend.vect/main.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_7_2/display/d.mon/render_cmd.py
===================================================================
--- grass/branches/releasebranch_7_2/display/d.mon/render_cmd.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/display/d.mon/render_cmd.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -8,7 +8,7 @@
# read environment variables from file
def read_env_file(env_file):
- width = height = None
+ width = height = legfile = None
fd = open(env_file, 'r')
if fd is None:
grass.fatal("Unable to open file '{}'".format(env_file))
@@ -22,16 +22,19 @@
width = int(v)
if height is None and k == 'GRASS_RENDER_HEIGHT':
height = int(v)
+ if legfile is None and k == 'GRASS_LEGEND_FILE':
+ legfile = v
fd.close()
if width is None or height is None:
grass.fatal("Unknown monitor size")
- return width, height
+ return width, height, legfile
# run display command
def render(cmd, mapfile):
env = os.environ.copy()
+
if mapfile:
env['GRASS_RENDER_FILE'] = mapfile
try:
@@ -101,10 +104,10 @@
path = os.path.dirname(os.path.abspath(__file__))
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'):
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', 'd.legend.vect'):
mapfile += '.png'
else:
mapfile += '.ppm'
@@ -114,5 +117,8 @@
render(cmd, mapfile)
update_cmd_file(os.path.join(path, 'cmd'), cmd, mapfile)
+ if cmd[0] == 'd.erase' and os.path.exists(legfile):
+ os.remove(legfile)
+
sys.exit(0)
Modified: grass/branches/releasebranch_7_2/display/d.mon/start.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.mon/start.c 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/display/d.mon/start.c 2016-08-21 22:54:25 UTC (rev 69199)
@@ -133,7 +133,7 @@
int truecolor, int x_only, int update)
{
char *mon_path;
- char *out_file, *env_file, *cmd_file;
+ char *out_file, *env_file, *cmd_file, *leg_file;
char buf[1024];
char file_path[GPATH_MAX], render_cmd_path[GPATH_MAX];
int fd;
@@ -158,6 +158,8 @@
env_file = G_store(file_path);
G_file_name(file_path, mon_path, "cmd", G_mapset());
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) */
sprintf(render_cmd_path, "%s/etc/d.mon/render_cmd.py", getenv("GISBASE"));
@@ -199,6 +201,10 @@
write(fd, buf, strlen(buf));
sprintf(buf, "GRASS_RENDER_HEIGHT=%d\n", height);
write(fd, buf, strlen(buf));
+ sprintf(buf, "GRASS_LEGEND_FILE=%s\n", leg_file);
+ write(fd, buf, strlen(buf));
+
+
if (bgcolor) {
if (strcmp(bgcolor, "none") == 0)
sprintf(buf, "GRASS_RENDER_TRANSPARENT=TRUE\n");
Added: grass/branches/releasebranch_7_2/display/d.vect/legend.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.vect/legend.c (rev 0)
+++ grass/branches/releasebranch_7_2/display/d.vect/legend.c 2016-08-21 22:54:25 UTC (rev 69199)
@@ -0,0 +1,78 @@
+#include <grass/gis.h>
+#include <grass/vector.h>
+#include "local_proto.h"
+
+void write_into_legfile(struct Map_info *Map, int type, const char *leglab, const char *name_map, const char *icon,
+ const char *size, const char *color, const char *fcolor, const char *width, const char *icon_area,
+ const char *icon_line, const char *size_column)
+{
+ int nfeatures;
+ FILE *fd;
+ char *leg_file;
+ char map[GNAME_MAX];
+ char *ptr;
+ strcpy(map, name_map);
+ strtok_r(map, "@", &ptr);
+
+ if (size_column)
+ size = "-1";
+
+ /* Write into legend file */
+ leg_file = getenv("GRASS_LEGEND_FILE");
+ if (leg_file) {
+ fd = fopen(leg_file, "a");
+
+ /* Point */
+ if (type & GV_POINT){
+ nfeatures = Vect_get_num_primitives(Map, GV_POINT);
+ if (nfeatures > 0) {
+ if (leglab)
+ fprintf(fd, "%s|", leglab);
+ else
+ fprintf(fd, "%s|", map);
+ fprintf(fd, "%s|%s|%s|%s|%s", icon, size, color, fcolor, width);
+ fprintf(fd, "|%s|%d\n", "point", nfeatures);
+ }
+ }
+
+ /* Line */
+ if (type & GV_LINE){
+ nfeatures = Vect_get_num_primitives(Map, GV_LINE);
+ if (nfeatures > 0){
+ if (leglab)
+ fprintf(fd, "%s|", leglab);
+ else
+ fprintf(fd, "%s|", map);
+ fprintf(fd, "%s|%s|%s|%s|%s", icon_line, size, color, fcolor, width);
+ fprintf(fd, "|%s|%d\n", "line", nfeatures);
+ }
+ }
+
+ /* Area */
+ if (type & GV_AREA){
+ nfeatures = Vect_get_num_primitives(Map, GV_BOUNDARY);
+ if (nfeatures > 0) {
+ if (leglab)
+ fprintf(fd, "%s|", leglab);
+ else
+ fprintf(fd, "%s|", map);
+ fprintf(fd, "%s|%s|%s|%s|%s", icon_area, size, color, fcolor, width);
+ fprintf(fd, "|%s|%d\n", "area", nfeatures);
+ }
+ }
+ /* Centroid */
+ if (type & GV_CENTROID){
+ nfeatures = Vect_get_num_primitives(Map, GV_CENTROID);
+ if (nfeatures > 0) {
+ if (leglab)
+ fprintf(fd, "%s|", leglab);
+ else
+ fprintf(fd, "%s|", map);
+ fprintf(fd, "%s|%s|%s|%s|%s", icon, size, color, fcolor, width);
+ fprintf(fd, "|%s|%d\n", "centroid", nfeatures);
+ }
+ }
+
+ fclose(fd);
+ }
+}
Property changes on: grass/branches/releasebranch_7_2/display/d.vect/legend.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_7_2/display/d.vect/local_proto.h
===================================================================
--- grass/branches/releasebranch_7_2/display/d.vect/local_proto.h 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/display/d.vect/local_proto.h 2016-08-21 22:54:25 UTC (rev 69199)
@@ -65,3 +65,8 @@
/* zcoor.c */
int display_zcoor(struct Map_info *, int, LATTR *);
+
+/* legend.c */
+void write_into_legfile(struct Map_info *, int, const char *, const char *,
+ const char *, const char *, const char *, const char *,
+ const char *, const char *, const char *, const char *);
Modified: grass/branches/releasebranch_7_2/display/d.vect/main.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.vect/main.c 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/display/d.vect/main.c 2016-08-21 22:54:25 UTC (rev 69199)
@@ -4,6 +4,7 @@
* MODULE: d.vect
* AUTHOR(S): CERL, Radim Blazek, others
* 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
* COPYRIGHT: (C) 2004-2014 by the GRASS Development Team
*
@@ -52,7 +53,9 @@
struct Option *lsize_opt, *font_opt, *enc_opt, *xref_opt, *yref_opt;
struct Option *attrcol_opt, *maxreg_opt, *minreg_opt;
struct Option *width_opt, *wcolumn_opt, *wscale_opt;
- struct Flag *id_flag, *cats_acolors_flag, *sqrt_flag;
+ struct Option *leglab_opt;
+ struct Option *icon_line_opt, *icon_area_opt;
+ struct Flag *id_flag, *cats_acolors_flag, *sqrt_flag, *legend_flag;
char *desc;
struct cat_list *Clist;
@@ -189,6 +192,32 @@
rotcolumn_opt->description =
_("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 */
lfield_opt = G_define_standard_option(G_OPT_V_FIELD);
lfield_opt->key = "label_layer";
@@ -295,6 +324,11 @@
"instead of circle radius");
sqrt_flag->guisection = _("Symbols");
+ legend_flag = G_define_flag();
+ legend_flag->key = 'l';
+ legend_flag->label = _("Do not add this layer to vector legend");
+ legend_flag->guisection = _("Legend");
+
/* Check command line */
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
@@ -424,6 +458,14 @@
stat += display_dir(&Map, type, Clist, chcat, size);
}
+ if (!legend_flag->answer) {
+ write_into_legfile(&Map, type, leglab_opt->answer, map_name,
+ icon_opt->answer, size_opt->answer,
+ color_opt->answer, fcolor_opt->answer,
+ width_opt->answer, icon_area_opt->answer,
+ icon_line_opt->answer, sizecolumn_opt->answer);
+ }
+
/* reset line width: Do we need to get line width from display
* driver (not implemented)? It will help restore previous line
* width (not just 0) determined by another module (e.g.,
Modified: grass/branches/releasebranch_7_2/gui/images/Makefile
===================================================================
--- grass/branches/releasebranch_7_2/gui/images/Makefile 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/images/Makefile 2016-08-21 22:54:25 UTC (rev 69199)
@@ -9,7 +9,7 @@
IMGDST := $(patsubst %,$(DSTDIR)/%,$(IMGSRC))
# symbols
-CATEGORIES = basic demo extra geology n_arrows
+CATEGORIES = basic demo extra geology legend n_arrows
SYMSRC := $(foreach dir,$(CATEGORIES),$(wildcard symbols/$(dir)/*.png))
SYMDST := $(patsubst symbols/%,$(DSTDIR)/symbols/%,$(SYMSRC))
Added: grass/branches/releasebranch_7_2/gui/images/symbols/legend/area.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_7_2/gui/images/symbols/legend/area.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_7_2/gui/images/symbols/legend/area_curved.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_7_2/gui/images/symbols/legend/area_curved.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_7_2/gui/images/symbols/legend/line.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_7_2/gui/images/symbols/legend/line.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_7_2/gui/images/symbols/legend/line_crooked.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_7_2/gui/images/symbols/legend/line_crooked.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Modified: grass/branches/releasebranch_7_2/gui/wxpython/core/giface.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/core/giface.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/core/giface.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -285,7 +285,7 @@
os.environ["GRASS_MESSAGE_FORMAT"] = orig
def GetLayerList(self):
- raise NotImplementedError()
+ return []
def GetLayerTree(self):
return None
Modified: grass/branches/releasebranch_7_2/gui/wxpython/core/render.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/core/render.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/core/render.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -324,6 +324,10 @@
"""Represents map layer in the map canvas
"""
Layer.__init__(self, *args, **kwargs)
+ if self.type in ('vector'): # will add d.vect.thematic
+ self._legrow = grass.tempfile(create=True)
+ else:
+ self._legrow = ''
def GetMapset(self):
"""Get mapset of map layer
@@ -364,6 +368,7 @@
self.thread = gThread()
self.updateProgress = Signal('RenderLayerMgr.updateProgress')
+ self.renderingFailed = Signal('RenderLayerMgr.renderingFailed')
self._startTime = None
self._render_env = env
@@ -383,20 +388,26 @@
env_cmd = env.copy()
env_cmd.update(self._render_env)
env_cmd['GRASS_RENDER_FILE'] = self.layer.mapfile
+ if self.layer.GetType() in ('vector'):
+ 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[1]['quiet'] = True # be quiet
self._startTime = time.time()
self.thread.Run(callable=self._render, cmd=cmd_render, env=env_cmd,
- ondone=self.OnRenderDone)
+ ondone=self.OnRenderDone, userdata={'cmd': cmd})
self.layer.forceRender = False
def _render(self, cmd, env):
- try:
- return grass.run_command(cmd[0], env=env, **cmd[1])
- except CalledModuleError as e:
- return 1
+ p = grass.start_command(cmd[0], env=env, stderr=grass.PIPE, **cmd[1])
+ stdout, stderr = p.communicate()
+ if p.returncode:
+ return stderr
+ else:
+ return None
def Abort(self):
"""Abort rendering process"""
@@ -419,13 +430,14 @@
Emits updateProcess
"""
- Debug.msg(1, "RenderLayerMgr.OnRenderDone(%s): ret=%d time=%f" %
+ Debug.msg(1, "RenderLayerMgr.OnRenderDone(%s): err=%s time=%f" %
(self.layer, event.ret, time.time() - self._startTime))
- if event.ret != 0:
- try:
- os.remove(self.layer.mapfile)
- except:
- pass
+ if event.ret is not None:
+ cmd = cmdtuple_to_list(event.userdata['cmd'])
+ self.renderingFailed.emit(cmd=cmd, error=event.ret)
+ # don't remove layer if overlay, we need to keep the old one
+ if self.layer.type != 'overlay':
+ try_remove(self.layer.mapfile)
self.updateProgress.emit(layer=self.layer)
@@ -443,6 +455,7 @@
self.updateMap = Signal('RenderMapMgr.updateMap')
self.updateProgress = Signal('RenderMapMgr.updateProgress')
+ self.renderingFailed = Signal('RenderMapMgr.renderingFailed')
self.renderDone = Signal('RenderMapMgr.renderDone')
self.renderDone.connect(self.OnRenderDone)
@@ -450,10 +463,13 @@
self._render_env = {"GRASS_RENDER_BACKGROUNDCOLOR": "000000",
"GRASS_RENDER_FILE_COMPRESSION": "0",
"GRASS_RENDER_TRUECOLOR": "TRUE",
- "GRASS_RENDER_TRANSPARENT": "TRUE"}
+ "GRASS_RENDER_TRANSPARENT": "TRUE",
+ "GRASS_LEGEND_FILE": self.Map.legfile
+ }
self._init()
self._rendering = False
+ self._old_legend = []
def _init(self, env=None):
"""Init render manager
@@ -469,6 +485,9 @@
if os.path.exists(self.Map.mapfile):
os.remove(self.Map.mapfile)
+ def UpdateRenderEnv(self, env):
+ self._render_env.update(env)
+
def _renderLayers(self, env, force=False, overlaysOnly=False):
"""Render all map layers into files
@@ -511,6 +530,7 @@
env['GRASS_REGION'] = self.Map.SetRegion(windres)
env['GRASS_RENDER_WIDTH'] = str(self.Map.width)
env['GRASS_RENDER_HEIGHT'] = str(self.Map.height)
+
if UserSettings.Get(group='display', key='driver',
subkey='type') == 'png':
env['GRASS_RENDER_IMMEDIATE'] = 'png'
@@ -519,6 +539,25 @@
return env
+ def RenderOverlays(self, force=False):
+ """Render only overlays
+
+ :param bool force: force rendering all map layers
+ """
+ if self._rendering:
+ Debug.msg(
+ 1, "RenderMapMgr().RenderOverlays(): cancelled (already rendering)")
+ return
+
+ wx.BeginBusyCursor()
+ self._rendering = True
+
+ env = self.GetRenderEnv()
+ self._init(env)
+ # no layer composition afterwards
+ if self._renderLayers(env, force, overlaysOnly=True) == 0:
+ self.renderDone.emit()
+
def Render(self, force=False, windres=False):
"""Render map composition
@@ -535,9 +574,10 @@
env = self.GetRenderEnv(windres)
self._init(env)
- if self._renderLayers(env, force, windres) == 0:
+ if self._renderLayers(env, force) == 0:
self.renderDone.emit()
+
def OnRenderDone(self):
"""Rendering process done
@@ -549,6 +589,8 @@
masks = list()
opacities = list()
+ # TODO: g.pnmcomp is now called every time
+ # even when only overlays are rendered
for layer in self.layers:
if layer.GetType() == 'overlay':
continue
@@ -584,11 +626,33 @@
Debug.msg(1, "RenderMapMgr.OnRenderDone() time=%f sec (comp: %f)" %
(stop - self._startTime, stop - startCompTime))
+ # Update legfile
+ new_legend = []
+ with open(self.Map.legfile, "w") as outfile:
+ for layer in reversed(self.layers):
+ if layer.GetType() not in ('vector'):
+ continue
+
+ if os.path.isfile(layer._legrow) and layer._legrow[-1].isdigit() \
+ and layer.hidden is False:
+ with open(layer._legrow) as infile:
+ line = infile.read()
+ outfile.write(line)
+ new_legend.append(line)
+
self._rendering = False
if wx.IsBusy():
wx.EndBusyCursor()
- self.updateMap.emit()
+ # if legend file changed, rerender vector legend
+ if new_legend != self._old_legend:
+ self._old_legend = new_legend
+ for layer in self.layers:
+ if layer.GetType() == 'overlay' and layer.GetName() == 'vectleg':
+ layer.forceRender = True
+ self.Render()
+ else:
+ self.updateMap.emit()
def Abort(self):
"""Abort all rendering processes"""
@@ -652,7 +716,10 @@
'progresVal'] == self.progressInfo['range']:
self.renderDone.emit()
+ def RenderingFailed(self, cmd, error):
+ self.renderingFailed.emit(cmd=cmd, error=error)
+
class Map(object):
def __init__(self, gisrc=None):
@@ -677,8 +744,11 @@
self.gisrc = gisrc
# 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'
+
# setting some initial env. variables
if not self.GetWindow():
sys.stderr.write(_("Trying to recover from default region..."))
@@ -1249,6 +1319,10 @@
basefile = os.path.join(base, tempbase) + r'.*'
for f in glob.glob(basefile):
os.remove(f)
+
+ if layer.GetType() in ('vector'):
+ os.remove(layer._legrow)
+
list.remove(layer)
self.layerRemoved.emit(layer=layer)
@@ -1413,6 +1487,7 @@
string=True))))
if renderMgr:
renderMgr.updateProgress.connect(self.renderMgr.ReportProgress)
+ renderMgr.renderingFailed.connect(self.renderMgr.RenderingFailed)
overlay.forceRender = render
return overlay
@@ -1511,9 +1586,7 @@
def RenderOverlays(self, force):
"""Render overlays only (for nviz)"""
- for layer in self.overlays:
- if force or layer.forceRender:
- layer.Render()
+ self.renderMgr.RenderOverlays(force)
def AbortAllThreads(self):
"""Abort all layers threads e. g. donwloading data"""
Modified: grass/branches/releasebranch_7_2/gui/wxpython/core/utils.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/core/utils.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/core/utils.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -1022,7 +1022,8 @@
'd.to.rast': 'torast',
'd.text': 'text',
'd.northarrow': 'northarrow',
- 'd.polar': 'polar'
+ 'd.polar': 'polar',
+ 'd.legend.vect': 'vectleg'
}
ltype2command = {}
for (cmd, ltype) in command2ltype.items():
Modified: grass/branches/releasebranch_7_2/gui/wxpython/core/workspace.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/core/workspace.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/core/workspace.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -1517,22 +1517,9 @@
"""Function for writing map elements (barscale, northarrow etc.)
"""
disp_size = mapdisp.GetMapWindow().GetClientSize()
+ for overlay in mapdisp.decorations.values():
+ self.__writeOverlayParams(disp_size, overlay.cmd, overlay.coords)
- if mapdisp.arrow.IsShown():
- cmd = mapdisp.arrow.cmd
- coord_px = mapdisp.arrow.coords
- self.__writeOverlayParams(disp_size, cmd, coord_px)
-
- if (mapdisp.legend) and mapdisp.legend.IsShown():
- cmd = mapdisp.legend.cmd
- coord_px = mapdisp.legend.coords
- self.__writeOverlayParams(disp_size, cmd, coord_px)
-
- if mapdisp.barscale and mapdisp.barscale.IsShown():
- cmd = mapdisp.barscale.cmd
- coord_px = mapdisp.barscale.coords
- self.__writeOverlayParams(disp_size, cmd, coord_px)
-
def __writeOverlayParams(self, disp_size, cmd, coord_px):
"""
:param mapdisp: mapdisplay
Modified: grass/branches/releasebranch_7_2/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/gui_core/forms.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/gui_core/forms.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -873,7 +873,7 @@
'MapWindow'):
# display decorations and
# pressing OK or cancel after setting layer properties
- if self.task.name in ['d.barscale', 'd.legend', 'd.northarrow', 'd.histogram'] \
+ 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:
self.Hide()
# canceled layer with nothing set
@@ -1230,7 +1230,7 @@
title_txt.SetLabel(title + ':')
value = self._getValue(p)
- if p['name'] == 'icon': # symbols
+ if p['name'] in ('icon', 'icon_area', 'icon_line'): # symbols
bitmap = wx.Bitmap(
os.path.join(
globalvar.SYMBDIR,
Modified: grass/branches/releasebranch_7_2/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/gui_core/widgets.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/gui_core/widgets.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -936,10 +936,6 @@
self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnPopupMenu) # wxMSW
self.Bind(wx.EVT_RIGHT_UP, self.OnPopupMenu) # wxGTK
- def LoadData(self):
- """Load data into list"""
- pass
-
def OnPopupMenu(self, event):
"""Show popup menu"""
if self.GetItemCount() < 1:
@@ -1020,10 +1016,12 @@
if data is None:
return
+ idx = 0
for item in data:
- index = self.InsertStringItem(sys.maxsize, str(item[0]))
+ index = self.InsertStringItem(idx, str(item[0]))
for i in range(1, self.GetColumnCount()):
self.SetStringItem(index, i, item[i])
+ idx += 1
# check by default only on one item
if len(data) == 1 and selectOne:
Modified: grass/branches/releasebranch_7_2/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/lmgr/frame.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/lmgr/frame.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -651,10 +651,10 @@
Also close associated map display
"""
- if UserSettings.Get(group='manager', key='askOnQuit',
- subkey='enabled') and self.workspaceChanged:
- maptree = self.GetLayerTree()
-
+ # save changes in the workspace
+ maptree = self.GetLayerTree()
+ if self.workspaceChanged and UserSettings.Get(
+ group='manager', key='askOnQuit', subkey='enabled'):
if self.workspaceFile:
message = _("Do you want to save changes in the workspace?")
else:
@@ -749,19 +749,29 @@
if layertype == 'barscale':
if len(command) > 1:
- self.GetMapDisplay().AddBarscale(cmd=command, showDialog=False)
+ self.GetMapDisplay().AddBarscale(cmd=command)
else:
- self.GetMapDisplay().AddBarscale(showDialog=True)
+ self.GetMapDisplay().AddBarscale()
elif layertype == 'rastleg':
if len(command) > 1:
- self.GetMapDisplay().AddLegend(cmd=command, showDialog=False)
+ self.GetMapDisplay().AddLegendRast(cmd=command)
else:
- self.GetMapDisplay().AddLegend(showDialog=True)
+ self.GetMapDisplay().AddLegendRast()
+ elif layertype == 'vectleg':
+ if len(command) > 1:
+ self.GetMapDisplay().AddLegendVect(cmd=command, showDialog=False)
+ else:
+ self.GetMapDisplay().AddLegendVect(showDialog=True)
elif layertype == 'northarrow':
if len(command) > 1:
- self.GetMapDisplay().AddArrow(cmd=command, showDialog=False)
+ self.GetMapDisplay().AddArrow(cmd=command)
else:
- self.GetMapDisplay().AddArrow(showDialog=True)
+ self.GetMapDisplay().AddArrow()
+ elif layertype == 'text':
+ if len(command) > 1:
+ self.GetMapDisplay().AddDtext(cmd=command)
+ else:
+ self.GetMapDisplay().AddDtext()
elif layertype == 'redraw':
self.GetMapDisplay().OnRender(None)
elif layertype == 'export':
@@ -1469,6 +1479,7 @@
else:
maptree.SelectItem(layer, select=False)
+
busy.Destroy()
# set render property again when all layers are loaded
@@ -1479,8 +1490,10 @@
# overlay["cmd"][0] name of command e.g. d.barscale, d.legend
# overlay["cmd"][1:] parameters and flags
if overlay['display'] == i:
+ if overlay['cmd'][0] == "d.legend.vect":
+ mapdisplay[i].AddLegendVect(overlay['cmd'])
if overlay['cmd'][0] == "d.legend":
- mapdisplay[i].AddLegend(overlay['cmd'])
+ mapdisplay[i].AddLegendRast(overlay['cmd'])
if overlay['cmd'][0] == "d.barscale":
mapdisplay[i].AddBarscale(overlay['cmd'])
if overlay['cmd'][0] == "d.northarrow":
Modified: grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/frame.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/frame.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -43,8 +43,8 @@
from mapwin.base import MapWindowProperties
from gui_core.query import QueryDialog, PrepareQueryResults
from mapwin.buffered import BufferedMapWindow
-from mapwin.decorations import TextLayerDialog, \
- LegendController, BarscaleController, ArrowController
+from mapwin.decorations import LegendController, BarscaleController, \
+ ArrowController, DtextController, LegendVectController
from modules.histogram import HistogramFrame
from wxplot.histogram import HistogramPlotFrame
from wxplot.profile import ProfileFrame
@@ -128,12 +128,7 @@
# init decoration objects
self.decorations = {}
- self.legend = LegendController(self.Map, self._giface)
- self.barscale = BarscaleController(self.Map, self._giface)
- self.arrow = ArrowController(self.Map, self._giface)
- self.decorations[self.legend.id] = self.legend
- self.decorations[self.barscale.id] = self.barscale
- self.decorations[self.arrow.id] = self.arrow
+ self._decorationWindows = {}
self.mapWindowProperties.autoRenderChanged.connect(
lambda value:
@@ -147,12 +142,8 @@
properties=self.mapWindowProperties, overlays=self.decorations)
self.MapWindow2D.mapQueried.connect(self.Query)
self.MapWindow2D.overlayActivated.connect(self._activateOverlay)
- self.MapWindow2D.overlayHidden.connect(self._hideOverlay)
- self.MapWindow2D.overlayHidden.connect(self._hideOverlay)
- for overlay in (self.legend, self.barscale, self.arrow):
- overlay.overlayChanged.connect(
- lambda: self.MapWindow2D.UpdateMap(
- render=False, renderVector=False))
+ self.MapWindow2D.overlayRemoved.connect(self.RemoveOverlay)
+ self.MapWindow2D.overlayRemoved.connect(self.RemoveOverlay)
self._setUpMapWindow(self.MapWindow2D)
self.MapWindow2D.mouseHandlerUnregistered.connect(self.ResetPointer)
@@ -254,6 +245,8 @@
#
self.Map.GetRenderMgr().updateProgress.connect(self.statusbarManager.SetProgress)
+ self.Map.GetRenderMgr().renderingFailed.connect(lambda cmd, error: self._giface.WriteError(
+ _("Failed to run command '{command}'. Details:\n{error}").format(command=' '.join(cmd), error=error)))
def GetMapWindow(self):
return self.MapWindow
@@ -414,8 +407,7 @@
self.MapWindow3D.ResetViewHistory()
self.MapWindow3D.UpdateView(None)
self.MapWindow3D.overlayActivated.connect(self._activateOverlay)
- self.MapWindow3D.overlayHidden.connect(self._hideOverlay)
- self.legend.overlayChanged.connect(self.MapWindow3D.UpdateOverlays)
+ self.MapWindow3D.overlayRemoved.connect(self.RemoveOverlay)
else:
self._switchMapWindow(self.MapWindow3D)
os.environ['GRASS_REGION'] = self.Map.SetRegion(
@@ -432,10 +424,14 @@
self.MapWindow3D.ResetViewHistory()
+ # connect signals for updating overlays
+ for overlay in self.decorations.values():
+ overlay.overlayChanged.connect(self.MapWindow3D.UpdateOverlays)
+ self.Map.GetRenderMgr().renderDone.connect(self.MapWindow3D._onUpdateOverlays)
+
self._giface.updateMap.disconnect(self.MapWindow2D.UpdateMap)
self._giface.updateMap.connect(self.MapWindow3D.UpdateMap)
self.MapWindow3D.overlays = self.MapWindow2D.overlays
- self.MapWindow3D.textdict = self.MapWindow2D.textdict
# update overlays needs to be called after because getClientSize
# is called during update and it must give reasonable values
wx.CallAfter(self.MapWindow3D.UpdateOverlays)
@@ -479,13 +475,16 @@
self.ending3dMode.emit()
try:
self.MapWindow2D.overlays = self.MapWindow3D.overlays
- self.MapWindow2D.textdict = self.MapWindow3D.textdict
except AttributeError:
pass
# TODO: here we end because self.MapWindow3D is None for a while
self._giface.updateMap.disconnect(self.MapWindow3D.UpdateMap)
self._giface.updateMap.connect(self.MapWindow2D.UpdateMap)
- self.legend.overlayChanged.disconnect(self.MapWindow3D.UpdateOverlays)
+ # disconnect overlays
+ for overlay in self.decorations.values():
+ overlay.overlayChanged.disconnect(self.MapWindow3D.UpdateOverlays)
+ self.Map.GetRenderMgr().renderDone.disconnect(self.MapWindow3D._onUpdateOverlays)
+ self.MapWindow3D.ClearTextures()
self.MapWindow.UpdateMap()
self._mgr.Update()
@@ -1195,113 +1194,74 @@
:param overlayId: id of overlay
"""
- if overlayId > 100:
- self.OnAddText(None)
- elif overlayId == 0:
- self.AddLegend(cmd=self.legend.cmd, showDialog=True)
- elif overlayId == 1:
- self.AddBarscale(showDialog=True)
- elif overlayId == 2:
- self.AddArrow(showDialog=True)
+ dlg = self.decorations[overlayId].dialog
+ if dlg.IsShown():
+ dlg.SetFocus()
+ dlg.Raise()
+ else:
+ dlg.Show()
- def _hideOverlay(self, overlayId):
+ def RemoveOverlay(self, overlayId):
"""Hide overlay.
:param overlayId: id of overlay
"""
- self.decorations[overlayId].Hide()
+ del self._decorationWindows[self.decorations[overlayId].dialog]
+ self.decorations[overlayId].Remove()
+ del self.decorations[overlayId]
- def AddBarscale(self, cmd=None, showDialog=None):
+ def AddBarscale(self, cmd=None):
"""Handler for scale bar map decoration menu selection."""
if self.IsPaneShown('3d'):
self.MapWindow3D.SetDrawScalebar((70, 70))
return
- if self.barscale.IsShown() and showDialog is None:
- self.barscale.Hide()
- return
-
if cmd:
- self.barscale.cmd = cmd
+ show = False
+ else:
+ show = True
+ cmd = ['d.barscale']
- if not showDialog:
- self.barscale.Show()
- return
-
# Decoration overlay control dialog
- if self.barscale.dialog:
- if self.barscale.dialog.IsShown():
- self.barscale.dialog.SetFocus()
- self.barscale.dialog.Raise()
- else:
- self.barscale.dialog.Show()
- else:
- # If location is latlon, only display north arrow (scale won't work)
- # proj = self.Map.projinfo['proj']
- # if proj == 'll':
- # barcmd = 'd.barscale -n'
- # else:
- # barcmd = 'd.barscale'
+ GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+ cmd, completed=(self.GetOptData, None, None))
- # decoration overlay control dialog
- GUI(parent=self, giface=self._giface, show=True, modal=False).ParseCommand(
- self.barscale.cmd, completed=(self.barscale.GetOptData, None, None))
-
self.MapWindow.mouse['use'] = 'pointer'
- def AddLegend(self, cmd=None, showDialog=None):
- """Handler for legend map decoration menu selection."""
- if self.legend.IsShown() and showDialog is None:
- self.legend.Hide()
- return
+ def AddLegendRast(self, cmd=None):
+ """Handler for legend raster map decoration menu selection."""
+
if cmd:
- self.legend.cmd = cmd
+ show = False
else:
+ show = True
+ cmd = ['d.legend']
layers = self._giface.GetLayerList().GetSelectedLayers()
for layer in layers:
if layer.type == 'raster':
- isMap = False
- # replace map
- for i, legendParam in enumerate(self.legend.cmd[1:]):
- idx = i + 1
- param_val = legendParam.split('=')
- if len(param_val) != 2:
- continue
- param, val = param_val
- if param == 'raster':
- self.legend.cmd[idx] = 'raster={rast}'.format(
- rast=layer.maplayer.name)
- isMap = True
- elif param in ('use', 'range'):
- # clear range or use to avoid problems
- del self.legend.cmd[idx]
-
- if not isMap: # for the first time
- self.legend.cmd.append(
- 'raster=%s' %
- layer.maplayer.name)
+ cmd.append('raster={rast}'.format(rast=layer.maplayer.name))
break
- if not showDialog and self.legend.CmdIsValid():
- self.legend.Show()
- return
+ GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+ cmd, completed=(self.GetOptData, None, None))
- # Decoration overlay control dialog
- # always create new one to avoid problem when switching between maps
- if self.legend.dialog:
- if self.legend.dialog.IsShown():
- self.legend.dialog.SetFocus()
- self.legend.dialog.Raise()
- else:
- self.legend.dialog.Destroy()
- self.legend.dialog = None
- if not self.legend.dialog:
- GUI(parent=self, giface=self._giface, show=True, modal=False).ParseCommand(
- self.legend.cmd, completed=(self.legend.GetOptData, None, None))
+ self.MapWindow.mouse['use'] = 'pointer'
+ def AddLegendVect(self, cmd=None, showDialog=None):
+ """Handler for legend vector map decoration menu selection."""
+
+ if cmd:
+ show = False
+ else:
+ show = True
+ cmd = ['d.legend.vect']
+
+ 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, showDialog=None):
+ def AddArrow(self, cmd=None):
"""Handler for north arrow menu selection."""
if self.IsPaneShown('3d'):
# here was opening of appearance page of nviz notebook
@@ -1310,96 +1270,70 @@
self.MapWindow3D.SetDrawArrow((70, 70))
return
- if self.arrow.IsShown() and showDialog is None:
- self.arrow.Hide()
- return
if cmd:
- self.arrow.cmd = cmd
+ show = False
+ else:
+ show = True
+ cmd = ['d.northarrow']
- if not showDialog:
- self.arrow.Show()
- return
-
# Decoration overlay control dialog
- if self.arrow.dialog:
- if self.arrow.dialog.IsShown():
- self.arrow.dialog.SetFocus()
- self.arrow.dialog.Raise()
- else:
- self.arrow.dialog.Show()
- else:
- GUI(parent=self, giface=self._giface, show=True, modal=False).ParseCommand(
- self.arrow.cmd, completed=(self.arrow.GetOptData, None, None))
+ GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+ cmd, completed=(self.GetOptData, None, None))
self.MapWindow.mouse['use'] = 'pointer'
- def OnAddText(self, event):
- """Handler for text decoration menu selection.
- """
- if self.MapWindow.dragid > -1:
- id = self.MapWindow.dragid
- self.MapWindow.dragid = -1
+ def AddDtext(self, cmd=None):
+ """Handler for d.text menu selection."""
+ if cmd:
+ show = False
else:
- # index for overlay layer in render
- if len(self.MapWindow.textdict.keys()) > 0:
- id = max(self.MapWindow.textdict.keys()) + 1
- else:
- id = 101
+ show = True
+ cmd = ['d.text']
- self.dialogs['text'] = TextLayerDialog(parent=self, ovlId=id,
- title=_('Add text layer'),
- size=(400, 200))
- self.dialogs['text'].CenterOnParent()
+ # Decoration overlay control dialog
+ GUI(parent=self, giface=self._giface, show=show, modal=False).ParseCommand(
+ cmd, completed=(self.GetOptData, None, None))
- # If OK button pressed in decoration control dialog
- if self.dialogs['text'].ShowModal() == wx.ID_OK:
- text = self.dialogs['text'].GetValues()['text']
- active = self.dialogs['text'].GetValues()['active']
+ self.MapWindow.mouse['use'] = 'pointer'
- # delete object if it has no text or is not active
- if text == '' or active == False:
- try:
- self.MapWindow2D.pdc.ClearId(id)
- self.MapWindow2D.pdc.RemoveId(id)
- del self.MapWindow.textdict[id]
- if self.IsPaneShown('3d'):
- self.MapWindow3D.UpdateOverlays()
- self.MapWindow.UpdateMap()
- else:
- self.MapWindow2D.UpdateMap(
- render=False, renderVector=False)
- except:
- pass
- return
+ def GetOptData(self, dcmd, layer, params, propwin):
+ """Called after options are set through module dialog.
- self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
+ :param dcmd: resulting command
+ :param layer: not used
+ :param params: module parameters (not used)
+ :param propwin: dialog window
+ """
- if self.IsPaneShown('3d'):
- self.MapWindow3D.UpdateOverlays()
- self.MapWindow3D.UpdateMap()
- else:
- self.MapWindow2D.pdc.ClearId(id)
- self.MapWindow2D.pdc.SetId(id)
- self.MapWindow2D.UpdateMap(render=False, renderVector=False)
+ if not dcmd:
+ return
+ if propwin in self._decorationWindows:
+ overlay = self._decorationWindows[propwin]
+ else:
+ cmd = dcmd[0]
+ if cmd == 'd.northarrow':
+ overlay = ArrowController(self.Map, self._giface)
+ elif cmd == 'd.barscale':
+ overlay = BarscaleController(self.Map, self._giface)
+ elif cmd == 'd.legend':
+ overlay = LegendController(self.Map, self._giface)
+ elif cmd == 'd.legend.vect':
+ overlay = LegendVectController(self.Map, self._giface)
+ elif cmd == 'd.text':
+ overlay = DtextController(self.Map, self._giface)
- self.MapWindow.mouse['use'] = 'pointer'
+ self.decorations[overlay.id] = overlay
+ overlay.overlayChanged.connect(lambda: self.MapWindow2D.UpdateMap(
+ render=False, renderVector=False))
+ if self.MapWindow3D:
+ overlay.overlayChanged.connect(self.MapWindow3D.UpdateOverlays)
- def GetOptData(self, dcmd, type, params, propwin):
- """Callback method for decoration overlay command generated by
- dialog created in menuform.py
- """
- # Reset comand and rendering options in render.Map. Always render decoration.
- # Showing/hiding handled by PseudoDC
- self.Map.ChangeOverlay(
- ovltype=type,
- type='overlay',
- name='',
- command=dcmd,
- active=True,
- render=False)
- self.params[type] = params
- self.propwin[type] = propwin
+ overlay.dialog = propwin
+ self._decorationWindows[propwin] = overlay
+ overlay.cmd = dcmd
+ overlay.Show()
+
def OnZoomToMap(self, event):
"""Set display extents to match selected raster (including
NULLs) or vector map.
Modified: grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/main.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/main.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/main.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -83,6 +83,7 @@
# TODO temporary solution, layer managment by different tools in GRASS
# should be resovled
self.ownedLayers = []
+ self.oldOverlays = []
if mapfile:
self.mapfileCmd = mapfile
@@ -103,6 +104,15 @@
self.renderMgr = RenderMapMgr(self)
+ # update legend file variable with the one d.mon uses
+ with open(monFile['env'], 'r') as f:
+ lines = f.readlines()
+ for line in lines:
+ if 'GRASS_LEGEND_FILE' in line:
+ legfile = line.split('=', 1)[1].strip()
+ self.renderMgr.UpdateRenderEnv({'GRASS_LEGEND_FILE': legfile})
+ break
+
def GetLayersFromCmdFile(self):
"""Get list of map layers from cmdfile
"""
@@ -141,6 +151,12 @@
self.query.emit(ltype=utils.split(dWhatCmd)[
0].split('.')[-1], maps=maps)
return
+ else:
+ # clean overlays after erase
+ self.oldOverlays = []
+ overlays = self._giface.GetMapDisplay().decorations.keys()
+ for each in overlays:
+ self._giface.GetMapDisplay().RemoveOverlay(each)
existingLayers = self.GetListOfLayers()
@@ -175,28 +191,36 @@
layerType=ltype)[0]
args = {}
- if ltype in ('barscale', 'rastleg', 'northarrow'):
- classLayer = Overlay
+
+ if ltype in ('barscale', 'rastleg', 'northarrow', 'text', 'vectleg'):
+ # TODO: this is still not optimal
+ # it is there to prevent adding the same overlay multiple times
+ if cmd in self.oldOverlays:
+ continue
if ltype == 'rastleg':
- args['id'] = 0
+ self._giface.GetMapDisplay().AddLegendRast(cmd=cmd)
elif ltype == 'barscale':
- args['id'] = 1
- else:
- args['id'] = 2
- else:
- classLayer = MapLayer
- args['ltype'] = ltype
+ self._giface.GetMapDisplay().AddBarscale(cmd=cmd)
+ elif ltype == 'northarrow':
+ self._giface.GetMapDisplay().AddArrow(cmd=cmd)
+ elif ltype == 'text':
+ self._giface.GetMapDisplay().AddDtext(cmd=cmd)
+ elif ltype == 'vectleg':
+ self._giface.GetMapDisplay().AddLegendVect(cmd=cmd)
+ self.oldOverlays.append(cmd)
+ continue
- mapLayer = classLayer(
- name=name,
- cmd=cmd,
- Map=None,
- hidden=True,
- render=False,
- mapfile=mapFile,
- **args)
- mapLayer.GetRenderMgr().updateProgress.connect(
- self.GetRenderMgr().ReportProgress)
+ classLayer = MapLayer
+ args['ltype'] = ltype
+
+ mapLayer = classLayer(name=name,
+ cmd=cmd,
+ Map=None,
+ hidden=True,
+ render=False,
+ mapfile=mapFile,
+ **args)
+ mapLayer.GetRenderMgr().updateProgress.connect(self.GetRenderMgr().ReportProgress)
if render_env:
mapLayer.GetRenderMgr().UpdateRenderEnv(render_env)
render_env = dict()
@@ -316,7 +340,23 @@
def __init__(self, map, giface):
self._map = map
self._giface = giface
+ self._index = 0
+ def __len__(self):
+ return len(self._map.GetListOfLayers())
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ items = self._map.GetListOfLayers()
+ try:
+ result = items[self._index]
+ except IndexError:
+ raise StopIteration
+ self._index += 1
+ return result
+
def GetSelectedLayers(self, checkedOnly=True):
# hidden and selected vs checked and selected
items = self._map.GetListOfLayers()
Modified: grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/toolbars.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/mapdisp/toolbars.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -32,11 +32,13 @@
label=_('Select vector feature(s)'),
desc=_('Select features interactively from vector map')),
'addBarscale': MetaIcon(img='scalebar-add',
- label=_('Show/hide scale bar')),
- 'addLegend': MetaIcon(img='legend-add',
- label=_('Show/hide legend')),
+ label=_('Add scale bar')),
+ 'addRasterLegend': MetaIcon(img='legend-add',
+ label=_('Add raster legend')),
+ 'addVectorLegend': MetaIcon(img='legend-add',
+ label=_('Add vector legend')),
'addNorthArrow': MetaIcon(img='north-arrow-add',
- label=_('Show/hide north arrow')),
+ label=_('Add north arrow')),
'analyze': MetaIcon(img='layer-raster-analyze',
label=_('Analyze map'),
desc=_('Measuring, profiling, histogramming, ...')),
@@ -49,7 +51,7 @@
'scatter': MetaIcon(img='layer-raster-profile',
label=_("Create bivariate scatterplot of raster maps")),
'addText': MetaIcon(img='text-add',
- label=_('Add text layer')),
+ label=_('Add text')),
'histogram': MetaIcon(img='layer-raster-histogram',
label=_('Create histogram of raster map')),
'vnet': MetaIcon(img='vector-tools',
@@ -267,14 +269,16 @@
"""Decorations overlay menu
"""
self._onMenu(
- ((MapIcons["addLegend"],
- lambda evt: self.parent.AddLegend()),
+ ((MapIcons["addRasterLegend"],
+ lambda evt: self.parent.AddLegendRast()),
+ (MapIcons["addVectorLegend"],
+ lambda evt: self.parent.AddLegendVect()),
(MapIcons["addBarscale"],
lambda evt: self.parent.AddBarscale()),
- (MapIcons["addNorthArrow"],
- lambda evt: self.parent.AddArrow()),
- (MapIcons["addText"],
- self.parent.OnAddText)))
+ (MapIcons["addNorthArrow"],
+ lambda evt: self.parent.AddArrow()),
+ (MapIcons["addText"],
+ lambda evt: self.parent.AddDtext())))
def ExitToolbars(self):
if self.parent.GetToolbar('vdigit'):
Modified: grass/branches/releasebranch_7_2/gui/wxpython/mapwin/base.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/mapwin/base.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/mapwin/base.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -125,7 +125,7 @@
# emitted after double click in pointer mode on legend, text, scalebar
self.overlayActivated = Signal('MapWindow.overlayActivated')
# emitted when overlay should be hidden
- self.overlayHidden = Signal('MapWindow.overlayHidden')
+ self.overlayRemoved = Signal('MapWindow.overlayRemoved')
# mouse attributes -- position on the screen, begin and end of
# dragging, and type of drawing
Modified: grass/branches/releasebranch_7_2/gui/wxpython/mapwin/buffered.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/mapwin/buffered.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/mapwin/buffered.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -160,15 +160,12 @@
self.img = None # wx.Image object (self.mapfile)
# decoration overlays
self.overlays = overlays
- self._overlayNames = {
- 0: _("legend"),
- 1: _("scale bar"),
- 2: _("north arrow")}
# images and their PseudoDC ID's for painting and dragging
self.imagedict = {}
self.select = {} # selecting/unselecting decorations for dragging
self.textdict = {} # text, font, and color indexed by id
+
# zoom objects
self.zoomhistory = [] # list of past zoom extents
self.currzoom = 0 # current set of extents in zoom history being used
@@ -274,27 +271,20 @@
pos = self.ScreenToClient(event.GetPosition())
idlist = self.pdc.FindObjects(pos[0], pos[1], self.hitradius)
- separator = True
- if idlist and idlist[0] in (0, 1, 2): # legend, scale bar, north arrow
- if separator:
- menu.AppendSeparator()
- separator = False
- self._hide = wx.NewId()
+ if self.overlays and idlist and [i for i in idlist if i in self.overlays.keys()]: # legend, scale bar, north arrow, dtext
+ menu.AppendSeparator()
+ removeId = wx.NewId()
self.Bind(wx.EVT_MENU,
- lambda evt: self.overlayHidden.emit(overlayId=idlist[0]),
- id=self._hide)
- menu.Append(
- self._hide,
- _("Hide {overlay}").format(
- overlay=self._overlayNames[
- idlist[0]]))
+ lambda evt: self.overlayRemoved.emit(overlayId=idlist[0]),
+ id=removeId)
+ menu.Append(removeId, self.overlays[idlist[0]].removeLabel)
- if idlist[0] == 0:
- self._resizeLegend = wx.NewId()
+ if self.overlays[idlist[0]].name == 'legend':
+ resizeLegendId = wx.NewId()
self.Bind(wx.EVT_MENU,
lambda evt: self.overlays[idlist[0]].StartResizing(),
- id=self._resizeLegend)
- menu.Append(self._resizeLegend, _("Resize legend"))
+ id=resizeLegendId)
+ menu.Append(resizeLegendId, _("Resize legend"))
self.PopupMenu(menu)
menu.Destroy()
@@ -1071,20 +1061,22 @@
if isinstance(r, list):
r = wx.Rect(r[0], r[1], r[2], r[3])
- if id > 100: # text dragging
+ if id in self.textdict: # text dragging
rtop = (r[0], r[1] - r[3], r[2], r[3])
r = r.Union(rtop)
rleft = (r[0] - r[2], r[1], r[2], r[3])
r = r.Union(rleft)
+
self.pdc.TranslateId(id, dx, dy)
r2 = self.pdc.GetIdBounds(id)
if isinstance(r2, list):
r2 = wx.Rect(r[0], r[1], r[2], r[3])
- if id > 100: # text
+ if id in self.textdict: # text
self.textdict[id]['bbox'] = r2
self.textdict[id]['coords'][0] += dx
self.textdict[id]['coords'][1] += dy
+
r = r.Union(r2)
r.Inflate(4, 4)
self.RefreshRect(r, False)
@@ -1514,6 +1506,7 @@
idlist.remove(99)
if idlist != []:
self.dragid = idlist[0] # drag whatever is on top
+
else:
pass
coords = self.Pixel2Cell(self.mouse['begin'])
@@ -1561,13 +1554,12 @@
self.dragid >= 0):
# end drag of overlay decoration
- if self.dragid < 99 and self.dragid in self.overlays:
+ if self.overlays and self.dragid in self.overlays:
self.overlays[
self.dragid].coords = self.pdc.GetIdBounds(
self.dragid)
- elif self.dragid > 100 and self.dragid in self.textdict:
- self.textdict[self.dragid][
- 'bbox'] = self.pdc.GetIdBounds(self.dragid)
+ elif self.dragid in self.textdict:
+ self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
else:
pass
self.dragid = None
@@ -1689,6 +1681,13 @@
self.digit:
self._onMouseMoving(event)
+ pos = event.GetPosition()
+ idlist = self.pdc.FindObjects(pos[0], pos[1], self.hitradius)
+ if self.overlays and idlist and [i for i in idlist if i in self.overlays.keys()]: # legend, scale bar, north arrow, dtext
+ self.SetToolTipString("Double click in Pointer mode to set object"
+ " properties,\nright click to remove")
+ else:
+ self.SetToolTip(None)
event.Skip()
def OnCopyCoordinates(self, event):
Modified: grass/branches/releasebranch_7_2/gui/wxpython/mapwin/decorations.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/mapwin/decorations.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/mapwin/decorations.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -22,7 +22,6 @@
from core.utils import _
import wx
-from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
from grass.pydispatch.signal import Signal
try:
@@ -32,12 +31,6 @@
hasPIL = False
-class OverlayId:
- legendId = 0
- barscaleId = 1
- arrowId = 2
-
-
class OverlayController(object):
"""Base class for decorations (barscale, legend) controller."""
@@ -52,7 +45,8 @@
self._defaultAt = ''
self._cmd = None # to be set by user
self._name = None # to be defined by subclass
- self._id = None # to be defined by subclass
+ self._removeLabel = None # to be defined by subclass
+ self._id = wx.NewId()
self._dialog = None
# signals that overlay or its visibility changed
@@ -97,6 +91,11 @@
name = property(fget=GetName)
+ def GetRemoveLabel(self):
+ return self._removeLabel
+
+ removeLabel = property(fget=GetRemoveLabel)
+
def GetId(self):
return self._id
@@ -145,22 +144,12 @@
self._overlay.SetActive(False)
self.overlayChanged.emit()
- def GetOptData(self, dcmd, layer, params, propwin):
- """Called after options are set through module dialog.
+ def Remove(self):
+ if self._dialog:
+ self._dialog.Destroy()
+ self._renderer.DeleteOverlay(self._overlay)
+ self.overlayChanged.emit()
- :param dcmd: resulting command
- :param layer: not used
- :param params: module parameters (not used)
- :param propwin: dialog window
- """
- if not dcmd:
- return
-
- self._cmd = dcmd
- self._dialog = propwin
-
- self.Show()
-
def _add(self):
self._overlay = self._renderer.AddOverlay(
id=self._id,
@@ -189,6 +178,7 @@
"Please install Python Imaging Library (PIL)\n"
"for better control of legend and other decorations."))
return 0, 0
+
for param in self._cmd:
if not param.startswith('at'):
continue
@@ -199,12 +189,35 @@
return x, y
+class DtextController(OverlayController):
+
+ def __init__(self, renderer, giface):
+ OverlayController.__init__(self, renderer, giface)
+ self._name = 'text'
+ self._removeLabel = _("Remove text")
+ self._defaultAt = 'at=50,50'
+ self._cmd = ['d.text', self._defaultAt]
+
+ def CmdIsValid(self):
+ inputs = 0
+ for param in self._cmd[1:]:
+ param = param.split('=')
+ if len(param) == 1:
+ inputs += 1
+ else:
+ if param[0] == 'text' and len(param) == 2:
+ inputs += 1
+ if inputs >= 1:
+ return True
+ return False
+
+
class BarscaleController(OverlayController):
def __init__(self, renderer, giface):
OverlayController.__init__(self, renderer, giface)
- self._id = OverlayId.barscaleId
self._name = 'barscale'
+ self._removeLabel = _("Remove scale bar")
# different from default because the reference point is not in the
# middle
self._defaultAt = 'at=0,98'
@@ -215,22 +228,34 @@
def __init__(self, renderer, giface):
OverlayController.__init__(self, renderer, giface)
- self._id = OverlayId.arrowId
self._name = 'arrow'
+ self._removeLabel = _("Remove north arrow")
# different from default because the reference point is not in the
# middle
self._defaultAt = 'at=85.0,25.0'
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):
def __init__(self, renderer, giface):
OverlayController.__init__(self, renderer, giface)
- self._id = OverlayId.legendId
self._name = 'legend'
- # TODO: synchronize with d.legend?
- self._defaultAt = 'at=5,50,7,10'
+ self._removeLabel = _("Remove legend")
+ # default is in the center to avoid trimmed legend on the edge
+ self._defaultAt = 'at=5,50,47,50'
self._cmd = ['d.legend', self._defaultAt]
def GetPlacement(self, screensize):
@@ -243,8 +268,12 @@
for param in self._cmd:
if not param.startswith('at'):
continue
- b, t, l, r = [float(number) for number in param.split(
- '=')[1].split(',')] # pylint: disable-msg=W0612
+ # if the at= is the default, we will move the legend from the center to bottom left
+ if param == self._defaultAt:
+ b, t, l, r = 5, 50, 7, 10
+ else:
+ b, t, l, r = [float(number) for number in param.split(
+ '=')[1].split(',')] # pylint: disable-msg=W0612
x = int((l / 100.) * screensize[0])
y = int((1 - t / 100.) * screensize[1])
@@ -313,202 +342,3 @@
self._giface.GetMapDisplay().GetMapToolbar().SelectDefault()
# redraw
self.overlayChanged.emit()
-
-
-class TextLayerDialog(wx.Dialog):
- """!Controls setting options and displaying/hiding map overlay decorations
- """
-
- def __init__(self, parent, ovlId, title, name='text', size=wx.DefaultSize,
- style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-
- wx.Dialog.__init__(
- self,
- parent=parent,
- id=wx.ID_ANY,
- title=title,
- style=style,
- size=size)
-
- self.ovlId = ovlId
- self.parent = parent
-
- if self.ovlId in self.parent.MapWindow.textdict.keys():
- self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
- self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
- self.currClr = self.parent.MapWindow.textdict[self.ovlId]['color']
- self.currRot = self.parent.MapWindow.textdict[
- self.ovlId]['rotation']
- self.currCoords = self.parent.MapWindow.textdict[
- self.ovlId]['coords']
- self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
- else:
- self.currClr = wx.BLACK
- self.currText = ''
- self.currFont = self.GetFont()
- self.currRot = 0.0
- self.currCoords = [10, 10]
- self.currBB = wx.Rect()
-
- self.sizer = wx.BoxSizer(wx.VERTICAL)
- box = wx.GridBagSizer(vgap=5, hgap=5)
-
- # show/hide
- self.chkbox = wx.CheckBox(parent=self, id=wx.ID_ANY,
- label=_('Show text object'))
- if self.parent.Map.GetOverlay(self.ovlId) is None:
- self.chkbox.SetValue(True)
- else:
- self.chkbox.SetValue(
- self.parent.MapWindow.overlays[
- self.ovlId]['layer'].IsActive())
- box.Add(item=self.chkbox, span=(1, 2),
- pos=(0, 0))
-
- # text entry
- box.Add(
- item=wx.StaticText(
- parent=self,
- id=wx.ID_ANY,
- label=_("Text:")),
- flag=wx.ALIGN_CENTER_VERTICAL,
- pos=(
- 1,
- 0))
-
- self.textentry = ExpandoTextCtrl(
- parent=self, id=wx.ID_ANY, value="", size=(300, -1))
- self.textentry.SetFont(self.currFont)
- self.textentry.SetForegroundColour(self.currClr)
- self.textentry.SetValue(self.currText)
- # get rid of unneeded scrollbar when text box first opened
- self.textentry.SetClientSize((300, -1))
-
- box.Add(item=self.textentry,
- flag=wx.EXPAND,
- pos=(1, 1))
-
- # rotation
- box.Add(
- item=wx.StaticText(
- parent=self,
- id=wx.ID_ANY,
- label=_("Rotation:")),
- flag=wx.ALIGN_CENTER_VERTICAL,
- pos=(
- 2,
- 0))
- self.rotation = wx.SpinCtrl(
- parent=self, id=wx.ID_ANY, value="", pos=(
- 30, 50), size=(
- 75, -1), style=wx.SP_ARROW_KEYS)
- self.rotation.SetRange(-360, 360)
- self.rotation.SetValue(int(self.currRot))
- box.Add(item=self.rotation,
- flag=wx.ALIGN_RIGHT,
- pos=(2, 1))
-
- # font
- box.Add(
- item=wx.StaticText(
- parent=self,
- id=wx.ID_ANY,
- label=_("Font:")),
- flag=wx.ALIGN_CENTER_VERTICAL,
- pos=(
- 3,
- 0))
- fontbtn = wx.Button(parent=self, id=wx.ID_ANY, label=_("Set font"))
- box.Add(item=fontbtn,
- flag=wx.ALIGN_RIGHT,
- pos=(3, 1))
-
- box.AddGrowableCol(1)
- box.AddGrowableRow(1)
- self.sizer.Add(item=box, proportion=1,
- flag=wx.ALL | wx.EXPAND, border=10)
-
- # note
- box = wx.BoxSizer(wx.HORIZONTAL)
- label = wx.StaticText(
- parent=self, id=wx.ID_ANY, label=_(
- "Drag text with mouse in pointer mode "
- "to position.\nDouble-click to change options"))
- box.Add(item=label, proportion=0,
- flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
- self.sizer.Add(
- item=box, proportion=0, flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER | wx.ALL, border=5)
-
- line = wx.StaticLine(parent=self, id=wx.ID_ANY,
- size=(20, -1), style=wx.LI_HORIZONTAL)
- self.sizer.Add(item=line, proportion=0,
- flag=wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border=5)
-
- btnsizer = wx.StdDialogButtonSizer()
-
- btn = wx.Button(parent=self, id=wx.ID_OK)
- btn.SetDefault()
- btnsizer.AddButton(btn)
-
- btn = wx.Button(parent=self, id=wx.ID_CANCEL)
- btnsizer.AddButton(btn)
- btnsizer.Realize()
-
- self.sizer.Add(item=btnsizer, proportion=0,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-
- self.SetSizer(self.sizer)
- self.sizer.Fit(self)
-
- # bindings
- self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
- self.Bind(wx.EVT_BUTTON, self.OnSelectFont, fontbtn)
- self.Bind(wx.EVT_TEXT, self.OnText, self.textentry)
- self.Bind(wx.EVT_SPINCTRL, self.OnRotation, self.rotation)
-
- self.SetMinSize((400, 230))
-
- def OnRefit(self, event):
- """Resize text entry to match text"""
- self.sizer.Fit(self)
-
- def OnText(self, event):
- """Change text string"""
- self.currText = event.GetString()
-
- def OnRotation(self, event):
- """Change rotation"""
- self.currRot = event.GetInt()
-
- event.Skip()
-
- def OnSelectFont(self, event):
- """Change font"""
- data = wx.FontData()
- data.EnableEffects(True)
- data.SetColour(self.currClr) # set colour
- data.SetInitialFont(self.currFont)
-
- dlg = wx.FontDialog(self, data)
-
- if dlg.ShowModal() == wx.ID_OK:
- data = dlg.GetFontData()
- self.currFont = data.GetChosenFont()
- self.currClr = data.GetColour()
-
- self.textentry.SetFont(self.currFont)
- self.textentry.SetForegroundColour(self.currClr)
-
- self.Layout()
-
- dlg.Destroy()
-
- def GetValues(self):
- """Get text properties"""
- return {'text': self.currText,
- 'font': self.currFont,
- 'color': self.currClr,
- 'rotation': self.currRot,
- 'coords': self.currCoords,
- 'active': self.chkbox.IsChecked()}
Modified: grass/branches/releasebranch_7_2/gui/wxpython/nviz/mapwindow.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/nviz/mapwindow.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/nviz/mapwindow.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -160,7 +160,6 @@
self.imagelist = []
self.overlay = wx.Overlay()
#self.pdc = wx.PseudoDC()
- self.textdict = {}
self.dragid = -1
self.hitradius = 5
# layer manager toolwindow
@@ -473,125 +472,36 @@
if texture.IsActive():
texture.Draw()
- def GetLegendRect(self):
- """Estimates legend size for dragging"""
- size = None
- if 0 in self.overlays:
- for param in self.overlays[0].cmd[1:]:
- if param.startswith("at="):
- size = map(float, param.split("=")[-1].split(','))
- break
- if size:
- wSize = self.GetClientSizeTuple()
- x, y = size[
- 2] / 100. * wSize[0], wSize[1] - (size[1] / 100. * wSize[1])
- x += self.overlays[1].coords[0]
- y += self.overlays[1].coords[1]
- w = (size[3] - size[2]) / 100. * wSize[0]
- h = (size[1] - size[0]) / 100. * wSize[1]
-
- rect = wx.Rect(x, y, w, h)
- return rect
-
- return wx.Rect()
-
- def DrawTextImage(self, textDict, relCoords):
- """Draw overlay text"""
- bmp = wx.EmptyBitmap(textDict['bbox'][2], textDict['bbox'][3])
- memDC = wx.MemoryDC()
- memDC.SelectObject(bmp)
-
- mask = self.view['background']['color']
- if mask == textDict['color']:
- mask = wx.WHITE
- memDC.SetBackground(wx.Brush(mask))
- memDC.Clear()
- memDC.SetFont(textDict['font'])
- memDC.SetTextForeground(textDict['color'])
- if textDict['rotation'] == 0:
- memDC.DrawText(textDict['text'], 0, 0)
- else:
- memDC.DrawRotatedText(textDict['text'], relCoords[0], relCoords[1],
- textDict['rotation'])
- bmp.SetMaskColour(mask)
- memDC.DrawBitmap(bmp, 0, 0, 1)
-
- filename = grass.tempfile(create=False) + '.png'
- bmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
- memDC.SelectObject(wx.NullBitmap)
-
- return filename
-
def UpdateOverlays(self):
- """Converts rendered overlay files and text labels to wx.Image
- and then to textures so that they can be rendered by OpenGL.
- Updates self.imagelist"""
+ """Renders overlays (legend, text).
+ Once this is done _onUpdateOverlays is called"""
self.Map.ChangeMapSize(self.GetClientSize())
self.Map.RenderOverlays(force=True)
- # delete textures
- for texture in self.imagelist:
- # inactive overlays, remove text labels
- if texture.GetId() < 100:
- if not self.overlays[texture.GetId()].IsShown():
- texture.SetActive(False)
- else:
- texture.SetActive(True)
- else: # text label
- if texture.GetId() not in self.textdict:
- self.imagelist.remove(texture)
-
- # update images (only legend so far)
+ def _onUpdateOverlays(self):
+ """Converts rendered overlay files and text labels to wx.Image
+ and then to textures so that they can be rendered by OpenGL.
+ Updates self.imagelist"""
+ # update images (legend and text)
for oid, overlay in self.overlays.iteritems():
- if not overlay.IsShown() or oid in (1, 2): # 0 for barscale
+ if not overlay.IsShown() or overlay.name in ('barscale', 'northarrow'):
continue
if oid not in [t.GetId() for t in self.imagelist]: # new
- self.CreateTexture(overlay=overlay.layer)
+ self.CreateTexture(overlay=overlay)
else:
for t in self.imagelist:
if t.GetId() == oid: # check if it is the same
if not t.Corresponds(overlay):
self.imagelist.remove(t)
- t = self.CreateTexture(overlay=overlay.layer)
+ t = self.CreateTexture(overlay=overlay)
- # update text labels
- for textId in self.textdict.keys():
- if textId not in [t.GetId() for t in self.imagelist]: # new
- self.CreateTexture(textId=textId)
- else:
- for t in self.imagelist:
- if t.GetId() == textId: # check if it is the same
- self.textdict[textId]['bbox'] = t.textDict['bbox']
- if not t.Corresponds(self.textdict[textId]):
- self.imagelist.remove(t)
- t = self.CreateTexture(textId=textId)
- # always set coordinates, needed for synchr. 2D and 3D
- # modes
- t.SetCoords(self.textdict[textId]['coords'])
self.Refresh()
- def CreateTexture(self, overlay=None, textId=None):
- """Create texture from overlay image or from textdict"""
- if overlay: # legend
- texture = wxnviz.ImageTexture(
- filepath=overlay.mapfile,
- overlayId=overlay.id,
- coords=list(
- self.overlays[
- overlay.id].coords),
- cmd=overlay.GetCmd())
- if overlay.id == 0: # legend
- texture.SetBounds(self.GetLegendRect())
- else: # text
- coords, bbox, relCoords = self.TextBounds(self.textdict[textId])
- self.textdict[textId]['coords'] = coords
- self.textdict[textId]['bbox'] = bbox
- file = self.DrawTextImage(self.textdict[textId], relCoords)
- texture = wxnviz.TextTexture(
- filepath=file, overlayId=textId, coords=coords,
- textDict=self.textdict[textId])
- bbox.OffsetXY(*relCoords)
- texture.SetBounds(bbox)
+ def CreateTexture(self, overlay):
+ """Create texture from overlay image"""
+ texture = wxnviz.ImageTexture(
+ filepath=overlay.layer.mapfile, overlayId=overlay.id,
+ coords=list(overlay.coords), cmd=overlay.GetCmd())
if not texture.textureId: # texture too big
GMessage(
@@ -605,6 +515,9 @@
return texture
+ def ClearTextures(self):
+ self.imagelist = []
+
def FindObjects(self, mouseX, mouseY, radius):
"""Find object which was clicked on"""
for texture in self.imagelist:
@@ -783,11 +696,12 @@
self.SetDrawScalebar((pos[0], size[1] - pos[1]))
if self.mouse['use'] == 'pointer':
- # get decoration or text id
+ # get decoration id
self.dragid = self.FindObjects(
self.mouse['tmp'][0],
self.mouse['tmp'][1],
self.hitradius)
+
if self.mouse['use'] == 'fly':
if not self.timerFly.IsRunning():
self.timerFly.Start(self.fly['interval'])
@@ -895,17 +809,11 @@
if self.dragid >= 0:
dx = self.mouse['end'][0] - self.mouse['begin'][0]
dy = self.mouse['end'][1] - self.mouse['begin'][1]
- if self.dragid < 99:
+ if self.dragid in self.overlays:
coords = self.overlays[self.dragid].coords
self.overlays[
self.dragid].coords = [
coords[0] + dx, coords[1] + dy]
- else: # text
- coords = self.textdict[self.dragid]['coords']
- self.textdict[
- self.dragid]['coords'] = [
- coords[0] + dx,
- coords[1] + dy]
self.dragid = -1
self.render['quick'] = False
self.Refresh(False)
@@ -2764,13 +2672,6 @@
"""
self.lmgr.nviz.OnResetView(None)
- def TextBounds(self, textinfo):
- """Return text boundary data
-
- :param textinfo: text metadata (text, font, color, rotation)
- """
- return self.parent.MapWindow2D.TextBounds(textinfo, relcoords=True)
-
def DisactivateWin(self):
"""Use when the class instance is hidden in MapFrame."""
pass
Modified: grass/branches/releasebranch_7_2/gui/wxpython/nviz/wxnviz.py
===================================================================
--- grass/branches/releasebranch_7_2/gui/wxpython/nviz/wxnviz.py 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/gui/wxpython/nviz/wxnviz.py 2016-08-21 22:54:25 UTC (rev 69199)
@@ -49,7 +49,7 @@
from grass.lib.raster import *
from core.debug import Debug
-from core.utils import _
+from core.utils import _, autoCropImageFromFile
import grass.script as grass
log = None
@@ -2041,12 +2041,11 @@
:param coords: image coordinates
"""
self.path = filepath
- self.image = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
- self.width = self.image.GetWidth()
- self.height = self.image.GetHeight()
+ self.image = autoCropImageFromFile(filepath)
+ self.width = self.orig_width = self.image.GetWidth()
+ self.height = self.orig_height = self.image.GetHeight()
self.id = overlayId
- self.coords = [0, 0]
- self.bounds = wx.Rect()
+ self.coords = coords
self.active = True
# alpha needs to be initialized
@@ -2131,12 +2130,8 @@
self.height,
self.textureId)
- def SetBounds(self, rect):
- """Set Bounding Rectangle"""
- self.bounds = rect
-
def HitTest(self, x, y, radius):
- copy = wx.Rect(*self.bounds)
+ copy = wx.Rect(self.coords[0], self.coords[1], self.orig_width, self.orig_height)
copy.Inflate(radius, radius)
return copy.ContainsXY(x, y)
@@ -2144,7 +2139,6 @@
"""Move texture on the screen"""
self.coords[0] += dx
self.coords[1] += dy
- self.bounds.OffsetXY(dx, dy)
def SetCoords(self, coords):
"""Set coordinates"""
@@ -2188,37 +2182,3 @@
def Corresponds(self, item):
return sorted(self.GetCmd()) == sorted(item.GetCmd())
-
-
-class TextTexture(Texture):
- """Class representing OpenGL texture as a text label"""
-
- def __init__(self, filepath, overlayId, coords, textDict):
- """Load image to texture
-
- :param filepath: path to image file
- :param overlayId: id of overlay (101 and more for text)
- :param coords: text coordinates
- :param textDict: text properties
- """
- Texture.__init__(
- self,
- filepath=filepath,
- overlayId=overlayId,
- coords=coords)
-
- self.textDict = textDict
-
- def GetTextDict(self):
- """Returns text properties."""
- return self.textDict
-
- def Corresponds(self, item):
- t = self.GetTextDict()
- for prop in t.keys():
- if prop in ('coords', 'bbox'):
- continue
- if t[prop] != item[prop]:
- return False
-
- return True
Modified: grass/branches/releasebranch_7_2/include/symbol.h
===================================================================
--- grass/branches/releasebranch_7_2/include/symbol.h 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/include/symbol.h 2016-08-21 22:54:25 UTC (rev 69199)
@@ -67,6 +67,8 @@
typedef struct
{
double scale; /* to get symbol of size 1, each vertex must be multiplied by this scale */
+ double yscale; /* scale in x dimension */
+ double xscale; /* scale in y dimension */
int count, alloc; /* numer of parts */
SYMBPART **part; /* objects ( parts ) */
} SYMBOL;
Modified: grass/branches/releasebranch_7_2/lib/symbol/Makefile
===================================================================
--- grass/branches/releasebranch_7_2/lib/symbol/Makefile 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/lib/symbol/Makefile 2016-08-21 22:54:25 UTC (rev 69199)
@@ -7,7 +7,7 @@
SYMBOL_SRC := $(wildcard symbol/*/*)
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
$(MAKE) $(SYMBOL_DST)
Modified: grass/branches/releasebranch_7_2/lib/symbol/read.c
===================================================================
--- grass/branches/releasebranch_7_2/lib/symbol/read.c 2016-08-21 22:40:25 UTC (rev 69198)
+++ grass/branches/releasebranch_7_2/lib/symbol/read.c 2016-08-21 22:54:25 UTC (rev 69199)
@@ -312,10 +312,14 @@
sprintf(buf, "Incorrect box definition: '%s'", data);
return (err(fp, symb, buf));
}
- if (x2 - x > y2 - y)
- symb->scale = 1 / (x2 - x);
- else
- symb->scale = 1 / (y2 - y);
+ symb->xscale = 1 / (x2 - x);
+ symb->yscale = 1 / (y2 - y);
+ if (x2 - x > y2 - y) {
+ symb->scale = symb->xscale;
+ }
+ else {
+ symb->scale = symb->yscale;
+ }
}
else if (strcmp(key, "STRING") == 0) {
G_debug(4, " STRING >");
Added: grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area
===================================================================
--- grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area (rev 0)
+++ grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area 2016-08-21 22:54:25 UTC (rev 69199)
@@ -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
+
Added: grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area_curved
===================================================================
--- grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area_curved (rev 0)
+++ grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/area_curved 2016-08-21 22:54:25 UTC (rev 69199)
@@ -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
+
Added: grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line
===================================================================
--- grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line (rev 0)
+++ grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line 2016-08-21 22:54:25 UTC (rev 69199)
@@ -0,0 +1,8 @@
+VERSION 1.0
+BOX -1 -1 1 1
+STRING
+ LINE
+ -1 0
+ 1 0
+ END
+END
Added: grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line_crooked
===================================================================
--- grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line_crooked (rev 0)
+++ grass/branches/releasebranch_7_2/lib/symbol/symbol/legend/line_crooked 2016-08-21 22:54:25 UTC (rev 69199)
@@ -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
More information about the grass-commit
mailing list