graphics.py 15 KB

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