~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/wx/lib/agw/aui/framemanager.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# --------------------------------------------------------------------------- #
 
2
# AUI 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: wxWidgets 2.9.4 SVN HEAD
 
11
#
 
12
#
 
13
# Python Code By:
 
14
#
 
15
# Andrea Gavana, @ 23 Dec 2005
 
16
# Latest Revision: 25 Apr 2012, 21.00 GMT
 
17
#
 
18
# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
 
19
# Write To Me At:
 
20
#
 
21
# andrea.gavana@gmail.com
 
22
# andrea.gavana@maerskoil.com
 
23
#
 
24
# Or, Obviously, To The wxPython Mailing List!!!
 
25
#
 
26
# End Of Comments
 
27
# --------------------------------------------------------------------------- #
 
28
 
 
29
"""
 
30
Description
 
31
===========
 
32
 
 
33
`framemanager.py` is the central module of the AUI class framework.
 
34
 
 
35
:class:`AuiManager` manages the panes associated with it for a particular :class:`Frame`, using
 
36
a pane's :class:`AuiPaneInfo` information to determine each pane's docking and floating
 
37
behavior. AuiManager uses wxPython' sizer mechanism to plan the layout of each frame.
 
38
It uses a replaceable dock art class to do all drawing, so all drawing is localized
 
39
in one area, and may be customized depending on an application's specific needs.
 
40
 
 
41
AuiManager works as follows: the programmer adds panes to the class, or makes
 
42
changes to existing pane properties (dock position, floating state, show state, etc...).
 
43
To apply these changes, AuiManager's :meth:`AuiManager.Update() <AuiManager.Update>` function is called. This batch
 
44
processing can be used to avoid flicker, by modifying more than one pane at a time,
 
45
and then "committing" all of the changes at once by calling `Update()`.
 
46
 
 
47
Panes can be added quite easily::
 
48
 
 
49
    text1 = wx.TextCtrl(self, -1)
 
50
    text2 = wx.TextCtrl(self, -1)
 
51
    self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
 
52
    self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
 
53
 
 
54
    self._mgr.Update()
 
55
 
 
56
 
 
57
Later on, the positions can be modified easily. The following will float an
 
58
existing pane in a tool window::
 
59
 
 
60
    self._mgr.GetPane(text1).Float()
 
61
 
 
62
 
 
63
Layers, Rows and Directions, Positions
 
64
======================================
 
65
 
 
66
Inside AUI, the docking layout is figured out by checking several pane parameters.
 
67
Four of these are important for determining where a pane will end up.
 
68
 
 
69
**Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`.
 
70
This is fairly self-explanatory. The pane will be placed in the location specified
 
71
by this variable.
 
72
 
 
73
**Position** - More than one pane can be placed inside of a "dock". Imagine two panes
 
74
being docked on the left side of a window. One pane can be placed over another.
 
75
In proportionally managed docks, the pane position indicates it's sequential position,
 
76
starting with zero. So, in our scenario with two panes docked on the left side, the
 
77
top pane in the dock would have position 0, and the second one would occupy position 1.
 
78
 
 
79
**Row** - A row can allow for two docks to be placed next to each other. One of the most
 
80
common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
 
81
the first row being in row 0, and the second in row 1. Rows can also be used on
 
82
vertically docked panes.
 
83
 
 
84
**Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
 
85
Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
 
86
known as the "content window"). Increasing layers "swallow up" all layers of a lower
 
87
value. This can look very similar to multiple rows, but is different because all panes
 
88
in a lower level yield to panes in higher levels. The best way to understand layers
 
89
is by running the AUI sample (`AUI.py`).
 
90
"""
 
91
 
 
92
__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
 
93
__date__ = "31 March 2009"
 
94
 
 
95
 
 
96
import wx
 
97
import time
 
98
import types
 
99
import warnings
 
100
 
 
101
import auibar
 
102
import auibook
 
103
import tabmdi
 
104
import dockart
 
105
import tabart
 
106
 
 
107
from aui_utilities import Clip, PaneCreateStippleBitmap, GetDockingImage, GetSlidingPoints
 
108
 
 
109
from aui_constants import *
 
110
 
 
111
# Define this as a translation function
 
112
_ = wx.GetTranslation
 
113
 
 
114
_winxptheme = False
 
115
if wx.Platform == "__WXMSW__":
 
116
    try:
 
117
        import winxptheme
 
118
        _winxptheme = True
 
119
    except ImportError:
 
120
        pass
 
121
 
 
122
# wxPython version string
 
123
_VERSION_STRING = wx.VERSION_STRING
 
124
 
 
125
# AUI Events
 
126
wxEVT_AUI_PANE_BUTTON = wx.NewEventType()
 
127
wxEVT_AUI_PANE_CLOSE = wx.NewEventType()
 
128
wxEVT_AUI_PANE_MAXIMIZE = wx.NewEventType()
 
129
wxEVT_AUI_PANE_RESTORE = wx.NewEventType()
 
130
wxEVT_AUI_RENDER = wx.NewEventType()
 
131
wxEVT_AUI_FIND_MANAGER = wx.NewEventType()
 
132
wxEVT_AUI_PANE_MINIMIZE = wx.NewEventType()
 
133
wxEVT_AUI_PANE_MIN_RESTORE = wx.NewEventType()
 
134
wxEVT_AUI_PANE_FLOATING = wx.NewEventType()
 
135
wxEVT_AUI_PANE_FLOATED = wx.NewEventType()
 
136
wxEVT_AUI_PANE_DOCKING = wx.NewEventType()
 
137
wxEVT_AUI_PANE_DOCKED = wx.NewEventType()
 
138
wxEVT_AUI_PANE_ACTIVATED = wx.NewEventType()
 
139
wxEVT_AUI_PERSPECTIVE_CHANGED = wx.NewEventType()
 
140
 
 
141
EVT_AUI_PANE_BUTTON = wx.PyEventBinder(wxEVT_AUI_PANE_BUTTON, 0)
 
142
""" Fires an event when the user left-clicks on a pane button. """
 
143
EVT_AUI_PANE_CLOSE = wx.PyEventBinder(wxEVT_AUI_PANE_CLOSE, 0)
 
144
""" A pane in `AuiManager` has been closed. """
 
145
EVT_AUI_PANE_MAXIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MAXIMIZE, 0)
 
146
""" A pane in `AuiManager` has been maximized. """
 
147
EVT_AUI_PANE_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_RESTORE, 0)
 
148
""" A pane in `AuiManager` has been restored from a maximized state. """
 
149
EVT_AUI_RENDER = wx.PyEventBinder(wxEVT_AUI_RENDER, 0)
 
150
""" Fires an event every time the AUI frame is being repainted. """
 
151
EVT_AUI_FIND_MANAGER = wx.PyEventBinder(wxEVT_AUI_FIND_MANAGER, 0)
 
152
""" Used to find which AUI manager is controlling a certain pane. """
 
153
EVT_AUI_PANE_MINIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MINIMIZE, 0)
 
154
""" A pane in `AuiManager` has been minimized. """
 
155
EVT_AUI_PANE_MIN_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_MIN_RESTORE, 0)
 
156
""" A pane in `AuiManager` has been restored from a minimized state. """
 
157
EVT_AUI_PANE_FLOATING = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATING, 0)
 
158
""" A pane in `AuiManager` is about to be floated. """
 
159
EVT_AUI_PANE_FLOATED = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATED, 0)
 
160
""" A pane in `AuiManager` has been floated. """
 
161
EVT_AUI_PANE_DOCKING = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKING, 0)
 
162
""" A pane in `AuiManager` is about to be docked. """
 
163
EVT_AUI_PANE_DOCKED = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKED, 0)
 
164
""" A pane in `AuiManager` has been docked. """
 
165
EVT_AUI_PANE_ACTIVATED = wx.PyEventBinder(wxEVT_AUI_PANE_ACTIVATED, 0)
 
166
""" A pane in `AuiManager` has been activated. """
 
167
EVT_AUI_PERSPECTIVE_CHANGED = wx.PyEventBinder(wxEVT_AUI_PERSPECTIVE_CHANGED, 0)
 
168
""" The layout in `AuiManager` has been changed. """
 
169
 
 
170
# ---------------------------------------------------------------------------- #
 
171
 
 
172
class AuiDockInfo(object):
 
173
    """ A class to store all properties of a dock. """
 
174
 
 
175
    def __init__(self):
 
176
        """
 
177
        Default class constructor.
 
178
        Used internally, do not call it in your code!
 
179
        """
 
180
 
 
181
        object.__init__(self)
 
182
 
 
183
        self.dock_direction = 0
 
184
        self.dock_layer = 0
 
185
        self.dock_row = 0
 
186
        self.size = 0
 
187
        self.min_size = 0
 
188
        self.resizable = True
 
189
        self.fixed = False
 
190
        self.toolbar = False
 
191
        self.rect = wx.Rect()
 
192
        self.panes = []
 
193
 
 
194
 
 
195
    def IsOk(self):
 
196
        """
 
197
        Returns whether a dock is valid or not.
 
198
 
 
199
        In order to be valid, a dock needs to have a non-zero `dock_direction`.
 
200
        """
 
201
 
 
202
        return self.dock_direction != 0
 
203
 
 
204
 
 
205
    def IsHorizontal(self):
 
206
        """ Returns whether the dock is horizontal or not. """
 
207
 
 
208
        return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
 
209
 
 
210
 
 
211
    def IsVertical(self):
 
212
        """ Returns whether the dock is vertical or not. """
 
213
 
 
214
        return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]
 
215
 
 
216
 
 
217
# ---------------------------------------------------------------------------- #
 
218
 
 
219
class AuiDockingGuideInfo(object):
 
220
    """ A class which holds information about VS2005 docking guide windows. """
 
221
 
 
222
    def __init__(self, other=None):
 
223
        """
 
224
        Default class constructor.
 
225
        Used internally, do not call it in your code!
 
226
 
 
227
        :param `other`: another instance of :class:`AuiDockingGuideInfo`.
 
228
        """
 
229
 
 
230
        if other:
 
231
            self.Assign(other)
 
232
        else:
 
233
            # window representing the docking target
 
234
            self.host = None
 
235
            # dock direction (top, bottom, left, right, center)
 
236
            self.dock_direction = AUI_DOCK_NONE
 
237
 
 
238
 
 
239
    def Assign(self, other):
 
240
        """
 
241
        Assigns the properties of the `other` :class:`AuiDockingGuideInfo` to `self`.
 
242
 
 
243
        :param `other`: another instance of :class:`AuiDockingGuideInfo`.
 
244
        """
 
245
 
 
246
        self.host = other.host
 
247
        self.dock_direction = other.dock_direction
 
248
 
 
249
 
 
250
    def Host(self, h):
 
251
        """
 
252
        Hosts a docking guide window.
 
253
 
 
254
        :param `h`: an instance of :class:`AuiDockingGuideWindow` or :class:`AuiDockingHintWindow`.
 
255
        """
 
256
 
 
257
        self.host = h
 
258
        return self
 
259
 
 
260
 
 
261
    def Left(self):
 
262
        """ Sets the guide window to left docking. """
 
263
 
 
264
        self.dock_direction = AUI_DOCK_LEFT
 
265
        return self
 
266
 
 
267
 
 
268
    def Right(self):
 
269
        """ Sets the guide window to right docking. """
 
270
 
 
271
        self.dock_direction = AUI_DOCK_RIGHT
 
272
        return self
 
273
 
 
274
 
 
275
    def Top(self):
 
276
        """ Sets the guide window to top docking. """
 
277
 
 
278
        self.dock_direction = AUI_DOCK_TOP
 
279
        return self
 
280
 
 
281
 
 
282
    def Bottom(self):
 
283
        """ Sets the guide window to bottom docking. """
 
284
 
 
285
        self.dock_direction = AUI_DOCK_BOTTOM
 
286
        return self
 
287
 
 
288
 
 
289
    def Center(self):
 
290
        """ Sets the guide window to center docking. """
 
291
 
 
292
        self.dock_direction = AUI_DOCK_CENTER
 
293
        return self
 
294
 
 
295
 
 
296
    def Centre(self):
 
297
        """ Sets the guide window to centre docking. """
 
298
 
 
299
        self.dock_direction = AUI_DOCK_CENTRE
 
300
        return self
 
301
 
 
302
 
 
303
# ---------------------------------------------------------------------------- #
 
304
 
 
305
class AuiDockUIPart(object):
 
306
    """ A class which holds attributes for a UI part in the interface. """
 
307
 
 
308
    typeCaption = 0
 
309
    typeGripper = 1
 
310
    typeDock = 2
 
311
    typeDockSizer = 3
 
312
    typePane = 4
 
313
    typePaneSizer = 5
 
314
    typeBackground = 6
 
315
    typePaneBorder = 7
 
316
    typePaneButton = 8
 
317
 
 
318
    def __init__(self):
 
319
        """
 
320
        Default class constructor.
 
321
        Used internally, do not call it in your code!
 
322
        """
 
323
 
 
324
        self.orientation = wx.VERTICAL
 
325
        self.type = 0
 
326
        self.rect = wx.Rect()
 
327
 
 
328
 
 
329
# ---------------------------------------------------------------------------- #
 
330
 
 
331
class AuiPaneButton(object):
 
332
    """ A simple class which describes the caption pane button attributes. """
 
333
 
 
334
    def __init__(self, button_id):
 
335
        """
 
336
        Default class constructor.
 
337
        Used internally, do not call it in your code!
 
338
 
 
339
        :param integer `button_id`: the pane button identifier.
 
340
        """
 
341
 
 
342
        self.button_id = button_id
 
343
 
 
344
 
 
345
# ---------------------------------------------------------------------------- #
 
346
 
 
347
# event declarations/classes
 
348
 
 
349
class AuiManagerEvent(wx.PyCommandEvent):
 
350
    """ A specialized command event class for events sent by :class:`AuiManager`. """
 
351
 
 
352
    def __init__(self, eventType, id=1):
 
353
        """
 
354
        Default class constructor.
 
355
 
 
356
        :param integer `eventType`: the event kind;
 
357
        :param integer `id`: the event identification number.
 
358
        """
 
359
 
 
360
        wx.PyCommandEvent.__init__(self, eventType, id)
 
361
 
 
362
        self.manager = None
 
363
        self.pane = None
 
364
        self.button = 0
 
365
        self.veto_flag = False
 
366
        self.canveto_flag = True
 
367
        self.dc = None
 
368
 
 
369
 
 
370
    def SetManager(self, mgr):
 
371
        """
 
372
        Associates a :class:`AuiManager` to the current event.
 
373
 
 
374
        :param `mgr`: an instance of :class:`AuiManager`.
 
375
        """
 
376
 
 
377
        self.manager = mgr
 
378
 
 
379
 
 
380
    def SetDC(self, pdc):
 
381
        """
 
382
        Associates a :class:`DC` device context to this event.
 
383
 
 
384
        :param `pdc`: a :class:`DC` device context object.
 
385
        """
 
386
 
 
387
        self.dc = pdc
 
388
 
 
389
 
 
390
    def SetPane(self, p):
 
391
        """
 
392
        Associates a :class:`AuiPaneInfo` instance to this event.
 
393
 
 
394
        :param `p`: a :class:`AuiPaneInfo` instance.
 
395
        """
 
396
 
 
397
        self.pane = p
 
398
 
 
399
 
 
400
    def SetButton(self, b):
 
401
        """
 
402
        Associates a :class:`AuiPaneButton` instance to this event.
 
403
 
 
404
        :param `b`: a :class:`AuiPaneButton` instance.
 
405
        """
 
406
 
 
407
        self.button = b
 
408
 
 
409
 
 
410
    def GetManager(self):
 
411
        """ Returns the associated :class:`AuiManager` (if any). """
 
412
 
 
413
        return self.manager
 
414
 
 
415
 
 
416
    def GetDC(self):
 
417
        """ Returns the associated :class:`DC` device context (if any). """
 
418
 
 
419
        return self.dc
 
420
 
 
421
 
 
422
    def GetPane(self):
 
423
        """ Returns the associated :class:`AuiPaneInfo` structure (if any). """
 
424
 
 
425
        return self.pane
 
426
 
 
427
 
 
428
    def GetButton(self):
 
429
        """ Returns the associated :class:`AuiPaneButton` instance (if any). """
 
430
 
 
431
        return self.button
 
432
 
 
433
 
 
434
    def Veto(self, veto=True):
 
435
        """
 
436
        Prevents the change announced by this event from happening.
 
437
 
 
438
        It is in general a good idea to notify the user about the reasons for
 
439
        vetoing the change because otherwise the applications behaviour (which
 
440
        just refuses to do what the user wants) might be quite surprising.
 
441
 
 
442
        :param bool `veto`: ``True`` to veto the event, ``False`` otherwise.
 
443
        """
 
444
 
 
445
        self.veto_flag = veto
 
446
 
 
447
 
 
448
    def GetVeto(self):
 
449
        """ Returns whether the event has been vetoed or not. """
 
450
 
 
451
        return self.veto_flag
 
452
 
 
453
 
 
454
    def SetCanVeto(self, can_veto):
 
455
        """
 
456
        Sets whether the event can be vetoed or not.
 
457
 
 
458
        :param bool `can_veto`: ``True`` if the event can be vetoed, ``False`` otherwise.
 
459
        """
 
460
 
 
461
        self.canveto_flag = can_veto
 
462
 
 
463
 
 
464
    def CanVeto(self):
 
465
        """ Returns whether the event can be vetoed and has been vetoed. """
 
466
 
 
467
        return  self.canveto_flag and self.veto_flag
 
468
 
 
469
 
 
470
# ---------------------------------------------------------------------------- #
 
471
 
 
472
class AuiPaneInfo(object):
 
473
    """
 
474
    AuiPaneInfo specifies all the parameters for a pane. These parameters specify where
 
475
    the pane is on the screen, whether it is docked or floating, or hidden. In addition,
 
476
    these parameters specify the pane's docked position, floating position, preferred
 
477
    size, minimum size, caption text among many other parameters.
 
478
    """
 
479
 
 
480
    optionFloating         = 2**0
 
481
    optionHidden           = 2**1
 
482
    optionLeftDockable     = 2**2
 
483
    optionRightDockable    = 2**3
 
484
    optionTopDockable      = 2**4
 
485
    optionBottomDockable   = 2**5
 
486
    optionFloatable        = 2**6
 
487
    optionMovable          = 2**7
 
488
    optionResizable        = 2**8
 
489
    optionPaneBorder       = 2**9
 
490
    optionCaption          = 2**10
 
491
    optionGripper          = 2**11
 
492
    optionDestroyOnClose   = 2**12
 
493
    optionToolbar          = 2**13
 
494
    optionActive           = 2**14
 
495
    optionGripperTop       = 2**15
 
496
    optionMaximized        = 2**16
 
497
    optionDockFixed        = 2**17
 
498
    optionNotebookDockable = 2**18
 
499
    optionMinimized        = 2**19
 
500
    optionLeftSnapped      = 2**20
 
501
    optionRightSnapped     = 2**21
 
502
    optionTopSnapped       = 2**22
 
503
    optionBottomSnapped    = 2**23
 
504
    optionFlyOut           = 2**24
 
505
    optionCaptionLeft      = 2**25
 
506
 
 
507
    buttonClose            = 2**26
 
508
    buttonMaximize         = 2**27
 
509
    buttonMinimize         = 2**28
 
510
    buttonPin              = 2**29
 
511
 
 
512
    buttonCustom1          = 2**30
 
513
    buttonCustom2          = 2**31
 
514
    buttonCustom3          = 2**32
 
515
 
 
516
    savedHiddenState       = 2**33    # used internally
 
517
    actionPane             = 2**34    # used internally
 
518
    wasMaximized           = 2**35    # used internally
 
519
    needsRestore           = 2**36    # used internally
 
520
 
 
521
 
 
522
    def __init__(self):
 
523
        """ Default class constructor. """
 
524
 
 
525
        self.window = None
 
526
        self.frame = None
 
527
        self.state = 0
 
528
        self.dock_direction = AUI_DOCK_LEFT
 
529
        self.dock_layer = 0
 
530
        self.dock_row = 0
 
531
        self.dock_pos = 0
 
532
        self.minimize_mode = AUI_MINIMIZE_POS_SMART
 
533
        self.floating_pos = wx.Point(-1, -1)
 
534
        self.floating_size = wx.Size(-1, -1)
 
535
        self.best_size = wx.Size(-1, -1)
 
536
        self.min_size = wx.Size(-1, -1)
 
537
        self.max_size = wx.Size(-1, -1)
 
538
        self.dock_proportion = 0
 
539
        self.caption = ""
 
540
        self.buttons = []
 
541
        self.name = ""
 
542
        self.icon = wx.NullIcon
 
543
        self.rect = wx.Rect()
 
544
        self.notebook_id = -1
 
545
        self.transparent = 255
 
546
        self.needsTransparency = False
 
547
        self.previousDockPos = None
 
548
        self.previousDockSize = 0
 
549
        self.snapped = 0
 
550
        self.minimize_target = None
 
551
 
 
552
        self.DefaultPane()
 
553
 
 
554
 
 
555
    def dock_direction_get(self):
 
556
        """
 
557
        Getter for the `dock_direction`.
 
558
 
 
559
        :see: :meth:`~AuiPaneInfo.dock_direction_set` for a set of valid docking directions.
 
560
        """
 
561
 
 
562
        if self.IsMaximized():
 
563
            return AUI_DOCK_CENTER
 
564
        else:
 
565
            return self._dock_direction
 
566
 
 
567
 
 
568
    def dock_direction_set(self, value):
 
569
        """
 
570
        Setter for the `dock_direction`.
 
571
 
 
572
        :param integer `value`: the docking direction. This can be one of the following bits:
 
573
 
 
574
        ============================ ======= =============================================
 
575
        Dock Flag                     Value  Description
 
576
        ============================ ======= =============================================
 
577
        ``AUI_DOCK_NONE``                  0 No docking direction.
 
578
        ``AUI_DOCK_TOP``                   1 Top docking direction.
 
579
        ``AUI_DOCK_RIGHT``                 2 Right docking direction.
 
580
        ``AUI_DOCK_BOTTOM``                3 Bottom docking direction.
 
581
        ``AUI_DOCK_LEFT``                  4 Left docking direction.
 
582
        ``AUI_DOCK_CENTER``                5 Center docking direction.
 
583
        ``AUI_DOCK_CENTRE``                5 Centre docking direction.
 
584
        ``AUI_DOCK_NOTEBOOK_PAGE``         6 Automatic AuiNotebooks docking style.
 
585
        ============================ ======= =============================================
 
586
 
 
587
        """
 
588
 
 
589
        self._dock_direction = value
 
590
 
 
591
    dock_direction = property(dock_direction_get, dock_direction_set)
 
592
 
 
593
    def IsOk(self):
 
594
        """
 
595
        Returns ``True`` if the :class:`AuiPaneInfo` structure is valid.
 
596
 
 
597
        :note: A pane structure is valid if it has an associated window.
 
598
        """
 
599
 
 
600
        return self.window != None
 
601
 
 
602
 
 
603
    def IsMaximized(self):
 
604
        """ Returns ``True`` if the pane is maximized. """
 
605
 
 
606
        return self.HasFlag(self.optionMaximized)
 
607
 
 
608
 
 
609
    def IsMinimized(self):
 
610
        """ Returns ``True`` if the pane is minimized. """
 
611
 
 
612
        return self.HasFlag(self.optionMinimized)
 
613
 
 
614
 
 
615
    def IsFixed(self):
 
616
        """ Returns ``True`` if the pane cannot be resized. """
 
617
 
 
618
        return not self.HasFlag(self.optionResizable)
 
619
 
 
620
 
 
621
    def IsResizeable(self):
 
622
        """ Returns ``True`` if the pane can be resized. """
 
623
 
 
624
        return self.HasFlag(self.optionResizable)
 
625
 
 
626
 
 
627
    def IsShown(self):
 
628
        """ Returns ``True`` if the pane is currently shown. """
 
629
 
 
630
        return not self.HasFlag(self.optionHidden)
 
631
 
 
632
 
 
633
    def IsFloating(self):
 
634
        """ Returns ``True`` if the pane is floating. """
 
635
 
 
636
        return self.HasFlag(self.optionFloating)
 
637
 
 
638
 
 
639
    def IsDocked(self):
 
640
        """ Returns ``True`` if the pane is docked. """
 
641
 
 
642
        return not self.HasFlag(self.optionFloating)
 
643
 
 
644
 
 
645
    def IsToolbar(self):
 
646
        """ Returns ``True`` if the pane contains a toolbar. """
 
647
 
 
648
        return self.HasFlag(self.optionToolbar)
 
649
 
 
650
 
 
651
    def IsTopDockable(self):
 
652
        """
 
653
        Returns ``True`` if the pane can be docked at the top
 
654
        of the managed frame.
 
655
        """
 
656
 
 
657
        return self.HasFlag(self.optionTopDockable)
 
658
 
 
659
 
 
660
    def IsBottomDockable(self):
 
661
        """
 
662
        Returns ``True`` if the pane can be docked at the bottom
 
663
        of the managed frame.
 
664
        """
 
665
 
 
666
        return self.HasFlag(self.optionBottomDockable)
 
667
 
 
668
 
 
669
    def IsLeftDockable(self):
 
670
        """
 
671
        Returns ``True`` if the pane can be docked at the left
 
672
        of the managed frame.
 
673
        """
 
674
 
 
675
        return self.HasFlag(self.optionLeftDockable)
 
676
 
 
677
 
 
678
    def IsRightDockable(self):
 
679
        """
 
680
        Returns ``True`` if the pane can be docked at the right
 
681
        of the managed frame.
 
682
        """
 
683
 
 
684
        return self.HasFlag(self.optionRightDockable)
 
685
 
 
686
 
 
687
    def IsDockable(self):
 
688
        """ Returns ``True`` if the pane can be docked. """
 
689
 
 
690
        return self.IsTopDockable() or self.IsBottomDockable() or self.IsLeftDockable() or \
 
691
               self.IsRightDockable() or self.IsNotebookDockable()
 
692
 
 
693
 
 
694
    def IsFloatable(self):
 
695
        """
 
696
        Returns ``True`` if the pane can be undocked and displayed as a
 
697
        floating window.
 
698
        """
 
699
 
 
700
        return self.HasFlag(self.optionFloatable)
 
701
 
 
702
 
 
703
    def IsMovable(self):
 
704
        """
 
705
        Returns ``True`` if the docked frame can be undocked or moved to
 
706
        another dock position.
 
707
        """
 
708
 
 
709
        return self.HasFlag(self.optionMovable)
 
710
 
 
711
 
 
712
    def IsDestroyOnClose(self):
 
713
        """
 
714
        Returns ``True`` if the pane should be destroyed when it is closed.
 
715
 
 
716
        Normally a pane is simply hidden when the close button is clicked. Calling :meth:`~AuiPaneInfo.DestroyOnClose`
 
717
        with a ``True`` input parameter will cause the window to be destroyed when the user clicks
 
718
        the pane's close button.
 
719
        """
 
720
 
 
721
        return self.HasFlag(self.optionDestroyOnClose)
 
722
 
 
723
 
 
724
    def IsNotebookDockable(self):
 
725
        """
 
726
        Returns ``True`` if a pane can be docked on top to another to create a
 
727
        :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
728
        """
 
729
 
 
730
        return self.HasFlag(self.optionNotebookDockable)
 
731
 
 
732
 
 
733
    def IsTopSnappable(self):
 
734
        """ Returns ``True`` if the pane can be snapped at the top of the managed frame. """
 
735
 
 
736
        return self.HasFlag(self.optionTopSnapped)
 
737
 
 
738
 
 
739
    def IsBottomSnappable(self):
 
740
        """ Returns ``True`` if the pane can be snapped at the bottom of the managed frame. """
 
741
 
 
742
        return self.HasFlag(self.optionBottomSnapped)
 
743
 
 
744
 
 
745
    def IsLeftSnappable(self):
 
746
        """ Returns ``True`` if the pane can be snapped on the left of the managed frame. """
 
747
 
 
748
        return self.HasFlag(self.optionLeftSnapped)
 
749
 
 
750
 
 
751
    def IsRightSnappable(self):
 
752
        """ Returns ``True`` if the pane can be snapped on the right of the managed frame. """
 
753
 
 
754
        return self.HasFlag(self.optionRightSnapped)
 
755
 
 
756
 
 
757
    def IsSnappable(self):
 
758
        """ Returns ``True`` if the pane can be snapped. """
 
759
 
 
760
        return self.IsTopSnappable() or self.IsBottomSnappable() or self.IsLeftSnappable() or \
 
761
               self.IsRightSnappable()
 
762
 
 
763
 
 
764
    def IsFlyOut(self):
 
765
        """ Returns ``True`` if the floating pane has a "fly-out" effect. """
 
766
 
 
767
        return self.HasFlag(self.optionFlyOut)
 
768
 
 
769
 
 
770
    def HasCaption(self):
 
771
        """ Returns ``True`` if the pane displays a caption. """
 
772
 
 
773
        return self.HasFlag(self.optionCaption)
 
774
 
 
775
 
 
776
    def HasCaptionLeft(self):
 
777
        """ Returns ``True`` if the pane displays a caption on the left (rotated by 90 degrees). """
 
778
 
 
779
        return self.HasFlag(self.optionCaptionLeft)
 
780
 
 
781
 
 
782
    def HasGripper(self):
 
783
        """ Returns ``True`` if the pane displays a gripper. """
 
784
 
 
785
        return self.HasFlag(self.optionGripper)
 
786
 
 
787
 
 
788
    def HasBorder(self):
 
789
        """ Returns ``True`` if the pane displays a border. """
 
790
 
 
791
        return self.HasFlag(self.optionPaneBorder)
 
792
 
 
793
 
 
794
    def HasCloseButton(self):
 
795
        """ Returns ``True`` if the pane displays a button to close the pane. """
 
796
 
 
797
        return self.HasFlag(self.buttonClose)
 
798
 
 
799
 
 
800
    def HasMaximizeButton(self):
 
801
        """ Returns ``True`` if the pane displays a button to maximize the pane. """
 
802
 
 
803
        return self.HasFlag(self.buttonMaximize)
 
804
 
 
805
 
 
806
    def HasMinimizeButton(self):
 
807
        """ Returns ``True`` if the pane displays a button to minimize the pane. """
 
808
 
 
809
        return self.HasFlag(self.buttonMinimize)
 
810
 
 
811
 
 
812
    def GetMinimizeMode(self):
 
813
        """
 
814
        Returns the minimization style for this pane.
 
815
 
 
816
        Possible return values are:
 
817
 
 
818
        ============================== ========= ==============================
 
819
        Minimize Mode Flag             Hex Value Description
 
820
        ============================== ========= ==============================
 
821
        ``AUI_MINIMIZE_POS_SMART``          0x01 Minimizes the pane on the closest tool bar
 
822
        ``AUI_MINIMIZE_POS_TOP``            0x02 Minimizes the pane on the top tool bar
 
823
        ``AUI_MINIMIZE_POS_LEFT``           0x03 Minimizes the pane on its left tool bar
 
824
        ``AUI_MINIMIZE_POS_RIGHT``          0x04 Minimizes the pane on its right tool bar
 
825
        ``AUI_MINIMIZE_POS_BOTTOM``         0x05 Minimizes the pane on its bottom tool bar
 
826
        ``AUI_MINIMIZE_POS_TOOLBAR``        0x06 Minimizes the pane on a target :class:`~lib.agw.aui.auibar.AuiToolBar`
 
827
        ``AUI_MINIMIZE_POS_MASK``           0x17 Mask to filter the position flags
 
828
        ``AUI_MINIMIZE_CAPT_HIDE``           0x0 Hides the caption of the minimized pane
 
829
        ``AUI_MINIMIZE_CAPT_SMART``         0x08 Displays the caption in the best rotation (horizontal or clockwise)
 
830
        ``AUI_MINIMIZE_CAPT_HORZ``          0x10 Displays the caption horizontally
 
831
        ``AUI_MINIMIZE_CAPT_MASK``          0x18 Mask to filter the caption flags
 
832
        ============================== ========= ==============================
 
833
 
 
834
        The flags can be filtered with the following masks:
 
835
 
 
836
        ============================== ========= ==============================
 
837
        Minimize Mask Flag             Hex Value Description
 
838
        ============================== ========= ==============================
 
839
        ``AUI_MINIMIZE_POS_MASK``           0x17 Filters the position flags
 
840
        ``AUI_MINIMIZE_CAPT_MASK``          0x18 Filters the caption flags
 
841
        ============================== ========= ==============================
 
842
 
 
843
        """
 
844
 
 
845
        return self.minimize_mode
 
846
 
 
847
 
 
848
    def HasPinButton(self):
 
849
        """ Returns ``True`` if the pane displays a button to float the pane. """
 
850
 
 
851
        return self.HasFlag(self.buttonPin)
 
852
 
 
853
 
 
854
    def HasGripperTop(self):
 
855
        """ Returns ``True`` if the pane displays a gripper at the top. """
 
856
 
 
857
        return self.HasFlag(self.optionGripperTop)
 
858
 
 
859
 
 
860
    def Window(self, w):
 
861
        """
 
862
        Associate a :class:`Window` derived window to this pane.
 
863
 
 
864
        This normally does not need to be specified, as the window pointer is
 
865
        automatically assigned to the :class:`AuiPaneInfo` structure as soon as it is
 
866
        added to the manager.
 
867
 
 
868
        :param `w`: a :class:`Window` derived window.
 
869
        """
 
870
 
 
871
        self.window = w
 
872
        return self
 
873
 
 
874
 
 
875
    def Name(self, name):
 
876
        """
 
877
        Sets the name of the pane so it can be referenced in lookup functions.
 
878
 
 
879
        If a name is not specified by the user, a random name is assigned to the pane
 
880
        when it is added to the manager.
 
881
 
 
882
        :param `name`: a string specifying the pane name.
 
883
 
 
884
        .. warning::
 
885
 
 
886
           If you are using :meth:`AuiManager.SavePerspective` and :meth:`AuiManager.LoadPerspective`,
 
887
           you will have to specify a name for your pane using :meth:`~AuiPaneInfo.Name`, as perspectives
 
888
           containing randomly generated names can not be properly restored.
 
889
        """
 
890
 
 
891
        self.name = name
 
892
        return self
 
893
 
 
894
 
 
895
    def Caption(self, caption):
 
896
        """
 
897
        Sets the caption of the pane.
 
898
 
 
899
        :param string `caption`: a string specifying the pane caption.
 
900
        """
 
901
 
 
902
        self.caption = caption
 
903
        return self
 
904
 
 
905
 
 
906
    def Left(self):
 
907
        """
 
908
        Sets the pane dock position to the left side of the frame.
 
909
 
 
910
        :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_LEFT`` as
 
911
         parameter.
 
912
        """
 
913
 
 
914
        self.dock_direction = AUI_DOCK_LEFT
 
915
        return self
 
916
 
 
917
 
 
918
    def Right(self):
 
919
        """
 
920
        Sets the pane dock position to the right side of the frame.
 
921
 
 
922
        :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_RIGHT`` as
 
923
         parameter.
 
924
        """
 
925
 
 
926
        self.dock_direction = AUI_DOCK_RIGHT
 
927
        return self
 
928
 
 
929
 
 
930
    def Top(self):
 
931
        """
 
932
        Sets the pane dock position to the top of the frame.
 
933
 
 
934
        :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_TOP`` as
 
935
         parameter.
 
936
        """
 
937
 
 
938
        self.dock_direction = AUI_DOCK_TOP
 
939
        return self
 
940
 
 
941
 
 
942
    def Bottom(self):
 
943
        """
 
944
        Sets the pane dock position to the bottom of the frame.
 
945
 
 
946
        :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_BOTTOM`` as
 
947
         parameter.
 
948
        """
 
949
 
 
950
        self.dock_direction = AUI_DOCK_BOTTOM
 
951
        return self
 
952
 
 
953
 
 
954
    def Center(self):
 
955
        """
 
956
        Sets the pane to the center position of the frame.
 
957
 
 
958
        The centre pane is the space in the middle after all border panes (left, top,
 
959
        right, bottom) are subtracted from the layout.
 
960
 
 
961
        :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_CENTER`` as
 
962
         parameter.
 
963
        """
 
964
 
 
965
        self.dock_direction = AUI_DOCK_CENTER
 
966
        return self
 
967
 
 
968
 
 
969
    def Centre(self):
 
970
        """
 
971
        Sets the pane to the center position of the frame.
 
972
 
 
973
        The centre pane is the space in the middle after all border panes (left, top,
 
974
        right, bottom) are subtracted from the layout.
 
975
 
 
976
        :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_CENTRE`` as
 
977
         parameter.
 
978
        """
 
979
 
 
980
        self.dock_direction = AUI_DOCK_CENTRE
 
981
        return self
 
982
 
 
983
 
 
984
    def Direction(self, direction):
 
985
        """
 
986
        Determines the direction of the docked pane. It is functionally the
 
987
        same as calling :meth:`Left`, :meth:`Right`, :meth:`Top` or :meth:`Bottom`,
 
988
        except that docking direction may be specified programmatically via the parameter `direction`.
 
989
 
 
990
        :param integer `direction`: the direction of the docked pane.
 
991
 
 
992
        :see: :meth:`dock_direction_set` for a list of valid docking directions.
 
993
        """
 
994
 
 
995
        self.dock_direction = direction
 
996
        return self
 
997
 
 
998
 
 
999
    def Layer(self, layer):
 
1000
        """
 
1001
        Determines the layer of the docked pane.
 
1002
 
 
1003
        The dock layer is similar to an onion, the inner-most layer being layer 0. Each
 
1004
        shell moving in the outward direction has a higher layer number. This allows for
 
1005
        more complex docking layout formation.
 
1006
 
 
1007
        :param integer `layer`: the layer of the docked pane.
 
1008
        """
 
1009
 
 
1010
        self.dock_layer = layer
 
1011
        return self
 
1012
 
 
1013
 
 
1014
    def Row(self, row):
 
1015
        """
 
1016
        Determines the row of the docked pane.
 
1017
 
 
1018
        :param integer `row`: the row of the docked pane.
 
1019
        """
 
1020
 
 
1021
        self.dock_row = row
 
1022
        return self
 
1023
 
 
1024
 
 
1025
    def Position(self, pos):
 
1026
        """
 
1027
        Determines the position of the docked pane.
 
1028
 
 
1029
        :param integer `pos`: the position of the docked pane.
 
1030
        """
 
1031
 
 
1032
        self.dock_pos = pos
 
1033
        return self
 
1034
 
 
1035
 
 
1036
    def MinSize(self, arg1=None, arg2=None):
 
1037
        """
 
1038
        Sets the minimum size of the pane.
 
1039
 
 
1040
        This method is split in 2 versions depending on the input type. If `arg1` is
 
1041
        a :class:`Size` object, then :meth:`~AuiPaneInfo.MinSize1` is called. Otherwise, :meth:`~AuiPaneInfo.MinSize2` is called.
 
1042
 
 
1043
        :param `arg1`: a :class:`Size` object, a (x, y) tuple or or a `x` coordinate.
 
1044
        :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
 
1045
        """
 
1046
 
 
1047
        if isinstance(arg1, wx.Size):
 
1048
            ret = self.MinSize1(arg1)
 
1049
        elif isinstance(arg1, types.TupleType):
 
1050
            ret = self.MinSize1(wx.Size(*arg1))
 
1051
        elif isinstance(arg1, types.IntType) and arg2 is not None:
 
1052
            ret = self.MinSize2(arg1, arg2)
 
1053
        else:
 
1054
            raise Exception("Invalid argument passed to `MinSize`: arg1=%s, arg2=%s"%(repr(arg1), repr(arg2)))
 
1055
 
 
1056
        return ret
 
1057
 
 
1058
 
 
1059
    def MinSize1(self, size):
 
1060
        """
 
1061
        Sets the minimum size of the pane.
 
1062
 
 
1063
        :see: :meth:`MinSize` for an explanation of input parameters.
 
1064
        """
 
1065
        self.min_size = size
 
1066
        return self
 
1067
 
 
1068
 
 
1069
    def MinSize2(self, x, y):
 
1070
        """
 
1071
        Sets the minimum size of the pane.
 
1072
 
 
1073
        :see: :meth:`MinSize` for an explanation of input parameters.
 
1074
        """
 
1075
 
 
1076
        self.min_size = wx.Size(x, y)
 
1077
        return self
 
1078
 
 
1079
 
 
1080
    def MaxSize(self, arg1=None, arg2=None):
 
1081
        """
 
1082
        Sets the maximum size of the pane.
 
1083
 
 
1084
        This method is split in 2 versions depending on the input type. If `arg1` is
 
1085
        a :class:`Size` object, then :meth:`~AuiPaneInfo.MaxSize1` is called. Otherwise, :meth:`~AuiPaneInfo.MaxSize2` is called.
 
1086
 
 
1087
        :param `arg1`: a :class:`Size` object, a (x, y) tuple or a `x` coordinate.
 
1088
        :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
 
1089
        """
 
1090
 
 
1091
        if isinstance(arg1, wx.Size):
 
1092
            ret = self.MaxSize1(arg1)
 
1093
        elif isinstance(arg1, types.TupleType):
 
1094
            ret = self.MaxSize1(wx.Size(*arg1))
 
1095
        elif isinstance(arg1, types.IntType) and arg2 is not None:
 
1096
            ret = self.MaxSize2(arg1, arg2)
 
1097
        else:
 
1098
            raise Exception("Invalid argument passed to `MaxSize`: arg1=%s, arg2=%s"%(repr(arg1), repr(arg2)))
 
1099
 
 
1100
        return ret
 
1101
 
 
1102
 
 
1103
    def MaxSize1(self, size):
 
1104
        """
 
1105
        Sets the maximum size of the pane.
 
1106
 
 
1107
        :see: :meth:`MaxSize` for an explanation of input parameters.
 
1108
        """
 
1109
 
 
1110
        self.max_size = size
 
1111
        return self
 
1112
 
 
1113
 
 
1114
    def MaxSize2(self, x, y):
 
1115
        """
 
1116
        Sets the maximum size of the pane.
 
1117
 
 
1118
        :see: :meth:`MaxSize` for an explanation of input parameters.
 
1119
        """
 
1120
 
 
1121
        self.max_size.Set(x,y)
 
1122
        return self
 
1123
 
 
1124
 
 
1125
    def BestSize(self, arg1=None, arg2=None):
 
1126
        """
 
1127
        Sets the ideal size for the pane. The docking manager will attempt to use
 
1128
        this size as much as possible when docking or floating the pane.
 
1129
 
 
1130
        This method is split in 2 versions depending on the input type. If `arg1` is
 
1131
        a :class:`Size` object, then :meth:`BestSize1` is called. Otherwise, :meth:`BestSize2` is called.
 
1132
 
 
1133
        :param `arg1`: a :class:`Size` object, a (x, y) tuple or a `x` coordinate.
 
1134
        :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
 
1135
        """
 
1136
 
 
1137
        if isinstance(arg1, wx.Size):
 
1138
            ret = self.BestSize1(arg1)
 
1139
        elif isinstance(arg1, types.TupleType):
 
1140
            ret = self.BestSize1(wx.Size(*arg1))
 
1141
        elif isinstance(arg1, types.IntType) and arg2 is not None:
 
1142
            ret = self.BestSize2(arg1, arg2)
 
1143
        else:
 
1144
            raise Exception("Invalid argument passed to `BestSize`: arg1=%s, arg2=%s"%(repr(arg1), repr(arg2)))
 
1145
 
 
1146
        return ret
 
1147
 
 
1148
 
 
1149
    def BestSize1(self, size):
 
1150
        """
 
1151
        Sets the best size of the pane.
 
1152
 
 
1153
        :see: :meth:`BestSize` for an explanation of input parameters.
 
1154
        """
 
1155
 
 
1156
        self.best_size = size
 
1157
        return self
 
1158
 
 
1159
 
 
1160
    def BestSize2(self, x, y):
 
1161
        """
 
1162
        Sets the best size of the pane.
 
1163
 
 
1164
        :see: :meth:`BestSize` for an explanation of input parameters.
 
1165
        """
 
1166
 
 
1167
        self.best_size.Set(x,y)
 
1168
        return self
 
1169
 
 
1170
 
 
1171
    def FloatingPosition(self, pos):
 
1172
        """
 
1173
        Sets the position of the floating pane.
 
1174
 
 
1175
        :param `pos`: a :class:`Point` or a tuple indicating the pane floating position.
 
1176
        """
 
1177
 
 
1178
        self.floating_pos = wx.Point(*pos)
 
1179
        return self
 
1180
 
 
1181
 
 
1182
    def FloatingSize(self, size):
 
1183
        """
 
1184
        Sets the size of the floating pane.
 
1185
 
 
1186
        :param `size`: a :class:`Size` or a tuple indicating the pane floating size.
 
1187
        """
 
1188
 
 
1189
        self.floating_size = wx.Size(*size)
 
1190
        return self
 
1191
 
 
1192
 
 
1193
    def Maximize(self):
 
1194
        """ Makes the pane take up the full area."""
 
1195
 
 
1196
        return self.SetFlag(self.optionMaximized, True)
 
1197
 
 
1198
 
 
1199
    def Minimize(self):
 
1200
        """
 
1201
        Makes the pane minimized in a :class:`~lib.agw.aui.auibar.AuiToolBar`.
 
1202
 
 
1203
        Clicking on the minimize button causes a new :class:`~lib.agw.aui.auibar.AuiToolBar` to be created
 
1204
        and added to the frame manager, (currently the implementation is such that
 
1205
        panes at West will have a toolbar at the right, panes at South will have
 
1206
        toolbars at the bottom etc...) and the pane is hidden in the manager.
 
1207
 
 
1208
        Clicking on the restore button on the newly created toolbar will result in the
 
1209
        toolbar being removed and the original pane being restored.
 
1210
        """
 
1211
 
 
1212
        return self.SetFlag(self.optionMinimized, True)
 
1213
 
 
1214
 
 
1215
    def MinimizeMode(self, mode):
 
1216
        """
 
1217
        Sets the expected minimized mode if the minimize button is visible.
 
1218
 
 
1219
        :param integer `mode`: the minimized pane can have a specific position in the work space:
 
1220
 
 
1221
        ============================== ========= ==============================
 
1222
        Minimize Mode Flag             Hex Value Description
 
1223
        ============================== ========= ==============================
 
1224
        ``AUI_MINIMIZE_POS_SMART``          0x01 Minimizes the pane on the closest tool bar
 
1225
        ``AUI_MINIMIZE_POS_TOP``            0x02 Minimizes the pane on the top tool bar
 
1226
        ``AUI_MINIMIZE_POS_LEFT``           0x03 Minimizes the pane on its left tool bar
 
1227
        ``AUI_MINIMIZE_POS_RIGHT``          0x04 Minimizes the pane on its right tool bar
 
1228
        ``AUI_MINIMIZE_POS_BOTTOM``         0x05 Minimizes the pane on its bottom tool bar
 
1229
        ``AUI_MINIMIZE_POS_TOOLBAR``        0x06 Minimizes the pane on a target :class:`~lib.agw.aui.auibar.AuiToolBar`
 
1230
        ============================== ========= ==============================
 
1231
 
 
1232
        The caption of the minimized pane can be displayed in different modes:
 
1233
 
 
1234
        ============================== ========= ==============================
 
1235
        Caption Mode Flag              Hex Value Description
 
1236
        ============================== ========= ==============================
 
1237
        ``AUI_MINIMIZE_CAPT_HIDE``           0x0 Hides the caption of the minimized pane
 
1238
        ``AUI_MINIMIZE_CAPT_SMART``         0x08 Displays the caption in the best rotation (horizontal in the top and in
 
1239
                                                 the bottom tool bar or clockwise in the right and in the left tool bar)
 
1240
        ``AUI_MINIMIZE_CAPT_HORZ``          0x10 Displays the caption horizontally
 
1241
        ============================== ========= ==============================
 
1242
 
 
1243
        .. note::
 
1244
 
 
1245
           In order to use the ``AUI_MINIMIZE_POS_TOOLBAR`` flag, the instance of :class:`AuiManager`
 
1246
           you pass as an input for :meth:`MinimizeTarget` **must** have a real name and not the randomly
 
1247
           generated one. Remember to set the :meth:`Name` property of the toolbar pane before calling this method.
 
1248
 
 
1249
        """
 
1250
 
 
1251
        self.minimize_mode = mode
 
1252
        return self
 
1253
 
 
1254
 
 
1255
    def MinimizeTarget(self, toolbarPane):
 
1256
        """
 
1257
        Minimizes the panes using a :class:`AuiPaneInfo` as a target. As :class:`AuiPaneInfo` properties
 
1258
        need to be copied back and forth every time the perspective has changed, we
 
1259
        only store the toobar **name**.
 
1260
 
 
1261
        :param `toolbarPane`: an instance of :class:`AuiPaneInfo`, containing a :class:`~lib.agw.aui.auibar.AuiToolBar`.
 
1262
 
 
1263
        .. note::
 
1264
 
 
1265
           In order to use this functionality (and with the ``AUI_MINIMIZE_POS_TOOLBAR``
 
1266
           flag set), the instance of :class:`AuiPaneInfo` you pass as an input **must** have a real
 
1267
           name and not the randomly generated one. Remember to set the :meth:`Name` property of
 
1268
           the toolbar pane before calling this method.
 
1269
 
 
1270
        """
 
1271
 
 
1272
        self.minimize_target = toolbarPane.name
 
1273
        return self
 
1274
 
 
1275
 
 
1276
    def Restore(self):
 
1277
        """ Is the reverse of :meth:`Maximize` and :meth:`Minimize`."""
 
1278
 
 
1279
        return self.SetFlag(self.optionMaximized or self.optionMinimized, False)
 
1280
 
 
1281
 
 
1282
    def Fixed(self):
 
1283
        """
 
1284
        Forces a pane to be fixed size so that it cannot be resized.
 
1285
        After calling :meth:`Fixed`, :meth:`IsFixed` will return ``True``.
 
1286
        """
 
1287
 
 
1288
        return self.SetFlag(self.optionResizable, False)
 
1289
 
 
1290
 
 
1291
    def Resizable(self, resizable=True):
 
1292
        """
 
1293
        Allows a pane to be resizable if `resizable` is ``True``, and forces
 
1294
        it to be a fixed size if `resizeable` is ``False``.
 
1295
 
 
1296
        If `resizable` is ``False``, this is simply an antonym for :meth:`Fixed`.
 
1297
 
 
1298
        :param bool `resizable`: whether the pane will be resizeable or not.
 
1299
        """
 
1300
 
 
1301
        return self.SetFlag(self.optionResizable, resizable)
 
1302
 
 
1303
 
 
1304
    def Transparent(self, alpha):
 
1305
        """
 
1306
        Makes the pane transparent when floating.
 
1307
 
 
1308
        :param integer `alpha`: a value between 0 and 255 for pane transparency.
 
1309
        """
 
1310
 
 
1311
        if alpha < 0 or alpha > 255:
 
1312
            raise Exception("Invalid transparency value (%s)"%repr(alpha))
 
1313
 
 
1314
        self.transparent = alpha
 
1315
        self.needsTransparency = True
 
1316
 
 
1317
 
 
1318
    def Dock(self):
 
1319
        """ Indicates that a pane should be docked. It is the opposite of :meth:`Float`. """
 
1320
 
 
1321
        if self.IsNotebookPage():
 
1322
            self.notebook_id = -1
 
1323
            self.dock_direction = AUI_DOCK_NONE
 
1324
 
 
1325
        return self.SetFlag(self.optionFloating, False)
 
1326
 
 
1327
 
 
1328
    def Float(self):
 
1329
        """ Indicates that a pane should be floated. It is the opposite of :meth:`Dock`. """
 
1330
 
 
1331
        if self.IsNotebookPage():
 
1332
            self.notebook_id = -1
 
1333
            self.dock_direction = AUI_DOCK_NONE
 
1334
 
 
1335
        return self.SetFlag(self.optionFloating, True)
 
1336
 
 
1337
 
 
1338
    def Hide(self):
 
1339
        """
 
1340
        Indicates that a pane should be hidden.
 
1341
 
 
1342
        Calling :meth:`Show(False) <Show>` achieve the same effect.
 
1343
        """
 
1344
 
 
1345
        return self.SetFlag(self.optionHidden, True)
 
1346
 
 
1347
 
 
1348
    def Show(self, show=True):
 
1349
        """
 
1350
        Indicates that a pane should be shown.
 
1351
 
 
1352
        :param bool `show`: whether the pane should be shown or not.
 
1353
        """
 
1354
 
 
1355
        return self.SetFlag(self.optionHidden, not show)
 
1356
 
 
1357
 
 
1358
    # By defaulting to 1000, the tab will get placed at the end
 
1359
    def NotebookPage(self, id, tab_position=1000):
 
1360
        """
 
1361
        Forces a pane to be a notebook page, so that the pane can be
 
1362
        docked on top to another to create a :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
1363
 
 
1364
        :param integer `id`: the notebook id;
 
1365
        :param integer `tab_position`: the tab number of the pane once docked in a notebook.
 
1366
        """
 
1367
 
 
1368
        # Remove any floating frame
 
1369
        self.Dock()
 
1370
        self.notebook_id = id
 
1371
        self.dock_pos = tab_position
 
1372
        self.dock_row = 0
 
1373
        self.dock_layer = 0
 
1374
        self.dock_direction = AUI_DOCK_NOTEBOOK_PAGE
 
1375
 
 
1376
        return self
 
1377
 
 
1378
 
 
1379
    def NotebookControl(self, id):
 
1380
        """
 
1381
        Forces a pane to be a notebook control (:class:`~lib.agw.aui.auibook.AuiNotebook`).
 
1382
 
 
1383
        :param integer `id`: the notebook id.
 
1384
        """
 
1385
 
 
1386
        self.notebook_id = id
 
1387
        self.window = None
 
1388
        self.buttons = []
 
1389
 
 
1390
        if self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE:
 
1391
            self.dock_direction = AUI_DOCK_NONE
 
1392
 
 
1393
        return self
 
1394
 
 
1395
 
 
1396
    def HasNotebook(self):
 
1397
        """ Returns whether a pane has a :class:`~lib.agw.aui.auibook.AuiNotebook` or not. """
 
1398
 
 
1399
        return self.notebook_id >= 0
 
1400
 
 
1401
 
 
1402
    def IsNotebookPage(self):
 
1403
        """ Returns whether the pane is a notebook page in a :class:`~lib.agw.aui.auibook.AuiNotebook`. """
 
1404
 
 
1405
        return self.notebook_id >= 0 and self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE
 
1406
 
 
1407
 
 
1408
    def IsNotebookControl(self):
 
1409
        """ Returns whether the pane is a notebook control (:class:`~lib.agw.aui.auibook.AuiNotebook`). """
 
1410
 
 
1411
        return not self.IsNotebookPage() and self.HasNotebook()
 
1412
 
 
1413
 
 
1414
    def SetNameFromNotebookId(self):
 
1415
        """ Sets the pane name once docked in a :class:`~lib.agw.aui.auibook.AuiNotebook` using the notebook id. """
 
1416
 
 
1417
        if self.notebook_id >= 0:
 
1418
            self.name = "__notebook_%d"%self.notebook_id
 
1419
 
 
1420
        return self
 
1421
 
 
1422
 
 
1423
    def CaptionVisible(self, visible=True, left=False):
 
1424
        """
 
1425
        Indicates that a pane caption should be visible. If `visible` is ``False``, no pane
 
1426
        caption is drawn.
 
1427
 
 
1428
        :param bool `visible`: whether the caption should be visible or not;
 
1429
        :param bool `left`: whether the caption should be drawn on the left (rotated by 90 degrees) or not.
 
1430
        """
 
1431
 
 
1432
        if left:
 
1433
            self.SetFlag(self.optionCaption, False)
 
1434
            return self.SetFlag(self.optionCaptionLeft, visible)
 
1435
 
 
1436
        self.SetFlag(self.optionCaptionLeft, False)
 
1437
        return self.SetFlag(self.optionCaption, visible)
 
1438
 
 
1439
 
 
1440
    def PaneBorder(self, visible=True):
 
1441
        """
 
1442
        Indicates that a border should be drawn for the pane.
 
1443
 
 
1444
        :param bool `visible`: whether the pane border should be visible or not.
 
1445
        """
 
1446
 
 
1447
        return self.SetFlag(self.optionPaneBorder, visible)
 
1448
 
 
1449
 
 
1450
    def Gripper(self, visible=True):
 
1451
        """
 
1452
        Indicates that a gripper should be drawn for the pane.
 
1453
 
 
1454
        :param bool `visible`: whether the gripper should be visible or not.
 
1455
        """
 
1456
 
 
1457
        return self.SetFlag(self.optionGripper, visible)
 
1458
 
 
1459
 
 
1460
    def GripperTop(self, attop=True):
 
1461
        """
 
1462
        Indicates that a gripper should be drawn at the top of the pane.
 
1463
 
 
1464
        :param bool `attop`: whether the gripper should be drawn at the top or not.
 
1465
        """
 
1466
 
 
1467
        return self.SetFlag(self.optionGripperTop, attop)
 
1468
 
 
1469
 
 
1470
    def CloseButton(self, visible=True):
 
1471
        """
 
1472
        Indicates that a close button should be drawn for the pane.
 
1473
 
 
1474
        :param bool `visible`: whether the close button should be visible or not.
 
1475
        """
 
1476
 
 
1477
        return self.SetFlag(self.buttonClose, visible)
 
1478
 
 
1479
 
 
1480
    def MaximizeButton(self, visible=True):
 
1481
        """
 
1482
        Indicates that a maximize button should be drawn for the pane.
 
1483
 
 
1484
        :param bool `visible`: whether the maximize button should be visible or not.
 
1485
        """
 
1486
 
 
1487
        return self.SetFlag(self.buttonMaximize, visible)
 
1488
 
 
1489
 
 
1490
    def MinimizeButton(self, visible=True):
 
1491
        """
 
1492
        Indicates that a minimize button should be drawn for the pane.
 
1493
 
 
1494
        :param bool `visible`: whether the minimize button should be visible or not.
 
1495
        """
 
1496
 
 
1497
        return self.SetFlag(self.buttonMinimize, visible)
 
1498
 
 
1499
 
 
1500
    def PinButton(self, visible=True):
 
1501
        """
 
1502
        Indicates that a pin button should be drawn for the pane.
 
1503
 
 
1504
        :param bool `visible`: whether the pin button should be visible or not.
 
1505
        """
 
1506
 
 
1507
        return self.SetFlag(self.buttonPin, visible)
 
1508
 
 
1509
 
 
1510
    def DestroyOnClose(self, b=True):
 
1511
        """
 
1512
        Indicates whether a pane should be destroyed when it is closed.
 
1513
 
 
1514
        Normally a pane is simply hidden when the close button is clicked. Setting
 
1515
        `b` to ``True`` will cause the window to be destroyed when the user clicks
 
1516
        the pane's close button.
 
1517
 
 
1518
        :param bool `b`: whether the pane should be destroyed when it is closed or not.
 
1519
        """
 
1520
 
 
1521
        return self.SetFlag(self.optionDestroyOnClose, b)
 
1522
 
 
1523
 
 
1524
    def TopDockable(self, b=True):
 
1525
        """
 
1526
        Indicates whether a pane can be docked at the top of the frame.
 
1527
 
 
1528
        :param bool `b`: whether the pane can be docked at the top or not.
 
1529
        """
 
1530
 
 
1531
        return self.SetFlag(self.optionTopDockable, b)
 
1532
 
 
1533
 
 
1534
    def BottomDockable(self, b=True):
 
1535
        """
 
1536
        Indicates whether a pane can be docked at the bottom of the frame.
 
1537
 
 
1538
        :param bool `b`: whether the pane can be docked at the bottom or not.
 
1539
        """
 
1540
 
 
1541
        return self.SetFlag(self.optionBottomDockable, b)
 
1542
 
 
1543
 
 
1544
    def LeftDockable(self, b=True):
 
1545
        """
 
1546
        Indicates whether a pane can be docked on the left of the frame.
 
1547
 
 
1548
        :param bool `b`: whether the pane can be docked at the left or not.
 
1549
        """
 
1550
 
 
1551
        return self.SetFlag(self.optionLeftDockable, b)
 
1552
 
 
1553
 
 
1554
    def RightDockable(self, b=True):
 
1555
        """
 
1556
        Indicates whether a pane can be docked on the right of the frame.
 
1557
 
 
1558
        :param bool `b`: whether the pane can be docked at the right or not.
 
1559
        """
 
1560
 
 
1561
        return self.SetFlag(self.optionRightDockable, b)
 
1562
 
 
1563
 
 
1564
    def Floatable(self, b=True):
 
1565
        """
 
1566
        Sets whether the user will be able to undock a pane and turn it
 
1567
        into a floating window.
 
1568
 
 
1569
        :param bool `b`: whether the pane can be floated or not.
 
1570
        """
 
1571
 
 
1572
        return self.SetFlag(self.optionFloatable, b)
 
1573
 
 
1574
 
 
1575
    def Movable(self, b=True):
 
1576
        """
 
1577
        Indicates whether a pane can be moved.
 
1578
 
 
1579
        :param bool `b`: whether the pane can be moved or not.
 
1580
        """
 
1581
 
 
1582
        return self.SetFlag(self.optionMovable, b)
 
1583
 
 
1584
 
 
1585
    def NotebookDockable(self, b=True):
 
1586
        """
 
1587
        Indicates whether a pane can be docked in an automatic :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
1588
 
 
1589
        :param bool `b`: whether the pane can be docked in a notebook or not.
 
1590
        """
 
1591
 
 
1592
        return self.SetFlag(self.optionNotebookDockable, b)
 
1593
 
 
1594
 
 
1595
    def DockFixed(self, b=True):
 
1596
        """
 
1597
        Causes the containing dock to have no resize sash. This is useful
 
1598
        for creating panes that span the entire width or height of a dock, but should
 
1599
        not be resizable in the other direction.
 
1600
 
 
1601
        :param bool `b`: whether the pane will have a resize sash or not.
 
1602
        """
 
1603
 
 
1604
        return self.SetFlag(self.optionDockFixed, b)
 
1605
 
 
1606
 
 
1607
    def Dockable(self, b=True):
 
1608
        """
 
1609
        Specifies whether a frame can be docked or not. It is the same as specifying
 
1610
        :meth:`TopDockable` . :meth:`BottomDockable` . :meth:`LeftDockable` . :meth:`RightDockable` .
 
1611
 
 
1612
        :param bool `b`: whether the frame can be docked or not.
 
1613
        """
 
1614
 
 
1615
        return self.TopDockable(b).BottomDockable(b).LeftDockable(b).RightDockable(b)
 
1616
 
 
1617
 
 
1618
    def TopSnappable(self, b=True):
 
1619
        """
 
1620
        Indicates whether a pane can be snapped at the top of the main frame.
 
1621
 
 
1622
        :param bool `b`: whether the pane can be snapped at the top of the main frame or not.
 
1623
        """
 
1624
 
 
1625
        return self.SetFlag(self.optionTopSnapped, b)
 
1626
 
 
1627
 
 
1628
    def BottomSnappable(self, b=True):
 
1629
        """
 
1630
        Indicates whether a pane can be snapped at the bottom of the main frame.
 
1631
 
 
1632
        :param bool `b`: whether the pane can be snapped at the bottom of the main frame or not.
 
1633
        """
 
1634
 
 
1635
        return self.SetFlag(self.optionBottomSnapped, b)
 
1636
 
 
1637
 
 
1638
    def LeftSnappable(self, b=True):
 
1639
        """
 
1640
        Indicates whether a pane can be snapped on the left of the main frame.
 
1641
 
 
1642
        :param bool `b`: whether the pane can be snapped at the left of the main frame or not.
 
1643
        """
 
1644
 
 
1645
        return self.SetFlag(self.optionLeftSnapped, b)
 
1646
 
 
1647
 
 
1648
    def RightSnappable(self, b=True):
 
1649
        """
 
1650
        Indicates whether a pane can be snapped on the right of the main frame.
 
1651
 
 
1652
        :param bool `b`: whether the pane can be snapped at the right of the main frame or not.
 
1653
        """
 
1654
 
 
1655
        return self.SetFlag(self.optionRightSnapped, b)
 
1656
 
 
1657
 
 
1658
    def Snappable(self, b=True):
 
1659
        """
 
1660
        Indicates whether a pane can be snapped on the main frame. This is
 
1661
        equivalent as calling :meth:`TopSnappable` . :meth:`BottomSnappable` . :meth:`LeftSnappable` . :meth:`RightSnappable` .
 
1662
 
 
1663
        :param bool `b`: whether the pane can be snapped on the main frame or not.
 
1664
        """
 
1665
 
 
1666
        return self.TopSnappable(b).BottomSnappable(b).LeftSnappable(b).RightSnappable(b)
 
1667
 
 
1668
 
 
1669
    def FlyOut(self, b=True):
 
1670
        """
 
1671
        Indicates whether a pane, when floating, has a "fly-out" effect
 
1672
        (i.e., floating panes which only show themselves when moused over).
 
1673
 
 
1674
        :param bool `b`: whether the pane can be snapped on the main frame or not.
 
1675
        """
 
1676
 
 
1677
        return self.SetFlag(self.optionFlyOut, b)
 
1678
 
 
1679
 
 
1680
    # Copy over the members that pertain to docking position
 
1681
    def SetDockPos(self, source):
 
1682
        """
 
1683
        Copies the `source` pane members that pertain to docking position to `self`.
 
1684
 
 
1685
        :param AuiPaneInfo `source`: the source pane from where to copy the attributes.
 
1686
        """
 
1687
 
 
1688
        self.dock_direction = source.dock_direction
 
1689
        self.dock_layer = source.dock_layer
 
1690
        self.dock_row = source.dock_row
 
1691
        self.dock_pos = source.dock_pos
 
1692
        self.dock_proportion = source.dock_proportion
 
1693
        self.floating_pos = wx.Point(*source.floating_pos)
 
1694
        self.floating_size = wx.Size(*source.floating_size)
 
1695
        self.rect = wx.Rect(*source.rect)
 
1696
 
 
1697
        return self
 
1698
 
 
1699
 
 
1700
    def DefaultPane(self):
 
1701
        """ Specifies that the pane should adopt the default pane settings. """
 
1702
 
 
1703
        state = self.state
 
1704
        state |= self.optionTopDockable | self.optionBottomDockable | \
 
1705
                 self.optionLeftDockable | self.optionRightDockable | \
 
1706
                 self.optionNotebookDockable | \
 
1707
                 self.optionFloatable | self.optionMovable | self.optionResizable | \
 
1708
                 self.optionCaption | self.optionPaneBorder | self.buttonClose
 
1709
 
 
1710
        self.state = state
 
1711
        return self
 
1712
 
 
1713
 
 
1714
    def CentrePane(self):
 
1715
        """
 
1716
        Specifies that the pane should adopt the default center pane settings.
 
1717
 
 
1718
        Centre panes usually do not have caption bars. This function provides an easy way of
 
1719
        preparing a pane to be displayed in the center dock position.
 
1720
        """
 
1721
 
 
1722
        return self.CenterPane()
 
1723
 
 
1724
 
 
1725
    def CenterPane(self):
 
1726
        """
 
1727
        Specifies that the pane should adopt the default center pane settings.
 
1728
 
 
1729
        Centre panes usually do not have caption bars. This function provides an easy way of
 
1730
        preparing a pane to be displayed in the center dock position.
 
1731
        """
 
1732
 
 
1733
        self.state = 0
 
1734
        return self.Center().PaneBorder().Resizable()
 
1735
 
 
1736
 
 
1737
    def ToolbarPane(self):
 
1738
        """ Specifies that the pane should adopt the default toolbar pane settings. """
 
1739
 
 
1740
        self.DefaultPane()
 
1741
        state = self.state
 
1742
 
 
1743
        state |= (self.optionToolbar | self.optionGripper)
 
1744
        state &= ~(self.optionResizable | self.optionCaption | self.optionCaptionLeft)
 
1745
 
 
1746
        if self.dock_layer == 0:
 
1747
            self.dock_layer = 10
 
1748
 
 
1749
        self.state = state
 
1750
 
 
1751
        return self
 
1752
 
 
1753
 
 
1754
    def Icon(self, icon):
 
1755
        """
 
1756
        Specifies whether an icon is drawn on the left of the caption text when
 
1757
        the pane is docked. If `icon` is ``None`` or :class:`NullIcon`, no icon is drawn on
 
1758
        the caption space.
 
1759
 
 
1760
        :param icon: an icon to draw on the caption space, or ``None``.
 
1761
        :type `icon`: :class:`Icon` or ``None``
 
1762
        """
 
1763
 
 
1764
        if icon is None:
 
1765
            icon = wx.NullIcon
 
1766
 
 
1767
        self.icon = icon
 
1768
        return self
 
1769
 
 
1770
 
 
1771
    def SetFlag(self, flag, option_state):
 
1772
        """
 
1773
        Turns the property given by `flag` on or off with the `option_state`
 
1774
        parameter.
 
1775
 
 
1776
        :param integer `flag`: the property to set;
 
1777
        :param bool `option_state`: either ``True`` or ``False``.
 
1778
        """
 
1779
 
 
1780
        state = self.state
 
1781
 
 
1782
        if option_state:
 
1783
            state |= flag
 
1784
        else:
 
1785
            state &= ~flag
 
1786
 
 
1787
        self.state = state
 
1788
 
 
1789
        if flag in [self.buttonClose, self.buttonMaximize, self.buttonMinimize, self.buttonPin]:
 
1790
            self.ResetButtons()
 
1791
 
 
1792
        return self
 
1793
 
 
1794
 
 
1795
    def HasFlag(self, flag):
 
1796
        """
 
1797
        Returns ``True`` if the the property specified by flag is active for the pane.
 
1798
 
 
1799
        :param integer `flag`: the property to check for activity.
 
1800
        """
 
1801
 
 
1802
        return (self.state & flag and [True] or [False])[0]
 
1803
 
 
1804
 
 
1805
    def ResetButtons(self):
 
1806
        """
 
1807
        Resets all the buttons and recreates them from scratch depending on the
 
1808
        :class:`AuiManager` flags.
 
1809
        """
 
1810
 
 
1811
        floating = self.HasFlag(self.optionFloating)
 
1812
        self.buttons = []
 
1813
 
 
1814
        if not floating and self.HasMinimizeButton():
 
1815
            button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
 
1816
            self.buttons.append(button)
 
1817
 
 
1818
        if not floating and self.HasMaximizeButton():
 
1819
            button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
 
1820
            self.buttons.append(button)
 
1821
 
 
1822
        if not floating and self.HasPinButton():
 
1823
            button = AuiPaneButton(AUI_BUTTON_PIN)
 
1824
            self.buttons.append(button)
 
1825
 
 
1826
        if self.HasCloseButton():
 
1827
            button = AuiPaneButton(AUI_BUTTON_CLOSE)
 
1828
            self.buttons.append(button)
 
1829
 
 
1830
 
 
1831
    def CountButtons(self):
 
1832
        """ Returns the number of visible buttons in the docked pane. """
 
1833
 
 
1834
        n = 0
 
1835
 
 
1836
        if self.HasCaption() or self.HasCaptionLeft():
 
1837
            if isinstance(wx.GetTopLevelParent(self.window), AuiFloatingFrame):
 
1838
                return 1
 
1839
 
 
1840
            if self.HasCloseButton():
 
1841
                n += 1
 
1842
            if self.HasMaximizeButton():
 
1843
                n += 1
 
1844
            if self.HasMinimizeButton():
 
1845
                n += 1
 
1846
            if self.HasPinButton():
 
1847
                n += 1
 
1848
 
 
1849
        return n
 
1850
 
 
1851
 
 
1852
    def IsHorizontal(self):
 
1853
        """ Returns ``True`` if the pane `dock_direction` is horizontal. """
 
1854
 
 
1855
        return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
 
1856
 
 
1857
    def IsVertical(self):
 
1858
        """ Returns ``True`` if the pane `dock_direction` is vertical. """
 
1859
 
 
1860
        return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
 
1861
 
 
1862
 
 
1863
# Null AuiPaneInfo reference
 
1864
NonePaneInfo = AuiPaneInfo()
 
1865
""" Null :class:`AuiPaneInfo` reference, an invalid instance of :class:`AuiPaneInfo`. """
 
1866
 
 
1867
 
 
1868
# ---------------------------------------------------------------------------- #
 
1869
 
 
1870
class AuiDockingGuide(wx.Frame):
 
1871
    """ Base class for :class:`AuiSingleDockingGuide` and :class:`AuiCenterDockingGuide`."""
 
1872
 
 
1873
    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
 
1874
                 size=wx.DefaultSize, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
 
1875
                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER, name="AuiDockingGuide"):
 
1876
        """
 
1877
        Default class constructor. Used internally, do not call it in your code!
 
1878
 
 
1879
        :param `parent`: the :class:`AuiManager` parent;
 
1880
        :param integer `id`: the window identifier. It may take a value of -1 to indicate a default value.
 
1881
        :param string `title`: the caption to be displayed on the frame's title bar.
 
1882
        :param Point `pos`: the window position. A value of (-1, -1) indicates a default position,
 
1883
         chosen by either the windowing system or wxPython, depending on platform.
 
1884
        :param Size `size`: the window size. A value of (-1, -1) indicates a default size, chosen by
 
1885
         either the windowing system or wxPython, depending on platform.
 
1886
        :param integer `style`: the window style.
 
1887
        :param string `name`: the name of the window. This parameter is used to associate a name with the
 
1888
         item, allowing the application user to set Motif resource values for individual windows.
 
1889
        """
 
1890
 
 
1891
        wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
 
1892
 
 
1893
 
 
1894
    def HitTest(self, x, y):
 
1895
        """
 
1896
        To be overridden by parent classes.
 
1897
 
 
1898
        :param integer `x`: the `x` mouse position;
 
1899
        :param integer `y`: the `y` mouse position.
 
1900
        """
 
1901
 
 
1902
        return 0
 
1903
 
 
1904
 
 
1905
    def ValidateNotebookDocking(self, valid):
 
1906
        """
 
1907
        To be overridden by parent classes.
 
1908
 
 
1909
        :param bool `valid`: whether a pane can be docked on top to another to form an automatic
 
1910
         :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
1911
        """
 
1912
 
 
1913
        return 0
 
1914
 
 
1915
# ============================================================================
 
1916
# implementation
 
1917
# ============================================================================
 
1918
 
 
1919
# ---------------------------------------------------------------------------
 
1920
# AuiDockingGuideWindow
 
1921
# ---------------------------------------------------------------------------
 
1922
 
 
1923
class AuiDockingGuideWindow(wx.Window):
 
1924
    """ Target class for :class:`AuiDockingGuide` and :class:`AuiCenterDockingGuide`. """
 
1925
 
 
1926
    def __init__(self, parent, rect, direction=0, center=False, useAero=False):
 
1927
        """
 
1928
        Default class constructor. Used internally, do not call it in your code!
 
1929
 
 
1930
        :param `parent`: the :class:`AuiManager` parent;
 
1931
        :param Rect `rect`: the window rect;
 
1932
        :param integer `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``,
 
1933
         ``wx.CENTER``;
 
1934
        :param bool `center`: whether the calling class is a :class:`AuiCenterDockingGuide`;
 
1935
        :param bool `useAero`: whether to use the new Aero-style bitmaps or Whidbey-style bitmaps
 
1936
         for the docking guide.
 
1937
        """
 
1938
 
 
1939
        wx.Window.__init__(self, parent, -1, rect.GetPosition(), rect.GetSize(), wx.NO_BORDER)
 
1940
 
 
1941
        self._direction = direction
 
1942
        self._center = center
 
1943
        self._valid = True
 
1944
        self._useAero = useAero
 
1945
 
 
1946
        self._bmp_unfocus, self._bmp_focus = GetDockingImage(direction, useAero, center)
 
1947
 
 
1948
        self._currentImage = self._bmp_unfocus
 
1949
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
 
1950
 
 
1951
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
 
1952
        self.Bind(wx.EVT_PAINT, self.OnPaint)
 
1953
 
 
1954
 
 
1955
    def SetValid(self, valid):
 
1956
        """
 
1957
        Sets the docking direction as valid or invalid.
 
1958
 
 
1959
        :param bool `valid`: whether the docking direction is allowed or not.
 
1960
        """
 
1961
 
 
1962
        self._valid = valid
 
1963
 
 
1964
 
 
1965
    def IsValid(self):
 
1966
        """ Returns whether the docking direction is valid. """
 
1967
 
 
1968
        return self._valid
 
1969
 
 
1970
 
 
1971
    def OnEraseBackground(self, event):
 
1972
        """
 
1973
        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiDockingGuideWindow`.
 
1974
 
 
1975
        :param `event`: a :class:`EraseEvent` to be processed.
 
1976
 
 
1977
        :note: This is intentionally empty to reduce flickering while drawing.
 
1978
        """
 
1979
 
 
1980
        pass
 
1981
 
 
1982
 
 
1983
    def DrawBackground(self, dc):
 
1984
        """
 
1985
        Draws the docking guide background.
 
1986
 
 
1987
        :param `dc`: a :class:`DC` device context object.
 
1988
        """
 
1989
 
 
1990
        rect = self.GetClientRect()
 
1991
 
 
1992
        dc.SetPen(wx.TRANSPARENT_PEN)
 
1993
        dc.SetBrush(wx.Brush(colourTargetBackground))
 
1994
        dc.DrawRectangleRect(rect)
 
1995
 
 
1996
        dc.SetPen(wx.Pen(colourTargetBorder))
 
1997
 
 
1998
        left = rect.GetLeft()
 
1999
        top = rect.GetTop()
 
2000
        right = rect.GetRight()
 
2001
        bottom = rect.GetBottom()
 
2002
 
 
2003
        if self._direction != wx.CENTER:
 
2004
 
 
2005
            if not self._center or self._direction != wx.BOTTOM:
 
2006
                dc.DrawLine(left, top, right+1, top)
 
2007
            if not self._center or self._direction != wx.RIGHT:
 
2008
                dc.DrawLine(left, top, left, bottom+1)
 
2009
            if not self._center or self._direction != wx.LEFT:
 
2010
                dc.DrawLine(right, top, right, bottom+1)
 
2011
            if not self._center or self._direction != wx.TOP:
 
2012
                dc.DrawLine(left, bottom, right+1, bottom)
 
2013
 
 
2014
            dc.SetPen(wx.Pen(colourTargetShade))
 
2015
 
 
2016
            if self._direction != wx.RIGHT:
 
2017
                dc.DrawLine(left + 1, top + 1, left + 1, bottom)
 
2018
            if self._direction != wx.BOTTOM:
 
2019
                dc.DrawLine(left + 1, top + 1, right, top + 1)
 
2020
 
 
2021
 
 
2022
    def DrawDottedLine(self, dc, point, length, vertical):
 
2023
        """
 
2024
        Draws a dotted line (not used if the docking guide images are ok).
 
2025
 
 
2026
        :param `dc`: a :class:`DC` device context object;
 
2027
        :param `point`: a :class:`Point` where to start drawing the dotted line;
 
2028
        :param integer `length`: the length of the dotted line;
 
2029
        :param bool `vertical`: whether it is a vertical docking guide window or not.
 
2030
        """
 
2031
 
 
2032
        for i in xrange(0, length, 2):
 
2033
            dc.DrawPoint(point.x, point.y)
 
2034
            if vertical:
 
2035
                point.y += 2
 
2036
            else:
 
2037
                point.x += 2
 
2038
 
 
2039
 
 
2040
    def DrawIcon(self, dc):
 
2041
        """
 
2042
        Draws the docking guide icon (not used if the docking guide images are ok).
 
2043
 
 
2044
        :param `dc`: a :class:`DC` device context object.
 
2045
        """
 
2046
 
 
2047
        rect = wx.Rect(*self.GetClientRect())
 
2048
        point = wx.Point()
 
2049
        length = 0
 
2050
 
 
2051
        rect.Deflate(4, 4)
 
2052
        dc.SetPen(wx.Pen(colourIconBorder))
 
2053
        dc.SetBrush(wx.Brush(colourIconBackground))
 
2054
        dc.DrawRectangleRect(rect)
 
2055
 
 
2056
        right1 = rect.GetRight() + 1
 
2057
        bottom1 = rect.GetBottom() + 1
 
2058
 
 
2059
        dc.SetPen(wx.Pen(colourIconShadow))
 
2060
        dc.DrawLine(rect.x + 1, bottom1, right1 + 1, bottom1)
 
2061
        dc.DrawLine(right1, rect.y + 1, right1, bottom1 + 1)
 
2062
 
 
2063
        rect.Deflate(1, 1)
 
2064
 
 
2065
        if self._direction == wx.TOP:
 
2066
            rect.height -= rect.height / 2
 
2067
            point = rect.GetBottomLeft()
 
2068
            length = rect.width
 
2069
 
 
2070
        elif self._direction == wx.LEFT:
 
2071
            rect.width -= rect.width / 2
 
2072
            point = rect.GetTopRight()
 
2073
            length = rect.height
 
2074
 
 
2075
        elif self._direction == wx.RIGHT:
 
2076
            rect.x += rect.width / 2
 
2077
            rect.width -= rect.width / 2
 
2078
            point = rect.GetTopLeft()
 
2079
            length = rect.height
 
2080
 
 
2081
        elif self._direction == wx.BOTTOM:
 
2082
            rect.y += rect.height / 2
 
2083
            rect.height -= rect.height / 2
 
2084
            point = rect.GetTopLeft()
 
2085
            length = rect.width
 
2086
 
 
2087
        elif self._direction == wx.CENTER:
 
2088
            rect.Deflate(1, 1)
 
2089
            point = rect.GetTopLeft()
 
2090
            length = rect.width
 
2091
 
 
2092
        dc.GradientFillLinear(rect, colourIconDockingPart1,
 
2093
                              colourIconDockingPart2, self._direction)
 
2094
 
 
2095
        dc.SetPen(wx.Pen(colourIconBorder))
 
2096
 
 
2097
        if self._direction == wx.CENTER:
 
2098
            self.DrawDottedLine(dc, rect.GetTopLeft(), rect.width, False)
 
2099
            self.DrawDottedLine(dc, rect.GetTopLeft(), rect.height, True)
 
2100
            self.DrawDottedLine(dc, rect.GetBottomLeft(), rect.width, False)
 
2101
            self.DrawDottedLine(dc, rect.GetTopRight(), rect.height, True)
 
2102
 
 
2103
        elif self._direction in [wx.TOP, wx.BOTTOM]:
 
2104
            self.DrawDottedLine(dc, point, length, False)
 
2105
 
 
2106
        else:
 
2107
            self.DrawDottedLine(dc, point, length, True)
 
2108
 
 
2109
 
 
2110
    def DrawArrow(self, dc):
 
2111
        """
 
2112
        Draws the docking guide arrow icon (not used if the docking guide images are ok).
 
2113
 
 
2114
        :param `dc`: a :class:`DC` device context object.
 
2115
        """
 
2116
 
 
2117
        rect = self.GetClientRect()
 
2118
        point = wx.Point()
 
2119
 
 
2120
        point.x = (rect.GetLeft() + rect.GetRight()) / 2
 
2121
        point.y = (rect.GetTop() + rect.GetBottom()) / 2
 
2122
        rx, ry = wx.Size(), wx.Size()
 
2123
 
 
2124
        if self._direction == wx.TOP:
 
2125
            rx = wx.Size(1, 0)
 
2126
            ry = wx.Size(0, 1)
 
2127
 
 
2128
        elif self._direction == wx.LEFT:
 
2129
            rx = wx.Size(0, -1)
 
2130
            ry = wx.Size(1, 0)
 
2131
 
 
2132
        elif self._direction == wx.RIGHT:
 
2133
            rx = wx.Size(0, 1)
 
2134
            ry = wx.Size(-1, 0)
 
2135
 
 
2136
        elif self._direction == wx.BOTTOM:
 
2137
            rx = wx.Size(-1, 0)
 
2138
            ry = wx.Size(0, -1)
 
2139
 
 
2140
        point.x += ry.x*3
 
2141
        point.y += ry.y*3
 
2142
 
 
2143
        dc.SetPen(wx.Pen(colourIconArrow))
 
2144
 
 
2145
        for i in xrange(4):
 
2146
            pt1 = wx.Point(point.x - rx.x*i, point.y - rx.y*i)
 
2147
            pt2 = wx.Point(point.x + rx.x*(i+1), point.y + rx.y*(i+1))
 
2148
            dc.DrawLinePoint(pt1, pt2)
 
2149
            point.x += ry.x
 
2150
            point.y += ry.y
 
2151
 
 
2152
 
 
2153
    def OnPaint(self, event):
 
2154
        """
 
2155
        Handles the ``wx.EVT_PAINT`` event for :class:`AuiDockingGuideWindow`.
 
2156
 
 
2157
        :param `event`: a :class:`PaintEvent` to be processed.
 
2158
        """
 
2159
 
 
2160
        dc = wx.AutoBufferedPaintDC(self)
 
2161
        if self._currentImage.IsOk() and self._valid:
 
2162
            dc.DrawBitmap(self._currentImage, 0, 0, True)
 
2163
        else:
 
2164
            self.Draw(dc)
 
2165
 
 
2166
 
 
2167
    def Draw(self, dc):
 
2168
        """
 
2169
        Draws the whole docking guide window (not used if the docking guide images are ok).
 
2170
 
 
2171
        :param `dc`: a :class:`DC` device context object.
 
2172
        """
 
2173
 
 
2174
        self.DrawBackground(dc)
 
2175
 
 
2176
        if self._valid:
 
2177
            self.DrawIcon(dc)
 
2178
            self.DrawArrow(dc)
 
2179
 
 
2180
 
 
2181
    def UpdateDockGuide(self, pos):
 
2182
        """
 
2183
        Updates the docking guide images depending on the mouse position, using focused
 
2184
        images if the mouse is inside the docking guide or unfocused images if it is
 
2185
        outside.
 
2186
 
 
2187
        :param `pos`: a :class:`Point` mouse position.
 
2188
        """
 
2189
 
 
2190
        inside = self.GetScreenRect().Contains(pos)
 
2191
 
 
2192
        if inside:
 
2193
            image = self._bmp_focus
 
2194
        else:
 
2195
            image = self._bmp_unfocus
 
2196
 
 
2197
        if image != self._currentImage:
 
2198
            self._currentImage = image
 
2199
            self.Refresh()
 
2200
            self.Update()
 
2201
 
 
2202
 
 
2203
# ---------------------------------------------------------------------------
 
2204
# AuiSingleDockingGuide
 
2205
# ---------------------------------------------------------------------------
 
2206
 
 
2207
class AuiSingleDockingGuide(AuiDockingGuide):
 
2208
    """ A docking guide window for single docking hint (not diamond-shaped HUD). """
 
2209
 
 
2210
    def __init__(self, parent, direction=0):
 
2211
        """
 
2212
        Default class constructor. Used internally, do not call it in your code!
 
2213
 
 
2214
        :param `parent`: the :class:`AuiManager` parent;
 
2215
        :param integer `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``.
 
2216
        """
 
2217
 
 
2218
        self._direction = direction
 
2219
 
 
2220
        style = wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | \
 
2221
                wx.FRAME_NO_TASKBAR | wx.NO_BORDER
 
2222
 
 
2223
        # Use of FRAME_SHAPED on wxMac causes the frame to be visible
 
2224
        # breaking the docking hints.
 
2225
        if wx.Platform != '__WXMAC__':
 
2226
            style |= wx.FRAME_SHAPED
 
2227
 
 
2228
        AuiDockingGuide.__init__(self, parent, style=style, name="auiSingleDockTarget")
 
2229
 
 
2230
        self.Hide()
 
2231
 
 
2232
        useAero = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES
 
2233
        useWhidbey = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES
 
2234
 
 
2235
        self._useAero = useAero or useWhidbey
 
2236
        self._valid = True
 
2237
 
 
2238
        if useAero:
 
2239
            sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
 
2240
        elif useWhidbey:
 
2241
            sizeX, sizeY = whidbeySizeX, whidbeySizeY
 
2242
        else:
 
2243
            sizeX, sizeY = guideSizeX, guideSizeY
 
2244
 
 
2245
        if direction not in [wx.TOP, wx.BOTTOM]:
 
2246
            sizeX, sizeY = sizeY, sizeX
 
2247
 
 
2248
        if self._useAero:
 
2249
            self.CreateShapesWithStyle(useWhidbey)
 
2250
 
 
2251
            if wx.Platform == "__WXGTK__":
 
2252
                self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
 
2253
            else:
 
2254
                self.SetGuideShape()
 
2255
 
 
2256
            self.SetSize(self.region.GetBox().GetSize())
 
2257
        else:
 
2258
            self.SetSize((sizeX, sizeY))
 
2259
 
 
2260
        self.rect = wx.Rect(0, 0, sizeX, sizeY)
 
2261
 
 
2262
        if self._useAero:
 
2263
            useAero = (useWhidbey and [2] or [1])[0]
 
2264
        else:
 
2265
            useAero = 0
 
2266
 
 
2267
        self.target = AuiDockingGuideWindow(self, self.rect, direction, False, useAero)
 
2268
 
 
2269
 
 
2270
    def CreateShapesWithStyle(self, useWhidbey):
 
2271
        """
 
2272
        Creates the docking guide window shape based on which docking bitmaps are used.
 
2273
 
 
2274
        :param bool `useWhidbey`: if ``True``, use Whidbey-style bitmaps; if ``False``, use the
 
2275
         Aero-style bitmaps.
 
2276
         """
 
2277
 
 
2278
        sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
 
2279
        if useWhidbey:
 
2280
            sizeX, sizeY = whidbeySizeX, whidbeySizeY
 
2281
 
 
2282
        if self._direction not in [wx.TOP, wx.BOTTOM]:
 
2283
            sizeX, sizeY = sizeY, sizeX
 
2284
 
 
2285
        useAero = (useWhidbey and [2] or [1])[0]
 
2286
        bmp, dummy = GetDockingImage(self._direction, useAero, False)
 
2287
        region = wx.RegionFromBitmap(bmp)
 
2288
 
 
2289
        self.region = region
 
2290
 
 
2291
 
 
2292
    def AeroMove(self, pos):
 
2293
        """
 
2294
        Moves the docking window to the new position. Overridden in children classes.
 
2295
 
 
2296
        :param Point `pos`: the new docking guide position.
 
2297
        """
 
2298
 
 
2299
        pass
 
2300
 
 
2301
 
 
2302
    def SetGuideShape(self, event=None):
 
2303
        """
 
2304
        Sets the correct shape for the docking guide window.
 
2305
 
 
2306
        :param `event`: on wxGTK, a :class:`WindowCreateEvent` event to process.
 
2307
        """
 
2308
 
 
2309
        self.SetShape(self.region)
 
2310
 
 
2311
        if event is not None:
 
2312
            # Skip the event on wxGTK
 
2313
            event.Skip()
 
2314
            wx.CallAfter(wx.SafeYield, self, True)
 
2315
 
 
2316
 
 
2317
    def SetShape(self, region):
 
2318
        """
 
2319
        If the platform supports it, sets the shape of the window to that depicted by `region`.
 
2320
        The system will not display or respond to any mouse event for the pixels that lie
 
2321
        outside of the region. To reset the window to the normal rectangular shape simply call
 
2322
        :meth:`SetShape` again with an empty region.
 
2323
 
 
2324
        :param Region `region`: the shape of the frame.
 
2325
 
 
2326
        :note: Overridden for wxMAC.
 
2327
        """
 
2328
 
 
2329
        if wx.Platform == '__WXMAC__':
 
2330
            # HACK so we don't crash when SetShape is called
 
2331
            return
 
2332
        else:
 
2333
            super(AuiSingleDockingGuide, self).SetShape(region)
 
2334
 
 
2335
 
 
2336
    def SetValid(self, valid):
 
2337
        """
 
2338
        Sets the docking direction as valid or invalid.
 
2339
 
 
2340
        :param bool `valid`: whether the docking direction is allowed or not.
 
2341
        """
 
2342
 
 
2343
        self._valid = valid
 
2344
 
 
2345
 
 
2346
    def IsValid(self):
 
2347
        """ Returns whether the docking direction is valid. """
 
2348
 
 
2349
        return self._valid
 
2350
 
 
2351
 
 
2352
    def UpdateDockGuide(self, pos):
 
2353
        """
 
2354
        Updates the docking guide images depending on the mouse position, using focused
 
2355
        images if the mouse is inside the docking guide or unfocused images if it is
 
2356
        outside.
 
2357
 
 
2358
        :param Point `pos`: the mouse position.
 
2359
        """
 
2360
 
 
2361
        self.target.UpdateDockGuide(pos)
 
2362
 
 
2363
 
 
2364
    def HitTest(self, x, y):
 
2365
        """
 
2366
        Checks if the mouse position is inside the target window rect.
 
2367
 
 
2368
        :param integer `x`: the `x` mouse position;
 
2369
        :param integer `y`: the `y` mouse position.
 
2370
        """
 
2371
 
 
2372
        if self.target.GetScreenRect().Contains((x, y)):
 
2373
            return wx.ALL
 
2374
 
 
2375
        return -1
 
2376
 
 
2377
 
 
2378
# ---------------------------------------------------------------------------
 
2379
# AuiCenterDockingGuide
 
2380
# ---------------------------------------------------------------------------
 
2381
 
 
2382
class AuiCenterDockingGuide(AuiDockingGuide):
 
2383
    """ A docking guide window for multiple docking hint (diamond-shaped HUD). """
 
2384
 
 
2385
    def __init__(self, parent):
 
2386
        """
 
2387
        Default class constructor.
 
2388
        Used internally, do not call it in your code!
 
2389
 
 
2390
        :param `parent`: the :class:`AuiManager` parent.
 
2391
        """
 
2392
 
 
2393
        AuiDockingGuide.__init__(self, parent, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
 
2394
                                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED,
 
2395
                                 name="auiCenterDockTarget")
 
2396
 
 
2397
        self.Hide()
 
2398
 
 
2399
        self.CreateShapesWithStyle()
 
2400
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
 
2401
 
 
2402
        if wx.Platform == "__WXGTK__":
 
2403
            self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
 
2404
        else:
 
2405
            self.SetGuideShape()
 
2406
 
 
2407
        self.SetSize(self.region.GetBox().GetSize())
 
2408
 
 
2409
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
 
2410
        self.Bind(wx.EVT_PAINT, self.OnPaint)
 
2411
 
 
2412
 
 
2413
    def CreateShapesWithStyle(self):
 
2414
        """ Creates the docking guide window shape based on which docking bitmaps are used. """
 
2415
 
 
2416
        useAero = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES) != 0
 
2417
        useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
 
2418
 
 
2419
        self._useAero = 0
 
2420
        if useAero:
 
2421
            self._useAero = 1
 
2422
        elif useWhidbey:
 
2423
            self._useAero = 2
 
2424
 
 
2425
        if useAero:
 
2426
            sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
 
2427
        elif useWhidbey:
 
2428
            sizeX, sizeY = whidbeySizeX, whidbeySizeY
 
2429
        else:
 
2430
            sizeX, sizeY = guideSizeX, guideSizeY
 
2431
 
 
2432
        rectLeft = wx.Rect(0, sizeY, sizeY, sizeX)
 
2433
        rectTop = wx.Rect(sizeY, 0, sizeX, sizeY)
 
2434
        rectRight = wx.Rect(sizeY+sizeX, sizeY, sizeY, sizeX)
 
2435
        rectBottom = wx.Rect(sizeY, sizeX + sizeY, sizeX, sizeY)
 
2436
        rectCenter = wx.Rect(sizeY, sizeY, sizeX, sizeX)
 
2437
 
 
2438
        if not self._useAero:
 
2439
 
 
2440
            self.targetLeft = AuiDockingGuideWindow(self, rectLeft, wx.LEFT, True, useAero)
 
2441
            self.targetTop = AuiDockingGuideWindow(self, rectTop, wx.TOP, True, useAero)
 
2442
            self.targetRight = AuiDockingGuideWindow(self, rectRight, wx.RIGHT, True, useAero)
 
2443
            self.targetBottom = AuiDockingGuideWindow(self, rectBottom, wx.BOTTOM, True, useAero)
 
2444
            self.targetCenter = AuiDockingGuideWindow(self, rectCenter, wx.CENTER, True, useAero)
 
2445
 
 
2446
 
 
2447
            # top-left diamond
 
2448
            tld = [wx.Point(rectTop.x, rectTop.y+rectTop.height-8),
 
2449
                   wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y),
 
2450
                   rectTop.GetBottomLeft()]
 
2451
            # bottom-left diamond
 
2452
            bld = [wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y+rectLeft.height),
 
2453
                   wx.Point(rectBottom.x, rectBottom.y+8),
 
2454
                   rectBottom.GetTopLeft()]
 
2455
            # top-right diamond
 
2456
            trd = [wx.Point(rectTop.x+rectTop.width, rectTop.y+rectTop.height-8),
 
2457
                   wx.Point(rectRight.x+8, rectRight.y),
 
2458
                   rectRight.GetTopLeft()]
 
2459
            # bottom-right diamond
 
2460
            brd = [wx.Point(rectRight.x+8, rectRight.y+rectRight.height),
 
2461
                   wx.Point(rectBottom.x+rectBottom.width, rectBottom.y+8),
 
2462
                   rectBottom.GetTopRight()]
 
2463
 
 
2464
            self._triangles = [tld[0:2], bld[0:2],
 
2465
                               [wx.Point(rectTop.x+rectTop.width-1, rectTop.y+rectTop.height-8),
 
2466
                                wx.Point(rectRight.x+7, rectRight.y)],
 
2467
                               [wx.Point(rectRight.x+7, rectRight.y+rectRight.height),
 
2468
                                wx.Point(rectBottom.x+rectBottom.width-1, rectBottom.y+8)]]
 
2469
 
 
2470
            region = wx.Region()
 
2471
            region.UnionRect(rectLeft)
 
2472
            region.UnionRect(rectTop)
 
2473
            region.UnionRect(rectRight)
 
2474
            region.UnionRect(rectBottom)
 
2475
            region.UnionRect(rectCenter)
 
2476
            region.UnionRegion(wx.RegionFromPoints(tld))
 
2477
            region.UnionRegion(wx.RegionFromPoints(bld))
 
2478
            region.UnionRegion(wx.RegionFromPoints(trd))
 
2479
            region.UnionRegion(wx.RegionFromPoints(brd))
 
2480
 
 
2481
        elif useAero:
 
2482
 
 
2483
            self._aeroBmp = aero_dock_pane.GetBitmap()
 
2484
            region = wx.RegionFromBitmap(self._aeroBmp)
 
2485
 
 
2486
            self._allAeroBmps = [aero_dock_pane_left.GetBitmap(), aero_dock_pane_top.GetBitmap(),
 
2487
                                 aero_dock_pane_right.GetBitmap(), aero_dock_pane_bottom.GetBitmap(),
 
2488
                                 aero_dock_pane_center.GetBitmap(), aero_dock_pane.GetBitmap()]
 
2489
            self._deniedBitmap = aero_denied.GetBitmap()
 
2490
            self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter]
 
2491
            self._valid = True
 
2492
 
 
2493
        elif useWhidbey:
 
2494
 
 
2495
            self._aeroBmp = whidbey_dock_pane.GetBitmap()
 
2496
            region = wx.RegionFromBitmap(self._aeroBmp)
 
2497
 
 
2498
            self._allAeroBmps = [whidbey_dock_pane_left.GetBitmap(), whidbey_dock_pane_top.GetBitmap(),
 
2499
                                 whidbey_dock_pane_right.GetBitmap(), whidbey_dock_pane_bottom.GetBitmap(),
 
2500
                                 whidbey_dock_pane_center.GetBitmap(), whidbey_dock_pane.GetBitmap()]
 
2501
            self._deniedBitmap = whidbey_denied.GetBitmap()
 
2502
            self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter]
 
2503
            self._valid = True
 
2504
 
 
2505
 
 
2506
        self.region = region
 
2507
 
 
2508
 
 
2509
    def SetGuideShape(self, event=None):
 
2510
        """
 
2511
        Sets the correct shape for the docking guide window.
 
2512
 
 
2513
        :param `event`: on wxGTK, a :class:`WindowCreateEvent` event to process.
 
2514
        """
 
2515
 
 
2516
        self.SetShape(self.region)
 
2517
 
 
2518
        if event is not None:
 
2519
            # Skip the event on wxGTK
 
2520
            event.Skip()
 
2521
            wx.CallAfter(wx.SafeYield, self, True)
 
2522
 
 
2523
 
 
2524
    def UpdateDockGuide(self, pos):
 
2525
        """
 
2526
        Updates the docking guides images depending on the mouse position, using focused
 
2527
        images if the mouse is inside the docking guide or unfocused images if it is
 
2528
        outside.
 
2529
 
 
2530
        :param Point `pos`: the mouse position.
 
2531
        """
 
2532
 
 
2533
        if not self._useAero:
 
2534
            for target in self.GetChildren():
 
2535
                target.UpdateDockGuide(pos)
 
2536
        else:
 
2537
            lenRects = len(self._aeroRects)
 
2538
            for indx, rect in enumerate(self._aeroRects):
 
2539
                if rect.Contains(pos):
 
2540
                    if self._allAeroBmps[indx] != self._aeroBmp:
 
2541
                        if indx < lenRects - 1 or (indx == lenRects - 1 and self._valid):
 
2542
                            self._aeroBmp = self._allAeroBmps[indx]
 
2543
                            self.Refresh()
 
2544
                        else:
 
2545
                            self._aeroBmp = self._allAeroBmps[-1]
 
2546
                            self.Refresh()
 
2547
 
 
2548
                    return
 
2549
 
 
2550
            if self._aeroBmp != self._allAeroBmps[-1]:
 
2551
                self._aeroBmp = self._allAeroBmps[-1]
 
2552
                self.Refresh()
 
2553
 
 
2554
 
 
2555
    def HitTest(self, x, y):
 
2556
        """
 
2557
        Checks if the mouse position is inside the target windows rect.
 
2558
 
 
2559
        :param integer `x`: the `x` mouse position;
 
2560
        :param integer `y`: the `y` mouse position.
 
2561
        """
 
2562
 
 
2563
        if not self._useAero:
 
2564
            if self.targetLeft.GetScreenRect().Contains((x, y)):
 
2565
                return wx.LEFT
 
2566
            if self.targetTop.GetScreenRect().Contains((x, y)):
 
2567
                return wx.UP
 
2568
            if self.targetRight.GetScreenRect().Contains((x, y)):
 
2569
                return wx.RIGHT
 
2570
            if self.targetBottom.GetScreenRect().Contains((x, y)):
 
2571
                return wx.DOWN
 
2572
            if self.targetCenter.IsValid() and self.targetCenter.GetScreenRect().Contains((x, y)):
 
2573
                return wx.CENTER
 
2574
        else:
 
2575
            constants = [wx.LEFT, wx.UP, wx.RIGHT, wx.DOWN, wx.CENTER]
 
2576
            lenRects = len(self._aeroRects)
 
2577
            for indx, rect in enumerate(self._aeroRects):
 
2578
                if rect.Contains((x, y)):
 
2579
                    if indx < lenRects or (indx == lenRects-1 and self._valid):
 
2580
                        return constants[indx]
 
2581
 
 
2582
        return -1
 
2583
 
 
2584
 
 
2585
    def ValidateNotebookDocking(self, valid):
 
2586
        """
 
2587
        Sets whether a pane can be docked on top of another to create an automatic
 
2588
        :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
2589
 
 
2590
        :param bool `valid`: whether a pane can be docked on top to another to form an automatic
 
2591
         :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
2592
        """
 
2593
 
 
2594
        if not self._useAero:
 
2595
            if self.targetCenter.IsValid() != valid:
 
2596
                self.targetCenter.SetValid(valid)
 
2597
                self.targetCenter.Refresh()
 
2598
        else:
 
2599
            if self._valid != valid:
 
2600
                self._valid = valid
 
2601
                self.Refresh()
 
2602
 
 
2603
 
 
2604
    def AeroMove(self, pos):
 
2605
        """
 
2606
        Moves the docking guide window to the new position.
 
2607
 
 
2608
        :param Point `pos`: the new docking guide position.
 
2609
        """
 
2610
 
 
2611
        if not self._useAero:
 
2612
            return
 
2613
 
 
2614
        useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
 
2615
 
 
2616
        if useWhidbey:
 
2617
            sizeX, sizeY = whidbeySizeX, whidbeySizeY
 
2618
        else:
 
2619
            sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
 
2620
 
 
2621
        size = self.GetSize()
 
2622
 
 
2623
        leftRect, topRect, rightRect, bottomRect, centerRect = self._aeroRects
 
2624
        thePos = pos + wx.Point((size.x-sizeY)/2, (size.y-sizeX)/2)
 
2625
 
 
2626
        centerRect.SetPosition(thePos)
 
2627
 
 
2628
        leftRect.SetPosition(thePos + wx.Point(-sizeY, 0))
 
2629
        topRect.SetPosition(thePos + wx.Point(0, -sizeY))
 
2630
        rightRect.SetPosition(thePos + wx.Point(sizeX, 0))
 
2631
        bottomRect.SetPosition(thePos + wx.Point(0, sizeX))
 
2632
 
 
2633
 
 
2634
    def OnEraseBackground(self, event):
 
2635
        """
 
2636
        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiCenterDockingGuide`.
 
2637
 
 
2638
        :param `event`: :class:`EraseEvent` to be processed.
 
2639
 
 
2640
        :note: This is intentionally empty to reduce flickering while drawing.
 
2641
        """
 
2642
 
 
2643
        pass
 
2644
 
 
2645
 
 
2646
    def OnPaint(self, event):
 
2647
        """
 
2648
        Handles the ``wx.EVT_PAINT`` event for :class:`AuiCenterDockingGuide`.
 
2649
 
 
2650
        :param `event`: a :class:`PaintEvent` to be processed.
 
2651
        """
 
2652
 
 
2653
        dc = wx.AutoBufferedPaintDC(self)
 
2654
 
 
2655
        if self._useAero:
 
2656
            dc.SetBrush(wx.TRANSPARENT_BRUSH)
 
2657
            dc.SetPen(wx.TRANSPARENT_PEN)
 
2658
        else:
 
2659
            dc.SetBrush(wx.Brush(colourTargetBackground))
 
2660
            dc.SetPen(wx.Pen(colourTargetBorder))
 
2661
 
 
2662
        rect = self.GetClientRect()
 
2663
        dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
 
2664
 
 
2665
        if self._useAero:
 
2666
            dc.DrawBitmap(self._aeroBmp, 0, 0, True)
 
2667
            if not self._valid:
 
2668
                diff = (self._useAero == 2 and [1] or [0])[0]
 
2669
                bmpX, bmpY = self._deniedBitmap.GetWidth(), self._deniedBitmap.GetHeight()
 
2670
                xPos, yPos = (rect.x + (rect.width)/2 - bmpX/2), (rect.y + (rect.height)/2 - bmpY/2)
 
2671
                dc.DrawBitmap(self._deniedBitmap, xPos+1, yPos+diff, True)
 
2672
 
 
2673
            return
 
2674
 
 
2675
        dc.SetPen(wx.Pen(colourTargetBorder, 2))
 
2676
        for pts in self._triangles:
 
2677
            dc.DrawLinePoint(pts[0], pts[1])
 
2678
 
 
2679
 
 
2680
# ----------------------------------------------------------------------------
 
2681
# AuiDockingHintWindow
 
2682
# ----------------------------------------------------------------------------
 
2683
 
 
2684
class AuiDockingHintWindow(wx.Frame):
 
2685
    """ The original wxAUI docking window hint. """
 
2686
 
 
2687
    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
 
2688
                 size=wx.Size(1, 1), style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT |
 
2689
                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED,
 
2690
                 name="auiHintWindow"):
 
2691
        """
 
2692
        Default class constructor. Used internally, do not call it in your code!
 
2693
 
 
2694
        :param `parent`: the :class:`AuiManager` parent;
 
2695
        :param integer `id`: the window identifier. It may take a value of -1 to indicate a default value.
 
2696
        :param string `title`: the caption to be displayed on the frame's title bar;
 
2697
        :param Point `pos`: the window position. A value of (-1, -1) indicates a default position,
 
2698
         chosen by either the windowing system or wxPython, depending on platform;
 
2699
        :param Size `size`: the window size. A value of (-1, -1) indicates a default size, chosen by
 
2700
         either the windowing system or wxPython, depending on platform;
 
2701
        :param integer `style`: the window style;
 
2702
        :param string `name`: the name of the window. This parameter is used to associate a name with the
 
2703
         item, allowing the application user to set Motif resource values for individual windows.
 
2704
        """
 
2705
        if wx.Platform == '__WXMAC__' and style & wx.FRAME_SHAPED:
 
2706
            # Having the shaped frame causes the frame to not be visible
 
2707
            # with the transparent style hints.
 
2708
            style -= wx.FRAME_SHAPED
 
2709
 
 
2710
        wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
 
2711
 
 
2712
        self._blindMode = False
 
2713
 
 
2714
        self._art = parent.GetEventHandler().GetArtProvider()
 
2715
        background = self._art.GetColour(AUI_DOCKART_HINT_WINDOW_COLOUR)
 
2716
        self.SetBackgroundColour(background)
 
2717
 
 
2718
        # Can't set background colour on a frame on wxMac
 
2719
        # so add a panel to set the colour on.
 
2720
        if wx.Platform == '__WXMAC__':
 
2721
            sizer = wx.BoxSizer(wx.HORIZONTAL)
 
2722
            self.panel = wx.Panel(self)
 
2723
            sizer.Add(self.panel, 1, wx.EXPAND)
 
2724
            self.SetSizer(sizer)
 
2725
            self.panel.SetBackgroundColour(background)
 
2726
        else:
 
2727
            self.Bind(wx.EVT_PAINT, self.OnPaint)
 
2728
 
 
2729
        self.Bind(wx.EVT_SIZE, self.OnSize)
 
2730
 
 
2731
 
 
2732
    def MakeVenetianBlinds(self):
 
2733
        """
 
2734
        Creates the "venetian blind" effect if :class:`AuiManager` has the ``AUI_MGR_VENETIAN_BLINDS_HINT``
 
2735
        flag set.
 
2736
        """
 
2737
 
 
2738
        amount = 128
 
2739
        size = self.GetClientSize()
 
2740
        region = wx.Region(0, 0, size.x, 1)
 
2741
 
 
2742
        for y in xrange(size.y):
 
2743
 
 
2744
            # Reverse the order of the bottom 4 bits
 
2745
            j = (y & 8 and [1] or [0])[0] | (y & 4 and [2] or [0])[0] | \
 
2746
                (y & 2 and [4] or [0])[0] | (y & 1 and [8] or [0])[0]
 
2747
 
 
2748
            if 16*j+8 < amount:
 
2749
                region.Union(0, y, size.x, 1)
 
2750
 
 
2751
        self.SetShape(region)
 
2752
 
 
2753
 
 
2754
    def SetBlindMode(self, agwFlags):
 
2755
        """
 
2756
        Sets whether venetian blinds or transparent hints will be shown as docking hint.
 
2757
        This depends on the :class:`AuiManager` flags.
 
2758
 
 
2759
        :param integer `agwFlags`: the :class:`AuiManager` flags.
 
2760
        """
 
2761
 
 
2762
        self._blindMode = (agwFlags & AUI_MGR_VENETIAN_BLINDS_HINT) != 0
 
2763
 
 
2764
        if self._blindMode or not self.CanSetTransparent():
 
2765
            self.MakeVenetianBlinds()
 
2766
            self.SetTransparent(255)
 
2767
 
 
2768
        else:
 
2769
            self.SetShape(wx.Region())
 
2770
            if agwFlags & AUI_MGR_HINT_FADE == 0:
 
2771
                self.SetTransparent(80)
 
2772
            else:
 
2773
                self.SetTransparent(0)
 
2774
 
 
2775
 
 
2776
    def SetShape(self, region):
 
2777
        """
 
2778
        If the platform supports it, sets the shape of the window to that depicted by `region`.
 
2779
        The system will not display or respond to any mouse event for the pixels that lie
 
2780
        outside of the region. To reset the window to the normal rectangular shape simply call
 
2781
        :meth:`SetShape` again with an empty region.
 
2782
 
 
2783
        :param Region `region`: the shape of the frame.
 
2784
 
 
2785
        :note: Overridden for wxMAC.
 
2786
        """
 
2787
 
 
2788
        if wx.Platform == '__WXMAC__':
 
2789
            # HACK so we don't crash when SetShape is called
 
2790
            return
 
2791
        else:
 
2792
            super(AuiDockingHintWindow, self).SetShape(region)
 
2793
 
 
2794
 
 
2795
    def Show(self, show=True):
 
2796
        """
 
2797
        Show the hint window.
 
2798
 
 
2799
        :param bool `show`: whether to show or hide the hint docking window.
 
2800
        """
 
2801
 
 
2802
        background = self._art.GetColour(AUI_DOCKART_HINT_WINDOW_COLOUR)
 
2803
 
 
2804
        if wx.Platform == '__WXMAC__':
 
2805
            self.panel.SetBackgroundColour(background)
 
2806
        else:
 
2807
            self.SetBackgroundColour(background)
 
2808
 
 
2809
        super(AuiDockingHintWindow, self).Show(show)
 
2810
        self.Refresh()
 
2811
 
 
2812
        if wx.Platform == '__WXMAC__':
 
2813
            # Need to manually do layout since its a borderless frame.
 
2814
            self.Layout()
 
2815
 
 
2816
 
 
2817
    def OnSize(self, event):
 
2818
        """
 
2819
        Handles the ``wx.EVT_SIZE`` event for :class:`AuiDockingHintWindow`.
 
2820
 
 
2821
        :param `event`: a :class:`SizeEvent` to be processed.
 
2822
        """
 
2823
 
 
2824
        if self._blindMode or not self.CanSetTransparent():
 
2825
            self.MakeVenetianBlinds()
 
2826
 
 
2827
        self.Refresh()
 
2828
 
 
2829
 
 
2830
    def OnPaint(self, event):
 
2831
        """
 
2832
        Handles the ``wx.EVT_PAINT`` event for :class:`AuiDockingHintWindow`.
 
2833
 
 
2834
        :param `event`: an instance of :class:`PaintEvent` to be processed.
 
2835
        """
 
2836
 
 
2837
        rect = wx.RectPS(wx.Point(0, 0), self.GetSize())
 
2838
 
 
2839
        dc = wx.PaintDC(self)
 
2840
        event.Skip()
 
2841
 
 
2842
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
 
2843
        dc.SetPen(wx.Pen(wx.Colour(60, 60, 60), 5))
 
2844
        rect.Deflate(1, 1)
 
2845
        dc.DrawRectangleRect(rect)
 
2846
 
 
2847
 
 
2848
# ---------------------------------------------------------------------------- #
 
2849
 
 
2850
# -- AuiFloatingFrame class implementation --
 
2851
 
 
2852
class AuiFloatingFrame(wx.MiniFrame):
 
2853
    """ AuiFloatingFrame is the frame class that holds floating panes. """
 
2854
 
 
2855
    def __init__(self, parent, owner_mgr, pane=None, id=wx.ID_ANY, title="",
 
2856
                 style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT |
 
2857
                 wx.FRAME_NO_TASKBAR | wx.CLIP_CHILDREN):
 
2858
        """
 
2859
        Default class constructor. Used internally, do not call it in your code!
 
2860
 
 
2861
        :param `parent`: the :class:`AuiManager` parent;
 
2862
        :param `owner_mgr`: the :class:`AuiManager` that manages the floating pane;
 
2863
        :param `pane`: the :class:`AuiPaneInfo` pane that is about to float;
 
2864
        :param integer `id`: the window identifier. It may take a value of -1 to indicate a default value.
 
2865
        :param string `title`: the caption to be displayed on the frame's title bar.
 
2866
        :param integer `style`: the window style.
 
2867
        """
 
2868
 
 
2869
        if pane and pane.IsResizeable():
 
2870
            style += wx.RESIZE_BORDER
 
2871
        if pane:
 
2872
            self._is_toolbar = pane.IsToolbar()
 
2873
 
 
2874
        self._useNativeMiniframes = False
 
2875
        if AuiManager_UseNativeMiniframes(owner_mgr):
 
2876
            # On wxMac we always use native miniframes
 
2877
            self._useNativeMiniframes = True
 
2878
            style += wx.CAPTION + wx.SYSTEM_MENU
 
2879
            if pane.HasCloseButton():
 
2880
                style += wx.CLOSE_BOX
 
2881
            if pane.HasMaximizeButton():
 
2882
                style += wx.MAXIMIZE_BOX
 
2883
            if pane.HasMinimizeButton():
 
2884
                style += wx.MINIMIZE_BOX
 
2885
 
 
2886
        wx.MiniFrame.__init__(self, parent, id, title, pos=pane.floating_pos,
 
2887
                              size=pane.floating_size, style=style, name="auiFloatingFrame")
 
2888
 
 
2889
        self._fly_timer = wx.Timer(self, wx.ID_ANY)
 
2890
        self._check_fly_timer = wx.Timer(self, wx.ID_ANY)
 
2891
 
 
2892
        self.Bind(wx.EVT_CLOSE, self.OnClose)
 
2893
        self.Bind(wx.EVT_SIZE, self.OnSize)
 
2894
        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
 
2895
        self.Bind(wx.EVT_TIMER, self.OnCheckFlyTimer, self._check_fly_timer)
 
2896
        self.Bind(wx.EVT_TIMER, self.OnFlyTimer, self._fly_timer)
 
2897
        self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager)
 
2898
 
 
2899
        if self._useNativeMiniframes:
 
2900
            self.Bind(wx.EVT_MOVE, self.OnMoveEvent)
 
2901
            self.Bind(wx.EVT_MOVING, self.OnMoveEvent)
 
2902
            self.Bind(wx.EVT_IDLE, self.OnIdle)
 
2903
            self._useNativeMiniframes = True
 
2904
            self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE)
 
2905
        else:
 
2906
            self.Bind(wx.EVT_MOVE, self.OnMove)
 
2907
 
 
2908
        self._fly = False
 
2909
        self._send_size = True
 
2910
        self._alpha_amount = 255
 
2911
 
 
2912
        self._owner_mgr = owner_mgr
 
2913
        self._moving = False
 
2914
        self._lastDirection = None
 
2915
        self._transparent = 255
 
2916
 
 
2917
        self._last_rect = wx.Rect()
 
2918
        self._last2_rect = wx.Rect()
 
2919
        self._last3_rect = wx.Rect()
 
2920
 
 
2921
        self._mgr = AuiManager()
 
2922
        self._mgr.SetManagedWindow(self)
 
2923
        self._mgr.SetArtProvider(owner_mgr.GetArtProvider())
 
2924
        self._mgr.SetAGWFlags(owner_mgr.GetAGWFlags())
 
2925
 
 
2926
 
 
2927
    def CopyAttributes(self, pane):
 
2928
        """
 
2929
        Copies all the attributes of the input `pane` into another :class:`AuiPaneInfo`.
 
2930
 
 
2931
        :param `pane`: the source :class:`AuiPaneInfo` from where to copy attributes.
 
2932
        """
 
2933
 
 
2934
        contained_pane = AuiPaneInfo()
 
2935
 
 
2936
        contained_pane.name = pane.name
 
2937
        contained_pane.caption = pane.caption
 
2938
        contained_pane.window = pane.window
 
2939
        contained_pane.frame = pane.frame
 
2940
        contained_pane.state = pane.state
 
2941
        contained_pane.dock_direction = pane.dock_direction
 
2942
        contained_pane.dock_layer = pane.dock_layer
 
2943
        contained_pane.dock_row = pane.dock_row
 
2944
        contained_pane.dock_pos = pane.dock_pos
 
2945
        contained_pane.best_size = wx.Size(*pane.best_size)
 
2946
        contained_pane.min_size = wx.Size(*pane.min_size)
 
2947
        contained_pane.max_size = wx.Size(*pane.max_size)
 
2948
        contained_pane.floating_pos = wx.Point(*pane.floating_pos)
 
2949
        contained_pane.floating_size = wx.Size(*pane.floating_size)
 
2950
        contained_pane.dock_proportion = pane.dock_proportion
 
2951
        contained_pane.buttons = pane.buttons
 
2952
        contained_pane.rect = wx.Rect(*pane.rect)
 
2953
        contained_pane.icon = pane.icon
 
2954
        contained_pane.notebook_id = pane.notebook_id
 
2955
        contained_pane.transparent = pane.transparent
 
2956
        contained_pane.snapped = pane.snapped
 
2957
        contained_pane.minimize_mode = pane.minimize_mode
 
2958
        contained_pane.minimize_target = pane.minimize_target
 
2959
 
 
2960
        return contained_pane
 
2961
 
 
2962
 
 
2963
    def SetPaneWindow(self, pane):
 
2964
        """
 
2965
        Sets all the properties of a pane.
 
2966
 
 
2967
        :param `pane`: the :class:`AuiPaneInfo` to analyze.
 
2968
        """
 
2969
 
 
2970
        self._is_toolbar = pane.IsToolbar()
 
2971
        self._pane_window = pane.window
 
2972
 
 
2973
        if isinstance(pane.window, auibar.AuiToolBar):
 
2974
            pane.window.SetAuiManager(self._mgr)
 
2975
 
 
2976
        self._pane_window.Reparent(self)
 
2977
 
 
2978
        contained_pane = self.CopyAttributes(pane)
 
2979
 
 
2980
        contained_pane.Dock().Center().Show(). \
 
2981
                       CaptionVisible(False). \
 
2982
                       PaneBorder(False). \
 
2983
                       Layer(0).Row(0).Position(0)
 
2984
 
 
2985
        if not contained_pane.HasGripper() and not self._useNativeMiniframes:
 
2986
            contained_pane.CaptionVisible(True)
 
2987
 
 
2988
        indx = self._owner_mgr._panes.index(pane)
 
2989
 
 
2990
        # Carry over the minimum size
 
2991
        pane_min_size = pane.window.GetMinSize()
 
2992
 
 
2993
        # if the best size is smaller than the min size
 
2994
        # then set the min size to the best size as well
 
2995
        pane_best_size = contained_pane.best_size
 
2996
        if pane_best_size.IsFullySpecified() and (pane_best_size.x < pane_min_size.x or \
 
2997
                                                  pane_best_size.y < pane_min_size.y):
 
2998
 
 
2999
            pane_min_size = pane_best_size
 
3000
            self._pane_window.SetMinSize(pane_min_size)
 
3001
 
 
3002
        # if the frame window's max size is greater than the min size
 
3003
        # then set the max size to the min size as well
 
3004
        cur_max_size = self.GetMaxSize()
 
3005
        if cur_max_size.IsFullySpecified() and  (cur_max_size.x < pane_min_size.x or \
 
3006
                                                 cur_max_size.y < pane_min_size.y):
 
3007
            self.SetMaxSize(pane_min_size)
 
3008
 
 
3009
        art_provider = self._mgr.GetArtProvider()
 
3010
        caption_size = art_provider.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
3011
        button_size = art_provider.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE) + \
 
3012
                      4*art_provider.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
 
3013
 
 
3014
        min_size = pane.window.GetMinSize()
 
3015
 
 
3016
        if min_size.y < caption_size or min_size.x < button_size:
 
3017
            new_x, new_y = min_size.x, min_size.y
 
3018
            if min_size.y < caption_size:
 
3019
                new_y = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)+caption_size] or [1])[0]
 
3020
            if min_size.x < button_size:
 
3021
                new_x = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_X)+button_size] or [1])[0]
 
3022
 
 
3023
            self.SetMinSize((new_x, new_y))
 
3024
        else:
 
3025
            self.SetMinSize(min_size)
 
3026
 
 
3027
        self._mgr.AddPane(self._pane_window, contained_pane)
 
3028
        self._mgr.Update()
 
3029
 
 
3030
        if pane.min_size.IsFullySpecified():
 
3031
            # because SetSizeHints() calls Fit() too (which sets the window
 
3032
            # size to its minimum allowed), we keep the size before calling
 
3033
            # SetSizeHints() and reset it afterwards...
 
3034
            tmp = self.GetSize()
 
3035
            self.GetSizer().SetSizeHints(self)
 
3036
            self.SetSize(tmp)
 
3037
 
 
3038
        self.SetTitle(pane.caption)
 
3039
 
 
3040
        if pane.floating_size != wx.Size(-1, -1):
 
3041
            self.SetSize(pane.floating_size)
 
3042
        else:
 
3043
            size = pane.best_size
 
3044
            if size == wx.Size(-1, -1):
 
3045
                size = pane.min_size
 
3046
            if size == wx.Size(-1, -1):
 
3047
                size = self._pane_window.GetSize()
 
3048
            if self._owner_mgr and pane.HasGripper():
 
3049
                if pane.HasGripperTop():
 
3050
                    size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
 
3051
                else:
 
3052
                    size.x += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
 
3053
 
 
3054
            if not self._useNativeMiniframes:
 
3055
                size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
3056
 
 
3057
            pane.floating_size = size
 
3058
 
 
3059
            self.SetClientSize(size)
 
3060
 
 
3061
        self._owner_mgr._panes[indx] = pane
 
3062
 
 
3063
        self._fly_step = abs(pane.floating_size.y - \
 
3064
                             (caption_size + 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)))/10
 
3065
 
 
3066
        self._floating_size = wx.Size(*self.GetSize())
 
3067
 
 
3068
        if pane.IsFlyOut():
 
3069
            self._check_fly_timer.Start(50)
 
3070
 
 
3071
 
 
3072
    def GetOwnerManager(self):
 
3073
        """ Returns the :class:`AuiManager` that manages the pane. """
 
3074
 
 
3075
        return self._owner_mgr
 
3076
 
 
3077
 
 
3078
    def OnSize(self, event):
 
3079
        """
 
3080
        Handles the ``wx.EVT_SIZE`` event for :class:`AuiFloatingFrame`.
 
3081
 
 
3082
        :param `event`: a :class:`SizeEvent` to be processed.
 
3083
        """
 
3084
 
 
3085
        if self._owner_mgr and self._send_size:
 
3086
            self._owner_mgr.OnFloatingPaneResized(self._pane_window, event.GetSize())
 
3087
 
 
3088
 
 
3089
    def OnClose(self, event):
 
3090
        """
 
3091
        Handles the ``wx.EVT_CLOSE`` event for :class:`AuiFloatingFrame`.
 
3092
 
 
3093
        :param `event`: a :class:`CloseEvent` to be processed.
 
3094
        """
 
3095
 
 
3096
        if self._owner_mgr:
 
3097
            self._owner_mgr.OnFloatingPaneClosed(self._pane_window, event)
 
3098
 
 
3099
        if not event.GetVeto():
 
3100
            self._mgr.DetachPane(self._pane_window)
 
3101
 
 
3102
            if isinstance(self._pane_window, auibar.AuiToolBar):
 
3103
                self._pane_window.SetAuiManager(self._owner_mgr)
 
3104
 
 
3105
            # if we do not do this, then we can crash...
 
3106
            if self._owner_mgr and self._owner_mgr._action_window == self:
 
3107
                self._owner_mgr._action_window = None
 
3108
 
 
3109
            self._mgr.UnInit()
 
3110
            self.Destroy()
 
3111
 
 
3112
 
 
3113
    def OnActivate(self, event):
 
3114
        """
 
3115
        Handles the ``wx.EVT_ACTIVATE`` event for :class:`AuiFloatingFrame`.
 
3116
 
 
3117
        :param `event`: a :class:`ActivateEvent` to be processed.
 
3118
        """
 
3119
 
 
3120
        if self._owner_mgr and event.GetActive():
 
3121
            self._owner_mgr.OnFloatingPaneActivated(self._pane_window)
 
3122
 
 
3123
 
 
3124
    def OnMove(self, event):
 
3125
        """
 
3126
        Handles the ``wx.EVT_MOVE`` event for :class:`AuiFloatingFrame`.
 
3127
 
 
3128
        :param `event`: a :class:`MoveEvent` to be processed.
 
3129
 
 
3130
        .. note::
 
3131
 
 
3132
           This event is not processed on wxMAC or if :class:`AuiManager` is not using the
 
3133
           ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
 
3134
 
 
3135
        """
 
3136
 
 
3137
        if self._owner_mgr:
 
3138
            self._owner_mgr.OnFloatingPaneMoved(self._pane_window, event)
 
3139
 
 
3140
 
 
3141
    def OnMoveEvent(self, event):
 
3142
        """
 
3143
        Handles the ``wx.EVT_MOVE`` and ``wx.EVT_MOVING`` events for :class:`AuiFloatingFrame`.
 
3144
 
 
3145
        :param `event`: a :class:`MoveEvent` to be processed.
 
3146
 
 
3147
        .. note::
 
3148
 
 
3149
           This event is only processed on wxMAC or if :class:`AuiManager` is using the
 
3150
           ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
 
3151
        """
 
3152
 
 
3153
        win_rect = self.GetRect()
 
3154
 
 
3155
        if win_rect == self._last_rect:
 
3156
            return
 
3157
 
 
3158
        # skip the first move event
 
3159
        if self._last_rect.IsEmpty():
 
3160
            self._last_rect = wx.Rect(*win_rect)
 
3161
            return
 
3162
 
 
3163
        # As on OSX moving windows are not getting all move events, only sporadically, this difference
 
3164
        # is almost always big on OSX, so avoid this early exit opportunity
 
3165
        if wx.Platform != '__WXMAC__':
 
3166
            # skip if moving too fast to avoid massive redraws and
 
3167
            # jumping hint windows
 
3168
            if abs(win_rect.x - self._last_rect.x) > 3 or abs(win_rect.y - self._last_rect.y) > 3:
 
3169
                self._last3_rect = wx.Rect(*self._last2_rect)
 
3170
                self._last2_rect = wx.Rect(*self._last_rect)
 
3171
                self._last_rect = wx.Rect(*win_rect)
 
3172
 
 
3173
                # However still update the internally stored position to avoid
 
3174
                # snapping back to the old one later.
 
3175
                if self._owner_mgr:
 
3176
                    self._owner_mgr.GetPane(self._pane_window).floating_pos = win_rect.GetPosition()
 
3177
 
 
3178
                return
 
3179
 
 
3180
        # prevent frame redocking during resize
 
3181
        if self._last_rect.GetSize() != win_rect.GetSize():
 
3182
            self._last3_rect = wx.Rect(*self._last2_rect)
 
3183
            self._last2_rect = wx.Rect(*self._last_rect)
 
3184
            self._last_rect = wx.Rect(*win_rect)
 
3185
            return
 
3186
 
 
3187
        dir = wx.ALL
 
3188
 
 
3189
        horiz_dist = abs(win_rect.x - self._last3_rect.x)
 
3190
        vert_dist = abs(win_rect.y - self._last3_rect.y)
 
3191
 
 
3192
        if vert_dist >= horiz_dist:
 
3193
            if win_rect.y < self._last3_rect.y:
 
3194
                dir = wx.NORTH
 
3195
            else:
 
3196
                dir = wx.SOUTH
 
3197
        else:
 
3198
            if win_rect.x < self._last3_rect.x:
 
3199
                dir = wx.WEST
 
3200
            else:
 
3201
                dir = wx.EAST
 
3202
 
 
3203
        self._last3_rect = wx.Rect(*self._last2_rect)
 
3204
        self._last2_rect = wx.Rect(*self._last_rect)
 
3205
        self._last_rect = wx.Rect(*win_rect)
 
3206
 
 
3207
        if _VERSION_STRING < "2.9":
 
3208
            leftDown = wx.GetMouseState().LeftDown()
 
3209
        else:
 
3210
            leftDown = wx.GetMouseState().LeftIsDown()
 
3211
 
 
3212
        if not leftDown:
 
3213
            return
 
3214
 
 
3215
        if not self._moving:
 
3216
            self.OnMoveStart(event)
 
3217
            self._moving = True
 
3218
 
 
3219
        if self._last3_rect.IsEmpty():
 
3220
            return
 
3221
 
 
3222
        if event.GetEventType() == wx.wxEVT_MOVING:
 
3223
            self.OnMoving(event.GetRect(), dir)
 
3224
        else:
 
3225
            self.OnMoving(wx.RectPS(event.GetPosition(), self.GetSize()), dir)
 
3226
 
 
3227
 
 
3228
    def OnIdle(self, event):
 
3229
        """
 
3230
        Handles the ``wx.EVT_IDLE`` event for :class:`AuiFloatingFrame`.
 
3231
 
 
3232
        :param `event`: a :class:`IdleEvent` event to be processed.
 
3233
 
 
3234
        .. note::
 
3235
 
 
3236
           This event is only processed on wxMAC if :class:`AuiManager` is using the
 
3237
           ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
 
3238
 
 
3239
        """
 
3240
 
 
3241
        if self._moving:
 
3242
            if _VERSION_STRING < "2.9":
 
3243
                leftDown = wx.GetMouseState().LeftDown()
 
3244
            else:
 
3245
                leftDown = wx.GetMouseState().LeftIsDown()
 
3246
 
 
3247
            if not leftDown:
 
3248
                self._moving = False
 
3249
                self.OnMoveFinished()
 
3250
            else:
 
3251
                event.RequestMore()
 
3252
 
 
3253
 
 
3254
    def OnMoveStart(self, event):
 
3255
        """
 
3256
        The user has just started moving the floating pane.
 
3257
 
 
3258
        :param `event`: an instance of :class:`MouseEvent`.
 
3259
 
 
3260
        .. note::
 
3261
 
 
3262
           This event is only processed on wxMAC if :class:`AuiManager` is using the
 
3263
           ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
 
3264
 
 
3265
        """
 
3266
 
 
3267
        # notify the owner manager that the pane has started to move
 
3268
        if self._owner_mgr:
 
3269
            if self._owner_mgr._from_move:
 
3270
                return
 
3271
            self._owner_mgr._action_window = self._pane_window
 
3272
            point = wx.GetMousePosition()
 
3273
            action_offset = point - self.GetPosition()
 
3274
 
 
3275
            if self._is_toolbar:
 
3276
                self._owner_mgr._toolbar_action_offset = action_offset
 
3277
                self._owner_mgr.OnMotion_DragToolbarPane(point)
 
3278
            else:
 
3279
                self._owner_mgr._action_offset = action_offset
 
3280
                self._owner_mgr.OnMotion_DragFloatingPane(point)
 
3281
 
 
3282
 
 
3283
    def OnMoving(self, rect, direction):
 
3284
        """
 
3285
        The user is moving the floating pane.
 
3286
 
 
3287
        :param Rect `rect`: the pane client rectangle;
 
3288
        :param integer `direction`: the direction in which the pane is moving, can be one of
 
3289
         ``wx.NORTH``, ``wx.SOUTH``, ``wx.EAST`` or ``wx.WEST``.
 
3290
 
 
3291
        .. note::
 
3292
 
 
3293
           This event is only processed on wxMAC if :class:`AuiManager` is using the
 
3294
           ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
 
3295
        """
 
3296
 
 
3297
        # notify the owner manager that the pane is moving
 
3298
        self.OnMoveStart(None)
 
3299
        self._lastDirection = direction
 
3300
 
 
3301
 
 
3302
    def OnMoveFinished(self):
 
3303
        """
 
3304
        The user has just finished moving the floating pane.
 
3305
 
 
3306
        .. note::
 
3307
 
 
3308
           This method is used only on wxMAC if :class:`AuiManager` is using the
 
3309
           ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
 
3310
 
 
3311
        """
 
3312
 
 
3313
        # notify the owner manager that the pane has finished moving
 
3314
        if self._owner_mgr:
 
3315
            self._owner_mgr._action_window = self._pane_window
 
3316
            point = wx.GetMousePosition()
 
3317
            if self._is_toolbar:
 
3318
                self._owner_mgr.OnLeftUp_DragToolbarPane(point)
 
3319
            else:
 
3320
                self._owner_mgr.OnLeftUp_DragFloatingPane(point)
 
3321
 
 
3322
            self._owner_mgr.OnFloatingPaneMoved(self._pane_window, point)
 
3323
 
 
3324
 
 
3325
    def OnCheckFlyTimer(self, event):
 
3326
        """
 
3327
        Handles the ``wx.EVT_TIMER`` event for :class:`AuiFloatingFrame`.
 
3328
 
 
3329
        :param `event`: a :class:`TimerEvent` to be processed.
 
3330
 
 
3331
        :note: This is used solely for "fly-out" panes.
 
3332
        """
 
3333
 
 
3334
        if self._owner_mgr:
 
3335
            pane = self._mgr.GetPane(self._pane_window)
 
3336
            if pane.IsFlyOut():
 
3337
                if self.IsShownOnScreen():
 
3338
                    self.FlyOut()
 
3339
 
 
3340
 
 
3341
    def OnFindManager(self, event):
 
3342
        """
 
3343
        Handles the ``EVT_AUI_FIND_MANAGER`` event for :class:`AuiFloatingFrame`.
 
3344
 
 
3345
        :param `event`: a :class:`AuiManagerEvent` event to be processed.
 
3346
        """
 
3347
 
 
3348
        event.SetManager(self._owner_mgr)
 
3349
 
 
3350
 
 
3351
    def FlyOut(self):
 
3352
        """ Starts the flying in and out of a floating pane. """
 
3353
 
 
3354
        if self._fly_timer.IsRunning():
 
3355
            return
 
3356
 
 
3357
        if _VERSION_STRING < "2.9":
 
3358
            leftDown = wx.GetMouseState().LeftDown()
 
3359
        else:
 
3360
            leftDown = wx.GetMouseState().LeftIsDown()
 
3361
 
 
3362
        if leftDown:
 
3363
            return
 
3364
 
 
3365
        rect = wx.Rect(*self.GetScreenRect())
 
3366
        rect.Inflate(10, 10)
 
3367
 
 
3368
        if rect.Contains(wx.GetMousePosition()):
 
3369
            if not self._fly:
 
3370
                return
 
3371
            self._send_size = False
 
3372
            self._fly_timer.Start(5)
 
3373
        else:
 
3374
            if self._fly:
 
3375
                return
 
3376
            self._send_size = False
 
3377
            self._fly_timer.Start(5)
 
3378
 
 
3379
 
 
3380
    def OnFlyTimer(self, event):
 
3381
        """
 
3382
        Handles the ``wx.EVT_TIMER`` event for :class:`AuiFloatingFrame`.
 
3383
 
 
3384
        :param `event`: a :class:`TimerEvent` to be processed.
 
3385
        """
 
3386
 
 
3387
        current_size = self.GetClientSize()
 
3388
        floating_size = wx.Size(*self._owner_mgr.GetPane(self._pane_window).floating_size)
 
3389
 
 
3390
        if floating_size.y == -1:
 
3391
            floating_size = self._floating_size
 
3392
 
 
3393
        if not self._fly:
 
3394
            min_size = self._mgr.GetArtProvider().GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
3395
 
 
3396
            if wx.Platform != "__WXMSW__":
 
3397
                min_size += 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)
 
3398
 
 
3399
            if current_size.y - self._fly_step <= min_size:
 
3400
                self.SetClientSize((current_size.x, min_size))
 
3401
                self._fly = True
 
3402
                self._fly_timer.Stop()
 
3403
                self._send_size = True
 
3404
            else:
 
3405
                self.SetClientSize((current_size.x, current_size.y-self._fly_step))
 
3406
 
 
3407
        else:
 
3408
            if current_size.y + self._fly_step >= floating_size.y:
 
3409
                self.SetClientSize((current_size.x, floating_size.y))
 
3410
                self._fly = False
 
3411
                self._fly_timer.Stop()
 
3412
                self._send_size = True
 
3413
            else:
 
3414
                self.SetClientSize((current_size.x, current_size.y+self._fly_step))
 
3415
 
 
3416
        self.Update()
 
3417
        self.Refresh()
 
3418
 
 
3419
 
 
3420
    def FadeOut(self):
 
3421
        """ Actually starts the fading out of the floating pane. """
 
3422
 
 
3423
        while 1:
 
3424
            self._alpha_amount -= 10
 
3425
            if self._alpha_amount <= 0:
 
3426
                self._alpha_amount = 255
 
3427
                return
 
3428
 
 
3429
            self.SetTransparent(self._alpha_amount)
 
3430
            wx.SafeYield()
 
3431
            wx.MilliSleep(15)
 
3432
 
 
3433
 
 
3434
# -- static utility functions --
 
3435
 
 
3436
def DrawResizeHint(dc, rect):
 
3437
    """
 
3438
    Draws a resize hint while a sash is dragged.
 
3439
 
 
3440
    :param Rect `rect`: a rectangle which specifies the sash dimensions.
 
3441
    """
 
3442
 
 
3443
    if wx.Platform == "__WXMSW__" and wx.App.GetComCtl32Version() >= 600:
 
3444
        if wx.GetOsVersion()[1] > 5:
 
3445
            # Windows Vista
 
3446
            dc.SetPen(wx.Pen("black", 2, wx.SOLID))
 
3447
            dc.SetBrush(wx.TRANSPARENT_BRUSH)
 
3448
        else:
 
3449
            # Draw the nice XP style splitter
 
3450
            dc.SetPen(wx.TRANSPARENT_PEN)
 
3451
            dc.SetBrush(wx.BLACK_BRUSH)
 
3452
        dc.SetLogicalFunction(wx.INVERT)
 
3453
        dc.DrawRectangleRect(rect)
 
3454
        dc.SetLogicalFunction(wx.COPY)
 
3455
    else:
 
3456
        stipple = PaneCreateStippleBitmap()
 
3457
        brush = wx.BrushFromBitmap(stipple)
 
3458
        dc.SetBrush(brush)
 
3459
        dc.SetPen(wx.TRANSPARENT_PEN)
 
3460
 
 
3461
        dc.SetLogicalFunction(wx.XOR)
 
3462
        dc.DrawRectangleRect(rect)
 
3463
 
 
3464
 
 
3465
def CopyDocksAndPanes(src_docks, src_panes):
 
3466
    """
 
3467
    This utility function creates shallow copies of
 
3468
    the dock and pane info. :class:`AuiManager` usually contain pointers
 
3469
    to :class:`AuiPaneInfo` classes, thus this function is necessary to reliably
 
3470
    reconstruct that relationship in the new dock info and pane info arrays.
 
3471
 
 
3472
    :param `src_docks`: a list of :class:`AuiDockInfo` classes;
 
3473
    :param `src_panes`: a list of :class:`AuiPaneInfo` classes.
 
3474
    """
 
3475
 
 
3476
    dest_docks = src_docks
 
3477
    dest_panes = src_panes
 
3478
 
 
3479
    for ii in xrange(len(dest_docks)):
 
3480
        dock = dest_docks[ii]
 
3481
        for jj in xrange(len(dock.panes)):
 
3482
            for kk in xrange(len(src_panes)):
 
3483
                if dock.panes[jj] == src_panes[kk]:
 
3484
                    dock.panes[jj] = dest_panes[kk]
 
3485
 
 
3486
    return dest_docks, dest_panes
 
3487
 
 
3488
 
 
3489
def CopyDocksAndPanes2(src_docks, src_panes):
 
3490
    """
 
3491
    This utility function creates full copies of
 
3492
    the dock and pane info. :class:`AuiManager` usually contain pointers
 
3493
    to :class:`AuiPaneInfo` classes, thus this function is necessary to reliably
 
3494
    reconstruct that relationship in the new dock info and pane info arrays.
 
3495
 
 
3496
    :param `src_docks`: a list of :class:`AuiDockInfo` classes;
 
3497
    :param `src_panes`: a list of :class:`AuiPaneInfo` classes.
 
3498
    """
 
3499
 
 
3500
    dest_docks = []
 
3501
 
 
3502
    for ii in xrange(len(src_docks)):
 
3503
        dest_docks.append(AuiDockInfo())
 
3504
        dest_docks[ii].dock_direction = src_docks[ii].dock_direction
 
3505
        dest_docks[ii].dock_layer = src_docks[ii].dock_layer
 
3506
        dest_docks[ii].dock_row = src_docks[ii].dock_row
 
3507
        dest_docks[ii].size = src_docks[ii].size
 
3508
        dest_docks[ii].min_size = src_docks[ii].min_size
 
3509
        dest_docks[ii].resizable = src_docks[ii].resizable
 
3510
        dest_docks[ii].fixed = src_docks[ii].fixed
 
3511
        dest_docks[ii].toolbar = src_docks[ii].toolbar
 
3512
        dest_docks[ii].panes = src_docks[ii].panes
 
3513
        dest_docks[ii].rect = wx.Rect(*src_docks[ii].rect)
 
3514
 
 
3515
    dest_panes = []
 
3516
 
 
3517
    for ii in xrange(len(src_panes)):
 
3518
        dest_panes.append(AuiPaneInfo())
 
3519
        dest_panes[ii].name = src_panes[ii].name
 
3520
        dest_panes[ii].caption = src_panes[ii].caption
 
3521
        dest_panes[ii].window = src_panes[ii].window
 
3522
        dest_panes[ii].frame = src_panes[ii].frame
 
3523
        dest_panes[ii].state = src_panes[ii].state
 
3524
        dest_panes[ii].dock_direction = src_panes[ii].dock_direction
 
3525
        dest_panes[ii].dock_layer = src_panes[ii].dock_layer
 
3526
        dest_panes[ii].dock_row = src_panes[ii].dock_row
 
3527
        dest_panes[ii].dock_pos = src_panes[ii].dock_pos
 
3528
        dest_panes[ii].best_size = wx.Size(*src_panes[ii].best_size)
 
3529
        dest_panes[ii].min_size = wx.Size(*src_panes[ii].min_size)
 
3530
        dest_panes[ii].max_size = wx.Size(*src_panes[ii].max_size)
 
3531
        dest_panes[ii].floating_pos = wx.Point(*src_panes[ii].floating_pos)
 
3532
        dest_panes[ii].floating_size = wx.Size(*src_panes[ii].floating_size)
 
3533
        dest_panes[ii].dock_proportion = src_panes[ii].dock_proportion
 
3534
        dest_panes[ii].buttons = src_panes[ii].buttons
 
3535
        dest_panes[ii].rect = wx.Rect(*src_panes[ii].rect)
 
3536
        dest_panes[ii].icon = src_panes[ii].icon
 
3537
        dest_panes[ii].notebook_id = src_panes[ii].notebook_id
 
3538
        dest_panes[ii].transparent = src_panes[ii].transparent
 
3539
        dest_panes[ii].snapped = src_panes[ii].snapped
 
3540
        dest_panes[ii].minimize_mode = src_panes[ii].minimize_mode
 
3541
        dest_panes[ii].minimize_target = src_panes[ii].minimize_target
 
3542
 
 
3543
    for ii in xrange(len(dest_docks)):
 
3544
        dock = dest_docks[ii]
 
3545
        for jj in xrange(len(dock.panes)):
 
3546
            for kk in xrange(len(src_panes)):
 
3547
                if dock.panes[jj] == src_panes[kk]:
 
3548
                    dock.panes[jj] = dest_panes[kk]
 
3549
 
 
3550
        dest_docks[ii] = dock
 
3551
 
 
3552
    return dest_docks, dest_panes
 
3553
 
 
3554
 
 
3555
def GetMaxLayer(docks, dock_direction):
 
3556
    """
 
3557
    This is an internal function which returns
 
3558
    the highest layer inside the specified dock.
 
3559
 
 
3560
    :param `docks`: a list of :class:`AuiDockInfo`;
 
3561
    :param `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze.
 
3562
    """
 
3563
 
 
3564
    max_layer = 0
 
3565
 
 
3566
    for dock in docks:
 
3567
        if dock.dock_direction == dock_direction and dock.dock_layer > max_layer and not dock.fixed:
 
3568
            max_layer = dock.dock_layer
 
3569
 
 
3570
    return max_layer
 
3571
 
 
3572
 
 
3573
def GetMaxRow(panes, dock_direction, dock_layer):
 
3574
    """
 
3575
    This is an internal function which returns
 
3576
    the highest layer inside the specified dock.
 
3577
 
 
3578
    :param `panes`: a list of :class:`AuiPaneInfo`;
 
3579
    :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze;
 
3580
    :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze.
 
3581
    """
 
3582
 
 
3583
    max_row = 0
 
3584
 
 
3585
    for pane in panes:
 
3586
        if pane.dock_direction == dock_direction and pane.dock_layer == dock_layer and \
 
3587
           pane.dock_row > max_row:
 
3588
            max_row = pane.dock_row
 
3589
 
 
3590
    return max_row
 
3591
 
 
3592
 
 
3593
def DoInsertDockLayer(panes, dock_direction, dock_layer):
 
3594
    """
 
3595
    This is an internal function that inserts a new dock
 
3596
    layer by incrementing all existing dock layer values by one.
 
3597
 
 
3598
    :param `panes`: a list of :class:`AuiPaneInfo`;
 
3599
    :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze;
 
3600
    :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze.
 
3601
    """
 
3602
 
 
3603
    for ii in xrange(len(panes)):
 
3604
        pane = panes[ii]
 
3605
        if not pane.IsFloating() and pane.dock_direction == dock_direction and pane.dock_layer >= dock_layer:
 
3606
            pane.dock_layer = pane.dock_layer + 1
 
3607
 
 
3608
        panes[ii] = pane
 
3609
 
 
3610
    return panes
 
3611
 
 
3612
 
 
3613
def DoInsertDockRow(panes, dock_direction, dock_layer, dock_row):
 
3614
    """
 
3615
    This is an internal function that inserts a new dock
 
3616
    row by incrementing all existing dock row values by one.
 
3617
 
 
3618
    :param `panes`: a list of :class:`AuiPaneInfo`;
 
3619
    :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze;
 
3620
    :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze;
 
3621
    :param integer `dock_row`: the :class:`AuiDockInfo` row to analyze.
 
3622
    """
 
3623
 
 
3624
    for pane in panes:
 
3625
        if not pane.IsFloating() and pane.dock_direction == dock_direction and \
 
3626
           pane.dock_layer == dock_layer and pane.dock_row >= dock_row:
 
3627
            pane.dock_row += 1
 
3628
 
 
3629
    return panes
 
3630
 
 
3631
 
 
3632
def DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos):
 
3633
    """
 
3634
    This is an internal function that inserts a new pane
 
3635
    by incrementing all existing dock position values by one.
 
3636
 
 
3637
    :param `panes`: a list of :class:`AuiPaneInfo`;
 
3638
    :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze;
 
3639
    :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze.
 
3640
    :param integer `dock_row`: the :class:`AuiDockInfo` row to analyze;
 
3641
    :param integer `dock_pos`: the :class:`AuiDockInfo` position to analyze.
 
3642
    """
 
3643
 
 
3644
    for ii in xrange(len(panes)):
 
3645
        pane = panes[ii]
 
3646
        if not pane.IsFloating() and pane.dock_direction == dock_direction and \
 
3647
           pane.dock_layer == dock_layer and  pane.dock_row == dock_row and \
 
3648
           pane.dock_pos >= dock_pos:
 
3649
            pane.dock_pos = pane.dock_pos + 1
 
3650
 
 
3651
        panes[ii] = pane
 
3652
 
 
3653
    return panes
 
3654
 
 
3655
 
 
3656
def FindDocks(docks, dock_direction, dock_layer=-1, dock_row=-1, reverse=False):
 
3657
    """
 
3658
    This is an internal function that returns a list of docks which meet
 
3659
    the specified conditions in the parameters and returns a sorted array
 
3660
    (sorted by layer and then row).
 
3661
 
 
3662
    :param `docks`: a list of :class:`AuiDockInfo`;
 
3663
    :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze;
 
3664
    :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze.
 
3665
    :param integer `dock_row`: the :class:`AuiDockInfo` row to analyze;
 
3666
    """
 
3667
 
 
3668
    matchDocks = [(d.dock_layer, d.dock_row, d.dock_direction, d) for d in docks if \
 
3669
                  (dock_direction == -1 or dock_direction == d.dock_direction) and \
 
3670
                  ((dock_layer == -1 or dock_layer == d.dock_layer) and \
 
3671
                  (dock_row == -1 or dock_row == d.dock_row))]
 
3672
 
 
3673
    arr = [x[-1] for x in sorted(matchDocks, reverse=reverse)]
 
3674
 
 
3675
    return arr
 
3676
 
 
3677
 
 
3678
def FindOppositeDocks(docks, dock_direction):
 
3679
    """
 
3680
    This is an internal function that returns a list of docks
 
3681
    which is related to the opposite direction.
 
3682
 
 
3683
    :param `docks`: a list of :class:`AuiDockInfo`;
 
3684
    :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze;
 
3685
    """
 
3686
 
 
3687
    if dock_direction == AUI_DOCK_LEFT:
 
3688
        arr = FindDocks(docks, AUI_DOCK_RIGHT, -1, -1)
 
3689
    elif dock_direction == AUI_DOCK_TOP:
 
3690
        arr = FindDocks(docks, AUI_DOCK_BOTTOM, -1, -1)
 
3691
    elif dock_direction == AUI_DOCK_RIGHT:
 
3692
        arr = FindDocks(docks, AUI_DOCK_LEFT, -1, -1)
 
3693
    elif dock_direction == AUI_DOCK_BOTTOM:
 
3694
        arr = FindDocks(docks, AUI_DOCK_TOP, -1, -1)
 
3695
 
 
3696
    return arr
 
3697
 
 
3698
 
 
3699
def FindPaneInDock(dock, window):
 
3700
    """
 
3701
    This method looks up a specified window pointer inside a dock.
 
3702
    If found, the corresponding :class:`AuiDockInfo` pointer is returned, otherwise ``None``.
 
3703
 
 
3704
    :param `dock`: a :class:`AuiDockInfo` structure;
 
3705
    :param Window `window`: the window associated to the pane we are seeking.
 
3706
    """
 
3707
 
 
3708
    for p in dock.panes:
 
3709
        if p.window == window:
 
3710
            return p
 
3711
 
 
3712
    return None
 
3713
 
 
3714
 
 
3715
def GetToolBarDockOffsets(docks):
 
3716
    """
 
3717
    Returns the toolbar dock offsets (top-left and bottom-right).
 
3718
 
 
3719
    :param `docks`: a list of :class:`AuiDockInfo` to analyze.
 
3720
    """
 
3721
 
 
3722
    top_left = wx.Size(0, 0)
 
3723
    bottom_right = wx.Size(0, 0)
 
3724
 
 
3725
    for dock in docks:
 
3726
        if dock.toolbar:
 
3727
            dock_direction = dock.dock_direction
 
3728
            if dock_direction == AUI_DOCK_LEFT:
 
3729
                top_left.x += dock.rect.width
 
3730
                bottom_right.x += dock.rect.width
 
3731
 
 
3732
            elif dock_direction == AUI_DOCK_TOP:
 
3733
                top_left.y += dock.rect.height
 
3734
                bottom_right.y += dock.rect.height
 
3735
 
 
3736
            elif dock_direction == AUI_DOCK_RIGHT:
 
3737
                bottom_right.x += dock.rect.width
 
3738
 
 
3739
            elif dock_direction == AUI_DOCK_BOTTOM:
 
3740
                bottom_right.y += dock.rect.height
 
3741
 
 
3742
    return top_left, bottom_right
 
3743
 
 
3744
 
 
3745
def GetInternalFrameRect(window, docks):
 
3746
    """
 
3747
    Returns the window rectangle excluding toolbars.
 
3748
 
 
3749
    :param `window`: a :class:`Window` derived window;
 
3750
    :param `docks`: a list of :class:`AuiDockInfo` structures.
 
3751
    """
 
3752
 
 
3753
    frameRect = wx.Rect()
 
3754
 
 
3755
    frameRect.SetTopLeft(window.ClientToScreen(window.GetClientAreaOrigin()))
 
3756
    frameRect.SetSize(window.GetClientSize())
 
3757
 
 
3758
    top_left, bottom_right = GetToolBarDockOffsets(docks)
 
3759
 
 
3760
    # make adjustments for toolbars
 
3761
    frameRect.x += top_left.x
 
3762
    frameRect.y += top_left.y
 
3763
    frameRect.width -= bottom_right.x
 
3764
    frameRect.height -= bottom_right.y
 
3765
 
 
3766
    return frameRect
 
3767
 
 
3768
 
 
3769
def CheckOutOfWindow(window, pt):
 
3770
    """
 
3771
    Checks if a point is outside the window rectangle.
 
3772
 
 
3773
    :param `window`: a :class:`Window` derived window;
 
3774
    :param `pt`: a :class:`Point` object.
 
3775
    """
 
3776
 
 
3777
    auiWindowMargin = 30
 
3778
    marginRect = wx.Rect(*window.GetClientRect())
 
3779
    marginRect.Inflate(auiWindowMargin, auiWindowMargin)
 
3780
 
 
3781
    return not marginRect.Contains(pt)
 
3782
 
 
3783
 
 
3784
def CheckEdgeDrop(window, docks, pt):
 
3785
    """
 
3786
    Checks on which edge of a window the drop action has taken place.
 
3787
 
 
3788
    :param `window`: a :class:`Window` derived window;
 
3789
    :param `docks`: a list of :class:`AuiDockInfo` structures;
 
3790
    :param `pt`: a :class:`Point` object.
 
3791
    """
 
3792
 
 
3793
    screenPt = window.ClientToScreen(pt)
 
3794
    clientSize = window.GetClientSize()
 
3795
    frameRect = GetInternalFrameRect(window, docks)
 
3796
 
 
3797
    if screenPt.y >= frameRect.GetTop() and screenPt.y < frameRect.GetBottom():
 
3798
        if pt.x < auiLayerInsertOffset and pt.x > auiLayerInsertOffset - auiLayerInsertPixels:
 
3799
            return wx.LEFT
 
3800
 
 
3801
        if pt.x >= clientSize.x - auiLayerInsertOffset and \
 
3802
           pt.x < clientSize.x - auiLayerInsertOffset + auiLayerInsertPixels:
 
3803
            return wx.RIGHT
 
3804
 
 
3805
    if screenPt.x >= frameRect.GetLeft() and screenPt.x < frameRect.GetRight():
 
3806
        if pt.y < auiLayerInsertOffset and pt.y > auiLayerInsertOffset - auiLayerInsertPixels:
 
3807
            return wx.TOP
 
3808
 
 
3809
        if pt.y >= clientSize.y - auiLayerInsertOffset and \
 
3810
           pt.y < clientSize.y - auiLayerInsertOffset + auiLayerInsertPixels:
 
3811
            return wx.BOTTOM
 
3812
 
 
3813
    return -1
 
3814
 
 
3815
 
 
3816
def RemovePaneFromDocks(docks, pane, exc=None):
 
3817
    """
 
3818
    Removes a pane window from all docks
 
3819
    with a possible exception specified by parameter `exc`.
 
3820
 
 
3821
    :param `docks`: a list of :class:`AuiDockInfo` structures;
 
3822
    :param AuiPaneInfo `pane`: the pane to be removed;
 
3823
    :param AuiPaneInfo `exc`: the possible pane exception.
 
3824
    """
 
3825
 
 
3826
    for ii in xrange(len(docks)):
 
3827
        d = docks[ii]
 
3828
        if d == exc:
 
3829
            continue
 
3830
        pi = FindPaneInDock(d, pane.window)
 
3831
        if pi:
 
3832
            d.panes.remove(pi)
 
3833
 
 
3834
        docks[ii] = d
 
3835
 
 
3836
    return docks
 
3837
 
 
3838
 
 
3839
def RenumberDockRows(docks):
 
3840
    """
 
3841
    Takes a dock and assigns sequential numbers
 
3842
    to existing rows.  Basically it takes out the gaps so if a
 
3843
    dock has rows with numbers 0, 2, 5, they will become 0, 1, 2.
 
3844
 
 
3845
    :param `docks`: a list of :class:`AuiDockInfo` structures.
 
3846
    """
 
3847
 
 
3848
    for ii in xrange(len(docks)):
 
3849
        dock = docks[ii]
 
3850
        dock.dock_row = ii
 
3851
        for jj in xrange(len(dock.panes)):
 
3852
            dock.panes[jj].dock_row = ii
 
3853
 
 
3854
        docks[ii] = dock
 
3855
 
 
3856
    return docks
 
3857
 
 
3858
 
 
3859
def SetActivePane(panes, active_pane):
 
3860
    """
 
3861
    Sets the active pane, as well as cycles through
 
3862
    every other pane and makes sure that all others' active flags
 
3863
    are turned off.
 
3864
 
 
3865
    :param `panes`: a list of :class:`AuiPaneInfo` structures;
 
3866
    :param AuiPaneInfo `active_pane`: the pane to be made active (if found).
 
3867
    """
 
3868
 
 
3869
    for pane in panes:
 
3870
        pane.state &= ~AuiPaneInfo.optionActive
 
3871
 
 
3872
    for pane in panes:
 
3873
        if pane.window == active_pane and not pane.IsNotebookPage():
 
3874
            pane.state |= AuiPaneInfo.optionActive
 
3875
            return True, panes
 
3876
 
 
3877
    return False, panes
 
3878
 
 
3879
 
 
3880
def ShowDockingGuides(guides, show):
 
3881
    """
 
3882
    Shows or hide the docking guide windows.
 
3883
 
 
3884
    :param `guides`: a list of :class:`AuiDockingGuide` classes;
 
3885
    :param bool `show`: whether to show or hide the docking guide windows.
 
3886
    """
 
3887
 
 
3888
    for target in guides:
 
3889
 
 
3890
        if show and not target.host.IsShown():
 
3891
            target.host.Show()
 
3892
            target.host.Update()
 
3893
 
 
3894
        elif not show and target.host.IsShown():
 
3895
            target.host.Hide()
 
3896
 
 
3897
 
 
3898
def RefreshDockingGuides(guides):
 
3899
    """
 
3900
    Refreshes the docking guide windows.
 
3901
 
 
3902
    :param `guides`: a list of :class:`AuiDockingGuide` classes;
 
3903
    """
 
3904
 
 
3905
    for target in guides:
 
3906
        if target.host.IsShown():
 
3907
            target.host.Refresh()
 
3908
 
 
3909
 
 
3910
def PaneSortFunc(p1, p2):
 
3911
    """
 
3912
    This function is used to sort panes by dock position.
 
3913
 
 
3914
    :param AuiPaneInfo `p1`: the first pane instance to compare;
 
3915
    :param AuiPaneInfo `p2`: the second pane instance to compare.
 
3916
    """
 
3917
 
 
3918
    return (p1.dock_pos < p2.dock_pos and [-1] or [1])[0]
 
3919
 
 
3920
 
 
3921
def GetNotebookRoot(panes, notebook_id):
 
3922
    """
 
3923
    Returns the :class:`~lib.agw.aui.auibook.AuiNotebook` which has the specified `notebook_id`.
 
3924
 
 
3925
    :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
3926
    :param integer `notebook_id`: the target notebook id.
 
3927
    """
 
3928
 
 
3929
    for paneInfo in panes:
 
3930
        if paneInfo.IsNotebookControl() and paneInfo.notebook_id == notebook_id:
 
3931
            return paneInfo
 
3932
 
 
3933
    return None
 
3934
 
 
3935
 
 
3936
def EscapeDelimiters(s):
 
3937
    """
 
3938
    Changes ``;`` into ``\`` and ``|`` into ``\|`` in the input string.
 
3939
 
 
3940
    :param string `s`: the string to be analyzed.
 
3941
 
 
3942
    :note: This is an internal functions which is used for saving perspectives.
 
3943
    """
 
3944
 
 
3945
    result = s.replace(";", "\\")
 
3946
    result = result.replace("|", "|\\")
 
3947
 
 
3948
    return result
 
3949
 
 
3950
 
 
3951
def IsDifferentDockingPosition(pane1, pane2):
 
3952
    """
 
3953
    Returns whether `pane1` and `pane2` are in a different docking position
 
3954
    based on pane status, docking direction, docking layer and docking row.
 
3955
 
 
3956
    :param `pane1`: a :class:`AuiPaneInfo` instance;
 
3957
    :param `pane2`: another :class:`AuiPaneInfo` instance.
 
3958
    """
 
3959
 
 
3960
    return pane1.IsFloating() != pane2.IsFloating() or \
 
3961
           pane1.dock_direction != pane2.dock_direction or \
 
3962
           pane1.dock_layer != pane2.dock_layer or \
 
3963
           pane1.dock_row != pane2.dock_row
 
3964
 
 
3965
 
 
3966
# Convenience function
 
3967
def AuiManager_HasLiveResize(manager):
 
3968
    """
 
3969
    Static function which returns if the input `manager` should have "live resize"
 
3970
    behaviour.
 
3971
 
 
3972
    :param `manager`: an instance of :class:`AuiManager`.
 
3973
 
 
3974
    .. note::
 
3975
 
 
3976
       This method always returns ``True`` on wxMAC as this platform doesn't have
 
3977
       the ability to use :class:`ScreenDC` to draw sashes.
 
3978
 
 
3979
    """
 
3980
 
 
3981
    # With Core Graphics on Mac, it's not possible to show sash feedback,
 
3982
    # so we'll always use live update instead.
 
3983
 
 
3984
    if wx.Platform == "__WXMAC__":
 
3985
        return True
 
3986
    else:
 
3987
        return (manager.GetAGWFlags() & AUI_MGR_LIVE_RESIZE) == AUI_MGR_LIVE_RESIZE
 
3988
 
 
3989
 
 
3990
# Convenience function
 
3991
def AuiManager_UseNativeMiniframes(manager):
 
3992
    """
 
3993
    Static function which returns if the input `manager` should use native :class:`MiniFrame` as
 
3994
    floating panes.
 
3995
 
 
3996
    :param `manager`: an instance of :class:`AuiManager`.
 
3997
 
 
3998
    .. note::
 
3999
 
 
4000
       This method always returns ``True`` on wxMAC as this platform doesn't have
 
4001
       the ability to use custom drawn miniframes.
 
4002
 
 
4003
    """
 
4004
 
 
4005
    # With Core Graphics on Mac, it's not possible to show sash feedback,
 
4006
    # so we'll always use live update instead.
 
4007
 
 
4008
    if wx.Platform == "__WXMAC__":
 
4009
        return True
 
4010
    else:
 
4011
        return (manager.GetAGWFlags() & AUI_MGR_USE_NATIVE_MINIFRAMES) == AUI_MGR_USE_NATIVE_MINIFRAMES
 
4012
 
 
4013
 
 
4014
def GetManager(window):
 
4015
    """
 
4016
    This function will return the aui manager for a given window.
 
4017
 
 
4018
    :param Window `window`: this parameter should be any child window or grand-child
 
4019
     window (and so on) of the frame/window managed by :class:`AuiManager`. The window
 
4020
     does not need to be managed by the manager itself, nor does it even need
 
4021
     to be a child or sub-child of a managed window. It must however be inside
 
4022
     the window hierarchy underneath the managed window.
 
4023
    """
 
4024
 
 
4025
    if not isinstance(wx.GetTopLevelParent(window), AuiFloatingFrame):
 
4026
        if isinstance(window, auibar.AuiToolBar):
 
4027
            return window.GetAuiManager()
 
4028
 
 
4029
    evt = AuiManagerEvent(wxEVT_AUI_FIND_MANAGER)
 
4030
    evt.SetManager(None)
 
4031
    evt.ResumePropagation(wx.EVENT_PROPAGATE_MAX)
 
4032
 
 
4033
    if not window.GetEventHandler().ProcessEvent(evt):
 
4034
        return None
 
4035
 
 
4036
    return evt.GetManager()
 
4037
 
 
4038
 
 
4039
# ---------------------------------------------------------------------------- #
 
4040
 
 
4041
class AuiManager(wx.EvtHandler):
 
4042
    """
 
4043
    AuiManager manages the panes associated with it for a particular :class:`Frame`,
 
4044
    using a pane's :class:`AuiManager` information to determine each pane's docking and
 
4045
    floating behavior. :class:`AuiManager` uses wxPython's sizer mechanism to plan the
 
4046
    layout of each frame. It uses a replaceable dock art class to do all drawing,
 
4047
    so all drawing is localized in one area, and may be customized depending on an
 
4048
    applications' specific needs.
 
4049
 
 
4050
    :class:`AuiManager` works as follows: the programmer adds panes to the class, or makes
 
4051
    changes to existing pane properties (dock position, floating state, show state, etc...).
 
4052
    To apply these changes, the :meth:`AuiManager.Update() <AuiManager.Update>` function is called. This batch
 
4053
    processing can be used to avoid flicker, by modifying more than one pane at a time,
 
4054
    and then "committing" all of the changes at once by calling `Update()`.
 
4055
 
 
4056
    Panes can be added quite easily::
 
4057
 
 
4058
        text1 = wx.TextCtrl(self, -1)
 
4059
        text2 = wx.TextCtrl(self, -1)
 
4060
        self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
 
4061
        self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
 
4062
 
 
4063
        self._mgr.Update()
 
4064
 
 
4065
 
 
4066
    Later on, the positions can be modified easily. The following will float an
 
4067
    existing pane in a tool window::
 
4068
 
 
4069
        self._mgr.GetPane(text1).Float()
 
4070
 
 
4071
 
 
4072
    **Layers, Rows and Directions, Positions:**
 
4073
 
 
4074
    Inside AUI, the docking layout is figured out by checking several pane parameters.
 
4075
    Four of these are important for determining where a pane will end up.
 
4076
 
 
4077
    **Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`.
 
4078
    This is fairly self-explanatory. The pane will be placed in the location specified
 
4079
    by this variable.
 
4080
 
 
4081
    **Position** - More than one pane can be placed inside of a "dock". Imagine two panes
 
4082
    being docked on the left side of a window. One pane can be placed over another.
 
4083
    In proportionally managed docks, the pane position indicates it's sequential position,
 
4084
    starting with zero. So, in our scenario with two panes docked on the left side, the
 
4085
    top pane in the dock would have position 0, and the second one would occupy position 1.
 
4086
 
 
4087
    **Row** - A row can allow for two docks to be placed next to each other. One of the most
 
4088
    common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
 
4089
    the first row being in row 0, and the second in row 1. Rows can also be used on
 
4090
    vertically docked panes.
 
4091
 
 
4092
    **Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
 
4093
    Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
 
4094
    known as the "content window"). Increasing layers "swallow up" all layers of a lower
 
4095
    value. This can look very similar to multiple rows, but is different because all panes
 
4096
    in a lower level yield to panes in higher levels. The best way to understand layers
 
4097
    is by running the AUI sample (`AUI.py`).
 
4098
    """
 
4099
 
 
4100
    def __init__(self, managed_window=None, agwFlags=None):
 
4101
        """
 
4102
        Default class constructor.
 
4103
 
 
4104
        :param Window `managed_window`: specifies the window which should be managed;
 
4105
        :param integer `agwFlags`: specifies options which allow the frame management behavior to be
 
4106
         modified. `agwFlags` can be a combination of the following style bits:
 
4107
 
 
4108
         ==================================== ==================================
 
4109
         Flag name                            Description
 
4110
         ==================================== ==================================
 
4111
         ``AUI_MGR_ALLOW_FLOATING``           Allow floating of panes
 
4112
         ``AUI_MGR_ALLOW_ACTIVE_PANE``        If a pane becomes active, "highlight" it in the interface
 
4113
         ``AUI_MGR_TRANSPARENT_DRAG``         If the platform supports it, set transparency on a floating pane while it is dragged by the user
 
4114
         ``AUI_MGR_TRANSPARENT_HINT``         If the platform supports it, show a transparent hint window when the user is about to dock a floating pane
 
4115
         ``AUI_MGR_VENETIAN_BLINDS_HINT``     Show a "venetian blind" effect when the user is about to dock a floating pane
 
4116
         ``AUI_MGR_RECTANGLE_HINT``           Show a rectangle hint effect when the user is about to dock a floating pane
 
4117
         ``AUI_MGR_HINT_FADE``                If the platform supports it, the hint window will fade in and out
 
4118
         ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``  Disables the "venetian blind" fade in and out
 
4119
         ``AUI_MGR_LIVE_RESIZE``              Live resize when the user drag a sash
 
4120
         ``AUI_MGR_ANIMATE_FRAMES``           Fade-out floating panes when they are closed (all platforms which support frames transparency)
 
4121
                                              and show a moving rectangle when they are docked (Windows < Vista and GTK only)
 
4122
         ``AUI_MGR_AERO_DOCKING_GUIDES``      Use the new Aero-style bitmaps as docking guides
 
4123
         ``AUI_MGR_PREVIEW_MINIMIZED_PANES``  Slide in and out minimized panes to preview them
 
4124
         ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``   Use the new Whidbey-style bitmaps as docking guides
 
4125
         ``AUI_MGR_SMOOTH_DOCKING``           Performs a "smooth" docking of panes (a la PyQT)
 
4126
         ``AUI_MGR_USE_NATIVE_MINIFRAMES``    Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMAC)
 
4127
         ``AUI_MGR_AUTONB_NO_CAPTION``        Panes that merge into an automatic notebook will not have the pane caption visible
 
4128
         ==================================== ==================================
 
4129
 
 
4130
         Default value for `agwFlags` is:
 
4131
         ``AUI_MGR_DEFAULT`` = ``AUI_MGR_ALLOW_FLOATING`` | ``AUI_MGR_TRANSPARENT_HINT`` | ``AUI_MGR_HINT_FADE`` | ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``
 
4132
 
 
4133
         .. note::
 
4134
 
 
4135
            If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a
 
4136
            floating pane caption will not re-dock the pane, but simply maximize it (if
 
4137
            :meth:`AuiPaneInfo.MaximizeButton` has been set to ``True``) or do nothing.
 
4138
 
 
4139
        """
 
4140
 
 
4141
        wx.EvtHandler.__init__(self)
 
4142
 
 
4143
        self._action = actionNone
 
4144
        self._action_window = None
 
4145
        self._hover_button = None
 
4146
        self._art = dockart.AuiDefaultDockArt()
 
4147
        self._hint_window = None
 
4148
        self._active_pane = None
 
4149
        self._has_maximized = False
 
4150
        self._has_minimized = False
 
4151
 
 
4152
        self._frame = None
 
4153
        self._dock_constraint_x = 0.3
 
4154
        self._dock_constraint_y = 0.3
 
4155
        self._reserved = None
 
4156
 
 
4157
        self._panes = []
 
4158
        self._docks = []
 
4159
        self._uiparts = []
 
4160
 
 
4161
        self._guides = []
 
4162
        self._notebooks = []
 
4163
 
 
4164
        self._masterManager = None
 
4165
        self._currentDragItem = -1
 
4166
        self._lastknowndocks = {}
 
4167
 
 
4168
        self._hint_fadetimer = wx.Timer(self, wx.ID_ANY)
 
4169
        self._hint_fademax = 50
 
4170
        self._last_hint = wx.Rect()
 
4171
 
 
4172
        self._from_move = False
 
4173
        self._last_rect = wx.Rect()
 
4174
 
 
4175
        if agwFlags is None:
 
4176
            agwFlags = AUI_MGR_DEFAULT
 
4177
 
 
4178
        self._agwFlags = agwFlags
 
4179
        self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
 
4180
        self._snap_limits = (15, 15)
 
4181
 
 
4182
        if wx.Platform == "__WXMSW__":
 
4183
            self._animation_step = 30.0
 
4184
        else:
 
4185
            self._animation_step = 5.0
 
4186
 
 
4187
        self._hint_rect = wx.Rect()
 
4188
 
 
4189
        self._preview_timer = wx.Timer(self, wx.ID_ANY)
 
4190
        self._sliding_frame = None
 
4191
 
 
4192
        self._autoNBTabArt = tabart.AuiDefaultTabArt()
 
4193
        self._autoNBStyle = AUI_NB_DEFAULT_STYLE | AUI_NB_BOTTOM | \
 
4194
                            AUI_NB_SUB_NOTEBOOK | AUI_NB_TAB_EXTERNAL_MOVE
 
4195
        self._autoNBStyle -= AUI_NB_DRAW_DND_TAB
 
4196
 
 
4197
        if managed_window:
 
4198
            self.SetManagedWindow(managed_window)
 
4199
 
 
4200
        self.Bind(wx.EVT_PAINT, self.OnPaint)
 
4201
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
 
4202
        self.Bind(wx.EVT_SIZE, self.OnSize)
 
4203
        self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor)
 
4204
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
 
4205
        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
 
4206
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
 
4207
        self.Bind(wx.EVT_MOTION, self.OnMotion)
 
4208
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
 
4209
        self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus)
 
4210
        self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost)
 
4211
        self.Bind(wx.EVT_TIMER, self.OnHintFadeTimer, self._hint_fadetimer)
 
4212
        self.Bind(wx.EVT_TIMER, self.SlideIn, self._preview_timer)
 
4213
        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
 
4214
 
 
4215
        self.Bind(wx.EVT_MOVE, self.OnMove)
 
4216
        self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged)
 
4217
 
 
4218
        self.Bind(EVT_AUI_PANE_BUTTON, self.OnPaneButton)
 
4219
        self.Bind(EVT_AUI_RENDER, self.OnRender)
 
4220
        self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager)
 
4221
        self.Bind(EVT_AUI_PANE_MIN_RESTORE, self.OnRestoreMinimizedPane)
 
4222
        self.Bind(EVT_AUI_PANE_DOCKED, self.OnPaneDocked)
 
4223
 
 
4224
        self.Bind(auibook.EVT_AUINOTEBOOK_BEGIN_DRAG, self.OnTabBeginDrag)
 
4225
        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnTabPageClose)
 
4226
        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnTabSelected)
 
4227
 
 
4228
 
 
4229
    def CreateFloatingFrame(self, parent, pane_info):
 
4230
        """
 
4231
        Creates a floating frame for the windows.
 
4232
 
 
4233
        :param Window `parent`: the floating frame parent;
 
4234
        :param `pane_info`: the :class:`AuiPaneInfo` class with all the pane's information.
 
4235
        """
 
4236
 
 
4237
        return AuiFloatingFrame(parent, self, pane_info)
 
4238
 
 
4239
 
 
4240
    def CanDockPanel(self, p):
 
4241
        """
 
4242
        Returns whether a pane can be docked or not.
 
4243
 
 
4244
        :param `p`: the :class:`AuiPaneInfo` class with all the pane's information.
 
4245
        """
 
4246
 
 
4247
        # is the pane dockable?
 
4248
        if not p.IsDockable():
 
4249
            return False
 
4250
 
 
4251
        # if a key modifier is pressed while dragging the frame,
 
4252
        # don't dock the window
 
4253
        return not (wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT))
 
4254
 
 
4255
 
 
4256
    def GetPaneByWidget(self, window):
 
4257
        """
 
4258
        This version of :meth:`GetPane` looks up a pane based on a 'pane window'.
 
4259
 
 
4260
        :param `window`: a :class:`Window` derived window.
 
4261
 
 
4262
        :see: :meth:`~AuiManager.GetPane`
 
4263
        """
 
4264
 
 
4265
        for p in self._panes:
 
4266
            if p.window == window:
 
4267
                return p
 
4268
 
 
4269
        return NonePaneInfo
 
4270
 
 
4271
 
 
4272
    def GetPaneByName(self, name):
 
4273
        """
 
4274
        This version of :meth:`GetPane` looks up a pane based on a 'pane name'.
 
4275
 
 
4276
        :param string `name`: the pane name.
 
4277
 
 
4278
        :see: :meth:`GetPane`
 
4279
        """
 
4280
 
 
4281
        for p in self._panes:
 
4282
            if p.name == name:
 
4283
                return p
 
4284
 
 
4285
        return NonePaneInfo
 
4286
 
 
4287
 
 
4288
    def GetPane(self, item):
 
4289
        """
 
4290
        Looks up a :class:`AuiPaneInfo` structure based on the supplied window pointer. Upon failure,
 
4291
        :meth:`GetPane` returns an empty :class:`AuiPaneInfo`, a condition which can be checked
 
4292
        by calling :meth:`AuiPaneInfo.IsOk() <AuiPaneInfo.IsOk>`.
 
4293
 
 
4294
        The pane info's structure may then be modified. Once a pane's info is modified, :meth:`Update`
 
4295
        must be called to realize the changes in the UI.
 
4296
 
 
4297
        :param `item`: either a pane name or a :class:`Window`.
 
4298
        """
 
4299
 
 
4300
        if isinstance(item, basestring):
 
4301
            return self.GetPaneByName(item)
 
4302
        else:
 
4303
            return self.GetPaneByWidget(item)
 
4304
 
 
4305
 
 
4306
    def GetAllPanes(self):
 
4307
        """ Returns a reference to all the pane info structures. """
 
4308
 
 
4309
        return self._panes
 
4310
 
 
4311
 
 
4312
    def ShowPane(self, window, show):
 
4313
        """
 
4314
        Shows or hides a pane based on the window passed as input.
 
4315
 
 
4316
        :param Window `window`: any subclass or derivation of :class:`Window`;
 
4317
        :param bool `show`: ``True`` to show the pane, ``False`` otherwise.
 
4318
        """
 
4319
 
 
4320
        p = self.GetPane(window)
 
4321
 
 
4322
        if p.IsOk():
 
4323
            if p.IsNotebookPage():
 
4324
                if show:
 
4325
 
 
4326
                    notebook = self._notebooks[p.notebook_id]
 
4327
                    id = notebook.GetPageIndex(p.window)
 
4328
                    if id >= 0:
 
4329
                        notebook.SetSelection(id)
 
4330
                    self.ShowPane(notebook, True)
 
4331
 
 
4332
            else:
 
4333
                p.Show(show)
 
4334
 
 
4335
            if p.frame:
 
4336
                p.frame.Raise()
 
4337
 
 
4338
            self.Update()
 
4339
 
 
4340
 
 
4341
    def HitTest(self, x, y):
 
4342
        """
 
4343
        This is an internal function which determines
 
4344
        which UI item the specified coordinates are over.
 
4345
 
 
4346
        :param integer `x`: specifies a x position in client coordinates;
 
4347
        :param integer `y`: specifies a y position in client coordinates.
 
4348
        """
 
4349
 
 
4350
        result = None
 
4351
 
 
4352
        for item in self._uiparts:
 
4353
            # we are not interested in typeDock, because this space
 
4354
            # isn't used to draw anything, just for measurements
 
4355
            # besides, the entire dock area is covered with other
 
4356
            # rectangles, which we are interested in.
 
4357
            if item.type == AuiDockUIPart.typeDock:
 
4358
                continue
 
4359
 
 
4360
            # if we already have a hit on a more specific item, we are not
 
4361
            # interested in a pane hit.  If, however, we don't already have
 
4362
            # a hit, returning a pane hit is necessary for some operations
 
4363
            if item.type in [AuiDockUIPart.typePane, AuiDockUIPart.typePaneBorder] and result:
 
4364
                continue
 
4365
 
 
4366
            # if the point is inside the rectangle, we have a hit
 
4367
            if item.rect.Contains((x, y)):
 
4368
                result = item
 
4369
 
 
4370
        return result
 
4371
 
 
4372
 
 
4373
    def PaneHitTest(self, panes, pt):
 
4374
        """
 
4375
        Similar to :meth:`HitTest`, but it checks in which :class:`AuiManager` rectangle the
 
4376
        input point belongs to.
 
4377
 
 
4378
        :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
4379
        :param Point `pt`: the mouse position.
 
4380
        """
 
4381
 
 
4382
        for paneInfo in panes:
 
4383
            if paneInfo.IsDocked() and paneInfo.IsShown() and paneInfo.rect.Contains(pt):
 
4384
                return paneInfo
 
4385
 
 
4386
        return NonePaneInfo
 
4387
 
 
4388
 
 
4389
    # SetAGWFlags() and GetAGWFlags() allow the owner to set various
 
4390
    # options which are global to AuiManager
 
4391
 
 
4392
    def SetAGWFlags(self, agwFlags):
 
4393
        """
 
4394
        This method is used to specify :class:`AuiManager` 's settings flags.
 
4395
 
 
4396
        :param integer `agwFlags`: specifies options which allow the frame management behavior
 
4397
         to be modified. `agwFlags` can be one of the following style bits:
 
4398
 
 
4399
         ==================================== ==================================
 
4400
         Flag name                            Description
 
4401
         ==================================== ==================================
 
4402
         ``AUI_MGR_ALLOW_FLOATING``           Allow floating of panes
 
4403
         ``AUI_MGR_ALLOW_ACTIVE_PANE``        If a pane becomes active, "highlight" it in the interface
 
4404
         ``AUI_MGR_TRANSPARENT_DRAG``         If the platform supports it, set transparency on a floating pane while it is dragged by the user
 
4405
         ``AUI_MGR_TRANSPARENT_HINT``         If the platform supports it, show a transparent hint window when the user is about to dock a floating pane
 
4406
         ``AUI_MGR_VENETIAN_BLINDS_HINT``     Show a "venetian blind" effect when the user is about to dock a floating pane
 
4407
         ``AUI_MGR_RECTANGLE_HINT``           Show a rectangle hint effect when the user is about to dock a floating pane
 
4408
         ``AUI_MGR_HINT_FADE``                If the platform supports it, the hint window will fade in and out
 
4409
         ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``  Disables the "venetian blind" fade in and out
 
4410
         ``AUI_MGR_LIVE_RESIZE``              Live resize when the user drag a sash
 
4411
         ``AUI_MGR_ANIMATE_FRAMES``           Fade-out floating panes when they are closed (all platforms which support frames transparency)
 
4412
                                              and show a moving rectangle when they are docked (Windows < Vista and GTK only)
 
4413
         ``AUI_MGR_AERO_DOCKING_GUIDES``      Use the new Aero-style bitmaps as docking guides
 
4414
         ``AUI_MGR_PREVIEW_MINIMIZED_PANES``  Slide in and out minimized panes to preview them
 
4415
         ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``   Use the new Whidbey-style bitmaps as docking guides
 
4416
         ``AUI_MGR_SMOOTH_DOCKING``           Performs a "smooth" docking of panes (a la PyQT)
 
4417
         ``AUI_MGR_USE_NATIVE_MINIFRAMES``    Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMAC)
 
4418
         ``AUI_MGR_AUTONB_NO_CAPTION``        Panes that merge into an automatic notebook will not have the pane caption visible
 
4419
         ==================================== ==================================
 
4420
 
 
4421
         .. note::
 
4422
 
 
4423
            If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a
 
4424
            floating pane caption will not re-dock the pane, but simply maximize it (if
 
4425
            :meth:`AuiPaneInfo.MaximizeButton` has been set to ``True``) or do nothing.
 
4426
 
 
4427
        """
 
4428
 
 
4429
        self._agwFlags = agwFlags
 
4430
 
 
4431
        if len(self._guides) > 0:
 
4432
            self.CreateGuideWindows()
 
4433
 
 
4434
        if self._hint_window and agwFlags & AUI_MGR_RECTANGLE_HINT == 0:
 
4435
            self.CreateHintWindow()
 
4436
 
 
4437
 
 
4438
    def GetAGWFlags(self):
 
4439
        """
 
4440
        Returns the current manager's flags.
 
4441
 
 
4442
        :see: :meth:`SetAGWFlags` for a list of possible :class:`AuiManager` flags.
 
4443
        """
 
4444
 
 
4445
        return self._agwFlags
 
4446
 
 
4447
 
 
4448
    def SetManagedWindow(self, managed_window):
 
4449
        """
 
4450
        Called to specify the frame or window which is to be managed by :class:`AuiManager`.
 
4451
        Frame management is not restricted to just frames. Child windows or custom
 
4452
        controls are also allowed.
 
4453
 
 
4454
        :param Window `managed_window`: specifies the window which should be managed by
 
4455
         the AUI manager.
 
4456
        """
 
4457
 
 
4458
        if not managed_window:
 
4459
            raise Exception("Specified managed window must be non-null. ")
 
4460
 
 
4461
        self.UnInit()
 
4462
 
 
4463
        self._frame = managed_window
 
4464
        self._frame.PushEventHandler(self)
 
4465
 
 
4466
        # if the owner is going to manage an MDI parent frame,
 
4467
        # we need to add the MDI client window as the default
 
4468
        # center pane
 
4469
 
 
4470
        if isinstance(self._frame, wx.MDIParentFrame):
 
4471
            mdi_frame = self._frame
 
4472
            client_window = mdi_frame.GetClientWindow()
 
4473
 
 
4474
            if not client_window:
 
4475
                raise Exception("Client window is None!")
 
4476
 
 
4477
            self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
 
4478
                         CenterPane().PaneBorder(False))
 
4479
 
 
4480
        elif isinstance(self._frame, tabmdi.AuiMDIParentFrame):
 
4481
 
 
4482
            mdi_frame = self._frame
 
4483
            client_window = mdi_frame.GetClientWindow()
 
4484
 
 
4485
            if not client_window:
 
4486
                raise Exception("Client window is None!")
 
4487
 
 
4488
            self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
 
4489
                         CenterPane().PaneBorder(False))
 
4490
 
 
4491
 
 
4492
    def GetManagedWindow(self):
 
4493
        """ Returns the window being managed by :class:`AuiManager`. """
 
4494
 
 
4495
        return self._frame
 
4496
 
 
4497
 
 
4498
    def SetFrame(self, managed_window):
 
4499
        """
 
4500
        Called to specify the frame or window which is to be managed by :class:`AuiManager`.
 
4501
        Frame management is not restricted to just frames. Child windows or custom
 
4502
        controls are also allowed.
 
4503
 
 
4504
        :param Window `managed_window`: specifies the window which should be managed by
 
4505
         the AUI manager.
 
4506
 
 
4507
        .. deprecated:: 0.6
 
4508
           This method is now deprecated, use :meth:`SetManagedWindow` instead.
 
4509
        """
 
4510
 
 
4511
        DeprecationWarning("This method is deprecated, use SetManagedWindow instead.")
 
4512
        return self.SetManagedWindow(managed_window)
 
4513
 
 
4514
 
 
4515
    def GetFrame(self):
 
4516
        """
 
4517
        Returns the window being managed by :class:`AuiManager`.
 
4518
 
 
4519
        .. deprecated:: 0.6
 
4520
           This method is now deprecated, use :meth:`GetManagedWindow` instead.
 
4521
        """
 
4522
 
 
4523
        DeprecationWarning("This method is deprecated, use GetManagedWindow instead.")
 
4524
        return self._frame
 
4525
 
 
4526
 
 
4527
    def CreateGuideWindows(self):
 
4528
        """ Creates the VS2005 HUD guide windows. """
 
4529
 
 
4530
        self.DestroyGuideWindows()
 
4531
 
 
4532
        self._guides.append(AuiDockingGuideInfo().Left().
 
4533
                            Host(AuiSingleDockingGuide(self._frame, wx.LEFT)))
 
4534
        self._guides.append(AuiDockingGuideInfo().Top().
 
4535
                            Host(AuiSingleDockingGuide(self._frame, wx.TOP)))
 
4536
        self._guides.append(AuiDockingGuideInfo().Right().
 
4537
                            Host(AuiSingleDockingGuide(self._frame, wx.RIGHT)))
 
4538
        self._guides.append(AuiDockingGuideInfo().Bottom().
 
4539
                            Host(AuiSingleDockingGuide(self._frame, wx.BOTTOM)))
 
4540
        self._guides.append(AuiDockingGuideInfo().Centre().
 
4541
                            Host(AuiCenterDockingGuide(self._frame)))
 
4542
 
 
4543
 
 
4544
    def DestroyGuideWindows(self):
 
4545
        """ Destroys the VS2005 HUD guide windows. """
 
4546
 
 
4547
        for guide in self._guides:
 
4548
            if guide.host:
 
4549
                guide.host.Destroy()
 
4550
 
 
4551
        self._guides = []
 
4552
 
 
4553
 
 
4554
    def CreateHintWindow(self):
 
4555
        """ Creates the standard wxAUI hint window. """
 
4556
 
 
4557
        self.DestroyHintWindow()
 
4558
 
 
4559
        self._hint_window = AuiDockingHintWindow(self._frame)
 
4560
        self._hint_window.SetBlindMode(self._agwFlags)
 
4561
 
 
4562
 
 
4563
    def DestroyHintWindow(self):
 
4564
        """ Destroys the standard wxAUI hint window. """
 
4565
 
 
4566
        if self._hint_window:
 
4567
 
 
4568
            self._hint_window.Destroy()
 
4569
            self._hint_window = None
 
4570
 
 
4571
 
 
4572
    def UnInit(self):
 
4573
        """
 
4574
        Uninitializes the framework and should be called before a managed frame or
 
4575
        window is destroyed. :meth:`UnInit` is usually called in the managed :class:`Frame` / :class:`Window`
 
4576
        destructor.
 
4577
 
 
4578
        It is necessary to call this function before the managed frame or window is
 
4579
        destroyed, otherwise the manager cannot remove its custom event handlers
 
4580
        from a window.
 
4581
        """
 
4582
 
 
4583
        if not self._frame:
 
4584
            return
 
4585
 
 
4586
        for klass in [self._frame] + list(self._frame.GetChildren()):
 
4587
            handler = klass.GetEventHandler()
 
4588
            if klass is not handler:
 
4589
                if isinstance(handler, AuiManager):
 
4590
                    klass.RemoveEventHandler(handler)
 
4591
 
 
4592
 
 
4593
    def OnDestroy(self, event) :
 
4594
 
 
4595
        if self._frame == event.GetEventObject():
 
4596
            self.UnInit();
 
4597
 
 
4598
 
 
4599
    def GetArtProvider(self):
 
4600
        """ Returns the current art provider being used. """
 
4601
 
 
4602
        return self._art
 
4603
 
 
4604
 
 
4605
    def ProcessMgrEvent(self, event):
 
4606
        """
 
4607
        Process the AUI events sent to the manager.
 
4608
 
 
4609
        :param `event`: the event to process, an instance of :class:`AuiManagerEvent`.
 
4610
        """
 
4611
 
 
4612
        # first, give the owner frame a chance to override
 
4613
        if self._frame:
 
4614
            if self._frame.GetEventHandler().ProcessEvent(event):
 
4615
                return
 
4616
 
 
4617
        self.ProcessEvent(event)
 
4618
 
 
4619
 
 
4620
    def FireEvent(self, evtType, pane, canVeto=False):
 
4621
        """
 
4622
        Fires one of the ``EVT_AUI_PANE_FLOATED`` / ``FLOATING`` / ``DOCKING`` / ``DOCKED`` / ``ACTIVATED`` event.
 
4623
 
 
4624
        :param integer `evtType`: one of the aforementioned events;
 
4625
        :param `pane`: the :class:`AuiPaneInfo` instance associated to this event;
 
4626
        :param bool `canVeto`: whether the event can be vetoed or not.
 
4627
        """
 
4628
 
 
4629
        event = AuiManagerEvent(evtType)
 
4630
        event.SetPane(pane)
 
4631
        event.SetCanVeto(canVeto)
 
4632
        self.ProcessMgrEvent(event)
 
4633
 
 
4634
        return event
 
4635
 
 
4636
 
 
4637
    def CanUseModernDockArt(self):
 
4638
        """
 
4639
        Returns whether :class:`dockart` can be used (Windows XP / Vista / 7 only,
 
4640
        requires Mark Hammonds's `pywin32 <http://sourceforge.net/projects/pywin32/>`_ package).
 
4641
        """
 
4642
 
 
4643
        if not _winxptheme:
 
4644
            return False
 
4645
 
 
4646
        # Get the size of a small close button (themed)
 
4647
        hwnd = self._frame.GetHandle()
 
4648
        hTheme = winxptheme.OpenThemeData(hwnd, "Window")
 
4649
 
 
4650
        if not hTheme:
 
4651
            return False
 
4652
 
 
4653
        return True
 
4654
 
 
4655
 
 
4656
    def SetArtProvider(self, art_provider):
 
4657
        """
 
4658
        Instructs :class:`AuiManager` to use art provider specified by the parameter
 
4659
        `art_provider` for all drawing calls. This allows plugable look-and-feel
 
4660
        features.
 
4661
 
 
4662
        :param `art_provider`: a AUI dock art provider.
 
4663
 
 
4664
        :note: The previous art provider object, if any, will be deleted by :class:`AuiManager`.
 
4665
        """
 
4666
 
 
4667
        # delete the last art provider, if any
 
4668
        del self._art
 
4669
 
 
4670
        # assign the new art provider
 
4671
        self._art = art_provider
 
4672
 
 
4673
        for pane in self.GetAllPanes():
 
4674
            if pane.IsFloating() and pane.frame:
 
4675
                pane.frame._mgr.SetArtProvider(art_provider)
 
4676
                pane.frame._mgr.Update()
 
4677
 
 
4678
 
 
4679
    def AddPane(self, window, arg1=None, arg2=None, target=None):
 
4680
        """
 
4681
        Tells the frame manager to start managing a child window. There
 
4682
        are four versions of this function. The first verison allows the full spectrum
 
4683
        of pane parameter possibilities (:meth:`AddPane1`). The second version is used for
 
4684
        simpler user interfaces which do not require as much configuration (:meth:`AddPane2`).
 
4685
        The :meth:`AddPane3` version allows a drop position to be specified, which will determine
 
4686
        where the pane will be added. The :meth:`AddPane4` version allows to turn the target
 
4687
        :class:`AuiPaneInfo` pane into a notebook and the added pane into a page.
 
4688
 
 
4689
        In your code, simply call :meth:`AddPane`.
 
4690
 
 
4691
        :param Window `window`: the child window to manage;
 
4692
        :param `arg1`: a :class:`AuiPaneInfo` or an integer value (direction);
 
4693
        :param `arg2`: a :class:`AuiPaneInfo` or a :class:`Point` (drop position);
 
4694
        :param `target`: a :class:`AuiPaneInfo` to be turned into a notebook
 
4695
         and new pane added to it as a page. (additionally, target can be any pane in
 
4696
         an existing notebook)
 
4697
         """
 
4698
 
 
4699
        if target in self._panes:
 
4700
            return self.AddPane4(window, arg1, target)
 
4701
 
 
4702
        if type(arg1) == type(1):
 
4703
            # This Is Addpane2
 
4704
            if arg1 is None:
 
4705
                arg1 = wx.LEFT
 
4706
            if arg2 is None:
 
4707
                arg2 = ""
 
4708
            return self.AddPane2(window, arg1, arg2)
 
4709
        else:
 
4710
            if isinstance(arg2, wx.Point):
 
4711
                return self.AddPane3(window, arg1, arg2)
 
4712
            else:
 
4713
                return self.AddPane1(window, arg1)
 
4714
 
 
4715
 
 
4716
    def AddPane1(self, window, pane_info):
 
4717
        """ See comments on :meth:`AddPane`. """
 
4718
 
 
4719
        # check if the pane has a valid window
 
4720
        if not window:
 
4721
            return False
 
4722
 
 
4723
        # check if the pane already exists
 
4724
        if self.GetPane(pane_info.window).IsOk():
 
4725
            return False
 
4726
 
 
4727
        # check if the pane name already exists, this could reveal a
 
4728
        # bug in the library user's application
 
4729
        already_exists = False
 
4730
        if pane_info.name != "" and self.GetPane(pane_info.name).IsOk():
 
4731
            warnings.warn("A pane with the name '%s' already exists in the manager!"%pane_info.name)
 
4732
            already_exists = True
 
4733
 
 
4734
        # if the new pane is docked then we should undo maximize
 
4735
        if pane_info.IsDocked():
 
4736
            self.RestoreMaximizedPane()
 
4737
 
 
4738
        self._panes.append(pane_info)
 
4739
        pinfo = self._panes[-1]
 
4740
 
 
4741
        # set the pane window
 
4742
        pinfo.window = window
 
4743
 
 
4744
        # if the pane's name identifier is blank, create a random string
 
4745
        if pinfo.name == "" or already_exists:
 
4746
            pinfo.name = ("%s%08x%08x%08x")%(pinfo.window.GetName(), time.time(),
 
4747
                                             time.clock(), len(self._panes))
 
4748
 
 
4749
        # set initial proportion (if not already set)
 
4750
        if pinfo.dock_proportion == 0:
 
4751
            pinfo.dock_proportion = 100000
 
4752
 
 
4753
        floating = isinstance(self._frame, AuiFloatingFrame)
 
4754
 
 
4755
        pinfo.buttons = []
 
4756
 
 
4757
        if not floating and pinfo.HasMinimizeButton():
 
4758
            button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
 
4759
            pinfo.buttons.append(button)
 
4760
 
 
4761
        if not floating and pinfo.HasMaximizeButton():
 
4762
            button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
 
4763
            pinfo.buttons.append(button)
 
4764
 
 
4765
        if not floating and pinfo.HasPinButton():
 
4766
            button = AuiPaneButton(AUI_BUTTON_PIN)
 
4767
            pinfo.buttons.append(button)
 
4768
 
 
4769
        if pinfo.HasCloseButton():
 
4770
            button = AuiPaneButton(AUI_BUTTON_CLOSE)
 
4771
            pinfo.buttons.append(button)
 
4772
 
 
4773
        if pinfo.HasGripper():
 
4774
            if isinstance(pinfo.window, auibar.AuiToolBar):
 
4775
                # prevent duplicate gripper -- both AuiManager and AuiToolBar
 
4776
                # have a gripper control.  The toolbar's built-in gripper
 
4777
                # meshes better with the look and feel of the control than ours,
 
4778
                # so turn AuiManager's gripper off, and the toolbar's on.
 
4779
 
 
4780
                tb = pinfo.window
 
4781
                pinfo.SetFlag(AuiPaneInfo.optionGripper, False)
 
4782
                tb.SetGripperVisible(True)
 
4783
 
 
4784
        if pinfo.window:
 
4785
            if pinfo.best_size == wx.Size(-1, -1):
 
4786
                pinfo.best_size = pinfo.window.GetClientSize()
 
4787
 
 
4788
            if isinstance(pinfo.window, wx.ToolBar):
 
4789
                # GetClientSize() doesn't get the best size for
 
4790
                # a toolbar under some newer versions of wxWidgets,
 
4791
                # so use GetBestSize()
 
4792
                pinfo.best_size = pinfo.window.GetBestSize()
 
4793
 
 
4794
                # this is needed for Win2000 to correctly fill toolbar backround
 
4795
                # it should probably be repeated once system colour change happens
 
4796
                if wx.Platform == "__WXMSW__" and pinfo.window.UseBgCol():
 
4797
                    pinfo.window.SetBackgroundColour(self.GetArtProvider().GetColour(AUI_DOCKART_BACKGROUND_COLOUR))
 
4798
 
 
4799
            if pinfo.min_size != wx.Size(-1, -1):
 
4800
                if pinfo.best_size.x < pinfo.min_size.x:
 
4801
                    pinfo.best_size.x = pinfo.min_size.x
 
4802
                if pinfo.best_size.y < pinfo.min_size.y:
 
4803
                    pinfo.best_size.y = pinfo.min_size.y
 
4804
 
 
4805
        self._panes[-1] = pinfo
 
4806
        if isinstance(window, auibar.AuiToolBar):
 
4807
            window.SetAuiManager(self)
 
4808
 
 
4809
        return True
 
4810
 
 
4811
 
 
4812
    def AddPane2(self, window, direction, caption):
 
4813
        """ See comments on :meth:`AddPane`. """
 
4814
 
 
4815
        pinfo = AuiPaneInfo()
 
4816
        pinfo.Caption(caption)
 
4817
 
 
4818
        if direction == wx.TOP:
 
4819
            pinfo.Top()
 
4820
        elif direction == wx.BOTTOM:
 
4821
            pinfo.Bottom()
 
4822
        elif direction == wx.LEFT:
 
4823
            pinfo.Left()
 
4824
        elif direction == wx.RIGHT:
 
4825
            pinfo.Right()
 
4826
        elif direction == wx.CENTER:
 
4827
            pinfo.CenterPane()
 
4828
 
 
4829
        return self.AddPane(window, pinfo)
 
4830
 
 
4831
 
 
4832
    def AddPane3(self, window, pane_info, drop_pos):
 
4833
        """ See comments on :meth:`AddPane`. """
 
4834
 
 
4835
        if not self.AddPane(window, pane_info):
 
4836
            return False
 
4837
 
 
4838
        pane = self.GetPane(window)
 
4839
        indx = self._panes.index(pane)
 
4840
 
 
4841
        ret, pane = self.DoDrop(self._docks, self._panes, pane, drop_pos, wx.Point(0, 0))
 
4842
        self._panes[indx] = pane
 
4843
 
 
4844
        return True
 
4845
 
 
4846
 
 
4847
    def AddPane4(self, window, pane_info, target):
 
4848
        """ See comments on :meth:`AddPane`. """
 
4849
 
 
4850
        if not self.AddPane(window, pane_info):
 
4851
            return False
 
4852
 
 
4853
        paneInfo = self.GetPane(window)
 
4854
 
 
4855
        if not paneInfo.IsNotebookDockable():
 
4856
            return self.AddPane1(window, pane_info)
 
4857
        if not target.IsNotebookDockable() and not target.IsNotebookControl():
 
4858
            return self.AddPane1(window, pane_info)
 
4859
 
 
4860
        if not target.HasNotebook():
 
4861
            self.CreateNotebookBase(self._panes, target)
 
4862
 
 
4863
        # Add new item to notebook
 
4864
        paneInfo.NotebookPage(target.notebook_id)
 
4865
 
 
4866
        # we also want to remove our captions sometimes
 
4867
        self.RemoveAutoNBCaption(paneInfo)
 
4868
        self.UpdateNotebook()
 
4869
 
 
4870
        return True
 
4871
 
 
4872
 
 
4873
    def InsertPane(self, window, pane_info, insert_level=AUI_INSERT_PANE):
 
4874
        """
 
4875
        This method is used to insert either a previously unmanaged pane window
 
4876
        into the frame manager, or to insert a currently managed pane somewhere else.
 
4877
        :meth:`InsertPane` will push all panes, rows, or docks aside and insert the window
 
4878
        into the position specified by `pane_info`.
 
4879
 
 
4880
        Because `pane_info` can specify either a pane, dock row, or dock layer, the
 
4881
        `insert_level` parameter is used to disambiguate this. The parameter `insert_level`
 
4882
        can take a value of ``AUI_INSERT_PANE``, ``AUI_INSERT_ROW`` or ``AUI_INSERT_DOCK``.
 
4883
 
 
4884
        :param Window `window`: the window to be inserted and managed;
 
4885
        :param `pane_info`: the insert location for the new window;
 
4886
        :param integer `insert_level`: the insertion level of the new pane.
 
4887
        """
 
4888
 
 
4889
        if not window:
 
4890
            raise Exception("Invalid window passed to InsertPane.")
 
4891
 
 
4892
        # shift the panes around, depending on the insert level
 
4893
        if insert_level == AUI_INSERT_PANE:
 
4894
            self._panes = DoInsertPane(self._panes, pane_info.dock_direction,
 
4895
                                       pane_info.dock_layer, pane_info.dock_row,
 
4896
                                       pane_info.dock_pos)
 
4897
 
 
4898
        elif insert_level == AUI_INSERT_ROW:
 
4899
            self._panes = DoInsertDockRow(self._panes, pane_info.dock_direction,
 
4900
                                          pane_info.dock_layer, pane_info.dock_row)
 
4901
 
 
4902
        elif insert_level == AUI_INSERT_DOCK:
 
4903
            self._panes = DoInsertDockLayer(self._panes, pane_info.dock_direction,
 
4904
                                            pane_info.dock_layer)
 
4905
 
 
4906
        # if the window already exists, we are basically just moving/inserting the
 
4907
        # existing window.  If it doesn't exist, we need to add it and insert it
 
4908
        existing_pane = self.GetPane(window)
 
4909
        indx = self._panes.index(existing_pane)
 
4910
 
 
4911
        if not existing_pane.IsOk():
 
4912
 
 
4913
            return self.AddPane(window, pane_info)
 
4914
 
 
4915
        else:
 
4916
 
 
4917
            if pane_info.IsFloating():
 
4918
                existing_pane.Float()
 
4919
                if pane_info.floating_pos != wx.Point(-1, -1):
 
4920
                    existing_pane.FloatingPosition(pane_info.floating_pos)
 
4921
                if pane_info.floating_size != wx.Size(-1, -1):
 
4922
                    existing_pane.FloatingSize(pane_info.floating_size)
 
4923
            else:
 
4924
                # if the new pane is docked then we should undo maximize
 
4925
                self.RestoreMaximizedPane()
 
4926
 
 
4927
                existing_pane.Direction(pane_info.dock_direction)
 
4928
                existing_pane.Layer(pane_info.dock_layer)
 
4929
                existing_pane.Row(pane_info.dock_row)
 
4930
                existing_pane.Position(pane_info.dock_pos)
 
4931
 
 
4932
            self._panes[indx] = existing_pane
 
4933
 
 
4934
        return True
 
4935
 
 
4936
 
 
4937
    def DetachPane(self, window):
 
4938
        """
 
4939
        Tells the :class:`AuiManager` to stop managing the pane specified
 
4940
        by `window`. The window, if in a floated frame, is reparented to the frame
 
4941
        managed by :class:`AuiManager`.
 
4942
 
 
4943
        :param Window `window`: the window to be un-managed.
 
4944
        """
 
4945
 
 
4946
        for p in self._panes:
 
4947
            if p.window == window:
 
4948
                if p.frame:
 
4949
                    # we have a floating frame which is being detached. We need to
 
4950
                    # reparent it to self._frame and destroy the floating frame
 
4951
 
 
4952
                    # reduce flicker
 
4953
                    p.window.SetSize((1, 1))
 
4954
                    if p.frame.IsShown():
 
4955
                        p.frame.Show(False)
 
4956
 
 
4957
                    if self._action_window == p.frame:
 
4958
                        self._action_window = None
 
4959
 
 
4960
                    # reparent to self._frame and destroy the pane
 
4961
                    p.window.Reparent(self._frame)
 
4962
                    p.frame.SetSizer(None)
 
4963
                    p.frame.Destroy()
 
4964
                    p.frame = None
 
4965
 
 
4966
                elif p.IsNotebookPage():
 
4967
                    notebook = self._notebooks[p.notebook_id]
 
4968
                    id = notebook.GetPageIndex(p.window)
 
4969
                    notebook.RemovePage(id)
 
4970
 
 
4971
                # make sure there are no references to this pane in our uiparts,
 
4972
                # just in case the caller doesn't call Update() immediately after
 
4973
                # the DetachPane() call.  This prevets obscure crashes which would
 
4974
                # happen at window repaint if the caller forgets to call Update()
 
4975
                counter = 0
 
4976
                for pi in xrange(len(self._uiparts)):
 
4977
                    part = self._uiparts[counter]
 
4978
                    if part.pane == p:
 
4979
                        self._uiparts.pop(counter)
 
4980
                        counter -= 1
 
4981
 
 
4982
                    counter += 1
 
4983
 
 
4984
                self._panes.remove(p)
 
4985
                return True
 
4986
 
 
4987
        return False
 
4988
 
 
4989
 
 
4990
    def ClosePane(self, pane_info):
 
4991
        """
 
4992
        Destroys or hides the pane depending on its flags.
 
4993
 
 
4994
        :param `pane_info`: a :class:`AuiPaneInfo` instance.
 
4995
        """
 
4996
 
 
4997
        # if we were maximized, restore
 
4998
        if pane_info.IsMaximized():
 
4999
            self.RestorePane(pane_info)
 
5000
 
 
5001
        if pane_info.frame:
 
5002
            if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
 
5003
                pane_info.frame.FadeOut()
 
5004
 
 
5005
        # first, hide the window
 
5006
        if pane_info.window and pane_info.window.IsShown():
 
5007
            pane_info.window.Show(False)
 
5008
 
 
5009
        # make sure that we are the parent of this window
 
5010
        if pane_info.window and pane_info.window.GetParent() != self._frame:
 
5011
            pane_info.window.Reparent(self._frame)
 
5012
 
 
5013
        # if we have a frame, destroy it
 
5014
        if pane_info.frame:
 
5015
            pane_info.frame.Destroy()
 
5016
            pane_info.frame = None
 
5017
 
 
5018
        elif pane_info.IsNotebookPage():
 
5019
            # if we are a notebook page, remove ourselves...
 
5020
            # the  code would index out of bounds
 
5021
            # if the last page of a sub-notebook was closed
 
5022
            # because the notebook would be deleted, before this
 
5023
            # code is executed.
 
5024
            # This code just prevents an out-of bounds error.
 
5025
            if self._notebooks:
 
5026
                nid = pane_info.notebook_id
 
5027
                if nid >= 0 and nid < len(self._notebooks):
 
5028
                    notebook = self._notebooks[nid]
 
5029
                    page_idx = notebook.GetPageIndex(pane_info.window)
 
5030
                    if page_idx >= 0:
 
5031
                        notebook.RemovePage(page_idx)
 
5032
 
 
5033
        # now we need to either destroy or hide the pane
 
5034
        to_destroy = 0
 
5035
        if pane_info.IsDestroyOnClose():
 
5036
            to_destroy = pane_info.window
 
5037
            self.DetachPane(to_destroy)
 
5038
        else:
 
5039
            if isinstance(pane_info.window, auibar.AuiToolBar) and pane_info.IsFloating():
 
5040
                tb = pane_info.window
 
5041
                if pane_info.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]:
 
5042
                    tb.SetAGWWindowStyleFlag(tb.GetAGWWindowStyleFlag() | AUI_TB_VERTICAL)
 
5043
 
 
5044
            pane_info.Dock().Hide()
 
5045
 
 
5046
        if pane_info.IsNotebookControl():
 
5047
 
 
5048
            notebook = self._notebooks[pane_info.notebook_id]
 
5049
            while notebook.GetPageCount():
 
5050
                window = notebook.GetPage(0)
 
5051
                notebook.RemovePage(0)
 
5052
                info = self.GetPane(window)
 
5053
                if info.IsOk():
 
5054
                    info.notebook_id = -1
 
5055
                    info.dock_direction = AUI_DOCK_NONE
 
5056
                    # Note: this could change our paneInfo reference ...
 
5057
                    self.ClosePane(info)
 
5058
 
 
5059
        if to_destroy:
 
5060
            to_destroy.Destroy()
 
5061
 
 
5062
 
 
5063
    def MaximizePane(self, pane_info, savesizes=True):
 
5064
        """
 
5065
        Maximizes the input pane.
 
5066
 
 
5067
        :param `pane_info`: a :class:`AuiPaneInfo` instance.
 
5068
        :param bool `savesizes`: whether to save previous dock sizes.
 
5069
        """
 
5070
 
 
5071
        if savesizes:
 
5072
            self.SavePreviousDockSizes(pane_info)
 
5073
 
 
5074
        for p in self._panes:
 
5075
 
 
5076
            # save hidden state
 
5077
            p.SetFlag(p.savedHiddenState, p.HasFlag(p.optionHidden))
 
5078
 
 
5079
            if not p.IsToolbar() and not p.IsFloating():
 
5080
                p.Restore()
 
5081
 
 
5082
                # hide the pane, because only the newly
 
5083
                # maximized pane should show
 
5084
                p.Hide()
 
5085
 
 
5086
        pane_info.previousDockPos = pane_info.dock_pos
 
5087
 
 
5088
        # mark ourselves maximized
 
5089
        pane_info.Maximize()
 
5090
        pane_info.Show()
 
5091
        self._has_maximized = True
 
5092
 
 
5093
        # last, show the window
 
5094
        if pane_info.window and not pane_info.window.IsShown():
 
5095
            pane_info.window.Show(True)
 
5096
 
 
5097
 
 
5098
    def SavePreviousDockSizes(self, pane_info):
 
5099
        """
 
5100
        Stores the previous dock sizes, to be used in a "restore" action later.
 
5101
 
 
5102
        :param `pane_info`: a :class:`AuiPaneInfo` instance.
 
5103
        """
 
5104
 
 
5105
        for d in self._docks:
 
5106
            if not d.toolbar:
 
5107
                for p in d.panes:
 
5108
                    p.previousDockSize = d.size
 
5109
                    if pane_info is not p:
 
5110
                        p.SetFlag(p.needsRestore, True)
 
5111
 
 
5112
 
 
5113
    def RestorePane(self, pane_info):
 
5114
        """
 
5115
        Restores the input pane from a previous maximized or minimized state.
 
5116
 
 
5117
        :param `pane_info`: a :class:`AuiPaneInfo` instance.
 
5118
        """
 
5119
 
 
5120
        # restore all the panes
 
5121
        for p in self._panes:
 
5122
            if not p.IsToolbar():
 
5123
                p.SetFlag(p.optionHidden, p.HasFlag(p.savedHiddenState))
 
5124
 
 
5125
        pane_info.SetFlag(pane_info.needsRestore, True)
 
5126
 
 
5127
        # mark ourselves non-maximized
 
5128
        pane_info.Restore()
 
5129
        self._has_maximized = False
 
5130
        self._has_minimized = False
 
5131
 
 
5132
        # last, show the window
 
5133
        if pane_info.window and not pane_info.window.IsShown():
 
5134
            pane_info.window.Show(True)
 
5135
 
 
5136
 
 
5137
    def RestoreMaximizedPane(self):
 
5138
        """ Restores the current maximized pane (if any). """
 
5139
 
 
5140
        # restore all the panes
 
5141
        for p in self._panes:
 
5142
            if p.IsMaximized():
 
5143
                self.RestorePane(p)
 
5144
                break
 
5145
 
 
5146
 
 
5147
    def ActivatePane(self, window):
 
5148
        """
 
5149
        Activates the pane to which `window` is associated.
 
5150
 
 
5151
        :param `window`: a :class:`Window` derived window.
 
5152
        """
 
5153
 
 
5154
        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
 
5155
            while window:
 
5156
                ret, self._panes = SetActivePane(self._panes, window)
 
5157
                if ret:
 
5158
                    break
 
5159
 
 
5160
                window = window.GetParent()
 
5161
 
 
5162
            self.RefreshCaptions()
 
5163
            self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, window, canVeto=False)
 
5164
 
 
5165
 
 
5166
    def CreateNotebook(self):
 
5167
        """
 
5168
        Creates an automatic :class:`~lib.agw.aui.auibook.AuiNotebook` when a pane is docked on
 
5169
        top of another pane.
 
5170
        """
 
5171
 
 
5172
        notebook = auibook.AuiNotebook(self._frame, -1, wx.Point(0, 0), wx.Size(0, 0), agwStyle=self._autoNBStyle)
 
5173
 
 
5174
        # This is so we can get the tab-drag event.
 
5175
        notebook.GetAuiManager().SetMasterManager(self)
 
5176
        notebook.SetArtProvider(self._autoNBTabArt.Clone())
 
5177
        self._notebooks.append(notebook)
 
5178
 
 
5179
        return notebook
 
5180
 
 
5181
 
 
5182
    def SetAutoNotebookTabArt(self, art):
 
5183
        """
 
5184
        Sets the default tab art provider for automatic notebooks.
 
5185
 
 
5186
        :param `art`: a tab art provider.
 
5187
        """
 
5188
 
 
5189
        for nb in self._notebooks:
 
5190
            nb.SetArtProvider(art.Clone())
 
5191
            nb.Refresh()
 
5192
            nb.Update()
 
5193
 
 
5194
        self._autoNBTabArt = art
 
5195
 
 
5196
 
 
5197
    def GetAutoNotebookTabArt(self):
 
5198
        """ Returns the default tab art provider for automatic notebooks. """
 
5199
 
 
5200
        return self._autoNBTabArt
 
5201
 
 
5202
 
 
5203
    def SetAutoNotebookStyle(self, agwStyle):
 
5204
        """
 
5205
        Sets the default AGW-specific window style for automatic notebooks.
 
5206
 
 
5207
        :param integer `agwStyle`: the underlying :class:`~lib.agw.aui.auibook.AuiNotebook` window style.
 
5208
         This can be a combination of the following bits:
 
5209
 
 
5210
         ==================================== ==================================
 
5211
         Flag name                            Description
 
5212
         ==================================== ==================================
 
5213
         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
 
5214
         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
 
5215
         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
 
5216
         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
 
5217
         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
 
5218
         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
 
5219
         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
 
5220
         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
 
5221
         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
 
5222
         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
 
5223
         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
 
5224
         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
 
5225
         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
 
5226
         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close :class:`~lib.agw.aui.auibook.AuiNotebook` tabs by mouse middle button click
 
5227
         ``AUI_NB_SUB_NOTEBOOK``              This style is used by :class:`AuiManager` to create automatic AuiNotebooks
 
5228
         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
 
5229
         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
 
5230
         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
 
5231
         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
 
5232
         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less
 
5233
                                              full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
 
5234
         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
 
5235
         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
 
5236
         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
 
5237
         ==================================== ==================================
 
5238
 
 
5239
        """
 
5240
 
 
5241
        for nb in self._notebooks:
 
5242
            nb.SetAGWWindowStyleFlag(agwStyle)
 
5243
            nb.Refresh()
 
5244
            nb.Update()
 
5245
 
 
5246
        self._autoNBStyle = agwStyle
 
5247
 
 
5248
 
 
5249
    def GetAutoNotebookStyle(self):
 
5250
        """
 
5251
        Returns the default AGW-specific window style for automatic notebooks.
 
5252
 
 
5253
        :see: :meth:`SetAutoNotebookStyle` method for a list of possible styles.
 
5254
        """
 
5255
 
 
5256
        return self._autoNBStyle
 
5257
 
 
5258
 
 
5259
    def SavePaneInfo(self, pane):
 
5260
        """
 
5261
        This method is similar to :meth:`SavePerspective`, with the exception
 
5262
        that it only saves information about a single pane. It is used in
 
5263
        combination with :meth:`LoadPaneInfo`.
 
5264
 
 
5265
        :param `pane`: a :class:`AuiPaneInfo` instance to save.
 
5266
        """
 
5267
 
 
5268
        result = "name=" + EscapeDelimiters(pane.name) + ";"
 
5269
        result += "caption=" + EscapeDelimiters(pane.caption) + ";"
 
5270
 
 
5271
        result += "state=%u;"%pane.state
 
5272
        result += "dir=%d;"%pane.dock_direction
 
5273
        result += "layer=%d;"%pane.dock_layer
 
5274
        result += "row=%d;"%pane.dock_row
 
5275
        result += "pos=%d;"%pane.dock_pos
 
5276
        result += "prop=%d;"%pane.dock_proportion
 
5277
        result += "bestw=%d;"%pane.best_size.x
 
5278
        result += "besth=%d;"%pane.best_size.y
 
5279
        result += "minw=%d;"%pane.min_size.x
 
5280
        result += "minh=%d;"%pane.min_size.y
 
5281
        result += "maxw=%d;"%pane.max_size.x
 
5282
        result += "maxh=%d;"%pane.max_size.y
 
5283
        result += "floatx=%d;"%pane.floating_pos.x
 
5284
        result += "floaty=%d;"%pane.floating_pos.y
 
5285
        result += "floatw=%d;"%pane.floating_size.x
 
5286
        result += "floath=%d;"%pane.floating_size.y
 
5287
        result += "notebookid=%d;"%pane.notebook_id
 
5288
        result += "transparent=%d"%pane.transparent
 
5289
 
 
5290
        return result
 
5291
 
 
5292
 
 
5293
    def LoadPaneInfo(self, pane_part, pane):
 
5294
        """
 
5295
        This method is similar to to :meth:`LoadPerspective`, with the exception that
 
5296
        it only loads information about a single pane. It is used in combination
 
5297
        with :meth:`SavePaneInfo`.
 
5298
 
 
5299
        :param string `pane_part`: the string to analyze;
 
5300
        :param `pane`: the :class:`AuiPaneInfo` structure in which to load `pane_part`.
 
5301
        """
 
5302
 
 
5303
        # replace escaped characters so we can
 
5304
        # split up the string easily
 
5305
        pane_part = pane_part.replace("\\|", "\a")
 
5306
        pane_part = pane_part.replace("\\;", "\b")
 
5307
 
 
5308
        options = pane_part.split(";")
 
5309
        for items in options:
 
5310
 
 
5311
            val_name, value = items.split("=")
 
5312
            val_name = val_name.strip()
 
5313
 
 
5314
            if val_name == "name":
 
5315
                pane.name = value
 
5316
            elif val_name == "caption":
 
5317
                pane.caption = value
 
5318
            elif val_name == "state":
 
5319
                pane.state = int(value)
 
5320
            elif val_name == "dir":
 
5321
                pane.dock_direction = int(value)
 
5322
            elif val_name == "layer":
 
5323
                pane.dock_layer = int(value)
 
5324
            elif val_name == "row":
 
5325
                pane.dock_row = int(value)
 
5326
            elif val_name == "pos":
 
5327
                pane.dock_pos = int(value)
 
5328
            elif val_name == "prop":
 
5329
                pane.dock_proportion = int(value)
 
5330
            elif val_name == "bestw":
 
5331
                pane.best_size.x = int(value)
 
5332
            elif val_name == "besth":
 
5333
                pane.best_size.y = int(value)
 
5334
                pane.best_size = wx.Size(pane.best_size.x, pane.best_size.y)
 
5335
            elif val_name == "minw":
 
5336
                pane.min_size.x = int(value)
 
5337
            elif val_name == "minh":
 
5338
                pane.min_size.y = int(value)
 
5339
                pane.min_size = wx.Size(pane.min_size.x, pane.min_size.y)
 
5340
            elif val_name == "maxw":
 
5341
                pane.max_size.x = int(value)
 
5342
            elif val_name == "maxh":
 
5343
                pane.max_size.y = int(value)
 
5344
                pane.max_size = wx.Size(pane.max_size.x, pane.max_size.y)
 
5345
            elif val_name == "floatx":
 
5346
                pane.floating_pos.x = int(value)
 
5347
            elif val_name == "floaty":
 
5348
                pane.floating_pos.y = int(value)
 
5349
                pane.floating_pos = wx.Point(pane.floating_pos.x, pane.floating_pos.y)
 
5350
            elif val_name == "floatw":
 
5351
                pane.floating_size.x = int(value)
 
5352
            elif val_name == "floath":
 
5353
                pane.floating_size.y = int(value)
 
5354
                pane.floating_size = wx.Size(pane.floating_size.x, pane.floating_size.y)
 
5355
            elif val_name == "notebookid":
 
5356
                pane.notebook_id = int(value)
 
5357
            elif val_name == "transparent":
 
5358
                pane.transparent = int(value)
 
5359
            else:
 
5360
                raise Exception("Bad perspective string")
 
5361
 
 
5362
        # replace escaped characters so we can
 
5363
        # split up the string easily
 
5364
        pane.name = pane.name.replace("\a", "|")
 
5365
        pane.name = pane.name.replace("\b", ";")
 
5366
        pane.caption = pane.caption.replace("\a", "|")
 
5367
        pane.caption = pane.caption.replace("\b", ";")
 
5368
        pane_part = pane_part.replace("\a", "|")
 
5369
        pane_part = pane_part.replace("\b", ";")
 
5370
 
 
5371
        return pane
 
5372
 
 
5373
 
 
5374
    def SavePerspective(self):
 
5375
        """
 
5376
        Saves the entire user interface layout into an encoded string, which can then
 
5377
        be stored by the application (probably using :class:`Config`).
 
5378
 
 
5379
        When a perspective is restored using :meth:`LoadPerspective`, the entire user
 
5380
        interface will return to the state it was when the perspective was saved.
 
5381
        """
 
5382
 
 
5383
        result = "layout2|"
 
5384
 
 
5385
        for pane in self._panes:
 
5386
            result += self.SavePaneInfo(pane) + "|"
 
5387
 
 
5388
        for dock in self._docks:
 
5389
            result = result + ("dock_size(%d,%d,%d)=%d|")%(dock.dock_direction,
 
5390
                                                           dock.dock_layer,
 
5391
                                                           dock.dock_row,
 
5392
                                                           dock.size)
 
5393
        return result
 
5394
 
 
5395
 
 
5396
    def LoadPerspective(self, layout, update=True, restorecaption=False):
 
5397
        """
 
5398
        Loads a layout which was saved with :meth:`SavePerspective`.
 
5399
 
 
5400
        If the `update` flag parameter is ``True``, :meth:`Update` will be
 
5401
        automatically invoked, thus realizing the saved perspective on screen.
 
5402
 
 
5403
        :param string `layout`: a string which contains a saved AUI layout;
 
5404
        :param bool `update`: whether to update immediately the window or not;
 
5405
        :param bool `restorecaption`: ``False``, restore from persist storage,
 
5406
         otherwise use the caption defined in code.
 
5407
        """
 
5408
 
 
5409
        input = layout
 
5410
 
 
5411
        # check layout string version
 
5412
        #    'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2
 
5413
        #    'layout2' = wxAUI 0.9.2 (wxWidgets 2.8)
 
5414
        index = input.find("|")
 
5415
        part = input[0:index].strip()
 
5416
        input = input[index+1:]
 
5417
 
 
5418
        if part != "layout2":
 
5419
            return False
 
5420
 
 
5421
        # mark all panes currently managed as docked and hidden
 
5422
        saveCapt = {} # see restorecaption param
 
5423
        for pane in self._panes:
 
5424
            pane.Dock().Hide()
 
5425
            saveCapt[pane.name] = pane.caption
 
5426
 
 
5427
        # clear out the dock array; this will be reconstructed
 
5428
        self._docks = []
 
5429
 
 
5430
        # replace escaped characters so we can
 
5431
        # split up the string easily
 
5432
        input = input.replace("\\|", "\a")
 
5433
        input = input.replace("\\;", "\b")
 
5434
 
 
5435
        while 1:
 
5436
 
 
5437
            pane = AuiPaneInfo()
 
5438
            index = input.find("|")
 
5439
            pane_part = input[0:index].strip()
 
5440
            input = input[index+1:]
 
5441
 
 
5442
            # if the string is empty, we're done parsing
 
5443
            if pane_part == "":
 
5444
                break
 
5445
 
 
5446
            if pane_part[0:9] == "dock_size":
 
5447
                index = pane_part.find("=")
 
5448
                val_name = pane_part[0:index]
 
5449
                value = pane_part[index+1:]
 
5450
 
 
5451
                index = val_name.find("(")
 
5452
                piece = val_name[index+1:]
 
5453
                index = piece.find(")")
 
5454
                piece = piece[0:index]
 
5455
 
 
5456
                vals = piece.split(",")
 
5457
                dir = int(vals[0])
 
5458
                layer = int(vals[1])
 
5459
                row = int(vals[2])
 
5460
                size = int(value)
 
5461
 
 
5462
                dock = AuiDockInfo()
 
5463
                dock.dock_direction = dir
 
5464
                dock.dock_layer = layer
 
5465
                dock.dock_row = row
 
5466
                dock.size = size
 
5467
                self._docks.append(dock)
 
5468
 
 
5469
                continue
 
5470
 
 
5471
            # Undo our escaping as LoadPaneInfo needs to take an unescaped
 
5472
            # name so it can be called by external callers
 
5473
            pane_part = pane_part.replace("\a", "|")
 
5474
            pane_part = pane_part.replace("\b", ";")
 
5475
 
 
5476
            pane = self.LoadPaneInfo(pane_part, pane)
 
5477
 
 
5478
            p = self.GetPane(pane.name)
 
5479
            # restore pane caption from code
 
5480
            if restorecaption:
 
5481
                if pane.name in saveCapt:
 
5482
                    pane.Caption(saveCapt[pane.name])
 
5483
 
 
5484
            if not p.IsOk():
 
5485
                if pane.IsNotebookControl():
 
5486
                    # notebook controls - auto add...
 
5487
                    self._panes.append(pane)
 
5488
                    indx = self._panes.index(pane)
 
5489
                else:
 
5490
                    # the pane window couldn't be found
 
5491
                    # in the existing layout -- skip it
 
5492
                    continue
 
5493
 
 
5494
            else:
 
5495
                indx = self._panes.index(p)
 
5496
            pane.window = p.window
 
5497
            pane.frame = p.frame
 
5498
            pane.buttons = p.buttons
 
5499
            self._panes[indx] = pane
 
5500
 
 
5501
            if isinstance(pane.window, auibar.AuiToolBar) and (pane.IsFloatable() or pane.IsDockable()):
 
5502
                pane.window.SetGripperVisible(True)
 
5503
 
 
5504
        for p in self._panes:
 
5505
            if p.IsMinimized():
 
5506
                self.MinimizePane(p, False)
 
5507
 
 
5508
        if update:
 
5509
            self.Update()
 
5510
 
 
5511
        return True
 
5512
 
 
5513
 
 
5514
    def GetPanePositionsAndSizes(self, dock):
 
5515
        """
 
5516
        Returns all the panes positions and sizes in a dock.
 
5517
 
 
5518
        :param `dock`: a :class:`AuiDockInfo` instance.
 
5519
        """
 
5520
 
 
5521
        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
5522
        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
 
5523
        gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
 
5524
 
 
5525
        positions = []
 
5526
        sizes = []
 
5527
 
 
5528
        action_pane = -1
 
5529
        pane_count = len(dock.panes)
 
5530
 
 
5531
        # find the pane marked as our action pane
 
5532
        for pane_i in xrange(pane_count):
 
5533
            pane = dock.panes[pane_i]
 
5534
            if pane.HasFlag(AuiPaneInfo.actionPane):
 
5535
                if action_pane != -1:
 
5536
                    raise Exception("Too many action panes!")
 
5537
                action_pane = pane_i
 
5538
 
 
5539
        # set up each panes default position, and
 
5540
        # determine the size (width or height, depending
 
5541
        # on the dock's orientation) of each pane
 
5542
        for pane in dock.panes:
 
5543
            positions.append(pane.dock_pos)
 
5544
            size = 0
 
5545
 
 
5546
            if pane.HasBorder():
 
5547
                size += pane_border_size*2
 
5548
 
 
5549
            if dock.IsHorizontal():
 
5550
                if pane.HasGripper() and not pane.HasGripperTop():
 
5551
                    size += gripper_size
 
5552
 
 
5553
                if pane.HasCaptionLeft():
 
5554
                    size += caption_size
 
5555
 
 
5556
                size += pane.best_size.x
 
5557
 
 
5558
            else:
 
5559
                if pane.HasGripper() and pane.HasGripperTop():
 
5560
                    size += gripper_size
 
5561
 
 
5562
                if pane.HasCaption() and not pane.HasCaptionLeft():
 
5563
                    size += caption_size
 
5564
 
 
5565
                size += pane.best_size.y
 
5566
 
 
5567
            sizes.append(size)
 
5568
 
 
5569
        # if there is no action pane, just return the default
 
5570
        # positions (as specified in pane.pane_pos)
 
5571
        if action_pane == -1:
 
5572
            return positions, sizes
 
5573
 
 
5574
        offset = 0
 
5575
        for pane_i in xrange(action_pane-1, -1, -1):
 
5576
            amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i])
 
5577
            if amount >= 0:
 
5578
                offset += amount
 
5579
            else:
 
5580
                positions[pane_i] -= -amount
 
5581
 
 
5582
            offset += sizes[pane_i]
 
5583
 
 
5584
        # if the dock mode is fixed, make sure none of the panes
 
5585
        # overlap we will bump panes that overlap
 
5586
        offset = 0
 
5587
        for pane_i in xrange(action_pane, pane_count):
 
5588
            amount = positions[pane_i] - offset
 
5589
            if amount >= 0:
 
5590
                offset += amount
 
5591
            else:
 
5592
                positions[pane_i] += -amount
 
5593
 
 
5594
            offset += sizes[pane_i]
 
5595
 
 
5596
        return positions, sizes
 
5597
 
 
5598
 
 
5599
    def LayoutAddPane(self, cont, dock, pane, uiparts, spacer_only):
 
5600
        """
 
5601
        Adds a pane into the existing layout (in an existing dock).
 
5602
 
 
5603
        :param `cont`: a :class:`Sizer` object;
 
5604
        :param `dock`: the :class:`AuiDockInfo` structure in which to add the pane;
 
5605
        :param `pane`: the :class:`AuiPaneInfo` instance to add to the dock;
 
5606
        :param `uiparts`: a list of UI parts in the interface;
 
5607
        :param bool `spacer_only`: whether to add a simple spacer or a real window.
 
5608
        """
 
5609
 
 
5610
        sizer_item = wx.SizerItem()
 
5611
        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
5612
        gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
 
5613
        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
 
5614
        pane_button_size = self._art.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE)
 
5615
 
 
5616
        # find out the orientation of the item (orientation for panes
 
5617
        # is the same as the dock's orientation)
 
5618
 
 
5619
        if dock.IsHorizontal():
 
5620
            orientation = wx.HORIZONTAL
 
5621
        else:
 
5622
            orientation = wx.VERTICAL
 
5623
 
 
5624
        # this variable will store the proportion
 
5625
        # value that the pane will receive
 
5626
        pane_proportion = pane.dock_proportion
 
5627
 
 
5628
        horz_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
 
5629
        vert_pane_sizer = wx.BoxSizer(wx.VERTICAL)
 
5630
 
 
5631
        if pane.HasGripper():
 
5632
 
 
5633
            part = AuiDockUIPart()
 
5634
            if pane.HasGripperTop():
 
5635
                sizer_item = vert_pane_sizer.Add((1, gripper_size), 0, wx.EXPAND)
 
5636
            else:
 
5637
                sizer_item = horz_pane_sizer.Add((gripper_size, 1), 0, wx.EXPAND)
 
5638
 
 
5639
            part.type = AuiDockUIPart.typeGripper
 
5640
            part.dock = dock
 
5641
            part.pane = pane
 
5642
            part.button = None
 
5643
            part.orientation = orientation
 
5644
            part.cont_sizer = horz_pane_sizer
 
5645
            part.sizer_item = sizer_item
 
5646
            uiparts.append(part)
 
5647
 
 
5648
        button_count = len(pane.buttons)
 
5649
        button_width_total = button_count*pane_button_size
 
5650
        if button_count >= 1:
 
5651
            button_width_total += 3
 
5652
 
 
5653
        caption, captionLeft = pane.HasCaption(), pane.HasCaptionLeft()
 
5654
        button_count = len(pane.buttons)
 
5655
 
 
5656
        if captionLeft:
 
5657
            caption_sizer = wx.BoxSizer(wx.VERTICAL)
 
5658
 
 
5659
            # add pane buttons to the caption
 
5660
            dummy_parts = []
 
5661
            for btn_id in xrange(len(pane.buttons)-1, -1, -1):
 
5662
                sizer_item = caption_sizer.Add((caption_size, pane_button_size), 0, wx.EXPAND)
 
5663
                part = AuiDockUIPart()
 
5664
                part.type = AuiDockUIPart.typePaneButton
 
5665
                part.dock = dock
 
5666
                part.pane = pane
 
5667
                part.button = pane.buttons[btn_id]
 
5668
                part.orientation = orientation
 
5669
                part.cont_sizer = caption_sizer
 
5670
                part.sizer_item = sizer_item
 
5671
                dummy_parts.append(part)
 
5672
 
 
5673
            sizer_item = caption_sizer.Add((caption_size, 1), 1, wx.EXPAND)
 
5674
            vert_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
 
5675
 
 
5676
            # create the caption sizer
 
5677
            part = AuiDockUIPart()
 
5678
 
 
5679
            part.type = AuiDockUIPart.typeCaption
 
5680
            part.dock = dock
 
5681
            part.pane = pane
 
5682
            part.button = None
 
5683
            part.orientation = orientation
 
5684
            part.cont_sizer = vert_pane_sizer
 
5685
            part.sizer_item = sizer_item
 
5686
            caption_part_idx = len(uiparts)
 
5687
            uiparts.append(part)
 
5688
            uiparts.extend(dummy_parts)
 
5689
 
 
5690
        elif caption:
 
5691
 
 
5692
            caption_sizer = wx.BoxSizer(wx.HORIZONTAL)
 
5693
            sizer_item = caption_sizer.Add((1, caption_size), 1, wx.EXPAND)
 
5694
 
 
5695
            # create the caption sizer
 
5696
            part = AuiDockUIPart()
 
5697
 
 
5698
            part.type = AuiDockUIPart.typeCaption
 
5699
            part.dock = dock
 
5700
            part.pane = pane
 
5701
            part.button = None
 
5702
            part.orientation = orientation
 
5703
            part.cont_sizer = vert_pane_sizer
 
5704
            part.sizer_item = sizer_item
 
5705
            caption_part_idx = len(uiparts)
 
5706
            uiparts.append(part)
 
5707
 
 
5708
            # add pane buttons to the caption
 
5709
            for button in pane.buttons:
 
5710
                sizer_item = caption_sizer.Add((pane_button_size, caption_size), 0, wx.EXPAND)
 
5711
                part = AuiDockUIPart()
 
5712
                part.type = AuiDockUIPart.typePaneButton
 
5713
                part.dock = dock
 
5714
                part.pane = pane
 
5715
                part.button = button
 
5716
                part.orientation = orientation
 
5717
                part.cont_sizer = caption_sizer
 
5718
                part.sizer_item = sizer_item
 
5719
                uiparts.append(part)
 
5720
 
 
5721
        if caption or captionLeft:
 
5722
            # if we have buttons, add a little space to the right
 
5723
            # of them to ease visual crowding
 
5724
            if button_count >= 1:
 
5725
                if captionLeft:
 
5726
                    caption_sizer.Add((caption_size, 3), 0, wx.EXPAND)
 
5727
                else:
 
5728
                    caption_sizer.Add((3, caption_size), 0, wx.EXPAND)
 
5729
 
 
5730
            # add the caption sizer
 
5731
            sizer_item = vert_pane_sizer.Add(caption_sizer, 0, wx.EXPAND)
 
5732
            uiparts[caption_part_idx].sizer_item = sizer_item
 
5733
 
 
5734
        # add the pane window itself
 
5735
        if spacer_only or not pane.window:
 
5736
            sizer_item = vert_pane_sizer.Add((1, 1), 1, wx.EXPAND)
 
5737
        else:
 
5738
            sizer_item = vert_pane_sizer.Add(pane.window, 1, wx.EXPAND)
 
5739
            vert_pane_sizer.SetItemMinSize(pane.window, (1, 1))
 
5740
 
 
5741
        part = AuiDockUIPart()
 
5742
        part.type = AuiDockUIPart.typePane
 
5743
        part.dock = dock
 
5744
        part.pane = pane
 
5745
        part.button = None
 
5746
        part.orientation = orientation
 
5747
        part.cont_sizer = vert_pane_sizer
 
5748
        part.sizer_item = sizer_item
 
5749
        uiparts.append(part)
 
5750
 
 
5751
        # determine if the pane should have a minimum size if the pane is
 
5752
        # non-resizable (fixed) then we must set a minimum size. Alternatively,
 
5753
        # if the pane.min_size is set, we must use that value as well
 
5754
 
 
5755
        min_size = pane.min_size
 
5756
        if pane.IsFixed():
 
5757
            if min_size == wx.Size(-1, -1):
 
5758
                min_size = pane.best_size
 
5759
                pane_proportion = 0
 
5760
 
 
5761
        if min_size != wx.Size(-1, -1):
 
5762
            vert_pane_sizer.SetItemMinSize(len(vert_pane_sizer.GetChildren())-1, (min_size.x, min_size.y))
 
5763
 
 
5764
        # add the vertical/horizontal sizer (caption, pane window) to the
 
5765
        # horizontal sizer (gripper, vertical sizer)
 
5766
        horz_pane_sizer.Add(vert_pane_sizer, 1, wx.EXPAND)
 
5767
 
 
5768
        # finally, add the pane sizer to the dock sizer
 
5769
        if pane.HasBorder():
 
5770
            # allowing space for the pane's border
 
5771
            sizer_item = cont.Add(horz_pane_sizer, pane_proportion,
 
5772
                                  wx.EXPAND | wx.ALL, pane_border_size)
 
5773
            part = AuiDockUIPart()
 
5774
            part.type = AuiDockUIPart.typePaneBorder
 
5775
            part.dock = dock
 
5776
            part.pane = pane
 
5777
            part.button = None
 
5778
            part.orientation = orientation
 
5779
            part.cont_sizer = cont
 
5780
            part.sizer_item = sizer_item
 
5781
            uiparts.append(part)
 
5782
        else:
 
5783
            sizer_item = cont.Add(horz_pane_sizer, pane_proportion, wx.EXPAND)
 
5784
 
 
5785
        return uiparts
 
5786
 
 
5787
 
 
5788
    def LayoutAddDock(self, cont, dock, uiparts, spacer_only):
 
5789
        """
 
5790
        Adds a dock into the existing layout.
 
5791
 
 
5792
        :param `cont`: a :class:`Sizer` object;
 
5793
        :param `dock`: the :class:`AuiDockInfo` structure to add to the layout;
 
5794
        :param `uiparts`: a list of UI parts in the interface;
 
5795
        :param bool `spacer_only`: whether to add a simple spacer or a real window.
 
5796
        """
 
5797
 
 
5798
        sizer_item = wx.SizerItem()
 
5799
        part = AuiDockUIPart()
 
5800
 
 
5801
        sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
5802
        orientation = (dock.IsHorizontal() and [wx.HORIZONTAL] or [wx.VERTICAL])[0]
 
5803
 
 
5804
        # resizable bottom and right docks have a sash before them
 
5805
        if not self._has_maximized and not dock.fixed and \
 
5806
           dock.dock_direction in [AUI_DOCK_BOTTOM, AUI_DOCK_RIGHT]:
 
5807
 
 
5808
            sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
 
5809
 
 
5810
            part.type = AuiDockUIPart.typeDockSizer
 
5811
            part.orientation = orientation
 
5812
            part.dock = dock
 
5813
            part.pane = None
 
5814
            part.button = None
 
5815
            part.cont_sizer = cont
 
5816
            part.sizer_item = sizer_item
 
5817
            uiparts.append(part)
 
5818
 
 
5819
        # create the sizer for the dock
 
5820
        dock_sizer = wx.BoxSizer(orientation)
 
5821
 
 
5822
        # add each pane to the dock
 
5823
        has_maximized_pane = False
 
5824
        pane_count = len(dock.panes)
 
5825
 
 
5826
        if dock.fixed:
 
5827
 
 
5828
            # figure out the real pane positions we will
 
5829
            # use, without modifying the each pane's pane_pos member
 
5830
            pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
 
5831
 
 
5832
            offset = 0
 
5833
            for pane_i in xrange(pane_count):
 
5834
 
 
5835
                pane = dock.panes[pane_i]
 
5836
                pane_pos = pane_positions[pane_i]
 
5837
 
 
5838
                if pane.IsMaximized():
 
5839
                    has_maximized_pane = True
 
5840
 
 
5841
                amount = pane_pos - offset
 
5842
                if amount > 0:
 
5843
 
 
5844
                    if dock.IsVertical():
 
5845
                        sizer_item = dock_sizer.Add((1, amount), 0, wx.EXPAND)
 
5846
                    else:
 
5847
                        sizer_item = dock_sizer.Add((amount, 1), 0, wx.EXPAND)
 
5848
 
 
5849
                    part = AuiDockUIPart()
 
5850
                    part.type = AuiDockUIPart.typeBackground
 
5851
                    part.dock = dock
 
5852
                    part.pane = None
 
5853
                    part.button = None
 
5854
                    part.orientation = (orientation==wx.HORIZONTAL and \
 
5855
                                        [wx.VERTICAL] or [wx.HORIZONTAL])[0]
 
5856
                    part.cont_sizer = dock_sizer
 
5857
                    part.sizer_item = sizer_item
 
5858
                    uiparts.append(part)
 
5859
 
 
5860
                    offset = offset + amount
 
5861
 
 
5862
                uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
 
5863
 
 
5864
                offset = offset + pane_sizes[pane_i]
 
5865
 
 
5866
            # at the end add a very small stretchable background area
 
5867
            sizer_item = dock_sizer.Add((0, 0), 1, wx.EXPAND)
 
5868
            part = AuiDockUIPart()
 
5869
            part.type = AuiDockUIPart.typeBackground
 
5870
            part.dock = dock
 
5871
            part.pane = None
 
5872
            part.button = None
 
5873
            part.orientation = orientation
 
5874
            part.cont_sizer = dock_sizer
 
5875
            part.sizer_item = sizer_item
 
5876
            uiparts.append(part)
 
5877
 
 
5878
        else:
 
5879
 
 
5880
            for pane_i in xrange(pane_count):
 
5881
 
 
5882
                pane = dock.panes[pane_i]
 
5883
 
 
5884
                if pane.IsMaximized():
 
5885
                    has_maximized_pane = True
 
5886
 
 
5887
                # if this is not the first pane being added,
 
5888
                # we need to add a pane sizer
 
5889
                if not self._has_maximized and pane_i > 0:
 
5890
                    sizer_item = dock_sizer.Add((sash_size, sash_size), 0, wx.EXPAND)
 
5891
                    part = AuiDockUIPart()
 
5892
                    part.type = AuiDockUIPart.typePaneSizer
 
5893
                    part.dock = dock
 
5894
                    part.pane = dock.panes[pane_i-1]
 
5895
                    part.button = None
 
5896
                    part.orientation = (orientation==wx.HORIZONTAL and \
 
5897
                                        [wx.VERTICAL] or [wx.HORIZONTAL])[0]
 
5898
                    part.cont_sizer = dock_sizer
 
5899
                    part.sizer_item = sizer_item
 
5900
                    uiparts.append(part)
 
5901
 
 
5902
                uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
 
5903
 
 
5904
        if dock.dock_direction == AUI_DOCK_CENTER or has_maximized_pane:
 
5905
            sizer_item = cont.Add(dock_sizer, 1, wx.EXPAND)
 
5906
        else:
 
5907
            sizer_item = cont.Add(dock_sizer, 0, wx.EXPAND)
 
5908
 
 
5909
        part = AuiDockUIPart()
 
5910
        part.type = AuiDockUIPart.typeDock
 
5911
        part.dock = dock
 
5912
        part.pane = None
 
5913
        part.button = None
 
5914
        part.orientation = orientation
 
5915
        part.cont_sizer = cont
 
5916
        part.sizer_item = sizer_item
 
5917
        uiparts.append(part)
 
5918
 
 
5919
        if dock.IsHorizontal():
 
5920
            cont.SetItemMinSize(dock_sizer, (0, dock.size))
 
5921
        else:
 
5922
            cont.SetItemMinSize(dock_sizer, (dock.size, 0))
 
5923
 
 
5924
        #  top and left docks have a sash after them
 
5925
        if not self._has_maximized and not dock.fixed and \
 
5926
           dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
 
5927
 
 
5928
            sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
 
5929
 
 
5930
            part = AuiDockUIPart()
 
5931
            part.type = AuiDockUIPart.typeDockSizer
 
5932
            part.dock = dock
 
5933
            part.pane = None
 
5934
            part.button = None
 
5935
            part.orientation = orientation
 
5936
            part.cont_sizer = cont
 
5937
            part.sizer_item = sizer_item
 
5938
            uiparts.append(part)
 
5939
 
 
5940
        return uiparts
 
5941
 
 
5942
 
 
5943
    def LayoutAll(self, panes, docks, uiparts, spacer_only=False, oncheck=True):
 
5944
        """
 
5945
        Layouts all the UI structures in the interface.
 
5946
 
 
5947
        :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
5948
        :param `docks`: a list of :class:`AuiDockInfo` classes;
 
5949
        :param `uiparts`: a list of UI parts in the interface;
 
5950
        :param bool `spacer_only`: whether to add a simple spacer or a real window;
 
5951
        :param bool `oncheck`: whether to store the results in a class member or not.
 
5952
        """
 
5953
 
 
5954
        container = wx.BoxSizer(wx.VERTICAL)
 
5955
 
 
5956
        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
 
5957
        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
5958
        cli_size = self._frame.GetClientSize()
 
5959
 
 
5960
        # empty all docks out
 
5961
        for dock in docks:
 
5962
            dock.panes = []
 
5963
            if dock.fixed:
 
5964
                # always reset fixed docks' sizes, because
 
5965
                # the contained windows may have been resized
 
5966
                dock.size = 0
 
5967
 
 
5968
        dock_count = len(docks)
 
5969
 
 
5970
        # iterate through all known panes, filing each
 
5971
        # of them into the appropriate dock. If the
 
5972
        # pane does not exist in the dock, add it
 
5973
        for p in panes:
 
5974
 
 
5975
            # don't layout hidden panes.
 
5976
            if p.IsShown():
 
5977
 
 
5978
                # find any docks with the same dock direction, dock layer, and
 
5979
                # dock row as the pane we are working on
 
5980
                arr = FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row)
 
5981
 
 
5982
                if arr:
 
5983
                    dock = arr[0]
 
5984
 
 
5985
                else:
 
5986
                    # dock was not found, so we need to create a new one
 
5987
                    d = AuiDockInfo()
 
5988
                    d.dock_direction = p.dock_direction
 
5989
                    d.dock_layer = p.dock_layer
 
5990
                    d.dock_row = p.dock_row
 
5991
                    docks.append(d)
 
5992
                    dock = docks[-1]
 
5993
 
 
5994
                    if p.HasFlag(p.needsRestore) and not p.HasFlag(p.wasMaximized):
 
5995
 
 
5996
                        isHor = dock.IsHorizontal()
 
5997
                        sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
5998
 
 
5999
                        # get the sizes of any docks that might
 
6000
                        # overlap with our restored dock
 
6001
 
 
6002
                        # make list of widths or heights from the size in the dock rects
 
6003
                        sizes = [d.rect[2:][isHor] for \
 
6004
                                 d in docks if d.IsOk() and \
 
6005
                                 (d.IsHorizontal() == isHor) and \
 
6006
                                 not d.toolbar and \
 
6007
                                 d.dock_direction != AUI_DOCK_CENTER]
 
6008
 
 
6009
                        frameRect = GetInternalFrameRect(self._frame, self._docks)
 
6010
 
 
6011
                        # set max size allowing for sashes and absolute minimum
 
6012
                        maxsize = frameRect[2:][isHor] - sum(sizes) - (len(sizes)*10) - (sashSize*len(sizes))
 
6013
                        dock.size = min(p.previousDockSize,maxsize)
 
6014
 
 
6015
                    else:
 
6016
                        dock.size = 0
 
6017
 
 
6018
                if p.HasFlag(p.wasMaximized):
 
6019
                    self.MaximizePane(p, savesizes=False)
 
6020
                    p.SetFlag(p.wasMaximized, False)
 
6021
 
 
6022
                if p.HasFlag(p.needsRestore):
 
6023
                    if p.previousDockPos is not None:
 
6024
                        DoInsertPane(dock.panes, dock.dock_direction, dock.dock_layer, dock.dock_row, p.previousDockPos)
 
6025
                        p.dock_pos = p.previousDockPos
 
6026
                        p.previousDockPos = None
 
6027
                    p.SetFlag(p.needsRestore, False)
 
6028
 
 
6029
                if p.IsDocked():
 
6030
                    # remove the pane from any existing docks except this one
 
6031
                    docks = RemovePaneFromDocks(docks, p, dock)
 
6032
 
 
6033
                    # pane needs to be added to the dock,
 
6034
                    # if it doesn't already exist
 
6035
                    if not FindPaneInDock(dock, p.window):
 
6036
                        dock.panes.append(p)
 
6037
                else:
 
6038
                    # remove the pane from any existing docks
 
6039
                    docks = RemovePaneFromDocks(docks, p)
 
6040
 
 
6041
        # remove any empty docks
 
6042
        docks = [dock for dock in docks if dock.panes]
 
6043
 
 
6044
        dock_count = len(docks)
 
6045
        # configure the docks further
 
6046
        for ii, dock in enumerate(docks):
 
6047
            # sort the dock pane array by the pane's
 
6048
            # dock position (dock_pos), in ascending order
 
6049
            dock.panes.sort(PaneSortFunc)
 
6050
            dock_pane_count = len(dock.panes)
 
6051
 
 
6052
            # for newly created docks, set up their initial size
 
6053
            if dock.size == 0:
 
6054
                size = 0
 
6055
                for pane in dock.panes:
 
6056
                    pane_size = pane.best_size
 
6057
                    if pane_size == wx.Size(-1, -1):
 
6058
                        pane_size = pane.min_size
 
6059
                    if pane_size == wx.Size(-1, -1) and pane.window:
 
6060
                        pane_size = pane.window.GetSize()
 
6061
                    if dock.IsHorizontal():
 
6062
                        size = max(pane_size.y, size)
 
6063
                    else:
 
6064
                        size = max(pane_size.x, size)
 
6065
 
 
6066
                # add space for the border (two times), but only
 
6067
                # if at least one pane inside the dock has a pane border
 
6068
                for pane in dock.panes:
 
6069
                    if pane.HasBorder():
 
6070
                        size = size + pane_border_size*2
 
6071
                        break
 
6072
 
 
6073
                # if pane is on the top or bottom, add the caption height,
 
6074
                # but only if at least one pane inside the dock has a caption
 
6075
                if dock.IsHorizontal():
 
6076
                    for pane in dock.panes:
 
6077
                        if pane.HasCaption() and not pane.HasCaptionLeft():
 
6078
                            size = size + caption_size
 
6079
                            break
 
6080
                else:
 
6081
                    for pane in dock.panes:
 
6082
                        if pane.HasCaptionLeft() and not pane.HasCaption():
 
6083
                            size = size + caption_size
 
6084
                            break
 
6085
 
 
6086
                # new dock's size may not be more than the dock constraint
 
6087
                # parameter specifies.  See SetDockSizeConstraint()
 
6088
                max_dock_x_size = int(self._dock_constraint_x*float(cli_size.x))
 
6089
                max_dock_y_size = int(self._dock_constraint_y*float(cli_size.y))
 
6090
                if cli_size <= wx.Size(20, 20):
 
6091
                    max_dock_x_size = 10000
 
6092
                    max_dock_y_size = 10000
 
6093
 
 
6094
                if dock.IsHorizontal():
 
6095
                    size = min(size, max_dock_y_size)
 
6096
                else:
 
6097
                    size = min(size, max_dock_x_size)
 
6098
 
 
6099
                # absolute minimum size for a dock is 10 pixels
 
6100
                if size < 10:
 
6101
                    size = 10
 
6102
 
 
6103
                dock.size = size
 
6104
 
 
6105
            # determine the dock's minimum size
 
6106
            plus_border = False
 
6107
            plus_caption = False
 
6108
            plus_caption_left = False
 
6109
            dock_min_size = 0
 
6110
            for pane in dock.panes:
 
6111
                if pane.min_size != wx.Size(-1, -1):
 
6112
                    if pane.HasBorder():
 
6113
                        plus_border = True
 
6114
                    if pane.HasCaption():
 
6115
                        plus_caption = True
 
6116
                    if pane.HasCaptionLeft():
 
6117
                        plus_caption_left = True
 
6118
                    if dock.IsHorizontal():
 
6119
                        if pane.min_size.y > dock_min_size:
 
6120
                            dock_min_size = pane.min_size.y
 
6121
                    else:
 
6122
                        if pane.min_size.x > dock_min_size:
 
6123
                            dock_min_size = pane.min_size.x
 
6124
 
 
6125
            if plus_border:
 
6126
                dock_min_size += pane_border_size*2
 
6127
            if plus_caption and dock.IsHorizontal():
 
6128
                dock_min_size += caption_size
 
6129
            if plus_caption_left and dock.IsVertical():
 
6130
                dock_min_size += caption_size
 
6131
 
 
6132
            dock.min_size = dock_min_size
 
6133
 
 
6134
            # if the pane's current size is less than it's
 
6135
            # minimum, increase the dock's size to it's minimum
 
6136
            if dock.size < dock.min_size:
 
6137
                dock.size = dock.min_size
 
6138
 
 
6139
            # determine the dock's mode (fixed or proportional)
 
6140
            # determine whether the dock has only toolbars
 
6141
            action_pane_marked = False
 
6142
            dock.fixed = True
 
6143
            dock.toolbar = True
 
6144
            for pane in dock.panes:
 
6145
                if not pane.IsFixed():
 
6146
                    dock.fixed = False
 
6147
                if not pane.IsToolbar():
 
6148
                    dock.toolbar = False
 
6149
                if pane.HasFlag(AuiPaneInfo.optionDockFixed):
 
6150
                    dock.fixed = True
 
6151
                if pane.HasFlag(AuiPaneInfo.actionPane):
 
6152
                    action_pane_marked = True
 
6153
 
 
6154
            # if the dock mode is proportional and not fixed-pixel,
 
6155
            # reassign the dock_pos to the sequential 0, 1, 2, 3
 
6156
            # e.g. remove gaps like 1, 2, 30, 500
 
6157
            if not dock.fixed:
 
6158
                for jj in xrange(dock_pane_count):
 
6159
                    pane = dock.panes[jj]
 
6160
                    pane.dock_pos = jj
 
6161
 
 
6162
            # if the dock mode is fixed, and none of the panes
 
6163
            # are being moved right now, make sure the panes
 
6164
            # do not overlap each other.  If they do, we will
 
6165
            # adjust the panes' positions
 
6166
            if dock.fixed and not action_pane_marked:
 
6167
                pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
 
6168
                offset = 0
 
6169
                for jj in xrange(dock_pane_count):
 
6170
                    pane = dock.panes[jj]
 
6171
                    pane.dock_pos = pane_positions[jj]
 
6172
                    amount = pane.dock_pos - offset
 
6173
                    if amount >= 0:
 
6174
                        offset += amount
 
6175
                    else:
 
6176
                        pane.dock_pos += -amount
 
6177
 
 
6178
                    offset += pane_sizes[jj]
 
6179
                    dock.panes[jj] = pane
 
6180
 
 
6181
            if oncheck:
 
6182
                self._docks[ii] = dock
 
6183
 
 
6184
        # shrink docks if needed
 
6185
##        docks = self.SmartShrink(docks, AUI_DOCK_TOP)
 
6186
##        docks = self.SmartShrink(docks, AUI_DOCK_LEFT)
 
6187
 
 
6188
        if oncheck:
 
6189
            self._docks = docks
 
6190
 
 
6191
        # discover the maximum dock layer
 
6192
        max_layer = 0
 
6193
        dock_count = len(docks)
 
6194
 
 
6195
        for ii in xrange(dock_count):
 
6196
            max_layer = max(max_layer, docks[ii].dock_layer)
 
6197
 
 
6198
        # clear out uiparts
 
6199
        uiparts = []
 
6200
 
 
6201
        # create a bunch of box sizers,
 
6202
        # from the innermost level outwards.
 
6203
        cont = None
 
6204
        middle = None
 
6205
 
 
6206
        if oncheck:
 
6207
            docks = self._docks
 
6208
 
 
6209
        for layer in xrange(max_layer+1):
 
6210
            # find any docks in this layer
 
6211
            arr = FindDocks(docks, -1, layer, -1)
 
6212
            # if there aren't any, skip to the next layer
 
6213
            if not arr:
 
6214
                continue
 
6215
 
 
6216
            old_cont = cont
 
6217
 
 
6218
            # create a container which will hold this layer's
 
6219
            # docks (top, bottom, left, right)
 
6220
            cont = wx.BoxSizer(wx.VERTICAL)
 
6221
 
 
6222
            # find any top docks in this layer
 
6223
            arr = FindDocks(docks, AUI_DOCK_TOP, layer, -1)
 
6224
            for row in arr:
 
6225
                uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
 
6226
 
 
6227
            # fill out the middle layer (which consists
 
6228
            # of left docks, content area and right docks)
 
6229
 
 
6230
            middle = wx.BoxSizer(wx.HORIZONTAL)
 
6231
 
 
6232
            # find any left docks in this layer
 
6233
            arr = FindDocks(docks, AUI_DOCK_LEFT, layer, -1)
 
6234
            for row in arr:
 
6235
                uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
 
6236
 
 
6237
            # add content dock (or previous layer's sizer
 
6238
            # to the middle
 
6239
            if not old_cont:
 
6240
                # find any center docks
 
6241
                arr = FindDocks(docks, AUI_DOCK_CENTER, -1, -1)
 
6242
                if arr:
 
6243
                    for row in arr:
 
6244
                       uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
 
6245
 
 
6246
                elif not self._has_maximized:
 
6247
                    # there are no center docks, add a background area
 
6248
                    sizer_item = middle.Add((1, 1), 1, wx.EXPAND)
 
6249
                    part = AuiDockUIPart()
 
6250
                    part.type = AuiDockUIPart.typeBackground
 
6251
                    part.pane = None
 
6252
                    part.dock = None
 
6253
                    part.button = None
 
6254
                    part.cont_sizer = middle
 
6255
                    part.sizer_item = sizer_item
 
6256
                    uiparts.append(part)
 
6257
            else:
 
6258
                middle.Add(old_cont, 1, wx.EXPAND)
 
6259
 
 
6260
            # find any right docks in this layer
 
6261
            arr = FindDocks(docks, AUI_DOCK_RIGHT, layer, -1, reverse=True)
 
6262
            for row in arr:
 
6263
                uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
 
6264
 
 
6265
            if len(middle.GetChildren()) > 0:
 
6266
                cont.Add(middle, 1, wx.EXPAND)
 
6267
 
 
6268
            # find any bottom docks in this layer
 
6269
            arr = FindDocks(docks, AUI_DOCK_BOTTOM, layer, -1, reverse=True)
 
6270
            for row in arr:
 
6271
                    uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
 
6272
 
 
6273
        if not cont:
 
6274
            # no sizer available, because there are no docks,
 
6275
            # therefore we will create a simple background area
 
6276
            cont = wx.BoxSizer(wx.VERTICAL)
 
6277
            sizer_item = cont.Add((1, 1), 1, wx.EXPAND)
 
6278
            part = AuiDockUIPart()
 
6279
            part.type = AuiDockUIPart.typeBackground
 
6280
            part.pane = None
 
6281
            part.dock = None
 
6282
            part.button = None
 
6283
            part.cont_sizer = middle
 
6284
            part.sizer_item = sizer_item
 
6285
            uiparts.append(part)
 
6286
 
 
6287
        if oncheck:
 
6288
            self._uiparts = uiparts
 
6289
            self._docks = docks
 
6290
 
 
6291
        container.Add(cont, 1, wx.EXPAND)
 
6292
 
 
6293
        if oncheck:
 
6294
            return container
 
6295
        else:
 
6296
            return container, panes, docks, uiparts
 
6297
 
 
6298
 
 
6299
    def SetDockSizeConstraint(self, width_pct, height_pct):
 
6300
        """
 
6301
        When a user creates a new dock by dragging a window into a docked position,
 
6302
        often times the large size of the window will create a dock that is unwieldly
 
6303
        large.
 
6304
 
 
6305
        :class:`AuiManager` by default limits the size of any new dock to 1/3 of the window
 
6306
        size. For horizontal docks, this would be 1/3 of the window height. For vertical
 
6307
        docks, 1/3 of the width. Calling this function will adjust this constraint value.
 
6308
 
 
6309
        The numbers must be between 0.0 and 1.0. For instance, calling :meth:`SetDockSizeConstraint`
 
6310
        with (0.5, 0.5) will cause new docks to be limited to half of the size of the entire
 
6311
        managed window.
 
6312
 
 
6313
        :param float `width_pct`: a number representing the `x` dock size constraint;
 
6314
        :param float `width_pct`: a number representing the `y` dock size constraint.
 
6315
        """
 
6316
 
 
6317
        self._dock_constraint_x = max(0.0, min(1.0, width_pct))
 
6318
        self._dock_constraint_y = max(0.0, min(1.0, height_pct))
 
6319
 
 
6320
 
 
6321
    def GetDockSizeConstraint(self):
 
6322
        """
 
6323
        Returns the current dock constraint values.
 
6324
 
 
6325
        :see: :meth:`SetDockSizeConstraint`
 
6326
        """
 
6327
 
 
6328
        return self._dock_constraint_x, self._dock_constraint_y
 
6329
 
 
6330
 
 
6331
    def Update(self):
 
6332
        """
 
6333
        This method is called after any number of changes are made to any of the
 
6334
        managed panes. :meth:`Update` must be invoked after :meth:`AddPane`
 
6335
        or :meth:`InsertPane` are called in order to "realize" or "commit" the changes.
 
6336
 
 
6337
        In addition, any number of changes may be made to :class:`AuiManager` structures
 
6338
        (retrieved with :meth:`GetPane`), but to realize the changes, :meth:`Update`
 
6339
        must be called. This construction allows pane flicker to be avoided by updating
 
6340
        the whole layout at one time.
 
6341
        """
 
6342
 
 
6343
        self._hover_button = None
 
6344
        self._action_part = None
 
6345
 
 
6346
        # destroy floating panes which have been
 
6347
        # redocked or are becoming non-floating
 
6348
        for p in self._panes:
 
6349
            if p.IsFloating() or not p.frame:
 
6350
                continue
 
6351
 
 
6352
            # because the pane is no longer in a floating, we need to
 
6353
            # reparent it to self._frame and destroy the floating frame
 
6354
            # reduce flicker
 
6355
            p.window.SetSize((1, 1))
 
6356
 
 
6357
            # the following block is a workaround for bug #1531361
 
6358
            # (see wxWidgets sourceforge page).  On wxGTK (only), when
 
6359
            # a frame is shown/hidden, a move event unfortunately
 
6360
            # also gets fired.  Because we may be dragging around
 
6361
            # a pane, we need to cancel that action here to prevent
 
6362
            # a spurious crash.
 
6363
            if self._action_window == p.frame:
 
6364
                if self._frame.HasCapture():
 
6365
                    self._frame.ReleaseMouse()
 
6366
                self._action = actionNone
 
6367
                self._action_window = None
 
6368
 
 
6369
            # hide the frame
 
6370
            if p.frame.IsShown():
 
6371
                p.frame.Show(False)
 
6372
 
 
6373
            if self._action_window == p.frame:
 
6374
                self._action_window = None
 
6375
 
 
6376
            # reparent to self._frame and destroy the pane
 
6377
            p.window.Reparent(self._frame)
 
6378
            if isinstance(p.window, auibar.AuiToolBar):
 
6379
                p.window.SetAuiManager(self)
 
6380
 
 
6381
            if p.frame:
 
6382
                p.frame.SetSizer(None)
 
6383
                p.frame.Destroy()
 
6384
            p.frame = None
 
6385
 
 
6386
        # Only the master manager should create/destroy notebooks...
 
6387
        if not self._masterManager:
 
6388
            self.UpdateNotebook()
 
6389
 
 
6390
        # delete old sizer first
 
6391
        self._frame.SetSizer(None)
 
6392
 
 
6393
        # create a layout for all of the panes
 
6394
        sizer = self.LayoutAll(self._panes, self._docks, self._uiparts, False)
 
6395
 
 
6396
        # hide or show panes as necessary,
 
6397
        # and float panes as necessary
 
6398
 
 
6399
        pane_count = len(self._panes)
 
6400
 
 
6401
        for ii in xrange(pane_count):
 
6402
            p = self._panes[ii]
 
6403
            pFrame = p.frame
 
6404
 
 
6405
            if p.IsFloating():
 
6406
                if pFrame is None:
 
6407
                    # we need to create a frame for this
 
6408
                    # pane, which has recently been floated
 
6409
                    frame = self.CreateFloatingFrame(self._frame, p)
 
6410
 
 
6411
                    # on MSW and Mac, if the owner desires transparent dragging, and
 
6412
                    # the dragging is happening right now, then the floating
 
6413
                    # window should have this style by default
 
6414
                    if self._action in [actionDragFloatingPane, actionDragToolbarPane] and \
 
6415
                       self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
 
6416
                        frame.SetTransparent(150)
 
6417
 
 
6418
                    if p.IsToolbar():
 
6419
                        bar = p.window
 
6420
                        if isinstance(bar, auibar.AuiToolBar):
 
6421
                            bar.SetGripperVisible(False)
 
6422
                            agwStyle = bar.GetAGWWindowStyleFlag()
 
6423
                            bar.SetAGWWindowStyleFlag(agwStyle & ~AUI_TB_VERTICAL)
 
6424
                            bar.Realize()
 
6425
 
 
6426
                        s = p.window.GetMinSize()
 
6427
                        p.BestSize(s)
 
6428
                        p.FloatingSize(wx.DefaultSize)
 
6429
 
 
6430
                    frame.SetPaneWindow(p)
 
6431
                    p.needsTransparency = True
 
6432
                    p.frame = pFrame = frame
 
6433
                    if p.IsShown() and not frame.IsShown():
 
6434
                        frame.Show()
 
6435
                        frame.Update()
 
6436
                else:
 
6437
 
 
6438
                    # frame already exists, make sure it's position
 
6439
                    # and size reflect the information in AuiPaneInfo
 
6440
                    if pFrame.GetPosition() != p.floating_pos or pFrame.GetSize() != p.floating_size:
 
6441
                        pFrame.SetDimensions(p.floating_pos.x, p.floating_pos.y,
 
6442
                                             p.floating_size.x, p.floating_size.y, wx.SIZE_USE_EXISTING)
 
6443
 
 
6444
                    # update whether the pane is resizable or not
 
6445
                    style = p.frame.GetWindowStyleFlag()
 
6446
                    if p.IsFixed():
 
6447
                        style &= ~wx.RESIZE_BORDER
 
6448
                    else:
 
6449
                        style |= wx.RESIZE_BORDER
 
6450
 
 
6451
                    p.frame.SetWindowStyleFlag(style)
 
6452
 
 
6453
                    if pFrame.IsShown() != p.IsShown():
 
6454
                        p.needsTransparency = True
 
6455
                        pFrame.Show(p.IsShown())
 
6456
 
 
6457
                if pFrame.GetTitle() != p.caption:
 
6458
                    pFrame.SetTitle(p.caption)
 
6459
                if p.icon.IsOk():
 
6460
                    pFrame.SetIcon(wx.IconFromBitmap(p.icon))
 
6461
 
 
6462
            else:
 
6463
 
 
6464
                if p.IsToolbar():
 
6465
#                    self.SwitchToolBarOrientation(p)
 
6466
                    p.best_size = p.window.GetBestSize()
 
6467
 
 
6468
                if p.window and not p.IsNotebookPage() and p.window.IsShown() != p.IsShown():
 
6469
                    p.window.Show(p.IsShown())
 
6470
 
 
6471
            if pFrame and p.needsTransparency:
 
6472
                if pFrame.IsShown() and pFrame._transparent != p.transparent:
 
6473
                    pFrame.SetTransparent(p.transparent)
 
6474
                    pFrame._transparent = p.transparent
 
6475
 
 
6476
                p.needsTransparency = False
 
6477
 
 
6478
            # if "active panes" are no longer allowed, clear
 
6479
            # any optionActive values from the pane states
 
6480
            if self._agwFlags & AUI_MGR_ALLOW_ACTIVE_PANE == 0:
 
6481
                p.state &= ~AuiPaneInfo.optionActive
 
6482
 
 
6483
            self._panes[ii] = p
 
6484
 
 
6485
        old_pane_rects = []
 
6486
        pane_count = len(self._panes)
 
6487
 
 
6488
        for p in self._panes:
 
6489
            r = wx.Rect()
 
6490
            if p.window and p.IsShown() and p.IsDocked():
 
6491
                r = p.rect
 
6492
 
 
6493
            old_pane_rects.append(r)
 
6494
 
 
6495
        # apply the new sizer
 
6496
        self._frame.SetSizer(sizer)
 
6497
        self._frame.SetAutoLayout(False)
 
6498
        self.DoFrameLayout()
 
6499
 
 
6500
        # now that the frame layout is done, we need to check
 
6501
        # the new pane rectangles against the old rectangles that
 
6502
        # we saved a few lines above here.  If the rectangles have
 
6503
        # changed, the corresponding panes must also be updated
 
6504
        for ii in xrange(pane_count):
 
6505
            p = self._panes[ii]
 
6506
            if p.window and p.IsShown() and p.IsDocked():
 
6507
                if p.rect != old_pane_rects[ii]:
 
6508
                    p.window.Refresh()
 
6509
                    p.window.Update()
 
6510
 
 
6511
        if wx.Platform == "__WXMAC__":
 
6512
            self._frame.Refresh()
 
6513
        else:
 
6514
            self.Repaint()
 
6515
 
 
6516
        if not self._masterManager:
 
6517
            e = self.FireEvent(wxEVT_AUI_PERSPECTIVE_CHANGED, None, canVeto=False)
 
6518
 
 
6519
 
 
6520
    def UpdateNotebook(self):
 
6521
        """ Updates the automatic :class:`~lib.agw.aui.auibook.AuiNotebook` in the layout (if any exists). """
 
6522
 
 
6523
        # Workout how many notebooks we need.
 
6524
        max_notebook = -1
 
6525
 
 
6526
        # destroy floating panes which have been
 
6527
        # redocked or are becoming non-floating
 
6528
        for paneInfo in self._panes:
 
6529
            if max_notebook < paneInfo.notebook_id:
 
6530
                max_notebook = paneInfo.notebook_id
 
6531
 
 
6532
        # We are the master of our domain
 
6533
        extra_notebook = len(self._notebooks)
 
6534
        max_notebook += 1
 
6535
 
 
6536
        for i in xrange(extra_notebook, max_notebook):
 
6537
            self.CreateNotebook()
 
6538
 
 
6539
        # Remove pages from notebooks that no-longer belong there ...
 
6540
        for nb, notebook in enumerate(self._notebooks):
 
6541
            pages = notebook.GetPageCount()
 
6542
            pageCounter, allPages = 0, pages
 
6543
 
 
6544
            # Check each tab ...
 
6545
            for page in xrange(pages):
 
6546
 
 
6547
                if page >= allPages:
 
6548
                    break
 
6549
 
 
6550
                window = notebook.GetPage(pageCounter)
 
6551
                paneInfo = self.GetPane(window)
 
6552
                if paneInfo.IsOk() and paneInfo.notebook_id != nb:
 
6553
                    notebook.RemovePage(pageCounter)
 
6554
                    window.Hide()
 
6555
                    window.Reparent(self._frame)
 
6556
                    pageCounter -= 1
 
6557
                    allPages -= 1
 
6558
 
 
6559
                pageCounter += 1
 
6560
 
 
6561
            notebook.DoSizing()
 
6562
 
 
6563
        # Add notebook pages that aren't there already...
 
6564
        for paneInfo in self._panes:
 
6565
            if paneInfo.IsNotebookPage():
 
6566
 
 
6567
                title = (paneInfo.caption == "" and [paneInfo.name] or [paneInfo.caption])[0]
 
6568
 
 
6569
                notebook = self._notebooks[paneInfo.notebook_id]
 
6570
                page_id = notebook.GetPageIndex(paneInfo.window)
 
6571
 
 
6572
                if page_id < 0:
 
6573
 
 
6574
                    paneInfo.window.Reparent(notebook)
 
6575
                    notebook.AddPage(paneInfo.window, title, True, paneInfo.icon)
 
6576
 
 
6577
                # Update title and icon ...
 
6578
                else:
 
6579
 
 
6580
                    notebook.SetPageText(page_id, title)
 
6581
                    notebook.SetPageBitmap(page_id, paneInfo.icon)
 
6582
 
 
6583
                notebook.DoSizing()
 
6584
 
 
6585
            # Wire-up newly created notebooks
 
6586
            elif paneInfo.IsNotebookControl() and not paneInfo.window:
 
6587
                paneInfo.window = self._notebooks[paneInfo.notebook_id]
 
6588
 
 
6589
        # Delete empty notebooks, and convert notebooks with 1 page to
 
6590
        # normal panes...
 
6591
        remap_ids = [-1]*len(self._notebooks)
 
6592
        nb_idx = 0
 
6593
 
 
6594
        for nb, notebook in enumerate(self._notebooks):
 
6595
            if notebook.GetPageCount() == 1:
 
6596
 
 
6597
                # Convert notebook page to pane...
 
6598
                window = notebook.GetPage(0)
 
6599
                child_pane = self.GetPane(window)
 
6600
                notebook_pane = self.GetPane(notebook)
 
6601
                if child_pane.IsOk() and notebook_pane.IsOk():
 
6602
 
 
6603
                    child_pane.SetDockPos(notebook_pane)
 
6604
                    child_pane.window.Hide()
 
6605
                    child_pane.window.Reparent(self._frame)
 
6606
                    child_pane.frame = None
 
6607
                    child_pane.notebook_id = -1
 
6608
                    if notebook_pane.IsFloating():
 
6609
                        child_pane.Float()
 
6610
 
 
6611
                    self.DetachPane(notebook)
 
6612
 
 
6613
                    notebook.RemovePage(0)
 
6614
                    notebook.Destroy()
 
6615
 
 
6616
                else:
 
6617
 
 
6618
                    raise Exception("Odd notebook docking")
 
6619
 
 
6620
            elif notebook.GetPageCount() == 0:
 
6621
 
 
6622
                self.DetachPane(notebook)
 
6623
                notebook.Destroy()
 
6624
 
 
6625
            else:
 
6626
 
 
6627
                # Correct page ordering. The original wxPython code
 
6628
                # for this did not work properly, and would misplace
 
6629
                # windows causing errors.
 
6630
                notebook.Freeze()
 
6631
                self._notebooks[nb_idx] = notebook
 
6632
                pages = notebook.GetPageCount()
 
6633
                selected = notebook.GetPage(notebook.GetSelection())
 
6634
 
 
6635
                # Take each page out of the notebook, group it with
 
6636
                # its current pane, and sort the list by pane.dock_pos
 
6637
                # order
 
6638
                pages_and_panes = []
 
6639
                for idx in reversed(range(pages)):
 
6640
                    page = notebook.GetPage(idx)
 
6641
                    pane = self.GetPane(page)
 
6642
                    pages_and_panes.append((page, pane))
 
6643
                    notebook.RemovePage(idx)
 
6644
                sorted_pnp = sorted(pages_and_panes, key=lambda tup: tup[1].dock_pos)
 
6645
 
 
6646
                # Grab the attributes from the panes which are ordered
 
6647
                # correctly, and copy those attributes to the original
 
6648
                # panes. (This avoids having to change the ordering
 
6649
                # of self._panes) Then, add the page back into the notebook
 
6650
                sorted_attributes = [self.GetAttributes(tup[1])
 
6651
                                     for tup in sorted_pnp]
 
6652
                for attrs, tup in zip(sorted_attributes, pages_and_panes):
 
6653
                    pane = tup[1]
 
6654
                    self.SetAttributes(pane, attrs)
 
6655
                    notebook.AddPage(pane.window, pane.caption)
 
6656
 
 
6657
                notebook.SetSelection(notebook.GetPageIndex(selected), True)
 
6658
                notebook.DoSizing()
 
6659
                notebook.Thaw()
 
6660
 
 
6661
                # It's a keeper.
 
6662
                remap_ids[nb] = nb_idx
 
6663
                nb_idx += 1
 
6664
 
 
6665
        # Apply remap...
 
6666
        nb_count = len(self._notebooks)
 
6667
 
 
6668
        if nb_count != nb_idx:
 
6669
 
 
6670
            self._notebooks = self._notebooks[0:nb_idx]
 
6671
            for p in self._panes:
 
6672
                if p.notebook_id >= 0:
 
6673
                    p.notebook_id = remap_ids[p.notebook_id]
 
6674
                    if p.IsNotebookControl():
 
6675
                        p.SetNameFromNotebookId()
 
6676
 
 
6677
        # Make sure buttons are correct ...
 
6678
        for notebook in self._notebooks:
 
6679
            want_max = True
 
6680
            want_min = True
 
6681
            want_close = True
 
6682
 
 
6683
            pages = notebook.GetPageCount()
 
6684
            for page in xrange(pages):
 
6685
 
 
6686
                win = notebook.GetPage(page)
 
6687
                pane = self.GetPane(win)
 
6688
                if pane.IsOk():
 
6689
 
 
6690
                    if not pane.HasCloseButton():
 
6691
                        want_close = False
 
6692
                    if not pane.HasMaximizeButton():
 
6693
                        want_max = False
 
6694
                    if not pane.HasMinimizeButton():
 
6695
                        want_min = False
 
6696
 
 
6697
            notebook_pane = self.GetPane(notebook)
 
6698
            if notebook_pane.IsOk():
 
6699
                if notebook_pane.HasMinimizeButton() != want_min:
 
6700
                    if want_min:
 
6701
                        button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
 
6702
                        notebook_pane.state |= AuiPaneInfo.buttonMinimize
 
6703
                        notebook_pane.buttons.append(button)
 
6704
 
 
6705
                    # todo: remove min/max
 
6706
 
 
6707
                if notebook_pane.HasMaximizeButton() != want_max:
 
6708
                    if want_max:
 
6709
                        button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
 
6710
                        notebook_pane.state |= AuiPaneInfo.buttonMaximize
 
6711
                        notebook_pane.buttons.append(button)
 
6712
 
 
6713
                    # todo: remove min/max
 
6714
 
 
6715
                if notebook_pane.HasCloseButton() != want_close:
 
6716
                    if want_close:
 
6717
                        button = AuiPaneButton(AUI_BUTTON_CLOSE)
 
6718
                        notebook_pane.state |= AuiPaneInfo.buttonClose
 
6719
                        notebook_pane.buttons.append(button)
 
6720
 
 
6721
                    # todo: remove close
 
6722
 
 
6723
 
 
6724
    def SmartShrink(self, docks, direction):
 
6725
        """
 
6726
        Used to intelligently shrink the docks' size (if needed).
 
6727
 
 
6728
        :param `docks`: a list of :class:`AuiDockInfo` instances;
 
6729
        :param integer `direction`: the direction in which to shrink.
 
6730
        """
 
6731
 
 
6732
        sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
6733
        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
6734
        clientSize = self._frame.GetClientSize()
 
6735
        ourDocks = FindDocks(docks, direction, -1, -1)
 
6736
        oppositeDocks = FindOppositeDocks(docks, direction)
 
6737
        oppositeSize = self.GetOppositeDockTotalSize(docks, direction)
 
6738
        ourSize = 0
 
6739
 
 
6740
        for dock in ourDocks:
 
6741
            ourSize += dock.size
 
6742
 
 
6743
            if not dock.toolbar:
 
6744
                ourSize += sashSize
 
6745
 
 
6746
        shrinkSize = ourSize + oppositeSize
 
6747
 
 
6748
        if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
 
6749
            shrinkSize -= clientSize.y
 
6750
        else:
 
6751
            shrinkSize -= clientSize.x
 
6752
 
 
6753
        if shrinkSize <= 0:
 
6754
            return docks
 
6755
 
 
6756
        # Combine arrays
 
6757
        for dock in oppositeDocks:
 
6758
            ourDocks.append(dock)
 
6759
 
 
6760
        oppositeDocks = []
 
6761
 
 
6762
        for dock in ourDocks:
 
6763
            if dock.toolbar or not dock.resizable:
 
6764
                continue
 
6765
 
 
6766
            dockRange = dock.size - dock.min_size
 
6767
 
 
6768
            if dock.min_size == 0:
 
6769
                dockRange -= sashSize
 
6770
                if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
 
6771
                    dockRange -= caption_size
 
6772
 
 
6773
            if dockRange >= shrinkSize:
 
6774
 
 
6775
                dock.size -= shrinkSize
 
6776
                return docks
 
6777
 
 
6778
            else:
 
6779
 
 
6780
                dock.size -= dockRange
 
6781
                shrinkSize -= dockRange
 
6782
 
 
6783
        return docks
 
6784
 
 
6785
 
 
6786
    def UpdateDockingGuides(self, paneInfo):
 
6787
        """
 
6788
        Updates the docking guide windows positions and appearance.
 
6789
 
 
6790
        :param `paneInfo`: a :class:`AuiPaneInfo` instance.
 
6791
        """
 
6792
 
 
6793
        if len(self._guides) == 0:
 
6794
            self.CreateGuideWindows()
 
6795
 
 
6796
        captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
6797
        frameRect = GetInternalFrameRect(self._frame, self._docks)
 
6798
        mousePos = wx.GetMousePosition()
 
6799
 
 
6800
        for indx, guide in enumerate(self._guides):
 
6801
 
 
6802
            pt = wx.Point()
 
6803
            guide_size = guide.host.GetSize()
 
6804
            if not guide.host:
 
6805
                raise Exception("Invalid docking host")
 
6806
 
 
6807
            direction = guide.dock_direction
 
6808
 
 
6809
            if direction == AUI_DOCK_LEFT:
 
6810
                pt.x = frameRect.x + guide_size.x / 2 + 16
 
6811
                pt.y = frameRect.y + frameRect.height / 2
 
6812
 
 
6813
            elif direction == AUI_DOCK_TOP:
 
6814
                pt.x = frameRect.x + frameRect.width / 2
 
6815
                pt.y = frameRect.y + guide_size.y / 2 + 16
 
6816
 
 
6817
            elif direction == AUI_DOCK_RIGHT:
 
6818
                pt.x = frameRect.x + frameRect.width - guide_size.x / 2 - 16
 
6819
                pt.y = frameRect.y + frameRect.height / 2
 
6820
 
 
6821
            elif direction == AUI_DOCK_BOTTOM:
 
6822
                pt.x = frameRect.x + frameRect.width / 2
 
6823
                pt.y = frameRect.y + frameRect.height - guide_size.y / 2 - 16
 
6824
 
 
6825
            elif direction == AUI_DOCK_CENTER:
 
6826
                rc = paneInfo.window.GetScreenRect()
 
6827
                pt.x = rc.x + rc.width / 2
 
6828
                pt.y = rc.y + rc.height / 2
 
6829
                if paneInfo.HasCaption():
 
6830
                    pt.y -= captionSize / 2
 
6831
                elif paneInfo.HasCaptionLeft():
 
6832
                    pt.x -= captionSize / 2
 
6833
 
 
6834
            # guide will be centered around point 'pt'
 
6835
            targetPosition = wx.Point(pt.x - guide_size.x / 2, pt.y - guide_size.y / 2)
 
6836
 
 
6837
            if guide.host.GetPosition() != targetPosition:
 
6838
                guide.host.Move(targetPosition)
 
6839
 
 
6840
            guide.host.AeroMove(targetPosition)
 
6841
 
 
6842
            if guide.dock_direction == AUI_DOCK_CENTER:
 
6843
                guide.host.ValidateNotebookDocking(paneInfo.IsNotebookDockable())
 
6844
 
 
6845
            guide.host.UpdateDockGuide(mousePos)
 
6846
 
 
6847
        paneInfo.window.Lower()
 
6848
 
 
6849
 
 
6850
    def DoFrameLayout(self):
 
6851
        """
 
6852
        This is an internal function which invokes :meth:`Sizer.Layout() <Sizer.Layout>`
 
6853
        on the frame's main sizer, then measures all the various UI items
 
6854
        and updates their internal rectangles.
 
6855
 
 
6856
        :note: This should always be called instead of calling
 
6857
         `self._managed_window.Layout()` directly.
 
6858
        """
 
6859
 
 
6860
        self._frame.Layout()
 
6861
 
 
6862
        for part in self._uiparts:
 
6863
            # get the rectangle of the UI part
 
6864
            # originally, this code looked like this:
 
6865
            #    part.rect = wx.Rect(part.sizer_item.GetPosition(),
 
6866
            #                       part.sizer_item.GetSize())
 
6867
            # this worked quite well, with one exception: the mdi
 
6868
            # client window had a "deferred" size variable
 
6869
            # that returned the wrong size.  It looks like
 
6870
            # a bug in wx, because the former size of the window
 
6871
            # was being returned.  So, we will retrieve the part's
 
6872
            # rectangle via other means
 
6873
 
 
6874
            part.rect = part.sizer_item.GetRect()
 
6875
            flag = part.sizer_item.GetFlag()
 
6876
            border = part.sizer_item.GetBorder()
 
6877
 
 
6878
            if flag & wx.TOP:
 
6879
                part.rect.y -= border
 
6880
                part.rect.height += border
 
6881
            if flag & wx.LEFT:
 
6882
                part.rect.x -= border
 
6883
                part.rect.width += border
 
6884
            if flag & wx.BOTTOM:
 
6885
                part.rect.height += border
 
6886
            if flag & wx.RIGHT:
 
6887
                part.rect.width += border
 
6888
 
 
6889
            if part.type == AuiDockUIPart.typeDock:
 
6890
                part.dock.rect = part.rect
 
6891
            if part.type == AuiDockUIPart.typePane:
 
6892
                part.pane.rect = part.rect
 
6893
 
 
6894
 
 
6895
    def GetPanePart(self, wnd):
 
6896
        """
 
6897
        Looks up the pane border UI part of the
 
6898
        pane specified. This allows the caller to get the exact rectangle
 
6899
        of the pane in question, including decorations like caption and border.
 
6900
 
 
6901
        :param Window `wnd`: the window to which the pane border belongs to.
 
6902
        """
 
6903
 
 
6904
        for part in self._uiparts:
 
6905
            if part.type == AuiDockUIPart.typePaneBorder and \
 
6906
               part.pane and part.pane.window == wnd:
 
6907
                return part
 
6908
 
 
6909
        for part in self._uiparts:
 
6910
            if part.type == AuiDockUIPart.typePane and \
 
6911
               part.pane and part.pane.window == wnd:
 
6912
                return part
 
6913
 
 
6914
        return None
 
6915
 
 
6916
 
 
6917
    def GetDockPixelOffset(self, test):
 
6918
        """
 
6919
        This is an internal function which returns a dock's offset in pixels from
 
6920
        the left side of the window (for horizontal docks) or from the top of the
 
6921
        window (for vertical docks).
 
6922
 
 
6923
        This value is necessary for calculating fixed-pane/toolbar offsets
 
6924
        when they are dragged.
 
6925
 
 
6926
        :param `test`: a fake :class:`AuiPaneInfo` for testing purposes.
 
6927
        """
 
6928
 
 
6929
        # the only way to accurately calculate the dock's
 
6930
        # offset is to actually run a theoretical layout
 
6931
        docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
 
6932
        panes.append(test)
 
6933
 
 
6934
        sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
 
6935
        client_size = self._frame.GetClientSize()
 
6936
        sizer.SetDimension(0, 0, client_size.x, client_size.y)
 
6937
        sizer.Layout()
 
6938
 
 
6939
        for part in uiparts:
 
6940
            pos = part.sizer_item.GetPosition()
 
6941
            size = part.sizer_item.GetSize()
 
6942
            part.rect = wx.RectPS(pos, size)
 
6943
            if part.type == AuiDockUIPart.typeDock:
 
6944
                part.dock.rect = part.rect
 
6945
 
 
6946
        sizer.Destroy()
 
6947
 
 
6948
        for dock in docks:
 
6949
            if test.dock_direction == dock.dock_direction and \
 
6950
               test.dock_layer == dock.dock_layer and  \
 
6951
               test.dock_row == dock.dock_row:
 
6952
 
 
6953
                if dock.IsVertical():
 
6954
                    return dock.rect.y
 
6955
                else:
 
6956
                    return dock.rect.x
 
6957
 
 
6958
        return 0
 
6959
 
 
6960
 
 
6961
    def GetPartnerDock(self, dock):
 
6962
        """
 
6963
        Returns the partner dock for the input dock.
 
6964
 
 
6965
        :param `dock`: a :class:`AuiDockInfo` instance.
 
6966
        """
 
6967
 
 
6968
        for layer in xrange(dock.dock_layer, -1, -1):
 
6969
 
 
6970
            bestDock = None
 
6971
 
 
6972
            for tmpDock in self._docks:
 
6973
 
 
6974
                if tmpDock.dock_layer != layer:
 
6975
                    continue
 
6976
 
 
6977
                if tmpDock.dock_direction != dock.dock_direction:
 
6978
                    continue
 
6979
 
 
6980
                if tmpDock.dock_layer < dock.dock_layer:
 
6981
 
 
6982
                    if not bestDock or tmpDock.dock_row < bestDock.dock_row:
 
6983
                        bestDock = tmpDock
 
6984
 
 
6985
                elif tmpDock.dock_row > dock.dock_row:
 
6986
 
 
6987
                    if not bestDock or tmpDock.dock_row > bestDock.dock_row:
 
6988
                        bestDock = tmpDock
 
6989
 
 
6990
            if bestDock:
 
6991
                return bestDock
 
6992
 
 
6993
        return None
 
6994
 
 
6995
 
 
6996
    def GetPartnerPane(self, dock, pane):
 
6997
        """
 
6998
        Returns the partner pane for the input pane. They both need to live
 
6999
        in the same :class:`AuiDockInfo`.
 
7000
 
 
7001
        :param `dock`: a :class:`AuiDockInfo` instance;
 
7002
        :param `pane`: a :class:`AuiPaneInfo` class.
 
7003
        """
 
7004
 
 
7005
        panePosition = -1
 
7006
 
 
7007
        for i, tmpPane in enumerate(dock.panes):
 
7008
            if tmpPane.window == pane.window:
 
7009
                panePosition = i
 
7010
            elif not tmpPane.IsFixed() and panePosition != -1:
 
7011
                return tmpPane
 
7012
 
 
7013
        return None
 
7014
 
 
7015
 
 
7016
    def GetTotalPixSizeAndProportion(self, dock):
 
7017
        """
 
7018
        Returns the dimensions and proportion of the input dock.
 
7019
 
 
7020
        :param `dock`: the :class:`AuiDockInfo` structure to analyze.
 
7021
        """
 
7022
 
 
7023
        totalPixsize = 0
 
7024
        totalProportion = 0
 
7025
 
 
7026
        # determine the total proportion of all resizable panes,
 
7027
        # and the total size of the dock minus the size of all
 
7028
        # the fixed panes
 
7029
        for tmpPane in dock.panes:
 
7030
 
 
7031
            if tmpPane.IsFixed():
 
7032
                continue
 
7033
 
 
7034
            totalProportion += tmpPane.dock_proportion
 
7035
 
 
7036
            if dock.IsHorizontal():
 
7037
                totalPixsize += tmpPane.rect.width
 
7038
            else:
 
7039
                totalPixsize += tmpPane.rect.height
 
7040
 
 
7041
##            if tmpPane.min_size.IsFullySpecified():
 
7042
##
 
7043
##                if dock.IsHorizontal():
 
7044
##                    totalPixsize -= tmpPane.min_size.x
 
7045
##                else:
 
7046
##                    totalPixsize -= tmpPane.min_size.y
 
7047
 
 
7048
        return totalPixsize, totalProportion
 
7049
 
 
7050
 
 
7051
    def GetOppositeDockTotalSize(self, docks, direction):
 
7052
        """
 
7053
        Returns the dimensions of the dock which lives opposite of the input dock.
 
7054
 
 
7055
        :param `docks`: a list of :class:`AuiDockInfo` structures to analyze;
 
7056
        :param integer `direction`: the direction in which to look for the opposite dock.
 
7057
        """
 
7058
 
 
7059
        sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
7060
        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
7061
        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
 
7062
        minSizeMax = 0
 
7063
        result = sash_size
 
7064
        vertical = False
 
7065
 
 
7066
        if direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
 
7067
            vertical = True
 
7068
 
 
7069
        # Get minimum size of the most inner area
 
7070
        for tmpDock in docks:
 
7071
 
 
7072
            if tmpDock.dock_layer != 0:
 
7073
                continue
 
7074
 
 
7075
            if tmpDock.dock_direction != AUI_DOCK_CENTER and tmpDock.IsVertical() != vertical:
 
7076
                continue
 
7077
 
 
7078
            for tmpPane in tmpDock.panes:
 
7079
 
 
7080
                minSize = pane_border_size*2 - sash_size
 
7081
 
 
7082
                if vertical:
 
7083
                    minSize += tmpPane.min_size.y + caption_size
 
7084
                else:
 
7085
                    minSize += tmpPane.min_size.x
 
7086
 
 
7087
                if minSize > minSizeMax:
 
7088
                    minSizeMax = minSize
 
7089
 
 
7090
        result += minSizeMax
 
7091
 
 
7092
        # Get opposite docks
 
7093
        oppositeDocks = FindOppositeDocks(docks, direction)
 
7094
 
 
7095
        # Sum size of the opposite docks and their sashes
 
7096
        for dock in oppositeDocks:
 
7097
            result += dock.size
 
7098
            # if it's not a toolbar add the sash_size too
 
7099
            if not dock.toolbar:
 
7100
                result += sash_size
 
7101
 
 
7102
        return result
 
7103
 
 
7104
 
 
7105
    def CalculateDockSizerLimits(self, dock):
 
7106
        """
 
7107
        Calculates the minimum and maximum sizes allowed for the input dock.
 
7108
 
 
7109
        :param `dock`: the :class:`AuiDockInfo` structure to analyze.
 
7110
        """
 
7111
 
 
7112
        docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
 
7113
 
 
7114
        sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
7115
        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
7116
        opposite_size = self.GetOppositeDockTotalSize(docks, dock.dock_direction)
 
7117
 
 
7118
        for tmpDock in docks:
 
7119
 
 
7120
            if tmpDock.dock_direction == dock.dock_direction and \
 
7121
               tmpDock.dock_layer == dock.dock_layer and \
 
7122
               tmpDock.dock_row == dock.dock_row:
 
7123
 
 
7124
                tmpDock.size = 1
 
7125
                break
 
7126
 
 
7127
        sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
 
7128
        client_size = self._frame.GetClientSize()
 
7129
        sizer.SetDimension(0, 0, client_size.x, client_size.y)
 
7130
        sizer.Layout()
 
7131
 
 
7132
        for part in uiparts:
 
7133
 
 
7134
            part.rect = wx.RectPS(part.sizer_item.GetPosition(), part.sizer_item.GetSize())
 
7135
            if part.type == AuiDockUIPart.typeDock:
 
7136
                part.dock.rect = part.rect
 
7137
 
 
7138
        sizer.Destroy()
 
7139
        new_dock = None
 
7140
 
 
7141
        for tmpDock in docks:
 
7142
            if tmpDock.dock_direction == dock.dock_direction and \
 
7143
               tmpDock.dock_layer == dock.dock_layer and \
 
7144
               tmpDock.dock_row == dock.dock_row:
 
7145
 
 
7146
                new_dock = tmpDock
 
7147
                break
 
7148
 
 
7149
        partnerDock = self.GetPartnerDock(dock)
 
7150
 
 
7151
        if partnerDock:
 
7152
            partnerRange = partnerDock.size - partnerDock.min_size
 
7153
            if partnerDock.min_size == 0:
 
7154
                partnerRange -= sash_size
 
7155
                if dock.IsHorizontal():
 
7156
                    partnerRange -= caption_size
 
7157
 
 
7158
            direction = dock.dock_direction
 
7159
 
 
7160
            if direction == AUI_DOCK_LEFT:
 
7161
                minPix = new_dock.rect.x + new_dock.rect.width
 
7162
                maxPix = dock.rect.x + dock.rect.width
 
7163
                maxPix += partnerRange
 
7164
 
 
7165
            elif direction == AUI_DOCK_TOP:
 
7166
                minPix = new_dock.rect.y + new_dock.rect.height
 
7167
                maxPix = dock.rect.y + dock.rect.height
 
7168
                maxPix += partnerRange
 
7169
 
 
7170
            elif direction == AUI_DOCK_RIGHT:
 
7171
                minPix = dock.rect.x - partnerRange - sash_size
 
7172
                maxPix = new_dock.rect.x - sash_size
 
7173
 
 
7174
            elif direction == AUI_DOCK_BOTTOM:
 
7175
                minPix = dock.rect.y - partnerRange - sash_size
 
7176
                maxPix = new_dock.rect.y - sash_size
 
7177
 
 
7178
            return minPix, maxPix
 
7179
 
 
7180
        direction = new_dock.dock_direction
 
7181
 
 
7182
        if direction == AUI_DOCK_LEFT:
 
7183
            minPix = new_dock.rect.x + new_dock.rect.width
 
7184
            maxPix = client_size.x - opposite_size - sash_size
 
7185
 
 
7186
        elif direction == AUI_DOCK_TOP:
 
7187
            minPix = new_dock.rect.y + new_dock.rect.height
 
7188
            maxPix = client_size.y - opposite_size - sash_size
 
7189
 
 
7190
        elif direction == AUI_DOCK_RIGHT:
 
7191
            minPix = opposite_size
 
7192
            maxPix = new_dock.rect.x - sash_size
 
7193
 
 
7194
        elif direction == AUI_DOCK_BOTTOM:
 
7195
            minPix = opposite_size
 
7196
            maxPix = new_dock.rect.y - sash_size
 
7197
 
 
7198
        return minPix, maxPix
 
7199
 
 
7200
 
 
7201
    def CalculatePaneSizerLimits(self, dock, pane):
 
7202
        """
 
7203
        Calculates the minimum and maximum sizes allowed for the input pane.
 
7204
 
 
7205
        :param `dock`: the :class:`AuiDockInfo` structure to which `pane` belongs to;
 
7206
        :param `pane`: a :class:`AuiPaneInfo` class for which calculation are requested.
 
7207
        """
 
7208
 
 
7209
        if pane.IsFixed():
 
7210
            if dock.IsHorizontal():
 
7211
                minPix = maxPix = pane.rect.x + 1 + pane.rect.width
 
7212
            else:
 
7213
                minPix = maxPix = pane.rect.y + 1 + pane.rect.height
 
7214
 
 
7215
            return minPix, maxPix
 
7216
 
 
7217
        totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
 
7218
        partnerPane = self.GetPartnerPane(dock, pane)
 
7219
 
 
7220
        if dock.IsHorizontal():
 
7221
 
 
7222
            minPix = pane.rect.x + 1
 
7223
            maxPix = pane.rect.x + 1 + pane.rect.width
 
7224
 
 
7225
            if pane.min_size.IsFullySpecified():
 
7226
                minPix += pane.min_size.x
 
7227
            else:
 
7228
                minPix += 1
 
7229
 
 
7230
            if partnerPane:
 
7231
                maxPix += partnerPane.rect.width
 
7232
 
 
7233
                if partnerPane.min_size.IsFullySpecified():
 
7234
                    maxPix -= partnerPane.min_size.x - 1
 
7235
 
 
7236
            else:
 
7237
                minPix = maxPix
 
7238
 
 
7239
        else:
 
7240
 
 
7241
            minPix = pane.rect.y + 1
 
7242
            maxPix = pane.rect.y + 1 + pane.rect.height
 
7243
 
 
7244
            if pane.min_size.IsFullySpecified():
 
7245
                minPix += pane.min_size.y
 
7246
            else:
 
7247
                minPix += 1
 
7248
 
 
7249
            if partnerPane:
 
7250
                maxPix += partnerPane.rect.height
 
7251
 
 
7252
                if partnerPane.min_size.IsFullySpecified():
 
7253
                    maxPix -= partnerPane.min_size.y - 1
 
7254
 
 
7255
            else:
 
7256
                minPix = maxPix
 
7257
 
 
7258
        return minPix, maxPix
 
7259
 
 
7260
 
 
7261
    def CheckMovableSizer(self, part):
 
7262
        """
 
7263
        Checks if a UI part can be actually resized.
 
7264
 
 
7265
        :param AuiDockUIPart `part`: a UI part.
 
7266
        """
 
7267
 
 
7268
        # a dock may not be resized if it has a single
 
7269
        # pane which is not resizable
 
7270
        if part.type == AuiDockUIPart.typeDockSizer and part.dock and \
 
7271
           len(part.dock.panes) == 1 and part.dock.panes[0].IsFixed():
 
7272
 
 
7273
            return False
 
7274
 
 
7275
        if part.pane:
 
7276
 
 
7277
            # panes that may not be resized should be ignored here
 
7278
            minPix, maxPix = self.CalculatePaneSizerLimits(part.dock, part.pane)
 
7279
 
 
7280
            if minPix == maxPix:
 
7281
                return False
 
7282
 
 
7283
        return True
 
7284
 
 
7285
 
 
7286
    def PaneFromTabEvent(self, event):
 
7287
        """
 
7288
        Returns a :class:`AuiPaneInfo` from a :class:`~lib.agw.aui.auibook.AuiNotebook` event.
 
7289
 
 
7290
        :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event.
 
7291
        """
 
7292
 
 
7293
        obj = event.GetEventObject()
 
7294
 
 
7295
        if obj and isinstance(obj, auibook.AuiTabCtrl):
 
7296
 
 
7297
            page_idx = obj.GetActivePage()
 
7298
 
 
7299
            if page_idx >= 0:
 
7300
                page = obj.GetPage(page_idx)
 
7301
                window = page.window
 
7302
                if window:
 
7303
                    return self.GetPane(window)
 
7304
 
 
7305
        elif obj and isinstance(obj, auibook.AuiNotebook):
 
7306
 
 
7307
            page_idx = event.GetSelection()
 
7308
 
 
7309
            if page_idx >= 0:
 
7310
                window = obj.GetPage(page_idx)
 
7311
                if window:
 
7312
                    return self.GetPane(window)
 
7313
 
 
7314
        return NonePaneInfo
 
7315
 
 
7316
 
 
7317
    def OnTabBeginDrag(self, event):
 
7318
        """
 
7319
        Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event.
 
7320
 
 
7321
        :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event to be processed.
 
7322
        """
 
7323
 
 
7324
        if self._masterManager:
 
7325
            self._masterManager.OnTabBeginDrag(event)
 
7326
 
 
7327
        else:
 
7328
            paneInfo = self.PaneFromTabEvent(event)
 
7329
 
 
7330
            if paneInfo.IsOk():
 
7331
 
 
7332
                # It's one of ours!
 
7333
                self._action = actionDragFloatingPane
 
7334
                mouse = wx.GetMousePosition()
 
7335
 
 
7336
                # set initial float position - may have to think about this
 
7337
                # offset a bit more later ...
 
7338
                self._action_offset = wx.Point(20, 10)
 
7339
                self._toolbar_action_offset = wx.Point(20, 10)
 
7340
 
 
7341
                paneInfo.floating_pos = mouse - self._action_offset
 
7342
                paneInfo.dock_pos = AUI_DOCK_NONE
 
7343
                paneInfo.notebook_id = -1
 
7344
 
 
7345
                tab = event.GetEventObject()
 
7346
 
 
7347
                if tab.HasCapture():
 
7348
                    tab.ReleaseMouse()
 
7349
 
 
7350
                # float the window
 
7351
                if paneInfo.IsMaximized():
 
7352
                    self.RestorePane(paneInfo)
 
7353
                paneInfo.Float()
 
7354
                self.Update()
 
7355
 
 
7356
                self._action_window = paneInfo.window
 
7357
 
 
7358
                self._frame.CaptureMouse()
 
7359
                event.SetDispatched(True)
 
7360
 
 
7361
            else:
 
7362
 
 
7363
                # not our window
 
7364
                event.Skip()
 
7365
 
 
7366
 
 
7367
    def OnTabPageClose(self, event):
 
7368
        """
 
7369
        Handles the ``EVT_AUINOTEBOOK_PAGE_CLOSE`` event.
 
7370
 
 
7371
        :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event to be processed.
 
7372
        """
 
7373
 
 
7374
        if self._masterManager:
 
7375
            self._masterManager.OnTabPageClose(event)
 
7376
 
 
7377
        else:
 
7378
 
 
7379
            p = self.PaneFromTabEvent(event)
 
7380
            if p.IsOk():
 
7381
 
 
7382
                # veto it because we will call "RemovePage" ourselves
 
7383
                event.Veto()
 
7384
 
 
7385
                # Now ask the app if they really want to close...
 
7386
                # fire pane close event
 
7387
                e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
 
7388
                e.SetPane(p)
 
7389
                e.SetCanVeto(True)
 
7390
                self.ProcessMgrEvent(e)
 
7391
 
 
7392
                if e.GetVeto():
 
7393
                    return
 
7394
 
 
7395
                self.ClosePane(p)
 
7396
                self.Update()
 
7397
            else:
 
7398
                event.Skip()
 
7399
 
 
7400
 
 
7401
    def OnTabSelected(self, event):
 
7402
        """
 
7403
        Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGED`` event.
 
7404
 
 
7405
        :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event to be processed.
 
7406
        """
 
7407
 
 
7408
        if self._masterManager:
 
7409
            self._masterManager.OnTabSelected(event)
 
7410
            return
 
7411
 
 
7412
        obj = event.GetEventObject()
 
7413
 
 
7414
        if obj and isinstance(obj, auibook.AuiNotebook):
 
7415
 
 
7416
            notebook = obj
 
7417
            page = notebook.GetPage(event.GetSelection())
 
7418
            paneInfo = self.GetPane(page)
 
7419
 
 
7420
            if paneInfo.IsOk():
 
7421
                notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
 
7422
                if notebookRoot:
 
7423
 
 
7424
                    notebookRoot.Caption(paneInfo.caption)
 
7425
                    self.RefreshCaptions()
 
7426
 
 
7427
        event.Skip()
 
7428
 
 
7429
 
 
7430
    def GetNotebooks(self):
 
7431
        """ Returns all the automatic :class:`~lib.agw.aui.auibook.AuiNotebook` in the :class:`AuiManager`. """
 
7432
 
 
7433
        if self._masterManager:
 
7434
            return self._masterManager.GetNotebooks()
 
7435
 
 
7436
        return self._notebooks
 
7437
 
 
7438
 
 
7439
    def SetMasterManager(self, manager):
 
7440
        """
 
7441
        Sets the master manager for an automatic :class:`~lib.agw.aui.auibook.AuiNotebook`.
 
7442
 
 
7443
        :param `manager`: an instance of :class:`AuiManager`.
 
7444
        """
 
7445
 
 
7446
        self._masterManager = manager
 
7447
 
 
7448
 
 
7449
    def ProcessDockResult(self, target, new_pos):
 
7450
        """
 
7451
        This is a utility function used by :meth:`DoDrop` - it checks
 
7452
        if a dock operation is allowed, the new dock position is copied into
 
7453
        the target info. If the operation was allowed, the function returns ``True``.
 
7454
 
 
7455
        :param `target`: the :class:`AuiPaneInfo` instance to be docked;
 
7456
        :param integer `new_pos`: the new docking position if the docking operation is allowed.
 
7457
        """
 
7458
 
 
7459
        allowed = False
 
7460
        direction = new_pos.dock_direction
 
7461
 
 
7462
        if direction == AUI_DOCK_TOP:
 
7463
            allowed = target.IsTopDockable()
 
7464
        elif direction == AUI_DOCK_BOTTOM:
 
7465
            allowed = target.IsBottomDockable()
 
7466
        elif direction == AUI_DOCK_LEFT:
 
7467
            allowed = target.IsLeftDockable()
 
7468
        elif direction == AUI_DOCK_RIGHT:
 
7469
            allowed = target.IsRightDockable()
 
7470
 
 
7471
        if allowed:
 
7472
            target = new_pos
 
7473
 
 
7474
            if target.IsToolbar():
 
7475
                self.SwitchToolBarOrientation(target)
 
7476
 
 
7477
        return allowed, target
 
7478
 
 
7479
 
 
7480
    def SwitchToolBarOrientation(self, pane):
 
7481
        """
 
7482
        Switches the toolbar orientation from vertical to horizontal and vice-versa.
 
7483
        This is especially useful for vertical docked toolbars once they float.
 
7484
 
 
7485
        :param `pane`: an instance of :class:`AuiPaneInfo`, which may have a :class:`~lib.agw.aui.auibar.AuiToolBar`
 
7486
         window associated with it.
 
7487
        """
 
7488
 
 
7489
        if not isinstance(pane.window, auibar.AuiToolBar):
 
7490
            return pane
 
7491
 
 
7492
        if pane.IsFloating():
 
7493
            return pane
 
7494
 
 
7495
        toolBar = pane.window
 
7496
        direction = pane.dock_direction
 
7497
        vertical = direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
 
7498
 
 
7499
        agwStyle = toolBar.GetAGWWindowStyleFlag()
 
7500
        new_agwStyle = agwStyle
 
7501
 
 
7502
        if vertical:
 
7503
            new_agwStyle |= AUI_TB_VERTICAL
 
7504
        else:
 
7505
            new_agwStyle &= ~(AUI_TB_VERTICAL)
 
7506
 
 
7507
        if agwStyle != new_agwStyle:
 
7508
            toolBar.SetAGWWindowStyleFlag(new_agwStyle)
 
7509
        if not toolBar.GetGripperVisible():
 
7510
            toolBar.SetGripperVisible(True)
 
7511
 
 
7512
        s = pane.window.GetMinSize()
 
7513
        pane.BestSize(s)
 
7514
 
 
7515
        if new_agwStyle != agwStyle:
 
7516
            toolBar.Realize()
 
7517
 
 
7518
        return pane
 
7519
 
 
7520
 
 
7521
    def DoDrop(self, docks, panes, target, pt, offset=wx.Point(0, 0)):
 
7522
        """
 
7523
        This is an important function. It basically takes a mouse position,
 
7524
        and determines where the panes new position would be. If the pane is to be
 
7525
        dropped, it performs the drop operation using the specified dock and pane
 
7526
        arrays. By specifying copy dock and pane arrays when calling, a "what-if"
 
7527
        scenario can be performed, giving precise coordinates for drop hints.
 
7528
 
 
7529
        :param `docks`: a list of :class:`AuiDockInfo` classes;
 
7530
        :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
7531
        :param Point `pt`: a mouse position to check for a drop operation;
 
7532
        :param Point `offset`: a possible offset from the input point `pt`.
 
7533
        """
 
7534
 
 
7535
        if target.IsToolbar():
 
7536
            return self.DoDropToolbar(docks, panes, target, pt, offset)
 
7537
        elif target.IsFloating():
 
7538
            return self.DoDropFloatingPane(docks, panes, target, pt)
 
7539
        else:
 
7540
            return self.DoDropNonFloatingPane(docks, panes, target, pt)
 
7541
 
 
7542
 
 
7543
    def CopyTarget(self, target):
 
7544
        """
 
7545
        Copies all the attributes of the input `target` into another :class:`AuiPaneInfo`.
 
7546
 
 
7547
        :param `target`: the source :class:`AuiPaneInfo` from where to copy attributes.
 
7548
        """
 
7549
 
 
7550
        drop = AuiPaneInfo()
 
7551
        drop.name = target.name
 
7552
        drop.caption = target.caption
 
7553
        drop.window = target.window
 
7554
        drop.frame = target.frame
 
7555
        drop.state = target.state
 
7556
        drop.dock_direction = target.dock_direction
 
7557
        drop.dock_layer = target.dock_layer
 
7558
        drop.dock_row = target.dock_row
 
7559
        drop.dock_pos = target.dock_pos
 
7560
        drop.best_size = wx.Size(*target.best_size)
 
7561
        drop.min_size = wx.Size(*target.min_size)
 
7562
        drop.max_size = wx.Size(*target.max_size)
 
7563
        drop.floating_pos = wx.Point(*target.floating_pos)
 
7564
        drop.floating_size = wx.Size(*target.floating_size)
 
7565
        drop.dock_proportion = target.dock_proportion
 
7566
        drop.buttons = target.buttons
 
7567
        drop.rect = wx.Rect(*target.rect)
 
7568
        drop.icon = target.icon
 
7569
        drop.notebook_id = target.notebook_id
 
7570
        drop.transparent = target.transparent
 
7571
        drop.snapped = target.snapped
 
7572
        drop.minimize_mode = target.minimize_mode
 
7573
        drop.minimize_target = target.minimize_target
 
7574
 
 
7575
        return drop
 
7576
 
 
7577
 
 
7578
    def DoDropToolbar(self, docks, panes, target, pt, offset):
 
7579
        """
 
7580
        Handles the situation in which the dropped pane contains a toolbar.
 
7581
 
 
7582
        :param `docks`: a list of :class:`AuiDockInfo` classes;
 
7583
        :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
7584
        :param AuiPaneInfo `target`: the target pane containing the toolbar;
 
7585
        :param Point `pt`: a mouse position to check for a drop operation;
 
7586
        :param Point `offset`: a possible offset from the input point `pt`.
 
7587
        """
 
7588
 
 
7589
        drop = self.CopyTarget(target)
 
7590
 
 
7591
        # The result should always be shown
 
7592
        drop.Show()
 
7593
 
 
7594
        # Check to see if the toolbar has been dragged out of the window
 
7595
        if CheckOutOfWindow(self._frame, pt):
 
7596
            if self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable():
 
7597
                drop.Float()
 
7598
 
 
7599
            return self.ProcessDockResult(target, drop)
 
7600
 
 
7601
        # Allow directional change when the cursor leaves this rect
 
7602
        safeRect = wx.Rect(*target.rect)
 
7603
        if target.IsHorizontal():
 
7604
            safeRect.Inflate(100, 50)
 
7605
        else:
 
7606
            safeRect.Inflate(50, 100)
 
7607
 
 
7608
        # Check to see if the toolbar has been dragged to edge of the frame
 
7609
        dropDir = CheckEdgeDrop(self._frame, docks, pt)
 
7610
 
 
7611
        if dropDir != -1:
 
7612
 
 
7613
            if dropDir == wx.LEFT:
 
7614
                drop.Dock().Left().Layer(auiToolBarLayer).Row(0). \
 
7615
                    Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
 
7616
 
 
7617
            elif dropDir == wx.RIGHT:
 
7618
                drop.Dock().Right().Layer(auiToolBarLayer).Row(0). \
 
7619
                    Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
 
7620
 
 
7621
            elif dropDir == wx.TOP:
 
7622
                drop.Dock().Top().Layer(auiToolBarLayer).Row(0). \
 
7623
                    Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
 
7624
 
 
7625
            elif dropDir == wx.BOTTOM:
 
7626
                drop.Dock().Bottom().Layer(auiToolBarLayer).Row(0). \
 
7627
                    Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
 
7628
 
 
7629
            if not target.IsFloating() and safeRect.Contains(pt) and \
 
7630
               target.dock_direction != drop.dock_direction:
 
7631
                return False, target
 
7632
 
 
7633
            return self.ProcessDockResult(target, drop)
 
7634
 
 
7635
        # If the windows is floating and out of the client area, do nothing
 
7636
        if drop.IsFloating() and not self._frame.GetClientRect().Contains(pt):
 
7637
            return False, target
 
7638
 
 
7639
        # Ok, can't drop on edge - check internals ...
 
7640
 
 
7641
        clientSize = self._frame.GetClientSize()
 
7642
        x = Clip(pt.x, 0, clientSize.x - 1)
 
7643
        y = Clip(pt.y, 0, clientSize.y - 1)
 
7644
        part = self.HitTest(x, y)
 
7645
 
 
7646
        if not part or not part.dock:
 
7647
            return False, target
 
7648
 
 
7649
        dock = part.dock
 
7650
 
 
7651
        # toolbars may only be moved in and to fixed-pane docks,
 
7652
        # otherwise we will try to float the pane.  Also, the pane
 
7653
        # should float if being dragged over center pane windows
 
7654
        if not dock.fixed or dock.dock_direction == AUI_DOCK_CENTER:
 
7655
 
 
7656
            if (self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable()) or \
 
7657
               dock.dock_direction not in [AUI_DOCK_CENTER, AUI_DOCK_NONE]:
 
7658
                if drop.IsFloatable():
 
7659
                    drop.Float()
 
7660
 
 
7661
            return self.ProcessDockResult(target, drop)
 
7662
 
 
7663
        # calculate the offset from where the dock begins
 
7664
        # to the point where the user dropped the pane
 
7665
        dockDropOffset = 0
 
7666
        if dock.IsHorizontal():
 
7667
            dockDropOffset = pt.x - dock.rect.x - offset.x
 
7668
        else:
 
7669
            dockDropOffset = pt.y - dock.rect.y - offset.y
 
7670
 
 
7671
        drop.Dock().Direction(dock.dock_direction).Layer(dock.dock_layer). \
 
7672
            Row(dock.dock_row).Position(dockDropOffset)
 
7673
 
 
7674
        if (pt.y <= dock.rect.GetTop() + 2 and dock.IsHorizontal()) or \
 
7675
           (pt.x <= dock.rect.GetLeft() + 2 and dock.IsVertical()):
 
7676
 
 
7677
            if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
 
7678
                row = drop.dock_row
 
7679
                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
 
7680
                drop.dock_row = row
 
7681
 
 
7682
            else:
 
7683
                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
 
7684
                drop.dock_row = dock.dock_row + 1
 
7685
 
 
7686
        if (pt.y >= dock.rect.GetBottom() - 2 and dock.IsHorizontal()) or \
 
7687
           (pt.x >= dock.rect.GetRight() - 2 and dock.IsVertical()):
 
7688
 
 
7689
            if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
 
7690
                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
 
7691
                drop.dock_row = dock.dock_row+1
 
7692
 
 
7693
            else:
 
7694
                row = drop.dock_row
 
7695
                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
 
7696
                drop.dock_row = row
 
7697
 
 
7698
        if not target.IsFloating() and safeRect.Contains(pt) and \
 
7699
           target.dock_direction != drop.dock_direction:
 
7700
            return False, target
 
7701
 
 
7702
        return self.ProcessDockResult(target, drop)
 
7703
 
 
7704
 
 
7705
    def DoDropFloatingPane(self, docks, panes, target, pt):
 
7706
        """
 
7707
        Handles the situation in which the dropped pane contains a normal window.
 
7708
 
 
7709
        :param `docks`: a list of :class:`AuiDockInfo` classes;
 
7710
        :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
7711
        :param AuiPaneInfo `target`: the target pane containing the window;
 
7712
        :param Point `pt`: a mouse position to check for a drop operation.
 
7713
        """
 
7714
 
 
7715
        screenPt = self._frame.ClientToScreen(pt)
 
7716
        paneInfo = self.PaneHitTest(panes, pt)
 
7717
 
 
7718
        if paneInfo.IsMaximized():
 
7719
            return False, target
 
7720
 
 
7721
        if paneInfo.window is None:
 
7722
            return False, target
 
7723
 
 
7724
        # search the dock guides.
 
7725
        # reverse order to handle the center first.
 
7726
        for i in xrange(len(self._guides)-1, -1, -1):
 
7727
            guide = self._guides[i]
 
7728
 
 
7729
            # do hit testing on the guide
 
7730
            dir = guide.host.HitTest(screenPt.x, screenPt.y)
 
7731
 
 
7732
            if dir == -1:  # point was outside of the dock guide
 
7733
                continue
 
7734
 
 
7735
            if dir == wx.ALL:   # target is a single dock guide
 
7736
                return self.DoDropLayer(docks, target, guide.dock_direction)
 
7737
 
 
7738
            elif dir == wx.CENTER:
 
7739
 
 
7740
                if not target.IsNotebookDockable():
 
7741
                    continue
 
7742
                if not paneInfo.IsNotebookDockable() and not paneInfo.IsNotebookControl():
 
7743
                    continue
 
7744
 
 
7745
                if not paneInfo.HasNotebook():
 
7746
 
 
7747
                    # Add a new notebook pane with the original as a tab...
 
7748
                    self.CreateNotebookBase(panes, paneInfo)
 
7749
 
 
7750
                # Add new item to notebook
 
7751
                target.NotebookPage(paneInfo.notebook_id)
 
7752
 
 
7753
            else:
 
7754
 
 
7755
                drop_pane = False
 
7756
                drop_row = False
 
7757
 
 
7758
                insert_dir = paneInfo.dock_direction
 
7759
                insert_layer = paneInfo.dock_layer
 
7760
                insert_row = paneInfo.dock_row
 
7761
                insert_pos = paneInfo.dock_pos
 
7762
 
 
7763
                if insert_dir == AUI_DOCK_CENTER:
 
7764
 
 
7765
                    insert_layer = 0
 
7766
                    if dir == wx.LEFT:
 
7767
                        insert_dir = AUI_DOCK_LEFT
 
7768
                    elif dir == wx.UP:
 
7769
                        insert_dir = AUI_DOCK_TOP
 
7770
                    elif dir == wx.RIGHT:
 
7771
                        insert_dir = AUI_DOCK_RIGHT
 
7772
                    elif dir == wx.DOWN:
 
7773
                        insert_dir = AUI_DOCK_BOTTOM
 
7774
 
 
7775
                if insert_dir == AUI_DOCK_LEFT:
 
7776
 
 
7777
                    drop_pane = (dir == wx.UP   or dir == wx.DOWN)
 
7778
                    drop_row  = (dir == wx.LEFT or dir == wx.RIGHT)
 
7779
                    if dir == wx.RIGHT:
 
7780
                        insert_row += 1
 
7781
                    elif dir == wx.DOWN:
 
7782
                        insert_pos += 1
 
7783
 
 
7784
                elif insert_dir == AUI_DOCK_RIGHT:
 
7785
 
 
7786
                    drop_pane = (dir == wx.UP   or dir == wx.DOWN)
 
7787
                    drop_row  = (dir == wx.LEFT or dir == wx.RIGHT)
 
7788
                    if dir == wx.LEFT:
 
7789
                        insert_row += 1
 
7790
                    elif dir == wx.DOWN:
 
7791
                        insert_pos += 1
 
7792
 
 
7793
                elif insert_dir == AUI_DOCK_TOP:
 
7794
 
 
7795
                    drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
 
7796
                    drop_row  = (dir == wx.UP   or dir == wx.DOWN)
 
7797
                    if dir == wx.DOWN:
 
7798
                        insert_row += 1
 
7799
                    elif dir == wx.RIGHT:
 
7800
                        insert_pos += 1
 
7801
 
 
7802
                elif insert_dir == AUI_DOCK_BOTTOM:
 
7803
 
 
7804
                    drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
 
7805
                    drop_row  = (dir == wx.UP   or dir == wx.DOWN)
 
7806
                    if dir == wx.UP:
 
7807
                        insert_row += 1
 
7808
                    elif dir == wx.RIGHT:
 
7809
                        insert_pos += 1
 
7810
 
 
7811
                if paneInfo.dock_direction == AUI_DOCK_CENTER:
 
7812
                    insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
 
7813
 
 
7814
                if drop_pane:
 
7815
                    return self.DoDropPane(panes, target, insert_dir, insert_layer, insert_row, insert_pos)
 
7816
 
 
7817
                if drop_row:
 
7818
                    return self.DoDropRow(panes, target, insert_dir, insert_layer, insert_row)
 
7819
 
 
7820
            return True, target
 
7821
 
 
7822
        return False, target
 
7823
 
 
7824
 
 
7825
    def DoDropNonFloatingPane(self, docks, panes, target, pt):
 
7826
        """
 
7827
        Handles the situation in which the dropped pane is not floating.
 
7828
 
 
7829
        :param `docks`: a list of :class:`AuiDockInfo` classes;
 
7830
        :param `panes`: a list of :class:`AuiPaneInfo` instances;
 
7831
        :param AuiPaneInfo `target`: the target pane containing the toolbar;
 
7832
        :param Point `pt`: a mouse position to check for a drop operation.
 
7833
        """
 
7834
 
 
7835
        screenPt = self._frame.ClientToScreen(pt)
 
7836
        clientSize = self._frame.GetClientSize()
 
7837
        frameRect = GetInternalFrameRect(self._frame, self._docks)
 
7838
 
 
7839
        drop = self.CopyTarget(target)
 
7840
 
 
7841
        # The result should always be shown
 
7842
        drop.Show()
 
7843
 
 
7844
        part = self.HitTest(pt.x, pt.y)
 
7845
 
 
7846
        if not part:
 
7847
            return False, target
 
7848
 
 
7849
        if part.type == AuiDockUIPart.typeDockSizer:
 
7850
 
 
7851
            if len(part.dock.panes) != 1:
 
7852
                return False, target
 
7853
 
 
7854
            part = self.GetPanePart(part.dock.panes[0].window)
 
7855
            if not part:
 
7856
                return False, target
 
7857
 
 
7858
        if not part.pane:
 
7859
            return False, target
 
7860
 
 
7861
        part = self.GetPanePart(part.pane.window)
 
7862
        if not part:
 
7863
            return False, target
 
7864
 
 
7865
        insert_dock_row = False
 
7866
        insert_row = part.pane.dock_row
 
7867
        insert_dir = part.pane.dock_direction
 
7868
        insert_layer = part.pane.dock_layer
 
7869
 
 
7870
        direction = part.pane.dock_direction
 
7871
 
 
7872
        if direction == AUI_DOCK_TOP:
 
7873
            if pt.y >= part.rect.y and pt.y < part.rect.y+auiInsertRowPixels:
 
7874
                insert_dock_row = True
 
7875
 
 
7876
        elif direction == AUI_DOCK_BOTTOM:
 
7877
            if pt.y > part.rect.y+part.rect.height-auiInsertRowPixels and \
 
7878
               pt.y <= part.rect.y + part.rect.height:
 
7879
                insert_dock_row = True
 
7880
 
 
7881
        elif direction == AUI_DOCK_LEFT:
 
7882
            if pt.x >= part.rect.x and pt.x < part.rect.x+auiInsertRowPixels:
 
7883
                insert_dock_row = True
 
7884
 
 
7885
        elif direction == AUI_DOCK_RIGHT:
 
7886
            if pt.x > part.rect.x+part.rect.width-auiInsertRowPixels and \
 
7887
               pt.x <= part.rect.x+part.rect.width:
 
7888
                insert_dock_row = True
 
7889
 
 
7890
        elif direction == AUI_DOCK_CENTER:
 
7891
 
 
7892
                # "new row pixels" will be set to the default, but
 
7893
                # must never exceed 20% of the window size
 
7894
                new_row_pixels_x = auiNewRowPixels
 
7895
                new_row_pixels_y = auiNewRowPixels
 
7896
 
 
7897
                if new_row_pixels_x > (part.rect.width*20)/100:
 
7898
                    new_row_pixels_x = (part.rect.width*20)/100
 
7899
 
 
7900
                if new_row_pixels_y > (part.rect.height*20)/100:
 
7901
                    new_row_pixels_y = (part.rect.height*20)/100
 
7902
 
 
7903
                # determine if the mouse pointer is in a location that
 
7904
                # will cause a new row to be inserted.  The hot spot positions
 
7905
                # are along the borders of the center pane
 
7906
 
 
7907
                insert_layer = 0
 
7908
                insert_dock_row = True
 
7909
                pr = part.rect
 
7910
 
 
7911
                if pt.x >= pr.x and pt.x < pr.x + new_row_pixels_x:
 
7912
                    insert_dir = AUI_DOCK_LEFT
 
7913
                elif pt.y >= pr.y and pt.y < pr.y + new_row_pixels_y:
 
7914
                    insert_dir = AUI_DOCK_TOP
 
7915
                elif pt.x >= pr.x + pr.width - new_row_pixels_x and pt.x < pr.x + pr.width:
 
7916
                    insert_dir = AUI_DOCK_RIGHT
 
7917
                elif pt.y >= pr.y+ pr.height - new_row_pixels_y and pt.y < pr.y + pr.height:
 
7918
                    insert_dir = AUI_DOCK_BOTTOM
 
7919
                else:
 
7920
                    return False, target
 
7921
 
 
7922
                insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
 
7923
 
 
7924
        if insert_dock_row:
 
7925
 
 
7926
            panes = DoInsertDockRow(panes, insert_dir, insert_layer, insert_row)
 
7927
            drop.Dock().Direction(insert_dir).Layer(insert_layer). \
 
7928
                Row(insert_row).Position(0)
 
7929
 
 
7930
            return self.ProcessDockResult(target, drop)
 
7931
 
 
7932
        # determine the mouse offset and the pane size, both in the
 
7933
        # direction of the dock itself, and perpendicular to the dock
 
7934
 
 
7935
        if part.orientation == wx.VERTICAL:
 
7936
 
 
7937
            offset = pt.y - part.rect.y
 
7938
            size = part.rect.GetHeight()
 
7939
 
 
7940
        else:
 
7941
 
 
7942
            offset = pt.x - part.rect.x
 
7943
            size = part.rect.GetWidth()
 
7944
 
 
7945
        drop_position = part.pane.dock_pos
 
7946
 
 
7947
        # if we are in the top/left part of the pane,
 
7948
        # insert the pane before the pane being hovered over
 
7949
        if offset <= size/2:
 
7950
 
 
7951
            drop_position = part.pane.dock_pos
 
7952
            panes = DoInsertPane(panes,
 
7953
                                 part.pane.dock_direction,
 
7954
                                 part.pane.dock_layer,
 
7955
                                 part.pane.dock_row,
 
7956
                                 part.pane.dock_pos)
 
7957
 
 
7958
        # if we are in the bottom/right part of the pane,
 
7959
        # insert the pane before the pane being hovered over
 
7960
        if offset > size/2:
 
7961
 
 
7962
            drop_position = part.pane.dock_pos+1
 
7963
            panes = DoInsertPane(panes,
 
7964
                                 part.pane.dock_direction,
 
7965
                                 part.pane.dock_layer,
 
7966
                                 part.pane.dock_row,
 
7967
                                 part.pane.dock_pos+1)
 
7968
 
 
7969
 
 
7970
        drop.Dock(). \
 
7971
                     Direction(part.dock.dock_direction). \
 
7972
                     Layer(part.dock.dock_layer).Row(part.dock.dock_row). \
 
7973
                     Position(drop_position)
 
7974
 
 
7975
        return self.ProcessDockResult(target, drop)
 
7976
 
 
7977
 
 
7978
    def DoDropLayer(self, docks, target, dock_direction):
 
7979
        """
 
7980
        Handles the situation in which `target` is a single dock guide.
 
7981
 
 
7982
        :param `docks`: a list of :class:`AuiDockInfo` classes;
 
7983
        :param AuiPaneInfo `target`: the target pane;
 
7984
        :param integer `dock_direction`: the docking direction.
 
7985
        """
 
7986
 
 
7987
        drop = self.CopyTarget(target)
 
7988
 
 
7989
        if dock_direction == AUI_DOCK_LEFT:
 
7990
            drop.Dock().Left()
 
7991
            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_LEFT),
 
7992
                                     GetMaxLayer(docks, AUI_DOCK_BOTTOM)),
 
7993
                                 GetMaxLayer(docks, AUI_DOCK_TOP)) + 1
 
7994
 
 
7995
        elif dock_direction == AUI_DOCK_TOP:
 
7996
            drop.Dock().Top()
 
7997
            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_TOP),
 
7998
                                     GetMaxLayer(docks, AUI_DOCK_LEFT)),
 
7999
                                 GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
 
8000
 
 
8001
        elif dock_direction == AUI_DOCK_RIGHT:
 
8002
            drop.Dock().Right()
 
8003
            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_RIGHT),
 
8004
                                     GetMaxLayer(docks, AUI_DOCK_TOP)),
 
8005
                                 GetMaxLayer(docks, AUI_DOCK_BOTTOM)) + 1
 
8006
 
 
8007
        elif dock_direction == AUI_DOCK_BOTTOM:
 
8008
            drop.Dock().Bottom()
 
8009
            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_BOTTOM),
 
8010
                                     GetMaxLayer(docks, AUI_DOCK_LEFT)),
 
8011
                                 GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
 
8012
 
 
8013
        else:
 
8014
            return False, target
 
8015
 
 
8016
 
 
8017
        drop.Dock().Layer(drop_new_layer)
 
8018
        return self.ProcessDockResult(target, drop)
 
8019
 
 
8020
 
 
8021
    def DoDropPane(self, panes, target, dock_direction, dock_layer, dock_row, dock_pos):
 
8022
        """
 
8023
        Drop a pane in the interface.
 
8024
 
 
8025
        :param `panes`: a list of :class:`AuiPaneInfo` classes;
 
8026
        :param AuiPaneInfo `target`: the target pane;
 
8027
        :param integer `dock_direction`: the docking direction;
 
8028
        :param integer `dock_layer`: the docking layer;
 
8029
        :param integer `dock_row`: the docking row;
 
8030
        :param integer `dock_pos`: the docking position.
 
8031
        """
 
8032
 
 
8033
        drop = self.CopyTarget(target)
 
8034
        panes = DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos)
 
8035
 
 
8036
        drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(dock_pos)
 
8037
        return self.ProcessDockResult(target, drop)
 
8038
 
 
8039
 
 
8040
    def DoDropRow(self, panes, target, dock_direction, dock_layer, dock_row):
 
8041
        """
 
8042
        Insert a row in the interface before dropping.
 
8043
 
 
8044
        :param `panes`: a list of :class:`AuiPaneInfo` classes;
 
8045
        :param AuiPaneInfo `target`: the target pane;
 
8046
        :param integer `dock_direction`: the docking direction;
 
8047
        :param integer `dock_layer`: the docking layer;
 
8048
        :param integer `dock_row`: the docking row.
 
8049
        """
 
8050
 
 
8051
        drop = self.CopyTarget(target)
 
8052
        panes = DoInsertDockRow(panes, dock_direction, dock_layer, dock_row)
 
8053
 
 
8054
        drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(0)
 
8055
        return self.ProcessDockResult(target, drop)
 
8056
 
 
8057
 
 
8058
    def ShowHint(self, rect):
 
8059
        """
 
8060
        Shows the AUI hint window.
 
8061
 
 
8062
        :param Rect `rect`: the hint rect calculated in advance.
 
8063
        """
 
8064
 
 
8065
        if rect == self._last_hint:
 
8066
            return
 
8067
 
 
8068
        if self._agwFlags & AUI_MGR_RECTANGLE_HINT and wx.Platform != "__WXMAC__":
 
8069
 
 
8070
            if self._last_hint != rect:
 
8071
                # remove the last hint rectangle
 
8072
                self._last_hint = wx.Rect(*rect)
 
8073
                self._frame.Refresh()
 
8074
                self._frame.Update()
 
8075
 
 
8076
            screendc = wx.ScreenDC()
 
8077
            clip = wx.Region(1, 1, 10000, 10000)
 
8078
 
 
8079
            # clip all floating windows, so we don't draw over them
 
8080
            for pane in self._panes:
 
8081
                if pane.IsFloating() and pane.frame.IsShown():
 
8082
 
 
8083
                    rect2 = wx.Rect(*pane.frame.GetRect())
 
8084
                    if wx.Platform == "__WXGTK__":
 
8085
                        # wxGTK returns the client size, not the whole frame size
 
8086
                        rect2.width += 15
 
8087
                        rect2.height += 35
 
8088
                        rect2.Inflate(5, 5)
 
8089
 
 
8090
                    clip.SubtractRect(rect2)
 
8091
 
 
8092
            # As we can only hide the hint by redrawing the managed window, we
 
8093
            # need to clip the region to the managed window too or we get
 
8094
            # nasty redrawn problems.
 
8095
            clip.IntersectRect(self._frame.GetRect())
 
8096
            screendc.SetClippingRegionAsRegion(clip)
 
8097
 
 
8098
            stipple = PaneCreateStippleBitmap()
 
8099
            brush = wx.BrushFromBitmap(stipple)
 
8100
            screendc.SetBrush(brush)
 
8101
            screendc.SetPen(wx.TRANSPARENT_PEN)
 
8102
            screendc.DrawRectangle(rect.x, rect.y, 5, rect.height)
 
8103
            screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5)
 
8104
            screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height)
 
8105
            screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5)
 
8106
            RefreshDockingGuides(self._guides)
 
8107
 
 
8108
            return
 
8109
 
 
8110
        if not self._hint_window:
 
8111
            self.CreateHintWindow()
 
8112
 
 
8113
        if self._hint_window:
 
8114
            self._hint_window.SetRect(rect)
 
8115
            self._hint_window.Show()
 
8116
 
 
8117
        self._hint_fadeamt = self._hint_fademax
 
8118
 
 
8119
        if self._agwFlags & AUI_MGR_HINT_FADE:
 
8120
            self._hint_fadeamt = 0
 
8121
            self._hint_window.SetTransparent(self._hint_fadeamt)
 
8122
 
 
8123
        if self._action == actionDragFloatingPane and self._action_window:
 
8124
            self._action_window.SetFocus()
 
8125
 
 
8126
        if self._hint_fadeamt != self._hint_fademax: #  Only fade if we need to
 
8127
            # start fade in timer
 
8128
            self._hint_fadetimer.Start(5)
 
8129
 
 
8130
        self._last_hint = wx.Rect(*rect)
 
8131
 
 
8132
 
 
8133
    def HideHint(self):
 
8134
        """ Hides a transparent window hint if there is one. """
 
8135
 
 
8136
        # hides a transparent window hint if there is one
 
8137
        if self._hint_window:
 
8138
            self._hint_window.Hide()
 
8139
 
 
8140
        self._hint_fadetimer.Stop()
 
8141
        self._last_hint = wx.Rect()
 
8142
 
 
8143
 
 
8144
    def IsPaneButtonVisible(self, part):
 
8145
        """
 
8146
        Returns whether a pane button in the pane caption is visible.
 
8147
 
 
8148
        :param AuiDockUIPart `part`: the UI part to analyze.
 
8149
        """
 
8150
 
 
8151
        captionRect = wx.Rect()
 
8152
 
 
8153
        for temp_part in self._uiparts:
 
8154
            if temp_part.pane == part.pane and \
 
8155
               temp_part.type == AuiDockUIPart.typeCaption:
 
8156
                captionRect = temp_part.rect
 
8157
                break
 
8158
 
 
8159
        return captionRect.ContainsRect(part.rect)
 
8160
 
 
8161
 
 
8162
    def DrawPaneButton(self, dc, part, pt):
 
8163
        """
 
8164
        Draws a pane button in the caption (convenience function).
 
8165
 
 
8166
        :param `dc`: a :class:`DC` device context object;
 
8167
        :param AuiDockUIPart `part`: the UI part to analyze;
 
8168
        :param Point `pt`: the mouse location.
 
8169
        """
 
8170
 
 
8171
        if not self.IsPaneButtonVisible(part):
 
8172
            return
 
8173
 
 
8174
        state = AUI_BUTTON_STATE_NORMAL
 
8175
 
 
8176
        if part.rect.Contains(pt):
 
8177
 
 
8178
            if _VERSION_STRING < "2.9":
 
8179
                leftDown = wx.GetMouseState().LeftDown()
 
8180
            else:
 
8181
                leftDown = wx.GetMouseState().LeftIsDown()
 
8182
 
 
8183
            if leftDown:
 
8184
                state = AUI_BUTTON_STATE_PRESSED
 
8185
            else:
 
8186
                state = AUI_BUTTON_STATE_HOVER
 
8187
 
 
8188
        self._art.DrawPaneButton(dc, self._frame, part.button.button_id,
 
8189
                                 state, part.rect, part.pane)
 
8190
 
 
8191
 
 
8192
    def RefreshButton(self, part):
 
8193
        """
 
8194
        Refreshes a pane button in the caption.
 
8195
 
 
8196
        :param AuiDockUIPart `part`: the UI part to analyze.
 
8197
        """
 
8198
 
 
8199
        rect = wx.Rect(*part.rect)
 
8200
        rect.Inflate(2, 2)
 
8201
        self._frame.Refresh(True, rect)
 
8202
        self._frame.Update()
 
8203
 
 
8204
 
 
8205
    def RefreshCaptions(self):
 
8206
        """ Refreshes all pane captions. """
 
8207
 
 
8208
        for part in self._uiparts:
 
8209
            if part.type == AuiDockUIPart.typeCaption:
 
8210
                self._frame.Refresh(True, part.rect)
 
8211
                self._frame.Update()
 
8212
 
 
8213
 
 
8214
    def CalculateHintRect(self, pane_window, pt, offset):
 
8215
        """
 
8216
        Calculates the drop hint rectangle.
 
8217
 
 
8218
        The method first calls :meth:`DoDrop` to determine the exact position the pane would
 
8219
        be at were if dropped. If the pane would indeed become docked at the
 
8220
        specified drop point, the the rectangle hint will be returned in
 
8221
        screen coordinates. Otherwise, an empty rectangle is returned.
 
8222
 
 
8223
        :param Window `pane_window`: it is the window pointer of the pane being dragged;
 
8224
        :param Point `pt`: is the mouse position, in client coordinates;
 
8225
        :param Point `offset`: describes the offset that the mouse is from the upper-left
 
8226
         corner of the item being dragged.
 
8227
        """
 
8228
 
 
8229
        # we need to paint a hint rectangle to find out the exact hint rectangle,
 
8230
        # we will create a new temporary layout and then measure the resulting
 
8231
        # rectangle we will create a copy of the docking structures (self._docks)
 
8232
        # so that we don't modify the real thing on screen
 
8233
 
 
8234
        rect = wx.Rect()
 
8235
        pane = self.GetPane(pane_window)
 
8236
 
 
8237
        attrs = self.GetAttributes(pane)
 
8238
        hint = AuiPaneInfo()
 
8239
        hint = self.SetAttributes(hint, attrs)
 
8240
 
 
8241
        if hint.name != "__HINT__":
 
8242
            self._oldname = hint.name
 
8243
 
 
8244
        hint.name = "__HINT__"
 
8245
        hint.PaneBorder(True)
 
8246
        hint.Show()
 
8247
 
 
8248
        if not hint.IsOk():
 
8249
            hint.name = self._oldname
 
8250
            return rect
 
8251
 
 
8252
        docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
 
8253
 
 
8254
        # remove any pane already there which bears the same window
 
8255
        # this happens when you are moving a pane around in a dock
 
8256
        for ii in xrange(len(panes)):
 
8257
            if panes[ii].window == pane_window:
 
8258
                docks = RemovePaneFromDocks(docks, panes[ii])
 
8259
                panes.pop(ii)
 
8260
                break
 
8261
 
 
8262
        # find out where the new pane would be
 
8263
        allow, hint = self.DoDrop(docks, panes, hint, pt, offset)
 
8264
 
 
8265
        if not allow:
 
8266
            return rect
 
8267
 
 
8268
        panes.append(hint)
 
8269
 
 
8270
        sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
 
8271
 
 
8272
        client_size = self._frame.GetClientSize()
 
8273
        sizer.SetDimension(0, 0, client_size.x, client_size.y)
 
8274
        sizer.Layout()
 
8275
 
 
8276
        sought = "__HINT__"
 
8277
 
 
8278
        # For a notebook page, actually look for the notebook itself.
 
8279
        if hint.IsNotebookPage():
 
8280
            id = hint.notebook_id
 
8281
            for pane in panes:
 
8282
                if pane.IsNotebookControl() and pane.notebook_id==id:
 
8283
                    sought = pane.name
 
8284
                    break
 
8285
 
 
8286
        for part in uiparts:
 
8287
            if part.pane and part.pane.name == sought:
 
8288
                rect.Union(wx.RectPS(part.sizer_item.GetPosition(),
 
8289
                                     part.sizer_item.GetSize()))
 
8290
 
 
8291
        sizer.Destroy()
 
8292
 
 
8293
        # check for floating frame ...
 
8294
        if rect.IsEmpty():
 
8295
            for p in panes:
 
8296
                if p.name == sought and p.IsFloating():
 
8297
                    return wx.RectPS(p.floating_pos, p.floating_size)
 
8298
 
 
8299
        if rect.IsEmpty():
 
8300
            return rect
 
8301
 
 
8302
        # actually show the hint rectangle on the screen
 
8303
        rect.x, rect.y = self._frame.ClientToScreen((rect.x, rect.y))
 
8304
        if self._frame.GetLayoutDirection() == wx.Layout_RightToLeft:
 
8305
            # Mirror rectangle in RTL mode
 
8306
            rect.x -= rect.GetWidth()
 
8307
 
 
8308
        return rect
 
8309
 
 
8310
 
 
8311
    def DrawHintRect(self, pane_window, pt, offset):
 
8312
        """
 
8313
        Calculates the hint rectangle by calling :meth:`CalculateHintRect`. If there is a
 
8314
        rectangle, it shows it by calling :meth:`ShowHint`, otherwise it hides any hint
 
8315
        rectangle currently shown.
 
8316
 
 
8317
        :param Window `pane_window`: it is the window pointer of the pane being dragged;
 
8318
        :param Point `pt`: is the mouse position, in client coordinates;
 
8319
        :param Point `offset`: describes the offset that the mouse is from the upper-left
 
8320
         corner of the item being dragged.
 
8321
        """
 
8322
 
 
8323
        rect = self.CalculateHintRect(pane_window, pt, offset)
 
8324
 
 
8325
        if rect.IsEmpty():
 
8326
            self.HideHint()
 
8327
            self._hint_rect = wx.Rect()
 
8328
        else:
 
8329
            self.ShowHint(rect)
 
8330
            self._hint_rect = wx.Rect(*rect)
 
8331
 
 
8332
 
 
8333
    def GetPartSizerRect(self, uiparts):
 
8334
        """
 
8335
        Returns the rectangle surrounding the specified UI parts.
 
8336
 
 
8337
        :param list `uiparts`: list of :class:`AuiDockUIPart` parts.
 
8338
        """
 
8339
 
 
8340
        rect = wx.Rect()
 
8341
 
 
8342
        for part in self._uiparts:
 
8343
            if part.pane and part.pane.name == "__HINT__":
 
8344
                rect.Union(wx.RectPS(part.sizer_item.GetPosition(),
 
8345
                                     part.sizer_item.GetSize()))
 
8346
 
 
8347
        return rect
 
8348
 
 
8349
 
 
8350
    def GetAttributes(self, pane):
 
8351
        """
 
8352
        Returns all the attributes of a :class:`AuiPaneInfo`.
 
8353
 
 
8354
        :param `pane`: a :class:`AuiPaneInfo` instance.
 
8355
        """
 
8356
 
 
8357
        attrs = []
 
8358
        attrs.extend([pane.window, pane.frame, pane.state, pane.dock_direction,
 
8359
                      pane.dock_layer, pane.dock_pos, pane.dock_row, pane.dock_proportion,
 
8360
                      pane.floating_pos, pane.floating_size, pane.best_size,
 
8361
                      pane.min_size, pane.max_size, pane.caption, pane.name,
 
8362
                      pane.buttons, pane.rect, pane.icon, pane.notebook_id,
 
8363
                      pane.transparent, pane.snapped, pane.minimize_mode, pane.minimize_target])
 
8364
 
 
8365
        return attrs
 
8366
 
 
8367
 
 
8368
    def SetAttributes(self, pane, attrs):
 
8369
        """
 
8370
        Sets all the attributes contained in `attrs` to a :class:`AuiPaneInfo`.
 
8371
 
 
8372
        :param `pane`: a :class:`AuiPaneInfo` instance;
 
8373
        :param list `attrs`: a list of attributes.
 
8374
        """
 
8375
 
 
8376
        pane.window = attrs[0]
 
8377
        pane.frame = attrs[1]
 
8378
        pane.state = attrs[2]
 
8379
        pane.dock_direction = attrs[3]
 
8380
        pane.dock_layer = attrs[4]
 
8381
        pane.dock_pos = attrs[5]
 
8382
        pane.dock_row = attrs[6]
 
8383
        pane.dock_proportion = attrs[7]
 
8384
        pane.floating_pos = attrs[8]
 
8385
        pane.floating_size = attrs[9]
 
8386
        pane.best_size = attrs[10]
 
8387
        pane.min_size = attrs[11]
 
8388
        pane.max_size = attrs[12]
 
8389
        pane.caption = attrs[13]
 
8390
        pane.name = attrs[14]
 
8391
        pane.buttons = attrs[15]
 
8392
        pane.rect = attrs[16]
 
8393
        pane.icon = attrs[17]
 
8394
        pane.notebook_id = attrs[18]
 
8395
        pane.transparent = attrs[19]
 
8396
        pane.snapped = attrs[20]
 
8397
        pane.minimize_mode = attrs[21]
 
8398
        pane.minimize_target = attrs[22]
 
8399
 
 
8400
        return pane
 
8401
 
 
8402
 
 
8403
    def OnFloatingPaneResized(self, wnd, size):
 
8404
        """
 
8405
        Handles the resizing of a floating pane.
 
8406
 
 
8407
        :param Window `wnd`: the window managed by the pane;
 
8408
        :param Size `size`: the new pane floating size.
 
8409
        """
 
8410
 
 
8411
        # try to find the pane
 
8412
        pane = self.GetPane(wnd)
 
8413
        if not pane.IsOk():
 
8414
            raise Exception("Pane window not found")
 
8415
 
 
8416
        if pane.frame:
 
8417
            indx = self._panes.index(pane)
 
8418
            pane.floating_pos = pane.frame.GetPosition()
 
8419
            pane.floating_size = size
 
8420
            self._panes[indx] = pane
 
8421
            if pane.IsSnappable():
 
8422
                self.SnapPane(pane, pane.floating_pos, pane.floating_size, True)
 
8423
 
 
8424
 
 
8425
    def OnFloatingPaneClosed(self, wnd, event):
 
8426
        """
 
8427
        Handles the close event of a floating pane.
 
8428
 
 
8429
        :param Window `wnd`: the window managed by the pane;
 
8430
        :param `event`: a :class:`CloseEvent` to be processed.
 
8431
        """
 
8432
 
 
8433
        # try to find the pane
 
8434
        pane = self.GetPane(wnd)
 
8435
        if not pane.IsOk():
 
8436
            raise Exception("Pane window not found")
 
8437
 
 
8438
        # fire pane close event
 
8439
        e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
 
8440
        e.SetPane(pane)
 
8441
        e.SetCanVeto(event.CanVeto())
 
8442
        self.ProcessMgrEvent(e)
 
8443
 
 
8444
        if e.GetVeto():
 
8445
            event.Veto()
 
8446
            return
 
8447
        else:
 
8448
            # close the pane, but check that it
 
8449
            # still exists in our pane array first
 
8450
            # (the event handler above might have removed it)
 
8451
 
 
8452
            check = self.GetPane(wnd)
 
8453
            if check.IsOk():
 
8454
                self.ClosePane(pane)
 
8455
 
 
8456
 
 
8457
    def OnFloatingPaneActivated(self, wnd):
 
8458
        """
 
8459
        Handles the activation event of a floating pane.
 
8460
 
 
8461
        :param Window `wnd`: the window managed by the pane.
 
8462
        """
 
8463
 
 
8464
        pane = self.GetPane(wnd)
 
8465
        if not pane.IsOk():
 
8466
            raise Exception("Pane window not found")
 
8467
 
 
8468
        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
 
8469
            ret, self._panes = SetActivePane(self._panes, wnd)
 
8470
            self.RefreshCaptions()
 
8471
            self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, wnd, canVeto=False)
 
8472
 
 
8473
 
 
8474
    def OnFloatingPaneMoved(self, wnd, eventOrPt):
 
8475
        """
 
8476
        Handles the move event of a floating pane.
 
8477
 
 
8478
        :param Window `wnd`: the window managed by the pane;
 
8479
        :param `eventOrPt`: a :class:`MoveEvent` to be processed or an instance of :class:`Point`.
 
8480
        """
 
8481
 
 
8482
        pane = self.GetPane(wnd)
 
8483
        if not pane.IsOk():
 
8484
            raise Exception("Pane window not found")
 
8485
 
 
8486
        if not pane.IsSnappable():
 
8487
            return
 
8488
 
 
8489
        if isinstance(eventOrPt, wx.Point):
 
8490
            pane_pos = wx.Point(*eventOrPt)
 
8491
        else:
 
8492
            pane_pos = eventOrPt.GetPosition()
 
8493
 
 
8494
        pane_size = pane.floating_size
 
8495
 
 
8496
        self.SnapPane(pane, pane_pos, pane_size, False)
 
8497
 
 
8498
 
 
8499
    def SnapPane(self, pane, pane_pos, pane_size, toSnap=False):
 
8500
        """
 
8501
        Snaps a floating pane to one of the main frame sides.
 
8502
 
 
8503
        :param `pane`: a :class:`AuiPaneInfo` instance;
 
8504
        :param Point `pane_pos`: the new pane floating position;
 
8505
        :param Size `pane_size`: the new pane floating size;
 
8506
        :param bool `toSnap`: a bool variable to check if :meth:`SnapPane` was called from
 
8507
         a move event.
 
8508
        """
 
8509
 
 
8510
        if self._from_move:
 
8511
            return
 
8512
 
 
8513
        managed_window = self.GetManagedWindow()
 
8514
        wnd_pos = managed_window.GetPosition()
 
8515
        wnd_size = managed_window.GetSize()
 
8516
        snapX, snapY = self._snap_limits
 
8517
 
 
8518
        if not toSnap:
 
8519
            pane.snapped = 0
 
8520
            if pane.IsLeftSnappable():
 
8521
                # Check if we can snap to the left
 
8522
                diff = wnd_pos.x - (pane_pos.x + pane_size.x)
 
8523
                if -snapX <= diff <= snapX:
 
8524
                    pane.snapped = wx.LEFT
 
8525
                    pane.floating_pos = wx.Point(wnd_pos.x-pane_size.x, pane_pos.y)
 
8526
            elif pane.IsTopSnappable():
 
8527
                # Check if we can snap to the top
 
8528
                diff = wnd_pos.y - (pane_pos.y + pane_size.y)
 
8529
                if -snapY <= diff <= snapY:
 
8530
                    pane.snapped = wx.TOP
 
8531
                    pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y-pane_size.y)
 
8532
            elif pane.IsRightSnappable():
 
8533
                # Check if we can snap to the right
 
8534
                diff = pane_pos.x - (wnd_pos.x + wnd_size.x)
 
8535
                if -snapX <= diff <= snapX:
 
8536
                    pane.snapped = wx.RIGHT
 
8537
                    pane.floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y)
 
8538
            elif pane.IsBottomSnappable():
 
8539
                # Check if we can snap to the bottom
 
8540
                diff = pane_pos.y - (wnd_pos.y + wnd_size.y)
 
8541
                if -snapY <= diff <= snapY:
 
8542
                    pane.snapped = wx.BOTTOM
 
8543
                    pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y)
 
8544
 
 
8545
        self.RepositionPane(pane, wnd_pos, wnd_size)
 
8546
 
 
8547
 
 
8548
    def RepositionPane(self, pane, wnd_pos, wnd_size):
 
8549
        """
 
8550
        Repositions a pane after the main frame has been moved/resized.
 
8551
 
 
8552
        :param `pane`: a :class:`AuiPaneInfo` instance;
 
8553
        :param Point `wnd_pos`: the main frame position;
 
8554
        :param Size `wnd_size`: the main frame size.
 
8555
        """
 
8556
 
 
8557
        pane_pos = pane.floating_pos
 
8558
        pane_size = pane.floating_size
 
8559
 
 
8560
        snap = pane.snapped
 
8561
        if snap == wx.LEFT:
 
8562
            floating_pos = wx.Point(wnd_pos.x - pane_size.x, pane_pos.y)
 
8563
        elif snap == wx.TOP:
 
8564
            floating_pos = wx.Point(pane_pos.x, wnd_pos.y - pane_size.y)
 
8565
        elif snap == wx.RIGHT:
 
8566
            floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y)
 
8567
        elif snap == wx.BOTTOM:
 
8568
            floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y)
 
8569
 
 
8570
        if snap:
 
8571
            if pane_pos != floating_pos:
 
8572
                pane.floating_pos = floating_pos
 
8573
                self._from_move = True
 
8574
                pane.frame.SetPosition(pane.floating_pos)
 
8575
                self._from_move = False
 
8576
 
 
8577
 
 
8578
    def OnGripperClicked(self, pane_window, start, offset):
 
8579
        """
 
8580
        Handles the mouse click on the pane gripper.
 
8581
 
 
8582
        :param Window `pane_window`: the window managed by the pane;
 
8583
        :param Point `start`: the mouse-click position;
 
8584
        :param Point `offset`: an offset point from the `start` position.
 
8585
        """
 
8586
 
 
8587
        # try to find the pane
 
8588
        paneInfo = self.GetPane(pane_window)
 
8589
 
 
8590
        if not paneInfo.IsOk():
 
8591
            raise Exception("Pane window not found")
 
8592
 
 
8593
        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
 
8594
            # set the caption as active
 
8595
            ret, self._panes = SetActivePane(self._panes, pane_window)
 
8596
            self.RefreshCaptions()
 
8597
            self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, pane_window, canVeto=False)
 
8598
 
 
8599
        self._action_part = None
 
8600
        self._action_pane = paneInfo
 
8601
        self._action_window = pane_window
 
8602
        self._action_start = start
 
8603
        self._action_offset = offset
 
8604
        self._toolbar_action_offset = wx.Point(*self._action_offset)
 
8605
 
 
8606
        self._frame.CaptureMouse()
 
8607
 
 
8608
        if paneInfo.IsDocked():
 
8609
            self._action = actionClickCaption
 
8610
        else:
 
8611
            if paneInfo.IsToolbar():
 
8612
                self._action = actionDragToolbarPane
 
8613
            else:
 
8614
                self._action = actionDragFloatingPane
 
8615
 
 
8616
            if paneInfo.frame:
 
8617
 
 
8618
                windowPt = paneInfo.frame.GetRect().GetTopLeft()
 
8619
                originPt = paneInfo.frame.ClientToScreen(wx.Point())
 
8620
                self._action_offset += originPt - windowPt
 
8621
                self._toolbar_action_offset = wx.Point(*self._action_offset)
 
8622
 
 
8623
                if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
 
8624
                    paneInfo.frame.SetTransparent(150)
 
8625
 
 
8626
            if paneInfo.IsToolbar():
 
8627
                self._frame.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
 
8628
 
 
8629
 
 
8630
    def OnRender(self, event):
 
8631
        """
 
8632
        Draws all of the pane captions, sashes, backgrounds, captions, grippers, pane borders and buttons.
 
8633
        It renders the entire user interface. It binds the ``EVT_AUI_RENDER`` event.
 
8634
 
 
8635
        :param `event`: an instance of :class:`AuiManagerEvent`.
 
8636
        """
 
8637
 
 
8638
        # if the frame is about to be deleted, don't bother
 
8639
        if not self._frame or self._frame.IsBeingDeleted():
 
8640
            return
 
8641
 
 
8642
        if not self._frame.GetSizer():
 
8643
            return
 
8644
 
 
8645
        mouse = wx.GetMouseState()
 
8646
        mousePos = wx.Point(mouse.GetX(), mouse.GetY())
 
8647
        point = self._frame.ScreenToClient(mousePos)
 
8648
        art = self._art
 
8649
 
 
8650
        dc = event.GetDC()
 
8651
 
 
8652
        for part in self._uiparts:
 
8653
 
 
8654
            # don't draw hidden pane items or items that aren't windows
 
8655
            if part.sizer_item and ((not part.sizer_item.IsWindow() and \
 
8656
                                     not part.sizer_item.IsSpacer() and \
 
8657
                                     not part.sizer_item.IsSizer()) or \
 
8658
                                    not part.sizer_item.IsShown()):
 
8659
 
 
8660
                continue
 
8661
 
 
8662
            ptype = part.type
 
8663
 
 
8664
            if ptype in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
 
8665
                art.DrawSash(dc, self._frame, part.orientation, part.rect)
 
8666
 
 
8667
            elif ptype == AuiDockUIPart.typeBackground:
 
8668
                art.DrawBackground(dc, self._frame, part.orientation, part.rect)
 
8669
 
 
8670
            elif ptype == AuiDockUIPart.typeCaption:
 
8671
                art.DrawCaption(dc, self._frame, part.pane.caption, part.rect, part.pane)
 
8672
 
 
8673
            elif ptype == AuiDockUIPart.typeGripper:
 
8674
                art.DrawGripper(dc, self._frame, part.rect, part.pane)
 
8675
 
 
8676
            elif ptype == AuiDockUIPart.typePaneBorder:
 
8677
                art.DrawBorder(dc, self._frame, part.rect, part.pane)
 
8678
 
 
8679
            elif ptype == AuiDockUIPart.typePaneButton:
 
8680
                self.DrawPaneButton(dc, part, point)
 
8681
 
 
8682
 
 
8683
    def Repaint(self, dc=None):
 
8684
        """
 
8685
        Repaints the entire frame decorations (sashes, borders, buttons and so on).
 
8686
        It renders the entire user interface.
 
8687
 
 
8688
        :param `dc`: if not ``None``, an instance of :class:`PaintDC`.
 
8689
        """
 
8690
 
 
8691
        w, h = self._frame.GetClientSize()
 
8692
 
 
8693
        # Figure out which dc to use; if one
 
8694
        # has been specified, use it, otherwise
 
8695
        # make a client dc
 
8696
        if dc is None:
 
8697
            client_dc = wx.ClientDC(self._frame)
 
8698
            dc = client_dc
 
8699
 
 
8700
        # If the frame has a toolbar, the client area
 
8701
        # origin will not be (0, 0).
 
8702
        pt = self._frame.GetClientAreaOrigin()
 
8703
        if pt.x != 0 or pt.y != 0:
 
8704
            dc.SetDeviceOrigin(pt.x, pt.y)
 
8705
 
 
8706
        # Render all the items
 
8707
        self.Render(dc)
 
8708
 
 
8709
 
 
8710
    def Render(self, dc):
 
8711
        """
 
8712
        Fires a render event, which is normally handled by :meth:`OnRender`. This allows the
 
8713
        render function to be overridden via the render event.
 
8714
 
 
8715
        This can be useful for painting custom graphics in the main window.
 
8716
        Default behavior can be invoked in the overridden function by calling
 
8717
        :meth:`OnRender`.
 
8718
 
 
8719
        :param `dc`: a :class:`DC` device context object.
 
8720
        """
 
8721
 
 
8722
        e = AuiManagerEvent(wxEVT_AUI_RENDER)
 
8723
        e.SetManager(self)
 
8724
        e.SetDC(dc)
 
8725
        self.ProcessMgrEvent(e)
 
8726
 
 
8727
 
 
8728
    def OnCaptionDoubleClicked(self, pane_window):
 
8729
        """
 
8730
        Handles the mouse double click on the pane caption.
 
8731
 
 
8732
        :param Window `pane_window`: the window managed by the pane.
 
8733
        """
 
8734
 
 
8735
        # try to find the pane
 
8736
        paneInfo = self.GetPane(pane_window)
 
8737
        if not paneInfo.IsOk():
 
8738
            raise Exception("Pane window not found")
 
8739
 
 
8740
        if not paneInfo.IsFloatable() or not paneInfo.IsDockable() or \
 
8741
           self._agwFlags & AUI_MGR_ALLOW_FLOATING == 0:
 
8742
            return
 
8743
 
 
8744
        indx = self._panes.index(paneInfo)
 
8745
        win_rect = None
 
8746
 
 
8747
        if paneInfo.IsFloating():
 
8748
            if paneInfo.name.startswith("__floating__"):
 
8749
                # It's a floating tab from a AuiNotebook
 
8750
                notebook = paneInfo.window.__aui_notebook__
 
8751
                notebook.ReDockPage(paneInfo)
 
8752
                self.Update()
 
8753
                return
 
8754
            else:
 
8755
 
 
8756
                e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
 
8757
                if e.GetVeto():
 
8758
                    self.HideHint()
 
8759
                    ShowDockingGuides(self._guides, False)
 
8760
                    return
 
8761
 
 
8762
                win_rect = paneInfo.frame.GetRect()
 
8763
                paneInfo.Dock()
 
8764
                if paneInfo.IsToolbar():
 
8765
                    paneInfo = self.SwitchToolBarOrientation(paneInfo)
 
8766
 
 
8767
                e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
 
8768
 
 
8769
        else:
 
8770
 
 
8771
            e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, paneInfo, canVeto=True)
 
8772
            if e.GetVeto():
 
8773
                return
 
8774
 
 
8775
            # float the window
 
8776
            if paneInfo.IsMaximized():
 
8777
                self.RestorePane(paneInfo)
 
8778
 
 
8779
            if paneInfo.floating_pos == wx.Point(-1, -1):
 
8780
                captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
 
8781
                paneInfo.floating_pos = pane_window.GetScreenPosition()
 
8782
                paneInfo.floating_pos.y -= captionSize
 
8783
 
 
8784
            paneInfo.Float()
 
8785
            e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, paneInfo, canVeto=False)
 
8786
 
 
8787
        self._panes[indx] = paneInfo
 
8788
        self.Update()
 
8789
 
 
8790
        if win_rect and self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
 
8791
            paneInfo = self.GetPane(pane_window)
 
8792
            pane_rect = paneInfo.window.GetScreenRect()
 
8793
            self.AnimateDocking(win_rect, pane_rect)
 
8794
 
 
8795
 
 
8796
    def OnPaint(self, event):
 
8797
        """
 
8798
        Handles the ``wx.EVT_PAINT`` event for :class:`AuiManager`.
 
8799
 
 
8800
        :param `event`: an instance of :class:`PaintEvent` to be processed.
 
8801
        """
 
8802
 
 
8803
        dc = wx.PaintDC(self._frame)
 
8804
        self.Repaint(dc)
 
8805
 
 
8806
 
 
8807
    def OnEraseBackground(self, event):
 
8808
        """
 
8809
        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiManager`.
 
8810
 
 
8811
        :param `event`: :class:`EraseEvent` to be processed.
 
8812
 
 
8813
        :note: This is intentionally empty (excluding wxMAC) to reduce
 
8814
         flickering while drawing.
 
8815
        """
 
8816
 
 
8817
        if wx.Platform == "__WXMAC__":
 
8818
            event.Skip()
 
8819
 
 
8820
 
 
8821
    def OnSize(self, event):
 
8822
        """
 
8823
        Handles the ``wx.EVT_SIZE`` event for :class:`AuiManager`.
 
8824
 
 
8825
        :param `event`: a :class:`SizeEvent` to be processed.
 
8826
        """
 
8827
 
 
8828
        skipped = False
 
8829
        if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
 
8830
            skipped = True
 
8831
            event.Skip()
 
8832
 
 
8833
        if self._frame:
 
8834
 
 
8835
            self.DoFrameLayout()
 
8836
            if wx.Platform == "__WXMAC__":
 
8837
                self._frame.Refresh()
 
8838
            else:
 
8839
                self.Repaint()
 
8840
 
 
8841
            if isinstance(self._frame, wx.MDIParentFrame) or isinstance(self._frame, tabmdi.AuiMDIClientWindow) \
 
8842
               or isinstance(self._frame, tabmdi.AuiMDIParentFrame):
 
8843
                # for MDI parent frames, this event must not
 
8844
                # be "skipped".  In other words, the parent frame
 
8845
                # must not be allowed to resize the client window
 
8846
                # after we are finished processing sizing changes
 
8847
                return
 
8848
 
 
8849
        if not skipped:
 
8850
            event.Skip()
 
8851
 
 
8852
        # For the snap to screen...
 
8853
        self.OnMove(None)
 
8854
 
 
8855
 
 
8856
    def OnFindManager(self, event):
 
8857
        """
 
8858
        Handles the ``EVT_AUI_FIND_MANAGER`` event for :class:`AuiManager`.
 
8859
 
 
8860
        :param `event`: a :class:`AuiManagerEvent` event to be processed.
 
8861
        """
 
8862
 
 
8863
        # Initialize to None
 
8864
        event.SetManager(None)
 
8865
 
 
8866
        if not self._frame:
 
8867
            return
 
8868
 
 
8869
        # See it this window wants to overwrite
 
8870
        self._frame.ProcessEvent(event)
 
8871
 
 
8872
        # if no, it must be us
 
8873
        if not event.GetManager():
 
8874
           event.SetManager(self)
 
8875
 
 
8876
 
 
8877
    def OnSetCursor(self, event):
 
8878
        """
 
8879
        Handles the ``wx.EVT_SET_CURSOR`` event for :class:`AuiManager`.
 
8880
 
 
8881
        :param `event`: a :class:`SetCursorEvent` to be processed.
 
8882
        """
 
8883
 
 
8884
        # determine cursor
 
8885
        part = self.HitTest(event.GetX(), event.GetY())
 
8886
        cursor = wx.NullCursor
 
8887
 
 
8888
        if part:
 
8889
            if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
 
8890
 
 
8891
                if not self.CheckMovableSizer(part):
 
8892
                    return
 
8893
 
 
8894
                if part.orientation == wx.VERTICAL:
 
8895
                    cursor = wx.StockCursor(wx.CURSOR_SIZEWE)
 
8896
                else:
 
8897
                    cursor = wx.StockCursor(wx.CURSOR_SIZENS)
 
8898
 
 
8899
            elif part.type == AuiDockUIPart.typeGripper:
 
8900
                cursor = wx.StockCursor(wx.CURSOR_SIZING)
 
8901
 
 
8902
        event.SetCursor(cursor)
 
8903
 
 
8904
 
 
8905
    def UpdateButtonOnScreen(self, button_ui_part, event):
 
8906
        """
 
8907
        Updates/redraws the UI part containing a pane button.
 
8908
 
 
8909
        :param AuiDockUIPart `button_ui_part`: the UI part the button belongs to;
 
8910
        :param `event`: a :class:`MouseEvent` to be processed.
 
8911
        """
 
8912
 
 
8913
        hit_test = self.HitTest(*event.GetPosition())
 
8914
 
 
8915
        if not hit_test or not button_ui_part:
 
8916
            return
 
8917
 
 
8918
        state = AUI_BUTTON_STATE_NORMAL
 
8919
 
 
8920
        if hit_test == button_ui_part:
 
8921
            if event.LeftDown():
 
8922
                state = AUI_BUTTON_STATE_PRESSED
 
8923
            else:
 
8924
                state = AUI_BUTTON_STATE_HOVER
 
8925
        else:
 
8926
            if event.LeftDown():
 
8927
                state = AUI_BUTTON_STATE_HOVER
 
8928
 
 
8929
        # now repaint the button with hover state
 
8930
        cdc = wx.ClientDC(self._frame)
 
8931
 
 
8932
        # if the frame has a toolbar, the client area
 
8933
        # origin will not be (0,0).
 
8934
        pt = self._frame.GetClientAreaOrigin()
 
8935
        if pt.x != 0 or pt.y != 0:
 
8936
            cdc.SetDeviceOrigin(pt.x, pt.y)
 
8937
 
 
8938
        if hit_test.pane:
 
8939
            self._art.DrawPaneButton(cdc, self._frame,
 
8940
                      button_ui_part.button.button_id,
 
8941
                      state,
 
8942
                      button_ui_part.rect, hit_test.pane)
 
8943
 
 
8944
 
 
8945
    def OnLeftDown(self, event):
 
8946
        """
 
8947
        Handles the ``wx.EVT_LEFT_DOWN`` event for :class:`AuiManager`.
 
8948
 
 
8949
        :param `event`: a :class:`MouseEvent` to be processed.
 
8950
        """
 
8951
 
 
8952
        part = self.HitTest(*event.GetPosition())
 
8953
 
 
8954
        if not part:
 
8955
            event.Skip()
 
8956
            return
 
8957
 
 
8958
        self._currentDragItem = -1
 
8959
 
 
8960
        if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
 
8961
 
 
8962
            if not self.CheckMovableSizer(part):
 
8963
                return
 
8964
 
 
8965
            self._action = actionResize
 
8966
            self._action_part = part
 
8967
            self._action_pane = None
 
8968
            self._action_rect = wx.Rect()
 
8969
            self._action_start = wx.Point(event.GetX(), event.GetY())
 
8970
            self._action_offset = wx.Point(event.GetX() - part.rect.x,
 
8971
                                           event.GetY() - part.rect.y)
 
8972
 
 
8973
            # draw the resize hint
 
8974
            rect = wx.RectPS(self._frame.ClientToScreen(part.rect.GetPosition()),
 
8975
                             part.rect.GetSize())
 
8976
 
 
8977
            self._action_rect = wx.Rect(*rect)
 
8978
 
 
8979
            if not AuiManager_HasLiveResize(self):
 
8980
                if wx.Platform == "__WXMAC__":
 
8981
                    dc = wx.ClientDC(self._frame)
 
8982
                else:
 
8983
                    dc = wx.ScreenDC()
 
8984
 
 
8985
                DrawResizeHint(dc, rect)
 
8986
 
 
8987
            self._frame.CaptureMouse()
 
8988
 
 
8989
        elif part.type == AuiDockUIPart.typePaneButton:
 
8990
            if self.IsPaneButtonVisible(part):
 
8991
                self._action = actionClickButton
 
8992
                self._action_part = part
 
8993
                self._action_pane = None
 
8994
                self._action_start = wx.Point(*event.GetPosition())
 
8995
                self._frame.CaptureMouse()
 
8996
 
 
8997
                self.RefreshButton(part)
 
8998
 
 
8999
        elif part.type in [AuiDockUIPart.typeCaption, AuiDockUIPart.typeGripper]:
 
9000
 
 
9001
            # if we are managing a AuiFloatingFrame window, then
 
9002
            # we are an embedded AuiManager inside the AuiFloatingFrame.
 
9003
            # We want to initiate a toolbar drag in our owner manager
 
9004
            if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
 
9005
                rootManager = GetManager(part.pane.window)
 
9006
            else:
 
9007
                rootManager = self
 
9008
 
 
9009
            offset = wx.Point(event.GetX() - part.rect.x, event.GetY() - part.rect.y)
 
9010
            rootManager.OnGripperClicked(part.pane.window, event.GetPosition(), offset)
 
9011
 
 
9012
        if wx.Platform != "__WXMAC__":
 
9013
            event.Skip()
 
9014
 
 
9015
 
 
9016
    def OnLeftDClick(self, event):
 
9017
        """
 
9018
        Handles the ``wx.EVT_LEFT_DCLICK`` event for :class:`AuiManager`.
 
9019
 
 
9020
        :param `event`: a :class:`MouseEvent` to be processed.
 
9021
        """
 
9022
 
 
9023
        part = self.HitTest(event.GetX(), event.GetY())
 
9024
 
 
9025
        if part and part.type == AuiDockUIPart.typeCaption:
 
9026
            if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
 
9027
                rootManager = GetManager(part.pane.window)
 
9028
            else:
 
9029
                rootManager = self
 
9030
 
 
9031
            rootManager.OnCaptionDoubleClicked(part.pane.window)
 
9032
 
 
9033
        elif part and part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
 
9034
            # Handles double click on AuiNotebook sashes to unsplit
 
9035
            sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
9036
            for child in part.cont_sizer.GetChildren():
 
9037
                if child.IsSizer():
 
9038
                    win = child.GetSizer().GetContainingWindow()
 
9039
                    if isinstance(win, auibook.AuiNotebook):
 
9040
                        win.UnsplitDClick(part, sash_size, event.GetPosition())
 
9041
                        break
 
9042
 
 
9043
        event.Skip()
 
9044
 
 
9045
 
 
9046
    def DoEndResizeAction(self, event):
 
9047
        """
 
9048
        Ends a resize action, or for live update, resizes the sash.
 
9049
 
 
9050
        :param `event`: a :class:`MouseEvent` to be processed.
 
9051
        """
 
9052
 
 
9053
        clientPt = event.GetPosition()
 
9054
        screenPt = self._frame.ClientToScreen(clientPt)
 
9055
 
 
9056
        return self.RestrictResize(clientPt, screenPt, createDC=False)
 
9057
 
 
9058
 
 
9059
    def RestrictResize(self, clientPt, screenPt, createDC):
 
9060
        """ Common method between :meth:`DoEndResizeAction` and :meth:`OnLeftUp_Resize`. """
 
9061
 
 
9062
        dock = self._action_part.dock
 
9063
        pane = self._action_part.pane
 
9064
 
 
9065
        if createDC:
 
9066
            if wx.Platform == "__WXMAC__":
 
9067
                dc = wx.ClientDC(self._frame)
 
9068
            else:
 
9069
                dc = wx.ScreenDC()
 
9070
 
 
9071
            DrawResizeHint(dc, self._action_rect)
 
9072
            self._action_rect = wx.Rect()
 
9073
 
 
9074
        newPos = clientPt - self._action_offset
 
9075
 
 
9076
        if self._action_part.type == AuiDockUIPart.typeDockSizer:
 
9077
            minPix, maxPix = self.CalculateDockSizerLimits(dock)
 
9078
        else:
 
9079
            if not self._action_part.pane:
 
9080
                return
 
9081
            minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
 
9082
 
 
9083
        if self._action_part.orientation == wx.HORIZONTAL:
 
9084
            newPos.y = Clip(newPos.y, minPix, maxPix)
 
9085
        else:
 
9086
            newPos.x = Clip(newPos.x, minPix, maxPix)
 
9087
 
 
9088
        if self._action_part.type == AuiDockUIPart.typeDockSizer:
 
9089
 
 
9090
            partnerDock = self.GetPartnerDock(dock)
 
9091
            sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
 
9092
            new_dock_size = 0
 
9093
            direction = dock.dock_direction
 
9094
 
 
9095
            if direction == AUI_DOCK_LEFT:
 
9096
                new_dock_size = newPos.x - dock.rect.x
 
9097
 
 
9098
            elif direction == AUI_DOCK_TOP:
 
9099
                new_dock_size = newPos.y - dock.rect.y
 
9100
 
 
9101
            elif direction == AUI_DOCK_RIGHT:
 
9102
                new_dock_size = dock.rect.x + dock.rect.width - newPos.x - sash_size
 
9103
 
 
9104
            elif direction == AUI_DOCK_BOTTOM:
 
9105
                new_dock_size = dock.rect.y + dock.rect.height - newPos.y - sash_size
 
9106
 
 
9107
            deltaDockSize = new_dock_size - dock.size
 
9108
 
 
9109
            if partnerDock:
 
9110
                if deltaDockSize > partnerDock.size - sash_size:
 
9111
                    deltaDockSize = partnerDock.size - sash_size
 
9112
 
 
9113
                partnerDock.size -= deltaDockSize
 
9114
 
 
9115
            dock.size += deltaDockSize
 
9116
            self.Update()
 
9117
 
 
9118
        else:
 
9119
 
 
9120
            # determine the new pixel size that the user wants
 
9121
            # this will help us recalculate the pane's proportion
 
9122
            if dock.IsHorizontal():
 
9123
                oldPixsize = pane.rect.width
 
9124
                newPixsize = oldPixsize + newPos.x - self._action_part.rect.x
 
9125
 
 
9126
            else:
 
9127
                oldPixsize = pane.rect.height
 
9128
                newPixsize = oldPixsize + newPos.y - self._action_part.rect.y
 
9129
 
 
9130
            totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
 
9131
            partnerPane = self.GetPartnerPane(dock, pane)
 
9132
 
 
9133
            # prevent division by zero
 
9134
            if totalPixsize <= 0 or totalProportion <= 0 or not partnerPane:
 
9135
                return
 
9136
 
 
9137
            # adjust for the surplus
 
9138
            while (oldPixsize > 0 and totalPixsize > 10 and \
 
9139
                  oldPixsize*totalProportion/totalPixsize < pane.dock_proportion):
 
9140
 
 
9141
                totalPixsize -= 1
 
9142
 
 
9143
            # calculate the new proportion of the pane
 
9144
 
 
9145
            newProportion = newPixsize*totalProportion/totalPixsize
 
9146
            newProportion = Clip(newProportion, 1, totalProportion)
 
9147
            deltaProp = newProportion - pane.dock_proportion
 
9148
 
 
9149
            if partnerPane.dock_proportion - deltaProp < 1:
 
9150
                deltaProp = partnerPane.dock_proportion - 1
 
9151
                newProportion = pane.dock_proportion + deltaProp
 
9152
 
 
9153
            # borrow the space from our neighbor pane to the
 
9154
            # right or bottom (depending on orientation)
 
9155
            partnerPane.dock_proportion -= deltaProp
 
9156
            pane.dock_proportion = newProportion
 
9157
 
 
9158
            self.Update()
 
9159
 
 
9160
        return True
 
9161
 
 
9162
 
 
9163
    def OnLeftUp(self, event):
 
9164
        """
 
9165
        Handles the ``wx.EVT_LEFT_UP`` event for :class:`AuiManager`.
 
9166
 
 
9167
        :param `event`: a :class:`MouseEvent` to be processed.
 
9168
        """
 
9169
 
 
9170
        if self._action == actionResize:
 
9171
##            self._frame.Freeze()
 
9172
            self.OnLeftUp_Resize(event)
 
9173
##            self._frame.Thaw()
 
9174
 
 
9175
        elif self._action == actionClickButton:
 
9176
            self.OnLeftUp_ClickButton(event)
 
9177
 
 
9178
        elif self._action == actionDragFloatingPane:
 
9179
            self.OnLeftUp_DragFloatingPane(event)
 
9180
 
 
9181
        elif self._action == actionDragToolbarPane:
 
9182
            self.OnLeftUp_DragToolbarPane(event)
 
9183
 
 
9184
        elif self._action == actionDragMovablePane:
 
9185
            self.OnLeftUp_DragMovablePane(event)
 
9186
 
 
9187
        else:
 
9188
            event.Skip()
 
9189
 
 
9190
        try:
 
9191
            if self._frame.HasCapture():
 
9192
                self._frame.ReleaseMouse()
 
9193
        except wx.PyDeadObjectError:
 
9194
            pass
 
9195
 
 
9196
        self._action = actionNone
 
9197
 
 
9198
 
 
9199
    def OnMotion(self, event):
 
9200
        """
 
9201
        Handles the ``wx.EVT_MOTION`` event for :class:`AuiManager`.
 
9202
 
 
9203
        :param `event`: a :class:`MouseEvent` to be processed.
 
9204
        """
 
9205
 
 
9206
        if self._action == actionResize:
 
9207
            self.OnMotion_Resize(event)
 
9208
 
 
9209
        elif self._action == actionClickCaption:
 
9210
            self.OnMotion_ClickCaption(event)
 
9211
 
 
9212
        elif self._action == actionDragFloatingPane:
 
9213
            self.OnMotion_DragFloatingPane(event)
 
9214
 
 
9215
        elif self._action == actionDragToolbarPane:
 
9216
            self.OnMotion_DragToolbarPane(event)
 
9217
 
 
9218
        elif self._action == actionDragMovablePane:
 
9219
            self.OnMotion_DragMovablePane(event)
 
9220
 
 
9221
        else:
 
9222
            self.OnMotion_Other(event)
 
9223
 
 
9224
 
 
9225
    def OnLeaveWindow(self, event):
 
9226
        """
 
9227
        Handles the ``wx.EVT_LEAVE_WINDOW`` event for :class:`AuiManager`.
 
9228
 
 
9229
        :param `event`: a :class:`MouseEvent` to be processed.
 
9230
        """
 
9231
 
 
9232
        if self._hover_button:
 
9233
            self.RefreshButton(self._hover_button)
 
9234
            self._hover_button = None
 
9235
 
 
9236
 
 
9237
    def OnCaptureLost(self, event):
 
9238
        """
 
9239
        Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for :class:`AuiManager`.
 
9240
 
 
9241
        :param `event`: a :class:`MouseCaptureLostEvent` to be processed.
 
9242
        """
 
9243
 
 
9244
        # cancel the operation in progress, if any
 
9245
        if self._action != actionNone:
 
9246
            self._action = actionNone
 
9247
            self.HideHint()
 
9248
 
 
9249
 
 
9250
    def OnHintFadeTimer(self, event):
 
9251
        """
 
9252
        Handles the ``wx.EVT_TIMER`` event for :class:`AuiManager`.
 
9253
 
 
9254
        :param `event`: a :class:`TimerEvent` to be processed.
 
9255
        """
 
9256
 
 
9257
        if not self._hint_window or self._hint_fadeamt >= self._hint_fademax:
 
9258
            self._hint_fadetimer.Stop()
 
9259
            return
 
9260
 
 
9261
        self._hint_fadeamt += 4
 
9262
        self._hint_window.SetTransparent(self._hint_fadeamt)
 
9263
 
 
9264
 
 
9265
    def OnMove(self, event):
 
9266
        """
 
9267
        Handles the ``wx.EVT_MOVE`` event for :class:`AuiManager`.
 
9268
 
 
9269
        :param `event`: a :class:`MoveEvent` to be processed.
 
9270
        """
 
9271
 
 
9272
        if event is not None:
 
9273
            event.Skip()
 
9274
 
 
9275
        if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
 
9276
            return
 
9277
 
 
9278
        docked, hAlign, vAlign, monitor = self._is_docked
 
9279
        if docked:
 
9280
            self.Snap()
 
9281
 
 
9282
        for pane in self._panes:
 
9283
            if pane.IsSnappable():
 
9284
                if pane.IsFloating() and pane.IsShown():
 
9285
                    self.SnapPane(pane, pane.floating_pos, pane.floating_size, True)
 
9286
 
 
9287
 
 
9288
    def OnSysColourChanged(self, event):
 
9289
        """
 
9290
        Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for :class:`AuiManager`.
 
9291
 
 
9292
        :param `event`: a :class:`SysColourChangedEvent` to be processed.
 
9293
        """
 
9294
 
 
9295
        # This event is probably triggered by a theme change
 
9296
        # so we have to re-init the art provider.
 
9297
        if self._art:
 
9298
            self._art.Init()
 
9299
 
 
9300
        if self._frame:
 
9301
            self.Update()
 
9302
            self._frame.Refresh()
 
9303
 
 
9304
 
 
9305
    def OnChildFocus(self, event):
 
9306
        """
 
9307
        Handles the ``wx.EVT_CHILD_FOCUS`` event for :class:`AuiManager`.
 
9308
 
 
9309
        :param `event`: a :class:`ChildFocusEvent` to be processed.
 
9310
        """
 
9311
 
 
9312
        # when a child pane has it's focus set, we should change the
 
9313
        # pane's active state to reflect this. (this is only true if
 
9314
        # active panes are allowed by the owner)
 
9315
 
 
9316
        window = event.GetWindow()
 
9317
        if isinstance(window, wx.Dialog):
 
9318
            # Ignore EVT_CHILD_FOCUS events originating from dialogs not
 
9319
            # managed by AUI
 
9320
            rootManager = None
 
9321
        elif isinstance(window.GetParent(), AuiFloatingFrame):
 
9322
            rootManager = GetManager(window)
 
9323
        else:
 
9324
            rootManager = self
 
9325
 
 
9326
        if rootManager:
 
9327
            rootManager.ActivatePane(window)
 
9328
 
 
9329
        event.Skip()
 
9330
 
 
9331
 
 
9332
    def OnMotion_ClickCaption(self, event):
 
9333
        """
 
9334
        Sub-handler for the :meth:`OnMotion` event.
 
9335
 
 
9336
        :param `event`: a :class:`MouseEvent` to be processed.
 
9337
        """
 
9338
 
 
9339
        clientPt = event.GetPosition()
 
9340
        screenPt = self._frame.ClientToScreen(clientPt)
 
9341
 
 
9342
        drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X)
 
9343
        drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y)
 
9344
 
 
9345
        if not self._action_pane:
 
9346
            return
 
9347
 
 
9348
        # we need to check if the mouse is now being dragged
 
9349
        if not (abs(clientPt.x - self._action_start.x) > drag_x_threshold or \
 
9350
                abs(clientPt.y - self._action_start.y) > drag_y_threshold):
 
9351
 
 
9352
            return
 
9353
 
 
9354
        # dragged -- we need to change the mouse action to 'drag'
 
9355
        if self._action_pane.IsToolbar():
 
9356
            self._action = actionDragToolbarPane
 
9357
            self._action_window = self._action_pane.window
 
9358
 
 
9359
        elif self._action_pane.IsFloatable() and self._agwFlags & AUI_MGR_ALLOW_FLOATING:
 
9360
 
 
9361
            e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, self._action_pane, canVeto=True)
 
9362
            if e.GetVeto():
 
9363
                return
 
9364
 
 
9365
            self._action = actionDragFloatingPane
 
9366
 
 
9367
            # set initial float position
 
9368
            self._action_pane.floating_pos = screenPt - self._action_offset
 
9369
 
 
9370
            # float the window
 
9371
            if self._action_pane.IsMaximized():
 
9372
                self.RestorePane(self._action_pane)
 
9373
 
 
9374
            self._action_pane.Hide()
 
9375
            self._action_pane.Float()
 
9376
            if wx.Platform == "__WXGTK__":
 
9377
                self._action_pane.Show()
 
9378
 
 
9379
            e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, self._action_pane, canVeto=False)
 
9380
 
 
9381
            if not self._action_pane.frame:
 
9382
                self.Update()
 
9383
 
 
9384
            self._action_window = self._action_pane.window
 
9385
 
 
9386
            # adjust action offset for window frame
 
9387
            windowPt = self._action_pane.frame.GetRect().GetTopLeft()
 
9388
            originPt = self._action_pane.frame.ClientToScreen(wx.Point())
 
9389
            self._toolbar_action_offset = originPt - windowPt
 
9390
 
 
9391
            if self._agwFlags & AUI_MGR_USE_NATIVE_MINIFRAMES:
 
9392
                originPt = windowPt + wx.Point(3, 3)
 
9393
 
 
9394
            self._action_offset += originPt - windowPt
 
9395
 
 
9396
            # action offset is used here to make it feel "natural" to the user
 
9397
            # to drag a docked pane and suddenly have it become a floating frame.
 
9398
            # Sometimes, however, the offset where the user clicked on the docked
 
9399
            # caption is bigger than the width of the floating frame itself, so
 
9400
            # in that case we need to set the action offset to a sensible value
 
9401
            frame_size = self._action_pane.frame.GetSize()
 
9402
            if self._action_offset.x > frame_size.x * 2 / 3:
 
9403
                self._action_offset.x = frame_size.x / 2
 
9404
            if self._action_offset.y > frame_size.y * 2 / 3:
 
9405
                self._action_offset.y = frame_size.y / 2
 
9406
 
 
9407
            self.OnMotion_DragFloatingPane(event)
 
9408
            if wx.Platform != "__WXGTK__":
 
9409
                self._action_pane.Show()
 
9410
 
 
9411
            self.Update()
 
9412
 
 
9413
        elif self._action_pane.IsMovable():
 
9414
            self._action = actionDragMovablePane
 
9415
            self._action_window = self._action_pane.window
 
9416
 
 
9417
 
 
9418
    def OnMotion_Resize(self, event):
 
9419
        """
 
9420
        Sub-handler for the :meth:`OnMotion` event.
 
9421
 
 
9422
        :param `event`: a :class:`MouseEvent` to be processed.
 
9423
        """
 
9424
 
 
9425
        if AuiManager_HasLiveResize(self):
 
9426
            if self._currentDragItem != -1:
 
9427
                self._action_part = self._uiparts[self._currentDragItem]
 
9428
            else:
 
9429
                self._currentDragItem = self._uiparts.index(self._action_part)
 
9430
 
 
9431
            if self._frame.HasCapture():
 
9432
                self._frame.ReleaseMouse()
 
9433
 
 
9434
            self.DoEndResizeAction(event)
 
9435
            self._frame.CaptureMouse()
 
9436
            return
 
9437
 
 
9438
        if not self._action_part or not self._action_part.dock or not self._action_part.orientation:
 
9439
            return
 
9440
 
 
9441
        clientPt = event.GetPosition()
 
9442
        screenPt = self._frame.ClientToScreen(clientPt)
 
9443
 
 
9444
        dock = self._action_part.dock
 
9445
        pos = self._action_part.rect.GetPosition()
 
9446
 
 
9447
        if self._action_part.type == AuiDockUIPart.typeDockSizer:
 
9448
            minPix, maxPix = self.CalculateDockSizerLimits(dock)
 
9449
        else:
 
9450
            if not self._action_part.pane:
 
9451
                return
 
9452
 
 
9453
            pane = self._action_part.pane
 
9454
            minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
 
9455
 
 
9456
        if self._action_part.orientation == wx.HORIZONTAL:
 
9457
            pos.y = Clip(clientPt.y - self._action_offset.y, minPix, maxPix)
 
9458
        else:
 
9459
            pos.x = Clip(clientPt.x - self._action_offset.x, minPix, maxPix)
 
9460
 
 
9461
        hintrect = wx.RectPS(self._frame.ClientToScreen(pos), self._action_part.rect.GetSize())
 
9462
 
 
9463
        if hintrect != self._action_rect:
 
9464
 
 
9465
            if wx.Platform == "__WXMAC__":
 
9466
                dc = wx.ClientDC(self._frame)
 
9467
            else:
 
9468
                dc = wx.ScreenDC()
 
9469
 
 
9470
            DrawResizeHint(dc, self._action_rect)
 
9471
            DrawResizeHint(dc, hintrect)
 
9472
            self._action_rect = wx.Rect(*hintrect)
 
9473
 
 
9474
 
 
9475
    def OnLeftUp_Resize(self, event):
 
9476
        """
 
9477
        Sub-handler for the :meth:`OnLeftUp` event.
 
9478
 
 
9479
        :param `event`: a :class:`MouseEvent` to be processed.
 
9480
        """
 
9481
 
 
9482
        if self._currentDragItem != -1 and AuiManager_HasLiveResize(self):
 
9483
            self._action_part = self._uiparts[self._currentDragItem]
 
9484
 
 
9485
            if self._frame.HasCapture():
 
9486
                self._frame.ReleaseMouse()
 
9487
 
 
9488
            self.DoEndResizeAction(event)
 
9489
            self._currentDragItem = -1
 
9490
            return
 
9491
 
 
9492
        if not self._action_part or not self._action_part.dock:
 
9493
            return
 
9494
 
 
9495
        clientPt = event.GetPosition()
 
9496
        screenPt = self._frame.ClientToScreen(clientPt)
 
9497
 
 
9498
        return self.RestrictResize(clientPt, screenPt, createDC=True)
 
9499
 
 
9500
 
 
9501
    def OnLeftUp_ClickButton(self, event):
 
9502
        """
 
9503
        Sub-handler for the :meth:`OnLeftUp` event.
 
9504
 
 
9505
        :param `event`: a :class:`MouseEvent` to be processed.
 
9506
        """
 
9507
 
 
9508
        self._hover_button = None
 
9509
 
 
9510
        if self._action_part:
 
9511
            self.RefreshButton(self._action_part)
 
9512
 
 
9513
            # make sure we're still over the item that was originally clicked
 
9514
            if self._action_part == self.HitTest(*event.GetPosition()):
 
9515
 
 
9516
                # fire button-click event
 
9517
                e = AuiManagerEvent(wxEVT_AUI_PANE_BUTTON)
 
9518
                e.SetManager(self)
 
9519
                e.SetPane(self._action_part.pane)
 
9520
                e.SetButton(self._action_part.button.button_id)
 
9521
                self.ProcessMgrEvent(e)
 
9522
 
 
9523
 
 
9524
    def CheckPaneMove(self, pane):
 
9525
        """
 
9526
        Checks if a pane has moved by a visible amount.
 
9527
 
 
9528
        :param `pane`: an instance of :class:`AuiPaneInfo`.
 
9529
        """
 
9530
 
 
9531
        win_rect = pane.frame.GetRect()
 
9532
        win_rect.x, win_rect.y = pane.floating_pos
 
9533
 
 
9534
        if win_rect == self._last_rect:
 
9535
            return False
 
9536
 
 
9537
        # skip the first move event
 
9538
        if self._last_rect.IsEmpty():
 
9539
            self._last_rect = wx.Rect(*win_rect)
 
9540
            return False
 
9541
 
 
9542
        # skip if moving too fast to avoid massive redraws and
 
9543
        # jumping hint windows
 
9544
        if abs(win_rect.x - self._last_rect.x) > 10 or \
 
9545
           abs(win_rect.y - self._last_rect.y) > 10:
 
9546
            self._last_rect = wx.Rect(*win_rect)
 
9547
            return False
 
9548
 
 
9549
        return True
 
9550
 
 
9551
 
 
9552
    def OnMotion_DragFloatingPane(self, eventOrPt):
 
9553
        """
 
9554
        Sub-handler for the :meth:`OnMotion` event.
 
9555
 
 
9556
        :param `event`: a :class:`MouseEvent` to be processed.
 
9557
        """
 
9558
 
 
9559
        isPoint = False
 
9560
        if isinstance(eventOrPt, wx.Point):
 
9561
            clientPt = self._frame.ScreenToClient(eventOrPt)
 
9562
            screenPt = wx.Point(*eventOrPt)
 
9563
            isPoint = True
 
9564
        else:
 
9565
            clientPt = eventOrPt.GetPosition()
 
9566
            screenPt = self._frame.ClientToScreen(clientPt)
 
9567
 
 
9568
        framePos = wx.Point()
 
9569
 
 
9570
        # try to find the pane
 
9571
        pane = self.GetPane(self._action_window)
 
9572
        if not pane.IsOk():
 
9573
            raise Exception("Pane window not found")
 
9574
 
 
9575
        # update floating position
 
9576
        if pane.IsFloating():
 
9577
            diff = pane.floating_pos - (screenPt - self._action_offset)
 
9578
            pane.floating_pos = screenPt - self._action_offset
 
9579
 
 
9580
        framePos = pane.floating_pos
 
9581
 
 
9582
        # Move the pane window
 
9583
        if pane.frame:
 
9584
 
 
9585
            if diff.x != 0 or diff.y != 0:
 
9586
                if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
 
9587
                    # return
 
9588
                    # HACK: Terrible hack on wxMSW (!)
 
9589
                    pane.frame.SetTransparent(254)
 
9590
 
 
9591
                self._from_move = True
 
9592
                pane.frame.Move(pane.floating_pos)
 
9593
                self._from_move = False
 
9594
 
 
9595
            if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
 
9596
                pane.frame.SetTransparent(150)
 
9597
 
 
9598
        # calculate the offset from the upper left-hand corner
 
9599
        # of the frame to the mouse pointer
 
9600
        action_offset = screenPt - framePos
 
9601
 
 
9602
        # is the pane dockable?
 
9603
        if not self.CanDockPanel(pane):
 
9604
            self.HideHint()
 
9605
            ShowDockingGuides(self._guides, False)
 
9606
            return
 
9607
 
 
9608
        for paneInfo in self._panes:
 
9609
 
 
9610
            if not paneInfo.IsDocked() or not paneInfo.IsShown():
 
9611
                continue
 
9612
            if paneInfo.IsToolbar() or paneInfo.IsNotebookControl():
 
9613
                continue
 
9614
            if paneInfo.IsMaximized():
 
9615
                continue
 
9616
 
 
9617
            if paneInfo.IsNotebookPage():
 
9618
 
 
9619
                notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
 
9620
 
 
9621
                if not notebookRoot or not notebookRoot.IsDocked():
 
9622
                    continue
 
9623
 
 
9624
            rc = paneInfo.window.GetScreenRect()
 
9625
            if rc.Contains(screenPt):
 
9626
                if rc.height < 20 or rc.width < 20:
 
9627
                    return
 
9628
 
 
9629
                self.UpdateDockingGuides(paneInfo)
 
9630
                ShowDockingGuides(self._guides, True)
 
9631
                break
 
9632
 
 
9633
        self.DrawHintRect(pane.window, clientPt, action_offset)
 
9634
 
 
9635
 
 
9636
    def OnMotion_DragMovablePane(self, eventOrPt):
 
9637
        """
 
9638
        Sub-handler for the :meth:`OnMotion` event.
 
9639
 
 
9640
        :param `event`: a :class:`MouseEvent` to be processed.
 
9641
        """
 
9642
 
 
9643
        # Try to find the pane.
 
9644
        pane = self.GetPane(self._action_window)
 
9645
        if not pane.IsOk():
 
9646
            raise Exception("Pane window not found")
 
9647
 
 
9648
        # Draw a hint for where the window will be moved.
 
9649
        if isinstance(eventOrPt, wx.Point):
 
9650
            pt = wx.Point(*eventOrPt)
 
9651
        else:
 
9652
            pt = eventOrPt.GetPosition()
 
9653
 
 
9654
        self.DrawHintRect(self._action_window, pt, wx.Point(0, 0))
 
9655
 
 
9656
        # Reduces flicker.
 
9657
        self._frame.Update()
 
9658
 
 
9659
 
 
9660
    def OnLeftUp_DragFloatingPane(self, eventOrPt):
 
9661
        """
 
9662
        Sub-handler for the :meth:`OnLeftUp` event.
 
9663
 
 
9664
        :param `event`: a :class:`MouseEvent` to be processed.
 
9665
        """
 
9666
 
 
9667
        if isinstance(eventOrPt, wx.Point):
 
9668
            clientPt = self._frame.ScreenToClient(eventOrPt)
 
9669
            screenPt = wx.Point(*eventOrPt)
 
9670
        else:
 
9671
            clientPt = eventOrPt.GetPosition()
 
9672
            screenPt = self._frame.ClientToScreen(clientPt)
 
9673
 
 
9674
        # try to find the pane
 
9675
        paneInfo = self.GetPane(self._action_window)
 
9676
        if not paneInfo.IsOk():
 
9677
            raise Exception("Pane window not found")
 
9678
 
 
9679
        ret = False
 
9680
 
 
9681
        if paneInfo.frame:
 
9682
 
 
9683
            # calculate the offset from the upper left-hand corner
 
9684
            # of the frame to the mouse pointer
 
9685
            framePos = paneInfo.frame.GetPosition()
 
9686
            action_offset = screenPt - framePos
 
9687
 
 
9688
            # is the pane dockable?
 
9689
            if self.CanDockPanel(paneInfo):
 
9690
                # do the drop calculation
 
9691
                indx = self._panes.index(paneInfo)
 
9692
                ret, paneInfo = self.DoDrop(self._docks, self._panes, paneInfo, clientPt, action_offset)
 
9693
 
 
9694
                if ret:
 
9695
                    e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
 
9696
                    if e.GetVeto():
 
9697
                        self.HideHint()
 
9698
                        ShowDockingGuides(self._guides, False)
 
9699
                        return
 
9700
 
 
9701
                    e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
 
9702
 
 
9703
                    if self._agwFlags & AUI_MGR_SMOOTH_DOCKING:
 
9704
                        self.SmoothDock(paneInfo)
 
9705
 
 
9706
                self._panes[indx] = paneInfo
 
9707
 
 
9708
        # if the pane is still floating, update it's floating
 
9709
        # position (that we store)
 
9710
        if paneInfo.IsFloating():
 
9711
            paneInfo.floating_pos = paneInfo.frame.GetPosition()
 
9712
            if paneInfo.frame._transparent != paneInfo.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
 
9713
                paneInfo.frame.SetTransparent(paneInfo.transparent)
 
9714
                paneInfo.frame._transparent = paneInfo.transparent
 
9715
 
 
9716
        elif self._has_maximized:
 
9717
            self.RestoreMaximizedPane()
 
9718
 
 
9719
        # reorder for dropping to a new notebook
 
9720
        # (caution: this code breaks the reference!)
 
9721
        tempPaneInfo = self.CopyTarget(paneInfo)
 
9722
        self._panes.remove(paneInfo)
 
9723
        self._panes.append(tempPaneInfo)
 
9724
 
 
9725
        if ret:
 
9726
            self.Update()
 
9727
 
 
9728
        if tempPaneInfo.IsFloating():
 
9729
            self.SnapPane(tempPaneInfo, tempPaneInfo.floating_pos, tempPaneInfo.floating_size, False)
 
9730
 
 
9731
        self.HideHint()
 
9732
        ShowDockingGuides(self._guides, False)
 
9733
 
 
9734
 
 
9735
    def OnLeftUp_DragMovablePane(self, event):
 
9736
        """
 
9737
        Sub-handler for the :meth:`OnLeftUp` event.
 
9738
 
 
9739
        :param `event`: a :class:`MouseEvent` to be processed.
 
9740
        """
 
9741
 
 
9742
        # Try to find the pane.
 
9743
        paneInfo = self.GetPane(self._action_window)
 
9744
        if not paneInfo.IsOk():
 
9745
            raise Exception("Pane window not found")
 
9746
 
 
9747
        # Hide the hint as it is no longer needed.
 
9748
        self.HideHint()
 
9749
 
 
9750
        # is the pane dockable?
 
9751
        if self.CanDockPanel(paneInfo):
 
9752
            # Move the pane to new position.
 
9753
            pt = event.GetPosition()
 
9754
            # do the drop calculation
 
9755
            indx = self._panes.index(paneInfo)
 
9756
            ret, paneInfo = self.DoDrop(self._docks, self._panes, paneInfo, pt, wx.Point(0,0))
 
9757
 
 
9758
            if ret:
 
9759
                e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
 
9760
                if e.GetVeto():
 
9761
                    self.HideHint()
 
9762
                    ShowDockingGuides(self._guides, False)
 
9763
                    return
 
9764
 
 
9765
                e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
 
9766
 
 
9767
                if self._agwFlags & AUI_MGR_SMOOTH_DOCKING:
 
9768
                    self.SmoothDock(paneInfo)
 
9769
 
 
9770
            self._panes[indx] = paneInfo
 
9771
 
 
9772
            if ret:
 
9773
                # Update the layout to realize new position and e.g. form notebooks if needed.
 
9774
                self.Update()
 
9775
 
 
9776
        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
 
9777
            # Ensure active before doing actual display.
 
9778
            ret, self._panes = SetActivePane(self._panes, paneInfo.window)
 
9779
 
 
9780
        # Make changes visible to user.
 
9781
        self.Repaint()
 
9782
 
 
9783
        # Cancel the action and release the mouse.
 
9784
        self._action = actionNone
 
9785
        self._frame.ReleaseMouse()
 
9786
        self._action_window = None
 
9787
 
 
9788
 
 
9789
    def OnMotion_DragToolbarPane(self, eventOrPt):
 
9790
        """
 
9791
        Sub-handler for the :meth:`OnMotion` event.
 
9792
 
 
9793
        :param `event`: a :class:`MouseEvent` to be processed.
 
9794
        """
 
9795
 
 
9796
        isPoint = False
 
9797
        if isinstance(eventOrPt, wx.Point):
 
9798
            clientPt = self._frame.ScreenToClient(eventOrPt)
 
9799
            screenPt = wx.Point(*eventOrPt)
 
9800
            isPoint = True
 
9801
        else:
 
9802
            clientPt = eventOrPt.GetPosition()
 
9803
            screenPt = self._frame.ClientToScreen(clientPt)
 
9804
 
 
9805
        pane = self.GetPane(self._action_window)
 
9806
        if not pane.IsOk():
 
9807
            raise Exception("Pane window not found")
 
9808
 
 
9809
        pane.state |= AuiPaneInfo.actionPane
 
9810
        indx = self._panes.index(pane)
 
9811
 
 
9812
        ret = False
 
9813
        wasFloating = pane.IsFloating()
 
9814
        # is the pane dockable?
 
9815
        if self.CanDockPanel(pane):
 
9816
            # do the drop calculation
 
9817
            ret, pane = self.DoDrop(self._docks, self._panes, pane, clientPt, self._action_offset)
 
9818
 
 
9819
        # update floating position
 
9820
        if pane.IsFloating():
 
9821
            pane.floating_pos = screenPt - self._toolbar_action_offset
 
9822
 
 
9823
        # move the pane window
 
9824
        if pane.frame:
 
9825
            if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
 
9826
                # return
 
9827
                # HACK: Terrible hack on wxMSW (!)
 
9828
                pane.frame.SetTransparent(254)
 
9829
 
 
9830
            self._from_move = True
 
9831
            pane.frame.Move(pane.floating_pos)
 
9832
            self._from_move = False
 
9833
 
 
9834
            if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
 
9835
                pane.frame.SetTransparent(150)
 
9836
 
 
9837
        self._panes[indx] = pane
 
9838
        if ret and wasFloating != pane.IsFloating() or (ret and not wasFloating):
 
9839
            wx.CallAfter(self.Update)
 
9840
 
 
9841
        # when release the button out of the window.
 
9842
        # TODO: a better fix is needed.
 
9843
 
 
9844
        if _VERSION_STRING < "2.9":
 
9845
            leftDown = wx.GetMouseState().LeftDown()
 
9846
        else:
 
9847
            leftDown = wx.GetMouseState().LeftIsDown()
 
9848
 
 
9849
        if not leftDown:
 
9850
            self._action = actionNone
 
9851
            self.OnLeftUp_DragToolbarPane(eventOrPt)
 
9852
 
 
9853
 
 
9854
    def OnMotion_Other(self, event):
 
9855
        """
 
9856
        Sub-handler for the :meth:`OnMotion` event.
 
9857
 
 
9858
        :param `event`: a :class:`MouseEvent` to be processed.
 
9859
        """
 
9860
 
 
9861
        part = self.HitTest(*event.GetPosition())
 
9862
 
 
9863
        if part and part.type == AuiDockUIPart.typePaneButton \
 
9864
           and self.IsPaneButtonVisible(part):
 
9865
            if part != self._hover_button:
 
9866
 
 
9867
                if self._hover_button:
 
9868
                    self.RefreshButton(self._hover_button)
 
9869
 
 
9870
                self._hover_button = part
 
9871
                self.RefreshButton(part)
 
9872
 
 
9873
        else:
 
9874
 
 
9875
            if self._hover_button:
 
9876
                self.RefreshButton(self._hover_button)
 
9877
            else:
 
9878
                event.Skip()
 
9879
 
 
9880
            self._hover_button = None
 
9881
 
 
9882
 
 
9883
    def OnLeftUp_DragToolbarPane(self, eventOrPt):
 
9884
        """
 
9885
        Sub-handler for the :meth:`OnLeftUp` event.
 
9886
 
 
9887
        :param `event`: a :class:`MouseEvent` to be processed.
 
9888
        """
 
9889
 
 
9890
        isPoint = False
 
9891
        if isinstance(eventOrPt, wx.Point):
 
9892
            clientPt = self._frame.ScreenToClient(eventOrPt)
 
9893
            screenPt = wx.Point(*eventOrPt)
 
9894
            isPoint = True
 
9895
        else:
 
9896
            clientPt = eventOrPt.GetPosition()
 
9897
            screenPt = self._frame.ClientToScreen(clientPt)
 
9898
 
 
9899
        # try to find the pane
 
9900
        pane = self.GetPane(self._action_window)
 
9901
        if not pane.IsOk():
 
9902
            raise Exception("Pane window not found")
 
9903
 
 
9904
        if pane.IsFloating():
 
9905
            pane.floating_pos = pane.frame.GetPosition()
 
9906
            if pane.frame._transparent != pane.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
 
9907
                pane.frame.SetTransparent(pane.transparent)
 
9908
                pane.frame._transparent = pane.transparent
 
9909
 
 
9910
        # save the new positions
 
9911
        docks = FindDocks(self._docks, pane.dock_direction, pane.dock_layer, pane.dock_row)
 
9912
        if len(docks) == 1:
 
9913
            dock = docks[0]
 
9914
            pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
 
9915
 
 
9916
            for i in xrange(len(dock.panes)):
 
9917
                dock.panes[i].dock_pos = pane_positions[i]
 
9918
 
 
9919
        pane.state &= ~AuiPaneInfo.actionPane
 
9920
        self.Update()
 
9921
 
 
9922
 
 
9923
    def OnPaneButton(self, event):
 
9924
        """
 
9925
        Handles the ``EVT_AUI_PANE_BUTTON`` event for :class:`AuiManager`.
 
9926
 
 
9927
        :param `event`: a :class:`AuiManagerEvent` event to be processed.
 
9928
        """
 
9929
 
 
9930
        if not event.pane:
 
9931
            raise Exception("Pane Info passed to AuiManager.OnPaneButton must be non-null")
 
9932
 
 
9933
        pane = event.pane
 
9934
 
 
9935
        if event.button == AUI_BUTTON_CLOSE:
 
9936
 
 
9937
            if isinstance(pane.window.GetParent(), AuiFloatingFrame):
 
9938
                rootManager = GetManager(pane.window)
 
9939
            else:
 
9940
                rootManager = self
 
9941
 
 
9942
            if rootManager != self:
 
9943
                self._frame.Close()
 
9944
                return
 
9945
 
 
9946
            # fire pane close event
 
9947
            e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
 
9948
            e.SetManager(self)
 
9949
            e.SetPane(event.pane)
 
9950
            self.ProcessMgrEvent(e)
 
9951
 
 
9952
            if not e.GetVeto():
 
9953
 
 
9954
                # close the pane, but check that it
 
9955
                # still exists in our pane array first
 
9956
                # (the event handler above might have removed it)
 
9957
 
 
9958
                check = self.GetPane(pane.window)
 
9959
                if check.IsOk():
 
9960
                    self.ClosePane(pane)
 
9961
 
 
9962
                self.Update()
 
9963
 
 
9964
        # mn this performs the minimizing of a pane
 
9965
        elif event.button == AUI_BUTTON_MINIMIZE:
 
9966
            e = AuiManagerEvent(wxEVT_AUI_PANE_MINIMIZE)
 
9967
            e.SetManager(self)
 
9968
            e.SetPane(event.pane)
 
9969
            self.ProcessMgrEvent(e)
 
9970
 
 
9971
            if not e.GetVeto():
 
9972
                self.MinimizePane(pane)
 
9973
 
 
9974
        elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and not pane.IsMaximized():
 
9975
 
 
9976
            # fire pane close event
 
9977
            e = AuiManagerEvent(wxEVT_AUI_PANE_MAXIMIZE)
 
9978
            e.SetManager(self)
 
9979
            e.SetPane(event.pane)
 
9980
            self.ProcessMgrEvent(e)
 
9981
 
 
9982
            if not e.GetVeto():
 
9983
 
 
9984
                self.MaximizePane(pane)
 
9985
                self.Update()
 
9986
 
 
9987
        elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and pane.IsMaximized():
 
9988
 
 
9989
            # fire pane close event
 
9990
            e = AuiManagerEvent(wxEVT_AUI_PANE_RESTORE)
 
9991
            e.SetManager(self)
 
9992
            e.SetPane(event.pane)
 
9993
            self.ProcessMgrEvent(e)
 
9994
 
 
9995
            if not e.GetVeto():
 
9996
 
 
9997
                self.RestorePane(pane)
 
9998
                self.Update()
 
9999
 
 
10000
        elif event.button == AUI_BUTTON_PIN:
 
10001
 
 
10002
            if self._agwFlags & AUI_MGR_ALLOW_FLOATING and pane.IsFloatable():
 
10003
                e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, pane, canVeto=True)
 
10004
                if e.GetVeto():
 
10005
                    return
 
10006
 
 
10007
                pane.Float()
 
10008
                e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, pane, canVeto=False)
 
10009
 
 
10010
            self.Update()
 
10011
 
 
10012
 
 
10013
    def MinimizePane(self, paneInfo, mgrUpdate=True):
 
10014
        """
 
10015
        Minimizes a pane in a newly and automatically created :class:`~lib.agw.aui.auibar.AuiToolBar`.
 
10016
 
 
10017
        Clicking on the minimize button causes a new :class:`~lib.agw.aui.auibar.AuiToolBar` to be created
 
10018
        and added to the frame manager (currently the implementation is such that
 
10019
        panes at West will have a toolbar at the right, panes at South will have
 
10020
        toolbars at the bottom etc...) and the pane is hidden in the manager.
 
10021
 
 
10022
        Clicking on the restore button on the newly created toolbar will result in the
 
10023
        toolbar being removed and the original pane being restored.
 
10024
 
 
10025
        :param `paneInfo`: a :class:`AuiPaneInfo` instance for the pane to be minimized;
 
10026
        :param bool `mgrUpdate`: ``True`` to call :meth:`Update` to realize the new layout,
 
10027
         ``False`` otherwise.
 
10028
 
 
10029
        .. note::
 
10030
 
 
10031
           The `mgrUpdate` parameter is currently only used while loading perspectives using
 
10032
           :meth:`LoadPerspective`, as minimized panes were not correctly taken into account before.
 
10033
 
 
10034
        """
 
10035
 
 
10036
        if not paneInfo.IsToolbar():
 
10037
 
 
10038
            if paneInfo.IsMinimized() and mgrUpdate:
 
10039
                # We are already minimized
 
10040
                return
 
10041
 
 
10042
            # Basically the idea is this.
 
10043
            #
 
10044
            # 1) create a toolbar, with a restore button
 
10045
            #
 
10046
            # 2) place the new toolbar in the toolbar area representative of the location of the pane
 
10047
            #  (NORTH/SOUTH/EAST/WEST, central area always to the right)
 
10048
            #
 
10049
            # 3) Hide the minimizing pane
 
10050
 
 
10051
            # personalize the toolbar style
 
10052
 
 
10053
            tbStyle = AUI_TB_DEFAULT_STYLE
 
10054
            posMask = paneInfo.minimize_mode & AUI_MINIMIZE_POS_MASK
 
10055
            captMask = paneInfo.minimize_mode & AUI_MINIMIZE_CAPT_MASK
 
10056
            dockDirection = paneInfo.dock_direction
 
10057
            if captMask != 0:
 
10058
                tbStyle |= AUI_TB_TEXT
 
10059
 
 
10060
            if posMask == AUI_MINIMIZE_POS_TOOLBAR:
 
10061
                minimize_toolbar = self.GetPane(paneInfo.minimize_target)
 
10062
                if not minimize_toolbar.IsOk():
 
10063
                    posMask = AUI_MINIMIZE_POS_SMART
 
10064
                    if paneInfo.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
 
10065
                        tbStyle |= AUI_TB_HORZ_LAYOUT
 
10066
 
 
10067
                    elif paneInfo.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
 
10068
                        tbStyle |= AUI_TB_VERTICAL
 
10069
                        if captMask == AUI_MINIMIZE_CAPT_SMART:
 
10070
                            tbStyle |= AUI_TB_CLOCKWISE
 
10071
                else:
 
10072
                    minimize_toolbar = minimize_toolbar.window
 
10073
 
 
10074
            elif posMask == AUI_MINIMIZE_POS_SMART:
 
10075
                if paneInfo.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
 
10076
                    tbStyle |= AUI_TB_HORZ_LAYOUT
 
10077
 
 
10078
                elif paneInfo.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
 
10079
                    tbStyle |= AUI_TB_VERTICAL
 
10080
                    if captMask == AUI_MINIMIZE_CAPT_SMART:
 
10081
                        tbStyle |= AUI_TB_CLOCKWISE
 
10082
 
 
10083
            elif posMask in [AUI_MINIMIZE_POS_TOP, AUI_MINIMIZE_POS_BOTTOM]:
 
10084
                tbStyle |= AUI_TB_HORZ_LAYOUT
 
10085
                if posMask == AUI_MINIMIZE_POS_TOP:
 
10086
                    dockDirection = AUI_DOCK_TOP
 
10087
                else:
 
10088
                    dockDirection = AUI_DOCK_BOTTOM
 
10089
 
 
10090
            else:
 
10091
                tbStyle |= AUI_TB_VERTICAL
 
10092
                if captMask == AUI_MINIMIZE_CAPT_SMART:
 
10093
                    tbStyle |= AUI_TB_CLOCKWISE
 
10094
                if posMask == AUI_MINIMIZE_POS_LEFT:
 
10095
                    dockDirection = AUI_DOCK_LEFT
 
10096
                elif posMask == AUI_MINIMIZE_POS_RIGHT:
 
10097
                    dockDirection = AUI_DOCK_RIGHT
 
10098
                elif posMask == AUI_MINIMIZE_POS_BOTTOM:
 
10099
                    dockDirection = AUI_DOCK_BOTTOM
 
10100
 
 
10101
            # Create a new toolbar
 
10102
            # give it the same name as the minimized pane with _min appended
 
10103
 
 
10104
            win_rect = paneInfo.window.GetScreenRect()
 
10105
 
 
10106
            if posMask != AUI_MINIMIZE_POS_TOOLBAR:
 
10107
                minimize_toolbar = auibar.AuiToolBar(self.GetManagedWindow(), agwStyle=tbStyle)
 
10108
                minimize_toolbar.Hide()
 
10109
                minimize_toolbar.SetToolBitmapSize(wx.Size(16, 16))
 
10110
 
 
10111
            if paneInfo.icon and paneInfo.icon.IsOk():
 
10112
                restore_bitmap = paneInfo.icon
 
10113
            else:
 
10114
                restore_bitmap = self._art._restore_bitmap
 
10115
 
 
10116
            if posMask == AUI_MINIMIZE_POS_TOOLBAR:
 
10117
                xsize, ysize = minimize_toolbar.GetToolBitmapSize()
 
10118
                if xsize != restore_bitmap.GetWidth():
 
10119
                    img = restore_bitmap.ConvertToImage()
 
10120
                    img.Rescale(xsize, ysize, wx.IMAGE_QUALITY_HIGH)
 
10121
                    restore_bitmap = img.ConvertToBitmap()
 
10122
 
 
10123
            target = None
 
10124
            if posMask == AUI_MINIMIZE_POS_TOOLBAR:
 
10125
                target = paneInfo.name
 
10126
 
 
10127
            minimize_toolbar.AddSimpleTool(ID_RESTORE_FRAME, paneInfo.caption, restore_bitmap,
 
10128
                                           _(u"Restore %s")%paneInfo.caption, target=target)
 
10129
            minimize_toolbar.SetAuiManager(self)
 
10130
            minimize_toolbar.Realize()
 
10131
            toolpanelname = paneInfo.name + "_min"
 
10132
 
 
10133
            if paneInfo.IsMaximized():
 
10134
                paneInfo.SetFlag(paneInfo.wasMaximized, True)
 
10135
 
 
10136
            if posMask != AUI_MINIMIZE_POS_TOOLBAR:
 
10137
 
 
10138
                if dockDirection == AUI_DOCK_TOP:
 
10139
                    self.AddPane(minimize_toolbar, AuiPaneInfo(). \
 
10140
                        Name(toolpanelname).Caption(paneInfo.caption). \
 
10141
                        ToolbarPane().Top().BottomDockable(False). \
 
10142
                        LeftDockable(False).RightDockable(False).DestroyOnClose())
 
10143
 
 
10144
                elif dockDirection == AUI_DOCK_BOTTOM:
 
10145
                    self.AddPane(minimize_toolbar, AuiPaneInfo(). \
 
10146
                        Name(toolpanelname).Caption(paneInfo.caption). \
 
10147
                        ToolbarPane().Bottom().TopDockable(False). \
 
10148
                        LeftDockable(False).RightDockable(False).DestroyOnClose())
 
10149
 
 
10150
                elif dockDirection == AUI_DOCK_LEFT:
 
10151
                    self.AddPane(minimize_toolbar, AuiPaneInfo(). \
 
10152
                        Name(toolpanelname).Caption(paneInfo.caption). \
 
10153
                        ToolbarPane().Left().TopDockable(False). \
 
10154
                        BottomDockable(False).RightDockable(False).DestroyOnClose())
 
10155
 
 
10156
                elif dockDirection in [AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
 
10157
                    self.AddPane(minimize_toolbar, AuiPaneInfo(). \
 
10158
                        Name(toolpanelname).Caption(paneInfo.caption). \
 
10159
                        ToolbarPane().Right().TopDockable(False). \
 
10160
                        LeftDockable(False).BottomDockable(False).DestroyOnClose())
 
10161
 
 
10162
            arr = FindDocks(self._docks, paneInfo.dock_direction, paneInfo.dock_layer, paneInfo.dock_row)
 
10163
 
 
10164
            if arr:
 
10165
                dock = arr[0]
 
10166
                paneInfo.previousDockSize = dock.size
 
10167
 
 
10168
            paneInfo.previousDockPos = paneInfo.dock_pos
 
10169
 
 
10170
            # mark ourselves minimized
 
10171
            paneInfo.Minimize()
 
10172
            paneInfo.Show(False)
 
10173
            self._has_minimized = True
 
10174
            # last, hide the window
 
10175
            if paneInfo.window and paneInfo.window.IsShown():
 
10176
                paneInfo.window.Show(False)
 
10177
 
 
10178
            minimize_toolbar.Show()
 
10179
 
 
10180
            if mgrUpdate:
 
10181
                self.Update()
 
10182
                if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
 
10183
                    self.AnimateDocking(win_rect, minimize_toolbar.GetScreenRect())
 
10184
 
 
10185
 
 
10186
    def OnRestoreMinimizedPane(self, event):
 
10187
        """
 
10188
        Handles the ``EVT_AUI_PANE_MIN_RESTORE`` event for :class:`AuiManager`.
 
10189
 
 
10190
        :param `event`: an instance of :class:`AuiManagerEvent` to be processed.
 
10191
        """
 
10192
 
 
10193
        self.RestoreMinimizedPane(event.pane)
 
10194
 
 
10195
 
 
10196
    def OnPaneDocked(self, event):
 
10197
        """
 
10198
        Handles the ``EVT_AUI_PANE_DOCKED`` event for :class:`AuiManager`.
 
10199
 
 
10200
        :param `event`: an instance of :class:`AuiManagerEvent` to be processed.
 
10201
        """
 
10202
 
 
10203
        event.Skip()
 
10204
        self.RemoveAutoNBCaption(event.GetPane())
 
10205
 
 
10206
 
 
10207
    def CreateNotebookBase(self, panes, paneInfo):
 
10208
        """
 
10209
        Creates an auto-notebook base from a pane, and then add that pane as a page.
 
10210
 
 
10211
        :param list `panes`: set of panes to append new notebook base pane to
 
10212
        :param AuiPaneInfo `paneInfo`: the pane to be converted to a new notebook.
 
10213
        """
 
10214
 
 
10215
        # Create base notebook pane ...
 
10216
        nbid = len(self._notebooks)
 
10217
 
 
10218
        baseInfo = AuiPaneInfo()
 
10219
        baseInfo.SetDockPos(paneInfo).NotebookControl(nbid). \
 
10220
            CloseButton(False).SetNameFromNotebookId(). \
 
10221
            NotebookDockable(False).Floatable(paneInfo.IsFloatable())
 
10222
        baseInfo.best_size = paneInfo.best_size
 
10223
        panes.append(baseInfo)
 
10224
 
 
10225
        # add original pane as tab ...
 
10226
        paneInfo.NotebookPage(nbid)
 
10227
 
 
10228
 
 
10229
    def RemoveAutoNBCaption(self, pane):
 
10230
        """
 
10231
        Removes the caption on newly created automatic notebooks.
 
10232
 
 
10233
        :param `pane`: an instance of :class:`AuiPaneInfo` (the target notebook).
 
10234
        """
 
10235
 
 
10236
        if self._agwFlags & AUI_MGR_AUTONB_NO_CAPTION == 0:
 
10237
            return False
 
10238
 
 
10239
        def RemoveCaption():
 
10240
            """ Sub-function used to remove the pane caption on automatic notebooks. """
 
10241
 
 
10242
            if pane.HasNotebook():
 
10243
                notebook = self._notebooks[pane.notebook_id]
 
10244
                self.GetPane(notebook).CaptionVisible(False).PaneBorder(False)
 
10245
                self.Update()
 
10246
 
 
10247
        # it seems the notebook isnt created by this stage, so remove
 
10248
        # the caption a moment later
 
10249
        wx.CallAfter(RemoveCaption)
 
10250
        return True
 
10251
 
 
10252
 
 
10253
    def RestoreMinimizedPane(self, paneInfo):
 
10254
        """
 
10255
        Restores a previously minimized pane.
 
10256
 
 
10257
        :param `paneInfo`: a :class:`AuiPaneInfo` instance for the pane to be restored.
 
10258
        """
 
10259
 
 
10260
        panename = paneInfo.name
 
10261
 
 
10262
        if paneInfo.minimize_mode & AUI_MINIMIZE_POS_TOOLBAR:
 
10263
            pane = self.GetPane(panename)
 
10264
            hasTarget = True
 
10265
        else:
 
10266
            panename = panename[0:-4]
 
10267
            hasTarget = False
 
10268
 
 
10269
        pane = self.GetPane(panename)
 
10270
        pane.SetFlag(pane.needsRestore, True)
 
10271
 
 
10272
        if not pane.IsOk():
 
10273
            panename = paneInfo.name
 
10274
            pane = self.GetPane(panename)
 
10275
            paneInfo = self.GetPane(panename + "_min")
 
10276
            if not paneInfo.IsOk():
 
10277
                # Already minimized
 
10278
                return
 
10279
 
 
10280
        if pane.IsOk():
 
10281
            if not pane.IsMinimized():
 
10282
                return
 
10283
 
 
10284
 
 
10285
            if pane.HasFlag(pane.wasMaximized):
 
10286
                self.SavePreviousDockSizes(pane)
 
10287
 
 
10288
            self.ShowPane(pane.window, True)
 
10289
            pane.Show(True)
 
10290
            self._has_minimized = False
 
10291
            pane.SetFlag(pane.optionMinimized, False)
 
10292
 
 
10293
            if hasTarget:
 
10294
                targetName = pane.minimize_target
 
10295
                toolbarPane = self.GetPane(targetName)
 
10296
                toolbar = toolbarPane.window
 
10297
                item = toolbar.FindToolByLabel(pane.caption)
 
10298
                toolbar.DeleteTool(item.id)
 
10299
            else:
 
10300
                paneInfo.window.Show(False)
 
10301
                self.DetachPane(paneInfo.window)
 
10302
                paneInfo.Show(False)
 
10303
                paneInfo.Hide()
 
10304
 
 
10305
            self.Update()
 
10306
 
 
10307
 
 
10308
    def AnimateDocking(self, win_rect, pane_rect):
 
10309
        """
 
10310
        Animates the minimization/docking of a pane a la Eclipse, using a :class:`ScreenDC`
 
10311
        to draw a "moving docking rectangle" on the screen.
 
10312
 
 
10313
        :param Rect `win_rect`: the original pane screen rectangle;
 
10314
        :param Rect `pane_rect`: the newly created toolbar/pane screen rectangle.
 
10315
 
 
10316
        :note: This functionality is not available on wxMAC as this platform doesn't have
 
10317
         the ability to use :class:`ScreenDC` to draw on-screen and on Windows > Vista.
 
10318
        """
 
10319
 
 
10320
        if wx.Platform == "__WXMAC__":
 
10321
            # No wx.ScreenDC on the Mac...
 
10322
            return
 
10323
        if wx.Platform == "__WXMSW__" and wx.GetOsVersion()[1] > 5:
 
10324
            # No easy way to handle this on Vista...
 
10325
            return
 
10326
 
 
10327
        xstart, ystart = win_rect.x, win_rect.y
 
10328
        xend, yend = pane_rect.x, pane_rect.y
 
10329
 
 
10330
        step = self.GetAnimationStep()
 
10331
 
 
10332
        wstep = int(abs(win_rect.width - pane_rect.width)/step)
 
10333
        hstep = int(abs(win_rect.height - pane_rect.height)/step)
 
10334
        xstep = int(win_rect.x - pane_rect.x)/step
 
10335
        ystep = int(win_rect.y - pane_rect.y)/step
 
10336
 
 
10337
        dc = wx.ScreenDC()
 
10338
        dc.SetLogicalFunction(wx.INVERT)
 
10339
        dc.SetBrush(wx.TRANSPARENT_BRUSH)
 
10340
        dc.SetPen(wx.LIGHT_GREY_PEN)
 
10341
 
 
10342
        for i in xrange(int(step)):
 
10343
            width, height = win_rect.width - i*wstep, win_rect.height - i*hstep
 
10344
            x, y = xstart - i*xstep, ystart - i*ystep
 
10345
            new_rect = wx.Rect(x, y, width, height)
 
10346
            dc.DrawRoundedRectangleRect(new_rect, 3)
 
10347
            wx.SafeYield()
 
10348
            wx.MilliSleep(10)
 
10349
            dc.DrawRoundedRectangleRect(new_rect, 3)
 
10350
 
 
10351
 
 
10352
    def SmoothDock(self, paneInfo):
 
10353
        """
 
10354
        This method implements a smooth docking effect for floating panes, similar to
 
10355
        what the PyQT library does with its floating windows.
 
10356
 
 
10357
        :param `paneInfo`: an instance of :class:`AuiPaneInfo`.
 
10358
 
 
10359
        :note: The smooth docking effect can only be used if you set the ``AUI_MGR_SMOOTH_DOCKING``
 
10360
         style to :class:`AuiManager`.
 
10361
        """
 
10362
 
 
10363
        if paneInfo.IsToolbar():
 
10364
            return
 
10365
 
 
10366
        if not paneInfo.frame or self._hint_rect.IsEmpty():
 
10367
            return
 
10368
 
 
10369
        hint_rect = self._hint_rect
 
10370
        win_rect = paneInfo.frame.GetScreenRect()
 
10371
 
 
10372
        xstart, ystart = win_rect.x, win_rect.y
 
10373
        xend, yend = hint_rect.x, hint_rect.y
 
10374
 
 
10375
        step = self.GetAnimationStep()/3
 
10376
 
 
10377
        wstep = int((win_rect.width - hint_rect.width)/step)
 
10378
        hstep = int((win_rect.height - hint_rect.height)/step)
 
10379
        xstep = int((win_rect.x - hint_rect.x))/step
 
10380
        ystep = int((win_rect.y - hint_rect.y))/step
 
10381
 
 
10382
        for i in xrange(int(step)):
 
10383
            width, height = win_rect.width - i*wstep, win_rect.height - i*hstep
 
10384
            x, y = xstart - i*xstep, ystart - i*ystep
 
10385
            new_rect = wx.Rect(x, y, width, height)
 
10386
            paneInfo.frame.SetRect(new_rect)
 
10387
            wx.MilliSleep(10)
 
10388
 
 
10389
 
 
10390
    def SetSnapLimits(self, x, y):
 
10391
        """
 
10392
        Modifies the snap limits used when snapping the `managed_window` to the screen
 
10393
        (using :meth:`SnapToScreen`) or when snapping the floating panes to one side of the
 
10394
        `managed_window` (using :meth:`SnapPane`).
 
10395
 
 
10396
        To change the limit after which the `managed_window` or the floating panes are
 
10397
        automatically stickled to the screen border (or to the `managed_window` side),
 
10398
        set these two variables. Default values are 15 pixels.
 
10399
 
 
10400
        :param integer `x`: the minimum horizontal distance below which the snap occurs;
 
10401
        :param integer `y`: the minimum vertical distance below which the snap occurs.
 
10402
        """
 
10403
 
 
10404
        self._snap_limits = (x, y)
 
10405
        self.Snap()
 
10406
 
 
10407
 
 
10408
    def Snap(self):
 
10409
        """
 
10410
        Snaps the main frame to specified position on the screen.
 
10411
 
 
10412
        :see: :meth:`SnapToScreen`
 
10413
        """
 
10414
 
 
10415
        snap, hAlign, vAlign, monitor = self._is_docked
 
10416
        if not snap:
 
10417
            return
 
10418
 
 
10419
        managed_window = self.GetManagedWindow()
 
10420
        snap_pos = self.GetSnapPosition()
 
10421
        wnd_pos = managed_window.GetPosition()
 
10422
        snapX, snapY = self._snap_limits
 
10423
 
 
10424
        if abs(snap_pos.x - wnd_pos.x) < snapX and abs(snap_pos.y - wnd_pos.y) < snapY:
 
10425
            managed_window.SetPosition(snap_pos)
 
10426
 
 
10427
 
 
10428
    def SnapToScreen(self, snap=True, monitor=0, hAlign=wx.RIGHT, vAlign=wx.TOP):
 
10429
        """
 
10430
        Snaps the main frame to specified position on the screen.
 
10431
 
 
10432
        :param bool `snap`: whether to snap the main frame or not;
 
10433
        :param integer `monitor`: the monitor display in which snapping the window;
 
10434
        :param integer `hAlign`: the horizontal alignment of the snapping position;
 
10435
        :param integer `vAlign`: the vertical alignment of the snapping position.
 
10436
        """
 
10437
 
 
10438
        if not snap:
 
10439
            self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
 
10440
            return
 
10441
 
 
10442
        displayCount = wx.Display.GetCount()
 
10443
        if monitor > displayCount:
 
10444
            raise Exception("Invalid monitor selected: you only have %d monitors"%displayCount)
 
10445
 
 
10446
        self._is_docked = (True, hAlign, vAlign, monitor)
 
10447
        self.GetManagedWindow().SetPosition(self.GetSnapPosition())
 
10448
 
 
10449
 
 
10450
    def GetSnapPosition(self):
 
10451
        """ Returns the main frame snapping position. """
 
10452
 
 
10453
        snap, hAlign, vAlign, monitor = self._is_docked
 
10454
 
 
10455
        display = wx.Display(monitor)
 
10456
        area = display.GetClientArea()
 
10457
        size = self.GetManagedWindow().GetSize()
 
10458
 
 
10459
        pos = wx.Point()
 
10460
        if hAlign == wx.LEFT:
 
10461
            pos.x = area.x
 
10462
        elif hAlign == wx.CENTER:
 
10463
            pos.x = area.x + (area.width - size.x)/2
 
10464
        else:
 
10465
            pos.x = area.x + area.width - size.x
 
10466
 
 
10467
        if vAlign == wx.TOP:
 
10468
            pos.y = area.y
 
10469
        elif vAlign == wx.CENTER:
 
10470
            pos.y = area.y + (area.height - size.y)/2
 
10471
        else:
 
10472
            pos.y = area.y + area.height - size.y
 
10473
 
 
10474
        return pos
 
10475
 
 
10476
 
 
10477
    def GetAnimationStep(self):
 
10478
        """ Returns the animation step speed (a float) to use in :meth:`AnimateDocking`. """
 
10479
 
 
10480
        return self._animation_step
 
10481
 
 
10482
 
 
10483
    def SetAnimationStep(self, step):
 
10484
        """
 
10485
        Sets the animation step speed (a float) to use in :meth:`AnimateDocking`.
 
10486
 
 
10487
        :param float `step`: the animation speed.
 
10488
        """
 
10489
 
 
10490
        self._animation_step = float(step)
 
10491
 
 
10492
 
 
10493
    def RequestUserAttention(self, pane_window):
 
10494
        """
 
10495
        Requests the user attention by intermittently highlighting the pane caption.
 
10496
 
 
10497
        :param Window `pane_window`: the window managed by the pane;
 
10498
        """
 
10499
 
 
10500
        # try to find the pane
 
10501
        paneInfo = self.GetPane(pane_window)
 
10502
        if not paneInfo.IsOk():
 
10503
            raise Exception("Pane window not found")
 
10504
 
 
10505
        dc = wx.ClientDC(self._frame)
 
10506
 
 
10507
        # if the frame is about to be deleted, don't bother
 
10508
        if not self._frame or self._frame.IsBeingDeleted():
 
10509
            return
 
10510
 
 
10511
        if not self._frame.GetSizer():
 
10512
            return
 
10513
 
 
10514
        for part in self._uiparts:
 
10515
            if part.pane == paneInfo:
 
10516
                self._art.RequestUserAttention(dc, self._frame, part.pane.caption, part.rect, part.pane)
 
10517
                self._frame.RefreshRect(part.rect, True)
 
10518
                break
 
10519
 
 
10520
 
 
10521
    def StartPreviewTimer(self, toolbar):
 
10522
        """
 
10523
        Starts a timer for sliding in and out a minimized pane.
 
10524
 
 
10525
        :param `toolbar`: the :class:`~lib.agw.aui.auibar.AuiToolBar` containing the minimized pane tool.
 
10526
        """
 
10527
 
 
10528
        toolbar_pane = self.GetPane(toolbar)
 
10529
        toolbar_name = toolbar_pane.name
 
10530
 
 
10531
        pane_name = toolbar_name[0:-4]
 
10532
 
 
10533
        self._sliding_pane = self.GetPane(pane_name)
 
10534
        self._sliding_rect = toolbar.GetScreenRect()
 
10535
        self._sliding_direction = toolbar_pane.dock_direction
 
10536
        self._sliding_frame = None
 
10537
 
 
10538
        self._preview_timer.Start(1000, wx.TIMER_ONE_SHOT)
 
10539
 
 
10540
 
 
10541
    def StopPreviewTimer(self):
 
10542
        """ Stops a timer for sliding in and out a minimized pane. """
 
10543
 
 
10544
        if self._preview_timer.IsRunning():
 
10545
            self._preview_timer.Stop()
 
10546
 
 
10547
        self.SlideOut()
 
10548
        self._sliding_pane = None
 
10549
 
 
10550
 
 
10551
    def SlideIn(self, event):
 
10552
        """
 
10553
        Handles the ``wx.EVT_TIMER`` event for :class:`AuiManager`.
 
10554
 
 
10555
        :param `event`: a :class:`TimerEvent` to be processed.
 
10556
 
 
10557
        :note: This is used solely for sliding in and out minimized panes.
 
10558
        """
 
10559
 
 
10560
        window = self._sliding_pane.window
 
10561
        self._sliding_frame = wx.MiniFrame(None, -1, title=_("Pane Preview"),
 
10562
                                           style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
 
10563
                                           wx.FRAME_NO_TASKBAR | wx.CAPTION)
 
10564
        window.Reparent(self._sliding_frame)
 
10565
        self._sliding_frame.SetSize((0, 0))
 
10566
        window.Show()
 
10567
        self._sliding_frame.Show()
 
10568
 
 
10569
        size = window.GetBestSize()
 
10570
 
 
10571
        startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
 
10572
 
 
10573
        step = stopX/10
 
10574
        window_size = 0
 
10575
 
 
10576
        for i in xrange(0, stopX, step):
 
10577
            window_size = i
 
10578
            self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
 
10579
            self._sliding_frame.Refresh()
 
10580
            self._sliding_frame.Update()
 
10581
            wx.MilliSleep(10)
 
10582
 
 
10583
        self._sliding_frame.SetDimensions(startX, startY, stopX, stopY)
 
10584
        self._sliding_frame.Refresh()
 
10585
        self._sliding_frame.Update()
 
10586
 
 
10587
 
 
10588
    def SlideOut(self):
 
10589
        """
 
10590
        Slides out a preview of a minimized pane.
 
10591
 
 
10592
        :note: This is used solely for sliding in and out minimized panes.
 
10593
        """
 
10594
 
 
10595
        if not self._sliding_frame:
 
10596
            return
 
10597
 
 
10598
        window = self._sliding_frame.GetChildren()[0]
 
10599
        size = window.GetBestSize()
 
10600
 
 
10601
        startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
 
10602
 
 
10603
        step = stopX/10
 
10604
        window_size = 0
 
10605
 
 
10606
        for i in xrange(stopX, 0, -step):
 
10607
            window_size = i
 
10608
            self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
 
10609
            self._sliding_frame.Refresh()
 
10610
            self._sliding_frame.Update()
 
10611
            self._frame.RefreshRect(wx.Rect(startX+window_size, startY, step, stopY))
 
10612
            self._frame.Update()
 
10613
            wx.MilliSleep(10)
 
10614
 
 
10615
        self._sliding_frame.SetDimensions(startX, startY, 0, stopY)
 
10616
 
 
10617
        window.Hide()
 
10618
        window.Reparent(self._frame)
 
10619
 
 
10620
        self._sliding_frame.Hide()
 
10621
        self._sliding_frame.Destroy()
 
10622
        self._sliding_frame = None
 
10623
        self._sliding_pane = None
 
10624
 
 
10625
 
 
10626
class AuiManager_DCP(AuiManager):
 
10627
    """
 
10628
    A class similar to :class:`AuiManager` but with a Dummy Center Pane (**DCP**).
 
10629
    The code for this class is still flickery due to the call to :func:`CallAfter`
 
10630
    and the double-update call.
 
10631
    """
 
10632
 
 
10633
    def __init__(self, *args, **keys):
 
10634
        """ See :meth:`AuiManager.__init__` for the class construction. """
 
10635
 
 
10636
        AuiManager.__init__(self, *args, **keys)
 
10637
        self.hasDummyPane = False
 
10638
 
 
10639
 
 
10640
    def _createDummyPane(self):
 
10641
        """ Creates a Dummy Center Pane (**DCP**). """
 
10642
 
 
10643
        if self.hasDummyPane:
 
10644
            return
 
10645
 
 
10646
        self.hasDummyPane = True
 
10647
        dummy = wx.Panel(self.GetManagedWindow())
 
10648
        info = AuiPaneInfo().CenterPane().NotebookDockable(True).Name('dummyCenterPane').DestroyOnClose(True)
 
10649
        self.AddPane(dummy, info)
 
10650
 
 
10651
 
 
10652
    def _destroyDummyPane(self):
 
10653
        """ Destroys the Dummy Center Pane (**DCP**). """
 
10654
 
 
10655
        if not self.hasDummyPane:
 
10656
            return
 
10657
 
 
10658
        self.hasDummyPane = False
 
10659
        self.ClosePane(self.GetPane('dummyCenterPane'))
 
10660
 
 
10661
 
 
10662
    def Update(self):
 
10663
        """
 
10664
        This method is called after any number of changes are made to any of the
 
10665
        managed panes. :meth:`Update` must be invoked after :meth:`AuiManager.AddPane` or
 
10666
        :meth:`AuiManager.InsertPane` are called in order to "realize" or "commit" the changes.
 
10667
 
 
10668
        In addition, any number of changes may be made to :class:`AuiManager` structures
 
10669
        (retrieved with :meth:`AuiManager.GetPane`), but to realize the changes,
 
10670
        :meth:`Update` must be called. This construction allows pane flicker to
 
10671
        be avoided by updating the whole layout at one time.
 
10672
        """
 
10673
 
 
10674
        AuiManager.Update(self)
 
10675
 
 
10676
        # check if there's already a center pane (except our dummy pane)
 
10677
        dummyCenterPane = self.GetPane('dummyCenterPane')
 
10678
        haveCenterPane = any((pane != dummyCenterPane) and (pane.dock_direction == AUI_DOCK_CENTER) and
 
10679
                             not pane.IsFloating() and pane.IsShown() for pane in self.GetAllPanes())
 
10680
        if haveCenterPane:
 
10681
            if self.hasDummyPane:
 
10682
                # there's our dummy pane and also another center pane, therefor let's remove our dummy
 
10683
                def do():
 
10684
                    self._destroyDummyPane()
 
10685
                    self.Update()
 
10686
                wx.CallAfter(do)
 
10687
        else:
 
10688
            # if we get here, there's no center pane, create our dummy
 
10689
            if not self.hasDummyPane:
 
10690
                self._createDummyPane()
 
10691
 
 
10692