properties.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. """
  2. @package mapdisp.properties
  3. @brief Classes for map display properties management
  4. Classes:
  5. - properties::PropertyItem
  6. - properties::ChBRender
  7. - properties::ChBShowRegion
  8. - properties::ChBAlignExtent
  9. - properties::ChBResolution
  10. - properties::ChBProjection
  11. - properties::RBShowInStatusbar
  12. - properties::MapDisplayPropertiesDialog
  13. (C) 2021 by the GRASS Development Team
  14. This program is free software under the GNU General Public License
  15. (>=v2). Read the file COPYING that comes with GRASS for details.
  16. @author Vaclav Petras <wenzeslaus gmail.com>
  17. @author Anna Kratochvilova <kratochanna gmail.com>
  18. @author Linda Kladivova <lindakladivova gmail.com>
  19. """
  20. import wx
  21. import wx.lib.scrolledpanel as SP
  22. from gui_core.wrap import Button
  23. class PropertyItem:
  24. """Base class for Map Display properties widgets that use property signals"""
  25. def __init__(self, mapWindowProperties):
  26. self._properties = mapWindowProperties
  27. @property
  28. def mapWindowProperty(self):
  29. pass
  30. @mapWindowProperty.setter
  31. def mapWindowProperty(self, value):
  32. pass
  33. def mapWindowPropertyChanged(self):
  34. """Returns signal from MapWindowProperties."""
  35. pass
  36. def _setValue(self, value):
  37. self.widget.SetValue(value)
  38. def GetValue(self):
  39. return self.widget.GetValue()
  40. def GetWidget(self):
  41. """Returns underlying widget.
  42. :return: widget or None if doesn't exist
  43. """
  44. return self.widget
  45. def _connect(self):
  46. self.mapWindowPropertyChanged().connect(self._setValue)
  47. def _disconnect(self):
  48. self.mapWindowPropertyChanged().disconnect(self._setValue)
  49. def _onToggle(self, event):
  50. self._disconnect()
  51. self.mapWindowProperty = self.GetValue()
  52. self._connect()
  53. class ChBRender(PropertyItem):
  54. """Checkbox to enable and disable auto-rendering."""
  55. def __init__(self, parent, mapWindowProperties):
  56. PropertyItem.__init__(self, mapWindowProperties)
  57. self.name = "render"
  58. self.widget = wx.CheckBox(
  59. parent=parent, id=wx.ID_ANY, label=_("Enable auto-rendering")
  60. )
  61. self.widget.SetValue(self.mapWindowProperty)
  62. self.widget.SetToolTip(wx.ToolTip(_("Enable/disable auto-rendering")))
  63. self.widget.Bind(wx.EVT_CHECKBOX, self._onToggle)
  64. self._connect()
  65. @property
  66. def mapWindowProperty(self):
  67. return self._properties.autoRender
  68. @mapWindowProperty.setter
  69. def mapWindowProperty(self, value):
  70. self._properties.autoRender = value
  71. def mapWindowPropertyChanged(self):
  72. return self._properties.autoRenderChanged
  73. class ChBAlignExtent(PropertyItem):
  74. """Checkbox to select zoom behavior.
  75. Used by BufferedWindow (through MapFrame property).
  76. See tooltip for explanation.
  77. """
  78. def __init__(self, parent, mapWindowProperties):
  79. PropertyItem.__init__(self, mapWindowProperties)
  80. self.name = "alignExtent"
  81. self.widget = wx.CheckBox(
  82. parent=parent,
  83. id=wx.ID_ANY,
  84. label=_("Align region extent based on display size"),
  85. )
  86. self.widget.SetValue(self.mapWindowProperty)
  87. self.widget.SetToolTip(
  88. wx.ToolTip(
  89. _(
  90. "Align region extent based on display "
  91. "size from center point. "
  92. "Default value for new map displays can "
  93. "be set up in 'User GUI settings' dialog."
  94. )
  95. )
  96. )
  97. self.widget.Bind(wx.EVT_CHECKBOX, self._onToggle)
  98. self._connect()
  99. @property
  100. def mapWindowProperty(self):
  101. return self._properties.alignExtent
  102. @mapWindowProperty.setter
  103. def mapWindowProperty(self, value):
  104. self._properties.alignExtent = value
  105. def mapWindowPropertyChanged(self):
  106. return self._properties.alignExtentChanged
  107. class ChBResolution(PropertyItem):
  108. """Checkbox to select used display resolution."""
  109. def __init__(self, parent, mapframe, mapWindowProperties):
  110. PropertyItem.__init__(self, mapWindowProperties)
  111. self.mapFrame = mapframe
  112. self.name = "resolution"
  113. self.widget = wx.CheckBox(
  114. parent=parent,
  115. id=wx.ID_ANY,
  116. label=_("Constrain display resolution to computational settings"),
  117. )
  118. self.widget.SetValue(self.mapWindowProperty)
  119. self.widget.SetToolTip(
  120. wx.ToolTip(
  121. _(
  122. "Constrain display resolution "
  123. "to computational region settings. "
  124. "Default value for new map displays can "
  125. "be set up in 'User GUI settings' dialog."
  126. )
  127. )
  128. )
  129. self.widget.Bind(wx.EVT_CHECKBOX, self._onToggle)
  130. self._connect()
  131. @property
  132. def mapWindowProperty(self):
  133. return self._properties.resolution
  134. @mapWindowProperty.setter
  135. def mapWindowProperty(self, value):
  136. self._properties.resolution = value
  137. def mapWindowPropertyChanged(self):
  138. return self._properties.resolutionChanged
  139. def _onToggle(self, event):
  140. """Update display when toggle display mode"""
  141. super()._onToggle(event)
  142. # redraw map if auto-rendering is enabled
  143. if self._properties.autoRender:
  144. self.mapFrame.GetWindow().UpdateMap()
  145. class ChBShowRegion(PropertyItem):
  146. """Checkbox to enable and disable showing of computational region."""
  147. def __init__(self, parent, mapframe, mapWindowProperties):
  148. PropertyItem.__init__(self, mapWindowProperties)
  149. self.mapFrame = mapframe
  150. self.name = "showRegion"
  151. self.widget = wx.CheckBox(
  152. parent=parent, id=wx.ID_ANY, label=_("Show computational extent")
  153. )
  154. self.widget.SetValue(self.mapWindowProperty)
  155. self.widget.SetToolTip(
  156. wx.ToolTip(
  157. _(
  158. "Show/hide computational "
  159. "region extent (set with g.region). "
  160. "Display region drawn as a blue box inside the "
  161. "computational region, "
  162. "computational region inside a display region "
  163. "as a red box)."
  164. )
  165. )
  166. )
  167. self.widget.Bind(wx.EVT_CHECKBOX, self._onToggle)
  168. self._connect()
  169. @property
  170. def mapWindowProperty(self):
  171. return self._properties.showRegion
  172. @mapWindowProperty.setter
  173. def mapWindowProperty(self, value):
  174. self._properties.showRegion = value
  175. def mapWindowPropertyChanged(self):
  176. return self._properties.showRegionChanged
  177. def _onToggle(self, event):
  178. """Shows/Hides extent (comp. region) in map canvas.
  179. Shows or hides according to checkbox value.
  180. """
  181. super()._onToggle(event)
  182. # redraw map if auto-rendering is enabled
  183. if self._properties.autoRender:
  184. self.mapFrame.GetWindow().UpdateMap(render=False)
  185. class ChBProjection(PropertyItem):
  186. """Checkbox to enable user defined projection"""
  187. def __init__(self, parent, mapWindowProperties):
  188. PropertyItem.__init__(self, mapWindowProperties)
  189. self.name = "useDefinedProjection"
  190. self.defaultLabel = _("Display coordinates in different CRS")
  191. self.widget = wx.CheckBox(parent=parent, id=wx.ID_ANY, label=self.defaultLabel)
  192. self.widget.SetValue(self.mapWindowProperty)
  193. self.widget.SetToolTip(
  194. wx.ToolTip(
  195. _(
  196. "Reproject coordinates displayed "
  197. "in the statusbar. Coordinate reference system can be "
  198. "specified in GUI preferences dialog "
  199. "(tab 'Projection')"
  200. )
  201. )
  202. )
  203. self.widget.Bind(wx.EVT_CHECKBOX, self._onToggle)
  204. self._connect()
  205. @property
  206. def mapWindowProperty(self):
  207. return self._properties.useDefinedProjection
  208. @mapWindowProperty.setter
  209. def mapWindowProperty(self, value):
  210. self._properties.useDefinedProjection = value
  211. def mapWindowPropertyChanged(self):
  212. return self._properties.useDefinedProjectionChanged
  213. def _onToggle(self, event):
  214. super()._onToggle(event)
  215. epsg = self._properties.epsg
  216. if epsg:
  217. label = _("{label} (EPSG: {epsg})").format(
  218. label=self.defaultLabel, epsg=epsg
  219. )
  220. self.widget.SetLabel(label)
  221. else:
  222. self.widget.SetLabel(self.defaultLabel)
  223. class RBShowInStatusbar(PropertyItem):
  224. """Radiobox managing widgets in statusbar."""
  225. def __init__(self, parent, mapWindowProperties, sbmanager):
  226. PropertyItem.__init__(self, mapWindowProperties)
  227. self.name = "showInStatusbar"
  228. self.statusbarManager = sbmanager
  229. choices = self.statusbarManager.GetItemLabels()
  230. self.widget = wx.RadioBox(
  231. parent=parent,
  232. id=wx.ID_ANY,
  233. label="Displayed content",
  234. choices=choices,
  235. majorDimension=1,
  236. style=wx.RA_SPECIFY_COLS,
  237. )
  238. self._setValue(self.mapWindowProperty)
  239. self._disableItems()
  240. self.widget.Bind(wx.EVT_RADIOBOX, self._onToggle)
  241. self._connect()
  242. def _setValue(self, mode):
  243. self.widget.SetSelection(mode)
  244. def GetValue(self):
  245. return self.widget.GetSelection()
  246. def _disableItems(self):
  247. """Disables a radiobox options"""
  248. for item in self.statusbarManager.disabledItems.keys():
  249. self.widget.EnableItem(n=item, enable=False)
  250. @property
  251. def mapWindowProperty(self):
  252. return self._properties.sbItem
  253. @mapWindowProperty.setter
  254. def mapWindowProperty(self, value):
  255. self._properties.sbItem = value
  256. def mapWindowPropertyChanged(self):
  257. return self._properties.sbItemChanged
  258. class MapDisplayPropertiesDialog(wx.Dialog):
  259. """Map Display properties dialog"""
  260. def __init__(
  261. self,
  262. parent,
  263. mapframe,
  264. properties,
  265. sbmanager,
  266. title=_("Map Display Settings"),
  267. size=(-1, 300),
  268. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  269. ):
  270. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
  271. self.parent = parent
  272. self.title = title
  273. self.size = size
  274. self.mapframe = mapframe
  275. self.mapWindowProperties = properties
  276. self.statusbarManager = sbmanager
  277. # notebook
  278. self.notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  279. # create notebook pages
  280. self._createDisplayPage(parent=self.notebook)
  281. self._createStatusBarPage(parent=self.notebook)
  282. self.btnClose = Button(self, wx.ID_CLOSE)
  283. self.SetEscapeId(wx.ID_CLOSE)
  284. self._layout()
  285. def _layout(self):
  286. """Layout window"""
  287. # sizers
  288. btnStdSizer = wx.StdDialogButtonSizer()
  289. btnStdSizer.AddButton(self.btnClose)
  290. btnStdSizer.Realize()
  291. mainSizer = wx.BoxSizer(wx.VERTICAL)
  292. mainSizer.Add(self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  293. mainSizer.Add(btnStdSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
  294. self.SetSizer(mainSizer)
  295. self.SetMinSize(self.GetBestSize())
  296. self.SetSize(self.size)
  297. def _createDisplayPage(self, parent):
  298. """Create notebook page for display settings"""
  299. panel = SP.ScrolledPanel(parent=parent, id=wx.ID_ANY)
  300. panel.SetupScrolling(scroll_x=False, scroll_y=True)
  301. parent.AddPage(page=panel, text=_("General"))
  302. # General settings
  303. sizer = wx.BoxSizer(wx.VERTICAL)
  304. # Auto-rendering
  305. self.autoRendering = ChBRender(panel, self.mapWindowProperties)
  306. sizer.Add(
  307. self.autoRendering.GetWidget(),
  308. proportion=0,
  309. flag=wx.EXPAND | wx.ALL,
  310. border=3,
  311. )
  312. # Align extent to display size
  313. self.alignExtent = ChBAlignExtent(panel, self.mapWindowProperties)
  314. sizer.Add(
  315. self.alignExtent.GetWidget(),
  316. proportion=0,
  317. flag=wx.EXPAND | wx.ALL,
  318. border=3,
  319. )
  320. # Use computation resolution
  321. self.compResolution = ChBResolution(
  322. panel, self.mapframe, self.mapWindowProperties
  323. )
  324. sizer.Add(
  325. self.compResolution.GetWidget(),
  326. proportion=0,
  327. flag=wx.EXPAND | wx.ALL,
  328. border=3,
  329. )
  330. # Show computation extent
  331. self.showCompExtent = ChBShowRegion(
  332. panel, self.mapframe, self.mapWindowProperties
  333. )
  334. sizer.Add(
  335. self.showCompExtent.GetWidget(),
  336. proportion=0,
  337. flag=wx.EXPAND | wx.ALL,
  338. border=3,
  339. )
  340. panel.SetSizer(sizer)
  341. def _createStatusBarPage(self, parent):
  342. """Create notebook page for statusbar settings"""
  343. panel = SP.ScrolledPanel(parent=parent, id=wx.ID_ANY)
  344. panel.SetupScrolling(scroll_x=False, scroll_y=True)
  345. parent.AddPage(page=panel, text=_("Status bar"))
  346. sizer = wx.BoxSizer(wx.VERTICAL)
  347. self.shownInStatusbar = RBShowInStatusbar(
  348. parent=panel,
  349. mapWindowProperties=self.mapWindowProperties,
  350. sbmanager=self.statusbarManager,
  351. )
  352. sizer.Add(
  353. self.shownInStatusbar.GetWidget(),
  354. proportion=0,
  355. flag=wx.EXPAND | wx.ALL,
  356. border=3,
  357. )
  358. # Display coordinates in different CRS
  359. self.projection = ChBProjection(panel, self.mapWindowProperties)
  360. sizer.Add(
  361. self.projection.GetWidget(),
  362. proportion=0,
  363. flag=wx.EXPAND | wx.ALL,
  364. border=3,
  365. )
  366. panel.SetSizer(sizer)