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