graphics.py 15 KB

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