graphics.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. """
  2. @package mapwin.graphics
  3. @brief Map display canvas - buffered window.
  4. Classes:
  5. - graphics::GraphicsSet
  6. - graphics::GraphicsSetItem
  7. (C) 2006-2013 by the GRASS Development Team
  8. This program is free software under the GNU General Public License
  9. (>=v2). Read the file COPYING that comes with GRASS for details.
  10. @author Stepan Turek <stepan.turek seznam.cz> (handlers support, GraphicsSet)
  11. """
  12. from copy import copy
  13. import wx
  14. from gui_core.wrap import NewId
  15. class GraphicsSet:
  16. def __init__(
  17. self,
  18. parentMapWin,
  19. graphicsType,
  20. pdc,
  21. setStatusFunc=None,
  22. drawFunc=None,
  23. mapCoords=True,
  24. ):
  25. """Class, which contains instances of GraphicsSetItem and
  26. draws them For description of parameters look at method
  27. RegisterGraphicsToDraw in BufferedWindow class.
  28. """
  29. self.pens = {
  30. "default": wx.Pen(colour=wx.BLACK, width=2, style=wx.SOLID),
  31. "selected": wx.Pen(colour=wx.GREEN, width=2, style=wx.SOLID),
  32. "unused": wx.Pen(colour=wx.LIGHT_GREY, width=2, style=wx.SOLID),
  33. "highest": wx.Pen(colour=wx.RED, width=2, style=wx.SOLID),
  34. }
  35. self.brushes = {"default": wx.TRANSPARENT_BRUSH}
  36. # list contains instances of GraphicsSetItem
  37. self.itemsList = []
  38. self.properties = {}
  39. self.graphicsType = graphicsType
  40. self.parentMapWin = parentMapWin
  41. self.setStatusFunc = setStatusFunc
  42. self.mapCoords = mapCoords
  43. self.pdc = pdc
  44. if drawFunc:
  45. self.drawFunc = drawFunc
  46. elif self.graphicsType == "point":
  47. self.properties["size"] = 5
  48. self.properties["text"] = {}
  49. self.properties["text"]["font"] = wx.Font(
  50. pointSize=self.properties["size"],
  51. family=wx.FONTFAMILY_DEFAULT,
  52. style=wx.FONTSTYLE_NORMAL,
  53. weight=wx.FONTWEIGHT_NORMAL,
  54. )
  55. self.properties["text"]["active"] = True
  56. self.drawFunc = self.parentMapWin.DrawCross
  57. elif self.graphicsType == "line":
  58. self.drawFunc = self.parentMapWin.DrawPolylines
  59. elif self.graphicsType == "rectangle":
  60. self.drawFunc = self.parentMapWin.DrawRectangle
  61. elif self.graphicsType == "polygon":
  62. self.drawFunc = self.parentMapWin.DrawPolygon
  63. def Draw(self):
  64. """Draws all containing items."""
  65. itemOrderNum = 0
  66. for item in self.itemsList:
  67. self._clearId(item.GetId())
  68. if self.setStatusFunc is not None:
  69. self.setStatusFunc(item, itemOrderNum)
  70. if item.GetPropertyVal("hide") is True:
  71. itemOrderNum += 1
  72. continue
  73. if self.graphicsType == "point":
  74. if item.GetPropertyVal("penName"):
  75. self.parentMapWin.pen = self.pens[item.GetPropertyVal("penName")]
  76. else:
  77. self.parentMapWin.pen = self.pens["default"]
  78. if self.mapCoords:
  79. coords = self.parentMapWin.Cell2Pixel(item.GetCoords())
  80. else:
  81. coords = item.GetCoords()
  82. size = self.properties["size"]
  83. label = item.GetPropertyVal("label")
  84. if label is None:
  85. self.properties["text"] = None
  86. else:
  87. self.properties["text"]["coords"] = [
  88. coords[0] + size,
  89. coords[1] + size,
  90. size,
  91. size,
  92. ]
  93. self.properties["text"]["color"] = self.parentMapWin.pen.GetColour()
  94. self.properties["text"]["text"] = label
  95. self.drawFunc(
  96. pdc=self.pdc,
  97. drawid=item.GetId(),
  98. coords=coords,
  99. text=self.properties["text"],
  100. size=self.properties["size"],
  101. )
  102. elif self.graphicsType == "line":
  103. if item.GetPropertyVal("penName"):
  104. pen = self.pens[item.GetPropertyVal("penName")]
  105. else:
  106. pen = self.pens["default"]
  107. if self.mapCoords:
  108. coords = [
  109. self.parentMapWin.Cell2Pixel(coords)
  110. for coords in item.GetCoords()
  111. ]
  112. else:
  113. coords = item.GetCoords()
  114. self.drawFunc(pdc=self.pdc, pen=pen, coords=coords, drawid=item.GetId())
  115. elif self.graphicsType == "rectangle":
  116. if item.GetPropertyVal("penName"):
  117. pen = self.pens[item.GetPropertyVal("penName")]
  118. else:
  119. pen = self.pens["default"]
  120. if item.GetPropertyVal("brushName"):
  121. brush = self.brushes[item.GetPropertyVal("brushName")]
  122. else:
  123. brush = self.brushes["default"]
  124. if self.mapCoords:
  125. coords = [
  126. self.parentMapWin.Cell2Pixel(coords)
  127. for coords in item.GetCoords()
  128. ]
  129. else:
  130. coords = item.GetCoords()
  131. self.drawFunc(
  132. pdc=self.pdc,
  133. pen=pen,
  134. brush=brush,
  135. drawid=item.GetId(),
  136. point1=coords[0],
  137. point2=coords[1],
  138. )
  139. elif self.graphicsType == "polygon":
  140. if item.GetPropertyVal("penName"):
  141. pen = self.pens[item.GetPropertyVal("penName")]
  142. else:
  143. pen = self.pens["default"]
  144. if item.GetPropertyVal("brushName"):
  145. brush = self.brushes[item.GetPropertyVal("brushName")]
  146. else:
  147. brush = self.brushes["default"]
  148. if self.mapCoords:
  149. coords = [
  150. self.parentMapWin.Cell2Pixel(coords)
  151. for coords in item.GetCoords()
  152. ]
  153. else:
  154. coords = item.GetCoords()
  155. self.drawFunc(
  156. pdc=self.pdc,
  157. pen=pen,
  158. brush=brush,
  159. coords=coords,
  160. drawid=item.GetId(),
  161. )
  162. itemOrderNum += 1
  163. def AddItem(self, coords, penName=None, label=None, hide=False):
  164. """Append item to the list.
  165. Added item is put to the last place in drawing order.
  166. Could be 'point' or 'line' according to graphicsType.
  167. :param coords: list of east, north coordinates (double) of item.
  168. Example:
  169. * point: [1023, 122]
  170. * line: [[10, 12],[20,40],[23, 2334]]
  171. * rectangle: [[10, 12], [33, 45]]
  172. :param penName: the 'default' pen is used if is not defined
  173. :type penName: str
  174. :param label: label, which will be drawn with point. It is
  175. relavant just for 'point' type.
  176. :type label: str
  177. :param hide: if it is True, the item is not drawn when self.Draw
  178. is called. Hidden items are also counted in drawing
  179. order.
  180. :type hide: bool
  181. :return: (GraphicsSetItem) - added item reference
  182. """
  183. item = GraphicsSetItem(coords=coords, penName=penName, label=label, hide=hide)
  184. self.itemsList.append(item)
  185. return item
  186. def DeleteItem(self, item):
  187. """Deletes item
  188. :param item: (GraphicsSetItem) - item to remove
  189. :return: True if item was removed
  190. :return: False if item was not found
  191. """
  192. try:
  193. self.itemsList.remove(item)
  194. except ValueError:
  195. return False
  196. return True
  197. def GetAllItems(self):
  198. """Returns list of all containing instances of GraphicsSetItem,
  199. in order as they are drawn. If you want to change order of
  200. drawing use: SetItemDrawOrder method.
  201. """
  202. # user can edit objects but not order in list, that is reason,
  203. # why is returned shallow copy of data list it should be used
  204. # SetItemDrawOrder for changing order
  205. return copy(self.itemsList)
  206. def GetItem(self, drawNum):
  207. """Get given item from the list.
  208. :param drawNum: drawing order (index) number of item
  209. :type drawNum: int
  210. :return: instance of GraphicsSetItem which is drawn in drawNum order
  211. :return: False if drawNum was out of range
  212. """
  213. return self.itemsList[drawNum]
  214. def SetPropertyVal(self, propName, propVal):
  215. """Set property value
  216. :param propName: - property name: "size", "text"
  217. - both properties are relevant for "point" type
  218. :type propName: str
  219. :param propVal: property value to be set
  220. :return: True if value was set
  221. :return: False if propName is not "size" or "text" or type is "line"
  222. """
  223. if propName in self.properties:
  224. self.properties[propName] = propVal
  225. return True
  226. return False
  227. def GetPropertyVal(self, propName):
  228. """Get property value
  229. Raises KeyError if propName is not "size" or "text" or type is
  230. "line"
  231. :param propName: property name: "size", "text" both properties
  232. are relevant for "point" type
  233. :type propName: str
  234. :return: value of property
  235. """
  236. if propName in self.properties:
  237. return self.properties[propName]
  238. raise KeyError(_("Property does not exist: %s") % (propName))
  239. def AddPen(self, penName, pen):
  240. """Add pen
  241. :param penName: name of added pen
  242. :type penName: str
  243. :param pen: added pen
  244. :type pen: Wx.Pen
  245. :return: True - if pen was added
  246. :return: False - if pen already exists
  247. """
  248. if penName in self.pens:
  249. return False
  250. self.pens[penName] = pen
  251. return True
  252. def GetPen(self, penName):
  253. """Get existing pen
  254. :param penName: name of pen
  255. :type penName: str
  256. :return: wx.Pen reference if is found
  257. :return: None if penName was not found
  258. """
  259. if penName in self.pens:
  260. return self.pens[penName]
  261. return None
  262. def AddBrush(self, brushName, brush):
  263. """Add brush
  264. :param brushName: name of added brush
  265. :type brushName: str
  266. :param brush: added brush
  267. :type brush: wx.Brush
  268. :return: True - if brush was added
  269. :return: False - if brush already exists
  270. """
  271. if brushName in self.brushes:
  272. return False
  273. self.brushes[brushName] = brush
  274. return True
  275. def GetBrush(self, brushName):
  276. """Get existing brush
  277. :param brushName: name of brush
  278. :type brushName: str
  279. :return: wx.Brush reference if is found
  280. :return: None if brushName was not found
  281. """
  282. if brushName in self.brushes:
  283. return self.brushes[brushName]
  284. return None
  285. def SetItemDrawOrder(self, item, drawNum):
  286. """Set draw order for item
  287. :param item: (GraphicsSetItem)
  288. :param drawNum: drawing order of item to be set
  289. :type drawNum: int
  290. :return: True if order was changed
  291. :return: False if drawNum is out of range or item was not found
  292. """
  293. if drawNum < len(self.itemsList) and drawNum >= 0 and item in self.itemsList:
  294. self.itemsList.insert(
  295. drawNum, self.itemsList.pop(self.itemsList.index(item))
  296. )
  297. return True
  298. return False
  299. def GetItemDrawOrder(self, item):
  300. """Get draw order for given item
  301. :param item: (GraphicsSetItem)
  302. :return: (int) - drawing order of item
  303. :return: None - if item was not found
  304. """
  305. try:
  306. return self.itemsList.index(item)
  307. except ValueError:
  308. return None
  309. def _clearId(self, drawid):
  310. """Clears old object before drawing new object."""
  311. try:
  312. self.pdc.ClearId(drawid)
  313. except:
  314. pass
  315. class GraphicsSetItem:
  316. def __init__(self, coords, penName=None, brushName=None, label=None, hide=False):
  317. """Could be point or line according to graphicsType in
  318. GraphicsSet class
  319. :param coords: list of coordinates (double) of item
  320. Example: point: [1023, 122]
  321. line: [[10, 12],[20,40],[23, 2334]]
  322. rectangle: [[10, 12], [33, 45]]
  323. :param penName: if it is not defined 'default' pen is used
  324. :type penName: str
  325. :param brushName: if it is not defined 'default' brush is used
  326. :type brushName: str
  327. :param label: label, which will be drawn with point. It is
  328. relevant just for 'point' type
  329. :type label: str
  330. :param hide: if it is True, item is not drawn Hidden items are
  331. also counted in drawing order in GraphicsSet class.
  332. :type hide: bool
  333. """
  334. self.coords = coords
  335. self.properties = {
  336. "penName": penName,
  337. "brushName": brushName,
  338. "hide": hide,
  339. "label": label,
  340. }
  341. self.id = NewId()
  342. def AddProperty(self, propName):
  343. """Adds new property, to set it, call SetPropertyVal afterwards.
  344. :param propName - name of the newly defined property
  345. :type propName: str
  346. """
  347. if propName not in self.properties:
  348. self.properties[propName] = None
  349. def SetPropertyVal(self, propName, propVal):
  350. """Set property value
  351. :param propName: - property name: "penName", "hide" or "label"
  352. - property "label" is relevant just for 'point' type
  353. - or newly defined property name
  354. :type propName: str
  355. :param propVal: property value to be set
  356. :return: True if value was set
  357. :return: False if propName is not "penName", "hide" or "label"
  358. """
  359. if propName in self.properties:
  360. self.properties[propName] = propVal
  361. return True
  362. return False
  363. def GetPropertyVal(self, propName):
  364. """Get property value
  365. Raises KeyError if propName is not "penName", "hide" or
  366. "label".
  367. :param propName: - property name: "penName", "hide" or "label"
  368. - property "label" is relevant just for 'point' type
  369. :type propName: str
  370. :return: value of property
  371. """
  372. if propName in self.properties:
  373. return self.properties[propName]
  374. raise KeyError(_("Property does not exist: %s") % (propName))
  375. def SetCoords(self, coords):
  376. """Set coordinates of item
  377. :param coords: list of east, north coordinates (double) of item
  378. Example:
  379. * point: [1023, 122]
  380. * line: [[10, 12],[20,40],[23, 2334]]
  381. * rectangle: [[10, 12], [33, 45]]
  382. """
  383. self.coords = coords
  384. def GetCoords(self):
  385. """Get item coordinates
  386. :return: coordinates
  387. """
  388. return self.coords
  389. def GetId(self):
  390. """Get item id (drawing id)."""
  391. return self.id