graphics.py 15 KB

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