/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/legend.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/UI/legend.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2562 - (show annotations)
Wed Feb 16 21:14:47 2005 UTC (20 years ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/legend.py
File MIME type: text/x-python
File size: 25030 byte(s)
Further wxPython 2.5 changes using patches from Daniel Calvelo Aros
so that that wxproj doesn't crash. Added GUI support for selecting
alpha channel (opacity can't be selected yet).

1 # Copyright (c) 2001, 2002, 2003, 2005 by Intevation GmbH
2 # Authors:
3 # Jonathan Coles <[email protected]>
4 # Frank Koormann <[email protected]>
5 #
6 # This program is free software under the GPL (>=v2)
7 # Read the file COPYING coming with Thuban for details.
8
9 __version__ = "$Revision$"
10
11 from math import fabs, cos, pi
12
13 from Thuban import _
14
15 import resource
16
17 from wxPython.wx import *
18 import wxPython
19
20 from Thuban.Model.layer import BaseLayer
21 from Thuban.Model.map import Map
22 from Thuban.Model.classification import ClassGroup
23 from Thuban.Model.proj import PROJ_UNITS_DEGREES
24
25 from Thuban.Model.messages import \
26 MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
27 LAYER_VISIBILITY_CHANGED, TITLE_CHANGED
28
29 from Thuban.UI.messages import SCALE_CHANGED
30
31 from Thuban.UI.classifier import ClassDataPreviewer
32 from Thuban.UI.dock import DockPanel
33 from Thuban.UI.scalebar import ScaleBar
34
35 from Thuban.UI.menu import Menu
36
37 from Thuban.Lib.connector import ConnectorError
38
39 ID_LEGEND_TOP = 4001
40 ID_LEGEND_RAISE = 4002
41 ID_LEGEND_LOWER = 4003
42 ID_LEGEND_BOTTOM = 4004
43 ID_LEGEND_TREE = 4005
44 ID_LEGEND_PROPS = 4006
45 ID_LEGEND_SHOWLAYER = 4007
46 ID_LEGEND_HIDELAYER = 4008
47
48 BMP_SIZE_W = 15
49 BMP_SIZE_H = 15
50
51 TOP_BMP = "top_layer"
52 RAISE_BMP = "raise_layer"
53 LOWER_BMP = "lower_layer"
54 BOTTOM_BMP = "bottom_layer"
55 SHOW_BMP = "show_layer"
56 HIDE_BMP = "hide_layer"
57 PROPS_BMP = "layer_properties"
58
59 class LegendPanel(DockPanel):
60
61 def __init__(self, parent, map, mainWindow):
62 DockPanel.__init__(self, parent, -1)
63
64 self.mainWindow = mainWindow
65 self.parent = parent
66
67 self.buttons = []
68
69 panelBox = wxBoxSizer(wxVERTICAL)
70
71 self.toolBar = wxToolBar(self, -1)
72 self.toolBar.SetToolBitmapSize(wxSize(24, 24))
73
74 bmp = resource.GetBitmapResource(TOP_BMP, wxBITMAP_TYPE_XPM)
75 self.toolBar.AddTool(ID_LEGEND_TOP, bmp,
76 shortHelpString=_("Top Layer"))
77
78 bmp = resource.GetBitmapResource(RAISE_BMP, wxBITMAP_TYPE_XPM)
79 self.toolBar.AddTool(ID_LEGEND_RAISE, bmp,
80 shortHelpString=_("Raise Layer"))
81
82 bmp = resource.GetBitmapResource(LOWER_BMP, wxBITMAP_TYPE_XPM)
83 self.toolBar.AddTool(ID_LEGEND_LOWER, bmp,
84 shortHelpString=_("Lower Layer"))
85
86 bmp = resource.GetBitmapResource(BOTTOM_BMP, wxBITMAP_TYPE_XPM)
87 self.toolBar.AddTool(ID_LEGEND_BOTTOM, bmp,
88 shortHelpString=_("Bottom Layer"))
89
90 bmp = resource.GetBitmapResource(SHOW_BMP, wxBITMAP_TYPE_XPM)
91 self.toolBar.AddTool(ID_LEGEND_SHOWLAYER, bmp,
92 shortHelpString=_("Show Layer"))
93
94 bmp = resource.GetBitmapResource(HIDE_BMP, wxBITMAP_TYPE_XPM)
95 self.toolBar.AddTool(ID_LEGEND_HIDELAYER, bmp,
96 shortHelpString=_("Hide Layer"))
97
98 bmp = resource.GetBitmapResource(PROPS_BMP, wxBITMAP_TYPE_XPM)
99 self.toolBar.AddTool(ID_LEGEND_PROPS, bmp,
100 shortHelpString=_("Edit Layer Properties"))
101
102 self.toolBar.Realize()
103 panelBox.Add(self.toolBar, 0, wxGROW, 0)
104
105 EVT_TOOL(self, ID_LEGEND_TOP, self._OnMoveTop)
106 EVT_TOOL(self, ID_LEGEND_RAISE, self._OnMoveUp)
107 EVT_TOOL(self, ID_LEGEND_LOWER, self._OnMoveDown)
108 EVT_TOOL(self, ID_LEGEND_BOTTOM, self._OnMoveBottom)
109 EVT_TOOL(self, ID_LEGEND_PROPS, self._OnProperties)
110 EVT_TOOL(self, ID_LEGEND_SHOWLAYER, self._OnShowLayer)
111 EVT_TOOL(self, ID_LEGEND_HIDELAYER, self._OnHideLayer)
112
113 self.tree = LegendTree(self, ID_LEGEND_TREE, map, mainWindow)
114
115 panelBox.Add(self.tree, 1, wxGROW, 0)
116
117 self.scalebarbitmap = ScaleBarBitmap(self, map, mainWindow)
118 panelBox.Add(self.scalebarbitmap, 0, wxGROW, 0)
119
120 self.SetAutoLayout(True)
121 self.SetSizer(panelBox)
122 panelBox.SetSizeHints(self)
123
124
125 self.panelBox = panelBox
126
127 self.__EnableButtons(False)
128
129 self.Create()
130
131 EVT_CLOSE(self, self._OnClose)
132
133
134 def GetMap(self):
135 return self.tree.GetMap()
136
137 def SetMap(self, map):
138 self.tree.SetMap(map)
139 self.scalebarbitmap.SetCanvas(self.mainWindow.canvas)
140
141 def DoOnSelChanged(self, layer, group):
142
143 ok = isinstance(layer, BaseLayer)
144 self.__EnableButtons(ok)
145
146 self.mainWindow.SelectLayer(layer)
147
148 def DoOnProperties(self):
149 list = self.tree.GetSelectedHierarchy()
150
151 ok = isinstance(list[0], BaseLayer)
152 if ok:
153 self.mainWindow.OpenLayerProperties(list[0], list[1])
154
155 def Destroy(self):
156 self.__Close()
157
158 def _OnProperties(self, event):
159 self.DoOnProperties()
160
161 def _OnMoveTop(self, event):
162 self.tree.MoveCurrentItemTop()
163
164 def _OnMoveUp(self, event):
165 self.tree.MoveCurrentItemUp()
166
167 def _OnMoveDown(self, event):
168 self.tree.MoveCurrentItemDown()
169
170 def _OnMoveBottom(self, event):
171 self.tree.MoveCurrentItemBottom()
172
173 def _OnShowLayer(self, event):
174 self.tree.DoOnShowLayer()
175 pass
176
177 #def Close(self, force = False):
178 #DockPanel.Close(self, force)
179
180 def _OnClose(self, event):
181 self.__Close()
182
183 def _OnHideLayer(self, event):
184 self.tree.DoOnHideLayer()
185 pass
186
187 def _OnToggleVisibility(self, event):
188 self.tree.ToggleVisibility()
189
190 def _OnProjection(self, event):
191 self.tree.LayerProjection()
192
193 def _OnRemoveLayer(self, event):
194 self.mainWindow.RemoveLayer()
195
196 def _OnShowTable(self, event):
197 self.mainWindow.LayerShowTable()
198
199 def __EnableButtons(self, on):
200 self.toolBar.EnableTool(ID_LEGEND_TOP, on)
201 self.toolBar.EnableTool(ID_LEGEND_RAISE, on)
202 self.toolBar.EnableTool(ID_LEGEND_LOWER, on)
203 self.toolBar.EnableTool(ID_LEGEND_BOTTOM, on)
204 self.toolBar.EnableTool(ID_LEGEND_SHOWLAYER, on)
205 self.toolBar.EnableTool(ID_LEGEND_HIDELAYER, on)
206 self.toolBar.EnableTool(ID_LEGEND_PROPS, on)
207
208 def __Close(self):
209 self.tree.Close()
210
211 class LegendTree(wxTreeCtrl):
212
213 def __init__(self, parent, id, map, mainWindow):
214 wxTreeCtrl.__init__(self, parent, id,
215 style = wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT,
216 size = (200, 200))
217
218 self.mainWindow = mainWindow
219 self.map = None
220 self.parent = parent
221 self.changing_selection = 0
222
223 #
224 # The image list used by the wxTreeCtrl causes problems when
225 # we remove layers and/or change a classification because it
226 # changes the image indices if you remove images from the list.
227 # Rather than removing unused images we use this list to keep
228 # track of which indices are available in the image list
229 # (because of a previous removal) and then replace those indices
230 # with new images rather than appending to the end of the image
231 # list (assuming there are any that are available).
232 #
233 self.availImgListIndices = []
234
235 self.image_list = None
236 self.emptyImageIndex = 0
237
238 self.previewer = ClassDataPreviewer()
239
240 self.preventExpandCollapse = False
241 self.raiseProperties = False
242
243 EVT_TREE_ITEM_ACTIVATED(self, ID_LEGEND_TREE, self._OnItemActivated)
244 EVT_TREE_SEL_CHANGED(self, ID_LEGEND_TREE, self._OnSelChanged)
245 EVT_TREE_ITEM_EXPANDING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
246 EVT_TREE_ITEM_COLLAPSING(self, ID_LEGEND_TREE, self.OnItemExpandCollapse)
247 EVT_TREE_ITEM_RIGHT_CLICK(self, ID_LEGEND_TREE, self._OnRightClick)
248
249 EVT_CLOSE(self, self._OnClose)
250
251 self.SetMap(map)
252
253 def _OnRightClick(self, event):
254 """Select item and pop up a context menu"""
255
256 # The pop up menu is related to the legend tree, so we have direct
257 # access on the tree items. The events issued by the menu are handled
258 # by the legend panel, since most of the handlers are already
259 # implemented there.
260
261 # Update item selection to the right click
262 item = event.GetItem()
263 self.SelectItem(item)
264
265 # Define the menu
266 popup_menu = Menu("PopUp", "",
267 [ "layer_visibility",
268 None,
269 "layer_properties",
270 "layer_projection",
271 "layer_remove",
272 "layer_show_table",
273 None,
274 "layer_to_top",
275 "layer_raise",
276 "layer_lower",
277 "layer_to_bottom"
278 ])
279
280 # Display the menu
281 pos = event.GetPoint()
282 shift = self.ClientToScreen((0,0))
283 self.PopupMenu(self.mainWindow.build_menu(popup_menu), pos)
284
285 def find_layer(self, layer):
286 """Return the tree item for the layer"""
287 root = self.GetRootItem()
288 id, cookie = self.GetFirstChild(root)
289 while id.IsOk():
290 if self.GetPyData(id) is layer:
291 return id
292 id, cookie = self.GetNextChild(root, cookie)
293 return None
294
295 def _OnClose(self, event):
296 self.SetMap(None)
297
298 def GetMap(self):
299 return self.map
300
301 def SetMap(self, map):
302
303 sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),
304 (MAP_LAYERS_ADDED, self._OnMsgMapLayersAdded),
305 (MAP_LAYERS_REMOVED, self._OnMsgMapLayersRemoved)]
306
307 if self.map is not None:
308 for msg, func in sub_list: self.map.Unsubscribe(msg, func)
309 #self.mainWindow.application.Unsubscribe(SESSION_REPLACED,
310 #self._OnMsgMapsChanged)
311 #try:
312 #self.mainWindow.application.session.Unsubscribe(MAPS_CHANGED,
313 #self._OnMsgMapsChanged)
314 #except ConnectorError:
315 #pass
316 self.DeleteAllItems()
317
318 self.map = map
319
320 if self.map is not None:
321 for msg, func in sub_list: self.map.Subscribe(msg, func)
322 #self.mainWindow.application.session.Subscribe(MAPS_CHANGED,
323 #self._OnMsgMapsChanged)
324 #self.mainWindow.application.Subscribe(SESSION_REPLACED,
325 #self._OnMsgMapsChanged)
326 self.__FillTree(self.map)
327
328 def MoveCurrentItemTop(self):
329 layer, group = self.GetSelectedHierarchy()
330
331 if layer is not None:
332 self.map.MoveLayerToTop(layer)
333 else:
334 assert False, "Shouldn't be allowed."
335 pass
336
337 def MoveCurrentItemUp(self):
338 layer, group = self.GetSelectedHierarchy()
339
340 if layer is not None:
341 self.map.RaiseLayer(layer)
342 else:
343 assert False, "Shouldn't be allowed."
344 pass
345
346 def MoveCurrentItemDown(self):
347 layer, group = self.GetSelectedHierarchy()
348
349 if layer is not None:
350 self.map.LowerLayer(layer)
351 else:
352 assert False, "Shouldn't be allowed."
353 pass
354
355 def MoveCurrentItemBottom(self):
356 layer, group = self.GetSelectedHierarchy()
357
358 if layer is not None:
359 self.map.MoveLayerToBottom(layer)
360 else:
361 assert False, "Shouldn't be allowed."
362 pass
363
364 def OnCompareItems(self, item1, item2):
365
366 data1 = self.GetPyData(item1)
367 data2 = self.GetPyData(item2)
368
369 if isinstance(data1, BaseLayer):
370 layers = self.map.Layers()
371 return layers.index(data2) - layers.index(data1)
372 else:
373 return wxTreeCtrl.OnCompareItems(self, item1, item2)
374
375 def DoOnShowLayer(self):
376 layer, group = self.GetSelectedHierarchy()
377 layer.SetVisible(True)
378
379 def DoOnHideLayer(self):
380 layer, group = self.GetSelectedHierarchy()
381 layer.SetVisible(False)
382
383 def ToggleVisibility(self):
384 layer, group = self.GetSelectedHierarchy()
385
386 layer.SetVisible(not layer.Visible())
387
388 def LayerProjection(self):
389 self.parent.mainWindow.LayerProjection()
390
391 def Sort(self):
392 self.SortChildren(self.GetRootItem())
393
394 def GetSelectedHierarchy(self):
395 id = self.GetSelection()
396
397 if not id.IsOk():
398 return (None, None)
399
400 layer = self.GetPyData(id)
401 group = None
402
403 if isinstance(layer, ClassGroup):
404 id = self.GetItemParent(id)
405 assert id.IsOk()
406 group = layer
407 layer = self.GetPyData(id)
408
409 return (layer, group)
410
411 def _OnMsgMapsChanged(self):
412 #print self.map is self.mainWindow.Map()
413 self.SetMap(self.mainWindow.Map())
414
415 def _OnSelChanged(self, event):
416 # If we change the selection from normalize_selection do nothing.
417 if self.changing_selection:
418 return
419
420 self.normalize_selection()
421 self.__UpdateSelection()
422
423 def normalize_selection(self):
424 """Select the layer containing currently selected item"""
425 # This is really a workaround for a bug in wx where deleting a
426 # subtree with DeleteChildren does not update the selection
427 # properly and can lead to segfaults later because the return
428 # value of GetSelection points to invalid data.
429 item = self.GetSelection()
430 while item.IsOk():
431 object = self.GetPyData(item)
432 if isinstance(object, BaseLayer):
433 break
434 item = self.GetItemParent(item)
435 else:
436 # No layer was found in the chain of parents, so there's
437 # nothing we can do.
438 return
439
440 self.changing_selection = 1
441 try:
442 self.SelectItem(item)
443 finally:
444 self.changing_selection = 0
445
446
447 def OnItemExpandCollapse(self, event):
448 if self.preventExpandCollapse:
449 event.Veto()
450 self.preventExpandCollapse = False
451
452 def _OnItemActivated(self, event):
453 # The following looks strange but is need under Windows to
454 # raise the Properties on double-click: The tree control
455 # always gets an Expanded / Collapsed event after the ItemActivated
456 # on double click, which raises the main window again. We add a second
457 # ItemActivated event to the queue, which simply raises the already
458 # displayed window.
459 if self.raiseProperties:
460 self.parent.DoOnProperties()
461 self.raiseProperties = False
462 else:
463 self.raiseProperties = True
464 self.preventExpandCollapse = True
465 self.parent.DoOnProperties()
466 self.AddPendingEvent(event)
467
468 def _OnMsgLayerChanged(self, layer):
469 assert isinstance(layer, BaseLayer)
470
471 id = self.find_layer(layer)
472 assert id is not None
473
474 self.__FillTreeLayer(id)
475 self.__UpdateSelection()
476
477 def _OnMsgMapStackingChanged(self, *args):
478 self.Sort()
479 id = self.GetSelection()
480
481 if id.IsOk():
482 self.EnsureVisible(id)
483 self.__UpdateSelection()
484
485 def _OnMsgMapLayersAdded(self, map):
486 assert map is self.map
487
488 # Build a dict with all layers known by the the tree as keys
489 layers = {}
490 root = self.GetRootItem()
491 id, cookie = self.GetFirstChild(root)
492 while id.IsOk():
493 layers[self.GetPyData(id)] = 1
494 id, cookie = self.GetNextChild(root, cookie)
495
496 # Add layers in the map but not in the dict
497 i = 0
498 for l in map.Layers():
499 if not l in layers:
500 self.__AddLayer(i, l)
501
502 self.__UpdateSelection()
503
504 def _OnMsgMapLayersRemoved(self, map):
505 assert map is self.map
506
507 layers = map.Layers()
508
509 root = self.GetRootItem()
510 id, cookie = self.GetFirstChild(root)
511 while id.IsOk():
512 if self.GetPyData(id) not in layers:
513 self.__RemoveLayer(id)
514 id, cookie = self.GetNextChild(root, cookie)
515
516
517 self.__UpdateSelection()
518
519 def _OnMsgLayerVisibilityChanged(self, layer):
520 assert isinstance(layer, BaseLayer)
521
522 self.__ShowHideLayer(layer)
523 self.__UpdateSelection()
524
525 def _OnMsgLayerTitleChanged(self, layer):
526
527 id = self.find_layer(layer)
528 if id.IsOk():
529 self.SetItemText(id, layer.Title())
530 self.__UpdateSelection()
531
532 def __UpdateSelection(self):
533 layer, group = self.GetSelectedHierarchy()
534 self.parent.DoOnSelChanged(layer, group)
535
536 def __FillTree(self, map):
537
538 self.Freeze()
539
540 self.DeleteAllItems()
541
542 if map.HasLayers():
543 root = self.GetRootItem()
544 for l in map.Layers():
545 self.__AddLayer(0, l)
546
547 self.Thaw()
548
549 def __FillTreeLayer(self, pid):
550
551 layer = self.GetPyData(pid)
552
553 self.Freeze()
554
555 self.DeleteChildren(pid)
556
557 if layer.HasClassification():
558
559 clazz = layer.GetClassification()
560
561 shapeType = layer.ShapeType()
562
563 show = layer.Visible()
564 for g in clazz:
565 if g.IsVisible():
566 id = self.AppendItem(pid, g.GetDisplayText())
567 self.SetPyData(id, g)
568 self.__SetVisibilityStyle(show, id)
569
570 bmp = self.__BuildGroupImage(g, shapeType)
571
572 if bmp is None:
573 self.SetItemImage(id, -1, wxTreeItemIcon_Normal)
574 self.SetItemImage(id, -1, wxTreeItemIcon_Selected)
575 #self.SetItemSelectedImage(id, -1)
576 else:
577 if self.availImgListIndices:
578 i = self.availImgListIndices.pop(0)
579 self.image_list.Replace(i, bmp)
580 else:
581 i = self.image_list.Add(bmp)
582
583 self.SetItemImage(id, i, wxTreeItemIcon_Normal)
584 self.SetItemImage(id, i, wxTreeItemIcon_Selected)
585 #self.SetItemlectedImage(id, i)
586
587 self.Thaw()
588
589 def __BuildGroupImage(self, group, shapeType):
590
591 bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
592 #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
593 dc = wxMemoryDC()
594 dc.SelectObject(bmp)
595 dc.Clear()
596
597 self.previewer.Draw(dc, None, group.GetProperties(), shapeType)
598
599 return bmp
600
601 def DeleteAllItems(self):
602
603 pid = self.GetRootItem()
604
605 id, cookie = self.GetFirstChild(pid)
606 while id.IsOk():
607 self.__RemoveLayer(id)
608 id, cookie = self.GetNextChild(pid, cookie)
609
610 wxTreeCtrl.DeleteAllItems(self)
611
612 def __AddLayer(self, before, l):
613 root = self.GetRootItem()
614 id = self.InsertItemBefore(root, before,
615 l.Title(),
616 self.mapImageIndex,
617 self.mapImageIndex)
618
619 self.SetPyData(id, l)
620 self.__SetVisibilityStyle(l.Visible(), id)
621
622 self.__FillTreeLayer(id)
623 self.Expand(id)
624
625 l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
626 l.Subscribe(LAYER_VISIBILITY_CHANGED,
627 self._OnMsgLayerVisibilityChanged)
628 l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
629
630 def __RemoveLayer(self, id):
631 self.DeleteChildren(id)
632
633 layer = self.GetPyData(id)
634 layer.Unsubscribe(LAYER_CHANGED,
635 self._OnMsgLayerChanged)
636 layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
637 self._OnMsgLayerVisibilityChanged)
638 layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
639
640 self.Delete(id)
641
642 def DeleteChildren(self, pid):
643 id, cookie = self.GetFirstChild(pid)
644 while id.IsOk():
645 self.availImgListIndices.append(self.GetItemImage(id))
646 id, cookie = self.GetNextChild(pid, cookie)
647 wxTreeCtrl.DeleteChildren(self, pid)
648
649 def GetRootItem(self):
650 root = wxTreeCtrl.GetRootItem(self)
651
652 if not root.IsOk():
653 self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
654
655 bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
656 dc = wxMemoryDC()
657 dc.SelectObject(bmp)
658 dc.SetBrush(wxBLACK_BRUSH)
659 dc.Clear()
660 dc.SelectObject(wxNullBitmap)
661
662 self.emptyImageIndex = \
663 self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
664
665 bmp = resource.GetBitmapResource("legend_icon_layer",
666 wxBITMAP_TYPE_XPM)
667 self.mapImageIndex = \
668 self.image_list.Add(bmp)
669
670 self.AssignImageList(self.image_list)
671 self.availImgListIndices = []
672
673 root = self.AddRoot("")
674
675 return root
676
677 def __SetVisibilityStyle(self, visible, id):
678 font = self.GetItemFont(id)
679
680 if visible:
681 font.SetStyle(wxNORMAL)
682 color = wxBLACK
683 else:
684 #font.SetStyle(wxITALIC)
685 font.SetStyle(wxNORMAL)
686 color = wxLIGHT_GREY
687
688 self.SetItemTextColour(id, color)
689 self.SetItemFont(id, font)
690
691 def __ShowHideLayer(self, layer):
692 parent = self.find_layer(layer)
693 assert parent.IsOk()
694
695 visible = layer.Visible()
696
697 self.__SetVisibilityStyle(visible, parent)
698
699 id, cookie = self.GetFirstChild(parent)
700
701 while id.IsOk():
702 self.__SetVisibilityStyle(visible, id)
703 id, cookie = self.GetNextChild(parent, cookie)
704
705 # In wxPython 2.4 the GetFirstChild method has to be called with a
706 # second argument and in 2.5 it must not. Reading the code of
707 # wxPython 2.4 it seems that the second parameter was intended to be
708 # optional there but due to a bug in the C++ code it doesn't work
709 # and omitting the second argument leads to a segfault. To cope
710 # with this and to make the code usable with both 2.5 and 2.4 we
711 # overwrite the inherited method when running with 2.4 to provide a
712 # default value for the second argument.
713 if map(int, wxPython.__version__.split(".")[:2]) < [2, 5]:
714 def GetFirstChild(self, item):
715 return wxTreeCtrl.GetFirstChild(self, item, 0)
716
717
718 class ScaleBarBitmap(wxBoxSizer):
719
720 def __init__(self, parent, map, mainWindow):
721 # While the width is fixed, get the height _now_.
722 dc = wxMemoryDC()
723 textwidth, textheight = dc.GetTextExtent("%d"%0)
724 self.width = 210
725 self.height = textheight + 3*2 + 8
726
727 wxBoxSizer.__init__(self, wxVERTICAL)
728 bmp=wxEmptyBitmap(self.width, self.height)
729 self.scalebarBitmap = wxStaticBitmap(parent, -1, bmp)
730 self.Add(self.scalebarBitmap, 0, wxALIGN_CENTER|wxLEFT|wxTOP|wxRIGHT, 1)
731
732 self.mainWindow = mainWindow
733 self.parent = parent
734 self.canvas = None
735 self.SetCanvas(self.mainWindow.canvas)
736
737 def SetCanvas(self, canvas):
738 sub_list = [(SCALE_CHANGED, self._OnMsgScaleChanged)]
739
740 if self.canvas is not None:
741 for msg, func in sub_list: self.canvas.Unsubscribe(msg, func)
742
743 self.canvas = canvas
744 self.scalebar = ScaleBar(canvas.map)
745
746 if self.canvas is not None:
747 for msg, func in sub_list: self.canvas.Subscribe(msg, func)
748 self.__SetScale(self.canvas.scale)
749
750 def _OnMsgScaleChanged(self, scale):
751 self.__SetScale(scale)
752
753 def __SetScale(self, scale):
754 bmp = wxEmptyBitmap(self.width, self.height)
755 dc = wxMemoryDC()
756 dc.SelectObject(bmp)
757 dc.Clear()
758
759 if self.canvas.map is not None \
760 and self.canvas.map.projection is not None:
761
762 # if we are using a projection with geographics coordinates
763 # we need to change the scale value based on where we are
764 # on the globe.
765 if self.canvas.map.projection.GetProjectedUnits() \
766 == PROJ_UNITS_DEGREES:
767
768 width, height = self.canvas.GetSizeTuple()
769 long, lat = self.canvas.win_to_proj(width/2, height/2)
770
771 # slightly inaccurate, but if we are looking at
772 # the north/south pole we could end up dividing by zero
773 #
774 # it shouldn't matter for our purposes that we ignore
775 # the original sign of lat.
776 if fabs(lat) > 89.9: lat = 89.9
777
778 #
779 # one degree is about 111,133m at the equator
780 # we need to adjust that for latitude as
781 # we move north/south. use the center of the map
782 # as the point to scale the length to.
783 #
784 scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
785
786 self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
787
788 self.scalebarBitmap.SetBitmap(bmp)
789

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26