2 @package modules::mcalc_builder
4 @brief Map calculator, GUI wrapper for r.mapcalc
7 - mcalc_builder::MapCalcFrame
9 (C) 2008, 2011-2012 by the GRASS Development Team
11 This program is free software under the GNU General Public License
12 (>=v2). Read the file COPYING that comes with GRASS for details.
14 @author Michael Barton, Arizona State University
15 @author Martin Landa <landa.martin gmail.com>
16 @author Tim Michelsen (load/save expression)
26 if __name__ ==
"__main__":
27 sys.path.append(os.path.join(os.getenv(
'GISBASE'),
'etc',
'wxpython'))
29 from core
import globalvar
36 """!Mapcalc Frame class. Calculator-style window to create and run
37 r(3).mapcalc statements.
39 def __init__(self, parent, cmd, id = wx.ID_ANY,
40 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, **kwargs):
43 self.
log = self.parent.GetLogWindow()
50 if self.
cmd ==
'r.mapcalc':
52 title = _(
'GRASS GIS Raster Map Calculator')
53 if self.
cmd ==
'r3.mapcalc':
55 title = _(
'GRASS GIS 3D Raster Map Calculator')
57 wx.Frame.__init__(self, parent, id = id, title = title, **kwargs)
58 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR,
'grass.ico'), wx.BITMAP_TYPE_ICO))
60 self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
61 self.CreateStatusBar()
72 'atan(x,y)':
'atan( , )',
74 'double(x)':
'double()',
75 'eval([x,y,...,]z)':
'eval()',
77 'exp(x,y)':
'exp( , )',
79 'graph(x,x1,y1[x2,y2..])':
'graph( , , )',
82 'if(x,a,b)':
'if( , , )',
83 'if(x,a,b,c)':
'if( , , , )',
85 'isnull(x)':
'isnull()',
87 'log(x,b)':
'log( , )',
88 'max(x,y[,z...])':
'max( , )',
89 'median(x,y[,z...])':
'median( , )',
90 'min(x,y[,z...])':
'min( , )',
91 'mode(x,y[,z...])':
'mode( , )',
93 'pow(x,y)':
'pow( , )',
94 'rand(a,b)':
'rand( , )',
99 'xor(x,y)':
'xor( , )',
122 label=
" %s " % _(
'Operators'))
124 label=
" %s " % _(
'Output'))
126 label=
" %s " % _(
'Operands'))
128 label=
" %s " % _(
'Expression'))
135 self.
btn_run = wx.Button(parent = self.
panel, id = wx.ID_ANY, label = _(
"&Run"))
136 self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
137 self.btn_run.SetDefault()
140 self.btn_save.SetToolTipString(_(
'Save expression to file'))
143 self.btn_load.SetToolTipString(_(
'Load expression from file'))
146 self.
btn[
'pow'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"^")
147 self.
btn[
'pow'].SetToolTipString(_(
'exponent'))
148 self.
btn[
'div'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"/")
149 self.
btn[
'div'].SetToolTipString(_(
'divide'))
150 self.
btn[
'add'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"+")
151 self.
btn[
'add'].SetToolTipString(_(
'add'))
152 self.
btn[
'minus'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"-")
153 self.
btn[
'minus'].SetToolTipString(_(
'subtract'))
154 self.
btn[
'mod'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"%")
155 self.
btn[
'mod'].SetToolTipString(_(
'modulus'))
156 self.
btn[
'mult'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"*")
157 self.
btn[
'mult'].SetToolTipString(_(
'multiply'))
159 self.
btn[
'parenl'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"(")
160 self.
btn[
'parenr'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
")")
161 self.
btn[
'lshift'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"<<")
162 self.
btn[
'lshift'].SetToolTipString(_(
'left shift'))
163 self.
btn[
'rshift'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">>")
164 self.
btn[
'rshift'].SetToolTipString(_(
'right shift'))
165 self.
btn[
'rshiftu'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">>>")
166 self.
btn[
'rshiftu'].SetToolTipString(_(
'right shift (unsigned)'))
167 self.
btn[
'gt'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">")
168 self.
btn[
'gt'].SetToolTipString(_(
'greater than'))
169 self.
btn[
'gteq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
">=")
170 self.
btn[
'gteq'].SetToolTipString(_(
'greater than or equal to'))
171 self.
btn[
'lt'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"<")
172 self.
btn[
'lt'].SetToolTipString(_(
'less than'))
173 self.
btn[
'lteq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"<=")
174 self.
btn[
'lteq'].SetToolTipString(_(
'less than or equal to'))
175 self.
btn[
'eq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"==")
176 self.
btn[
'eq'].SetToolTipString(_(
'equal to'))
177 self.
btn[
'noteq'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"!=")
178 self.
btn[
'noteq'].SetToolTipString(_(
'not equal to'))
180 self.
btn[
'compl'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"~")
181 self.
btn[
'compl'].SetToolTipString(_(
'one\'s complement'))
182 self.
btn[
'not'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"!")
183 self.
btn[
'not'].SetToolTipString(_(
'NOT'))
184 self.
btn[
'andbit'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
'&&')
185 self.
btn[
'andbit'].SetToolTipString(_(
'bitwise AND'))
186 self.
btn[
'orbit'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"|")
187 self.
btn[
'orbit'].SetToolTipString(_(
'bitwise OR'))
188 self.
btn[
'and'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"&&&&")
189 self.
btn[
'and'].SetToolTipString(_(
'logical AND'))
190 self.
btn[
'andnull'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"&&&&&&")
191 self.
btn[
'andnull'].SetToolTipString(_(
'logical AND (ignores NULLs)'))
192 self.
btn[
'or'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"||")
193 self.
btn[
'or'].SetToolTipString(_(
'logical OR'))
194 self.
btn[
'ornull'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"|||")
195 self.
btn[
'ornull'].SetToolTipString(_(
'logical OR (ignores NULLs)'))
196 self.
btn[
'cond'] = wx.Button(parent = self.
panel, id = wx.ID_ANY, label =
"a ? b : c")
197 self.
btn[
'cond'].SetToolTipString(_(
'conditional'))
203 style = wx.TE_MULTILINE)
204 wx.CallAfter(self.text_mcalc.SetFocus)
210 self.newmaplabel.SetLabel(_(
'Name for new 3D raster map to create'))
212 self.newmaplabel.SetLabel(_(
'Name for new raster map to create'))
213 self.
newmaptxt = wx.TextCtrl(parent = self.
panel, id = wx.ID_ANY, size=(250, -1))
216 self.mapsellabel.SetLabel(_(
'Insert existing 3D raster map'))
218 self.mapsellabel.SetLabel(_(
'Insert existing raster map'))
220 type = element, multiple =
False)
222 label = _(
'Insert mapcalc function'))
224 size = (250, -1), choices = sorted(self.funct_dict.keys()),
225 style = wx.CB_DROPDOWN |
226 wx.CB_READONLY | wx.TE_PROCESS_ENTER)
229 label=_(
'Add created raster map into layer tree'), style = wx.NO_BORDER)
230 self.addbox.SetValue(UserSettings.Get(group=
'cmd', key=
'addNewLayer', subkey=
'enabled'))
231 if not self.
parent or self.parent.GetName() !=
'LayerManager':
237 for btn
in self.btn.keys():
238 self.
btn[btn].Bind(wx.EVT_BUTTON, self.
AddMark)
240 self.btn_close.Bind(wx.EVT_BUTTON, self.
OnClose)
241 self.btn_clear.Bind(wx.EVT_BUTTON, self.
OnClear)
242 self.btn_run.Bind(wx.EVT_BUTTON, self.
OnMCalcRun)
243 self.btn_help.Bind(wx.EVT_BUTTON, self.
OnHelp)
249 self.function.Bind(wx.EVT_TEXT_ENTER, self.
OnSelect)
255 self.SetMinSize(self.GetBestSize())
257 def _return_funct(self,event):
258 i = event.GetString()
262 sizer = wx.BoxSizer(wx.VERTICAL)
264 controlSizer = wx.BoxSizer(wx.HORIZONTAL)
265 operatorSizer = wx.StaticBoxSizer(self.
operatorBox, wx.HORIZONTAL)
266 outOpeSizer = wx.BoxSizer(wx.VERTICAL)
268 buttonSizer1 = wx.GridBagSizer(5, 1)
269 buttonSizer1.Add(item = self.
btn[
'add'], pos = (0,0))
270 buttonSizer1.Add(item = self.
btn[
'minus'], pos = (0,1))
271 buttonSizer1.Add(item = self.
btn[
'mod'], pos = (5,0))
272 buttonSizer1.Add(item = self.
btn[
'mult'], pos = (1,0))
273 buttonSizer1.Add(item = self.
btn[
'div'], pos = (1,1))
274 buttonSizer1.Add(item = self.
btn[
'pow'], pos = (5,1))
275 buttonSizer1.Add(item = self.
btn[
'gt'], pos = (2,0))
276 buttonSizer1.Add(item = self.
btn[
'gteq'], pos = (2,1))
277 buttonSizer1.Add(item = self.
btn[
'eq'], pos = (4,0))
278 buttonSizer1.Add(item = self.
btn[
'lt'], pos = (3,0))
279 buttonSizer1.Add(item = self.
btn[
'lteq'], pos = (3,1))
280 buttonSizer1.Add(item = self.
btn[
'noteq'], pos = (4,1))
282 buttonSizer2 = wx.GridBagSizer(5, 1)
283 buttonSizer2.Add(item = self.
btn[
'and'], pos = (0,0))
284 buttonSizer2.Add(item = self.
btn[
'andbit'], pos = (1,0))
285 buttonSizer2.Add(item = self.
btn[
'andnull'], pos = (2,0))
286 buttonSizer2.Add(item = self.
btn[
'or'], pos = (0,1))
287 buttonSizer2.Add(item = self.
btn[
'orbit'], pos = (1,1))
288 buttonSizer2.Add(item = self.
btn[
'ornull'], pos = (2,1))
289 buttonSizer2.Add(item = self.
btn[
'lshift'], pos = (3,0))
290 buttonSizer2.Add(item = self.
btn[
'rshift'], pos = (3,1))
291 buttonSizer2.Add(item = self.
btn[
'rshiftu'], pos = (4,0))
292 buttonSizer2.Add(item = self.
btn[
'cond'], pos = (5,0))
293 buttonSizer2.Add(item = self.
btn[
'compl'], pos = (5,1))
294 buttonSizer2.Add(item = self.
btn[
'not'], pos = (4,1))
296 outputSizer = wx.StaticBoxSizer(self.
outputBox, wx.VERTICAL)
298 flag = wx.ALIGN_CENTER | wx.BOTTOM | wx.TOP, border = 5)
302 operandSizer = wx.StaticBoxSizer(self.
operandBox, wx.HORIZONTAL)
303 buttonSizer3 = wx.GridBagSizer(7, 1)
304 buttonSizer3.Add(item = self.
functlabel, pos = (0,0),
305 span = (1,2), flag = wx.ALIGN_CENTER)
306 buttonSizer3.Add(item = self.
function, pos = (1,0),
308 buttonSizer3.Add(item = self.
mapsellabel, pos = (2,0),
309 span = (1,2), flag = wx.ALIGN_CENTER)
310 buttonSizer3.Add(item = self.
mapselect, pos = (3,0),
312 threebutton = wx.GridBagSizer(1, 2)
313 threebutton.Add(item = self.
btn[
'parenl'], pos = (0,0),
314 span = (1,1), flag = wx.ALIGN_LEFT)
315 threebutton.Add(item = self.
btn[
'parenr'], pos = (0,1),
316 span = (1,1), flag = wx.ALIGN_CENTER)
317 threebutton.Add(item = self.
btn_clear, pos = (0,2),
318 span = (1,1), flag = wx.ALIGN_RIGHT)
319 buttonSizer3.Add(item = threebutton, pos = (4,0),
320 span = (1,1), flag = wx.ALIGN_CENTER)
322 buttonSizer4 = wx.BoxSizer(wx.HORIZONTAL)
323 buttonSizer4.AddSpacer(10)
324 buttonSizer4.Add(item = self.
btn_load,
325 flag = wx.ALL, border = 5)
326 buttonSizer4.Add(item = self.
btn_save,
327 flag = wx.ALL, border = 5)
328 buttonSizer4.AddSpacer(30)
329 buttonSizer4.Add(item = self.
btn_help,
330 flag = wx.ALL, border = 5)
331 buttonSizer4.Add(item = self.
btn_run,
332 flag = wx.ALL, border = 5)
334 flag = wx.ALL, border = 5)
336 operatorSizer.Add(item = buttonSizer1, proportion = 0,
337 flag = wx.ALL | wx.EXPAND, border = 5)
338 operatorSizer.Add(item = buttonSizer2, proportion = 0,
339 flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND, border = 5)
341 operandSizer.Add(item = buttonSizer3, proportion = 0,
342 flag = wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
344 controlSizer.Add(item = operatorSizer, proportion = 1,
345 flag = wx.RIGHT | wx.EXPAND, border = 5)
346 outOpeSizer.Add(item = outputSizer, proportion = 0,
348 outOpeSizer.Add(item = operandSizer, proportion = 1,
349 flag = wx.EXPAND | wx.TOP, border = 5)
350 controlSizer.Add(item = outOpeSizer, proportion = 0,
353 expressSizer = wx.StaticBoxSizer(self.
expressBox, wx.HORIZONTAL)
354 expressSizer.Add(item = self.
text_mcalc, proportion = 1,
357 sizer.Add(item = controlSizer, proportion = 0,
358 flag = wx.EXPAND | wx.ALL,
360 sizer.Add(item = expressSizer, proportion = 1,
361 flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
363 sizer.Add(item = buttonSizer4, proportion = 0,
364 flag = wx.ALIGN_RIGHT | wx.ALL, border = 3)
365 if self.addbox.IsShown():
366 sizer.Add(item = self.
addbox, proportion = 0,
367 flag = wx.LEFT | wx.RIGHT,
370 self.panel.SetAutoLayout(
True)
371 self.panel.SetSizer(sizer)
372 sizer.Fit(self.
panel)
377 """!Sends operators to insertion method
379 if event.GetId() == self.
btn[
'compl'].GetId(): mark =
"~"
380 elif event.GetId() == self.
btn[
'not'].GetId(): mark =
"!"
381 elif event.GetId() == self.
btn[
'pow'].GetId(): mark =
"^"
382 elif event.GetId() == self.
btn[
'div'].GetId(): mark =
"/"
383 elif event.GetId() == self.
btn[
'add'].GetId(): mark =
"+"
384 elif event.GetId() == self.
btn[
'minus'].GetId(): mark =
"-"
385 elif event.GetId() == self.
btn[
'mod'].GetId(): mark =
"%"
386 elif event.GetId() == self.
btn[
'mult'].GetId(): mark =
"*"
387 elif event.GetId() == self.
btn[
'lshift'].GetId(): mark =
"<<"
388 elif event.GetId() == self.
btn[
'rshift'].GetId(): mark =
">>"
389 elif event.GetId() == self.
btn[
'rshiftu'].GetId(): mark =
">>>"
390 elif event.GetId() == self.
btn[
'gt'].GetId(): mark =
">"
391 elif event.GetId() == self.
btn[
'gteq'].GetId(): mark =
">="
392 elif event.GetId() == self.
btn[
'lt'].GetId(): mark =
"<"
393 elif event.GetId() == self.
btn[
'lteq'].GetId(): mark =
"<="
394 elif event.GetId() == self.
btn[
'eq'].GetId(): mark =
"=="
395 elif event.GetId() == self.
btn[
'noteq'].GetId(): mark =
"!="
396 elif event.GetId() == self.
btn[
'andbit'].GetId(): mark =
"&"
397 elif event.GetId() == self.
btn[
'orbit'].GetId(): mark =
"|"
398 elif event.GetId() == self.
btn[
'or'].GetId(): mark =
"||"
399 elif event.GetId() == self.
btn[
'ornull'].GetId(): mark =
"|||"
400 elif event.GetId() == self.
btn[
'and'].GetId(): mark =
"&&"
401 elif event.GetId() == self.
btn[
'andnull'].GetId(): mark =
"&&&"
402 elif event.GetId() == self.
btn[
'cond'].GetId(): mark =
" ? : "
403 elif event.GetId() == self.
btn[
'parenl'].GetId(): mark =
"("
404 elif event.GetId() == self.
btn[
'parenr'].GetId(): mark =
")"
408 """!Checks if user is typing or the event was emited by map selection.
409 Prevents from changing focus.
411 item = event.GetString()
412 if not (abs(len(item) - len(self.
lastMapName)) == 1
and \
418 """!Gets raster map or function selection and send it to
421 Checks for characters which can be in raster map name but
422 the raster map name must be then quoted.
424 item = event.GetString().strip()
426 item =
'"' + item +
'"'
430 """!Update statusbar text"""
431 expr = self.text_mcalc.GetValue().strip().replace(
"\n",
" ")
435 self.SetStatusText(
"{cmd} '{new} = {expr}'".format(cmd=cmd, expr=expr,
436 new=self.newmaptxt.GetValue()))
439 def _addSomething(self, what):
440 """!Inserts operators, map names, and functions into text area
442 self.text_mcalc.SetFocus()
443 mcalcstr = self.text_mcalc.GetValue()
444 position = self.text_mcalc.GetInsertionPoint()
446 newmcalcstr = mcalcstr[:position]
450 if newmcalcstr[-1] !=
' ':
456 newmcalcstr += what +
' ' + mcalcstr[position:]
458 self.text_mcalc.SetValue(newmcalcstr)
460 match = re.search(pattern=
"\(.*\)", string=what)
462 position_offset += match.start() + 1
464 position_offset += len(what)
466 self.text_mcalc.SetInsertionPoint(position + position_offset)
467 self.text_mcalc.Update()
470 """!Builds and runs r.mapcalc statement
472 name = self.newmaptxt.GetValue().strip()
474 GError(parent = self,
475 message = _(
"You must enter the name of "
476 "a new raster map to create."))
479 if not (name[0] ==
'"' and name[-1] ==
'"')
and any((char
in name)
for char
in self.
charactersToQuote):
480 name =
'"' + name +
'"'
482 expr = self.text_mcalc.GetValue().strip().replace(
"\n",
" ")
484 GError(parent = self,
485 message = _(
"You must enter an expression "
486 "to create a new raster map."))
490 cmd = [self.
cmd, str(
'%s = %s' % (name, expr))]
491 self.log.RunCmd(cmd, onDone = self.
OnDone)
498 """!Add create map to the layer tree"""
499 if not self.addbox.IsChecked():
501 name = self.newmaptxt.GetValue().strip(
' "') +
'@' + grass.gisenv()[
'MAPSET']
507 mapTree = self.parent.GetLayerTree()
508 if not mapTree.GetMap().GetListOfLayers(l_name = name):
509 mapTree.AddLayer(ltype = ltype,
511 lcmd = [lcmd,
'map=%s' % name],
514 display = self.parent.GetLayerTree().GetMapDisplay()
515 if display
and display.IsAutoRendered():
516 display.GetWindow().UpdateMap(render =
True)
519 """!Saves expression to file
521 mctxt = self.newmaptxt.GetValue() +
' = ' + self.text_mcalc.GetValue() + os.linesep
524 dlg = wx.FileDialog(parent = self,
525 message = _(
"Choose a file name to save the expression"),
526 wildcard = _(
"Expression file (*)|*"),
527 style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
528 if dlg.ShowModal() == wx.ID_OK:
535 fobj = open(path,
'w')
543 """!Load expression from file
545 dlg = wx.FileDialog(parent = self,
546 message = _(
"Choose a file name to load the expression"),
547 wildcard = _(
"Expression file (*)|*"),
549 if dlg.ShowModal() == wx.ID_OK:
556 fobj = open(path,
'r')
562 result, exp = mctxt.split(
'=', 1)
567 self.newmaptxt.SetValue(result.strip())
568 self.text_mcalc.SetValue(exp.strip())
569 self.text_mcalc.SetFocus()
570 self.text_mcalc.SetInsertionPointEnd()
577 self.text_mcalc.SetValue(
'')
580 """!Launches r.mapcalc help
588 if __name__ ==
"__main__":
590 gettext.install(
'grasswxpy', os.path.join(os.getenv(
"GISBASE"),
'locale'), unicode =
True)
def OnLoadExpression
Load expression from file.
def OnUpdateStatusBar
Update statusbar text.
Custom control that selects elements.
def OnSaveExpression
Saves expression to file.
def OnSelect
Gets raster map or function selection and send it to insertion method.
def OnClear
Clears text area.
def OnDone
Add create map to the layer tree.
def OnSelectTextEvt
Checks if user is typing or the event was emited by map selection.
def OnHelp
Launches r.mapcalc help.
def _addSomething
Inserts operators, map names, and functions into text area.
def RunCommand
Run GRASS command.
def OnMCalcRun
Builds and runs r.mapcalc statement.
def AddMark
Sends operators to insertion method.