properties.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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 _onToggleCheckBox(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._onToggleCheckBox)
  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._onToggleCheckBox)
  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._onToggleCheckBox)
  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 _onToggleCheckBox(self, event):
  140. """Update display when toggle display mode"""
  141. super()._onToggleCheckBox(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._onToggleCheckBox)
  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 _onToggleCheckBox(self, event):
  178. """Shows/Hides extent (comp. region) in map canvas.
  179. Shows or hides according to checkbox value.
  180. """
  181. super()._onToggleCheckBox(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._onToggleCheckBox)
  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 _onToggleCheckBox(self, event):
  214. super()._onToggleCheckBox(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:
  224. """Radiobox managing widgets in statusbar."""
  225. def __init__(self, parent, sbmanager):
  226. self.name = "showInStatusbar"
  227. self.statusbarManager = sbmanager
  228. choices = self.statusbarManager.GetItemLabels()
  229. self.widget = wx.RadioBox(
  230. parent=parent,
  231. id=wx.ID_ANY,
  232. label="Displayed content",
  233. choices=choices,
  234. majorDimension=1,
  235. style=wx.RA_SPECIFY_COLS,
  236. )
  237. self._setValue(self.statusbarManager.GetMode())
  238. self._disableItems()
  239. self.widget.Bind(wx.EVT_RADIOBOX, self._onToggleRadioBox)
  240. def _setValue(self, mode):
  241. self.widget.SetSelection(mode)
  242. def GetValue(self):
  243. return self.widget.GetSelection()
  244. def _disableItems(self):
  245. """Disables a radiobox options"""
  246. for item in self.statusbarManager.disabledItems.keys():
  247. self.widget.EnableItem(n=item, enable=False)
  248. def GetWidget(self):
  249. """Returns underlying widget.
  250. :return: widget or None if doesn't exist
  251. """
  252. return self.widget
  253. def _onToggleRadioBox(self, event):
  254. self.statusbarManager.SetMode(self.GetValue())
  255. self.statusbarManager.Update()
  256. class MapDisplayPropertiesDialog(wx.Dialog):
  257. """Map Display properties dialog"""
  258. def __init__(
  259. self,
  260. parent,
  261. mapframe,
  262. properties,
  263. sbmanager,
  264. title=_("Map Display Settings"),
  265. size=(-1, 300),
  266. style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  267. ):
  268. wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
  269. self.parent = parent
  270. self.title = title
  271. self.size = size
  272. self.mapframe = mapframe
  273. self.mapWindowProperties = properties
  274. self.statusbarManager = sbmanager
  275. # notebook
  276. self.notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
  277. # create notebook pages
  278. self._createDisplayPage(parent=self.notebook)
  279. self._createStatusBarPage(parent=self.notebook)
  280. self.btnClose = Button(self, wx.ID_CLOSE)
  281. self.SetEscapeId(wx.ID_CLOSE)
  282. self._layout()
  283. def _layout(self):
  284. """Layout window"""
  285. # sizers
  286. btnStdSizer = wx.StdDialogButtonSizer()
  287. btnStdSizer.AddButton(self.btnClose)
  288. btnStdSizer.Realize()
  289. mainSizer = wx.BoxSizer(wx.VERTICAL)
  290. mainSizer.Add(self.notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
  291. mainSizer.Add(btnStdSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
  292. self.SetSizer(mainSizer)
  293. self.SetMinSize(self.GetBestSize())
  294. self.SetSize(self.size)
  295. def _createDisplayPage(self, parent):
  296. """Create notebook page for display settings"""
  297. panel = SP.ScrolledPanel(parent=parent, id=wx.ID_ANY)
  298. panel.SetupScrolling(scroll_x=False, scroll_y=True)
  299. parent.AddPage(page=panel, text=_("General"))
  300. # General settings
  301. sizer = wx.BoxSizer(wx.VERTICAL)
  302. # Auto-rendering
  303. self.autoRendering = ChBRender(panel, self.mapWindowProperties)
  304. sizer.Add(
  305. self.autoRendering.GetWidget(),
  306. proportion=0,
  307. flag=wx.EXPAND | wx.ALL,
  308. border=3,
  309. )
  310. # Align extent to display size
  311. self.alignExtent = ChBAlignExtent(panel, self.mapWindowProperties)
  312. sizer.Add(
  313. self.alignExtent.GetWidget(),
  314. proportion=0,
  315. flag=wx.EXPAND | wx.ALL,
  316. border=3,
  317. )
  318. # Use computation resolution
  319. self.compResolution = ChBResolution(
  320. panel, self.mapframe, self.mapWindowProperties
  321. )
  322. sizer.Add(
  323. self.compResolution.GetWidget(),
  324. proportion=0,
  325. flag=wx.EXPAND | wx.ALL,
  326. border=3,
  327. )
  328. # Show computation extent
  329. self.showCompExtent = ChBShowRegion(
  330. panel, self.mapframe, self.mapWindowProperties
  331. )
  332. sizer.Add(
  333. self.showCompExtent.GetWidget(),
  334. proportion=0,
  335. flag=wx.EXPAND | wx.ALL,
  336. border=3,
  337. )
  338. panel.SetSizer(sizer)
  339. def _createStatusBarPage(self, parent):
  340. """Create notebook page for statusbar settings"""
  341. panel = SP.ScrolledPanel(parent=parent, id=wx.ID_ANY)
  342. panel.SetupScrolling(scroll_x=False, scroll_y=True)
  343. parent.AddPage(page=panel, text=_("Status bar"))
  344. sizer = wx.BoxSizer(wx.VERTICAL)
  345. self.shownInStatusbar = RBShowInStatusbar(
  346. parent=panel, sbmanager=self.statusbarManager
  347. )
  348. sizer.Add(
  349. self.shownInStatusbar.GetWidget(),
  350. proportion=0,
  351. flag=wx.EXPAND | wx.ALL,
  352. border=3,
  353. )
  354. # Display coordinates in different CRS
  355. self.projection = ChBProjection(panel, self.mapWindowProperties)
  356. sizer.Add(
  357. self.projection.GetWidget(),
  358. proportion=0,
  359. flag=wx.EXPAND | wx.ALL,
  360. border=3,
  361. )
  362. panel.SetSizer(sizer)