Mercurial > traipse_dev
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() |