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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26