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