graphics.py 14 KB

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