comparison orpg/tools/PyAUI.py @ 0:4385a7d0efd1 grumpy-goblin

Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author sirebral
date Tue, 14 Jul 2009 16:41:58 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4385a7d0efd1
1 # --------------------------------------------------------------------------- #
2 # PYAUI Library wxPython IMPLEMENTATION
3 #
4 # Original C++ Code From Kirix (wxAUI). You Can Find It At:
5 #
6 # License: wxWidgets license
7 #
8 # http://www.kirix.com/en/community/opensource/wxaui/about_wxaui.html
9 #
10 # Current wxAUI Version Tracked: 0.9.2
11 #
12 #
13 # Python Code By:
14 #
15 # Andrea Gavana, @ 23 Dec 2005
16 # Latest Revision: 30 Jun 2006, 21.00 GMT
17 #
18 #
19 # PyAUI version 0.9.2 Adds:
20 #
21 # * Fixes For Display Glitches;
22 # * Fixes For Other Bugs Found In Previous Versions.
23 #
24 #
25 # TODO List/Caveats
26 #
27 # 1. Using The New Versions Of wxPython (2.6.2.1pre.20060106 Or Higher) There
28 # Is A New Method Called wx.GetMouseState() That Gets Rid Of The Import Of
29 # win32all or ctypes. Moreover, It Should Make PyAUI Working On All
30 # Platforms (I Hope).
31 #
32 #
33 # Latest Patches:
34 #
35 # 1) Reduced Flicker While Drawing The Dock Hint
36 # 2) Made Impossoible To Drag The Sash Separator Outside The Main Frame
37 # 3) Improved Repaint When Using The Active Pane Option
38 # 4) Fixed The Mac Problem (Thanks To David Pratt) And Applied The wxGTK Patches
39 # Suggested By Robin Dunn To Correctly Draw The Dock Hint
40 #
41 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
42 # Write To Me At:
43 #
44 # andrea.gavana@agip.it
45 # andrea_gavan@tin.it
46 #
47 # Or, Obviously, To The wxPython Mailing List!!!
48 #
49 # with OS X support and refactoring implemented by Chris Mellon (arkanes@gmail.com) -
50 # contact me directly or on wxPython ML for more info
51 #
52 #
53 # End Of Comments
54 # --------------------------------------------------------------------------- #
55
56 """
57 PyAUI is an Advanced User Interface library that aims to implement "cutting-edge"
58 interface usability and design features so developers can quickly and easily create
59 beautiful and usable application interfaces.
60
61 Vision and Design Principles
62
63 PyAUI attempts to encapsulate the following aspects of the user interface:
64
65 * Frame Management: Frame management provides the means to open, move and hide common
66 controls that are needed to interact with the document, and allow these configurations
67 to be saved into different perspectives and loaded at a later time.
68
69 * Toolbars: Toolbars are a specialized subset of the frame management system and should
70 behave similarly to other docked components. However, they also require additional
71 functionality, such as "spring-loaded" rebar support, "chevron" buttons and end-user
72 customizability.
73
74 * Modeless Controls: Modeless controls expose a tool palette or set of options that
75 float above the application content while allowing it to be accessed. Usually accessed
76 by the toolbar, these controls disappear when an option is selected, but may also be
77 "torn off" the toolbar into a floating frame of their own.
78
79 * Look and Feel: Look and feel encompasses the way controls are drawn, both when shown
80 statically as well as when they are being moved. This aspect of user interface design
81 incorporates "special effects" such as transparent window dragging as well as frame animation.
82
83 PyAUI adheres to the following principles:
84
85 - Use native floating frames to obtain a native look and feel for all platforms;
86 - Use existing wxPython code where possible, such as sizer implementation for frame management;
87 - Use standard wxPython coding conventions.
88
89
90 Usage:
91
92 The following example shows a simple implementation that utilizes AuiManager to manage
93 three text controls in a frame window:
94
95 class MyFrame(wx.Frame):
96
97 def __init__(self, parent, id=-1, title="PyAUI Test", pos=wx.DefaultPosition,
98 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
99
100 wx.Frame.__init__(self, parent, id, title, pos, size, style)
101
102 self._mgr = PyAUI.AuiManager()
103
104 # notify PyAUI which frame to use
105 self._mgr.SetFrame(self)
106
107 # create several text controls
108 text1 = wx.TextCtrl(self, -1, "Pane 1 - sample text",
109 wx.DefaultPosition, wx.Size(200,150),
110 wx.NO_BORDER | wx.TE_MULTILINE)
111
112 text2 = wx.TextCtrl(self, -1, "Pane 2 - sample text",
113 wx.DefaultPosition, wx.Size(200,150),
114 wx.NO_BORDER | wx.TE_MULTILINE)
115
116 text3 = wx.TextCtrl(self, -1, "Main content window",
117 wx.DefaultPosition, wx.Size(200,150),
118 wx.NO_BORDER | wx.TE_MULTILINE)
119
120 # add the panes to the manager
121 self._mgr.AddPane(text1, wx.LEFT, "Pane Number One")
122 self._mgr.AddPane(text2, wx.BOTTOM, "Pane Number Two")
123 self._mgr.AddPane(text3, wx.CENTER)
124
125 # tell the manager to "commit" all the changes just made
126 self._mgr.Update()
127
128 self.Bind(wx.EVT_CLOSE, self.OnClose)
129
130
131 def OnClose(self, event):
132
133 # deinitialize the frame manager
134 self._mgr.UnInit()
135
136 self.Destroy()
137 event.Skip()
138
139
140 # our normal wxApp-derived class, as usual
141
142 app = wx.PySimpleApp()
143
144 frame = MyFrame(None)
145 app.SetTopWindow(frame)
146 frame.Show()
147
148 app.MainLoop()
149
150 What's New:
151
152 PyAUI version 0.9.2 Adds:
153
154 * Fixes For Display Glitches;
155 * Fixes For Other Bugs Found In Previous Versions.
156
157
158 License And Version:
159
160 PyAUI Library Is Freeware And Distributed Under The wxPython License.
161
162 Latest Revision: Andrea Gavana @ 30 Jun 2006, 21.00 GMT
163 Version 0.9.2.
164
165 """
166
167 from orpg.orpg_wx import *
168 import cStringIO, zlib
169 import time
170
171 _libimported = None
172 _newversion = False
173
174 # Check For The New wxVersion: It Should Be > 2.6.2.1pre.20060102
175 # In Order To Let PyAUI Working On All Platforms
176
177 wxver = wx.VERSION_STRING
178 if wxver < "2.7":
179 wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point)
180
181 if hasattr(wx, "GetMouseState"):
182 _newversion = True
183 if wx.Platform == "__WXMSW__":
184 try:
185 import win32api
186 import win32con
187 import winxpgui
188 _libimported = "MH"
189 except:
190 try:
191 import ctypes
192 _libimported = "ctypes"
193 except:
194 pass
195
196 else:
197 if wx.Platform == "__WXMSW__":
198 try:
199 import win32api
200 import win32con
201 import winxpgui
202 _libimported = "MH"
203 except:
204 try:
205 import ctypes
206 _libimported = "ctypes"
207 except:
208 raise "\nERROR: At Present, On Windows Machines, You Need To Install "\
209 "Mark Hammond's pywin32 Extensions Or The ctypes Module, Or Download" \
210 "The Latest wxPython Version."
211
212 else:
213 raise "\nSorry: I Still Don't Know How To Work On GTK/MAC Platforms... " \
214 "Please Download The Latest wxPython Version."
215
216
217 if wx.Platform == "__WXMAC__":
218 try:
219 import ctypes
220 _carbon_dll = ctypes.cdll.LoadLibrary(r'/System/Frameworks/Carbon.framework/Carbon')
221 except:
222 _carbon_dll = None
223
224 # Docking Styles
225 AUI_DOCK_NONE = 0
226 AUI_DOCK_TOP = 1
227 AUI_DOCK_RIGHT = 2
228 AUI_DOCK_BOTTOM = 3
229 AUI_DOCK_LEFT = 4
230 AUI_DOCK_CENTER = 5
231 AUI_DOCK_CENTRE = AUI_DOCK_CENTER
232
233 # Floating/Dragging Styles
234 AUI_MGR_ALLOW_FLOATING = 1
235 AUI_MGR_ALLOW_ACTIVE_PANE = 2
236 AUI_MGR_TRANSPARENT_DRAG = 4
237 AUI_MGR_TRANSPARENT_HINT = 8
238 AUI_MGR_TRANSPARENT_HINT_FADE = 16
239
240 AUI_MGR_DEFAULT = AUI_MGR_ALLOW_FLOATING | \
241 AUI_MGR_TRANSPARENT_HINT | \
242 AUI_MGR_TRANSPARENT_HINT_FADE | \
243 AUI_MGR_TRANSPARENT_DRAG
244
245 # Panes Customization
246 AUI_ART_SASH_SIZE = 0
247 AUI_ART_CAPTION_SIZE = 1
248 AUI_ART_GRIPPER_SIZE = 2
249 AUI_ART_PANE_BORDER_SIZE = 3
250 AUI_ART_PANE_BUTTON_SIZE = 4
251 AUI_ART_BACKGROUND_COLOUR = 5
252 AUI_ART_SASH_COLOUR = 6
253 AUI_ART_ACTIVE_CAPTION_COLOUR = 7
254 AUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR = 8
255 AUI_ART_INACTIVE_CAPTION_COLOUR = 9
256 AUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR = 10
257 AUI_ART_ACTIVE_CAPTION_TEXT_COLOUR = 11
258 AUI_ART_INACTIVE_CAPTION_TEXT_COLOUR = 12
259 AUI_ART_BORDER_COLOUR = 13
260 AUI_ART_GRIPPER_COLOUR = 14
261 AUI_ART_CAPTION_FONT = 15
262 AUI_ART_GRADIENT_TYPE = 16
263
264 # Caption Gradient Type
265 AUI_GRADIENT_NONE = 0
266 AUI_GRADIENT_VERTICAL = 1
267 AUI_GRADIENT_HORIZONTAL = 2
268
269 # Pane Button State
270 AUI_BUTTON_STATE_NORMAL = 0
271 AUI_BUTTON_STATE_HOVER = 1
272 AUI_BUTTON_STATE_PRESSED = 2
273
274 # Pane Insert Level
275 AUI_INSERT_PANE = 0
276 AUI_INSERT_ROW = 1
277 AUI_INSERT_DOCK = 2
278
279 # some built in bitmaps
280 close_bits = '\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00' \
281 '\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00' \
282 '\xef\x00\x00\x00\xfb\x00\x00\x00\xcf\x00\x00\x00\xf9\x00\x00\x00' \
283 '\x9f\x00\x00\x00\xfc\x00\x00\x00?\x00\x00\x00\xfe\x00\x00\x00?\x00' \
284 '\x00\x00\xfe\x00\x00\x00\x9f\x00\x00\x00\xfc\x00\x00\x00\xcf\x00' \
285 '\x00\x00\xf9\x00\x00\x00\xef\x00\x00\x00\xfb\x00\x00\x00\xff\x00' \
286 '\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00' \
287 '\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00'
288
289 pin_bits = '\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff' \
290 '\x00\x00\x00\xff\x00\x00\x00\x1f\x00\x00\x00\xfc\x00\x00\x00\xdf\x00' \
291 '\x00\x00\xfc\x00\x00\x00\xdf\x00\x00\x00\xfc\x00\x00\x00\xdf\x00\x00' \
292 '\x00\xfc\x00\x00\x00\xdf\x00\x00\x00\xfc\x00\x00\x00\xdf\x00\x00\x00' \
293 '\xfc\x00\x00\x00\x0f\x00\x00\x00\xf8\x00\x00\x00\x7f\x00\x00\x00\xff' \
294 '\x00\x00\x00\x7f\x00\x00\x00\xff\x00\x00\x00\x7f\x00\x00\x00\xff\x00' \
295 '\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00' \
296 '\x00\xff\x00\x00\x00\xff\x00\x00\x00'
297
298 # PyAUI Event
299 wxEVT_AUI_PANEBUTTON = wx.NewEventType()
300 EVT_AUI_PANEBUTTON = wx.PyEventBinder(wxEVT_AUI_PANEBUTTON, 0)
301 wxEVT_AUI_PANECLOSE = wx.NewEventType()
302 EVT_AUI_PANECLOSE = wx.PyEventBinder(wxEVT_AUI_PANECLOSE, 0)
303
304
305 def GetCloseData():
306 return zlib.decompress(
307 'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\x02 \xcc\xc1\
308 \x06$\xe5?\xffO\x04R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4Gy\xba8\x86X\xf4\
309 \x9e\r:\xcd\xc7\xa0\xc0\xe1\xf5\xfb\xbf\xff\xbb\xc2\xacb6\xdbg\xaez\xb9|\x1c\
310 \x9a\x82kU\x99xW\x16K\xf5\xdccS\xdad\xe9\xf3\xe0\xa4\x0f\x0f\xaf\xcb\xea\x88\
311 \x8bV\xd7k\x1eoN\xdf\xb2\xdd\xc8\xd0\xe7Cw2{\xdd\\uf\xfd}3\x0f\xb0\xd4=\x0ff\
312 \xdfr$\\\xe5\xcf\xa9\xfd3\xfa\xcdu\xa4\x7fk\xa6\x89\x03ma\xf0t\xf5sY\xe7\x94\
313 \xd0\x04\x00\x1714z')
314
315
316 def GetCloseBitmap():
317 return wx.BitmapFromImage(GetCloseImage())
318
319
320 def GetCloseImage():
321 stream = cStringIO.StringIO(GetCloseData())
322 return wx.ImageFromStream(stream)
323
324
325 def StepColour(c, percent):
326 """
327 StepColour() it a utility function that simply darkens
328 a color by the specified percentage.
329 """
330
331 r = c.Red()
332 g = c.Green()
333 b = c.Blue()
334
335 return wx.Colour(min((r*percent)/100, 255),
336 min((g*percent)/100, 255),
337 min((b*percent)/100, 255))
338
339
340 def LightContrastColour(c):
341
342 amount = 120
343
344 # if the color is especially dark, then
345 # make the contrast even lighter
346 if c.Red() < 128 and c.Green() < 128 and c.Blue() < 128:
347 amount = 160
348
349 return StepColour(c, amount)
350
351
352 def BitmapFromBits(color, type=0):
353 """
354 BitmapFromBits() is a utility function that creates a
355 masked bitmap from raw bits (XBM format).
356 """
357
358 if type == 0: # Close Bitmap
359 img = GetCloseImage()
360 else:
361 # this should be GetClosePin()... but what the hell is a "pin"?
362 img = GetCloseImage()
363
364 img.Replace(255, 255, 255, 123, 123, 123)
365 img.Replace(0, 0, 0, color.Red(), color.Green(), color.Blue())
366
367 return img.ConvertToBitmap()
368
369
370 def DrawGradientRectangle(dc, rect, start_color, end_color, direction):
371
372 rd = end_color.Red() - start_color.Red()
373 gd = end_color.Green() - start_color.Green()
374 bd = end_color.Blue() - start_color.Blue()
375
376 if direction == AUI_GRADIENT_VERTICAL:
377 high = rect.GetHeight() - 1
378 else:
379 high = rect.GetWidth() - 1
380
381 for ii in xrange(high+1):
382 r = start_color.Red() + ((ii*rd*100)/high)/100
383 g = start_color.Green() + ((ii*gd*100)/high)/100
384 b = start_color.Blue() + ((ii*bd*100)/high)/100
385
386 p = wx.Pen(wx.Colour(r, g, b))
387 dc.SetPen(p)
388
389 if direction == AUI_GRADIENT_VERTICAL:
390 dc.DrawLine(rect.x, rect.y+ii, rect.x+rect.width, rect.y+ii)
391 else:
392 dc.DrawLine(rect.x+ii, rect.y, rect.x+ii, rect.y+rect.height)
393
394
395 class DockInfo:
396
397 def __init__(self):
398
399 self.dock_direction = 0
400 self.dock_layer = 0
401 self.dock_row = 0
402 self.size = 0
403 self.min_size = 0
404 self.resizable = True
405 self.fixed = False
406 self.toolbar = False
407 self.rect = wx.Rect()
408 self.panes = []
409
410
411 def IsOk(self):
412
413 return (self.dock_direction != 0 and [True] or [False])[0]
414
415
416 def IsHorizontal(self):
417
418 return ((self.dock_direction == AUI_DOCK_TOP or \
419 self.dock_direction == AUI_DOCK_BOTTOM) and \
420 [True] or [False])[0]
421
422
423 def IsVertical(self):
424
425 return ((self.dock_direction == AUI_DOCK_LEFT or \
426 self.dock_direction == AUI_DOCK_RIGHT or \
427 self.dock_direction == AUI_DOCK_CENTER) and [True] or [False])[0]
428
429
430 class DockUIPart:
431
432 typeCaption = 0
433 typeGripper = 1
434 typeDock = 2
435 typeDockSizer = 3
436 typePane = 4
437 typePaneSizer = 5
438 typeBackground = 6
439 typePaneBorder = 7
440 typePaneButton = 8
441
442 def __init__(self):
443
444 self.orientation = wx.VERTICAL
445 self.type = 0
446 self.rect = wx.Rect()
447
448
449 class PaneButton:
450
451 def __init__(self, button_id):
452
453 self.button_id = button_id
454
455
456 # event declarations/classes
457
458 class AuiManagerEvent(wx.PyCommandEvent):
459
460 def __init__(self, eventType, id=1):
461
462 wx.PyCommandEvent.__init__(self, eventType, id)
463
464 self.pane = None
465 self.button = 0
466
467
468 def SetPane(self, p):
469
470 self.pane = p
471
472
473 def SetButton(self, b):
474
475 self.button = b
476
477
478 def GetPane(self):
479
480 return self.pane
481
482
483 def GetButton(self):
484
485 return self.button
486
487
488 # -- DefaultDockArt class implementation --
489 #
490 # DefaultDockArt is an art provider class which does all of the drawing for
491 # AuiManager. This allows the library caller to customize the dock art
492 # (probably by deriving from this class), or to completely replace all drawing
493 # with custom dock art. The active dock art class can be set via
494 # AuiManager.SetDockArt()
495
496 class DefaultDockArt:
497
498 def __init__(self):
499
500 base_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
501 darker1_color = StepColour(base_color, 85)
502 darker2_color = StepColour(base_color, 70)
503 darker3_color = StepColour(base_color, 60)
504 darker4_color = StepColour(base_color, 50)
505 darker5_color = StepColour(base_color, 40)
506
507 self._active_caption_colour = LightContrastColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))
508 self._active_caption_gradient_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
509 self._active_caption_text_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
510 self._inactive_caption_colour = StepColour(darker1_color, 80)
511 self._inactive_caption_gradient_colour = darker1_color
512 self._inactive_caption_text_colour = wx.BLACK
513
514 sash_color = base_color
515 caption_color = darker1_color
516 paneborder_color = darker2_color
517 selectbutton_color = base_color
518 selectbuttonpen_color = darker3_color
519
520 self._sash_brush = wx.Brush(base_color)
521 self._background_brush = wx.Brush(base_color)
522 self._border_pen = wx.Pen(darker2_color)
523 self._gripper_brush = wx.Brush(base_color)
524 self._gripper_pen1 = wx.Pen(darker5_color)
525 self._gripper_pen2 = wx.Pen(darker3_color)
526 self._gripper_pen3 = wx.WHITE_PEN
527
528 self._caption_font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False)
529
530 self._inactive_close_bitmap = BitmapFromBits(self._inactive_caption_text_colour, 0)
531 self._inactive_pin_bitmap = BitmapFromBits(self._inactive_caption_text_colour, 1)
532 self._active_close_bitmap = BitmapFromBits(self._active_caption_text_colour, 0)
533 self._active_pin_bitmap = BitmapFromBits(self._active_caption_text_colour, 1)
534
535 # default metric values
536 self._sash_size = 4
537 self._caption_size = 17
538 self._border_size = 1
539 self._button_size = 14
540 self._gripper_size = 9
541 self._gradient_type = AUI_GRADIENT_VERTICAL
542
543
544 def GetMetric(self, id):
545
546 if id == AUI_ART_SASH_SIZE:
547 return self._sash_size
548 elif id == AUI_ART_CAPTION_SIZE:
549 return self._caption_size
550 elif id == AUI_ART_GRIPPER_SIZE:
551 return self._gripper_size
552 elif id == AUI_ART_PANE_BORDER_SIZE:
553 return self._border_size
554 elif id == AUI_ART_PANE_BUTTON_SIZE:
555 return self._button_size
556 elif id == AUI_ART_GRADIENT_TYPE:
557 return self._gradient_type
558 else:
559 raise "\nERROR: Invalid Metric Ordinal. "
560
561
562 def SetMetric(self, id, new_val):
563
564 if id == AUI_ART_SASH_SIZE:
565 self._sash_size = new_val
566 elif id == AUI_ART_CAPTION_SIZE:
567 self._caption_size = new_val
568 elif id == AUI_ART_GRIPPER_SIZE:
569 self._gripper_size = new_val
570 elif id == AUI_ART_PANE_BORDER_SIZE:
571 self._border_size = new_val
572 elif id == AUI_ART_PANE_BUTTON_SIZE:
573 self._button_size = new_val
574 elif id == AUI_ART_GRADIENT_TYPE:
575 self._gradient_type = new_val
576 else:
577 raise "\nERROR: Invalid Metric Ordinal. "
578
579
580 def GetColor(self, id):
581
582 if id == AUI_ART_BACKGROUND_COLOUR:
583 return self._background_brush.GetColour()
584 elif id == AUI_ART_SASH_COLOUR:
585 return self._sash_brush.GetColour()
586 elif id == AUI_ART_INACTIVE_CAPTION_COLOUR:
587 return self._inactive_caption_colour
588 elif id == AUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR:
589 return self._inactive_caption_gradient_colour
590 elif id == AUI_ART_INACTIVE_CAPTION_TEXT_COLOUR:
591 return self._inactive_caption_text_colour
592 elif id == AUI_ART_ACTIVE_CAPTION_COLOUR:
593 return self._active_caption_colour
594 elif id == AUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR:
595 return self._active_caption_gradient_colour
596 elif id == AUI_ART_ACTIVE_CAPTION_TEXT_COLOUR:
597 return self._active_caption_text_colour
598 elif id == AUI_ART_BORDER_COLOUR:
599 return self._border_pen.GetColour()
600 elif id == AUI_ART_GRIPPER_COLOUR:
601 return self._gripper_brush.GetColour()
602 else:
603 raise "\nERROR: Invalid Metric Ordinal. "
604
605
606 def SetColor(self, id, colour):
607
608 if id == AUI_ART_BACKGROUND_COLOUR:
609 self._background_brush.SetColour(colour)
610 elif id == AUI_ART_SASH_COLOUR:
611 self._sash_brush.SetColour(colour)
612 elif id == AUI_ART_INACTIVE_CAPTION_COLOUR:
613 self._inactive_caption_colour = colour
614 elif id == AUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR:
615 self._inactive_caption_gradient_colour = colour
616 elif id == AUI_ART_INACTIVE_CAPTION_TEXT_COLOUR:
617 self._inactive_caption_text_colour = colour
618 elif id == AUI_ART_ACTIVE_CAPTION_COLOUR:
619 self._active_caption_colour = colour
620 elif id == AUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR:
621 self._active_caption_gradient_colour = colour
622 elif id == AUI_ART_ACTIVE_CAPTION_TEXT_COLOUR:
623 self._active_caption_text_colour = colour
624 elif id == AUI_ART_BORDER_COLOUR:
625 self._border_pen.SetColour(colour)
626 elif id == AUI_ART_GRIPPER_COLOUR:
627 self._gripper_brush.SetColour(colour)
628 self._gripper_pen1.SetColour(StepColour(colour, 40))
629 self._gripper_pen2.SetColour(StepColour(colour, 60))
630 else:
631 raise "\nERROR: Invalid Metric Ordinal. "
632
633
634 GetColour = GetColor
635 SetColour = SetColor
636
637 def SetFont(self, id, font):
638
639 if id == AUI_ART_CAPTION_FONT:
640 self._caption_font = font
641
642
643 def GetFont(self, id):
644
645 if id == AUI_ART_CAPTION_FONT:
646 return self._caption_font
647
648 return wx.NoneFont
649
650
651 def DrawSash(self, dc, orient, rect):
652
653 dc.SetPen(wx.TRANSPARENT_PEN)
654 dc.SetBrush(self._sash_brush)
655 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
656
657
658 def DrawBackground(self, dc, orient, rect):
659
660 dc.SetPen(wx.TRANSPARENT_PEN)
661 dc.SetBrush(self._background_brush)
662 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
663
664
665 def DrawBorder(self, dc, rect, pane):
666
667 drect = wx.Rect()
668 drect.x = rect.x
669 drect.y = rect.y
670 drect.width = rect.width
671 drect.height = rect.height
672
673 dc.SetPen(self._border_pen)
674 dc.SetBrush(wx.TRANSPARENT_BRUSH)
675
676 border_width = self.GetMetric(AUI_ART_PANE_BORDER_SIZE)
677
678 if pane.IsToolbar():
679
680 for ii in xrange(0, border_width):
681
682 dc.SetPen(wx.WHITE_PEN)
683 dc.DrawLine(drect.x, drect.y, drect.x+drect.width, drect.y)
684 dc.DrawLine(drect.x, drect.y, drect.x, drect.y+drect.height)
685 dc.SetPen(self._border_pen)
686 dc.DrawLine(drect.x, drect.y+drect.height-1,
687 drect.x+drect.width, drect.y+drect.height-1)
688 dc.DrawLine(drect.x+drect.width-1, drect.y,
689 drect.x+drect.width-1, drect.y+drect.height)
690 drect.Deflate(1, 1)
691
692 else:
693
694 for ii in xrange(0, border_width):
695
696 dc.DrawRectangle(drect.x, drect.y, drect.width, drect.height)
697 drect.Deflate(1, 1)
698
699
700 def DrawCaptionBackground(self, dc, rect, active):
701
702 if self._gradient_type == AUI_GRADIENT_NONE:
703 if active:
704 dc.SetBrush(wx.Brush(self._active_caption_colour))
705 else:
706 dc.SetBrush(wx.Brush(self._inactive_caption_colour))
707
708 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
709 else:
710 if active:
711 DrawGradientRectangle(dc, rect, self._active_caption_colour,
712 self._active_caption_gradient_colour,
713 self._gradient_type)
714 else:
715 DrawGradientRectangle(dc, rect, self._inactive_caption_colour,
716 self._inactive_caption_gradient_colour,
717 self._gradient_type)
718
719
720 def DrawCaption(self, dc, text, rect, pane):
721
722 dc.SetPen(wx.TRANSPARENT_PEN)
723 dc.SetFont(self._caption_font)
724
725 self.DrawCaptionBackground(dc, rect, ((pane.state & AuiPaneInfo.optionActive) and \
726 [True] or [False])[0])
727
728 if pane.state & AuiPaneInfo.optionActive:
729 dc.SetTextForeground(self._active_caption_text_colour)
730 else:
731 dc.SetTextForeground(self._inactive_caption_text_colour)
732
733 w, h = dc.GetTextExtent("ABCDEFHXfgkj")
734
735 dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height)
736 dc.DrawText(text, rect.x+3, rect.y+(rect.height/2)-(h/2)-1)
737 dc.DestroyClippingRegion()
738
739
740 def DrawGripper(self, dc, rect, pane):
741
742 dc.SetPen(wx.TRANSPARENT_PEN)
743 dc.SetBrush(self._gripper_brush)
744
745 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
746
747 if not pane.HasGripperTop():
748 y = 5
749 while 1:
750 dc.SetPen(self._gripper_pen1)
751 dc.DrawPoint(rect.x+3, rect.y+y)
752 dc.SetPen(self._gripper_pen2)
753 dc.DrawPoint(rect.x+3, rect.y+y+1)
754 dc.DrawPoint(rect.x+4, rect.y+y)
755 dc.SetPen(self._gripper_pen3)
756 dc.DrawPoint(rect.x+5, rect.y+y+1)
757 dc.DrawPoint(rect.x+5, rect.y+y+2)
758 dc.DrawPoint(rect.x+4, rect.y+y+2)
759 y = y + 4
760 if y > rect.GetHeight() - 5:
761 break
762 else:
763 x = 5
764 while 1:
765 dc.SetPen(self._gripper_pen1)
766 dc.DrawPoint(rect.x+x, rect.y+3)
767 dc.SetPen(self._gripper_pen2)
768 dc.DrawPoint(rect.x+x+1, rect.y+3)
769 dc.DrawPoint(rect.x+x, rect.y+4)
770 dc.SetPen(self._gripper_pen3)
771 dc.DrawPoint(rect.x+x+1, rect.y+5)
772 dc.DrawPoint(rect.x+x+2, rect.y+5)
773 dc.DrawPoint(rect.x+x+2, rect.y+4)
774 x = x + 4
775 if x > rect.GetWidth() - 5:
776 break
777
778
779 def DrawPaneButton(self, dc, button, button_state, rect, pane):
780
781 drect = wx.Rect()
782 drect.x = rect.x
783 drect.y = rect.y
784 drect.width = rect.width
785 drect.height = rect.height
786
787 if button_state == AUI_BUTTON_STATE_PRESSED:
788
789 drect.x = drect.x + 1
790 drect.y = drect.y + 1
791
792 if button_state in [AUI_BUTTON_STATE_HOVER, AUI_BUTTON_STATE_PRESSED]:
793
794 if pane.state & AuiPaneInfo.optionActive:
795 dc.SetBrush(wx.Brush(StepColour(self._active_caption_colour, 120)))
796 dc.SetPen(wx.Pen(StepColour(self._active_caption_colour, 70)))
797 else:
798 dc.SetBrush(wx.Brush(StepColour(self._inactive_caption_colour, 120)))
799 dc.SetPen(wx.Pen(StepColour(self._inactive_caption_colour, 70)))
800
801 # draw the background behind the button
802 dc.DrawRectangle(drect.x, drect.y, 15, 15)
803
804 if button == AuiPaneInfo.buttonClose:
805 if pane.state & AuiPaneInfo.optionActive:
806
807 bmp = self._active_close_bitmap
808
809 else:
810 bmp = self._inactive_close_bitmap
811 elif button == AuiPaneInfo.buttonPin:
812 if pane.state & AuiPaneInfo.optionActive:
813
814 bmp = self._active_pin_bitmap
815
816 else:
817 bmp = self._inactive_pin_bitmap
818
819 # draw the button itself
820 dc.DrawBitmap(bmp, drect.x, drect.y, True)
821
822
823 # -- AuiPaneInfo class implementation --
824 #
825 # AuiPaneInfo specifies all the parameters for a pane. These parameters specify where
826 # the pane is on the screen, whether it is docked or floating, or hidden. In addition,
827 # these parameters specify the pane's docked position, floating position, preferred
828 # size, minimum size, caption text among many other parameters.
829
830 class AuiPaneInfo:
831
832 optionFloating = 2**0
833 optionHidden = 2**1
834 optionLeftDockable = 2**2
835 optionRightDockable = 2**3
836 optionTopDockable = 2**4
837 optionBottomDockable = 2**5
838 optionFloatable = 2**6
839 optionMovable = 2**7
840 optionResizable = 2**8
841 optionPaneBorder = 2**9
842 optionCaption = 2**10
843 optionGripper = 2**11
844 optionDestroyOnClose = 2**12
845 optionToolbar = 2**13
846 optionActive = 2**14
847 optionGripperTop = 2**15
848
849 buttonClose = 2**24
850 buttonMaximize = 2**25
851 buttonMinimize = 2**26
852 buttonPin = 2**27
853 buttonCustom1 = 2**28
854 buttonCustom2 = 2**29
855 buttonCustom3 = 2**30
856 actionPane = 2**31 # used internally
857
858 def __init__(self):
859
860 wx.DefaultSize = wx.Size(-1, -1)
861 self.window = None
862 self.frame = None
863 self.state = 0
864 self.dock_direction = AUI_DOCK_LEFT
865 self.dock_layer = 0
866 self.dock_row = 0
867 self.dock_pos = 0
868 self.floating_pos = wx.Point(-1, -1)
869 self.floating_size = wx.Size(-1, -1)
870 self.best_size = wx.Size(-1, -1)
871 self.min_size = wx.Size(-1, -1)
872 self.max_size = wx.Size(-1, -1)
873 self.dock_proportion = 0
874 self.caption = ""
875 self.buttons = []
876 self.name = ""
877 self.rect = wx.Rect()
878
879 self.DefaultPane()
880
881
882 def IsOk(self):
883 """ IsOk() returns True if the AuiPaneInfo structure is valid. """
884
885 return (self.window != None and [True] or [False])[0]
886
887
888 def IsFixed(self):
889 """ IsFixed() returns True if the pane cannot be resized. """
890
891 return not self.HasFlag(self.optionResizable)
892
893
894 def IsResizable(self):
895 """ IsResizeable() returns True if the pane can be resized. """
896
897 return self.HasFlag(self.optionResizable)
898
899
900 def IsShown(self):
901 """ IsShown() returns True if the pane should be drawn on the screen. """
902
903 return not self.HasFlag(self.optionHidden)
904
905
906 def IsFloating(self):
907 """ IsFloating() returns True if the pane is floating. """
908
909 return self.HasFlag(self.optionFloating)
910
911
912 def IsDocked(self):
913 """ IsDocked() returns True if the pane is docked. """
914
915 return not self.HasFlag(self.optionFloating)
916
917
918 def IsToolbar(self):
919 """ IsToolbar() returns True if the pane contains a toolbar. """
920
921 return self.HasFlag(self.optionToolbar)
922
923
924 def IsTopDockable(self):
925 """
926 IsTopDockable() returns True if the pane can be docked at the top
927 of the managed frame.
928 """
929
930 return self.HasFlag(self.optionTopDockable)
931
932
933 def IsBottomDockable(self):
934 """
935 IsBottomDockable() returns True if the pane can be docked at the bottom
936 of the managed frame.
937 """
938
939 return self.HasFlag(self.optionBottomDockable)
940
941
942 def IsLeftDockable(self):
943 """
944 IsLeftDockable() returns True if the pane can be docked at the left
945 of the managed frame.
946 """
947
948 return self.HasFlag(self.optionLeftDockable)
949
950
951 def IsRightDockable(self):
952 """
953 IsRightDockable() returns True if the pane can be docked at the right
954 of the managed frame.
955 """
956
957 return self.HasFlag(self.optionRightDockable)
958
959
960 def IsDockable(self):
961 """ IsDockable() returns True if the pane can be docked. """
962
963 return self.IsTopDockable() or self.IsBottomDockable() or self.IsLeftDockable() or \
964 self.IsRightDockable()
965
966
967 def IsFloatable(self):
968 """
969 IsFloatable() returns True if the pane can be undocked and displayed as a
970 floating window.
971 """
972
973 return self.HasFlag(self.optionFloatable)
974
975
976 def IsMovable(self):
977 """
978 IsMoveable() returns True if the docked frame can be undocked or moved to
979 another dock position.
980 """
981
982 return self.HasFlag(self.optionMovable)
983
984
985 def HasCaption(self):
986 """ HasCaption() returns True if the pane displays a caption. """
987
988 return self.HasFlag(self.optionCaption)
989
990
991 def HasGripper(self):
992 """ HasGripper() returns True if the pane displays a gripper. """
993
994 return self.HasFlag(self.optionGripper)
995
996
997 def HasBorder(self):
998 """ HasBorder() returns True if the pane displays a border. """
999
1000 return self.HasFlag(self.optionPaneBorder)
1001
1002
1003 def HasCloseButton(self):
1004 """
1005 HasCloseButton() returns True if the pane displays a button to close
1006 the pane.
1007 """
1008
1009 return self.HasFlag(self.buttonClose)
1010
1011
1012 def HasMaximizeButton(self):
1013 """
1014 HasMaximizeButton() returns True if the pane displays a button to
1015 maximize the pane.
1016 """
1017
1018 return self.HasFlag(self.buttonMaximize)
1019
1020
1021 def HasMinimizeButton(self):
1022 """
1023 HasMinimizeButton() returns True if the pane displays a button to
1024 minimize the pane.
1025 """
1026
1027 return self.HasFlag(self.buttonMinimize)
1028
1029
1030 def HasPinButton(self):
1031 """ HasPinButton() returns True if the pane displays a button to float the pane. """
1032
1033 return self.HasFlag(self.buttonPin)
1034
1035
1036 def HasGripperTop(self):
1037
1038 return self.HasFlag(self.optionGripperTop)
1039
1040
1041 def Window(self, w):
1042
1043 self.window = w
1044 return self
1045
1046
1047 def Name(self, n):
1048 """ Name() sets the name of the pane so it can be referenced in lookup functions. """
1049
1050 self.name = n
1051 return self
1052
1053
1054 def Caption(self, c):
1055 """ Caption() sets the caption of the pane. """
1056
1057 self.caption = c
1058 return self
1059
1060
1061 def Left(self):
1062 """ Left() sets the pane dock position to the left side of the frame. """
1063
1064 self.dock_direction = AUI_DOCK_LEFT
1065 return self
1066
1067
1068 def Right(self):
1069 """ Right() sets the pane dock position to the right side of the frame. """
1070
1071 self.dock_direction = AUI_DOCK_RIGHT
1072 return self
1073
1074
1075 def Top(self):
1076 """ Top() sets the pane dock position to the top of the frame. """
1077
1078 self.dock_direction = AUI_DOCK_TOP
1079 return self
1080
1081
1082 def Bottom(self):
1083 """ Bottom() sets the pane dock position to the bottom of the frame. """
1084
1085 self.dock_direction = AUI_DOCK_BOTTOM
1086 return self
1087
1088
1089 def Center(self):
1090 """ Center() sets the pane to the center position of the frame. """
1091
1092 self.dock_direction = AUI_DOCK_CENTER
1093 return self
1094
1095
1096 def Centre(self):
1097 """ Centre() sets the pane to the center position of the frame. """
1098
1099 self.dock_direction = AUI_DOCK_CENTRE
1100 return self
1101
1102
1103 def Direction(self, direction):
1104 """ Direction() determines the direction of the docked pane. """
1105
1106 self.dock_direction = direction
1107 return self
1108
1109
1110 def Layer(self, layer):
1111 """ Layer() determines the layer of the docked pane. """
1112
1113 self.dock_layer = layer
1114 return self
1115
1116
1117 def Row(self, row):
1118 """ Row() determines the row of the docked pane. """
1119
1120 self.dock_row = row
1121 return self
1122
1123
1124 def Position(self, pos):
1125 """ Position() determines the position of the docked pane. """
1126
1127 self.dock_pos = pos
1128 return self
1129
1130
1131 def MinSize(self, arg1=None, arg2=None):
1132 """ MinSize() sets the minimum size of the pane. """
1133
1134 if isinstance(arg1, wx.Size):
1135 ret = self.MinSize1(arg1)
1136 else:
1137 ret = self.MinSize2(arg1, arg2)
1138
1139 return ret
1140
1141
1142 def MinSize1(self, size):
1143
1144 self.min_size = size
1145 return self
1146
1147
1148 def MinSize2(self, x, y):
1149
1150 self.min_size.Set(x,y)
1151 return self
1152
1153
1154 def MaxSize(self, arg1=None, arg2=None):
1155 """ MaxSize() sets the maximum size of the pane. """
1156
1157 if isinstance(arg1, wx.Size):
1158 ret = self.MaxSize1(arg1)
1159 else:
1160 ret = self.MaxSize2(arg1, arg2)
1161
1162 return ret
1163
1164
1165 def MaxSize1(self, size):
1166
1167 self.max_size = size
1168 return self
1169
1170
1171 def MaxSize2(self, x, y):
1172
1173 self.max_size.Set(x,y)
1174 return self
1175
1176
1177 def BestSize(self, arg1=None, arg2=None):
1178 """ BestSize() sets the ideal size for the pane. """
1179
1180 if isinstance(arg1, wx.Size):
1181 ret = self.BestSize1(arg1)
1182 else:
1183 ret = self.BestSize2(arg1, arg2)
1184
1185 return ret
1186
1187
1188 def BestSize1(self, size):
1189
1190 self.best_size = size
1191 return self
1192
1193
1194 def BestSize2(self, x, y):
1195
1196 self.best_size.Set(x,y)
1197 return self
1198
1199
1200 def FloatingPosition(self, pos):
1201 """ FloatingPosition() sets the position of the floating pane. """
1202
1203 self.floating_pos = pos
1204 return self
1205
1206
1207 def FloatingSize(self, size):
1208 """ FloatingSize() sets the size of the floating pane. """
1209
1210 self.floating_size = size
1211 return self
1212
1213
1214 def Fixed(self):
1215 """ Fixed() forces a pane to be fixed size so that it cannot be resized. """
1216
1217 return self.SetFlag(self.optionResizable, False)
1218
1219
1220 def Resizable(self, resizable=True):
1221 """
1222 Resizable() allows a pane to be resizable if resizable is True, and forces
1223 it to be a fixed size if resizeable is False.
1224 """
1225
1226 return self.SetFlag(self.optionResizable, resizable)
1227
1228
1229 def Dock(self):
1230 """ Dock() indicates that a pane should be docked. """
1231
1232 return self.SetFlag(self.optionFloating, False)
1233
1234
1235 def Float(self):
1236 """ Float() indicates that a pane should be floated. """
1237
1238 return self.SetFlag(self.optionFloating, True)
1239
1240
1241 def Hide(self):
1242 """ Hide() indicates that a pane should be hidden. """
1243
1244 return self.SetFlag(self.optionHidden, True)
1245
1246
1247 def Show(self, show=True):
1248 """ Show() indicates that a pane should be shown. """
1249
1250 return self.SetFlag(self.optionHidden, not show)
1251
1252
1253 def CaptionVisible(self, visible=True):
1254 """ CaptionVisible() indicates that a pane caption should be visible. """
1255
1256 return self.SetFlag(self.optionCaption, visible)
1257
1258
1259 def PaneBorder(self, visible=True):
1260 """ PaneBorder() indicates that a border should be drawn for the pane. """
1261
1262 return self.SetFlag(self.optionPaneBorder, visible)
1263
1264
1265 def Gripper(self, visible=True):
1266 """ Gripper() indicates that a gripper should be drawn for the pane. """
1267
1268 return self.SetFlag(self.optionGripper, visible)
1269
1270
1271 def GripperTop(self, attop=True):
1272 """ GripperTop() indicates that a gripper should be drawn for the pane. """
1273
1274 return self.SetFlag(self.optionGripperTop, attop)
1275
1276
1277 def CloseButton(self, visible=True):
1278 """ CloseButton() indicates that a close button should be drawn for the pane. """
1279
1280 return self.SetFlag(self.buttonClose, visible)
1281
1282
1283 def MaximizeButton(self, visible=True):
1284 """ MaximizeButton() indicates that a maximize button should be drawn for the pane. """
1285
1286 return self.SetFlag(self.buttonMaximize, visible)
1287
1288
1289 def MinimizeButton(self, visible=True):
1290 """ MinimizeButton() indicates that a minimize button should be drawn for the pane. """
1291
1292 return self.SetFlag(self.buttonMinimize, visible)
1293
1294
1295 def PinButton(self, visible=True):
1296 """ PinButton() indicates that a pin button should be drawn for the pane. """
1297
1298 return self.SetFlag(self.buttonPin, visible)
1299
1300
1301 def DestroyOnClose(self, b=True):
1302 """ DestroyOnClose() indicates whether a pane should be destroyed when it is closed. """
1303
1304 return self.SetFlag(self.optionDestroyOnClose, b)
1305
1306
1307 def TopDockable(self, b=True):
1308 """ TopDockable() indicates whether a pane can be docked at the top of the frame. """
1309
1310 return self.SetFlag(self.optionTopDockable, b)
1311
1312
1313 def BottomDockable(self, b=True):
1314 """ BottomDockable() indicates whether a pane can be docked at the bottom of the frame. """
1315
1316 return self.SetFlag(self.optionBottomDockable, b)
1317
1318
1319 def LeftDockable(self, b=True):
1320 """ LeftDockable() indicates whether a pane can be docked on the left of the frame. """
1321
1322 return self.SetFlag(self.optionLeftDockable, b)
1323
1324
1325 def RightDockable(self, b=True):
1326 """ RightDockable() indicates whether a pane can be docked on the right of the frame. """
1327
1328 return self.SetFlag(self.optionRightDockable, b)
1329
1330
1331 def Floatable(self, b=True):
1332 """ Floatable() indicates whether a frame can be floated. """
1333
1334 return self.SetFlag(self.optionFloatable, b)
1335
1336
1337 def Movable(self, b=True):
1338 """ Movable() indicates whether a frame can be moved. """
1339
1340 return self.SetFlag(self.optionMovable, b)
1341
1342
1343 def Dockable(self, b=True):
1344
1345 return self.TopDockable(b).BottomDockable(b).LeftDockable(b).RightDockable(b)
1346
1347
1348 def DefaultPane(self):
1349 """ DefaultPane() specifies that the pane should adopt the default pane settings. """
1350
1351 state = self.state
1352 state |= self.optionTopDockable | self.optionBottomDockable | \
1353 self.optionLeftDockable | self.optionRightDockable | \
1354 self.optionFloatable | self.optionMovable | self.optionResizable | \
1355 self.optionCaption | self.optionPaneBorder | self.buttonClose
1356
1357 self.state = state
1358
1359 return self
1360
1361
1362 def CentrePane(self):
1363 """ CentrePane() specifies that the pane should adopt the default center pane settings. """
1364
1365 return self.CenterPane()
1366
1367
1368 def CenterPane(self):
1369 """ CenterPane() specifies that the pane should adopt the default center pane settings. """
1370
1371 self.state = 0
1372 return self.Center().PaneBorder().Resizable()
1373
1374
1375 def ToolbarPane(self):
1376 """ ToolbarPane() specifies that the pane should adopt the default toolbar pane settings. """
1377
1378 self.DefaultPane()
1379 state = self.state
1380
1381 state |= (self.optionToolbar | self.optionGripper)
1382 state &= ~(self.optionResizable | self.optionCaption)
1383
1384 if self.dock_layer == 0:
1385 self.dock_layer = 10
1386
1387 self.state = state
1388
1389 return self
1390
1391
1392 def SetFlag(self, flag, option_state):
1393 """ SetFlag() turns the property given by flag on or off with the option_state parameter. """
1394
1395 state = self.state
1396
1397 if option_state:
1398 state |= flag
1399 else:
1400 state &= ~flag
1401
1402 self.state = state
1403
1404 return self
1405
1406
1407 def HasFlag(self, flag):
1408 """ HasFlag() returns True if the the property specified by flag is active for the pane. """
1409
1410 return (self.state & flag and [True] or [False])[0]
1411
1412
1413 NoneAuiPaneInfo = AuiPaneInfo()
1414
1415 # -- AuiFloatingPane class implementation --
1416 #
1417 # AuiFloatingPane implements a frame class with some special functionality
1418 # which allows the library to sense when the frame move starts, is active,
1419 # and completes. Note that it contains it's own AuiManager instance,
1420 # which, in the future, would allow for nested managed frames.
1421 # For now, with wxMSW, the wx.MiniFrame window is used, but on wxGTK, wx.Frame
1422
1423 if wx.Platform == "__WXGTK__":
1424
1425 class AuiFloatingPaneBaseClass(wx.Frame):
1426 def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
1427 size=wx.DefaultSize, style=0):
1428 wx.Frame.__init__(self, parent, id, title, pos, size, style)
1429
1430 else:
1431
1432 class AuiFloatingPaneBaseClass(wx.MiniFrame):
1433 def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
1434 size=wx.DefaultSize, style=0):
1435 wx.MiniFrame.__init__(self, parent, id, title, pos, size, style)
1436 if wx.Platform == "__WXMAC__":
1437 self.MacSetMetalAppearance(True)
1438
1439
1440 class AuiFloatingPane(AuiFloatingPaneBaseClass):
1441
1442 def __init__(self, parent, owner_mgr, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
1443 size=wx.DefaultSize, style=wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION |
1444 wx.CLOSE_BOX | wx.FRAME_NO_TASKBAR |
1445 wx.FRAME_FLOAT_ON_PARENT | wx.CLIP_CHILDREN,
1446 resizeborder=0):
1447
1448 if not resizeborder:
1449 style = style & ~wx.RESIZE_BORDER
1450
1451 AuiFloatingPaneBaseClass.__init__(self, parent, id, title, pos, size, style)
1452 self._owner_mgr = owner_mgr
1453 self._moving = False
1454 self._last_rect = wx.Rect()
1455 self._mgr = AuiManager(None)
1456 self._mgr.SetFrame(self)
1457 self._mousedown = False
1458 self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE)
1459
1460 self.Bind(wx.EVT_CLOSE, self.OnClose)
1461 self.Bind(wx.EVT_SIZE, self.OnSize)
1462 self.Bind(wx.EVT_MOVE, self.OnMoveEvent)
1463 self.Bind(wx.EVT_MOVING, self.OnMoveEvent)
1464 self.Bind(wx.EVT_IDLE, self.OnIdle)
1465 self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
1466
1467
1468 def CopyAttributes(self, pane, contained_pane):
1469
1470 contained_pane.name = pane.name
1471 contained_pane.caption = pane.caption
1472 contained_pane.window = pane.window
1473 contained_pane.frame = pane.frame
1474 contained_pane.state = pane.state
1475 contained_pane.dock_direction = pane.dock_direction
1476 contained_pane.dock_layer = pane.dock_layer
1477 contained_pane.dock_row = pane.dock_row
1478 contained_pane.dock_pos = pane.dock_pos
1479 contained_pane.best_size = pane.best_size
1480 contained_pane.min_size = pane.min_size
1481 contained_pane.max_size = pane.max_size
1482 contained_pane.floating_pos = pane.floating_pos
1483 contained_pane.floating_size = pane.floating_size
1484 contained_pane.dock_proportion = pane.dock_proportion
1485 contained_pane.buttons = pane.buttons
1486 contained_pane.rect = pane.rect
1487
1488 return contained_pane
1489
1490
1491 def SetPaneWindow(self, pane):
1492
1493 self._pane_window = pane.window
1494 self._pane_window.Reparent(self)
1495
1496 contained_pane = AuiPaneInfo()
1497
1498 contained_pane = self.CopyAttributes(pane, contained_pane)
1499
1500 contained_pane.Dock().Center().Show(). \
1501 CaptionVisible(False). \
1502 PaneBorder(False). \
1503 Layer(0).Row(0).Position(0)
1504
1505 indx = self._owner_mgr._panes.index(pane)
1506 self._owner_mgr._panes[indx] = pane
1507
1508 self._mgr.AddPane(self._pane_window, contained_pane)
1509 self._mgr.Update()
1510
1511 if pane.min_size.IsFullySpecified():
1512 tmp = self.GetSize()
1513 self.GetSizer().SetSizeHints(self)
1514 self.SetSize(tmp)
1515
1516 self.SetTitle(pane.caption)
1517
1518 if pane.floating_size != wx.DefaultSize:
1519 self.SetSize(pane.floating_size)
1520 self._owner_mgr._panes[indx] = pane
1521 else:
1522 size = pane.best_size
1523 if size == wx.DefaultSize:
1524 size = pane.min_size
1525 if size == wx.DefaultSize:
1526 size = self._pane_window.GetSize()
1527 if pane.HasGripper():
1528 if pane.HasGripperTop():
1529 size.y += self._owner_mgr._art.GetMetric(AUI_ART_GRIPPER_SIZE)
1530 else:
1531 size.x += self._owner_mgr._art.GetMetric(AUI_ART_GRIPPER_SIZE)
1532
1533 pane.floating_size = size
1534 self._owner_mgr._panes[indx] = pane
1535 self.SetClientSize(size)
1536
1537
1538 def OnSize(self, event):
1539
1540 self._owner_mgr.OnAuiFloatingPaneResized(self._pane_window, event.GetSize())
1541
1542
1543 def OnClose(self, event):
1544 self._owner_mgr.OnAuiFloatingPaneClosed(self._pane_window, event)
1545 if event.GetSkipped():
1546 self.Destroy()
1547 self._mgr.UnInit()
1548
1549
1550 def OnMoveEvent(self, event):
1551
1552 win_rect = self.GetRect()
1553
1554 # skip the first move event
1555 if self._last_rect.IsEmpty():
1556 self._last_rect = win_rect
1557 return
1558
1559 # prevent frame redocking during resize
1560 if self._last_rect.GetSize() != win_rect.GetSize():
1561 self._last_rect = win_rect
1562 return
1563
1564 self._last_rect = win_rect
1565
1566 if not self.IsMouseDown():
1567 return
1568
1569 if not self._moving:
1570 self.OnMoveStart()
1571 self._moving = True
1572
1573 self.OnMoving(event.GetRect())
1574
1575
1576 def IsMouseDown(self):
1577
1578 if _newversion:
1579 ms = wx.GetMouseState()
1580 return ms.leftDown
1581 else:
1582 if wx.Platform == "__WXMSW__":
1583 if _libimported == "MH":
1584 return ((win32api.GetKeyState(win32con.VK_LBUTTON) & (1<<15))\
1585 and [True] or [False])[0]
1586 elif _libimported == "ctypes":
1587 return ((ctypes.windll.user32.GetKeyState(1) & (1<<15)) and \
1588 [True] or [False])[0]
1589
1590
1591 def OnIdle(self, event):
1592
1593 if self._moving:
1594 if not self.IsMouseDown():
1595 self._moving = False
1596 self.OnMoveFinished()
1597 else:
1598 event.RequestMore()
1599
1600 event.Skip()
1601
1602
1603 def OnMoveStart(self):
1604
1605 # notify the owner manager that the pane has started to move
1606 self._owner_mgr.OnAuiFloatingPaneMoveStart(self._pane_window)
1607
1608
1609 def OnMoving(self, window_rect):
1610
1611 # notify the owner manager that the pane is moving
1612 self._owner_mgr.OnAuiFloatingPaneMoving(self._pane_window)
1613
1614
1615 def OnMoveFinished(self):
1616
1617 # notify the owner manager that the pane has finished moving
1618 self._owner_mgr.OnAuiFloatingPaneMoved(self._pane_window)
1619
1620
1621 def OnActivate(self, event):
1622
1623 if event.GetActive():
1624 self._owner_mgr.OnAuiFloatingPaneActivated(self._pane_window)
1625
1626
1627 # -- static utility functions --
1628
1629 def PaneCreateStippleBitmap():
1630
1631 data = [0, 0, 0, 192, 192, 192, 192, 192, 192, 0, 0, 0]
1632 img = wx.EmptyImage(2, 2)
1633 counter = 0
1634
1635 for ii in xrange(2):
1636 for jj in xrange(2):
1637 img.SetRGB(ii, jj, data[counter], data[counter+1], data[counter+2])
1638 counter = counter + 3
1639
1640 return img.ConvertToBitmap()
1641
1642
1643 def DrawResizeHint(dc, rect):
1644
1645 stipple = PaneCreateStippleBitmap()
1646 brush = wx.BrushFromBitmap(stipple)
1647 dc.SetBrush(brush)
1648 dc.SetPen(wx.TRANSPARENT_PEN)
1649
1650 dc.SetLogicalFunction(wx.XOR)
1651 dc.DrawRectangleRect(rect)
1652
1653
1654 def CopyDocksAndPanes(src_docks, src_panes):
1655 """
1656 CopyDocksAndPanes() - this utility function creates shallow copies of
1657 the dock and pane info. DockInfo's usually contain pointers
1658 to AuiPaneInfo classes, thus this function is necessary to reliably
1659 reconstruct that relationship in the new dock info and pane info arrays.
1660 """
1661
1662 dest_docks = src_docks
1663 dest_panes = src_panes
1664
1665 for ii in xrange(len(dest_docks)):
1666 dock = dest_docks[ii]
1667 for jj in xrange(len(dock.panes)):
1668 for kk in xrange(len(src_panes)):
1669 if dock.panes[jj] == src_panes[kk]:
1670 dock.panes[jj] = dest_panes[kk]
1671
1672 return dest_docks, dest_panes
1673
1674
1675 def CopyDocksAndPanes2(src_docks, src_panes):
1676 """
1677 CopyDocksAndPanes2() - this utility function creates full copies of
1678 the dock and pane info. DockInfo's usually contain pointers
1679 to AuiPaneInfo classes, thus this function is necessary to reliably
1680 reconstruct that relationship in the new dock info and pane info arrays.
1681 """
1682
1683 dest_docks = []
1684
1685 for ii in xrange(len(src_docks)):
1686 dest_docks.append(DockInfo())
1687 dest_docks[ii].dock_direction = src_docks[ii].dock_direction
1688 dest_docks[ii].dock_layer = src_docks[ii].dock_layer
1689 dest_docks[ii].dock_row = src_docks[ii].dock_row
1690 dest_docks[ii].size = src_docks[ii].size
1691 dest_docks[ii].min_size = src_docks[ii].min_size
1692 dest_docks[ii].resizable = src_docks[ii].resizable
1693 dest_docks[ii].fixed = src_docks[ii].fixed
1694 dest_docks[ii].toolbar = src_docks[ii].toolbar
1695 dest_docks[ii].panes = src_docks[ii].panes
1696 dest_docks[ii].rect = src_docks[ii].rect
1697
1698 dest_panes = []
1699
1700 for ii in xrange(len(src_panes)):
1701 dest_panes.append(AuiPaneInfo())
1702 dest_panes[ii].name = src_panes[ii].name
1703 dest_panes[ii].caption = src_panes[ii].caption
1704 dest_panes[ii].window = src_panes[ii].window
1705 dest_panes[ii].frame = src_panes[ii].frame
1706 dest_panes[ii].state = src_panes[ii].state
1707 dest_panes[ii].dock_direction = src_panes[ii].dock_direction
1708 dest_panes[ii].dock_layer = src_panes[ii].dock_layer
1709 dest_panes[ii].dock_row = src_panes[ii].dock_row
1710 dest_panes[ii].dock_pos = src_panes[ii].dock_pos
1711 dest_panes[ii].best_size = src_panes[ii].best_size
1712 dest_panes[ii].min_size = src_panes[ii].min_size
1713 dest_panes[ii].max_size = src_panes[ii].max_size
1714 dest_panes[ii].floating_pos = src_panes[ii].floating_pos
1715 dest_panes[ii].floating_size = src_panes[ii].floating_size
1716 dest_panes[ii].dock_proportion = src_panes[ii].dock_proportion
1717 dest_panes[ii].buttons = src_panes[ii].buttons
1718 dest_panes[ii].rect = src_panes[ii].rect
1719
1720 for ii in xrange(len(dest_docks)):
1721 dock = dest_docks[ii]
1722 for jj in xrange(len(dock.panes)):
1723 for kk in xrange(len(src_panes)):
1724 if dock.panes[jj] == src_panes[kk]:
1725 dock.panes[jj] = dest_panes[kk]
1726
1727 dest_docks[ii] = dock
1728
1729 return dest_docks, dest_panes
1730
1731
1732 def GetMaxLayer(docks, dock_direction):
1733 """
1734 GetMaxLayer() is an internal function which returns
1735 the highest layer inside the specified dock.
1736 """
1737
1738 max_layer = 0
1739
1740 for dock in docks:
1741 if dock.dock_direction == dock_direction and dock.dock_layer > max_layer and not dock.fixed:
1742 max_layer = dock.dock_layer
1743
1744 return max_layer
1745
1746
1747 def GetMaxRow(panes, direction, layer):
1748 """
1749 GetMaxRow() is an internal function which returns
1750 the highest layer inside the specified dock.
1751 """
1752
1753 max_row = 0
1754
1755 for pane in panes:
1756 if pane.dock_direction == direction and pane.dock_layer == layer and \
1757 pane.dock_row > max_row:
1758 max_row = pane.dock_row
1759
1760 return max_row
1761
1762
1763 def DoInsertDockLayer(panes, dock_direction, dock_layer):
1764 """
1765 DoInsertDockLayer() is an internal function that inserts a new dock
1766 layer by incrementing all existing dock layer values by one.
1767 """
1768
1769 for ii in xrange(len(panes)):
1770 pane = panes[ii]
1771 if not pane.IsFloating() and pane.dock_direction == dock_direction and pane.dock_layer >= dock_layer:
1772 pane.dock_layer = pane.dock_layer + 1
1773
1774 panes[ii] = pane
1775
1776 return panes
1777
1778
1779 def DoInsertDockRow(panes, dock_direction, dock_layer, dock_row):
1780 """
1781 DoInsertDockRow() is an internal function that inserts a new dock
1782 row by incrementing all existing dock row values by one.
1783 """
1784
1785 for ii in xrange(len(panes)):
1786 pane = panes[ii]
1787 if not pane.IsFloating() and pane.dock_direction == dock_direction and \
1788 pane.dock_layer == dock_layer and pane.dock_row >= dock_row:
1789 pane.dock_row = pane.dock_row + 1
1790
1791 panes[ii] = pane
1792
1793 return panes
1794
1795
1796 def DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos):
1797
1798 for ii in xrange(len(panes)):
1799 pane = panes[ii]
1800 if not pane.IsFloating() and pane.dock_direction == dock_direction and \
1801 pane.dock_layer == dock_layer and pane.dock_row == dock_row and \
1802 pane.dock_pos >= dock_pos:
1803 pane.dock_pos = pane.dock_pos + 1
1804
1805 panes[ii] = pane
1806
1807 return panes
1808
1809
1810 def FindDocks(docks, dock_direction, dock_layer=-1, dock_row=-1, arr=[]):
1811 """
1812 FindDocks() is an internal function that returns a list of docks which meet
1813 the specified conditions in the parameters and returns a sorted array
1814 (sorted by layer and then row).
1815 """
1816
1817 begin_layer = dock_layer
1818 end_layer = dock_layer
1819 begin_row = dock_row
1820 end_row = dock_row
1821 dock_count = len(docks)
1822 max_row = 0
1823 max_layer = 0
1824
1825 # discover the maximum dock layer and the max row
1826 for ii in xrange(dock_count):
1827 max_row = max(max_row, docks[ii].dock_row)
1828 max_layer = max(max_layer, docks[ii].dock_layer)
1829
1830 # if no dock layer was specified, search all dock layers
1831 if dock_layer == -1:
1832 begin_layer = 0
1833 end_layer = max_layer
1834
1835 # if no dock row was specified, search all dock row
1836 if dock_row == -1:
1837 begin_row = 0
1838 end_row = max_row
1839
1840 arr = []
1841
1842 for layer in xrange(begin_layer, end_layer+1):
1843 for row in xrange(begin_row, end_row+1):
1844 for ii in xrange(dock_count):
1845 d = docks[ii]
1846 if dock_direction == -1 or dock_direction == d.dock_direction:
1847 if d.dock_layer == layer and d.dock_row == row:
1848 arr.append(d)
1849
1850 return arr
1851
1852
1853 def FindPaneInDock(dock, window):
1854 """
1855 FindPaneInDock() looks up a specified window pointer inside a dock.
1856 If found, the corresponding AuiPaneInfo pointer is returned, otherwise None.
1857 """
1858
1859 for p in dock.panes:
1860 if p.window == window:
1861 return p
1862
1863 return None
1864
1865
1866 def RemovePaneFromDocks(docks, pane, exc=None):
1867 """
1868 RemovePaneFromDocks() removes a pane window from all docks
1869 with a possible exception specified by parameter "except".
1870 """
1871
1872 for ii in xrange(len(docks)):
1873 d = docks[ii]
1874 if d == exc:
1875 continue
1876 pi = FindPaneInDock(d, pane.window)
1877 if pi:
1878 d.panes.remove(pi)
1879
1880 docks[ii] = d
1881
1882 return docks
1883
1884
1885 def RenumberDockRows(docks):
1886 """
1887 RenumberDockRows() takes a dock and assigns sequential numbers
1888 to existing rows. Basically it takes out the gaps so if a
1889 dock has rows with numbers 0, 2, 5, they will become 0, 1, 2.
1890 """
1891
1892 for ii in xrange(len(docks)):
1893 dock = docks[ii]
1894 dock.dock_row = ii
1895 for jj in xrange(len(dock.panes)):
1896 dock.panes[jj].dock_row = ii
1897
1898 docks[ii] = dock
1899
1900 return docks
1901
1902
1903 def SetActivePane(panes, active_pane):
1904
1905 for ii in xrange(len(panes)):
1906 pane = panes[ii]
1907 pane.state &= ~AuiPaneInfo.optionActive
1908
1909 if pane.window == active_pane:
1910 pane.state |= AuiPaneInfo.optionActive
1911
1912 panes[ii] = pane
1913
1914 return panes
1915
1916
1917 def PaneSortFunc(p1, p2):
1918 """ This function is used to sort panes by dock position. """
1919
1920 return (p1.dock_pos < p2.dock_pos and [-1] or [1])[0]
1921
1922
1923 def EscapeDelimiters(s):
1924 """
1925 EscapeDelimiters() changes "" into "\" and "|" into "\|"
1926 in the input string. This is an internal functions which is
1927 used for saving perspectives.
1928 """
1929
1930 result = s.replace(";", "\\")
1931 result = result.replace("|", "|\\")
1932
1933 return result
1934
1935
1936 actionNone = 0
1937 actionResize = 1
1938 actionClickButton = 2
1939 actionClickCaption = 3
1940 actionDragToolbarPane = 4
1941 actionDragAuiFloatingPane = 5
1942
1943 auiInsertRowPixels = 10
1944 auiNewRowPixels = 40
1945 auiLayerInsertPixels = 40
1946 auiLayerInsertOffset = 5
1947
1948 # -- AuiManager class implementation --
1949 #
1950 # AuiManager manages the panes associated with it for a particular wx.Frame,
1951 # using a pane's AuiPaneInfo information to determine each pane's docking and
1952 # floating behavior. AuiManager uses wxPython's sizer mechanism to plan the
1953 # layout of each frame. It uses a replaceable dock art class to do all drawing,
1954 # so all drawing is localized in one area, and may be customized depending on an
1955 # applications' specific needs.
1956 #
1957 # AuiManager works as follows: The programmer adds panes to the class, or makes
1958 # changes to existing pane properties (dock position, floating state, show state, etc.).
1959 # To apply these changes, AuiManager's Update() function is called. This batch
1960 # processing can be used to avoid flicker, by modifying more than one pane at a time,
1961 # and then "committing" all of the changes at once by calling Update().
1962 #
1963 # Panes can be added quite easily:
1964 #
1965 # text1 = wx.TextCtrl(self, -1)
1966 # text2 = wx.TextCtrl(self, -1)
1967 # self._mgr.AddPane(text1, wx.LEFT, "Pane Caption")
1968 # self._mgr.AddPane(text2, wx.BOTTOM, "Pane Caption")
1969 # self._mgr.Update()
1970 #
1971 # Later on, the positions can be modified easily. The following will float an
1972 # existing pane in a tool window:
1973
1974 # self._mgr.GetPane(text1).Float()
1975
1976 # Layers, Rows and Directions, Positions
1977 # Inside PyAUI, the docking layout is figured out by checking several pane parameters.
1978 # Four of these are important for determining where a pane will end up.
1979 #
1980 # Direction - Each docked pane has a direction, Top, Bottom, Left, Right, or Center.
1981 # This is fairly self-explanatory. The pane will be placed in the location specified
1982 # by this variable.
1983 #
1984 # Position - More than one pane can be placed inside of a "dock." Imagine to panes
1985 # being docked on the left side of a window. One pane can be placed over another.
1986 # In proportionally managed docks, the pane position indicates it's sequential position,
1987 # starting with zero. So, in our scenario with two panes docked on the left side, the
1988 # top pane in the dock would have position 0, and the second one would occupy position 1.
1989 #
1990 # Row - A row can allow for two docks to be placed next to each other. One of the most
1991 # common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
1992 # the first row being in row 0, and the second in row 1. Rows can also be used on
1993 # vertically docked panes.
1994 #
1995 # Layer - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
1996 # Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
1997 # known as the "content window"). Increasing layers "swallow up" all layers of a lower
1998 # value. This can look very similar to multiple rows, but is different because all panes
1999 # in a lower level yield to panes in higher levels. The best way to understand layers
2000 # is by running the PyAUI sample (PyAUIDemo.py).
2001
2002 class AuiManager(wx.EvtHandler):
2003
2004 def __init__(self, frame=None, flags=None):
2005 """
2006 Default Class Constructor. frame specifies the wx.Frame which should be managed.
2007 flags specifies options which allow the frame management behavior to be modified.
2008 """
2009
2010 wx.EvtHandler.__init__(self)
2011 self._action = actionNone
2012 self._last_mouse_move = wx.Point()
2013 self._hover_button = None
2014 self._art = DefaultDockArt()
2015 self._hint_wnd = None
2016 self._action_window = None
2017 self._last_hint = wx.Rect()
2018 self._hint_fadetimer = wx.Timer(self, wx.NewId())
2019 self._hintshown = False
2020
2021 if flags is None:
2022 flags = AUI_MGR_DEFAULT
2023
2024 self._flags = flags
2025 self._active_pane = None
2026
2027 if frame:
2028 self.SetFrame(frame)
2029
2030 self._panes = []
2031 self._docks = []
2032 self._uiparts = []
2033
2034 self.Bind(wx.EVT_PAINT, self.OnPaint)
2035 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
2036 self.Bind(wx.EVT_SIZE, self.OnSize)
2037 self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor)
2038 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
2039 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
2040 self.Bind(wx.EVT_MOTION, self.OnMotion)
2041 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
2042 self.Bind(wx.EVT_TIMER, self.OnHintFadeTimer)
2043 self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus)
2044 self.Bind(EVT_AUI_PANEBUTTON, self.OnPaneButton)
2045
2046
2047 def GetPaneByWidget(self, window):
2048 """
2049 This version of GetPane() looks up a pane based on a
2050 'pane window', see below comment for more info.
2051 """
2052
2053 for p in self._panes:
2054 if p.window == window:
2055 return p
2056
2057 return NoneAuiPaneInfo
2058
2059
2060 def GetPaneByName(self, name):
2061 """
2062 This version of GetPane() looks up a pane based on a
2063 'pane name', see below comment for more info.
2064 """
2065
2066 for p in self._panes:
2067 if p.name == name:
2068 return p
2069
2070 return NoneAuiPaneInfo
2071
2072
2073 def GetPane(self, item):
2074 """
2075 GetPane() looks up a AuiPaneInfo structure based
2076 on the supplied window pointer. Upon failure, GetPane()
2077 returns an empty AuiPaneInfo, a condition which can be checked
2078 by calling AuiPaneInfo.IsOk().
2079
2080 The pane info's structure may then be modified. Once a pane's
2081 info is modified, AuiManager.Update() must be called to
2082 realize the changes in the UI.
2083
2084 AG: Added To Handle 2 Different Versions Of GetPane() For
2085 wxPython/Python.
2086 """
2087
2088 if isinstance(item, type("")):
2089 return self.GetPaneByName(item)
2090 else:
2091 return self.GetPaneByWidget(item)
2092
2093
2094 def GetAllPanes(self):
2095 """ GetAllPanes() returns a reference to all the pane info structures. """
2096
2097 return self._panes
2098
2099
2100 def HitTest(self, x, y):
2101 """
2102 HitTest() is an internal function which determines
2103 which UI item the specified coordinates are over
2104 (x,y) specify a position in client coordinates.
2105 """
2106
2107 result = None
2108
2109 for item in self._uiparts:
2110 # we are not interested in typeDock, because this space
2111 # isn't used to draw anything, just for measurements
2112 # besides, the entire dock area is covered with other
2113 # rectangles, which we are interested in.
2114 if item.type == DockUIPart.typeDock:
2115 continue
2116
2117 # if we already have a hit on a more specific item, we are not
2118 # interested in a pane hit. If, however, we don't already have
2119 # a hit, returning a pane hit is necessary for some operations
2120 if (item.type == DockUIPart.typePane or \
2121 item.type == DockUIPart.typePaneBorder) and result:
2122 continue
2123
2124 # if the point is inside the rectangle, we have a hit
2125 if item.rect.Contains((x, y)):
2126 result = item
2127
2128 return result
2129
2130
2131 # SetFlags() and GetFlags() allow the owner to set various
2132 # options which are global to AuiManager
2133
2134 def SetFlags(self, flags):
2135 """
2136 SetFlags() is used to specify AuiManager's settings flags. flags specifies
2137 options which allow the frame management behavior to be modified.
2138 """
2139
2140 self._flags = flags
2141
2142
2143 def GetFlags(self):
2144 """ GetFlags() returns the current manager's flags. """
2145
2146 return self._flags
2147
2148
2149 def SetFrame(self, frame):
2150 """
2151 SetFrame() is usually called once when the frame
2152 manager class is being initialized. "frame" specifies
2153 the frame which should be managed by the frame manager.
2154 """
2155
2156 if not frame:
2157 raise "\nERROR: Specified Frame Must Be Non-Null. "
2158
2159 self._frame = frame
2160 self._frame.PushEventHandler(self)
2161
2162 # if the owner is going to manage an MDI parent frame,
2163 # we need to add the MDI client window as the default
2164 # center pane
2165 if isinstance(frame, wx.MDIParentFrame):
2166 mdi_frame = frame
2167 client_window = mdi_frame.GetClientWindow()
2168
2169 if not client_window:
2170 raise "\nERROR: MDI Client Window Is Null. "
2171
2172 self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
2173 CenterPane().PaneBorder(False))
2174
2175
2176 def GetFrame(self):
2177 """ GetFrame() returns the frame pointer being managed by AuiManager. """
2178
2179 return self._frame
2180
2181
2182 def UnInit(self):
2183 """
2184 UnInit() must be called, usually in the destructor
2185 of the frame class. If it is not called, usually this
2186 will result in a crash upon program exit.
2187 """
2188
2189 self._frame.RemoveEventHandler(self)
2190
2191
2192 def GetArtProvider(self):
2193 """ GetArtProvider() returns the current art provider being used. """
2194
2195 return self._art
2196
2197
2198 def ProcessMgrEvent(self, event):
2199
2200 # first, give the owner frame a chance to override
2201 if self._frame:
2202 if self._frame.ProcessEvent(event):
2203 return
2204
2205 if event.GetEventType() != wxEVT_AUI_PANECLOSE:
2206 self.ProcessEvent(event)
2207
2208
2209 def CanMakeWindowsTransparent(self):
2210 if wx.Platform == "__WXMSW__":
2211 version = wx.GetOsDescription()
2212 found = version.find("XP") >= 0 or version.find("2000") >= 0 or version.find("NT") >= 0
2213 return found and _libimported
2214 elif wx.Platform == "__WXMAC__" and _carbon_dll:
2215 return True
2216 else:
2217 return False
2218
2219 # on supported windows systems (Win2000 and greater), this function
2220 # will make a frame window transparent by a certain amount
2221 def MakeWindowTransparent(self, wnd, amount):
2222
2223 if wnd.GetSize() == (0, 0):
2224 return
2225
2226 # this API call is not in all SDKs, only the newer ones, so
2227 # we will runtime bind this
2228 if wx.Platform == "__WXMSW__":
2229 hwnd = wnd.GetHandle()
2230
2231 if not hasattr(self, "_winlib"):
2232 if _libimported == "MH":
2233 self._winlib = win32api.LoadLibrary("user32")
2234 elif _libimported == "ctypes":
2235 self._winlib = ctypes.windll.user32
2236
2237 if _libimported == "MH":
2238 pSetLayeredWindowAttributes = win32api.GetProcAddress(self._winlib,
2239 "SetLayeredWindowAttributes")
2240
2241 if pSetLayeredWindowAttributes == None:
2242 return
2243
2244 exstyle = win32api.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
2245 if 0 == (exstyle & 0x80000):
2246 win32api.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, exstyle | 0x80000)
2247
2248 winxpgui.SetLayeredWindowAttributes(hwnd, 0, amount, 2)
2249
2250 elif _libimported == "ctypes":
2251 style = self._winlib.GetWindowLongA(hwnd, 0xffffffecL)
2252 style |= 0x00080000
2253 self._winlib.SetWindowLongA(hwnd, 0xffffffecL, style)
2254 self._winlib.SetLayeredWindowAttributes(hwnd, 0, amount, 2)
2255
2256 elif wx.Platform == "__WXMAC__" and _carbon_dll:
2257 handle = _carbon_dll.GetControlOwner(wnd.GetHandle())
2258 if amount == 0:
2259 amnt = float(0)
2260 else:
2261 amnt = float(amount)/255.0 #convert from the 0-255 amount to the float that Carbon wants
2262 _carbon_dll.SetWindowAlpha(handle, ctypes.c_float(amnt))
2263 else:
2264 #shouldn't be called, but just in case...
2265 return
2266
2267
2268 def SetArtProvider(self, art_provider):
2269 """
2270 SetArtProvider() instructs AuiManager to use the
2271 specified art provider for all drawing calls. This allows
2272 plugable look-and-feel features.
2273 """
2274
2275 # delete the last art provider, if any
2276 del self._art
2277
2278 # assign the new art provider
2279 self._art = art_provider
2280
2281
2282 def AddPane(self, window, arg1=None, arg2=None):
2283 """
2284 AddPane() tells the frame manager to start managing a child window. There
2285 are two versions of this function. The first verison allows the full spectrum
2286 of pane parameter possibilities (AddPane1). The second version is used for
2287 simpler user interfaces which do not require as much configuration (AddPane2).
2288 In wxPython, simply call AddPane.
2289 """
2290
2291 if type(arg1) == type(1):
2292 # This Is Addpane2
2293 if arg1 is None:
2294 arg1 = wx.LEFT
2295 if arg2 is None:
2296 arg2 = ""
2297 return self.AddPane2(window, arg1, arg2)
2298 else:
2299 return self.AddPane1(window, arg1)
2300
2301
2302 def AddPane1(self, window, pane_info):
2303
2304 # check if the pane has a valid window
2305 if not window:
2306 return False
2307
2308 # check if the pane already exists
2309 if self.GetPane(pane_info.window).IsOk():
2310 return False
2311
2312 if isinstance(window, wx.ToolBar):
2313 window.SetBestFittingSize()
2314
2315 self._panes.append(pane_info)
2316
2317 pinfo = self._panes[-1]
2318
2319 # set the pane window
2320 pinfo.window = window
2321
2322 # if the pane's name identifier is blank, create a random string
2323 if len(pinfo.name) == 0 or pinfo.name == "":
2324 pinfo.name = ("%s%08x%08x%08x")%(pinfo.window.GetName(), time.time(),
2325 time.clock(), len(self._panes))
2326
2327 # set initial proportion (if not already set)
2328 if pinfo.dock_proportion == 0:
2329 pinfo.dock_proportion = 100000
2330
2331 if pinfo.HasCloseButton() and len(pinfo.buttons) == 0:
2332 button = PaneButton(None)
2333 button.button_id = AuiPaneInfo.buttonClose
2334 pinfo.buttons.append(button)
2335
2336 if pinfo.best_size == wx.DefaultSize and pinfo.window:
2337 pinfo.best_size = pinfo.window.GetClientSize()
2338
2339 if isinstance(pinfo.window, wx.ToolBar):
2340 # GetClientSize() doesn't get the best size for
2341 # a toolbar under some newer versions of wxWidgets,
2342 # so use GetBestSize()
2343 pinfo.best_size = pinfo.window.GetBestSize()
2344
2345 # for some reason, wxToolBar::GetBestSize() is returning
2346 # a size that is a pixel shy of the correct amount.
2347 # I believe this to be the correct action, until
2348 # wxToolBar::GetBestSize() is fixed. Is this assumption
2349 # correct?
2350 pinfo.best_size.y = pinfo.best_size.y + 1
2351
2352 # this is needed for Win2000 to correctly fill toolbar backround
2353 # it should probably be repeated once system colour change happens
2354 if wx.Platform == "__WXMSW__" and pinfo.window.UseBgCol():
2355 pinfo.window.SetBackgroundColour(self.GetArtProvider().GetColour(AUI_ART_BACKGROUND_COLOUR))
2356
2357 if pinfo.min_size != wx.DefaultSize:
2358 if pinfo.best_size.x < pinfo.min_size.x:
2359 pinfo.best_size.x = pinfo.min_size.x
2360 if pinfo.best_size.y < pinfo.min_size.y:
2361 pinfo.best_size.y = pinfo.min_size.y
2362
2363 self._panes[-1] = pinfo
2364
2365 return True
2366
2367
2368 def AddPane2(self, window, direction, caption):
2369
2370 pinfo = AuiPaneInfo()
2371 pinfo.Caption(caption)
2372
2373 if direction == wx.TOP:
2374 pinfo.Top()
2375 elif direction == wx.BOTTOM:
2376 pinfo.Bottom()
2377 elif direction == wx.LEFT:
2378 pinfo.Left()
2379 elif direction == wx.RIGHT:
2380 pinfo.Right()
2381 elif direction == wx.CENTER:
2382 pinfo.CenterPane()
2383
2384 return self.AddPane(window, pinfo)
2385
2386
2387 def InsertPane(self, window, pane_info, insert_level=AUI_INSERT_PANE):
2388 """
2389 InsertPane() is used to insert either a previously unmanaged pane window
2390 into the frame manager, or to insert a currently managed pane somewhere else.
2391 InsertPane() will push all panes, rows, or docks aside and insert the window
2392 into the position specified by insert_location. Because insert_location can
2393 specify either a pane, dock row, or dock layer, the insert_level parameter is
2394 used to disambiguate this. The parameter insert_level can take a value of
2395 AUI_INSERT_PANE, AUI_INSERT_ROW or AUI_INSERT_DOCK.
2396 """
2397
2398 # shift the panes around, depending on the insert level
2399 if insert_level == AUI_INSERT_PANE:
2400 self._panes = DoInsertPane(self._panes, pane_info.dock_direction,
2401 pane_info.dock_layer, pane_info.dock_row,
2402 pane_info.dock_pos)
2403
2404 elif insert_level == AUI_INSERT_ROW:
2405 self._panes = DoInsertDockRow(self._panes, pane_info.dock_direction,
2406 pane_info.dock_layer, pane_info.dock_row)
2407
2408 elif insert_level == AUI_INSERT_DOCK:
2409 self._panes = DoInsertDockLayer(self._panes, pane_info.dock_direction,
2410 pane_info.dock_layer)
2411
2412 # if the window already exists, we are basically just moving/inserting the
2413 # existing window. If it doesn't exist, we need to add it and insert it
2414 existing_pane = self.GetPane(window)
2415 indx = self._panes.index(existing_pane)
2416
2417 if not existing_pane.IsOk():
2418
2419 return self.AddPane(window, pane_info)
2420
2421 else:
2422
2423 if pane_info.IsFloating():
2424 existing_pane.Float()
2425 if pane_info.floating_pos != wx.DefaultPosition:
2426 existing_pane.FloatingPosition(pane_info.floating_pos)
2427 if pane_info.floating_size != wx.DefaultSize:
2428 existing_pane.FloatingSize(pane_info.floating_size)
2429 else:
2430 existing_pane.Direction(pane_info.dock_direction)
2431 existing_pane.Layer(pane_info.dock_layer)
2432 existing_pane.Row(pane_info.dock_row)
2433 existing_pane.Position(pane_info.dock_pos)
2434
2435 self._panes[indx] = existing_pane
2436
2437 return True
2438
2439
2440 def DetachPane(self, window):
2441 """
2442 DetachPane() tells the AuiManager to stop managing the pane specified
2443 by window. The window, if in a floated frame, is reparented to the frame
2444 managed by AuiManager.
2445 """
2446
2447 for p in self._panes:
2448 if p.window == window:
2449 if p.frame:
2450 # we have a floating frame which is being detached. We need to
2451 # reparent it to m_frame and destroy the floating frame
2452
2453 # reduce flicker
2454 p.window.SetSize(1,1)
2455 p.frame.Show(False)
2456
2457 # reparent to self._frame and destroy the pane
2458 p.window.Reparent(self._frame)
2459 p.frame.SetSizer(None)
2460 p.frame.Destroy()
2461 p.frame = None
2462
2463 self._panes.remove(p)
2464 return True
2465
2466 return False
2467
2468
2469 def SavePerspective(self):
2470 """
2471 SavePerspective() saves all pane information as a single string.
2472 This string may later be fed into LoadPerspective() to restore
2473 all pane settings. This save and load mechanism allows an
2474 exact pane configuration to be saved and restored at a later time.
2475 """
2476
2477 result = "layout1|"
2478 pane_count = len(self._panes)
2479
2480 for pane_i in xrange(pane_count):
2481 pane = self._panes[pane_i]
2482 result = result + "name=" + EscapeDelimiters(pane.name) + ";"
2483 result = result + "caption=" + EscapeDelimiters(pane.caption) + ";"
2484 result = result + "state=%u;"%pane.state
2485 result = result + "dir=%d;"%pane.dock_direction
2486 result = result + "layer=%d;"%pane.dock_layer
2487 result = result + "row=%d;"%pane.dock_row
2488 result = result + "pos=%d;"%pane.dock_pos
2489 result = result + "prop=%d;"%pane.dock_proportion
2490 result = result + "bestw=%d;"%pane.best_size.x
2491 result = result + "besth=%d;"%pane.best_size.y
2492 result = result + "minw=%d;"%pane.min_size.x
2493 result = result + "minh=%d;"%pane.min_size.y
2494 result = result + "maxw=%d;"%pane.max_size.x
2495 result = result + "maxh=%d;"%pane.max_size.y
2496 result = result + "floatx=%d;"%pane.floating_pos.x
2497 result = result + "floaty=%d;"%pane.floating_pos.y
2498 result = result + "floatw=%d;"%pane.floating_size.x
2499 result = result + "floath=%d"%pane.floating_size.y
2500 result = result + "|"
2501
2502 dock_count = len(self._docks)
2503
2504 for dock_i in xrange(dock_count):
2505 dock = self._docks[dock_i]
2506 result = result + ("dock_size(%d,%d,%d)=%d|")%(dock.dock_direction,
2507 dock.dock_layer,
2508 dock.dock_row,
2509 dock.size)
2510
2511 return result
2512
2513
2514 def LoadPerspective(self, layout, update=True):
2515 """
2516 LoadPerspective() loads a layout which was saved with SavePerspective()
2517 If the "update" flag parameter is True, the GUI will immediately be updated.
2518 """
2519
2520 input = layout
2521 # check layout string version
2522 indx = input.index("|")
2523 part = input[0:indx]
2524 input = input[indx+1:]
2525 part = part.strip()
2526
2527 if part != "layout1":
2528 return False
2529
2530 olddocks = self._docks[:]
2531 oldpanes = self._panes[:]
2532
2533 # mark all panes currently managed as docked and hidden
2534 pane_count = len(self._panes)
2535 for pane_i in xrange(pane_count):
2536 pane = self._panes[pane_i]
2537 pane.Dock().Hide()
2538 self._panes[pane_i] = pane
2539
2540 # clear out the dock array this will be reconstructed
2541 self._docks = []
2542
2543 # replace escaped characters so we can
2544 # split up the string easily
2545 input = input.replace("\\|", "\a")
2546 input = input.replace("\\", "\b")
2547
2548 input = input.split("|")
2549
2550 for line in input:
2551
2552 if line.startswith("dock_size"):
2553
2554 indx = line.index("=")
2555 size = int(line[indx+1:])
2556 indx1 = line.index("(")
2557 indx2 = line.index(")")
2558 line2 = line[indx1+1:indx2]
2559 vals = line2.split(",")
2560 dir = int(vals[0])
2561 layer = int(vals[1])
2562 row = int(vals[2])
2563 dock = DockInfo()
2564 dock.dock_direction = dir
2565 dock.dock_layer = layer
2566 dock.dock_row = row
2567 dock.size = size
2568
2569 self._docks.append(dock)
2570
2571 elif line.startswith("name"):
2572
2573 newline = line.split(";")
2574 pane = AuiPaneInfo()
2575
2576 for newl in newline:
2577 myline = newl.strip()
2578 vals = myline.split("=")
2579 val_name = vals[0]
2580 value = vals[1]
2581 if val_name == "name":
2582 pane.name = value
2583 elif val_name == "caption":
2584 pane.caption = value
2585 elif val_name == "state":
2586 pane.state = int(value)
2587 elif val_name == "dir":
2588 pane.dock_direction = int(value)
2589 elif val_name == "layer":
2590 pane.dock_layer = int(value)
2591 elif val_name == "row":
2592 pane.dock_row = int(value)
2593 elif val_name == "pos":
2594 pane.dock_pos = int(value)
2595 elif val_name == "prop":
2596 pane.dock_proportion = int(value)
2597 elif val_name == "bestw":
2598 pane.best_size.x = int(value)
2599 elif val_name == "besth":
2600 pane.best_size.y = int(value)
2601 pane.best_size = wx.Size(pane.best_size.x, pane.best_size.y)
2602 elif val_name == "minw":
2603 pane.min_size.x = int(value)
2604 elif val_name == "minh":
2605 pane.min_size.y = int(value)
2606 pane.min_size = wx.Size(pane.min_size.x, pane.min_size.y)
2607 elif val_name == "maxw":
2608 pane.max_size.x = int(value)
2609 elif val_name == "maxh":
2610 pane.max_size.y = int(value)
2611 pane.max_size = wx.Size(pane.max_size.x, pane.max_size.y)
2612 elif val_name == "floatx":
2613 pane.floating_pos.x = int(value)
2614 elif val_name == "floaty":
2615 pane.floating_pos.y = int(value)
2616 pane.floating_pos = wx.Point(pane.floating_pos.x, pane.floating_pos.y)
2617 elif val_name == "floatw":
2618 pane.floating_size.x = int(value)
2619 elif val_name == "floath":
2620 pane.floating_size.y = int(value)
2621 pane.floating_size = wx.Size(pane.floating_size.x, pane.floating_size.y)
2622 else:
2623 raise "\nERROR: Bad Perspective String."
2624
2625 # replace escaped characters so we can
2626 # split up the string easily
2627 pane.name = pane.name.replace("\a", "|")
2628 pane.name = pane.name.replace("\b", ";")
2629 pane.caption = pane.caption.replace("\a", "|")
2630 pane.caption = pane.caption.replace("\b", ";")
2631
2632 p = self.GetPane(pane.name)
2633 if not p.IsOk():
2634 # the pane window couldn't be found
2635 # in the existing layout
2636 return False
2637
2638 indx = self._panes.index(p)
2639 pane.window = p.window
2640 pane.frame = p.frame
2641 pane.buttons = p.buttons
2642 self._panes[indx] = pane
2643
2644 if update:
2645 self.Update()
2646
2647 return True
2648
2649
2650 def GetPanePositionsAndSizes(self, dock):
2651 """ Returns all the panes positions and sizes. """
2652
2653 caption_size = self._art.GetMetric(AUI_ART_CAPTION_SIZE)
2654 pane_border_size = self._art.GetMetric(AUI_ART_PANE_BORDER_SIZE)
2655 gripper_size = self._art.GetMetric(AUI_ART_GRIPPER_SIZE)
2656
2657 positions = []
2658 sizes = []
2659
2660 action_pane = -1
2661 pane_count = len(dock.panes)
2662
2663 # find the pane marked as our action pane
2664 for pane_i in xrange(pane_count):
2665 pane = dock.panes[pane_i]
2666 if pane.state & AuiPaneInfo.actionPane:
2667 action_pane = pane_i
2668
2669 # set up each panes default position, and
2670 # determine the size (width or height, depending
2671 # on the dock's orientation) of each pane
2672 for pane in dock.panes:
2673 positions.append(pane.dock_pos)
2674 size = 0
2675
2676 if pane.HasBorder():
2677 size = size + pane_border_size*2
2678
2679 if dock.IsHorizontal():
2680 if pane.HasGripper() and not pane.HasGripperTop():
2681 size = size + gripper_size
2682
2683 size = size + pane.best_size.x
2684
2685 else:
2686 if pane.HasGripper() and pane.HasGripperTop():
2687 size = size + gripper_size
2688
2689 if pane.HasCaption():
2690 size = size + caption_size
2691
2692 size = size + pane.best_size.y
2693
2694 sizes.append(size)
2695
2696 # if there is no action pane, just return the default
2697 # positions (as specified in pane.pane_pos)
2698 if action_pane == -1:
2699 return positions, sizes
2700
2701 offset = 0
2702 for pane_i in xrange(action_pane-1, -1, -1):
2703 amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i])
2704 if amount >= 0:
2705 offset = offset + amount
2706 else:
2707 positions[pane_i] -= -amount
2708
2709 offset = offset + sizes[pane_i]
2710
2711 # if the dock mode is fixed, make sure none of the panes
2712 # overlap we will bump panes that overlap
2713 offset = 0
2714 for pane_i in xrange(action_pane, pane_count):
2715 amount = positions[pane_i] - offset
2716 if amount >= 0:
2717 offset = offset + amount
2718 else:
2719 positions[pane_i] += -amount
2720
2721 offset = offset + sizes[pane_i]
2722
2723 return positions, sizes
2724
2725
2726 def LayoutAddPane(self, cont, dock, pane, uiparts, spacer_only):
2727
2728 sizer_item = wx.SizerItem()
2729 caption_size = self._art.GetMetric(AUI_ART_CAPTION_SIZE)
2730 gripper_size = self._art.GetMetric(AUI_ART_GRIPPER_SIZE)
2731 pane_border_size = self._art.GetMetric(AUI_ART_PANE_BORDER_SIZE)
2732 pane_button_size = self._art.GetMetric(AUI_ART_PANE_BUTTON_SIZE)
2733
2734 # find out the orientation of the item (orientation for panes
2735 # is the same as the dock's orientation)
2736
2737 if dock.IsHorizontal():
2738 orientation = wx.HORIZONTAL
2739 else:
2740 orientation = wx.VERTICAL
2741
2742 # this variable will store the proportion
2743 # value that the pane will receive
2744 pane_proportion = pane.dock_proportion
2745
2746 horz_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
2747 vert_pane_sizer = wx.BoxSizer(wx.VERTICAL)
2748
2749 if pane.HasGripper():
2750
2751 part = DockUIPart()
2752 if pane.HasGripperTop():
2753 sizer_item = vert_pane_sizer.Add((1, gripper_size), 0, wx.EXPAND)
2754 else:
2755 sizer_item = horz_pane_sizer.Add((gripper_size, 1), 0, wx.EXPAND)
2756
2757 part.type = DockUIPart.typeGripper
2758 part.dock = dock
2759 part.pane = pane
2760 part.button = None
2761 part.orientation = orientation
2762 part.cont_sizer = horz_pane_sizer
2763 part.sizer_item = sizer_item
2764 uiparts.append(part)
2765
2766 if pane.HasCaption():
2767
2768 # create the caption sizer
2769 part = DockUIPart()
2770 caption_sizer = wx.BoxSizer(wx.HORIZONTAL)
2771 sizer_item = caption_sizer.Add((1, caption_size), 1, wx.EXPAND)
2772 part.type = DockUIPart.typeCaption
2773 part.dock = dock
2774 part.pane = pane
2775 part.button = None
2776 part.orientation = orientation
2777 part.cont_sizer = vert_pane_sizer
2778 part.sizer_item = sizer_item
2779 caption_part_idx = len(uiparts)
2780 uiparts.append(part)
2781
2782 # add pane buttons to the caption
2783 for button in pane.buttons:
2784 sizer_item = caption_sizer.Add((pane_button_size,
2785 caption_size),
2786 0, wx.EXPAND)
2787 part = DockUIPart()
2788 part.type = DockUIPart.typePaneButton
2789 part.dock = dock
2790 part.pane = pane
2791 part.button = button
2792 part.orientation = orientation
2793 part.cont_sizer = caption_sizer
2794 part.sizer_item = sizer_item
2795 uiparts.append(part)
2796
2797 # add the caption sizer
2798 sizer_item = vert_pane_sizer.Add(caption_sizer, 0, wx.EXPAND)
2799 uiparts[caption_part_idx].sizer_item = sizer_item
2800
2801 # add the pane window itself
2802 if spacer_only:
2803 sizer_item = vert_pane_sizer.Add((1, 1), 1, wx.EXPAND)
2804 else:
2805 sizer_item = vert_pane_sizer.Add(pane.window, 1, wx.EXPAND)
2806 vert_pane_sizer.SetItemMinSize(pane.window, (1, 1))
2807
2808 part = DockUIPart()
2809 part.type = DockUIPart.typePane
2810 part.dock = dock
2811 part.pane = pane
2812 part.button = None
2813 part.orientation = orientation
2814 part.cont_sizer = vert_pane_sizer
2815 part.sizer_item = sizer_item
2816 uiparts.append(part)
2817
2818 # determine if the pane should have a minimum size if the pane is
2819 # non-resizable (fixed) then we must set a minimum size. Alternitavely,
2820 # if the pane.min_size is set, we must use that value as well
2821
2822 min_size = pane.min_size
2823 if pane.IsFixed():
2824 if min_size == wx.DefaultSize:
2825 min_size = pane.best_size
2826 pane_proportion = 0
2827
2828 if min_size != wx.DefaultSize:
2829 vert_pane_sizer.SetItemMinSize(
2830 len(vert_pane_sizer.GetChildren())-1, (min_size.x, min_size.y))
2831
2832 # add the verticle sizer (caption, pane window) to the
2833 # horizontal sizer (gripper, verticle sizer)
2834 horz_pane_sizer.Add(vert_pane_sizer, 1, wx.EXPAND)
2835
2836 # finally, add the pane sizer to the dock sizer
2837 if pane.HasBorder():
2838 # allowing space for the pane's border
2839 sizer_item = cont.Add(horz_pane_sizer, pane_proportion,
2840 wx.EXPAND | wx.ALL, pane_border_size)
2841 part = DockUIPart()
2842 part.type = DockUIPart.typePaneBorder
2843 part.dock = dock
2844 part.pane = pane
2845 part.button = None
2846 part.orientation = orientation
2847 part.cont_sizer = cont
2848 part.sizer_item = sizer_item
2849 uiparts.append(part)
2850 else:
2851 sizer_item = cont.Add(horz_pane_sizer, pane_proportion, wx.EXPAND)
2852
2853 return uiparts
2854
2855
2856 def LayoutAddDock(self, cont, dock, uiparts, spacer_only):
2857
2858 sizer_item = wx.SizerItem()
2859 part = DockUIPart()
2860
2861 sash_size = self._art.GetMetric(AUI_ART_SASH_SIZE)
2862 orientation = (dock.IsHorizontal() and [wx.HORIZONTAL] or [wx.VERTICAL])[0]
2863
2864 # resizable bottom and right docks have a sash before them
2865 if not dock.fixed and (dock.dock_direction == AUI_DOCK_BOTTOM or \
2866 dock.dock_direction == AUI_DOCK_RIGHT):
2867
2868 sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
2869
2870 part.type = DockUIPart.typeDockSizer
2871 part.orientation = orientation
2872 part.dock = dock
2873 part.pane = None
2874 part.button = None
2875 part.cont_sizer = cont
2876 part.sizer_item = sizer_item
2877 uiparts.append(part)
2878
2879 # create the sizer for the dock
2880 dock_sizer = wx.BoxSizer(orientation)
2881
2882 # add each pane to the dock
2883 pane_count = len(dock.panes)
2884
2885 if dock.fixed:
2886
2887 # figure out the real pane positions we will
2888 # use, without modifying the each pane's pane_pos member
2889 pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
2890
2891 offset = 0
2892 for pane_i in xrange(pane_count):
2893
2894 pane = dock.panes[pane_i]
2895 pane_pos = pane_positions[pane_i]
2896
2897 amount = pane_pos - offset
2898 if amount > 0:
2899
2900 if dock.IsVertical():
2901 sizer_item = dock_sizer.Add((1, amount), 0, wx.EXPAND)
2902 else:
2903 sizer_item = dock_sizer.Add((amount, 1), 0, wx.EXPAND)
2904
2905 part = DockUIPart()
2906 part.type = DockUIPart.typeBackground
2907 part.dock = dock
2908 part.pane = None
2909 part.button = None
2910 part.orientation = (orientation==wx.HORIZONTAL and \
2911 [wx.VERTICAL] or [wx.HORIZONTAL])[0]
2912 part.cont_sizer = dock_sizer
2913 part.sizer_item = sizer_item
2914 uiparts.append(part)
2915
2916 offset = offset + amount
2917
2918 uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
2919
2920 offset = offset + pane_sizes[pane_i]
2921
2922 # at the end add a very small stretchable background area
2923 sizer_item = dock_sizer.Add((1, 1), 1, wx.EXPAND)
2924 part = DockUIPart()
2925 part.type = DockUIPart.typeBackground
2926 part.dock = dock
2927 part.pane = None
2928 part.button = None
2929 part.orientation = orientation
2930 part.cont_sizer = dock_sizer
2931 part.sizer_item = sizer_item
2932 uiparts.append(part)
2933
2934 else:
2935
2936 for pane_i in xrange(pane_count):
2937
2938 pane = dock.panes[pane_i]
2939
2940 # if this is not the first pane being added,
2941 # we need to add a pane sizer
2942 if pane_i > 0:
2943 sizer_item = dock_sizer.Add((sash_size, sash_size), 0, wx.EXPAND)
2944 part = DockUIPart()
2945 part.type = DockUIPart.typePaneSizer
2946 part.dock = dock
2947 part.pane = dock.panes[pane_i-1]
2948 part.button = None
2949 part.orientation = (orientation==wx.HORIZONTAL and \
2950 [wx.VERTICAL] or [wx.HORIZONTAL])[0]
2951 part.cont_sizer = dock_sizer
2952 part.sizer_item = sizer_item
2953 uiparts.append(part)
2954
2955 uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
2956
2957 if dock.dock_direction == AUI_DOCK_CENTER:
2958 sizer_item = cont.Add(dock_sizer, 1, wx.EXPAND)
2959 else:
2960 sizer_item = cont.Add(dock_sizer, 0, wx.EXPAND)
2961
2962 part = DockUIPart()
2963 part.type = DockUIPart.typeDock
2964 part.dock = dock
2965 part.pane = None
2966 part.button = None
2967 part.orientation = orientation
2968 part.cont_sizer = cont
2969 part.sizer_item = sizer_item
2970 uiparts.append(part)
2971
2972 if dock.IsHorizontal():
2973 cont.SetItemMinSize(dock_sizer, (0, dock.size))
2974 else:
2975 cont.SetItemMinSize(dock_sizer, (dock.size, 0))
2976
2977 # top and left docks have a sash after them
2978 if not dock.fixed and (dock.dock_direction == AUI_DOCK_TOP or \
2979 dock.dock_direction == AUI_DOCK_LEFT):
2980
2981 sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
2982
2983 part = DockUIPart()
2984 part.type = DockUIPart.typeDockSizer
2985 part.dock = dock
2986 part.pane = None
2987 part.button = None
2988 part.orientation = orientation
2989 part.cont_sizer = cont
2990 part.sizer_item = sizer_item
2991 uiparts.append(part)
2992
2993 return uiparts
2994
2995
2996 def LayoutAll(self, panes, docks, uiparts, spacer_only=False, oncheck=True):
2997
2998 container = wx.BoxSizer(wx.VERTICAL)
2999
3000 pane_border_size = self._art.GetMetric(AUI_ART_PANE_BORDER_SIZE)
3001 caption_size = self._art.GetMetric(AUI_ART_CAPTION_SIZE)
3002 cli_size = self._frame.GetClientSize()
3003
3004 # empty all docks out
3005 for ii in xrange(len(docks)):
3006 docks[ii].panes = []
3007
3008 dock_count = len(docks)
3009
3010 # iterate through all known panes, filing each
3011 # of them into the appropriate dock. If the
3012 # pane does not exist in the dock, add it
3013 for p in panes:
3014
3015 # find any docks in this layer
3016 arr = FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row)
3017
3018 if len(arr) > 0:
3019 dock = arr[0]
3020 else:
3021 # dock was not found, so we need to create a new one
3022 d = DockInfo()
3023 d.dock_direction = p.dock_direction
3024 d.dock_layer = p.dock_layer
3025 d.dock_row = p.dock_row
3026 docks.append(d)
3027 dock = docks[-1]
3028
3029 if p.IsDocked() and p.IsShown():
3030 # remove the pane from any existing docks except this one
3031 docks = RemovePaneFromDocks(docks, p, dock)
3032
3033 # pane needs to be added to the dock,
3034 # if it doesn't already exist
3035 if not FindPaneInDock(dock, p.window):
3036 dock.panes.append(p)
3037 else:
3038 # remove the pane from any existing docks
3039 docks = RemovePaneFromDocks(docks, p)
3040
3041 # remove any empty docks
3042 for ii in xrange(len(docks)-1, -1, -1):
3043 if len(docks[ii].panes) == 0:
3044 docks.pop(ii)
3045
3046 dock_count = len(docks)
3047 # configure the docks further
3048 for ii in xrange(len(docks)):
3049 dock = docks[ii]
3050 dock_pane_count = len(dock.panes)
3051
3052 # sort the dock pane array by the pane's
3053 # dock position (dock_pos), in ascending order
3054 dock.panes.sort(PaneSortFunc)
3055
3056 # for newly created docks, set up their initial size
3057 if dock.size == 0:
3058 size = 0
3059 for jj in xrange(dock_pane_count):
3060 pane = dock.panes[jj]
3061 pane_size = pane.best_size
3062 if pane_size == wx.DefaultSize:
3063 pane_size = pane.min_size
3064 if pane_size == wx.DefaultSize:
3065 pane_size = pane.window.GetSize()
3066
3067 if dock.IsHorizontal():
3068 size = max(pane_size.y, size)
3069 else:
3070 size = max(pane_size.x, size)
3071
3072 # add space for the border (two times), but only
3073 # if at least one pane inside the dock has a pane border
3074 for jj in xrange(dock_pane_count):
3075 if dock.panes[jj].HasBorder():
3076 size = size + pane_border_size*2
3077 break
3078
3079 # if pane is on the top or bottom, add the caption height,
3080 # but only if at least one pane inside the dock has a caption
3081 if dock.IsHorizontal():
3082 for jj in xrange(dock_pane_count):
3083 if dock.panes[jj].HasCaption():
3084 size = size + caption_size
3085 break
3086
3087 # new dock's size may not be more than 1/3 of the frame size
3088 if dock.IsHorizontal():
3089 size = min(size, cli_size.y/3)
3090 else:
3091 size = min(size, cli_size.x/3)
3092
3093 if size < 10:
3094 size = 10
3095
3096 dock.size = size
3097
3098 # determine the dock's minimum size
3099 plus_border = False
3100 plus_caption = False
3101 dock_min_size = 0
3102 for jj in xrange(dock_pane_count):
3103 pane = dock.panes[jj]
3104 if pane.min_size != wx.DefaultSize:
3105 if pane.HasBorder():
3106 plus_border = True
3107 if pane.HasCaption():
3108 plus_caption = True
3109 if dock.IsHorizontal():
3110 if pane.min_size.y > dock_min_size:
3111 dock_min_size = pane.min_size.y
3112 else:
3113 if pane.min_size.x > dock_min_size:
3114 dock_min_size = pane.min_size.x
3115
3116 if plus_border:
3117 dock_min_size = dock_min_size + pane_border_size*2
3118 if plus_caption and dock.IsHorizontal():
3119 dock_min_size = dock_min_size + caption_size
3120
3121 dock.min_size = dock_min_size
3122
3123 # if the pane's current size is less than it's
3124 # minimum, increase the dock's size to it's minimum
3125 if dock.size < dock.min_size:
3126 dock.size = dock.min_size
3127
3128 # determine the dock's mode (fixed or proportional)
3129 # determine whether the dock has only toolbars
3130 action_pane_marked = False
3131 dock.fixed = True
3132 dock.toolbar = True
3133 for jj in xrange(dock_pane_count):
3134 pane = dock.panes[jj]
3135 if not pane.IsFixed():
3136 dock.fixed = False
3137 if not pane.IsToolbar():
3138 dock.toolbar = False
3139 if pane.state & AuiPaneInfo.actionPane:
3140 action_pane_marked = True
3141
3142 # if the dock mode is proportional and not fixed-pixel,
3143 # reassign the dock_pos to the sequential 0, 1, 2, 3
3144 # e.g. remove gaps like 1, 2, 30, 500
3145 if not dock.fixed:
3146 for jj in xrange(dock_pane_count):
3147 pane = dock.panes[jj]
3148 pane.dock_pos = jj
3149 dock.panes[jj] = pane
3150
3151 # if the dock mode is fixed, and none of the panes
3152 # are being moved right now, make sure the panes
3153 # do not overlap each other. If they do, we will
3154 # adjust the panes' positions
3155 if dock.fixed and not action_pane_marked:
3156 pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
3157 offset = 0
3158 for jj in xrange(dock_pane_count):
3159 pane = dock.panes[jj]
3160 pane.dock_pos = pane_positions[jj]
3161 amount = pane.dock_pos - offset
3162 if amount >= 0:
3163 offset = offset + amount
3164 else:
3165 pane.dock_pos += -amount
3166
3167 offset = offset + pane_sizes[jj]
3168 dock.panes[jj] = pane
3169
3170 if oncheck:
3171 self._docks[ii] = dock
3172
3173 # discover the maximum dock layer
3174 max_layer = 0
3175
3176 for ii in xrange(dock_count):
3177 max_layer = max(max_layer, docks[ii].dock_layer)
3178
3179 # clear out uiparts
3180 uiparts = []
3181
3182 # create a bunch of box sizers,
3183 # from the innermost level outwards.
3184 cont = None
3185 middle = None
3186
3187 if oncheck:
3188 docks = self._docks
3189
3190 for layer in xrange(max_layer+1):
3191 # find any docks in this layer
3192 arr = FindDocks(docks, -1, layer, -1)
3193 # if there aren't any, skip to the next layer
3194 if len(arr) == 0:
3195 continue
3196
3197 old_cont = cont
3198
3199 # create a container which will hold this layer's
3200 # docks (top, bottom, left, right)
3201 cont = wx.BoxSizer(wx.VERTICAL)
3202
3203 # find any top docks in this layer
3204 arr = FindDocks(docks, AUI_DOCK_TOP, layer, -1, arr)
3205 arr = RenumberDockRows(arr)
3206 if len(arr) > 0:
3207 for row in xrange(len(arr)):
3208 uiparts = self.LayoutAddDock(cont, arr[row], uiparts, spacer_only)
3209
3210 # fill out the middle layer (which consists
3211 # of left docks, content area and right docks)
3212
3213 middle = wx.BoxSizer(wx.HORIZONTAL)
3214
3215 # find any left docks in this layer
3216 arr = FindDocks(docks, AUI_DOCK_LEFT, layer, -1, arr)
3217 arr = RenumberDockRows(arr)
3218 if len(arr) > 0:
3219 for row in xrange(len(arr)):
3220 uiparts = self.LayoutAddDock(middle, arr[row], uiparts, spacer_only)
3221
3222 # add content dock (or previous layer's sizer
3223 # to the middle
3224 if not old_cont:
3225 # find any center docks
3226 arr = FindDocks(docks, AUI_DOCK_CENTER, -1, -1, arr)
3227 if len(arr) > 0:
3228 for row in xrange(len(arr)):
3229 uiparts = self.LayoutAddDock(middle, arr[row], uiparts, spacer_only)
3230 else:
3231 # there are no center docks, add a background area
3232 sizer_item = middle.Add((1, 1), 1, wx.EXPAND)
3233 part = DockUIPart()
3234 part.type = DockUIPart.typeBackground
3235 part.pane = None
3236 part.dock = None
3237 part.button = None
3238 part.cont_sizer = middle
3239 part.sizer_item = sizer_item
3240 uiparts.append(part)
3241 else:
3242 middle.Add(old_cont, 1, wx.EXPAND)
3243
3244 # find any right docks in this layer
3245 arr = FindDocks(docks, AUI_DOCK_RIGHT, layer, -1, arr)
3246 arr = RenumberDockRows(arr)
3247 if len(arr) > 0:
3248 for row in xrange(len(arr)-1, -1, -1):
3249 uiparts = self.LayoutAddDock(middle, arr[row], uiparts, spacer_only)
3250
3251 cont.Add(middle, 1, wx.EXPAND)
3252
3253 # find any bottom docks in this layer
3254 arr = FindDocks(docks, AUI_DOCK_BOTTOM, layer, -1, arr)
3255 arr = RenumberDockRows(arr)
3256 if len(arr) > 0:
3257 for row in xrange(len(arr)-1, -1, -1):
3258 uiparts = self.LayoutAddDock(cont, arr[row], uiparts, spacer_only)
3259
3260 if not cont:
3261 # no sizer available, because there are no docks,
3262 # therefore we will create a simple background area
3263 cont = wx.BoxSizer(wx.VERTICAL)
3264 sizer_item = cont.Add((1, 1), 1, wx.EXPAND)
3265 part = DockUIPart()
3266 part.type = DockUIPart.typeBackground
3267 part.pane = None
3268 part.dock = None
3269 part.button = None
3270 part.cont_sizer = middle
3271 part.sizer_item = sizer_item
3272 uiparts.append(part)
3273
3274 if oncheck:
3275 self._uiparts = uiparts
3276 self._docks = docks
3277
3278 container.Add(cont, 1, wx.EXPAND)
3279
3280 if oncheck:
3281 return container
3282 else:
3283 return container, panes, docks, uiparts
3284
3285
3286 def Update(self):
3287 """
3288 Update() updates the layout. Whenever changes are made to
3289 one or more panes, this function should be called. It is the
3290 external entry point for running the layout engine.
3291 """
3292
3293 pane_count = len(self._panes)
3294 # delete old sizer first
3295 self._frame.SetSizer(None)
3296
3297 # destroy floating panes which have been
3298 # redocked or are becoming non-floating
3299 for ii in xrange(pane_count):
3300 p = self._panes[ii]
3301 if not p.IsFloating() and p.frame:
3302 # because the pane is no longer in a floating, we need to
3303 # reparent it to self._frame and destroy the floating frame
3304 # reduce flicker
3305 p.window.SetSize((1, 1))
3306 p.frame.Show(False)
3307
3308 # reparent to self._frame and destroy the pane
3309 p.window.Reparent(self._frame)
3310 p.frame.SetSizer(None)
3311 p.frame.Destroy()
3312 p.frame = None
3313
3314 self._panes[ii] = p
3315
3316 # create a layout for all of the panes
3317 sizer = self.LayoutAll(self._panes, self._docks, self._uiparts, False)
3318
3319 # hide or show panes as necessary,
3320 # and float panes as necessary
3321
3322 pane_count = len(self._panes)
3323
3324 for ii in xrange(pane_count):
3325 p = self._panes[ii]
3326 if p.IsFloating():
3327 if p.frame == None:
3328 # we need to create a frame for this
3329 # pane, which has recently been floated
3330 resizeborder = 1
3331 if p.IsFixed():
3332 resizeborder = 0
3333
3334 frame = AuiFloatingPane(self._frame, self, -1, "", p.floating_pos,
3335 p.floating_size, resizeborder=resizeborder)
3336
3337 # on MSW, if the owner desires transparent dragging, and
3338 # the dragging is happening right now, then the floating
3339 # window should have this style by default
3340
3341 if self._action == actionDragAuiFloatingPane and self.UseTransparentDrag():
3342 self.MakeWindowTransparent(frame, 150)
3343
3344 frame.SetPaneWindow(p)
3345 p.frame = frame
3346 if p.IsShown():
3347 frame.Show()
3348 else:
3349
3350 # frame already exists, make sure it's position
3351 # and size reflect the information in AuiPaneInfo
3352 if p.frame.GetPosition() != p.floating_pos:
3353 p.frame.SetDimensions(p.floating_pos.x, p.floating_pos.y,
3354 -1, -1, wx.SIZE_USE_EXISTING)
3355 p.frame.Show(p.IsShown())
3356 else:
3357
3358 p.window.Show(p.IsShown())
3359
3360 # if "active panes" are no longer allowed, clear
3361 # any optionActive values from the pane states
3362 if self._flags & AUI_MGR_ALLOW_ACTIVE_PANE == 0:
3363 p.state &= ~AuiPaneInfo.optionActive
3364
3365 self._panes[ii] = p
3366
3367
3368 old_pane_rects = []
3369
3370 for ii in xrange(pane_count):
3371 r = wx.Rect()
3372 p = self._panes[ii]
3373
3374 if p.window and p.IsShown() and p.IsDocked():
3375 r = p.rect
3376
3377 old_pane_rects.append(r)
3378
3379 # apply the new sizer
3380 self._frame.SetSizer(sizer)
3381 self._frame.SetAutoLayout(False)
3382 self.DoFrameLayout()
3383
3384 # now that the frame layout is done, we need to check
3385 # the new pane rectangles against the old rectangles that
3386 # we saved a few lines above here. If the rectangles have
3387 # changed, the corresponding panes must also be updated
3388 for ii in xrange(pane_count):
3389 p = self._panes[ii]
3390 if p.window and p.IsShown() and p.IsDocked():
3391 if p.rect != old_pane_rects[ii]:
3392 p.window.Refresh()
3393 p.window.Update()
3394
3395 self.Repaint()
3396
3397
3398 def DoFrameLayout(self):
3399 """
3400 DoFrameLayout() is an internal function which invokes wxSizer.Layout
3401 on the frame's main sizer, then measures all the various UI items
3402 and updates their internal rectangles. This should always be called
3403 instead of calling self._frame.Layout() directly
3404 """
3405
3406 self._frame.Layout()
3407
3408 for ii in xrange(len(self._uiparts)):
3409 part = self._uiparts[ii]
3410
3411 # get the rectangle of the UI part
3412 # originally, this code looked like this:
3413 # part.rect = wx.Rect(part.sizer_item.GetPosition(),
3414 # part.sizer_item.GetSize())
3415 # this worked quite well, with one exception: the mdi
3416 # client window had a "deferred" size variable
3417 # that returned the wrong size. It looks like
3418 # a bug in wx, because the former size of the window
3419 # was being returned. So, we will retrieve the part's
3420 # rectangle via other means
3421
3422 part.rect = part.sizer_item.GetRect()
3423 flag = part.sizer_item.GetFlag()
3424 border = part.sizer_item.GetBorder()
3425
3426 if flag & wx.TOP:
3427 part.rect.y -= border
3428 part.rect.height += border
3429 if flag & wx.LEFT:
3430 part.rect.x -= border
3431 part.rect.width += border
3432 if flag & wx.BOTTOM:
3433 part.rect.height += border
3434 if flag & wx.RIGHT:
3435 part.rect.width += border
3436
3437 if part.type == DockUIPart.typeDock:
3438 part.dock.rect = part.rect
3439 if part.type == DockUIPart.typePane:
3440 part.pane.rect = part.rect
3441
3442 self._uiparts[ii] = part
3443
3444
3445 def GetPanePart(self, wnd):
3446 """
3447 GetPanePart() looks up the pane border UI part of the
3448 pane specified. This allows the caller to get the exact rectangle
3449 of the pane in question, including decorations like caption and border.
3450 """
3451
3452 for ii in xrange(len(self._uiparts)):
3453 part = self._uiparts[ii]
3454 if part.type == DockUIPart.typePaneBorder and \
3455 part.pane and part.pane.window == wnd:
3456 return part
3457
3458 for ii in xrange(len(self._uiparts)):
3459 part = self._uiparts[ii]
3460 if part.type == DockUIPart.typePane and \
3461 part.pane and part.pane.window == wnd:
3462 return part
3463
3464 return None
3465
3466
3467 def GetDockPixelOffset(self, test):
3468 """
3469 GetDockPixelOffset() is an internal function which returns
3470 a dock's offset in pixels from the left side of the window
3471 (for horizontal docks) or from the top of the window (for
3472 vertical docks). This value is necessary for calculating
3473 fixel-pane/toolbar offsets when they are dragged.
3474 """
3475
3476 # the only way to accurately calculate the dock's
3477 # offset is to actually run a theoretical layout
3478
3479 docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
3480 panes.append(test)
3481
3482 sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
3483 client_size = self._frame.GetClientSize()
3484 sizer.SetDimension(0, 0, client_size.x, client_size.y)
3485 sizer.Layout()
3486
3487 for ii in xrange(len(uiparts)):
3488 part = uiparts[ii]
3489 pos = part.sizer_item.GetPosition()
3490 size = part.sizer_item.GetSize()
3491 part.rect = wx.Rect(pos[0], pos[1], size[0], size[1])
3492 if part.type == DockUIPart.typeDock:
3493 part.dock.rect = part.rect
3494
3495 sizer.Destroy()
3496
3497 for ii in xrange(len(docks)):
3498 dock = docks[ii]
3499 if test.dock_direction == dock.dock_direction and \
3500 test.dock_layer == dock.dock_layer and \
3501 test.dock_row == dock.dock_row:
3502
3503 if dock.IsVertical():
3504 return dock.rect.y
3505 else:
3506 return dock.rect.x
3507
3508 return 0
3509
3510
3511 def ProcessDockResult(self, target, new_pos):
3512 """
3513 ProcessDockResult() is a utility function used by DoDrop() - it checks
3514 if a dock operation is allowed, the new dock position is copied into
3515 the target info. If the operation was allowed, the function returns True.
3516 """
3517
3518 allowed = False
3519 if new_pos.dock_direction == AUI_DOCK_TOP:
3520 allowed = target.IsTopDockable()
3521 elif new_pos.dock_direction == AUI_DOCK_BOTTOM:
3522 allowed = target.IsBottomDockable()
3523 elif new_pos.dock_direction == AUI_DOCK_LEFT:
3524 allowed = target.IsLeftDockable()
3525 elif new_pos.dock_direction == AUI_DOCK_RIGHT:
3526 allowed = target.IsRightDockable()
3527
3528 if allowed:
3529 target = new_pos
3530
3531 return allowed, target
3532
3533
3534 def DoDrop(self, docks, panes, target, pt, offset=wx.Point(0,0)):
3535 """
3536 DoDrop() is an important function. It basically takes a mouse position,
3537 and determines where the panes new position would be. If the pane is to be
3538 dropped, it performs the drop operation using the specified dock and pane
3539 arrays. By specifying copy dock and pane arrays when calling, a "what-if"
3540 scenario can be performed, giving precise coordinates for drop hints.
3541 """
3542
3543 cli_size = self._frame.GetClientSize()
3544
3545 drop = AuiPaneInfo()
3546 drop.name = target.name
3547 drop.caption = target.caption
3548 drop.window = target.window
3549 drop.frame = target.frame
3550 drop.state = target.state
3551 drop.dock_direction = target.dock_direction
3552 drop.dock_layer = target.dock_layer
3553 drop.dock_row = target.dock_row
3554 drop.dock_pos = target.dock_pos
3555 drop.best_size = target.best_size
3556 drop.min_size = target.min_size
3557 drop.max_size = target.max_size
3558 drop.floating_pos = target.floating_pos
3559 drop.floating_size = target.floating_size
3560 drop.dock_proportion = target.dock_proportion
3561 drop.buttons = target.buttons
3562 drop.rect = target.rect
3563
3564 # The result should always be shown
3565 drop.Show()
3566
3567 # Check to see if the pane has been dragged outside of the window
3568 # (or near to the outside of the window), if so, dock it along the edge
3569
3570 layer_insert_offset = auiLayerInsertOffset
3571
3572 if target.IsToolbar():
3573 layer_insert_offset = 0
3574
3575 if pt.x < layer_insert_offset and \
3576 pt.x > layer_insert_offset-auiLayerInsertPixels:
3577 new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_LEFT),
3578 GetMaxLayer(docks, AUI_DOCK_BOTTOM)),
3579 GetMaxLayer(docks, AUI_DOCK_TOP)) + 1
3580
3581 drop.Dock().Left().Layer(new_layer).Row(0). \
3582 Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
3583
3584 return self.ProcessDockResult(target, drop)
3585
3586 elif pt.y < layer_insert_offset and \
3587 pt.y > layer_insert_offset-auiLayerInsertPixels:
3588 new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_TOP),
3589 GetMaxLayer(docks, AUI_DOCK_LEFT)),
3590 GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
3591
3592 drop.Dock().Top().Layer(new_layer).Row(0). \
3593 Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
3594
3595 return self.ProcessDockResult(target, drop)
3596
3597 elif pt.x >= cli_size.x - layer_insert_offset and \
3598 pt.x < cli_size.x - layer_insert_offset + auiLayerInsertPixels:
3599
3600 new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_RIGHT),
3601 GetMaxLayer(docks, AUI_DOCK_TOP)),
3602 GetMaxLayer(docks, AUI_DOCK_BOTTOM)) + 1
3603
3604 drop.Dock().Right().Layer(new_layer).Row(0). \
3605 Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
3606
3607 return self.ProcessDockResult(target, drop)
3608
3609 elif pt.y >= cli_size.y - layer_insert_offset and \
3610 pt.y < cli_size.y - layer_insert_offset + auiLayerInsertPixels:
3611
3612 new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_BOTTOM),
3613 GetMaxLayer(docks, AUI_DOCK_LEFT)),
3614 GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
3615
3616 drop.Dock().Bottom().Layer(new_layer).Row(0). \
3617 Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
3618
3619 return self.ProcessDockResult(target, drop)
3620
3621 part = self.HitTest(pt.x, pt.y)
3622
3623 if drop.IsToolbar():
3624 if not part or not part.dock:
3625 return False, target
3626
3627 # calculate the offset from where the dock begins
3628 # to the point where the user dropped the pane
3629 dock_drop_offset = 0
3630 if part.dock.IsHorizontal():
3631 dock_drop_offset = pt.x - part.dock.rect.x - offset.x
3632 else:
3633 dock_drop_offset = pt.y - part.dock.rect.y - offset.y
3634
3635 # toolbars may only be moved in and to fixed-pane docks,
3636 # otherwise we will try to float the pane. Also, the pane
3637 # should float if being dragged over center pane windows
3638 if not part.dock.fixed or part.dock.dock_direction == AUI_DOCK_CENTER:
3639 if (self._flags & AUI_MGR_ALLOW_FLOATING) and (drop.IsFloatable() or (\
3640 part.dock.dock_direction != AUI_DOCK_CENTER and \
3641 part.dock.dock_direction != AUI_DOCK_NONE)):
3642
3643 drop.Float()
3644
3645 return self.ProcessDockResult(target, drop)
3646
3647 drop.Dock(). \
3648 Direction(part.dock.dock_direction). \
3649 Layer(part.dock.dock_layer). \
3650 Row(part.dock.dock_row). \
3651 Position(dock_drop_offset)
3652
3653 if pt.y < part.dock.rect.y + 2 and len(part.dock.panes) > 1:
3654 row = drop.dock_row
3655 panes = DoInsertDockRow(panes, part.dock.dock_direction,
3656 part.dock.dock_layer,
3657 part.dock.dock_row)
3658 drop.dock_row = row
3659
3660 if pt.y > part.dock.rect.y + part.dock.rect.height - 2 and \
3661 len(part.dock.panes) > 1:
3662 panes = DoInsertDockRow(panes, part.dock.dock_direction,
3663 part.dock.dock_layer,
3664 part.dock.dock_row+1)
3665 drop.dock_row = part.dock.dock_row + 1
3666
3667 return self.ProcessDockResult(target, drop)
3668
3669 if not part:
3670 return False, target
3671
3672 if part.type == DockUIPart.typePaneBorder or \
3673 part.type == DockUIPart.typeCaption or \
3674 part.type == DockUIPart.typeGripper or \
3675 part.type == DockUIPart.typePaneButton or \
3676 part.type == DockUIPart.typePane or \
3677 part.type == DockUIPart.typePaneSizer or \
3678 part.type == DockUIPart.typeDockSizer or \
3679 part.type == DockUIPart.typeBackground:
3680
3681 if part.type == DockUIPart.typeDockSizer:
3682 if len(part.dock.panes) != 1:
3683 return False, target
3684
3685 part = self.GetPanePart(part.dock.panes[0].window)
3686
3687 if not part:
3688 return False, target
3689
3690 # If a normal frame is being dragged over a toolbar, insert it
3691 # along the edge under the toolbar, but over all other panes.
3692 # (this could be done much better, but somehow factoring this
3693 # calculation with the one at the beginning of this function)
3694 if part.dock and (hasattr(part.dock, "toolbar") and part.dock.toolbar):
3695 layer = 0
3696
3697 if part.dock.dock_direction == AUI_DOCK_LEFT:
3698 layer = max(max(GetMaxLayer(docks, AUI_DOCK_LEFT),
3699 GetMaxLayer(docks, AUI_DOCK_BOTTOM)),
3700 GetMaxLayer(docks, AUI_DOCK_TOP))
3701 elif part.dock.dock_direction == AUI_DOCK_TOP:
3702 layer = max(max(GetMaxLayer(docks, AUI_DOCK_TOP),
3703 GetMaxLayer(docks, AUI_DOCK_LEFT)),
3704 GetMaxLayer(docks, AUI_DOCK_RIGHT))
3705 elif part.dock.dock_direction == AUI_DOCK_RIGHT:
3706 layer = max(max(GetMaxLayer(docks, AUI_DOCK_RIGHT),
3707 GetMaxLayer(docks, AUI_DOCK_TOP)),
3708 GetMaxLayer(docks, AUI_DOCK_BOTTOM))
3709 elif part.dock.dock_direction == AUI_DOCK_BOTTOM:
3710 layer = max(max(GetMaxLayer(docks, AUI_DOCK_BOTTOM),
3711 GetMaxLayer(docks, AUI_DOCK_LEFT)),
3712 GetMaxLayer(docks, AUI_DOCK_RIGHT))
3713
3714 panes = DoInsertDockRow(panes, part.dock.dock_direction,
3715 layer, 0)
3716 drop.Dock(). \
3717 Direction(part.dock.dock_direction). \
3718 Layer(layer).Row(0).Position(0)
3719
3720 return self.ProcessDockResult(target, drop)
3721
3722 if not part.pane:
3723 return False, target
3724
3725 part = self.GetPanePart(part.pane.window)
3726 if not part:
3727 return False, target
3728
3729 insert_dock_row = False
3730 insert_row = part.pane.dock_row
3731 insert_dir = part.pane.dock_direction
3732 insert_layer = part.pane.dock_layer
3733
3734 if part.pane.dock_direction == AUI_DOCK_TOP:
3735 if pt.y >= part.rect.y and \
3736 pt.y < part.rect.y+auiInsertRowPixels:
3737 insert_dock_row = True
3738
3739 elif part.pane.dock_direction == AUI_DOCK_BOTTOM:
3740 if pt.y > part.rect.y+part.rect.height-auiInsertRowPixels and \
3741 pt.y <= part.rect.y + part.rect.height:
3742 insert_dock_row = True
3743
3744 elif part.pane.dock_direction == AUI_DOCK_LEFT:
3745 if pt.x >= part.rect.x and \
3746 pt.x < part.rect.x+auiInsertRowPixels:
3747 insert_dock_row = True
3748
3749 elif part.pane.dock_direction == AUI_DOCK_RIGHT:
3750 if pt.x > part.rect.x+part.rect.width-auiInsertRowPixels and \
3751 pt.x <= part.rect.x+part.rect.width:
3752 insert_dock_row = True
3753
3754 elif part.pane.dock_direction == AUI_DOCK_CENTER:
3755 # "new row pixels" will be set to the default, but
3756 # must never exceed 20% of the window size
3757 new_row_pixels_x = auiNewRowPixels
3758 new_row_pixels_y = auiNewRowPixels
3759
3760 if new_row_pixels_x > part.rect.width*20/100:
3761 new_row_pixels_x = part.rect.width*20/100
3762
3763 if new_row_pixels_y > part.rect.height*20/100:
3764 new_row_pixels_y = part.rect.height*20/100
3765
3766 # determine if the mouse pointer is in a location that
3767 # will cause a new row to be inserted. The hot spot positions
3768 # are along the borders of the center pane
3769
3770 insert_layer = 0
3771 insert_dock_row = True
3772
3773 if pt.x >= part.rect.x and \
3774 pt.x < part.rect.x+new_row_pixels_x:
3775 insert_dir = AUI_DOCK_LEFT
3776 elif pt.y >= part.rect.y and \
3777 pt.y < part.rect.y+new_row_pixels_y:
3778 insert_dir = AUI_DOCK_TOP
3779 elif pt.x >= part.rect.x + part.rect.width-new_row_pixels_x and \
3780 pt.x < part.rect.x + part.rect.width:
3781 insert_dir = AUI_DOCK_RIGHT
3782 elif pt.y >= part.rect.y+ part.rect.height-new_row_pixels_y and \
3783 pt.y < part.rect.y + part.rect.height:
3784 insert_dir = AUI_DOCK_BOTTOM
3785 else:
3786 return False, target
3787
3788 insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
3789
3790 if insert_dock_row:
3791
3792 panes = DoInsertDockRow(panes, insert_dir, insert_layer,
3793 insert_row)
3794 drop.Dock().Direction(insert_dir). \
3795 Layer(insert_layer). \
3796 Row(insert_row). \
3797 Position(0)
3798
3799 return self.ProcessDockResult(target, drop)
3800
3801 # determine the mouse offset and the pane size, both in the
3802 # direction of the dock itself, and perpendicular to the dock
3803
3804 if part.orientation == wx.VERTICAL:
3805
3806 offset = pt.y - part.rect.y
3807 size = part.rect.GetHeight()
3808
3809 else:
3810
3811 offset = pt.x - part.rect.x
3812 size = part.rect.GetWidth()
3813
3814 drop_position = part.pane.dock_pos
3815
3816 # if we are in the top/left part of the pane,
3817 # insert the pane before the pane being hovered over
3818 if offset <= size/2:
3819
3820 drop_position = part.pane.dock_pos
3821 panes = DoInsertPane(panes,
3822 part.pane.dock_direction,
3823 part.pane.dock_layer,
3824 part.pane.dock_row,
3825 part.pane.dock_pos)
3826
3827 # if we are in the bottom/right part of the pane,
3828 # insert the pane before the pane being hovered over
3829 if offset > size/2:
3830
3831 drop_position = part.pane.dock_pos+1
3832 panes = DoInsertPane(panes,
3833 part.pane.dock_direction,
3834 part.pane.dock_layer,
3835 part.pane.dock_row,
3836 part.pane.dock_pos+1)
3837
3838 drop.Dock(). \
3839 Direction(part.dock.dock_direction). \
3840 Layer(part.dock.dock_layer). \
3841 Row(part.dock.dock_row). \
3842 Position(drop_position)
3843
3844 return self.ProcessDockResult(target, drop)
3845
3846 return False, target
3847
3848
3849 def UseTransparentHint(self):
3850 return (self._flags & AUI_MGR_TRANSPARENT_HINT) and self.CanMakeWindowsTransparent()
3851
3852 def OnHintFadeTimer(self, event):
3853 #sanity check
3854 if not self.UseTransparentHint():
3855 return
3856
3857 if not self._hint_wnd or self._hint_fadeamt >= 50:
3858 self._hint_fadetimer.Stop()
3859 return
3860
3861 self._hint_fadeamt = self._hint_fadeamt + 5
3862 self.MakeWindowTransparent(self._hint_wnd, self._hint_fadeamt)
3863
3864
3865 def ShowHint(self, rect):
3866 self._hintshown = True
3867 if self.UseTransparentHint():
3868 if wx.Platform == "__WXMSW__":
3869 if self._last_hint == rect:
3870 return
3871 self._last_hint = rect
3872
3873 initial_fade = 50
3874
3875 if self._flags & AUI_MGR_TRANSPARENT_HINT_FADE:
3876 initial_fade = 0
3877
3878 if self._hint_wnd == None:
3879
3880 pt = rect.GetPosition()
3881 size = rect.GetSize()
3882 self._hint_wnd = wx.Frame(self._frame, -1, "", pt, size,
3883 wx.FRAME_TOOL_WINDOW |
3884 wx.FRAME_FLOAT_ON_PARENT |
3885 wx.FRAME_NO_TASKBAR |
3886 wx.NO_BORDER)
3887
3888 self.MakeWindowTransparent(self._hint_wnd, initial_fade)
3889 self._hint_wnd.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION))
3890 self._hint_wnd.Show()
3891
3892 # if we are dragging a floating pane, set the focus
3893
3894 # back to that floating pane (otherwise it becomes unfocused)
3895
3896 if self._action == actionDragAuiFloatingPane and self._action_window:
3897 self._action_window.SetFocus()
3898
3899 else:
3900
3901 pt = rect.GetPosition()
3902 size = rect.GetSize()
3903 self.MakeWindowTransparent(self._hint_wnd, initial_fade)
3904 self._hint_wnd.SetDimensions(pt.x, pt.y, rect.width, rect.height)
3905
3906 if self._flags & AUI_MGR_TRANSPARENT_HINT_FADE:
3907 # start fade in timer
3908 self._hint_fadeamt = 0
3909 self._hint_fadetimer.SetOwner(self, 101)
3910 self._hint_fadetimer.Start(5)
3911 return
3912 elif wx.Platform == "__WXMAC__":
3913 if self._last_hint == rect:
3914 return #same rect, already shown, no-op
3915 if self._flags & AUI_MGR_TRANSPARENT_HINT_FADE:
3916 initial_fade = 0
3917 else:
3918 initial_fade = 80
3919
3920 if not self._hint_wnd:
3921 self._hint_wnd = wx.MiniFrame(self._frame,
3922 style=wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_TOOL_WINDOW
3923 |wx.CAPTION#|wx.FRAME_SHAPED
3924 #without wxCAPTION + wx.FRAME_TOOL_WINDOW, the hint window
3925 #gets focus & dims the main frames toolbar, which is both wrong
3926 #and distracting.
3927 #wx.CAPTION + wx.FRAME_TOOL_WINDOW cures the focus problem,
3928 #but then it draws the caption. Adding wx.FRAME_SHAPED takes
3929 #care of that, but then SetRect doesn't work to size - need to
3930 #create a bitmap or mask or something.
3931 )
3932 #can't set the background of a wx.Frame in OSX
3933 p = wx.Panel(self._hint_wnd)
3934
3935 #the caption color is a light silver thats really hard to see
3936 #especially transparent. See if theres some other system
3937 #setting that is more appropriate, or just extend the art provider
3938 #to cover this
3939 #p.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION))
3940 p.SetBackgroundColour(wx.BLUE)
3941
3942 self.MakeWindowTransparent(self._hint_wnd, initial_fade)
3943 self._hint_wnd.SetRect(rect)
3944 self._hint_wnd.Show()
3945
3946 if self._action == actionDragAuiFloatingPane and self._action_window:
3947 self._action_window.SetFocus()
3948
3949 if self._flags & AUI_MGR_TRANSPARENT_HINT_FADE:
3950 # start fade in timer
3951 self._hint_fadeamt = 0
3952 self._hint_fadetimer.SetOwner(self, 101)
3953 self._hint_fadetimer.Start(5)
3954 return
3955
3956
3957 if self._last_hint != rect:
3958 # remove the last hint rectangle
3959 self._last_hint = rect
3960 self._frame.Refresh()
3961 self._frame.Update()
3962
3963
3964
3965 screendc = wx.ScreenDC()
3966 clip = wx.Region(1, 1, 10000, 10000)
3967
3968 # clip all floating windows, so we don't draw over them
3969 for pane in self._panes:
3970 if pane.IsFloating() and pane.frame.IsShown():
3971 recta = pane.frame.GetRect()
3972 if wx.Platform == "__WXGTK__":
3973 # wxGTK returns the client size, not the whole frame size
3974 width, height = pane.frame.ClientToScreen((0,0)) - pane.frame.GetPosition()
3975 recta.width = recta.width + width
3976 recta.height = recta.height + height
3977 recta.Inflate(5, 5)
3978 #endif
3979
3980 clip.SubtractRect(recta)
3981
3982 screendc.SetClippingRegionAsRegion(clip)
3983
3984 screendc.SetBrush(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)))
3985 screendc.SetPen(wx.TRANSPARENT_PEN)
3986
3987 screendc.DrawRectangle(rect.x, rect.y, 5, rect.height)
3988 screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5)
3989 screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height)
3990 screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5)
3991
3992
3993 def HideHint(self):
3994
3995 self._hintshown = False
3996
3997 # hides a transparent window hint (currently wxMSW only)
3998 if self.UseTransparentHint():
3999 if self._hint_wnd:
4000 self._hint_fadetimer.Stop()
4001 #self._hint_wnd.Destroy()
4002 self.MakeWindowTransparent(self._hint_wnd, 0)
4003 self._last_hint = wx.Rect()
4004
4005 return
4006
4007 # hides a painted hint by redrawing the frame window
4008 if not self._last_hint.IsEmpty():
4009 self._frame.Refresh()
4010 self._frame.Update()
4011 self._last_hint = wx.Rect()
4012
4013
4014 def DrawHintRect(self, pane_window, pt, offset):
4015 """
4016 DrawHintRect() draws a drop hint rectangle. First calls DoDrop() to
4017 determine the exact position the pane would be at were if dropped. If
4018 the pame would indeed become docked at the specified drop point,
4019 DrawHintRect() then calls ShowHint() to indicate this drop rectangle.
4020 "pane_window" is the window pointer of the pane being dragged, pt is
4021 the mouse position, in client coordinates.
4022 """
4023
4024 # we need to paint a hint rectangle to find out the exact hint rectangle,
4025 # we will create a new temporary layout and then measure the resulting
4026 # rectangle we will create a copy of the docking structures (self._docks)
4027 # so that we don't modify the real thing on screen
4028
4029 rect = wx.Rect()
4030 pane = self.GetPane(pane_window)
4031
4032 attrs = self.GetAttributes(pane)
4033 hint = AuiPaneInfo()
4034 hint = self.SetAttributes(hint, attrs)
4035
4036 if hint.name != "__HINT__":
4037 self._oldname = hint.name
4038
4039 hint.name = "__HINT__"
4040
4041 if not hint.IsOk():
4042 hint.name = self._oldname
4043 return
4044
4045 docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
4046
4047 # remove any pane already there which bears the same window
4048 # this happens when you are moving a pane around in a dock
4049 for ii in xrange(len(panes)):
4050 if panes[ii].window == pane_window:
4051 docks = RemovePaneFromDocks(docks, panes[ii])
4052 panes.pop(ii)
4053 break
4054
4055 # find out where the new pane would be
4056 allow, hint = self.DoDrop(docks, panes, hint, pt, offset)
4057
4058 if not allow:
4059 self.HideHint()
4060 return
4061
4062 panes.append(hint)
4063
4064 sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
4065 client_size = self._frame.GetClientSize()
4066 sizer.SetDimension(0, 0, client_size.x, client_size.y)
4067 sizer.Layout()
4068
4069 for ii in xrange(len(uiparts)):
4070 part = uiparts[ii]
4071 if part.type == DockUIPart.typePaneBorder and \
4072 part.pane and part.pane.name == "__HINT__":
4073 pos = part.sizer_item.GetPosition()
4074 size = part.sizer_item.GetSize()
4075 rect = wx.Rect(pos[0], pos[1], size[0], size[1])
4076 break
4077
4078 sizer.Destroy()
4079
4080 if rect.IsEmpty():
4081 self.HideHint()
4082 return
4083
4084 # actually show the hint rectangle on the screen
4085 rect.x, rect.y = self._frame.ClientToScreen((rect.x, rect.y))
4086 self.ShowHint(rect)
4087
4088
4089 def GetAttributes(self, pane):
4090
4091 attrs = []
4092 attrs.extend([pane.window, pane.frame, pane.state, pane.dock_direction,
4093 pane.dock_layer, pane.dock_pos, pane.dock_row, pane.dock_proportion,
4094 pane.floating_pos, pane.floating_size, pane.best_size,
4095 pane.min_size, pane.max_size, pane.caption, pane.name,
4096 pane.buttons, pane.rect])
4097
4098 return attrs
4099
4100
4101 def SetAttributes(self, pane, attrs):
4102
4103 pane.window = attrs[0]
4104 pane.frame = attrs[1]
4105 pane.state = attrs[2]
4106 pane.dock_direction = attrs[3]
4107 pane.dock_layer = attrs[4]
4108 pane.dock_pos = attrs[5]
4109 pane.dock_row = attrs[6]
4110 pane.dock_proportion = attrs[7]
4111 pane.floating_pos = attrs[8]
4112 pane.floating_size = attrs[9]
4113 pane.best_size = attrs[10]
4114 pane.min_size = attrs[11]
4115 pane.max_size = attrs[12]
4116 pane.caption = attrs[13]
4117 pane.name = attrs[14]
4118 pane.buttons = attrs[15]
4119 pane.rect = attrs[16]
4120
4121 return pane
4122
4123 def UseTransparentDrag(self):
4124
4125 if self._flags & AUI_MGR_TRANSPARENT_DRAG:
4126 return self.CanMakeWindowsTransparent()
4127 else:
4128 return False
4129
4130
4131 def OnAuiFloatingPaneMoveStart(self, wnd):
4132
4133 # try to find the pane
4134 pane = self.GetPane(wnd)
4135 if not pane.IsOk():
4136 raise "\nERROR: Pane Window Not Found"
4137 if self.UseTransparentDrag() and pane.IsDockable():
4138 self.MakeWindowTransparent(pane.frame, 150)
4139
4140
4141 def OnAuiFloatingPaneMoving(self, wnd):
4142
4143 # try to find the pane
4144 pane = self.GetPane(wnd)
4145
4146 if not pane.IsOk():
4147 raise "\nERROR: Pane Window Not Found"
4148
4149 pt = wx.GetMousePosition()
4150 client_pt = self._frame.ScreenToClient(pt)
4151
4152 # calculate the offset from the upper left-hand corner
4153 # of the frame to the mouse pointer
4154 frame_pos = pane.frame.GetPosition()
4155 action_offset = wx.Point(pt[0]-frame_pos.x, pt[1]-frame_pos.y)
4156
4157 ## # no hint for toolbar floating windows
4158 ## if pane.IsToolbar() and self._action == actionDragAuiFloatingPane:
4159 ##
4160 ## oldname = pane.name
4161 ## indx = self._panes.index(pane)
4162 ## hint = pane
4163 ## docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
4164 ##
4165 ## # find out where the new pane would be
4166 ## ret, hint = self.DoDrop(docks, panes, hint, client_pt)
4167 ##
4168 ## if not ret:
4169 ## return
4170 ##
4171 ## if hint.IsFloating():
4172 ## return
4173 ##
4174 ## pane = hint
4175 ## pane.name = oldname
4176 ##
4177 ## self._panes[indx] = pane
4178 ## self._action = actionDragToolbarPane
4179 ## self._action_window = pane.window
4180 ##
4181 ## self.Update()
4182 ##
4183 ## return
4184
4185 # if a key modifier is pressed while dragging the frame,
4186 # don't dock the window
4187 if wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT):
4188 self.HideHint()
4189 return
4190
4191 if pane.IsDockable():
4192 self.DrawHintRect(wnd, client_pt, action_offset)
4193
4194 # reduces flicker
4195 self._frame.Update()
4196
4197
4198 def OnAuiFloatingPaneMoved(self, wnd):
4199
4200 # try to find the pane
4201 pane = self.GetPane(wnd)
4202
4203 if not pane.IsOk():
4204 raise "\nERROR: Pane Window Not Found"
4205
4206 pt = wx.GetMousePosition()
4207 client_pt = self._frame.ScreenToClient(pt)
4208
4209 indx = self._panes.index(pane)
4210
4211 # calculate the offset from the upper left-hand corner
4212 # of the frame to the mouse pointer
4213 frame_pos = pane.frame.GetPosition()
4214 action_offset = wx.Point(pt[0]-frame_pos.x, pt[1]-frame_pos.y)
4215
4216 # if a key modifier is pressed while dragging the frame,
4217 # don't dock the window
4218 if wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT):
4219 self.HideHint()
4220 return
4221
4222 if not pane.IsToolbar() and pane.IsDockable() and not self._hintshown:
4223 if not pane.IsFloating():
4224 pane.Float()
4225 pane.floating_pos = pane.frame.GetPosition()
4226 self._panes[indx] = pane
4227 if self.UseTransparentDrag():
4228 self.MakeWindowTransparent(pane.frame, 255)
4229
4230 # do the drop calculation
4231 allow, pane = self.DoDrop(self._docks, self._panes, pane, client_pt, action_offset)
4232
4233 # if the pane is still floating, update it's floating
4234 # position (that we store)
4235 if pane.IsFloating():
4236 pane.floating_pos = pane.frame.GetPosition()
4237 if self.UseTransparentDrag():
4238 self.MakeWindowTransparent(pane.frame, 255)
4239
4240 if not pane.IsToolbar() and pane.IsDockable():
4241 pane.name = self._oldname
4242
4243 self._panes[indx] = pane
4244
4245 self.Update()
4246 self.HideHint()
4247
4248
4249 def OnAuiFloatingPaneResized(self, wnd, size):
4250
4251 # try to find the pane
4252 pane = self.GetPane(wnd)
4253 if not pane.IsOk():
4254 raise "\nERROR: Pane Window Not Found"
4255
4256 indx = self._panes.index(pane)
4257 pane.floating_size = size
4258 self._panes[indx] = pane
4259
4260
4261 def OnAuiFloatingPaneClosed(self, wnd, event):
4262 # try to find the pane
4263 pane = self.GetPane(wnd)
4264 if not pane.IsOk():
4265 raise "\nERROR: Pane Window Not Found"
4266
4267 e = AuiManagerEvent(wxEVT_AUI_PANECLOSE)
4268 e.SetPane(pane)
4269 self.ProcessMgrEvent(e)
4270
4271 if e.GetSkipped():
4272 indx = self._panes.index(pane)
4273 # reparent the pane window back to us and
4274 # prepare the frame window for destruction
4275 pane.window.Show(False)
4276 pane.window.Reparent(self._frame)
4277 pane.frame = None
4278 pane.Hide()
4279
4280 self._panes[indx] = pane
4281 event.Skip()
4282
4283
4284
4285 def OnAuiFloatingPaneActivated(self, wnd):
4286
4287 if self.GetFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
4288 # try to find the pane
4289 pane = self.GetPane(wnd)
4290 if not pane.IsOk():
4291 raise "\nERROR: Pane Window Not Found"
4292
4293 self._panes = SetActivePane(self._panes, wnd)
4294 self.Repaint()
4295
4296
4297 def Render(self, dc):
4298 """
4299 Render() draws all of the pane captions, sashes,
4300 backgrounds, captions, grippers, pane borders and buttons.
4301 It renders the entire user interface.
4302 """
4303
4304 for part in self._uiparts:
4305
4306 # don't draw hidden pane items
4307 if part.sizer_item and not part.sizer_item.IsShown():
4308 continue
4309
4310 if part.type == DockUIPart.typeDockSizer or \
4311 part.type == DockUIPart.typePaneSizer:
4312 self._art.DrawSash(dc, part.orientation, part.rect)
4313 elif part.type == DockUIPart.typeBackground:
4314 self._art.DrawBackground(dc, part.orientation, part.rect)
4315 elif part.type == DockUIPart.typeCaption:
4316 self._art.DrawCaption(dc, part.pane.caption, part.rect, part.pane)
4317 elif part.type == DockUIPart.typeGripper:
4318 self._art.DrawGripper(dc, part.rect, part.pane)
4319 elif part.type == DockUIPart.typePaneBorder:
4320 self._art.DrawBorder(dc, part.rect, part.pane)
4321 elif part.type == DockUIPart.typePaneButton:
4322 self._art.DrawPaneButton(dc, part.button.button_id,
4323 AUI_BUTTON_STATE_NORMAL, part.rect, part.pane)
4324
4325
4326 def Repaint(self, dc=None):
4327
4328 w, h = self._frame.GetClientSize()
4329 # figure out which dc to use if one
4330 # has been specified, use it, otherwise
4331 # make a client dc
4332 client_dc = None
4333
4334 if not dc:
4335 client_dc = wx.ClientDC(self._frame)
4336 dc = client_dc
4337
4338 # if the frame has a toolbar, the client area
4339 # origin will not be (0,0).
4340 pt = self._frame.GetClientAreaOrigin()
4341 if pt.x != 0 or pt.y != 0:
4342 dc.SetDeviceOrigin(pt.x, pt.y)
4343
4344 # render all the items
4345 self.Render(dc)
4346
4347 # if we created a client_dc, delete it
4348 if client_dc:
4349 del client_dc
4350
4351
4352 def OnPaint(self, event):
4353
4354 dc = wx.PaintDC(self._frame)
4355
4356 if wx.Platform == "__WXMAC__":
4357 #Macs paint optimizations clip the area we need to paint a log
4358 #of the time, this is a dirty hack to always paint everything
4359 self.Repaint(None)
4360 else:
4361 self.Repaint(dc)
4362
4363
4364 def OnEraseBackground(self, event):
4365
4366 if wx.Platform == "__WXMAC__":
4367 event.Skip()
4368
4369
4370 def OnSize(self, event):
4371
4372 if self._frame:
4373
4374 self.DoFrameLayout()
4375 wx.CallAfter(self.Repaint)
4376
4377 if not isinstance(self._frame, wx.MDIParentFrame):
4378 event.Skip()
4379
4380
4381 def OnSetCursor(self, event):
4382
4383 # determine cursor
4384 part = self.HitTest(event.GetX(), event.GetY())
4385 cursor = None
4386
4387 if part:
4388 if part.type == DockUIPart.typeDockSizer or \
4389 part.type == DockUIPart.typePaneSizer:
4390
4391 # a dock may not be resized if it has a single
4392 # pane which is not resizable
4393 if part.type == DockUIPart.typeDockSizer and part.dock and \
4394 len(part.dock.panes) == 1 and part.dock.panes[0].IsFixed():
4395 return
4396
4397 # panes that may not be resized do not get a sizing cursor
4398 if part.pane and part.pane.IsFixed():
4399 return
4400
4401 if part.orientation == wx.VERTICAL:
4402 cursor = wx.StockCursor(wx.CURSOR_SIZEWE)
4403 else:
4404 cursor = wx.StockCursor(wx.CURSOR_SIZENS)
4405
4406 elif part.type == DockUIPart.typeGripper:
4407 cursor = wx.StockCursor(wx.CURSOR_SIZING)
4408
4409 if cursor is not None:
4410 event.SetCursor(cursor)
4411
4412
4413 def UpdateButtonOnScreen(self, button_ui_part, event):
4414
4415 hit_test = self.HitTest(event.GetX(), event.GetY())
4416 state = AUI_BUTTON_STATE_NORMAL
4417
4418 if hit_test == button_ui_part:
4419 if event.LeftDown():
4420 state = AUI_BUTTON_STATE_PRESSED
4421 else:
4422 state = AUI_BUTTON_STATE_HOVER
4423 else:
4424 if event.LeftDown():
4425 state = AUI_BUTTON_STATE_HOVER
4426
4427 # now repaint the button with hover state
4428 cdc = wx.ClientDC(self._frame)
4429
4430 # if the frame has a toolbar, the client area
4431 # origin will not be (0,0).
4432 pt = self._frame.GetClientAreaOrigin()
4433 if pt.x != 0 or pt.y != 0:
4434 cdc.SetDeviceOrigin(pt.x, pt.y)
4435
4436 self._art.DrawPaneButton(cdc,
4437 button_ui_part.button.button_id,
4438 state,
4439 button_ui_part.rect, hit_test.pane)
4440
4441
4442 def OnLeftDown(self, event):
4443
4444 part = self.HitTest(event.GetX(), event.GetY())
4445
4446 if part:
4447 if part.dock and part.dock.dock_direction == AUI_DOCK_CENTER:
4448 return
4449
4450 if part.type == DockUIPart.typeDockSizer or \
4451 part.type == DockUIPart.typePaneSizer:
4452
4453 # a dock may not be resized if it has a single
4454 # pane which is not resizable
4455 if part.type == DockUIPart.typeDockSizer and part.dock and \
4456 len(part.dock.panes) == 1 and part.dock.panes[0].IsFixed():
4457 return
4458
4459 # panes that may not be resized should be ignored here
4460 if part.pane and part.pane.IsFixed():
4461 return
4462
4463 self._action = actionResize
4464 self._action_part = part
4465 self._action_hintrect = wx.Rect()
4466 self._action_start = wx.Point(event.GetX(), event.GetY())
4467 self._action_offset = wx.Point(event.GetX() - part.rect.x,
4468 event.GetY() - part.rect.y)
4469 self._frame.CaptureMouse()
4470
4471 elif part.type == DockUIPart.typePaneButton:
4472
4473 self._action = actionClickButton
4474 self._action_part = part
4475 self._action_start = wx.Point(event.GetX(), event.GetY())
4476 self._frame.CaptureMouse()
4477
4478 self.UpdateButtonOnScreen(part, event)
4479
4480 elif part.type == DockUIPart.typeCaption or \
4481 part.type == DockUIPart.typeGripper:
4482
4483 if self.GetFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
4484 # set the caption as active
4485 self._panes = SetActivePane(self._panes, part.pane.window)
4486 self.Repaint()
4487
4488 self._action = actionClickCaption
4489 self._action_part = part
4490 self._action_start = wx.Point(event.GetX(), event.GetY())
4491 self._action_offset = wx.Point(event.GetX() - part.rect.x,
4492 event.GetY() - part.rect.y)
4493 self._frame.CaptureMouse()
4494
4495 if wx.Platform != "__WXMAC__":
4496 event.Skip()
4497
4498
4499 def OnLeftUp(self, event):
4500
4501 if self._action == actionResize:
4502
4503 self._frame.ReleaseMouse()
4504
4505 # get rid of the hint rectangle
4506 dc = wx.ScreenDC()
4507 DrawResizeHint(dc, self._action_hintrect)
4508
4509 # resize the dock or the pane
4510 if self._action_part and self._action_part.type == DockUIPart.typeDockSizer:
4511 rect = self._action_part.dock.rect
4512 new_pos = wx.Point(event.GetX() - self._action_offset.x,
4513 event.GetY() - self._action_offset.y)
4514
4515 if self._action_part.dock.dock_direction == AUI_DOCK_LEFT:
4516 self._action_part.dock.size = new_pos.x - rect.x
4517 elif self._action_part.dock.dock_direction == AUI_DOCK_TOP:
4518 self._action_part.dock.size = new_pos.y - rect.y
4519 elif self._action_part.dock.dock_direction == AUI_DOCK_RIGHT:
4520 self._action_part.dock.size = rect.x + rect.width - \
4521 new_pos.x - \
4522 self._action_part.rect.GetWidth()
4523 elif self._action_part.dock.dock_direction == AUI_DOCK_BOTTOM:
4524 self._action_part.dock.size = rect.y + rect.height - \
4525 new_pos.y - \
4526 self._action_part.rect.GetHeight()
4527
4528 self.Update()
4529 self.Repaint(None)
4530
4531 elif self._action_part and \
4532 self._action_part.type == DockUIPart.typePaneSizer:
4533
4534 dock = self._action_part.dock
4535 pane = self._action_part.pane
4536
4537 total_proportion = 0
4538 dock_pixels = 0
4539 new_pixsize = 0
4540
4541 caption_size = self._art.GetMetric(AUI_ART_CAPTION_SIZE)
4542 pane_border_size = self._art.GetMetric(AUI_ART_PANE_BORDER_SIZE)
4543 sash_size = self._art.GetMetric(AUI_ART_SASH_SIZE)
4544
4545 new_pos = wx.Point(event.GetX() - self._action_offset.x,
4546 event.GetY() - self._action_offset.y)
4547
4548 # determine the pane rectangle by getting the pane part
4549 pane_part = self.GetPanePart(pane.window)
4550 if not pane_part:
4551 raise "\nERROR: Pane border part not found -- shouldn't happen"
4552
4553 # determine the new pixel size that the user wants
4554 # this will help us recalculate the pane's proportion
4555 if dock.IsHorizontal():
4556 new_pixsize = new_pos.x - pane_part.rect.x
4557 else:
4558 new_pixsize = new_pos.y - pane_part.rect.y
4559
4560 # determine the size of the dock, based on orientation
4561 if dock.IsHorizontal():
4562 dock_pixels = dock.rect.GetWidth()
4563 else:
4564 dock_pixels = dock.rect.GetHeight()
4565
4566 # determine the total proportion of all resizable panes,
4567 # and the total size of the dock minus the size of all
4568 # the fixed panes
4569 dock_pane_count = len(dock.panes)
4570 pane_position = -1
4571
4572 for ii in xrange(dock_pane_count):
4573 p = dock.panes[ii]
4574 if p.window == pane.window:
4575 pane_position = ii
4576
4577 # while we're at it, subtract the pane sash
4578 # width from the dock width, because this would
4579 # skew our proportion calculations
4580 if ii > 0:
4581 dock_pixels = dock_pixels - sash_size
4582
4583 # also, the whole size (including decorations) of
4584 # all fixed panes must also be subtracted, because they
4585 # are not part of the proportion calculation
4586 if p.IsFixed():
4587 if dock.IsHorizontal():
4588 dock_pixels = dock_pixels - p.best_size.x
4589 else:
4590 dock_pixels = dock_pixels - p.best_size.y
4591 else:
4592 total_proportion = total_proportion + p.dock_proportion
4593
4594 # find a pane in our dock to 'steal' space from or to 'give'
4595 # space to -- this is essentially what is done when a pane is
4596 # resized the pane should usually be the first non-fixed pane
4597 # to the right of the action pane
4598 borrow_pane = -1
4599
4600 for ii in xrange(pane_position+1, dock_pane_count):
4601 p = dock.panes[ii]
4602 if not p.IsFixed():
4603 borrow_pane = ii
4604 break
4605
4606 # demand that the pane being resized is found in this dock
4607 # (this assert really never should be raised)
4608 if pane_position == -1:
4609 raise "\nERROR: Pane not found in dock"
4610
4611 # prevent division by zero
4612 if dock_pixels == 0 or total_proportion == 0 or borrow_pane == -1:
4613 self._action = actionNone
4614 return
4615
4616 # calculate the new proportion of the pane
4617 new_proportion = new_pixsize*total_proportion/dock_pixels
4618
4619 # default minimum size
4620 min_size = 0
4621
4622 # check against the pane's minimum size, if specified. please note
4623 # that this is not enough to ensure that the minimum size will
4624 # not be violated, because the whole frame might later be shrunk,
4625 # causing the size of the pane to violate it's minimum size
4626 if pane.min_size.IsFullySpecified():
4627 min_size = 0
4628 if pane.HasBorder():
4629 min_size = min_size + pane_border_size*2
4630
4631 # calculate minimum size with decorations (border,caption)
4632 if pane_part.orientation == wx.VERTICAL:
4633 min_size = min_size + pane.min_size.y
4634 if pane.HasCaption():
4635 min_size = min_size + caption_size
4636 else:
4637 min_size = min_size + pane.min_size.x
4638
4639 # for some reason, an arithmatic error somewhere is causing
4640 # the proportion calculations to always be off by 1 pixel
4641 # for now we will add the 1 pixel on, but we really should
4642 # determine what's causing this.
4643 min_size = min_size + 1
4644
4645 min_proportion = min_size*total_proportion/dock_pixels
4646
4647 if new_proportion < min_proportion:
4648 new_proportion = min_proportion
4649
4650 prop_diff = new_proportion - pane.dock_proportion
4651
4652 # borrow the space from our neighbor pane to the
4653 # right or bottom (depending on orientation)
4654 dock.panes[borrow_pane].dock_proportion -= prop_diff
4655 pane.dock_proportion = new_proportion
4656
4657 indxd = self._docks.index(dock)
4658 indxp = self._panes.index(pane)
4659
4660 self._docks[indxd] = dock
4661 self._panes[indxp] = pane
4662
4663 # repaint
4664 self.Update()
4665 self.Repaint(None)
4666
4667 elif self._action == actionClickButton:
4668
4669 self._hover_button = None
4670 self._frame.ReleaseMouse()
4671 self.UpdateButtonOnScreen(self._action_part, event)
4672
4673 # make sure we're still over the item that was originally clicked
4674 if self._action_part == self.HitTest(event.GetX(), event.GetY()):
4675 # fire button-click event
4676 e = AuiManagerEvent(wxEVT_AUI_PANEBUTTON)
4677 e.SetPane(self._action_part.pane)
4678 e.SetButton(self._action_part.button.button_id)
4679 self.ProcessMgrEvent(e)
4680
4681 elif self._action == actionClickCaption:
4682
4683 self._frame.ReleaseMouse()
4684
4685 elif self._action == actionDragAuiFloatingPane:
4686
4687 self._frame.ReleaseMouse()
4688
4689 elif self._action == actionDragToolbarPane:
4690
4691 self._frame.ReleaseMouse()
4692
4693 pane = self.GetPane(self._action_window)
4694 if not pane.IsOk():
4695 raise "\nERROR: Pane Window Not Found"
4696
4697 # save the new positions
4698 docks = FindDocks(self._docks, pane.dock_direction,
4699 pane.dock_layer, pane.dock_row)
4700
4701 if len(docks) == 1:
4702 dock = docks[0]
4703 pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
4704
4705 dock_pane_count = len(dock.panes)
4706 for ii in xrange(dock_pane_count):
4707 dock.panes[ii].dock_pos = pane_positions[ii]
4708
4709 pane.state &= ~AuiPaneInfo.actionPane
4710 indx = self._panes.index(pane)
4711 self._panes[indx] = pane
4712
4713 self.Update()
4714
4715 else:
4716
4717 event.Skip()
4718
4719 self._action = actionNone
4720 self._last_mouse_move = wx.Point() # see comment in OnMotion()
4721
4722
4723 def OnMotion(self, event):
4724
4725 # sometimes when Update() is called from inside this method,
4726 # a spurious mouse move event is generated this check will make
4727 # sure that only real mouse moves will get anywhere in this method
4728 # this appears to be a bug somewhere, and I don't know where the
4729 # mouse move event is being generated. only verified on MSW
4730
4731 mouse_pos = event.GetPosition()
4732 if self._last_mouse_move == mouse_pos:
4733 return
4734
4735 self._last_mouse_move = mouse_pos
4736
4737 if self._action == actionResize:
4738 pos = self._action_part.rect.GetPosition()
4739 if self._action_part.orientation == wx.HORIZONTAL:
4740 pos.y = max(0, mouse_pos.y - self._action_offset.y)
4741 pos.y = min(pos.y, self._frame.GetClientSize().y - self._action_part.rect.GetSize().y)
4742 else:
4743 pos.x = max(0, mouse_pos.x - self._action_offset.x)
4744 pos.x = min(pos.x, self._frame.GetClientSize().x - self._action_part.rect.GetSize().x)
4745
4746 mypos = self._frame.ClientToScreen(pos)
4747 mysize = self._action_part.rect.GetSize()
4748 rect = wx.Rect(mypos[0], mypos[1], mysize[0], mysize[1])
4749
4750 # is it the same as the old rectangle?
4751 if self._action_hintrect == rect:
4752 # heck, yes, no need to draw again, it will only bring about flicker
4753 event.Skip()
4754 return
4755
4756 # otherwise draw the hint
4757
4758 dc = wx.ScreenDC()
4759
4760 if not self._action_hintrect.IsEmpty() and self._action_hintrect != rect:
4761 DrawResizeHint(dc, self._action_hintrect)
4762
4763 DrawResizeHint(dc, rect)
4764 self._action_hintrect = rect
4765
4766 elif self._action == actionClickCaption:
4767
4768 drag_x_threshold = wx.SystemSettings_GetMetric(wx.SYS_DRAG_X)
4769 drag_y_threshold = wx.SystemSettings_GetMetric(wx.SYS_DRAG_Y)
4770
4771 # caption has been clicked. we need to check if the mouse
4772 # is now being dragged. if it is, we need to change the
4773 # mouse action to 'drag'
4774 if abs(mouse_pos.x - self._action_start.x) > drag_x_threshold or \
4775 abs(mouse_pos.y - self._action_start.y) > drag_y_threshold:
4776
4777 pane_info = self._action_part.pane
4778 indx = self._panes.index(pane_info)
4779
4780 if not pane_info.IsToolbar():
4781
4782 if self._flags & AUI_MGR_ALLOW_FLOATING and \
4783 pane_info.IsFloatable():
4784
4785 self._action = actionDragAuiFloatingPane
4786
4787 # set initial float position
4788 pt = self._frame.ClientToScreen(event.GetPosition())
4789 pane_info.floating_pos = wx.Point(pt.x - self._action_offset.x,
4790 pt.y - self._action_offset.y)
4791 # float the window
4792 pane_info.Float()
4793 self._panes[indx] = pane_info
4794
4795 self.Update()
4796
4797 self._action_window = pane_info.frame
4798
4799 # action offset is used here to make it feel "natural" to the user
4800 # to drag a docked pane and suddenly have it become a floating frame.
4801 # Sometimes, however, the offset where the user clicked on the docked
4802 # caption is bigger than the width of the floating frame itself, so
4803 # in that case we need to set the action offset to a sensible value
4804 frame_size = self._action_window.GetSize()
4805 if frame_size.x <= self._action_offset.x:
4806 self._action_offset.x = 30
4807
4808 else:
4809
4810 self._action = actionDragToolbarPane
4811 self._action_window = pane_info.window
4812
4813 elif self._action == actionDragAuiFloatingPane:
4814
4815 pt = self._frame.ClientToScreen(event.GetPosition())
4816 if self._action_window:
4817 self._action_window.Move((pt.x - self._action_offset.x,
4818 pt.y - self._action_offset.y))
4819
4820 elif self._action == actionDragToolbarPane:
4821
4822 pane = self.GetPane(self._action_window)
4823 if not pane.IsOk():
4824 raise "\nERROR: Pane Window Not Found"
4825
4826 indx = self._panes.index(pane)
4827 pane.state |= AuiPaneInfo.actionPane
4828
4829 pt = event.GetPosition()
4830 ret, pane = self.DoDrop(self._docks, self._panes, pane, pt, self._action_offset)
4831
4832 if not ret:
4833 return
4834
4835 # if DoDrop() decided to float the pane, set up
4836 # the floating pane's initial position
4837 if pane.IsFloating():
4838
4839 pt = self._frame.ClientToScreen(event.GetPosition())
4840 pane.floating_pos = wx.Point(pt.x - self._action_offset.x,
4841 pt.y - self._action_offset.y)
4842
4843 self._panes[indx] = pane
4844
4845 # this will do the actiual move operation
4846 # in the case that the pane has been floated,
4847 # this call will create the floating pane
4848 # and do the reparenting
4849 self.Update()
4850
4851 # if the pane has been floated, change the mouse
4852 # action actionDragAuiFloatingPane so that subsequent
4853 # EVT_MOTION() events will move the floating pane
4854 if pane.IsFloating():
4855
4856 pane.state &= ~AuiPaneInfo.actionPane
4857 self._action = actionDragAuiFloatingPane
4858 self._action_window = pane.frame
4859
4860 self._panes[indx] = pane
4861
4862 else:
4863
4864 part = self.HitTest(event.GetX(), event.GetY())
4865 if part and part.type == DockUIPart.typePaneButton:
4866 if part != self._hover_button:
4867 # make the old button normal
4868 if self._hover_button:
4869 self.UpdateButtonOnScreen(self._hover_button, event)
4870
4871 # mouse is over a button, so repaint the
4872 # button in hover mode
4873 self.UpdateButtonOnScreen(part, event)
4874 self._hover_button = part
4875 else:
4876 if self._hover_button:
4877
4878 self._hover_button = None
4879 self.Repaint()
4880
4881 else:
4882
4883 event.Skip()
4884
4885
4886 def OnLeaveWindow(self, event):
4887
4888 if self._hover_button:
4889 self._hover_button = None
4890 self.Repaint()
4891
4892
4893 def OnChildFocus(self, event):
4894
4895 # when a child pane has it's focus set, we should change the
4896 # pane's active state to reflect this. (this is only true if
4897 # active panes are allowed by the owner)
4898 if self.GetFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
4899 if self.GetPane(event.GetWindow()).IsOk():
4900 self._panes = SetActivePane(self._panes, event.GetWindow())
4901 self._frame.Refresh()
4902
4903 event.Skip()
4904
4905
4906 def OnPaneButton(self, event):
4907 """
4908 OnPaneButton() is an event handler that is called
4909 when a pane button has been pressed.
4910 """
4911
4912 pane = event.pane
4913 indx = self._panes.index(pane)
4914
4915 if event.button == AuiPaneInfo.buttonClose:
4916 e = AuiManagerEvent(wxEVT_AUI_PANECLOSE)
4917 e.SetPane(pane)
4918 self.ProcessMgrEvent(e)
4919
4920 if e.GetSkipped():
4921 pane.Hide()
4922 self._panes[indx] = pane
4923 self.Update()
4924
4925 elif event.button == AuiPaneInfo.buttonPin:
4926
4927 if self._flags & AUI_MGR_ALLOW_FLOATING and pane.IsFloatable():
4928 pane.Float()
4929
4930 self._panes[indx] = pane
4931 self.Update()