/[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 2560 - (show annotations)
Tue Feb 8 20:25:22 2005 UTC (20 years ago) by bh
Original Path: trunk/thuban/Thuban/UI/legend.py
File MIME type: text/x-python
File size: 24834 byte(s)
Compatibility with wxPython 2.5.  The changes should make it work
better with 2.5 while still keeping compatibility with 2.4.  There
are still problems with 2.5, though.

* Thuban/UI/dock.py (DockableWindow.__CreateBorder): Pass the size
of a spacer as a single item.

* Thuban/UI/classifier.py (ClassGroupPropertiesCtrl): Derive only
from wxControl

* Thuban/UI/legend.py (LegendTree): When running with wxPython <
2.5, add an implementation of the GetFirstChild method that does
not require the second parameter.
(LegendTree.find_layer, LegendTree._OnMsgMapLayersAdded)
(LegendTree._OnMsgMapLayersRemoved, LegendTree.DeleteAllItems)
(LegendTree.DeleteChildren, LegendTree.__ShowHideLayer): Do not
pass the second parameter to GetFirstChild

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 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)
573 self.SetItemSelectedImage(id, -1)
574 else:
575 if self.availImgListIndices:
576 i = self.availImgListIndices.pop(0)
577 self.image_list.Replace(i, bmp)
578 else:
579 i = self.image_list.Add(bmp)
580
581 self.SetItemImage(id, i)
582 self.SetItemSelectedImage(id, i)
583
584 self.Thaw()
585
586 def __BuildGroupImage(self, group, shapeType):
587
588 bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
589 #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
590 dc = wxMemoryDC()
591 dc.SelectObject(bmp)
592 dc.Clear()
593
594 self.previewer.Draw(dc, None, group.GetProperties(), shapeType)
595
596 return bmp
597
598 def DeleteAllItems(self):
599
600 pid = self.GetRootItem()
601
602 id, cookie = self.GetFirstChild(pid)
603 while id.IsOk():
604 self.__RemoveLayer(id)
605 id, cookie = self.GetNextChild(pid, cookie)
606
607 wxTreeCtrl.DeleteAllItems(self)
608
609 def __AddLayer(self, before, l):
610 root = self.GetRootItem()
611 id = self.InsertItemBefore(root, before,
612 l.Title(),
613 self.mapImageIndex,
614 self.mapImageIndex)
615
616 self.SetPyData(id, l)
617 self.__SetVisibilityStyle(l.Visible(), id)
618
619 self.__FillTreeLayer(id)
620 self.Expand(id)
621
622 l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
623 l.Subscribe(LAYER_VISIBILITY_CHANGED,
624 self._OnMsgLayerVisibilityChanged)
625 l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
626
627 def __RemoveLayer(self, id):
628 self.DeleteChildren(id)
629
630 layer = self.GetPyData(id)
631 layer.Unsubscribe(LAYER_CHANGED,
632 self._OnMsgLayerChanged)
633 layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
634 self._OnMsgLayerVisibilityChanged)
635 layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
636
637 self.Delete(id)
638
639 def DeleteChildren(self, pid):
640 id, cookie = self.GetFirstChild(pid)
641 while id.IsOk():
642 self.availImgListIndices.append(self.GetItemImage(id))
643 id, cookie = self.GetNextChild(pid, cookie)
644 wxTreeCtrl.DeleteChildren(self, pid)
645
646 def GetRootItem(self):
647 root = wxTreeCtrl.GetRootItem(self)
648
649 if not root.IsOk():
650 self.image_list = wxImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
651
652 bmp = wxEmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
653 dc = wxMemoryDC()
654 dc.SelectObject(bmp)
655 dc.SetBrush(wxBLACK_BRUSH)
656 dc.Clear()
657 dc.SelectObject(wxNullBitmap)
658
659 self.emptyImageIndex = \
660 self.image_list.AddWithColourMask(bmp, wxColour(0, 0, 0))
661
662 bmp = resource.GetBitmapResource("legend_icon_layer",
663 wxBITMAP_TYPE_XPM)
664 self.mapImageIndex = \
665 self.image_list.Add(bmp)
666
667 self.AssignImageList(self.image_list)
668 self.availImgListIndices = []
669
670 root = self.AddRoot("")
671
672 return root
673
674 def __SetVisibilityStyle(self, visible, id):
675 font = self.GetItemFont(id)
676
677 if visible:
678 font.SetStyle(wxNORMAL)
679 color = wxBLACK
680 else:
681 #font.SetStyle(wxITALIC)
682 font.SetStyle(wxNORMAL)
683 color = wxLIGHT_GREY
684
685 self.SetItemTextColour(id, color)
686 self.SetItemFont(id, font)
687
688 def __ShowHideLayer(self, layer):
689 parent = self.find_layer(layer)
690 assert parent.IsOk()
691
692 visible = layer.Visible()
693
694 self.__SetVisibilityStyle(visible, parent)
695
696 id, cookie = self.GetFirstChild(parent)
697
698 while id.IsOk():
699 self.__SetVisibilityStyle(visible, id)
700 id, cookie = self.GetNextChild(parent, cookie)
701
702 # In wxPython 2.4 the GetFirstChild method has to be called with a
703 # second argument and in 2.5 it must not. Reading the code of
704 # wxPython 2.4 it seems that the second parameter was intended to be
705 # optional there but due to a bug in the C++ code it doesn't work
706 # and omitting the second argument leads to a segfault. To cope
707 # with this and to make the code usable with both 2.5 and 2.4 we
708 # overwrite the inherited method when running with 2.4 to provide a
709 # default value for the second argument.
710 if map(int, wxPython.__version__.split(".")[:2]) < [2, 5]:
711 def GetFirstChild(self, item):
712 return wxTreeCtrl.GetFirstChild(self, item, 0)
713
714
715 class ScaleBarBitmap(wxBoxSizer):
716
717 def __init__(self, parent, map, mainWindow):
718 # While the width is fixed, get the height _now_.
719 dc = wxMemoryDC()
720 textwidth, textheight = dc.GetTextExtent("%d"%0)
721 self.width = 210
722 self.height = textheight + 3*2 + 8
723
724 wxBoxSizer.__init__(self, wxVERTICAL)
725 bmp=wxEmptyBitmap(self.width, self.height)
726 self.scalebarBitmap = wxStaticBitmap(parent, -1, bmp)
727 self.Add(self.scalebarBitmap, 0, wxALIGN_CENTER|wxLEFT|wxTOP|wxRIGHT, 1)
728
729 self.mainWindow = mainWindow
730 self.parent = parent
731 self.canvas = None
732 self.SetCanvas(self.mainWindow.canvas)
733
734 def SetCanvas(self, canvas):
735 sub_list = [(SCALE_CHANGED, self._OnMsgScaleChanged)]
736
737 if self.canvas is not None:
738 for msg, func in sub_list: self.canvas.Unsubscribe(msg, func)
739
740 self.canvas = canvas
741 self.scalebar = ScaleBar(canvas.map)
742
743 if self.canvas is not None:
744 for msg, func in sub_list: self.canvas.Subscribe(msg, func)
745 self.__SetScale(self.canvas.scale)
746
747 def _OnMsgScaleChanged(self, scale):
748 self.__SetScale(scale)
749
750 def __SetScale(self, scale):
751 bmp = wxEmptyBitmap(self.width, self.height)
752 dc = wxMemoryDC()
753 dc.SelectObject(bmp)
754 dc.Clear()
755
756 if self.canvas.map is not None \
757 and self.canvas.map.projection is not None:
758
759 # if we are using a projection with geographics coordinates
760 # we need to change the scale value based on where we are
761 # on the globe.
762 if self.canvas.map.projection.GetProjectedUnits() \
763 == PROJ_UNITS_DEGREES:
764
765 width, height = self.canvas.GetSizeTuple()
766 long, lat = self.canvas.win_to_proj(width/2, height/2)
767
768 # slightly inaccurate, but if we are looking at
769 # the north/south pole we could end up dividing by zero
770 #
771 # it shouldn't matter for our purposes that we ignore
772 # the original sign of lat.
773 if fabs(lat) > 89.9: lat = 89.9
774
775 #
776 # one degree is about 111,133m at the equator
777 # we need to adjust that for latitude as
778 # we move north/south. use the center of the map
779 # as the point to scale the length to.
780 #
781 scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
782
783 self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
784
785 self.scalebarBitmap.SetBitmap(bmp)
786

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26