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

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/dock.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2734 - (hide annotations)
Thu Mar 1 12:42:59 2007 UTC (18 years ago) by bramz
File MIME type: text/x-python
File size: 14019 byte(s)
made a copy
1 jonathan 561 # Copyright (c) 2003 by Intevation GmbH
2     # Authors:
3     # Jonathan Coles <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8 jonathan 1527 """Classes for creating dockable windows.
9 jonathan 561
10 jonathan 1527 The DockFrame is the main window that will be the parent for the
11     dockable windows.
12    
13     The DockPanel is a panel that all windows that wish to be dockable
14     should derive from.
15     """
16    
17 jonathan 561 __version__ = "$Revision$"
18    
19 jonathan 651 import resource
20    
21 jonathan 561 from Thuban import _
22    
23 dpinte 2700 import wx
24 jonathan 561
25     from Thuban.Lib.connector import Publisher
26    
27 jonathan 566 from dialogs import NonModalDialog
28    
29 jonathan 561 from messages import DOCKABLE_DOCKED, DOCKABLE_UNDOCKED, DOCKABLE_CLOSED
30    
31     ID_BUTTON_DOCK = 4001
32 jonathan 571 ID_BUTTON_CLOSE = 4002
33 jonathan 561
34 jonathan 571 PANEL_ID = 3141
35    
36 jonathan 651 DOCK_BMP = "dock_12"
37     UNDOCK_BMP = "undock_12"
38     CLOSE_BMP = "close_12"
39    
40 dpinte 2700 class DockPanel(wx.Panel):
41 jonathan 1527 """A DockPanel is a panel that should be derived from to create panels
42     that can be docked in a DockFrame.
43     """
44 jonathan 561
45     def __init__(self, parent, id):
46 jonathan 1527 """parent should be a DockableWindow created from
47     DockFrame.CreateDock().
48     """
49 jonathan 561
50 jonathan 571 if not isinstance(parent, DockableWindow):
51     raise TypeError("")
52 jonathan 561
53 dpinte 2700 wx.Panel.__init__(self, parent.GetCurrentParent(), id)
54 jonathan 561
55 jonathan 659 self.parent = parent
56    
57 jonathan 571 #self.SetDockParent(None)
58 jonathan 659 #parent.SetPanel(self)
59 jonathan 571
60 jonathan 659 def Create(self):
61     self.parent.SetPanel(self)
62 dpinte 2700
63 jonathan 561 def SetDockParent(self, parent):
64 jonathan 571 self.__dockParent = parent
65 jonathan 561
66     def GetDockParent(self):
67 jonathan 571 return self.__dockParent
68 jonathan 561
69 jonathan 571 def SetDock(self, dock):
70 jonathan 1527 """Specifically set the docked state of the panel
71     to dock (True or False).
72     """
73 jonathan 571 #if dock == self.IsDocked(): return
74    
75     if dock:
76     self.Dock()
77     else:
78     self.UnDock()
79    
80 jonathan 561 def Dock(self):
81 jonathan 1527 """Dock the panel in the DockFrame."""
82 jonathan 561 self.GetDockParent().Dock()
83    
84     def UnDock(self):
85 jonathan 1527 """Undock the panel in the DockFrame."""
86 jonathan 561 self.GetDockParent().UnDock()
87    
88     def IsDocked(self):
89 jonathan 1527 """Return True if the panel is docked."""
90 jonathan 561 return self.GetDockParent().IsDocked()
91    
92 jonathan 571 class DockableWindow(Publisher):
93 jonathan 561
94 jonathan 571 def __getattr__(self, attr):
95     return getattr(self.__topWindow, attr)
96    
97 dpinte 2700 def __init__(self, parent, id, name, title, dockWindow, orient):
98 jonathan 659 """Create the dockable window.
99 jonathan 561
100 jonathan 659 Initially, the window is hidden, but in an undocked state.
101     """
102    
103 jonathan 571 if not isinstance(parent, DockFrame): raise TypeError("")
104 jonathan 561
105 jonathan 571 self.__parent = parent
106     self.__id = id
107     self.__name = name
108 jonathan 561
109 jonathan 571 self.__orientation = orient
110 jonathan 561
111 jonathan 571 self.__dockWindow = dockWindow
112 dpinte 2700 self.__floatWindow = wx.Frame(parent, id, title)
113 jonathan 561
114 jonathan 571 self.__docked = False
115     if self.__docked:
116     self.__topWindow = self.__dockWindow
117     else:
118     self.__topWindow = self.__floatWindow
119 jonathan 561
120 jonathan 571 self.__floatSize = None
121     self.__floatPosition = None
122    
123 jonathan 659 self.__dockPanel = None
124 jonathan 571 self.__panel = None
125    
126     self.__dockWindow.Hide()
127     self.__floatWindow.Hide()
128    
129 dpinte 2700 self.Bind(wx.EVT_CLOSE, self._OnClose)
130 jonathan 571
131     ##
132     # Public methods
133     #
134    
135     def GetName(self):
136     return self.__name
137    
138     def SetPanel(self, panel):
139    
140 jonathan 561 if not isinstance(panel, DockPanel):
141     raise TypeError("")
142    
143 jonathan 571 self.__panel = panel
144     self.__panel.SetDockParent(self)
145 jonathan 561 self.__CreateBorder()
146 jonathan 571
147     self.SetDock(self.__docked)
148    
149     def GetPanel(self):
150     return self.__panel
151 dpinte 2700
152 jonathan 571 def GetCurrentParent(self):
153     return self.__topWindow
154    
155 jonathan 561 def SetDock(self, dock):
156 jonathan 571
157     self.__CheckAllGood()
158 dpinte 2700
159 jonathan 561 if dock:
160     self.Dock()
161     else:
162     self.UnDock()
163    
164     def Dock(self):
165 jonathan 1527 """Dock the window."""
166 jonathan 571 self.__CheckAllGood()
167 jonathan 561
168 jonathan 571 wasVisible = self.IsShown()
169 jonathan 561
170 jonathan 571 if wasVisible: self.Show(False)
171 jonathan 561
172 jonathan 571 self.__docked = True
173 jonathan 561
174 jonathan 571 #
175     # save window information
176     #
177     self.__floatSize = self.GetSize()
178     self.__floatPosition = self.GetPosition()
179 jonathan 561
180 jonathan 571 #
181     # reparent
182     #
183     self.__topWindow = self.__dockWindow
184     self.__dockPanel.Reparent(self.__topWindow)
185 jonathan 561
186 jonathan 667 self.__dockButton.SetBitmapLabel(self.__bmpUnDock)
187     self.__dockButton.SetBitmapFocus(self.__bmpUnDock)
188     self.__dockButton.SetBitmapSelected(self.__bmpUnDock)
189     self.__dockButton.SetBitmapDisabled(self.__bmpUnDock)
190 dpinte 2700 self.__dockButton.SetToolTip(wx.ToolTip(_("Undock")))
191 jonathan 561
192 jonathan 571 self.SetDockSize(self.__dockWindow.GetSize())
193 jonathan 561
194 jonathan 571 if wasVisible: self.Show(True)
195    
196     self.issue(DOCKABLE_DOCKED, self.__id, self)
197    
198 jonathan 561 def UnDock(self):
199 jonathan 1527 """Undock the window."""
200 jonathan 571 self.__CheckAllGood()
201 jonathan 561
202 jonathan 571 wasVisible = self.IsShown()
203 jonathan 561
204 jonathan 571 if wasVisible: self.Show(False)
205    
206     self.__docked = False
207 dpinte 2700
208 jonathan 571 #
209     # reparent
210     #
211     self.__topWindow = self.__floatWindow
212     self.__dockPanel.Reparent(self.__topWindow)
213 jonathan 561
214 jonathan 667 self.__dockButton.SetBitmapLabel(self.__bmpDock)
215     self.__dockButton.SetBitmapFocus(self.__bmpDock)
216     self.__dockButton.SetBitmapSelected(self.__bmpDock)
217     self.__dockButton.SetBitmapDisabled(self.__bmpDock)
218 dpinte 2700 self.__dockButton.SetToolTip(wx.ToolTip(_("Dock")))
219 jonathan 561
220 jonathan 571 if wasVisible: self.Show()
221 jonathan 561
222 jonathan 571 #
223     # restore window information
224     #
225 dpinte 2700 if self.__floatPosition is not None:
226 jonathan 666 self.SetPosition(self.__floatPosition)
227 dpinte 2700 if self.__floatSize is not None:
228 jonathan 666 self.SetSize(self.__floatSize)
229 jonathan 561
230 jonathan 620 self.__dockPanel.SetSize(self.__topWindow.GetClientSize())
231    
232 jonathan 571 self.issue(DOCKABLE_UNDOCKED, self.__id, self)
233 jonathan 561
234     def IsDocked(self):
235 jonathan 571 self.__CheckAllGood()
236     return self.__docked
237 jonathan 561
238 jonathan 571 def Show(self, show = True):
239 jonathan 1527 """Show or hide the window."""
240 jonathan 571 if show:
241     self.__DoShow()
242     else:
243     self.__DoHide()
244 jonathan 561
245 jonathan 571 def SetDockSize(self, rect = None):
246 jonathan 1527 """Set the size of the dock window to rect."""
247 jonathan 561
248 jonathan 571 w0, h0 = self.__dockPanel.GetBestSize()
249     w, h = self.__panel.GetBestSize()
250 jonathan 561
251 jonathan 571 if (w, h) < (w0, h0):
252     w = w0
253     h = h0
254 jonathan 659
255 jonathan 571 if rect is not None:
256     rw = rect.width
257     rh = rect.height
258     if rw < w: rw = w
259     if rh < h: rh = h
260     else:
261     rw = w
262     rh = h
263 dpinte 2700
264 jonathan 571 # these are to account for the border?!!?
265     rw += 8 # XXX: without this the sash isn't visible!?!?!?!
266     rh += 8 # XXX: without this the sash isn't visible!?!?!?!
267 jonathan 561
268 dpinte 2700 self.__dockWindow.SetDefaultSize(wx.Size(rw, rh))
269 jonathan 561
270 dpinte 2700
271 jonathan 577 def Destroy(self):
272     self.__panel.Destroy()
273 jonathan 571 self.__floatWindow.Destroy()
274     self.__dockWindow.Destroy()
275 jonathan 631 self.__parent.OnDockDestroy(self)
276 dpinte 2700
277 jonathan 571 ##
278     # Event handlers
279     #
280 jonathan 561
281 jonathan 571 def _OnButtonClose(self, event):
282 jonathan 583 #self.Close()
283 jonathan 631 self.Show(False)
284 jonathan 561
285 jonathan 571 def _OnClose(self, force = False):
286 jonathan 631 self.Show(False)
287 jonathan 561
288 jonathan 571 def _OnToggleDock(self, event):
289     self.__CheckAllGood()
290 jonathan 561
291 jonathan 571 self.SetDock(not self.IsDocked())
292 jonathan 561
293 jonathan 571 ##
294     # Private methods
295     #
296 jonathan 561
297 jonathan 571 def __CheckAllGood(self):
298     if self.__panel is None:
299     raise TypeError("")
300 jonathan 561
301 jonathan 571 def __DoShow(self):
302     if self.IsShown(): return
303 jonathan 561
304 jonathan 571 self.__topWindow.Show()
305 jonathan 561
306 jonathan 571 if self.__topWindow is self.__dockWindow:
307     self.__parent._UpdateDocks()
308 dpinte 2700
309 jonathan 571 def __DoHide(self):
310     if not self.IsShown(): return
311 jonathan 666
312 jonathan 571 self.__topWindow.Show(False)
313    
314     if self.__topWindow is self.__dockWindow:
315     self.__parent._UpdateDocks()
316    
317     def __CreateBorder(self):
318    
319 dpinte 2700 self.__dockPanel = wx.Panel(self.__topWindow, -1, style=wx.SUNKEN_BORDER)
320 jonathan 571
321 jonathan 657 self.__panel.Reparent(self.__dockPanel)
322     self.__panel.SetId(PANEL_ID)
323    
324 dpinte 2700 if self.__orientation == wx.LAYOUT_VERTICAL:
325     sizer = wx.BoxSizer(wx.VERTICAL)
326     headerBoxOrient = wx.HORIZONTAL
327 jonathan 561 else:
328 dpinte 2700 sizer = wx.BoxSizer(wx.HORIZONTAL)
329     headerBoxOrient = wx.VERTICAL
330 jonathan 561
331    
332 dpinte 2700 headerBox = wx.StaticBoxSizer(
333     wx.StaticBox(self.__dockPanel, -1, ""), headerBoxOrient)
334    
335 jonathan 571 #
336     # ideally, we should be able to rotate this text depending on
337     # our orientation
338     #
339 dpinte 2700 text = wx.StaticText(self.__dockPanel, -1, self.GetTitle(),
340     style = wx.ALIGN_CENTRE)
341 jonathan 651 font = text.GetFont()
342     font.SetPointSize(10)
343     text.SetFont(font)
344    
345 jonathan 561 #
346 jonathan 666 # load the dock/undock/close bitmaps
347     # and create the buttons
348 jonathan 561 #
349 jonathan 657 self.__bmpDock = \
350 dpinte 2700 resource.GetBitmapResource(DOCK_BMP, wx.BITMAP_TYPE_XPM)
351 jonathan 657 self.__bmpUnDock = \
352 dpinte 2700 resource.GetBitmapResource(UNDOCK_BMP, wx.BITMAP_TYPE_XPM)
353 jonathan 561
354 jonathan 666 if self.__docked:
355     bmp = self.__bmpDock
356 jonathan 651 else:
357 jonathan 666 bmp = self.__bmpUnDock
358 jonathan 561
359 dpinte 2700 self.__dockButton = wx.BitmapButton(
360     self.__dockPanel, ID_BUTTON_DOCK,
361     bmp,
362     size = wx.Size(bmp.GetWidth() + 4, bmp.GetHeight() + 4),
363     style = wx.BU_EXACTFIT | wx.ADJUST_MINSIZE)
364 jonathan 561
365 dpinte 2700 bmp = resource.GetBitmapResource(CLOSE_BMP, wx.BITMAP_TYPE_XPM)
366 jonathan 651
367 dpinte 2700 closeX = wx.BitmapButton(self.__dockPanel, ID_BUTTON_CLOSE, bmp,
368     size = wx.Size(bmp.GetWidth() + 4,
369 jonathan 651 bmp.GetHeight() + 4),
370 dpinte 2700 style = wx.BU_EXACTFIT | wx.ADJUST_MINSIZE)
371     closeX.SetToolTip(wx.ToolTip(_("Close")))
372 jonathan 651
373 jonathan 666 #
374     # fill in the sizer in an order appropriate to the orientation
375     #
376 dpinte 2700 if self.__orientation == wx.LAYOUT_VERTICAL:
377     headerBox.Add(text, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTRE_VERTICAL, 0)
378     headerBox.Add((1, 5), 1, wx.GROW)
379     headerBox.Add(self.__dockButton, 0, wx.ALIGN_RIGHT, 0)
380     headerBox.Add(closeX, 0, wx.ALIGN_RIGHT | wx.LEFT, 4)
381 jonathan 571 else:
382 dpinte 2700 headerBox.Add(closeX, 0, wx.ALIGN_RIGHT | wx.BOTTOM, 4)
383     headerBox.Add(self.__dockButton, 0, wx.ALIGN_RIGHT, 0)
384     headerBox.Add(text, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTRE_VERTICAL, 0)
385 jonathan 561
386 dpinte 2700 sizer.Add(headerBox, 0, wx.GROW, 0)
387     sizer.Add(self.__panel, 1, wx.GROW, 0)
388 jonathan 561
389 jonathan 666
390 jonathan 659 self.__dockPanel.SetAutoLayout(True)
391     self.__dockPanel.SetSizer(sizer)
392     sizer.SetSizeHints(self.__dockPanel)
393 jonathan 666 sizer.SetSizeHints(self.__floatWindow)
394 jonathan 571
395 dpinte 2700 self.Bind(wx.EVT_BUTTON, self._OnToggleDock, self.__dockPanel, id=ID_BUTTON_DOCK)
396     self.Bind(wx.EVT_BUTTON, self._OnButtonClose, self.__dockPanel, id=ID_BUTTON_CLOSE)
397 jonathan 571
398    
399 dpinte 2700 class DockFrame(wx.Frame):
400 jonathan 1527 """A DockFrame is a frame that will contain dockable panels."""
401 jonathan 571
402     def __init__(self, parent, id, title, position, size):
403 dpinte 2700 wx.Frame.__init__(self, parent, id, title, position, size)
404 jonathan 571
405     self.openWindows = {}
406    
407 jonathan 577 self.__update_lock = 0
408 jonathan 571
409     self.SetMainWindow(None)
410    
411 jonathan 577
412 dpinte 2700 self.Bind(wx.EVT_SIZE, self._OnSashSize)
413     self.Bind(wx.EVT_CLOSE, self.OnClose)
414 jonathan 577
415 dpinte 2700 layout2oppSash = {
416     wx.LAYOUT_NONE : wx.SASH_NONE,
417     wx.LAYOUT_TOP : wx.SASH_BOTTOM,
418     wx.LAYOUT_LEFT : wx.SASH_RIGHT,
419     wx.LAYOUT_RIGHT : wx.SASH_LEFT,
420     wx.LAYOUT_BOTTOM : wx.SASH_TOP }
421 jonathan 571
422 jonathan 577
423 jonathan 973 def OnClose(self, event):
424 jonathan 577
425     self.__update_lock += 1
426    
427     #
428     # child windows are not notified when the parent is destroyed
429     # as of v2.4.0.3 so we need to interate over our children
430     # and tell them to go away.
431     #
432     for key in self.openWindows.keys():
433     win = self.openWindows[key]
434     win.Destroy()
435    
436     self.__update_lock -= 1
437    
438     # should really call _UpdateDocks() here but we don't need to
439     # since we're going away
440    
441 jonathan 571 def CreateDock(self, name, id, title, align):
442 jonathan 1527 """Create a new dock. align specifies where the dock will
443     be placed. It can be one of wxLAYOUT_NONE, wxLAYOUT_LEFT,
444     wxLAYOUT_RIGHT.
445     """
446 jonathan 571
447 dpinte 2700 if align in (wx.LAYOUT_NONE, wx.LAYOUT_LEFT, wx.LAYOUT_RIGHT):
448     orient = wx.LAYOUT_VERTICAL
449 jonathan 571 else:
450 dpinte 2700 orient = wx.LAYOUT_HORIZONTAL
451 jonathan 571
452 dpinte 2700 sash = wx.SashLayoutWindow(self, id, style=wx.NO_BORDER|wx.SW_3D)
453 jonathan 571 sash.SetOrientation(orient)
454     sash.SetAlignment(align)
455     sash.SetSashVisible(DockFrame.layout2oppSash[align], True)
456     sash.SetSashBorder(DockFrame.layout2oppSash[align], True)
457    
458     win = DockableWindow(self, id, name, title, sash, orient)
459    
460     self.__RegisterDock(name, win)
461 dpinte 2700 self.Bind(wx.EVT_SASH_DRAGGED, self._OnSashDragged, id=id)
462 jonathan 571
463     return win
464    
465     def FindRegisteredDock(self, name):
466 jonathan 1527 """Return a reference to a dock that has name."""
467 jonathan 571 return self.openWindows.get(name)
468    
469 jonathan 631 def OnDockDestroy(self, win):
470 jonathan 571 del self.openWindows[win.GetName()]
471     self._UpdateDocks()
472    
473     def SetMainWindow(self, main):
474     self.__mainWindow = main
475     self._UpdateDocks()
476 dpinte 2700
477 jonathan 571 def _UpdateDocks(self):
478 jonathan 577 if self.__update_lock == 0:
479 dpinte 2700 wx.LayoutAlgorithm().LayoutWindow(self, self.__mainWindow)
480 jonathan 571
481     def _OnSashDragged(self, event):
482 dpinte 2700 if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE:
483 jonathan 571 return
484    
485     id = event.GetId()
486     sash = self.FindWindowById(id)
487     #assert(isinstance(win, wxPanel))
488     dockPanel = sash.GetChildren()[0]
489     panel = dockPanel.FindWindowById(PANEL_ID)
490 jonathan 605 assert isinstance(panel, DockPanel)
491 jonathan 571 win = panel.GetDockParent()
492 jonathan 605 assert isinstance(win, DockableWindow)
493 jonathan 571
494 jonathan 605 assert win.IsDocked()
495 jonathan 571
496     rect = event.GetDragRect()
497    
498     win.SetDockSize(rect)
499    
500     self._UpdateDocks()
501    
502     def _OnSashSize(self, event):
503     self._UpdateDocks()
504    
505     def __RegisterDock(self, name, win):
506     if self.FindRegisteredDock(name) is not None:
507     raise ValueError(
508     "A dockable window is already registered under the name '%s'" % name)
509    
510     self.openWindows[name] = win
511    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26