properties.py 12 KB

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