frame.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. """!
  2. @package iscatt.frame
  3. @brief Main scatter plot widgets.
  4. Classes:
  5. - frame::IClassIScattPanel
  6. - frame::IScattDialog
  7. - frame::MapDispIScattPanel
  8. - frame::ScatterPlotsPanel
  9. - frame::CategoryListCtrl
  10. (C) 2013 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.
  13. @author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
  14. """
  15. import os
  16. import sys
  17. import wx
  18. import wx.lib.scrolledpanel as scrolled
  19. import wx.lib.mixins.listctrl as listmix
  20. from core import globalvar
  21. from core.gcmd import GException, GError, RunCommand
  22. from gui_core.gselect import Select
  23. from gui_core.dialogs import SetOpacityDialog
  24. from iscatt.controllers import ScattsManager
  25. from iscatt.toolbars import MainToolbar, EditingToolbar, CategoryToolbar
  26. from iscatt.iscatt_core import idScattToidBands
  27. from iscatt.dialogs import ManageBusyCursorMixin, RenameClassDialog
  28. from iscatt.plots import ScatterPlotWidget
  29. from iclass.dialogs import ContrastColor
  30. try:
  31. from agw import aui
  32. except ImportError:
  33. import wx.lib.agw.aui as aui
  34. class IClassIScattPanel(wx.Panel, ManageBusyCursorMixin):
  35. def __init__(self, parent, giface, iclass_mapwin = None,
  36. id = wx.ID_ANY):
  37. #wx.SplitterWindow.__init__(self, parent = parent, id = id,
  38. # style = wx.SP_LIVE_UPDATE)
  39. wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
  40. ManageBusyCursorMixin.__init__(self, window=self)
  41. self.scatt_mgr = self._createScattMgr(guiparent=parent, giface=giface,
  42. iclass_mapwin=iclass_mapwin)
  43. # toobars
  44. self.toolbars = {}
  45. self.toolbars['mainToolbar'] = self._createMainToolbar()
  46. self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
  47. self._createCategoryPanel(self)
  48. self.plot_panel = ScatterPlotsPanel(self, self.scatt_mgr)
  49. self.mainsizer = wx.BoxSizer(wx.VERTICAL)
  50. self.mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
  51. self.mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
  52. self.mainsizer.Add(item = self.catsPanel, proportion = 0,
  53. flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
  54. self.mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
  55. self.catsPanel.Hide()
  56. self.toolbars['editingToolbar'].Hide()
  57. self.SetSizer(self.mainsizer)
  58. self.scatt_mgr.computingStarted.connect(lambda : self.UpdateCur(busy=True))
  59. self.scatt_mgr.renderingStarted.connect(lambda : self.UpdateCur(busy=True))
  60. self.scatt_mgr.renderingFinished.connect(lambda : self.UpdateCur(busy=False))
  61. #self.SetSashGravity(0.5)
  62. #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
  63. self.Layout()
  64. def CloseWindow(self):
  65. self.scatt_mgr.CleanUp()
  66. def UpdateCur(self, busy):
  67. self.plot_panel.SetBusy(busy)
  68. ManageBusyCursorMixin.UpdateCur(self, busy)
  69. def _selCatInIScatt(self):
  70. return False
  71. def _createMainToolbar(self):
  72. return MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
  73. def _createScattMgr(self, guiparent, giface, iclass_mapwin):
  74. return ScattsManager(guiparent=self, giface=giface, iclass_mapwin=iclass_mapwin)
  75. def NewScatterPlot(self, scatt_id, transpose):
  76. return self.plot_panel.NewScatterPlot(scatt_id, transpose)
  77. def ShowPlotEditingToolbar(self, show):
  78. self.toolbars["editingToolbar"].Show(show)
  79. self.Layout()
  80. def ShowCategoryPanel(self, show):
  81. self.catsPanel.Show(show)
  82. #if show:
  83. # self.SetSashSize(5)
  84. #else:
  85. # self.SetSashSize(0)
  86. self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
  87. self.Layout()
  88. def _createCategoryPanel(self, parent):
  89. self.catsPanel = wx.Panel(parent=parent)
  90. self.cats_list = CategoryListCtrl(parent=self.catsPanel,
  91. cats_mgr=self.scatt_mgr.GetCategoriesManager(),
  92. sel_cats_in_iscatt=self._selCatInIScatt())
  93. self.catsPanel.SetMinSize((-1, 100))
  94. self.catsPanel.SetInitialSize((-1, 150))
  95. box_capt = wx.StaticBox(parent=self.catsPanel, id=wx.ID_ANY,
  96. label=' %s ' % _("Classes"),)
  97. catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
  98. self.toolbars['categoryToolbar'] = self._createCategoryToolbar(self.catsPanel)
  99. catsSizer.Add(item=self.cats_list, proportion=1, flag=wx.EXPAND | wx.TOP, border = 5)
  100. if self.toolbars['categoryToolbar']:
  101. catsSizer.Add(item=self.toolbars['categoryToolbar'], proportion=0)
  102. self.catsPanel.SetSizer(catsSizer)
  103. def _createCategoryToolbar(self, parent):
  104. return CategoryToolbar(parent=parent,
  105. scatt_mgr=self.scatt_mgr,
  106. cats_list=self.cats_list)
  107. class IScattDialog(wx.Dialog):
  108. def __init__(self, parent, giface, title=_("GRASS GIS Interactive Scatter Plot Tool"),
  109. id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE, **kwargs):
  110. wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
  111. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  112. self.iscatt_panel = MapDispIScattPanel(self, giface)
  113. mainsizer = wx.BoxSizer(wx.VERTICAL)
  114. mainsizer.Add(item=self.iscatt_panel, proportion=1, flag=wx.EXPAND)
  115. self.SetSizer(mainsizer)
  116. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  117. self.SetMinSize((300, 300))
  118. def OnCloseWindow(self, event):
  119. event.Skip()
  120. #self.
  121. class MapDispIScattPanel(IClassIScattPanel):
  122. def __init__(self, parent, giface,
  123. id=wx.ID_ANY, **kwargs):
  124. IClassIScattPanel.__init__(self, parent=parent, giface=giface,
  125. id=id, **kwargs)
  126. def _createScattMgr(self, guiparent, giface, iclass_mapwin):
  127. return ScattsManager(guiparent = self, giface = giface)
  128. def _createMainToolbar(self):
  129. return MainToolbar(parent = self, scatt_mgr = self.scatt_mgr, opt_tools=['add_group'])
  130. def _selCatInIScatt(self):
  131. return True
  132. class ScatterPlotsPanel(scrolled.ScrolledPanel):
  133. def __init__(self, parent, scatt_mgr, id=wx.ID_ANY):
  134. scrolled.ScrolledPanel.__init__(self, parent)
  135. self.SetupScrolling(scroll_x=False, scroll_y=True, scrollToTop=False)
  136. self.scatt_mgr = scatt_mgr
  137. self.mainPanel = wx.Panel(parent=self, id=wx.ID_ANY)
  138. #self._createCategoryPanel()
  139. # Fancy gui
  140. self._mgr = aui.AuiManager(self.mainPanel)
  141. #self._mgr.SetManagedWindow(self)
  142. self._mgr.Update()
  143. self._doLayout()
  144. self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
  145. self.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged)
  146. self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed)
  147. dlgSize = (-1, 400)
  148. #self.SetBestSize(dlgSize)
  149. #self.SetInitialSize(dlgSize)
  150. self.SetAutoLayout(1)
  151. #fix goutput's pane size (required for Mac OSX)
  152. #if self.gwindow:
  153. # self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
  154. self.ignore_scroll = 0
  155. self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
  156. self.scatt_i = 1
  157. self.scatt_id_scatt_i = {}
  158. self.transpose = {}
  159. self.scatts = {}
  160. self.Bind(wx.EVT_CLOSE, self.OnClose)
  161. self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
  162. def SetBusy(self, busy):
  163. for scatt in self.scatts.itervalues():
  164. scatt.UpdateCur(busy)
  165. def CursorPlotMove(self, x, y, scatt_id):
  166. try:
  167. x = int(round(x))
  168. y = int(round(y))
  169. coords = True
  170. except:
  171. coords = False
  172. pane = self._getPane(scatt_id)
  173. caption = self._creteCaption(scatt_id)
  174. if coords:
  175. caption += " %d, %d" % (x, y)
  176. pane.Caption(caption)
  177. self._mgr.RefreshCaptions()
  178. def _getPane(self, scatt_id):
  179. scatt_i = self.scatt_id_scatt_i[scatt_id]
  180. name = self._getScatterPlotName(scatt_i)
  181. return self._mgr.GetPane(name)
  182. def ScatterPlotClosed(self, scatt_id):
  183. scatt_i = self.scatt_id_scatt_i[scatt_id]
  184. name = self._getScatterPlotName(scatt_i)
  185. pane = self._mgr.GetPane(name)
  186. del self.scatt_id_scatt_i[scatt_id]
  187. del self.scatts[scatt_id]
  188. if pane.IsOk():
  189. self._mgr.ClosePane(pane)
  190. self._mgr.Update()
  191. def OnMouseWheel(self, event):
  192. #TODO very ugly find some better solution
  193. self.ignore_scroll = 3
  194. event.Skip()
  195. def ScrollChildIntoView(self, child):
  196. #For aui manager it does not work and returns position always to the top -> deactivated.
  197. pass
  198. def OnPlotPaneClosed(self, event):
  199. if isinstance(event.pane.window, ScatterPlotWidget):
  200. event.pane.window.CleanUp()
  201. def OnScrollChanged(self, event):
  202. wx.CallAfter(self.Layout)
  203. def OnScroll(self, event):
  204. if self.ignore_scroll > 0:
  205. self.ignore_scroll -= 1
  206. else:
  207. event.Skip()
  208. #wx.CallAfter(self._mgr.Update)
  209. #wx.CallAfter(self.Layout)
  210. def _doLayout(self):
  211. mainsizer = wx.BoxSizer(wx.VERTICAL)
  212. mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
  213. self.SetSizer(mainsizer)
  214. self.Layout()
  215. self.SetupScrolling()
  216. def OnClose(self, event):
  217. """!Close dialog"""
  218. #TODO
  219. print "closed"
  220. self.scatt_mgr.CleanUp()
  221. self.Destroy()
  222. def OnSettings(self, event):
  223. pass
  224. def _newScatterPlotName(self, scatt_id):
  225. name = self._getScatterPlotName(self.scatt_i)
  226. self.scatt_id_scatt_i[scatt_id] = self.scatt_i
  227. self.scatt_i += 1
  228. return name
  229. def _getScatterPlotName(self, i):
  230. name = "scatter plot %d" % i
  231. return name
  232. def NewScatterPlot(self, scatt_id, transpose):
  233. #TODO needs to be resolved (should be in this class)
  234. scatt = ScatterPlotWidget(parent = self.mainPanel,
  235. scatt_mgr = self.scatt_mgr,
  236. scatt_id = scatt_id,
  237. transpose = transpose)
  238. scatt.plotClosed.connect(self.ScatterPlotClosed)
  239. self.transpose[scatt_id] = transpose
  240. caption = self._creteCaption(scatt_id)
  241. self._mgr.AddPane(scatt,
  242. aui.AuiPaneInfo().Dockable(True).Floatable(True).
  243. Name(self._newScatterPlotName(scatt_id)).MinSize((-1, 300)).
  244. Caption(caption).
  245. Center().Position(1).MaximizeButton(True).
  246. MinimizeButton(True).CaptionVisible(True).
  247. CloseButton(True).Layer(0))
  248. self._mgr.Update()
  249. self.SetVirtualSize(self.GetBestVirtualSize())
  250. self.Layout()
  251. self.scatts[scatt_id] = scatt
  252. return scatt
  253. def _creteCaption(self, scatt_id):
  254. transpose = self.transpose[scatt_id]
  255. bands = self.scatt_mgr.GetBands()
  256. #TODO too low level
  257. b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
  258. x_b = bands[b1_id].split('@')[0]
  259. y_b = bands[b2_id].split('@')[0]
  260. if transpose:
  261. tmp = x_b
  262. x_b = y_b
  263. y_b = tmp
  264. return "%s x: %s y: %s" % (_("scatter plot"), x_b, y_b)
  265. def GetScattMgr(self):
  266. return self.scatt_mgr
  267. class CategoryListCtrl(wx.ListCtrl,
  268. listmix.ListCtrlAutoWidthMixin):
  269. #listmix.TextEditMixin):
  270. def __init__(self, parent, cats_mgr, sel_cats_in_iscatt, id = wx.ID_ANY):
  271. wx.ListCtrl.__init__(self, parent, id,
  272. style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|
  273. wx.LC_VRULES|wx.LC_SINGLE_SEL|wx.LC_NO_HEADER)
  274. self.columns = ((_('Class name'), 'name'), )
  275. #(_('Color'), 'color'))
  276. self.sel_cats_in_iscatt = sel_cats_in_iscatt
  277. self.Populate(columns = self.columns)
  278. self.cats_mgr = cats_mgr
  279. self.SetItemCount(len(self.cats_mgr.GetCategories()))
  280. self.rightClickedItemIdx = wx.NOT_FOUND
  281. listmix.ListCtrlAutoWidthMixin.__init__(self)
  282. #listmix.TextEditMixin.__init__(self)
  283. self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnCategoryRightUp) #wxMSW
  284. self.Bind(wx.EVT_RIGHT_UP, self.OnCategoryRightUp) #wxGTK
  285. #self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
  286. self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
  287. self.cats_mgr.setCategoryAttrs.connect(self.Update)
  288. self.cats_mgr.deletedCategory.connect(self.Update)
  289. self.cats_mgr.addedCategory.connect(self.Update)
  290. def Update(self, **kwargs):
  291. self.SetItemCount(len(self.cats_mgr.GetCategories()))
  292. if len(self.cats_mgr.GetCategories()):
  293. self.RefreshItems(0, len(self.cats_mgr.GetCategories()) - 1)
  294. def SetVirtualData(self, row, column, text):
  295. attr = self.columns[column][1]
  296. if attr == 'name':
  297. try:
  298. text.encode('ascii')
  299. except UnicodeEncodeError:
  300. GMessage(parent = self, message = _("Please use only ASCII characters."))
  301. return
  302. cat_id = self.cats_mgr.GetCategories()[row]
  303. self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
  304. self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
  305. self.cats_mgr.setCategoryAttrs.connect(self.Update)
  306. self.Select(row)
  307. def Populate(self, columns):
  308. for i, col in enumerate(columns):
  309. self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
  310. #self.SetColumnWidth(0, 100)
  311. #self.SetColumnWidth(1, 100)
  312. def AddCategory(self):
  313. self.cats_mgr.addedCategory.disconnect(self.Update)
  314. cat_id = self.cats_mgr.AddCategory()
  315. self.cats_mgr.addedCategory.connect(self.Update)
  316. if cat_id < 0:
  317. GError(_("Maximum limit of categories number was reached."))
  318. return
  319. self.SetItemCount(len(self.cats_mgr.GetCategories()))
  320. def DeleteCategory(self):
  321. indexList = sorted(self.GetSelectedIndices(), reverse = True)
  322. cats = []
  323. for i in indexList:
  324. # remove temporary raster
  325. cat_id = self.cats_mgr.GetCategories()[i]
  326. cats.append(cat_id)
  327. self.cats_mgr.deletedCategory.disconnect(self.Update)
  328. self.cats_mgr.DeleteCategory(cat_id)
  329. self.cats_mgr.deletedCategory.connect(self.Update)
  330. self.SetItemCount(len(self.cats_mgr.GetCategories()))
  331. def OnSel(self, event):
  332. if self.sel_cats_in_iscatt:
  333. indexList = self.GetSelectedIndices()
  334. sel_cats = []
  335. cats = self.cats_mgr.GetCategories()
  336. for i in indexList:
  337. sel_cats.append(cats[i])
  338. if sel_cats:
  339. self.cats_mgr.SetSelectedCat(sel_cats[0])
  340. event.Skip()
  341. def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
  342. indices = []
  343. lastFound = -1
  344. while True:
  345. index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
  346. if index == -1:
  347. break
  348. else:
  349. lastFound = index
  350. indices.append(index)
  351. return indices
  352. def DeselectAll(self):
  353. """!Deselect all items"""
  354. indexList = self.GetSelectedIndices()
  355. for i in indexList:
  356. self.Select(i, on = 0)
  357. # no highlight
  358. self.OnCategorySelected(None)
  359. def OnGetItemText(self, item, col):
  360. attr = self.columns[col][1]
  361. cat_id = self.cats_mgr.GetCategories()[item]
  362. return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
  363. def OnGetItemImage(self, item):
  364. return -1
  365. def OnGetItemAttr(self, item):
  366. cat_id = self.cats_mgr.GetCategories()[item]
  367. cattr = self.cats_mgr.GetCategoryAttrs(cat_id)
  368. if cattr['show']:
  369. c = cattr['color']
  370. back_c = wx.Colour(*map(int, c.split(':')))
  371. text_c = wx.Colour(*ContrastColor(back_c))
  372. else:
  373. back_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)
  374. text_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTIONTEXT)
  375. # if it is in scope of the method, gui falls, using self solved it
  376. self.l = wx.ListItemAttr(colText=text_c, colBack=back_c)
  377. return self.l
  378. def OnCategoryRightUp(self, event):
  379. """!Show context menu on right click"""
  380. item, flags = self.HitTest((event.GetX(), event.GetY()))
  381. if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
  382. self.rightClickedItemIdx = item
  383. # generate popup-menu
  384. cat_idx = self.rightClickedItemIdx
  385. cats = self.cats_mgr.GetCategories()
  386. cat_id = cats[cat_idx]
  387. showed = self.cats_mgr.GetCategoryAttrs(cat_id)['show']
  388. menu = wx.Menu()
  389. item_id = wx.NewId()
  390. menu.Append(item_id, text=_("Rename class"))
  391. self.Bind(wx.EVT_MENU, self.OnRename, id=item_id)
  392. item_id = wx.NewId()
  393. menu.Append(item_id, text=_("Set color"))
  394. self.Bind(wx.EVT_MENU, self.OnSetColor, id=item_id)
  395. item_id = wx.NewId()
  396. menu.Append(item_id, text=_("Change opacity level"))
  397. self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id=item_id)
  398. if showed:
  399. text = _("Hide")
  400. else:
  401. text = _("Show")
  402. item_id = wx.NewId()
  403. menu.Append(item_id, text = text)
  404. self.Bind(wx.EVT_MENU, lambda event : self._setCatAttrs(cat_id=cat_id,
  405. attrs={'show' : not showed}),
  406. id=item_id)
  407. menu.AppendSeparator()
  408. item_id = wx.NewId()
  409. menu.Append(item_id, text=_("Move to top"))
  410. self.Bind(wx.EVT_MENU, self.OnMoveTop, id=item_id)
  411. if cat_idx == 0:
  412. menu.Enable(item_id, False)
  413. item_id = wx.NewId()
  414. menu.Append(item_id, text=_("Move to bottom"))
  415. self.Bind(wx.EVT_MENU, self.OnMoveBottom, id=item_id)
  416. if cat_idx == len(cats) - 1:
  417. menu.Enable(item_id, False)
  418. menu.AppendSeparator()
  419. item_id = wx.NewId()
  420. menu.Append(item_id, text=_("Move category up"))
  421. self.Bind(wx.EVT_MENU, self.OnMoveUp, id=item_id)
  422. if cat_idx == 0:
  423. menu.Enable(item_id, False)
  424. item_id = wx.NewId()
  425. menu.Append(item_id, text=_("Move category down"))
  426. self.Bind(wx.EVT_MENU, self.OnMoveDown, id=item_id)
  427. if cat_idx == len(cats) - 1:
  428. menu.Enable(item_id, False)
  429. menu.AppendSeparator()
  430. item_id = wx.NewId()
  431. menu.Append(item_id, text=_("Export class raster"))
  432. self.Bind(wx.EVT_MENU, self.OnExportCatRast, id=item_id)
  433. self.PopupMenu(menu)
  434. menu.Destroy()
  435. def OnExportCatRast(self, event):
  436. """!Export training areas"""
  437. #TODO
  438. # GMessage(parent=self, message=_("No class raster to export."))
  439. # return
  440. cat_idx = self.rightClickedItemIdx
  441. cat_id = self.cats_mgr.GetCategories()[cat_idx]
  442. self.cats_mgr.ExportCatRast(cat_id)
  443. def OnMoveUp(self, event):
  444. cat_idx = self.rightClickedItemIdx
  445. cat_id = self.cats_mgr.GetCategories()[cat_idx]
  446. self.cats_mgr.ChangePosition(cat_id, cat_idx - 1)
  447. self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
  448. def OnMoveDown(self, event):
  449. cat_idx = self.rightClickedItemIdx
  450. cat_id = self.cats_mgr.GetCategories()[cat_idx]
  451. self.cats_mgr.ChangePosition(cat_id, cat_idx + 1)
  452. self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
  453. def OnMoveTop(self, event):
  454. cat_idx = self.rightClickedItemIdx
  455. cat_id = self.cats_mgr.GetCategories()[cat_idx]
  456. self.cats_mgr.ChangePosition(cat_id, 0)
  457. self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
  458. def OnMoveBottom(self, event):
  459. cat_idx = self.rightClickedItemIdx
  460. cats = self.cats_mgr.GetCategories()
  461. cat_id = cats[cat_idx]
  462. self.cats_mgr.ChangePosition(cat_id, len(cats) - 1)
  463. self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
  464. def OnSetColor(self, event):
  465. """!Popup opacity level indicator"""
  466. cat_idx = self.rightClickedItemIdx
  467. cat_id = self.cats_mgr.GetCategories()[cat_idx]
  468. col = self.cats_mgr.GetCategoryAttrs(cat_id)['color']
  469. col = map(int, col.split(':'))
  470. col_data = wx.ColourData()
  471. col_data.SetColour(wx.Colour(*col))
  472. dlg = wx.ColourDialog(self, col_data)
  473. dlg.GetColourData().SetChooseFull(True)
  474. if dlg.ShowModal() == wx.ID_OK:
  475. color = dlg.GetColourData().GetColour().Get()
  476. color = ':'.join(map(str, color))
  477. self.cats_mgr.SetCategoryAttrs(cat_id, {"color" : color})
  478. dlg.Destroy()
  479. def OnPopupOpacityLevel(self, event):
  480. """!Popup opacity level indicator"""
  481. cat_id = self.cats_mgr.GetCategories()[self.rightClickedItemIdx]
  482. cat_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
  483. value = cat_attrs['opacity'] * 100
  484. name = cat_attrs['name']
  485. dlg = SetOpacityDialog(self, opacity = value,
  486. title = _("Change opacity of class <%s>" % name))
  487. dlg.applyOpacity.connect(lambda value:
  488. self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value}))
  489. dlg.CentreOnParent()
  490. if dlg.ShowModal() == wx.ID_OK:
  491. self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value})
  492. dlg.Destroy()
  493. def OnRename(self, event):
  494. cat_id = self.cats_mgr.GetCategories()[self.rightClickedItemIdx]
  495. cat_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
  496. dlg = RenameClassDialog(self, old_name=cat_attrs['name'])
  497. dlg.CentreOnParent()
  498. while True:
  499. if dlg.ShowModal() == wx.ID_OK:
  500. name = dlg.GetNewName().strip()
  501. if not name:
  502. GMessage(parent=self, message=_("Empty name was inserted."))
  503. else:
  504. self.cats_mgr.SetCategoryAttrs(cat_id, {"name" : name})
  505. break
  506. else:
  507. break
  508. dlg.Destroy()
  509. def _setCatAttrs(self, cat_id, attrs):
  510. self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
  511. self.cats_mgr.SetCategoryAttrs(cat_id, attrs)
  512. self.cats_mgr.setCategoryAttrs.connect(self.Update)