remove numpy + matrix
authorPierre <ratinaud@univ-tlse2.fr>
Sat, 12 Jan 2013 23:23:12 +0000 (00:23 +0100)
committerPierre <ratinaud@univ-tlse2.fr>
Sat, 12 Jan 2013 23:23:12 +0000 (00:23 +0100)
35 files changed:
OptionAlceste.py
PrintRScript.py
ProfList.py
Rscripts/chdfunct.R
analysematrix.py [new file with mode: 0644]
analysetxt.py
aui/__init__.py [new file with mode: 0644]
aui/aui_constants.py [new file with mode: 0644]
aui/aui_switcherdialog.py [new file with mode: 0644]
aui/aui_utilities.py [new file with mode: 0644]
aui/auibar.py [new file with mode: 0644]
aui/auibook.py [new file with mode: 0644]
aui/dockart.py [new file with mode: 0644]
aui/framemanager.py [new file with mode: 0644]
aui/tabart.py [new file with mode: 0644]
aui/tabmdi.py [new file with mode: 0644]
chemins.py
corpus.py
functions.py
iramuteq.py
layout.py
listlex.py
openanalyse.py
profile_segment.py
tabchdalc.py
tabchddist.py
tableau.py
tabsimi.py
tabstudent.py
textaslexico.py
textsimi.py
textstat.py
tools.py [new file with mode: 0644]
tree.py
ttparser.py

index 6465e29..49ff0f1 100755 (executable)
@@ -21,8 +21,8 @@ class OptionAlc(wx.Dialog):
         self.AlcesteConf = parametres
         self.choose = False
         
-        self.label_1 = wx.StaticText(self, -1, u"Lemmatisation")
-        self.radio_1 = wx.RadioBox(self, -1, u"", choices=['oui', 'non'], majorDimension=0, style=wx.RA_SPECIFY_ROWS)
+        #self.label_1 = wx.StaticText(self, -1, u"Lemmatisation")
+        #self.radio_1 = wx.RadioBox(self, -1, u"", choices=['oui', 'non'], majorDimension=0, style=wx.RA_SPECIFY_ROWS)
 
         self.label_12 = wx.StaticText(self, -1, u"Classification")
         self.radio_box_2 = wx.RadioBox(self, -1, u"", choices=[u"double sur UC", u"simple sur UCE", u"simple sur UCI"], majorDimension=0, style=wx.RA_SPECIFY_ROWS) #, u"simple sur UCE (non implemente)"
@@ -42,8 +42,8 @@ analysée (2 = automatique)"""
         self.spin_ctrl_5 = wx.SpinCtrl(self, -1, "",size = (100,30), min=2, max=1000)
         self.label_max_actives =  wx.StaticText(self, -1, u"Nombre maximum de formes analysées")
         self.spin_max_actives = wx.SpinCtrl(self, -1, "",size = (100,30), min=20, max=10000)
-        self.label_4 = wx.StaticText(self, -1, u"Configuration \ndes clés d'analyse")
-        self.button_5 = wx.Button(self, wx.ID_PREFERENCES, "")
+        #self.label_4 = wx.StaticText(self, -1, u"Configuration \ndes clés d'analyse")
+        #self.button_5 = wx.Button(self, wx.ID_PREFERENCES, "")
         self.button_1 = wx.Button(self, wx.ID_CANCEL, "")
         self.button_2 = wx.Button(self, wx.ID_DEFAULT, u"Valeurs par défaut")
         self.button_4 = wx.Button(self, wx.ID_OK, "")
@@ -52,18 +52,18 @@ analysée (2 = automatique)"""
         self.__set_properties()
         self.__do_layout()
 
-        self.Bind(wx.EVT_BUTTON, self.OnKeyPref, self.button_5)
+        #self.Bind(wx.EVT_BUTTON, self.OnKeyPref, self.button_5)
         self.Bind(wx.EVT_BUTTON, self.OnDef, self.button_2)
         
     def __set_properties(self):
         self.SetTitle("Options")
         #lang = self.AlcesteConf.get('ALCESTE', 'lang')
         #self.choice_dict.SetSelection(self.langues.index(lang))
-        DefaultLem = self.parametres['lem']
-        if DefaultLem :
-            self.radio_1.SetSelection(0)
-        else:
-            self.radio_1.SetSelection(1)
+        #DefaultLem = self.parametres['lem']
+        #if DefaultLem :
+        #    self.radio_1.SetSelection(0)
+        #else:
+        #    self.radio_1.SetSelection(1)
         self.radio_box_2.SetSelection(int(self.parametres['classif_mode']))
         self.spin_ctrl_1.SetValue(int(self.parametres['tailleuc1']))
         self.spin_ctrl_2.SetValue(int(self.parametres['tailleuc2']))
@@ -82,10 +82,10 @@ analysée (2 = automatique)"""
         #grid_sizer2.Add(self.label_dict, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
         #grid_sizer2.Add(self.choice_dict, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
 
-        grid_sizer2.Add(self.label_1, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
-        grid_sizer2.Add(self.radio_1, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
-        grid_sizer2.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 1)
-        grid_sizer2.Add(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, 1)
+        #grid_sizer2.Add(self.label_1, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
+        #grid_sizer2.Add(self.radio_1, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
+        #grid_sizer2.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 1)
+        #grid_sizer2.Add(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, 1)
 
         grid_sizer2.Add(self.label_12, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
         grid_sizer2.Add(self.radio_box_2, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
@@ -122,10 +122,10 @@ analysée (2 = automatique)"""
         grid_sizer2.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 1)
         grid_sizer2.Add(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, 1)
        
-        grid_sizer2.Add(self.label_4, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
-        grid_sizer2.Add(self.button_5, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
-        grid_sizer2.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 1)
-        grid_sizer2.Add(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, 1)
+        #grid_sizer2.Add(self.label_4, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
+        #grid_sizer2.Add(self.button_5, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 0)
+        #grid_sizer2.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.ALL, 1)
+        #grid_sizer2.Add(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, 1)
         
         grid_button.Add(self.button_1, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
         grid_button.Add(self.button_2, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
index db2eeac..9a92096 100644 (file)
@@ -275,7 +275,7 @@ def RchdQuest(DicoPath, RscriptPath, nbcl = 10, mincl = 10):
     chd.result<-Rchdquest("%s","%s","%s", nbt = nbt, mincl = mincl)
     n1 <- chd.result$n1
     classeuce1 <- chd.result$cuce1
-    """ % (DicoPath['Act01'], DicoPath['listeuce1'], DicoPath['uce'])
+    """ % (DicoPath['mat01'], DicoPath['listeuce1'], DicoPath['uce'])
     
     txt += """
     tree_tot1 <- make_tree_tot(chd.result$chd)
index db822cf..600dbcf 100644 (file)
@@ -49,13 +49,17 @@ class ProfListctrlPanel(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.Col
             self.lenact = profclasse.index([u'*****', u'*', u'*', u'*', u'*', u'*', '', ''])
             profclasse.pop(self.lenact)
         except ValueError:
-            self.lenact = len(profclasse)
+            try :
+                self.lenact = profclasse.index([u'*', u'*', u'*', u'*', u'*', u'*', '', ''])
+                profclasse.pop(self.lenact)
+            except ValueError:
+                self.lenact = len(profclasse)
         try :
             self.lensup = profclasse.index([u'*', u'*', u'*', u'*', u'*', u'*', '', ''])
             self.lensup = self.lensup - self.lenact
             profclasse.pop(self.lensup)
         except ValueError: 
-            self.lensup = 0
+            self.lensup = len(profclasse) - self.lenact
         self.lenet = len(profclasse) - (self.lenact + self.lensup)
 #        print self.lenact, self.lensup, self.lenet
         for i,  line in enumerate(classen) :
index dd86dc1..a2dc502 100644 (file)
@@ -293,95 +293,12 @@ AsLexico2<- function(mat, chip = FALSE) {
     out
 }
 
-
-##from textometrieR
-##http://txm.sourceforge.net/doc/R/textometrieR-package.html
-##Sylvain Loiseau
-#specificites.probabilities <- function (lexicaltable, types = NULL, parts = NULL) 
-#{
-#    rowMargin <- rowSums(lexicaltable)
-#    colMargin <- colSums(lexicaltable)
-#    F <- sum(lexicaltable)
-#    if (!is.null(types)) {
-#        if (is.character(types)) {
-#            if (is.null(rownames(lexicaltable))) 
-#                stop("The lexical table has no row names and the \"types\" argument is a character vector.")
-#            if (!all(types %in% rownames(lexicaltable))) 
-#                stop(paste("Some requested types are not known in the lexical table: ", 
-#                  paste(types[!(types %in% rownames(lexicaltable))], 
-#                    collapse = " ")))
-#        }
-#        else {
-#            if (any(types < 1)) 
-#                stop("The row index must be greater than 0.")
-#            if (max(types) > nrow(lexicaltable)) 
-#                stop("Row index must be smaller than the number of rows.")
-#        }
-#        lexicaltable <- lexicaltable[types, , drop = FALSE]
-#        rowMargin <- rowMargin[types]
-#    }
-#    if (!is.null(parts)) {
-#        if (is.character(parts)) {
-#            if (is.null(colnames(lexicaltable))) 
-#                stop("The lexical table has no col names and the \"parts\" argument is a character vector.")
-#            if (!all(parts %in% colnames(lexicaltable))) 
-#                stop(paste("Some requested parts are not known in the lexical table: ", 
-#                  paste(parts[!(parts %in% colnames(lexicaltable))], 
-#                    collapse = " ")))
-#        }
-#        else {
-#            if (max(parts) > ncol(lexicaltable)) 
-#                stop("Column index must be smaller than the number of cols.")
-#            if (any(parts < 1)) 
-#                stop("The col index must be greater than 0.")
-#        }
-#        lexicaltable <- lexicaltable[, parts, drop = FALSE]
-#        colMargin <- colMargin[parts]
-#    }
-#    if (nrow(lexicaltable) == 0 | ncol(lexicaltable) == 0) {
-#        stop("The lexical table must contains at least one row and one column.")
-#    }
-#    specif <- matrix(0, nrow = nrow(lexicaltable), ncol = ncol(lexicaltable))
-#    for (i in 1:ncol(lexicaltable)) {
-#        whiteDrawn <- lexicaltable[, i]
-#        white <- rowMargin
-#        black <- F - white
-#        drawn <- colMargin[i]
-#        independance <- (white * drawn)/F
-#        specif_negative <- whiteDrawn < independance
-#        specif_positive <- whiteDrawn >= independance
-#        specif[specif_negative, i] <- phyper(whiteDrawn[specif_negative], 
-#            white[specif_negative], black[specif_negative], drawn)
-#        specif[specif_positive, i] <- phyper(whiteDrawn[specif_positive] - 
-#            1, white[specif_positive], black[specif_positive], 
-#            drawn)
-#    }
-#    dimnames(specif) <- dimnames(lexicaltable)
-#    return(specif)
-#}
-#
-##from textometrieR
-##http://txm.sourceforge.net/doc/R/textometrieR-package.html
-##Sylvain Loiseau
-#specificites <- function (lexicaltable, types = NULL, parts = NULL) 
-#{
-#    spe <- specificites.probabilities(lexicaltable, types, parts)
-#    spelog <- matrix(0, nrow = nrow(spe), ncol = ncol(spe))
-#    spelog[spe < 0.5] <- log10(spe[spe < 0.5])
-#    spelog[spe > 0.5] <- abs(log10(1 - spe[spe > 0.5]))
-#    spelog[spe == 0.5] <- 0
-#    spelog[is.infinite(spe)] <- 0
-#    spelog <- round(spelog, digits = 4)
-#    rownames(spelog) <- rownames(spe)
-#    colnames(spelog) <- colnames(spe)
-#    return(spelog)
-#}
-
 make.spec.hypergeo <- function(mat) {
     library(textometrieR)
     spec <- specificites(mat)
        sumcol<-colSums(mat)
     eff_relatif<-round(t(apply(mat,1,function(x) {(x/t(as.matrix(sumcol))*1000)})),2)
+    colnames(eff_relatif) <- colnames(mat)
     out <-list()
     out[[1]]<-spec
     out[[3]]<-eff_relatif
diff --git a/analysematrix.py b/analysematrix.py
new file mode 100644 (file)
index 0000000..1a14c4a
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/env python
+# -*- coding: utf-8 -*-
+#Author: Pierre Ratinaud
+#Copyright (c) 2013 Pierre Ratinaud
+#Lisense: GNU GPL
+
+
+
+import logging
+import os
+from time import time
+from uuid import uuid4
+
+
+from chemins import PathOut
+from functions import exec_rcode, check_Rresult, DoConf
+from time import time, sleep
+from openanalyse import OpenAnalyse
+
+class AnalyseMatrix :
+    def __init__(self, ira, tableau, parametres = None, dlg = False) :
+        self.tableau = tableau
+        self.ira = ira
+        self.parent = ira
+        self.dlg = dlg
+        self.parametres = parametres
+        self.val = False
+        if not 'pathout' in self.parametres :
+            self.pathout = PathOut(tableau.parametres['filename'], analyse_type = parametres['type'], dirout = parametres['pathout'])
+        else :
+            self.pathout = PathOut(filename = tableau.parametres['filename'], dirout = self.parametres['pathout'], analyse_type = self.parametres['type'])
+
+        self.parametres['pathout'] = self.pathout.dirout
+        self.parametres['uuid'] = str(uuid4())
+        self.parametres['name'] = os.path.split(self.parametres['pathout'])[1]
+        self.parametres['encoding'] = self.ira.syscoding
+
+        self.t1 = time()
+        result_analyse = self.doanalyse()
+        if result_analyse is None :
+            self.time = time() - self.t1
+            minutes, seconds = divmod(self.time, 60)
+            hours, minutes = divmod(minutes, 60)            
+            self.parametres['time'] = '%.0fh %.0fm %.0fs' % (hours, minutes, seconds)
+            self.parametres['ira'] = self.pathout['Analyse.ira']
+            DoConf().makeoptions([self.parametres['type']], [self.parametres], self.pathout['Analyse.ira'])
+            self.ira.history.addMatrix(self.parametres)
+            if dlg :
+                dlg.Destroy()
+                OpenAnalyse(self.parent, self.parametres['ira'])
+                #self.ira.tree.AddAnalyse(self.parametres)
+                self.val = 5100
+        else :
+            self.val = False
+            if dlg :
+                dlg.Destroy()
+    def doanalyse(self) :
+        pass
+        
index 3edf0a9..db69d01 100644 (file)
@@ -13,6 +13,7 @@ from PrintRScript import RchdTxt, AlcesteTxtProf
 from OptionAlceste import OptionAlc 
 from layout import PrintRapport
 from openanalyse import OpenAnalyse
+from dialog import StatDialog
 from time import time
 
 log = logging.getLogger('iramuteq.analyse')
@@ -30,15 +31,14 @@ class AnalyseText :
             self.pathout = PathOut(corpus.parametres['originalpath'], analyse_type = parametres['type'], dirout = corpus.parametres['pathout'])
         else :
             self.pathout = PathOut(filename = corpus.parametres['originalpath'], dirout = self.parametres['pathout'], analyse_type = self.parametres['name'])
-        self.parametres = self.make_config(parametres)
+        self.parametres = self.lemparam()
+        if self.parametres is not None :
+            self.parametres = self.make_config(parametres)
         log.info(self.pathout.dirout)
         if self.parametres is not None :
             self.keys = DoConf(self.ira.ConfigPath['key']).getoptions()
             gramact = [k for k in keys if keys[k] == 1]
             gramsup = [k for k in keys if keys[k] == 2]
-            #FIXME
-            if not 'lem' in self.parametres :
-                self.parametres['lem'] = 1
             self.parametres['pathout'] = self.pathout.mkdirout()
             self.pathout = PathOut(dirout = self.parametres['pathout'])
             self.pathout.createdir(self.parametres['pathout'])
@@ -76,18 +76,39 @@ class AnalyseText :
     def doanalyse(self) :
         pass
 
+    def lemparam(self) :
+        if self.dlg :
+            dial = StatDialog(self, self.parent)
+            dial.CenterOnParent()
+            val = dial.ShowModal()
+            if val == 5100 :
+                if dial.radio_lem.GetSelection() == 0 :
+                    lem = 1
+                else :
+                    lem = 0            
+                self.parametres['lem'] = lem
+                dial.Destroy()
+                return self.parametres
+            else :
+                dial.Destroy()
+                return None        
+        else :
+            return self.parametres
+
     def make_config(self, config) :
         if config is not None :
             if not self.dlg : 
                 return config
             else :
                 return self.preferences()
+        else :
+            return None
 
     def readconfig(self, config) :
         return config
 
     def preferences(self) :
-        return {}
+        return self.parametres
 
     def printRscript(self) :
         pass
@@ -159,8 +180,6 @@ class Alceste(AnalyseText) :
             parametres['max_actives'] = self.dial.spin_max_actives.GetValue()
             parametres['corpus'] = ''
             parametres['pathout'] = self.pathout.dirout
-            for val in parametres :
-                print val, parametres[val]
             DoConf(self.parent.ConfigPath['alceste']).makeoptions(['ALCESTE'], [parametres])
             self.dial.Destroy()
             return parametres
diff --git a/aui/__init__.py b/aui/__init__.py
new file mode 100644 (file)
index 0000000..ba3b51d
--- /dev/null
@@ -0,0 +1,290 @@
+"""
+AUI is an Advanced User Interface library that aims to implement "cutting-edge"
+interface usability and design features so developers can quickly and easily create
+beautiful and usable application interfaces.
+
+
+Vision and Design Principles
+============================
+
+AUI attempts to encapsulate the following aspects of the user interface:
+
+* **Frame Management**: Frame management provides the means to open, move and hide common
+  controls that are needed to interact with the document, and allow these configurations
+  to be saved into different perspectives and loaded at a later time. 
+
+* **Toolbars**: Toolbars are a specialized subset of the frame management system and should
+  behave similarly to other docked components. However, they also require additional
+  functionality, such as "spring-loaded" rebar support, "chevron" buttons and end-user
+  customizability. 
+
+* **Modeless Controls**: Modeless controls expose a tool palette or set of options that
+  float above the application content while allowing it to be accessed. Usually accessed
+  by the toolbar, these controls disappear when an option is selected, but may also be
+  "torn off" the toolbar into a floating frame of their own. 
+
+* **Look and Feel**: Look and feel encompasses the way controls are drawn, both when shown
+  statically as well as when they are being moved. This aspect of user interface design
+  incorporates "special effects" such as transparent window dragging as well as frame animation. 
+
+AUI adheres to the following principles:
+
+- Use native floating frames to obtain a native look and feel for all platforms;
+- Use existing wxPython code where possible, such as sizer implementation for frame management; 
+- Use standard wxPython coding conventions.
+
+
+Usage
+=====
+
+The following example shows a simple implementation that uses L{AuiManager} to manage
+three text controls in a frame window::
+
+    class MyFrame(wx.Frame):
+
+        def __init__(self, parent, id=-1, title="AUI Test", pos=wx.DefaultPosition,
+                     size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
+
+            wx.Frame.__init__(self, parent, id, title, pos, size, style)
+
+            self._mgr = aui.AuiManager()
+            
+            # notify AUI which frame to use
+            self._mgr.SetManagedWindow(self)
+
+            # create several text controls
+            text1 = wx.TextCtrl(self, -1, "Pane 1 - sample text",
+                                wx.DefaultPosition, wx.Size(200,150),
+                                wx.NO_BORDER | wx.TE_MULTILINE)
+                                               
+            text2 = wx.TextCtrl(self, -1, "Pane 2 - sample text",
+                                wx.DefaultPosition, wx.Size(200,150),
+                                wx.NO_BORDER | wx.TE_MULTILINE)
+                                               
+            text3 = wx.TextCtrl(self, -1, "Main content window",
+                                wx.DefaultPosition, wx.Size(200,150),
+                                wx.NO_BORDER | wx.TE_MULTILINE)
+            
+            # add the panes to the manager
+            self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
+            self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
+            self._mgr.AddPane(text3, AuiPaneInfo().CenterPane())
+                                  
+            # tell the manager to "commit" all the changes just made
+            self._mgr.Update()
+
+            self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+
+        def OnClose(self, event):
+
+            # deinitialize the frame manager
+            self._mgr.UnInit()
+
+            self.Destroy()        
+            event.Skip()        
+
+
+    # our normal wxApp-derived class, as usual
+
+    app = wx.PySimpleApp()
+
+    frame = MyFrame(None)
+    app.SetTopWindow(frame)
+    frame.Show()
+
+    app.MainLoop()
+
+
+What's New
+==========
+
+Current wxAUI Version Tracked: wxWidgets 2.9.0 (SVN HEAD)
+
+The wxPython AUI version fixes the following bugs or implement the following
+missing features (the list is not exhaustive):
+
+- Visual Studio 2005 style docking: http://www.kirix.com/forums/viewtopic.php?f=16&t=596
+- Dock and Pane Resizing: http://www.kirix.com/forums/viewtopic.php?f=16&t=582 
+- Patch concerning dock resizing: http://www.kirix.com/forums/viewtopic.php?f=16&t=610 
+- Patch to effect wxAuiToolBar orientation switch: http://www.kirix.com/forums/viewtopic.php?f=16&t=641 
+- AUI: Core dump when loading a perspective in wxGTK (MSW OK): http://www.kirix.com/forums/viewtopic.php?f=15&t=627 
+- wxAuiNotebook reordered AdvanceSelection(): http://www.kirix.com/forums/viewtopic.php?f=16&t=617 
+- Vertical Toolbar Docking Issue: http://www.kirix.com/forums/viewtopic.php?f=16&t=181 
+- Patch to show the resize hint on mouse-down in aui: http://trac.wxwidgets.org/ticket/9612 
+- The Left/Right and Top/Bottom Docks over draw each other: http://trac.wxwidgets.org/ticket/3516 
+- MinSize() not honoured: http://trac.wxwidgets.org/ticket/3562 
+- Layout problem with wxAUI: http://trac.wxwidgets.org/ticket/3597 
+- Resizing children ignores current window size: http://trac.wxwidgets.org/ticket/3908 
+- Resizing panes under Vista does not repaint background: http://trac.wxwidgets.org/ticket/4325 
+- Resize sash resizes in response to click: http://trac.wxwidgets.org/ticket/4547 
+- "Illegal" resizing of the AuiPane? (wxPython): http://trac.wxwidgets.org/ticket/4599 
+- Floating wxAUIPane Resize Event doesn't update its position: http://trac.wxwidgets.org/ticket/9773
+- Don't hide floating panels when we maximize some other panel: http://trac.wxwidgets.org/ticket/4066 
+- wxAUINotebook incorrect ALLOW_ACTIVE_PANE handling: http://trac.wxwidgets.org/ticket/4361 
+- Page changing veto doesn't work, (patch supplied): http://trac.wxwidgets.org/ticket/4518 
+- Show and DoShow are mixed around in wxAuiMDIChildFrame: http://trac.wxwidgets.org/ticket/4567 
+- wxAuiManager & wxToolBar - ToolBar Of Size Zero: http://trac.wxwidgets.org/ticket/9724 
+- wxAuiNotebook doesn't behave properly like a container as far as...: http://trac.wxwidgets.org/ticket/9911
+- Serious layout bugs in wxAUI: http://trac.wxwidgets.org/ticket/10620
+- wAuiDefaultTabArt::Clone() should just use copy contructor: http://trac.wxwidgets.org/ticket/11388
+- Drop down button for check tool on wxAuiToolbar: http://trac.wxwidgets.org/ticket/11139
+
+Plus the following features:
+
+- AuiManager:
+
+  (a) Implementation of a simple minimize pane system: Clicking on this minimize button causes a new
+      AuiToolBar to be created and added to the frame manager, (currently the implementation is such
+      that panes at West will have a toolbar at the right, panes at South will have toolbars at the
+      bottom etc...) and the pane is hidden in the manager.
+      Clicking on the restore button on the newly created toolbar will result in the toolbar being
+      removed and the original pane being restored;
+  (b) Panes can be docked on top of each other to form `AuiNotebooks`; `AuiNotebooks` tabs can be torn
+      off to create floating panes;
+  (c) On Windows XP, use the nice sash drawing provided by XP while dragging the sash;
+  (d) Possibility to set an icon on docked panes;
+  (e) Possibility to draw a sash visual grip, for enhanced visualization of sashes;
+  (f) Implementation of a native docking art (`ModernDockArt`). Windows XP only, **requires** Mark Hammond's
+      pywin32 package (winxptheme);
+  (g) Possibility to set a transparency for floating panes (a la Paint .NET);
+  (h) Snapping the main frame to the screen in any positin specified by horizontal and vertical
+      alignments;
+  (i) Snapping floating panes on left/right/top/bottom or any combination of directions, a la Winamp;
+  (j) "Fly-out" floating panes, i.e. panes which show themselves only when the mouse hover them;
+  (k) Ability to set custom bitmaps for pane buttons (close, maximize, etc...);
+  (l) Implementation of the style ``AUI_MGR_ANIMATE_FRAMES``, which fade-out floating panes when
+      they are closed (all platforms which support frames transparency) and show a moving rectangle
+      when they are docked and minimized (Windows < Vista and GTK only);
+  (m) A pane switcher dialog is available to cycle through existing AUI panes;
+  (n) Some flags which allow to choose the orientation and the position of the minimized panes;
+  (o) The functions [Get]MinimizeMode() in `AuiPaneInfo` which allow to set/get the flags described above;
+  (p) Events like ``EVT_AUI_PANE_DOCKING``, ``EVT_AUI_PANE_DOCKED``, ``EVT_AUI_PANE_FLOATING`` and ``EVT_AUI_PANE_FLOATED`` are
+      available for all panes *except* toolbar panes;
+  (q) Implementation of the RequestUserAttention method for panes;
+  (r) Ability to show the caption bar of docked panes on the left instead of on the top (with caption
+      text rotated by 90 degrees then). This is similar to what `wxDockIt` did. To enable this feature on any
+      given pane, simply call `CaptionVisible(True, left=True)`;
+  (s) New Aero-style docking guides: you can enable them by using the `AuiManager` style ``AUI_MGR_AERO_DOCKING_GUIDES``;
+  (t) A slide-in/slide-out preview of minimized panes can be seen by enabling the `AuiManager` style
+      ``AUI_MGR_PREVIEW_MINIMIZED_PANES`` and by hovering with the mouse on the minimized pane toolbar tool;
+  (u) New Whidbey-style docking guides: you can enable them by using the `AuiManager` style ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``;
+  (v) Native of custom-drawn mini frames can be used as floating panes, depending on the ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style;
+  (w) A "smooth docking effect" can be obtained by using the ``AUI_MGR_SMOOTH_DOCKING`` style (similar to PyQT docking style).
+  
+|
+
+- AuiNotebook:
+
+  (a) Implementation of the style ``AUI_NB_HIDE_ON_SINGLE_TAB``, a la `wx.lib.agw.flatnotebook`;
+  (b) Implementation of the style ``AUI_NB_SMART_TABS``, a la `wx.lib.agw.flatnotebook`;
+  (c) Implementation of the style ``AUI_NB_USE_IMAGES_DROPDOWN``, which allows to show tab images
+      on the tab dropdown menu instead of bare check menu items (a la `wx.lib.agw.flatnotebook`);
+  (d) 6 different tab arts are available, namely:
+  
+      (1) Default "glossy" theme (as in `wx.aui.AuiNotebook`)
+      (2) Simple theme (as in `wx.aui.AuiNotebook`)
+      (3) Firefox 2 theme
+      (4) Visual Studio 2003 theme (VC71)
+      (5) Visual Studio 2005 theme (VC81)
+      (6) Google Chrome theme
+
+  (e) Enabling/disabling tabs;
+  (f) Setting the colour of the tab's text;
+  (g) Implementation of the style ``AUI_NB_CLOSE_ON_TAB_LEFT``, which draws the tab close button on
+      the left instead of on the right (a la Camino browser);
+  (h) Ability to save and load perspectives in `AuiNotebook` (experimental);
+  (i) Possibility to add custom buttons in the `AuiNotebook` tab area;
+  (j) Implementation of the style ``AUI_NB_TAB_FLOAT``, which allows the floating of single tabs.
+      Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far
+      enough outside of the notebook to become floating pages;
+  (k) Implementation of the style ``AUI_NB_DRAW_DND_TAB`` (on by default), which draws an image
+      representation of a tab while dragging;
+  (l) Implementation of the `AuiNotebook` unsplit functionality, which unsplit a splitted AuiNotebook
+      when double-clicking on a sash;
+  (m) Possibility to hide all the tabs by calling `HideAllTAbs`;
+  (n) wxPython controls can now be added inside page tabs by calling `AddControlToPage`, and they can be
+      removed by calling `RemoveControlFromPage`;
+  (o) Possibility to preview all the pages in a `AuiNotebook` (as thumbnails) by using the `NotebookPreview`
+      method of `AuiNotebook`;
+  (p) Tab labels can be edited by calling the `SetRenamable` method on a `AuiNotebook` page;
+  (q) Support for multi-lines tab labels in `AuiNotebook`;
+  (r) Support for setting minimum and maximum tab widths for fixed width tabs;
+  (s) Implementation of the style ``AUI_NB_ORDER_BY_ACCESS``, which orders the tabs by last access time
+      inside the Tab Navigator dialog;
+  (t) Implementation of the style ``AUI_NB_NO_TAB_FOCUS``, allowing the developer not to draw the tab
+      focus rectangle on tne `AuiNotebook` tabs.
+
+|
+
+- AuiToolBar:
+
+  (a) ``AUI_TB_PLAIN_BACKGROUND`` style that allows to easy setup a plain background to the AUI toolbar,
+      without the need to override drawing methods. This style contrasts with the default behaviour
+      of the `wx.aui.AuiToolBar` that draws a background gradient and this break the window design when
+      putting it within a control that has margin between the borders and the toolbar (example: put
+      `wx.aui.AuiToolBar` within a `wx.StaticBoxSizer` that has a plain background);
+  (b) `AuiToolBar` allow item alignment: http://trac.wxwidgets.org/ticket/10174;
+  (c) `AUIToolBar` `DrawButton()` improvement: http://trac.wxwidgets.org/ticket/10303;
+  (d) `AuiToolBar` automatically assign new id for tools: http://trac.wxwidgets.org/ticket/10173;
+  (e) `AuiToolBar` Allow right-click on any kind of button: http://trac.wxwidgets.org/ticket/10079;
+  (f) `AuiToolBar` idle update only when visible: http://trac.wxwidgets.org/ticket/10075;
+  (g) Ability of creating `AuiToolBar` tools with [counter]clockwise rotation. This allows to propose a
+      variant of the minimizing functionality with a rotated button which keeps the caption of the pane
+      as label;
+  (h) Allow setting the alignment of all tools in a toolbar that is expanded.
+
+
+TODOs
+=====
+
+- Documentation, documentation and documentation;
+- Fix `tabmdi.AuiMDIParentFrame` and friends, they do not work correctly at present;
+- Allow specification of `CaptionLeft()` to `AuiPaneInfo` to show the caption bar of docked panes
+  on the left instead of on the top (with caption text rotated by 90 degrees then). This is
+  similar to what `wxDockIt` did - DONE;
+- Make developer-created `AuiNotebooks` and automatic (framemanager-created) `AuiNotebooks` behave
+  the same way (undocking of tabs) - DONE, to some extent;
+- Find a way to dock panes in already floating panes (`AuiFloatingFrames`), as they already have
+  their own `AuiManager`;
+- Add more gripper styles (see, i.e., PlusDock 4.0);
+- Add an "AutoHide" feature to docked panes, similar to fly-out floating panes (see, i.e., PlusDock 4.0);
+- Add events for panes when they are about to float or to be docked (something like
+  ``EVT_AUI_PANE_FLOATING/ED`` and ``EVT_AUI_PANE_DOCKING/ED``) - DONE, to some extent;
+- Implement the 4-ways splitter behaviour for horizontal and vertical sashes if they intersect;
+- Extend `tabart.py` with more aui tab arts;
+- Implement ``AUI_NB_LEFT`` and ``AUI_NB_RIGHT`` tab locations in `AuiNotebook`;
+- Move `AuiDefaultToolBarArt` into a separate module (as with `tabart.py` and `dockart.py`) and
+  provide more arts for toolbars (maybe from `wx.lib.agw.flatmenu`?)
+- Support multiple-rows/multiple columns toolbars;
+- Integrate as much as possible with `wx.lib.agw.flatmenu`, from dropdown menus in `AuiNotebook` to
+  toolbars and menu positioning;
+- Possibly handle minimization of panes in a different way (or provide an option to switch to
+  another way of minimizing panes);
+- Clean up/speed up the code, especially time-consuming for-loops;
+- Possibly integrate `wxPyRibbon` (still on development), at least on Windows.
+
+
+License And Version
+===================
+
+AUI library is distributed under the wxPython license. 
+
+Latest revision: Andrea Gavana @ 21 Jun 2011, 22.00 GMT
+
+Version 1.3. 
+
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+from aui_constants import *
+from aui_utilities import *
+from auibar import *
+from auibook import *
+from tabart import *
+from dockart import *
+from framemanager import *
+from tabmdi import *
diff --git a/aui/aui_constants.py b/aui/aui_constants.py
new file mode 100644 (file)
index 0000000..38f183d
--- /dev/null
@@ -0,0 +1,2588 @@
+"""
+This module contains all the constants used by wxPython-AUI.
+
+Especially important and meaningful are constants for AuiManager, AuiDockArt and
+AuiNotebook.
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+from wx.lib.embeddedimage import PyEmbeddedImage
+
+# ------------------------- #
+# - AuiNotebook Constants - #
+# ------------------------- #
+
+# For tabart
+# --------------
+
+vertical_border_padding = 4
+""" Border padding used in drawing tabs. """
+
+if wx.Platform == "__WXMAC__":
+    nb_close_bits = "\xFF\xFF\xFF\xFF\x0F\xFE\x03\xF8\x01\xF0\x19\xF3" \
+                    "\xB8\xE3\xF0\xE1\xE0\xE0\xF0\xE1\xB8\xE3\x19\xF3" \
+                    "\x01\xF0\x03\xF8\x0F\xFE\xFF\xFF"
+    """ AuiNotebook close button image on wxMAC. """
+    
+elif wx.Platform == "__WXGTK__":
+    nb_close_bits = "\xff\xff\xff\xff\x07\xf0\xfb\xef\xdb\xed\x8b\xe8" \
+                    "\x1b\xec\x3b\xee\x1b\xec\x8b\xe8\xdb\xed\xfb\xef" \
+                    "\x07\xf0\xff\xff\xff\xff\xff\xff"
+    """ AuiNotebook close button image on wxGTK. """
+    
+else:
+    nb_close_bits = "\xff\xff\xff\xff\xff\xff\xff\xff\xe7\xf3\xcf\xf9" \
+                    "\x9f\xfc\x3f\xfe\x3f\xfe\x9f\xfc\xcf\xf9\xe7\xf3" \
+                    "\xff\xff\xff\xff\xff\xff\xff\xff"
+    """ AuiNotebook close button image on wxMSW. """
+
+nb_left_bits = "\xff\xff\xff\xff\xff\xff\xff\xfe\x7f\xfe\x3f\xfe\x1f" \
+               "\xfe\x0f\xfe\x1f\xfe\x3f\xfe\x7f\xfe\xff\xfe\xff\xff" \
+               "\xff\xff\xff\xff\xff\xff"
+""" AuiNotebook left button image. """
+
+nb_right_bits = "\xff\xff\xff\xff\xff\xff\xdf\xff\x9f\xff\x1f\xff\x1f" \
+                "\xfe\x1f\xfc\x1f\xfe\x1f\xff\x9f\xff\xdf\xff\xff\xff" \
+                "\xff\xff\xff\xff\xff\xff"
+""" AuiNotebook right button image. """
+
+nb_list_bits = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x0f" \
+               "\xf8\xff\xff\x0f\xf8\x1f\xfc\x3f\xfe\x7f\xff\xff\xff" \
+               "\xff\xff\xff\xff\xff\xff"
+""" AuiNotebook windows list button image. """
+
+
+#----------------------------------------------------------------------
+tab_active_center = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAbCAYAAAC9WOV0AAAABHNCSVQICAgIfAhkiAAAADNJ"
+    "REFUCJltzMEJwDAUw9DHX6OLdP/Bop4KDc3F2EIYrsFtrZow8GnH6OD1zvRTajvY2QMHIhNx"
+    "jUhuAgAAAABJRU5ErkJggg==")
+""" Center active tab image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_active_left = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAglJ"
+    "REFUOI2Nkk9rE0EYh5/J7mpW06xE2iSmeFHxEoqIAc/FQ5CKgn4DP4KlIQG/QVsQbBEKgop+"
+    "Anvy4rV4bLT2JCGJPVXqwaZJd+f1kN26WTfJDrzszDLPPL/5o0jeFGAC54A0YKmEYAo4DzjA"
+    "LHAZmElqtIGrhmEsvtzcfPNtb6/V6524SWALKBiGsfhxe/uzFhGth5XEmgVubWxsvA1Az68k"
+    "1nngYbPZ7ASg69c06wxwe3V9/b3reVqHwGmwCZRs2370fX//wIuA0+CLwEKj0XilZTSu602G"
+    "FcP7vLe7+7XlRaCgPw62gGv5fP6p63raiwFdLWKOgdNArl6vV1UqpQgcYdcYbwooAPfb7c7h"
+    "mTWmUjGwCWTL5fL1K6VSLiqQyMTYyLVa/UEwe9IC0chFYKnb/XnkeiIDV+Q0UsG/qNkCnEql"
+    "crNQLDpaxpskJnYayD1bXl4S/xrDoPLHKjQOmsHwlCuHv44+ZJ2sLTrGGqzg7zEc+VK1Wl1w"
+    "HMcG0DFxw6sFsRVwAZhdWak9FoRJ+w2HCKzzwN3jXv+daVmGDkdWoMKb9fumHz0DFFfX1p5Y"
+    "lmXo6N0G48jzVEDOt97pdA9ezOXzGU+PzBmN6VuDqyoDN3Z2vjyfKxQynhYkJuJ/L02Ara3X"
+    "n3602r8HrpaTUy3HAy1/+hNq8O+r+q4WETirmFMNBwm3v+gdmytKNIUpAAAAAElFTkSuQmCC")
+""" Left active tab image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_active_right = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAkpJ"
+    "REFUOI2NlM1rU0EUxX9zZ5KaWq3GKKnGutC0FEWCWAWLRUOxBetK/wdp6Re6F6TFXXGhuFdw"
+    "b7dCQUUpiFt1XbB2q7Uf1iTvunjzkpe0afNgmLnDnHvOPe/OWCALtAFC+Cktfha4CRwBDnhg"
+    "BQhaSrK19bf89dv35WfPX7y01haBbiAFmH3BlUA1Gm8WFt75BFkg0TK4VAl0Y3NL5+efvgIK"
+    "wOH92EVjxRljGBi4VgTOeLDbk7kcqEZju1TWX7/Xgtm5J6+BS8ChvdilLhAhkUya4eFbxVQq"
+    "1e3ZbUtgg8GKJd/Tk70/NjYCHCPsgX1kV8K5VA70z8amfvy0tAwMAcebSRfijikY8ez5/OlM"
+    "JrOncbIjp4K1lmRb0sw8eDgCpAm7rwlz46YIzjpGb48WveyDNPhDfCOuHmNwzpHL5dK9fX3n"
+    "mkmvaxJiayOCWMvM1PSdZtJrhiloLJMYIeESDFwf7Acyu0mXGLYmX0PpYi3ZbFdnoVDoBTpp"
+    "uCxCjFob1tYKzlnGJyZHd5Mu6uVGkqvMCmCwzjE4eOMqcALoINauUic37hjhLXPWcTSdThWL"
+    "QxcJX5yqdGk4H/cP9a4755iYnLpL+M/b8e0qjafrekb9TUskuNx/5TzQ5Y1zO9yOZEd1R7OI"
+    "JdXebh/Pzt3zCToAMZv/AjU1orDWWKAGVJVSqcTqysp6X+/ZaeAL8KNac9wsVQ8yNeOsdZw8"
+    "let4/2HpEdAPXDAb20HLj7xqeHT158ra4uLbz2bdg03krmetxrH9KDAmHP8Bn0j1t/01UV0A"
+    "AAAASUVORK5CYII=")
+""" Right active tab image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_close = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAI9J"
+    "REFUKJG90MEKAWEUxfEfM4rxAFIommzZzNb7v4BsLJTsiGQlYjHfME3flrO75/xvnXv5p/qY"
+    "R/wcWTUktWCKFbrYB6/AAhecmwunAI/RwQAjbLGpoFakwjLATxzqMLQjC68A3/FohkljLkKN"
+    "Ha4YKg8+VkBag3Pll9a1GikmuPk+4qMMs0jFMXoR/0d6A9JRFV/jxY+iAAAAAElFTkSuQmCC")
+""" Normal close button image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_close_h = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAOlJ"
+    "REFUKJGVkiFuw0AQRd849hUS7iPUwGEllhyjYJ+gaK9Q4CsY9QTFIY4shQQucI8Q7l6h3Z0S"
+    "r7UgjdrPZvVm52k0wpJLWe4y51qgVpECQFQnYPzabN4ra2cAAbgWxZMmyavAkTtROIn33fM0"
+    "fcilLHep92+/wXHTd5K8JJlzbYD3w8C2aVZo2zTsh4FF5Zg516ZAHYBb35MbszbkxnDr+3hQ"
+    "napIIUv1eT6vYPggvAGoSJE88r6XVFQnRA7BOdYIk8IUUZ1SYAQOsXOskRsT1+P/11pZO4v3"
+    "ncLpESzed5W1c1jQn0/jBzPfck1qdmfjAAAAAElFTkSuQmCC")
+""" Hover close button image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_close_p = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAASxJ"
+    "REFUKJF9kbFLQlEYxX/nvbs55OAkiJAE7k7Nibo9xf+hrTlyr3Boipb+BCGq0bApJEQcG0Ms"
+    "aQ0Lmq5+Dc+nDtbZ7uHce37fd8VSlWwh50PfRKqClWJXI8y6bu5uHj5e3wEEcJDP75txLBSx"
+    "RYbdS7QfJ5PnsJIt5BbB4hQjkrQtjxlFILOXyvQDH/qmUCSJznDAYetkFTxsndAZDggkhCIf"
+    "+qaLmWP1bu8oN+qrC+VGnd7t3bpKqrp4wBjl+ux8FUweSLwlXCnYCv2PHGgE1BLmTYykad2i"
+    "kcOsi1TbZN7EKDfq67NZV5VsIeedvzQjCv5YK8R/4bw7Cl+/P7920+kJkBEq/hWWaPem45cQ"
+    "YDybTfdSmf5CizckwHaAH9ATZldu7i560/ELwC+6RXdU6KzezAAAAABJRU5ErkJggg==")
+""" Pressed close button image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_inactive_center = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAbCAYAAAC9WOV0AAAABHNCSVQICAgIfAhkiAAAAElJ"
+    "REFUCJlVyiEOgDAUBNHp3qmX5iYkyMpqBAaFILRdDGn4qybZB98yy3ZZrRu1PpABAQiDSLN+"
+    "h4NLEU8CBAfoPHZUywr3M/wCTz8c3/qQrUcAAAAASUVORK5CYII=")
+""" Center inactive tab image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_inactive_left = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAf5J"
+    "REFUOI2llE1rE1EUhp8bZwyhaZomk5DaD40hSWPQVkTd6KIIEUWlLqTEhTaLulBQ6sfKjeBC"
+    "ECULXQku/Alx7d6/U1EQae45LjJpJ5NOnOKBgYG5z33Px3sG/iPMIc87QAmYBZKHgdOu69a2"
+    "3/W2yrVGK5vPLTlxFV3Xrb3+8v1Ntd5oiSpWBmnEidKT972tar3R6ovSt4qoxoIdoFipNlpW"
+    "B6AVRYFEHNWn3a8dz/PK1rIHEgN2UpnMseVTK7fUGBME48CFe88+3sh5+SXr1xmMSbABvJXz"
+    "l9siYAVGWJ0Mu/OVZr5Q8CpWfFWzD2Imj2qu/fhtG4wRVUIZg0bDBsgtn15dt6qIKKBDQZ81"
+    "kWmnzly6OZ+ZzhSt7jfK6CBjFMwEk5TWOy82AVQGhzVUb5RJEkC2fLK6JgIiPhioeZJJUhev"
+    "3j2RTqdzooqge2ojCxwxqrnrG4/uq4Ida3HgAjMOJ4CZSq1+RVBUzCgQinDDstfa282jyeTU"
+    "rhUGF4CJgMPKhbXbmw9VFfG7fBA4LCao7AAzi8cXz1kF0dENMqH38KgWnnd7nSMJxxE5wI4+"
+    "MHyCaeeAYvPshQ0RJby3wVSDHxxgAVh99elb9/evndmfP3boW2FsqGNhMMCdBy8/fJ5KZ6at"
+    "qL+3Q1dEzFkNGMX82ZWh18e0/vVT/wuFmdYVv/ruKgAAAABJRU5ErkJggg==")
+""" Left inactive tab image for the Chrome tab art. """
+
+#----------------------------------------------------------------------
+tab_inactive_right = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAhBJ"
+    "REFUOI2llM9rE1EQxz8zb1dSTKNuYtW01kQDRoKFWi9FEEq1IooUUWoPokWCtVqkR69KsSBU"
+    "8OJRPOhBxZNe/At6FBER/HFUPEq1IGn3ecgm2ZjdJODCHPY9vvP9fufNDPzHZ4DDQBrYBKwB"
+    "ftfoJys/Kw9ef/1y8/6rh67rHgKS3WLl6cqqtcCGD58+vn+zdPXorUql8g5Y7wTWdd+y4Vus"
+    "teQK+yfKi8/KwM5umBXAAgioCIP54gTQBzgdwTbsQZR0JpOfXXw+0w27hn9EBGMcyRcPnulJ"
+    "pbKd2JvACKgKnpcePH99+TSwvT3YEphusKsqB4ZHp4FMNWUn5loSEVSFbZ63b8eeUhpwu5Md"
+    "JBFRjHHk7LXb08CuNuAaZTgEEaFQHJoEvDjpakOYmnURUFWSvam+0ujJfqAnmlnABhG2jlTZ"
+    "j19YuEzMm7dUu34hihrDQG7vGLCViPq0VruuvdquyWSvN3xsKhclvbXaoUQiihFlfLJ8iYiq"
+    "O/EtUC2xGGF3vjAObAnI6stCsZbYCLwnEonNY+dulALvHWSH2YN2PXLq4hz/9HpjnmOs18DZ"
+    "bP9IIL0+afV5juqzRgLFcV1n9u6LGWAgWnaMBFHBOIbi0MgU1S3jAcjyyw9xqpvzWou1Pj++"
+    "f/t8b/7EAvBW5u48agU37abWs99rv1YfL81fkT8V34YxbZ696d4CfwEszZSZx6Z26wAAAABJ"
+    "RU5ErkJggg==")
+""" Right inactive tab image for the Chrome tab art. """
+
+# For auibook
+# -----------
+
+AuiBaseTabCtrlId = 5380
+""" Base window identifier for AuiTabCtrl. """
+
+AUI_NB_TOP                 = 1 << 0
+""" With this style, tabs are drawn along the top of the notebook. """
+AUI_NB_LEFT                = 1 << 1  # not implemented yet
+""" With this style, tabs are drawn along the left of the notebook.
+Not implemented yet. """
+AUI_NB_RIGHT               = 1 << 2  # not implemented yet
+""" With this style, tabs are drawn along the right of the notebook.
+Not implemented yet. """
+AUI_NB_BOTTOM              = 1 << 3
+""" With this style, tabs are drawn along the bottom of the notebook. """
+AUI_NB_TAB_SPLIT           = 1 << 4
+""" Allows the tab control to be split by dragging a tab. """
+AUI_NB_TAB_MOVE            = 1 << 5
+""" Allows a tab to be moved horizontally by dragging. """
+AUI_NB_TAB_EXTERNAL_MOVE   = 1 << 6
+""" Allows a tab to be moved to another tab control. """
+AUI_NB_TAB_FIXED_WIDTH     = 1 << 7
+""" With this style, all tabs have the same width. """
+AUI_NB_SCROLL_BUTTONS      = 1 << 8
+""" With this style, left and right scroll buttons are displayed. """
+AUI_NB_WINDOWLIST_BUTTON   = 1 << 9
+""" With this style, a drop-down list of windows is available. """
+AUI_NB_CLOSE_BUTTON        = 1 << 10
+""" With this style, a close button is available on the tab bar. """
+AUI_NB_CLOSE_ON_ACTIVE_TAB = 1 << 11
+""" With this style, a close button is available on the active tab. """
+AUI_NB_CLOSE_ON_ALL_TABS   = 1 << 12
+""" With this style, a close button is available on all tabs. """
+AUI_NB_MIDDLE_CLICK_CLOSE  = 1 << 13
+""" Allows to close `AuiNotebook` tabs by mouse middle button click. """
+AUI_NB_SUB_NOTEBOOK        = 1 << 14
+""" This style is used by `AuiManager` to create automatic `AuiNotebooks`. """
+AUI_NB_HIDE_ON_SINGLE_TAB  = 1 << 15
+""" Hides the tab window if only one tab is present. """
+AUI_NB_SMART_TABS          = 1 << 16
+""" Use `Smart Tabbing`, like ``Alt`` + ``Tab`` on Windows. """
+AUI_NB_USE_IMAGES_DROPDOWN = 1 << 17
+""" Uses images on dropdown window list menu instead of check items. """
+AUI_NB_CLOSE_ON_TAB_LEFT   = 1 << 18
+""" Draws the tab close button on the left instead of on the right
+(a la Camino browser). """
+AUI_NB_TAB_FLOAT           = 1 << 19
+""" Allows the floating of single tabs.
+Known limitation: when the notebook is more or less full screen, tabs 
+cannot be dragged far enough outside of the notebook to become 
+floating pages. """
+AUI_NB_DRAW_DND_TAB        = 1 << 20
+""" Draws an image representation of a tab while dragging. """
+AUI_NB_ORDER_BY_ACCESS     = 1 << 21
+""" Tab navigation order by last access time. """
+AUI_NB_NO_TAB_FOCUS        = 1 << 22
+""" Don't draw tab focus rectangle. """
+
+AUI_NB_DEFAULT_STYLE = AUI_NB_TOP | AUI_NB_TAB_SPLIT | AUI_NB_TAB_MOVE | \
+                       AUI_NB_SCROLL_BUTTONS | AUI_NB_CLOSE_ON_ACTIVE_TAB | \
+                       AUI_NB_MIDDLE_CLICK_CLOSE | AUI_NB_DRAW_DND_TAB
+""" Default `AuiNotebook` style. """
+
+#----------------------------------------------------------------------
+Mondrian = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAHFJ"
+    "REFUWIXt1jsKgDAQRdF7xY25cpcWC60kioI6Fm/ahHBCMh+BRmGMnAgEWnvPpzK8dvrFCCCA"
+    "coD8og4c5Lr6WB3Q3l1TBwLYPuF3YS1gn1HphgEEEABcKERrGy0E3B0HFJg7C1N/f/kTBBBA"
+    "+Vi+AMkgFEvBPD17AAAAAElFTkSuQmCC")
+""" Default icon for the Smart Tabbing dialog. """
+
+# -------------------------- #
+# - FrameManager Constants - #
+# -------------------------- #
+
+# Docking Styles
+AUI_DOCK_NONE = 0
+""" No docking direction. """
+AUI_DOCK_TOP = 1
+""" Top docking direction. """
+AUI_DOCK_RIGHT = 2
+""" Right docking direction. """
+AUI_DOCK_BOTTOM = 3
+""" Bottom docking direction. """
+AUI_DOCK_LEFT = 4
+""" Left docking direction. """
+AUI_DOCK_CENTER = 5
+""" Center docking direction. """
+AUI_DOCK_CENTRE = AUI_DOCK_CENTER
+""" Centre docking direction. """
+AUI_DOCK_NOTEBOOK_PAGE = 6
+""" Automatic AuiNotebooks docking style. """
+
+# Floating/Dragging Styles
+AUI_MGR_ALLOW_FLOATING           = 1 << 0
+""" Allow floating of panes. """
+AUI_MGR_ALLOW_ACTIVE_PANE        = 1 << 1
+""" If a pane becomes active, "highlight" it in the interface. """
+AUI_MGR_TRANSPARENT_DRAG         = 1 << 2
+""" If the platform supports it, set transparency on a floating pane
+while it is dragged by the user. """
+AUI_MGR_TRANSPARENT_HINT         = 1 << 3
+""" If the platform supports it, show a transparent hint window when
+the user is about to dock a floating pane. """
+AUI_MGR_VENETIAN_BLINDS_HINT     = 1 << 4
+""" Show a "venetian blind" effect when the user is about to dock a
+floating pane. """
+AUI_MGR_RECTANGLE_HINT           = 1 << 5
+""" Show a rectangle hint effect when the user is about to dock a
+floating pane. """
+AUI_MGR_HINT_FADE                = 1 << 6
+""" If the platform supports it, the hint window will fade in and out. """
+AUI_MGR_NO_VENETIAN_BLINDS_FADE  = 1 << 7
+""" Disables the "venetian blind" fade in and out. """
+AUI_MGR_LIVE_RESIZE              = 1 << 8
+""" Live resize when the user drag a sash. """
+AUI_MGR_ANIMATE_FRAMES           = 1 << 9
+""" Fade-out floating panes when they are closed (all platforms which support
+frames transparency) and show a moving rectangle when they are docked
+(Windows < Vista and GTK only). """
+AUI_MGR_AERO_DOCKING_GUIDES      = 1 << 10
+""" Use the new Aero-style bitmaps as docking guides. """
+AUI_MGR_PREVIEW_MINIMIZED_PANES  = 1 << 11
+""" Slide in and out minimized panes to preview them. """
+AUI_MGR_WHIDBEY_DOCKING_GUIDES   = 1 << 12
+""" Use the new Whidbey-style bitmaps as docking guides. """
+AUI_MGR_SMOOTH_DOCKING           = 1 << 13
+""" Performs a "smooth" docking of panes (a la PyQT). """
+AUI_MGR_USE_NATIVE_MINIFRAMES    = 1 << 14
+""" Use miniframes with native caption bar as floating panes instead or custom
+drawn caption bars (forced on wxMac). """
+AUI_MGR_AUTONB_NO_CAPTION        = 1 << 15
+""" Panes that merge into an automatic notebook will not have the pane
+caption visible. """
+
+
+AUI_MGR_DEFAULT = AUI_MGR_ALLOW_FLOATING | AUI_MGR_TRANSPARENT_HINT | \
+                  AUI_MGR_HINT_FADE | AUI_MGR_NO_VENETIAN_BLINDS_FADE
+""" Default `AuiManager` style. """
+
+# Panes Customization
+AUI_DOCKART_SASH_SIZE = 0
+""" Customizes the sash size. """
+AUI_DOCKART_CAPTION_SIZE = 1
+""" Customizes the caption size. """
+AUI_DOCKART_GRIPPER_SIZE = 2
+""" Customizes the gripper size. """
+AUI_DOCKART_PANE_BORDER_SIZE = 3
+""" Customizes the pane border size. """
+AUI_DOCKART_PANE_BUTTON_SIZE = 4
+""" Customizes the pane button size. """
+AUI_DOCKART_BACKGROUND_COLOUR = 5
+""" Customizes the background colour. """
+AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR = 6
+""" Customizes the background gradient colour. """
+AUI_DOCKART_SASH_COLOUR = 7
+""" Customizes the sash colour. """
+AUI_DOCKART_ACTIVE_CAPTION_COLOUR = 8
+""" Customizes the active caption colour. """
+AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR = 9
+""" Customizes the active caption gradient colour. """
+AUI_DOCKART_INACTIVE_CAPTION_COLOUR = 10
+""" Customizes the inactive caption colour. """
+AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR = 11
+""" Customizes the inactive gradient caption colour. """
+AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR = 12
+""" Customizes the active caption text colour. """
+AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR = 13
+""" Customizes the inactive caption text colour. """
+AUI_DOCKART_BORDER_COLOUR = 14
+""" Customizes the border colour. """
+AUI_DOCKART_GRIPPER_COLOUR = 15
+""" Customizes the gripper colour. """
+AUI_DOCKART_CAPTION_FONT = 16
+""" Customizes the caption font. """
+AUI_DOCKART_GRADIENT_TYPE = 17
+""" Customizes the gradient type (no gradient, vertical or horizontal). """
+AUI_DOCKART_DRAW_SASH_GRIP = 18
+""" Draw a sash grip on the sash. """
+
+# Caption Gradient Type
+AUI_GRADIENT_NONE = 0
+""" No gradient on the captions. """
+AUI_GRADIENT_VERTICAL = 1
+""" Vertical gradient on the captions. """
+AUI_GRADIENT_HORIZONTAL = 2
+""" Horizontal gradient on the captions. """
+
+# Pane Button State
+AUI_BUTTON_STATE_NORMAL = 0
+""" Normal button state. """
+AUI_BUTTON_STATE_HOVER = 1 << 1
+""" Hovered button state. """
+AUI_BUTTON_STATE_PRESSED = 1 << 2
+""" Pressed button state. """
+AUI_BUTTON_STATE_DISABLED = 1 << 3
+""" Disabled button state. """
+AUI_BUTTON_STATE_HIDDEN   = 1 << 4
+""" Hidden button state. """
+AUI_BUTTON_STATE_CHECKED  = 1 << 5
+""" Checked button state. """
+
+# Pane minimize mode
+AUI_MINIMIZE_POS_SMART    = 0x01
+""" Minimizes the pane on the closest tool bar. """
+AUI_MINIMIZE_POS_TOP      = 0x02
+""" Minimizes the pane on the top tool bar. """
+AUI_MINIMIZE_POS_LEFT     = 0x03
+""" Minimizes the pane on its left tool bar. """
+AUI_MINIMIZE_POS_RIGHT    = 0x04
+""" Minimizes the pane on its right tool bar. """
+AUI_MINIMIZE_POS_BOTTOM   = 0x05
+""" Minimizes the pane on its bottom tool bar. """
+AUI_MINIMIZE_POS_MASK     = 0x07
+""" Mask to filter the position flags. """
+AUI_MINIMIZE_CAPT_HIDE    = 0
+""" Hides the caption of the minimized pane. """
+AUI_MINIMIZE_CAPT_SMART   = 0x08
+""" Displays the caption in the best rotation (horz or clockwise). """
+AUI_MINIMIZE_CAPT_HORZ    = 0x10
+""" Displays the caption horizontally. """
+AUI_MINIMIZE_CAPT_MASK    = 0x18
+""" Mask to filter the caption flags. """
+
+# Button kind
+AUI_BUTTON_CLOSE = 101
+""" Shows a close button on the pane. """
+AUI_BUTTON_MAXIMIZE_RESTORE = 102
+""" Shows a maximize/restore button on the pane. """
+AUI_BUTTON_MINIMIZE = 103
+""" Shows a minimize button on the pane. """
+AUI_BUTTON_PIN = 104
+""" Shows a pin button on the pane. """
+AUI_BUTTON_OPTIONS = 105
+""" Shows an option button on the pane (not implemented). """
+AUI_BUTTON_WINDOWLIST = 106
+""" Shows a window list button on the pane (for AuiNotebook). """
+AUI_BUTTON_LEFT = 107
+""" Shows a left button on the pane (for AuiNotebook). """
+AUI_BUTTON_RIGHT = 108
+""" Shows a right button on the pane (for AuiNotebook). """
+AUI_BUTTON_UP = 109
+""" Shows an up button on the pane (not implemented). """
+AUI_BUTTON_DOWN = 110
+""" Shows a down button on the pane (not implemented). """
+AUI_BUTTON_CUSTOM1 = 201
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM2 = 202
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM3 = 203
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM4 = 204
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM5 = 205
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM6 = 206
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM7 = 207
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM8 = 208
+""" Shows a custom button on the pane. """
+AUI_BUTTON_CUSTOM9 = 209
+""" Shows a custom button on the pane. """
+
+# Pane Insert Level
+AUI_INSERT_PANE = 0
+""" Level for inserting a pane. """
+AUI_INSERT_ROW = 1
+""" Level for inserting a row. """
+AUI_INSERT_DOCK = 2
+""" Level for inserting a dock. """
+
+# Action constants
+actionNone = 0
+""" No current action. """
+actionResize = 1
+""" Resize action. """
+actionClickButton = 2
+""" Click on a pane button action. """
+actionClickCaption = 3
+""" Click on a pane caption action. """
+actionDragToolbarPane = 4
+""" Drag a floating toolbar action. """
+actionDragFloatingPane = 5
+""" Drag a floating pane action. """
+
+# Drop/Float constants
+auiInsertRowPixels = 10
+""" Number of pixels between rows. """
+auiNewRowPixels = 40
+""" Number of pixels for a new inserted row. """
+auiLayerInsertPixels = 40
+""" Number of pixels between layers. """
+auiLayerInsertOffset = 5
+""" Number of offset pixels between layers. """
+auiToolBarLayer = 10
+""" AUI layer for a toolbar. """
+
+# some built in bitmaps
+
+if wx.Platform == "__WXMAC__":
+
+    close_bits = "\xFF\xFF\xFF\xFF\x0F\xFE\x03\xF8\x01\xF0\x19\xF3\xB8\xE3\xF0" \
+                 "\xE1\xE0\xE0\xF0\xE1\xB8\xE3\x19\xF3\x01\xF0\x03\xF8\x0F\xFE\xFF\xFF"
+    """ Close button bitmap for a pane on wxMAC. """
+
+elif wx.Platform == "__WXGTK__":
+
+    close_bits = "\xff\xff\xff\xff\x07\xf0\xfb\xef\xdb\xed\x8b\xe8\x1b\xec\x3b\xee" \
+                 "\x1b\xec\x8b\xe8\xdb\xed\xfb\xef\x07\xf0\xff\xff\xff\xff\xff\xff"
+    """ Close button bitmap for a pane on wxGTK. """
+
+else:
+
+    close_bits = "\xff\xff\xff\xff\xff\xff\xff\xff\xcf\xf3\x9f\xf9\x3f\xfc\x7f\xfe" \
+                 "\x3f\xfc\x9f\xf9\xcf\xf3\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+    """ Close button bitmap for a pane on wxMSW. """
+
+pin_bits     = '\xff\xff\xff\xff\xff\xff\x1f\xfc\xdf\xfc\xdf\xfc\xdf\xfc\xdf\xfc' \
+               '\xdf\xfc\x0f\xf8\x7f\xff\x7f\xff\x7f\xff\xff\xff\xff\xff\xff\xff'
+""" Pin button bitmap for a pane. """
+
+max_bits     = '\xff\xff\xff\xff\xff\xff\x07\xf0\xf7\xf7\x07\xf0\xf7\xf7\xf7\xf7' \
+               '\xf7\xf7\xf7\xf7\xf7\xf7\x07\xf0\xff\xff\xff\xff\xff\xff\xff\xff'
+""" Maximize button bitmap for a pane. """
+
+restore_bits = '\xff\xff\xff\xff\xff\xff\x1f\xf0\x1f\xf0\xdf\xf7\x07\xf4\x07\xf4' \
+               '\xf7\xf5\xf7\xf1\xf7\xfd\xf7\xfd\x07\xfc\xff\xff\xff\xff\xff\xff'
+""" Restore/maximize button bitmap for a pane. """
+
+minimize_bits = '\xff\xff\xff\xff\xff\xff\x07\xf0\xf7\xf7\x07\xf0\xff\xff\xff\xff' \
+                '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
+""" Minimize button bitmap for a pane. """
+
+restore_xpm = ["16 15 3 1",
+               "       c None",
+               ".      c #000000",
+               "+      c #FFFFFF",
+               "                ",
+               "     .......... ",
+               "     .++++++++. ",
+               "     .......... ",
+               "     .++++++++. ",
+               " ..........+++. ",
+               " .++++++++.+++. ",
+               " ..........+++. ",
+               " .++++++++..... ",
+               " .++++++++.     ",
+               " .++++++++.     ",
+               " .++++++++.     ",
+               " .++++++++.     ",
+               " ..........     ",
+               "                "]
+""" Restore/minimize button bitmap for a pane. """
+
+#----------------------------------------------------------------------
+
+down_focus_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACaUlE"
+    "QVRIib2WvWsUQRjGn5mdnWxyTaqz9q+QlLnGToSgWAYDNjbpNCAGDGIvaRPbNJGQyiAEbK+w"
+    "sAo2qexyEhbxsvt+jMXc3u3liPfhmWeXnWVm9vc+vO/M7prVzTb+gxyA7Ye/nXPWWmvtXKBb"
+    "B9YBcM5lWZam6by4QNcBsNamaeq9d87NmWutdc59+NgGoKIizCwsxMTMFI8oZmZilzomZiFm"
+    "FWERaXbv7eyueO+TJEHM79LSkvfeWnv2qftgex2ASGDmkrUkKUspiIuCy5IL4qKQgnghdQVx"
+    "ScKsxCKiaH8lIu99NOwAEFGsG4Dv5xeiQYOKBBYVUWJlFhIVVmIlEZGQJKVIYBbWoKqqwQN5"
+    "nqdpuri42OMys6rGOG/X78yW0bXWNyLqcyyAEEIIYcYK3aB5Lazb4o5fsPc3ToFaloxBwMle"
+    "6+9Pjfd7stda6HR85+dCPC86Y6ETcQEcHz32eZ7meZrnx0ePJnlk0vwenm70r/PkTgWdjjuV"
+    "rnPPfvxaa+3NcL3GMaub7XdPtNFoZFn24tmX1/trAOLuM6aaFQwQYExAMPWNaUw1FW+eHj5/"
+    "dbfZbDYajY33F7e1L4gUA5uo3fd8AWbQH70bjGqEyxLq3LoMYhKCgakCIWZoLLdkMRE43Iy0"
+    "tWi9QOP8xoIFAyBUjF7dgOizb9iMhLmByxIAHbAGKYigUPX3hqog47hSvfCHfYRaDcNg3IzO"
+    "7GmydRaGi37zMujrut/9l58nijROQ9yd3ZXLy8urq6vZWFmW9f+Yhrje++XlZR2keDpZa4f+"
+    "H/pKkiR+/f9dDsDWgQW6QHcuxKg/ZbVtCjjzINkAAAAASUVORK5CYII=")
+""" VS2005 focused docking guide window down bitmap. """
+
+#----------------------------------------------------------------------
+down_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACY0lE"
+    "QVRIib2WwWrUUBSG/3tzc5s2m0JhXPsU0u1s3Lkpui4W3PgAuhAFi2/QbesTVEphwCIU3Hbh"
+    "wk2LG1fujJQgtMk55x4Xd2aS6VAzM479JyQhufnOz3/uzcQMBgP8BzkAeZ4756y11tqlQIui"
+    "cACcc1mWpWm6ZK61Nk1T771zbilcxBxiAs659x/OAAQJIswsLMTEzBR/UczMxC51TMxCzEGE"
+    "RaR39WB3b9N7nyTJkLu2tua9t9ZefLx69GYbgIgyc82hJqlrqYiriuuaK+Kqkop4JXUVcU3C"
+    "HIhFJODsCxF57xu/RBT7BuDb958SNGgQUZYgEogDs5AE4UAcSEREk6QWUWbhoCGEENQDZVmm"
+    "abq6ujrkMnMIIdZ5t31vsUC3+l+JaMyxAFRVVRds0C1azsS6O273hH24cwq0UjIGipP9/t+f"
+    "6vZ7st9fKQpf/FqJ28+iEzoTF8Dx0RNflmlZpmV5fPR4lkdmzffwdGe8XyZ3Luh83Ll0k3vx"
+    "4/dWf3+B/Q2OGQwGGxsbeZ5nWfbi2efXB1sA4uozZjRKDaAwRqGmvTCNGQ3F26eHz1/d7/V6"
+    "eZ6fn5/f1bogCmhsonU+9AWY5nr0bjCtKS6LtrltGcQQ1MCMCiEm1MmtWUwETh6mjq1qw0Jd"
+    "fmPD1ADQEWPYNyD6HBs2U2Vu4bIoEBpWE0EE6ej68NaoSBdXRi/8SR/a6qE29830yKFmm2c6"
+    "2fTbp8FYN/0evPw0U6UuTXB39zYvLy+vr68XY2VZNv5imuB679fX10MT8Xyy1k58P4yVJEn8"
+    "9/93OQBFURRFsRTcWH8An5lwqISXsWUAAAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window down bitmap. """
+
+#----------------------------------------------------------------------
+left_focus_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACVElE"
+    "QVRIibWWvW8TQRDF3+7Ors8ShSsaSpo0dEgoFcINVChSBFRUkajpIKKgiPgP0pqGJiAhITqE"
+    "FIk2BQUVHT2VK+y7ndmhWN/5Ixcbh8tYWvtO8vvdm5mdPXPv+RmuMgjA670/RGSttdZ2q354"
+    "YgkAERVF4b3vHABMCIC11nsfQiCiqwJYa4noxbNvOw/6AJIk62ySJMLMwhI5MnPMnxzMzJHJ"
+    "E0dmicxJhEXk+uTO0fFuCME5h1yDxbh5+zEz93q+LGOv50WUmStOVZSqkjJyWXJVcRm5LKWM"
+    "3PNURq6iMKfIIpJw9n08Hg8Gg36/3wL4+eu3iHpykcWTS5pElCWJpMiJWaIk4RQ5RRERda4S"
+    "UWbhpCmllDQA0+k0pZQFVwF3bzEAZ5N3jgje+0COnPVknbUAdm5cW5/1/eGPxcuL2saoAczC"
+    "DQWAV0/fr1c/HxcBFNC8QGEMMu3NuyddAfIjG9QLjKJTB3NIHV050EZuoQI6+93q4P7B6TYA"
+    "A2gW1xlC61K0OXi492HZ6EbAnGFqEmBmhlYc7A9HutRq/wgA5plSwDT9tORgfzgCNsmv2QfQ"
+    "OvEwps7BooOPpwebxFsB83wazdWdl321BjOGWWejrciZ0+wBMwef76LPnx6trXFrivIfVOsl"
+    "P2V7FwH4MhpuCTBLX7mjckU628naTImlrdDdLDJ59OT+XDDU8SwyTX+Y2bC7hIPVA+fty6/b"
+    "SmwBODreHY/H0+n0P0WLomjegJYAIYTBYNAcp5cOa20IoQXgnMuvAh0GATg8scAEmHQrneMv"
+    "3LAo6X/e0vAAAAAASUVORK5CYII=")
+""" VS2005 focused docking guide window left bitmap. """
+
+#----------------------------------------------------------------------
+left_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACTklE"
+    "QVRIibWWPWsUURSG3/u5u8RiKxtLmzR2gqQSttFKhKBWqQL+BQXL4D9IGxsrBUGEFCIEbC0s"
+    "rOzshYHt3Jl7PizuzsduJhs3Ts7C3Z2BfZ95zzn33DGnp6e4zvAAdnZ2vPfWWmvtsOpFUXgA"
+    "3vvxeBxCuC6AtTaEEGP03g8LQE5RTo73/sXzr7sPJwCExTorLMxExMSJEhGl/MlBRJTIB0+J"
+    "iBORMBMz3/xz7+h4L8bonFsCunH77lMiGo1CWabRKDArEVUkVeKq4jJRWVJVUZmoLLlMNAq+"
+    "TFQlJpJEzCz49n0+n0+n08lk0gP4+es3swbvEnHwTlSYlViYJZEQcWJhkkSSmJnVuYpZiZhE"
+    "RUREI7BYLESkTVE37t8hAM5KcM57hBCid97Z4K2zFsDurRubk74/+9G9vKhtjBrAdG4oALw6"
+    "eLdZ/XxcBFBA8wKFMci012+fDQXIj2xQLzCKQR20kDqGcqCNXKcCuvzd6+DB4dk2AANoFtcl"
+    "QutS9Dl49Pj9qtFLAS3D1CTALA2tOdifnehKq/0jAGgzpYBp+mnFwf7sBLhMfsM+gNaJhzF1"
+    "DroOPpwdXibeC2jzaTRXty37eg2WDLPJRl+RM6fZA6YFn++iTx+fbKxxb4ryH1TrJT9lfxcB"
+    "+Hwy2xJgVr5yR+WKDLaTtZkSK1thuFlk8ujJ/dkxNPAsMk1/mOWwu4KD9QPnzcsv20psATg6"
+    "3pvP54vF4j9Fx+Nx8wa0AogxTqfT5ji9clhrY4w9AOdcfhUYMDyAoiiKohhWt4m/9Qss43IB"
+    "CBMAAAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window left bitmap. """
+
+#----------------------------------------------------------------------
+right_focus_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACWElE"
+    "QVRIibWWv2/TQBTHv3e+uyRbJwZWFv4AJNSRLjChSkhlYqrEzFZVDAwVC3PXsrAUISTExlKJ"
+    "tQMSWzcmFqaqQqT2+8VwtuMkbiBp+mzF0pPz/dzX7z373IMXp7jJCABebf8JIXjvvffrVd8/"
+    "9gFACGE4HMYY1w4AxgGA9z7GmFIKIdwUwHsfQth7/vXuoxEAFfWFV1ERZhYWYmJmykcOZmbi"
+    "EAMTsxCzirCI3BrfPzjcTCkVRYFcg27cubfDzINBLEsaDKKIMXPFWpFUlZTEZclVxSVxWUpJ"
+    "PIihJK5ImJVYRBSn387Pzzc2NkajUQ/g7McvEYuhIJYYCjUVMRYVUWJlFhIVVmIlERErikrE"
+    "mIXVVFXVEnB5eamqWXAW8Gb39uKHevbzNwARZVFirUSIlFkqEVUD8Pb71P1Lt83LZ+8BAA7O"
+    "AYABMAPcFfcvDXj97ikA5wxmHVVrf64LyA7Mau1so770uVjRQa1lzaKtSc2ZWAR4uHsyn2xq"
+    "YBnjbFp4zsRCBw6Ptz/M5GoHgLla15AfUV8F/gEwA/Bk66jPgXNwMNhkyf199F816DIaB5bx"
+    "yB2aO2qFLsp/+Xiy22YmczA1Cq4hLQlwsK56xwHgumLWln0pgPv8aWcmNdVF7TKujkWAL0db"
+    "88nagXWb0xYgVn4XWf0CymdzWQNgapJzWC7HCnPQF5M5aBhXzthqgMkcoF57Zxx6YvaDMzO3"
+    "148pwMHhJhFdXFwQ0XVEh8NhuwOaAqSUUkoxxvaLulp471NKPYC80ci7gXVFALB/7IExMF6j"
+    "bht/AXIQRaTUgkiHAAAAAElFTkSuQmCC")
+""" VS2005 focused docking guide window right bitmap. """
+
+#----------------------------------------------------------------------
+right_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACVElE"
+    "QVRIibWWv2sUQRTHvzM7M3dHmlQWtjb+AYKkTaOVCEKsrAL+CxaWwcY6bWysRAQRUtgEbC0E"
+    "u3RWNsJCCILZfb8sZvdu925zej/yveMWHnvvM9837+2OOz09xU0qANjZ2QkheO+999vNXpZl"
+    "ABBCGI/HMcabAnjvY4wppRDCdgHIJcrFCSG8eP7l7sMJABX1hVdREWYWFmJiZsqfLGZm4hAD"
+    "E7MQs4qwiNz6c//oeC+lVBRFA+jqzr0DZh6NYlXRaBRFjJlr1pqkrqUiriqua66Iq0oq4lEM"
+    "FXFNwqzEIqL4+u3i4mJ3d3cymQwAzn/8ErEYCmKJoVBTEWNRESVWZiFRYSVWEhGxoqhFjFlY"
+    "TVVVLQFXV1eqOitRV68Pby+v6fnP3wBElEWJtRYhUmapRVQNwJvvvftXbpuXz94BABycAwAD"
+    "YAa4a+5fGfDq7VMAzhnMOllt+rMpIDswa3JnG81lyMWaDppc1i7a2tCCiWWAB4dni8F2Dyxj"
+    "nPUTL5hY6sDh0eP3c7HGAWCuyWvIJRragX8AzAA82T8ZcuAcHAw2W/JwH/3XHnQZrQPLeOQO"
+    "zR21Rhflv3w4O5xGZnPQGwXXklYEOFg3e8cB4LrJbLrtKwHcp48Hc6FeF02Xcb2WAT6f7C8G"
+    "GwfWbU5bglj7WWTNAyh/28sWAL1JzrK8HWvMwZBmc9Ayrp2x9QCzOUCz9s44DGj+hTM3t5ur"
+    "Bzg63iOiy8tLItok6Xg8np6AeoCUUkopxjh9o64n731KaQCQDxr5NLAtBQBlWZZlucWkXf0F"
+    "imtJnvbT2psAAAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window right bitmap. """
+
+#----------------------------------------------------------------------
+tab_focus_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAAC10lE"
+    "QVRIidWWT0gUcRTH387+ZveXZgzsbmvSsmqEfzBJSYz+gUsHCYJgISPytCQKFhJdpIN0qIUO"
+    "ezIUaU/roQ5eEzp46ZT/DhG4haCXdSUPK+Wuzvze+02HgdFmFqMtD76Bx8yb3/v8vr/3Zn4z"
+    "np6ReTgCYwAwdqfEGFMURVGU/wIdfaswAGCMcc5VVf1fXIBdBgCKoqiq+nxkobn3BABIkgBA"
+    "hIiEJFAgorAOyxARBTKVoUAkgSiJkIhO73a/nLjGOd/nWkrPXbqLiH6/CgBEJiIaKA1BhkG6"
+    "QF1Hw0BdoK6TLtCvMl2gIQhRCiQiCfPLm5ubtbW1YNXXtuzadyJTZV4AkKYkMpEkkRQoEUmQ"
+    "JJQCpSAiMr1eg8hEJJSmlFJK0wdQLBYR0cl9laj7l6LGY5/tc2ejsrmdgeGJbG5nYHgym9uJ"
+    "x9KHeGuMNd7B8fSMzCfvyerq6rHHn2bmEgPDE09G+/9WaSqZmRofisfSiadnotHoozclp94K"
+    "oGWznNxn/e8q4LqznNwXmb4KuO6s4643lZyugOvOcj8PDyrgurOOe30r05tKZv7ALavXmszt"
+    "rXZZL7EjhTmuU8lpRxNSyemZuUEAmJlLOPzU+CAAuKFluO7OWpF4LO1OPsTcejOOTcRepqXR"
+    "tngs7Y6U4bbcqNrIF6bGh6yt0prAgm7kC6E2fSNfWF9b2d7e1jStvqGlbMSmeRsuP7zZZvp8"
+    "PvCoW1s/a2qq7vddD57y3b7VZfmNfGFxadUQBgqztbWps7Pdy04uLq0WSyVJnoMRgUY45NM0"
+    "bXZZ7OvtaA8vLOdeT85mP+4eXN35K/6W5nBjxFz5tv7+w8LWF3+oTW+IBpsavStf1+xIfTTY"
+    "cNbknDPGfqsD5/xCa6AuDFe791xtEJyHIhHedTGw17tnj49EeFdH8GAkEAhwzgF+7HMZY5qm"
+    "cc6tD6rDGGOMMUS075aN2Ho9R/R/9gsXZ7dKHM+ODQAAAABJRU5ErkJggg==")
+""" VS2005 focused docking guide window center bitmap. """
+
+#----------------------------------------------------------------------
+tab_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAAC1klE"
+    "QVRIidWVTWgTQRTHJ5vZZEyMLKSx1RbSImJbioeiCKIechLBU8CCtadAaaGIFC/iQTxowENO"
+    "hUohp/Tiocdce/Gk/TiIpTm0JCnmA+OaFJs2u/PerIcp27IbKsZ66Ft47P5n3m/evLc768lm"
+    "s+Q/GCWEBINBSqmiKIqinApU13VKCKGUMsZUVT1lrqIoqqq+frYyeP8cIUSgIIQgAgACcuAA"
+    "wOUlDQCAA1UpcADkAAIREPHiwa2383cYY0TWwa7AlRuPAMDvVwkhiBYAmCBMjqaJBgfDANME"
+    "g4NhoMHBr1KDg8kRQHBAREE+r1er1Z6enkOubbn8d0RLpV5CiLAEogUoEAUHAYAcBYLgIDgi"
+    "ouX1mogWAIKwhBBCWD5Cms0mADi57xKX/6Ws8dgX+97ZqFxpb3JmPlfam5x5nyvtxWPpE7yc"
+    "I+c7OJ5sNhsOh4PB4Kunn5aWE5Mz87MvJv4201QyszA3HY+lE88vRaPRYrHozLcDaNsoJ/fl"
+    "xIcOuO4oJ/dNZqwDrjvqrOebSi52wHVHud+HJx1w3VFnvb6d5ZtKZv7AbZuvXMztZbvkR+wI"
+    "oY7nVHLR0YRUcnFpeYoQsrSccPiFuSlCiBvahuvurFTisbQ7+ARz55txHCL2NmWOtsVjabfS"
+    "hjt0L1Cu1BfmpuVRKReQ0HKlHhkxypV6Ib/ZaDQ0TesfGGqr2DTv+Ph4IBDw+XzEo9Zqv0Kh"
+    "wOOxu10XfA8f3JS+XKmvrm2Z3ARuDQ9fGx297qXnV9e2mvv7Aj3HFQ5md8Snadru7u7Rua6q"
+    "6sp6aTNXzX08OL67q7f9Q4PdTP1ZKCn5Qq321R8ZMQaiXf19VuGbJ1/8IZX+aNdAnxWJRHp7"
+    "e7e3t4+4oVCo0Wjout5qtdx9YIwxxlqtlj3aVgmHw5qmbWxsHNWXUqppGmNM/lCd/aWUUgoA"
+    "9mhbhTFGKT3sm67ruq7v7Oy4cR3bb5uW079be13FAAAAAElFTkSuQmCC")
+""" VS2005 unfocused docking guide window center bitmap. """
+
+#----------------------------------------------------------------------
+up_focus_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACTUlE"
+    "QVRIic2WP28TMRjGH/85c1miqEF8CnbUgSFdukVRmZGQ+gW6Vgwd+hW60Yq1gMQMQzpHGZAg"
+    "C6JS+QIMmUju/L5+Ge6ulzoRTcMh5TmdZfv8/vT4Pcu26h2N8R9kAZwMfltrtdZa60agx5fa"
+    "ArDWpmmaJElTXGBmAWitkyRxzllrG+Zqra21bz+OAQQOzETExJ48EfniKURE5MkmljwRe6LA"
+    "TMz8ZPbs9GzXOWeMQZHfW33/NOufvALALESUU8g95zlnnrKM8pwyT1nGmadHic085Z6Jgidm"
+    "Dhh/mU6nnU6n1WrFXAA/fv7iIEECsxAH5uApELHnwBQ8Bc/MLMbkzELEFCSEEII4YD6fhxAK"
+    "Tsx9/tQDEIgqOzRggAQQQEEBguIFgKoNqDdfvy1yYq41emG4QKkSpDQAiNQfFQClpBoZcaK2"
+    "s0awEHzXVVyri1gxN7FaFuILu6qwtAyokqWWwEvcxNTTKsIK95Cqs4JJzV02vMJvHS/1cFFQ"
+    "UGV+K3tSzWlZq/5bOWGllIio0mzpX+pZSJXdVRmOuabcItRC+ZfKcn+pFRvN65fvNihj9Y7G"
+    "o9FoMplcX18f9M5lUx30zofD4WQyubm56R2Nm9oYY20B98XeRfPcAro+ei1uf/DBt9u+3c7b"
+    "7f7gfTPc/cOr7HE36+5k3Z28u5N1u/uHV/dG3X+gfb7YW8dgpC1YD1vBjfP7oEW6Lvf0bHc6"
+    "nc7n881YaZre3pjucJ1znU7n9qx+qLTWzrkVXGNMcav4d1kAx5camAGzRoiF/gCKPmudbgYP"
+    "HQAAAABJRU5ErkJggg==")
+""" VS2005 focused docking guide window up bitmap. """
+
+#----------------------------------------------------------------------
+up_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACTklE"
+    "QVRIic2WP4vUQBjGn/mTMUtgWS6yvb29XGGzzXXHwdWCcGBzH8BCweK+wnWyWKtot6DNge0V"
+    "gjYnNn4BA9vdJvO+81ok2ewmi7d3RtgnZEgm8/545skwiZrNZvgPsgCSJLHWaq211r1Asyyz"
+    "AKy1cRxHUdQzV2sdRZFzzlrbCxdlDmUC1to3Hy8BBA7MRMTEnjwR+fIoRUTkyUaWPBF7osBM"
+    "zDy+fnR2vu+cM8ZU3KV+fLo+fPUUALMQUUGh8FwUnHvKcyoKyj3lOeee7kU291R4JgqemDng"
+    "8ut8Ph+NRoPBoM0F8PPXbw4SJDALcWAOngIRew5MwVPwzMxiTMEsRExBQgghiAMWi0UIoclh"
+    "VY8fegACUVWHBgwQAQIoKEBQngBQ3wPq9bfv7XzX7o1eGS5QqgIpDQAizUMFQCmpR3bf26qc"
+    "NYKV4nVX7aumaavNjayWlfrSriotdQF1WKoD7nAj00yrLCvdQ+rOGiYNt2t4g9+mXprhoqCg"
+    "qnxre1LPqatN762asFJKRFRltvIvzSykTndTwm2uqbYItdL+5aLbX2nDRvPiyds7tC2p2WyW"
+    "pmmSJHEcP3/25cPFSXfQNjqeTE9fPhiPx0mSXF1d9bMxdrUD3OPJtH9uCd0evRX38Oi9Hw79"
+    "cFgMh4dH7/rhHpxc5PfTPN3L070i3cvT9ODk4saqmz9on6eTbQy2tAPrYSe47XxvtUi35Z6d"
+    "78/n88VicTdWHMfLP6Y1rnNuNBotv9W3ldbaObeBa4wp/yr+XRZAlmVZlvWCW+oP2FUt8NYb"
+    "g5wAAAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window up bitmap. """
+
+#----------------------------------------------------------------------
+down = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACFUlE"
+    "QVRIidWVPWvbUBSG3+tv8KKpnYtH/4DuJtCti2nntBm7depQWih0zT9w/AtSQsDQ0JIfkKFD"
+    "wRC61Iu3uBgRiKXz1eFalizb8QfxkFdCurofz3l1zhVyg8EAe1BhH9BHyC3NWkTU/XYFQEVF"
+    "mFlYiImZyR9ezMzEpXKJiVmIWUVYRJ7cPT/uHizhFgqF6+93Lz8fAhAxZo5ZY5I4log4ijiO"
+    "OSKOIomIq+VSRByTMCuxiCiufo3H4yAI8txisQjgz98bUVNTEWNRESVWZiFRYSVWEhGxYjEW"
+    "MWZhNVVVtQoQhuESrtfXw6e7JbTd+k1E6dv3+/3dQPeo3+8/3n22Si+OLgFLn52D4aLTun/V"
+    "er8XnVZ1NKqM/lX9eTNaC92IC+D87HUlDMthWA7D87NXmyzZNL+nl0ez60Nyt4Jux91Kee71"
+    "8Lbd6uxwzXFcr9drNpv+4f2bn59O2gDMAMC5ZJY5wOCcwZxlV7tkKr68PX338Vmj0cBev7f8"
+    "d0GkSG0i0576Alza7707LGqBy2JZblYOPgnm4JJA8Blay41ZnAfO3xbumWjTQOv8+oKZA2AJ"
+    "Y1o3wPucGXYLYVZwWQzQlJWmwIMs6Z8OJUHWcUU1aWZ9WKaGlo67xZlTbbbPbL7oq7fBTHm/"
+    "Jx9+bBRpnea4x92D4XA4mUx2Y9VqteVcAEEQ1Ov13bhZ5fP7IFB4v/v41f8HFQ1ap0nfm7YA"
+    "AAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window down bitmap. """
+
+#----------------------------------------------------------------------
+down_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACaUlE"
+    "QVRIib2WvWsUQRjGn5mdnWxyTaqz9q+QlLnGToSgWAYDNjbpNCAGDGIvaRPbNJGQyiAEbK+w"
+    "sAo2qexyEhbxsvt+jMXc3u3liPfhmWeXnWVm9vc+vO/M7prVzTb+gxyA7Ye/nXPWWmvtXKBb"
+    "B9YBcM5lWZam6by4QNcBsNamaeq9d87NmWutdc59+NgGoKIizCwsxMTMFI8oZmZilzomZiFm"
+    "FWERaXbv7eyueO+TJEHM79LSkvfeWnv2qftgex2ASGDmkrUkKUspiIuCy5IL4qKQgnghdQVx"
+    "ScKsxCKiaH8lIu99NOwAEFGsG4Dv5xeiQYOKBBYVUWJlFhIVVmIlEZGQJKVIYBbWoKqqwQN5"
+    "nqdpuri42OMys6rGOG/X78yW0bXWNyLqcyyAEEIIYcYK3aB5Lazb4o5fsPc3ToFaloxBwMle"
+    "6+9Pjfd7stda6HR85+dCPC86Y6ETcQEcHz32eZ7meZrnx0ePJnlk0vwenm70r/PkTgWdjjuV"
+    "rnPPfvxaa+3NcL3GMaub7XdPtNFoZFn24tmX1/trAOLuM6aaFQwQYExAMPWNaUw1FW+eHj5/"
+    "dbfZbDYajY33F7e1L4gUA5uo3fd8AWbQH70bjGqEyxLq3LoMYhKCgakCIWZoLLdkMRE43Iy0"
+    "tWi9QOP8xoIFAyBUjF7dgOizb9iMhLmByxIAHbAGKYigUPX3hqog47hSvfCHfYRaDcNg3IzO"
+    "7GmydRaGi37zMujrut/9l58nijROQ9yd3ZXLy8urq6vZWFmW9f+Yhrje++XlZR2keDpZa4f+"
+    "H/pKkiR+/f9dDsDWgQW6QHcuxKg/ZbVtCjjzINkAAAAASUVORK5CYII=")
+""" VS2005 focused docking guide window down bitmap. """
+
+#----------------------------------------------------------------------
+left = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACMElE"
+    "QVRIib2WPYsTURSG3zv3ThKJRSqblDYLwU6wFMKCViIEtbKQ/QdWgrXt/oO4hZWCIEIKUfYH"
+    "WFgIATuraewHM3PPh8XNZCaTSWI2oydwMx/kfeY959wzMbPZDC3FaDTavOi23Wgron8n/Z8A"
+    "rnry/NmXk/vXAAhLZCNhYSYiJvbkiciHTwgiIk8uduSJ2BMJMzHzjd93zi9OmwEAbt5+TETd"
+    "bpxlvtuNmZWIcpLcc55z5inLKM8p85RlnHnqxi7zlHsmEk/MLPj6LUmS4XDYDPjx8xezxs56"
+    "4thZUWFWYmEWT0LEnoVJPIlnZlZrc2YlYhIVERHtAIvFYquDu7cIgI0kttY5xHHccdbZKHaR"
+    "jSIAJ8Pru5M+GX+vnm4rslEDmMoFBYCXT9/uVt+MbQAFNCxQGINAe/XmSVuA8MgGxQKjaNVB"
+    "CSmiLQe6kqtUQJfHjQ7unV0eAjCABnFdIrQoRZODBw/frRvdCygZpiABZmmo5mAynupaq/0l"
+    "ACgzpYBZ9dOag8l4CuyT37EPoEXiYUyRg6qD95dn+8QbAWU+jYbqlmWv12DJMLtsNBU5cFZ7"
+    "wJTgzS76+OHRzho3pij8QLVYwlM2dxGAT9PxgQCz9hU6KlSktZ2sqymxthXam0UmjJ7QnxVD"
+    "Lc8is+oPsxx2V3BQf+G8fvH5UIkDAOcXp0mSVF94V4ter5emab/frwMADAaDcOOYSNO00+mE"
+    "4zrgePWaiAMwn8+PF932//MPv0Uk8OspzrYAAAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window left bitmap. """
+
+#----------------------------------------------------------------------
+left_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACVElE"
+    "QVRIibWWvW8TQRDF3+7Ors8ShSsaSpo0dEgoFcINVChSBFRUkajpIKKgiPgP0pqGJiAhITqE"
+    "FIk2BQUVHT2VK+y7ndmhWN/5Ixcbh8tYWvtO8vvdm5mdPXPv+RmuMgjA670/RGSttdZ2q354"
+    "YgkAERVF4b3vHABMCIC11nsfQiCiqwJYa4noxbNvOw/6AJIk62ySJMLMwhI5MnPMnxzMzJHJ"
+    "E0dmicxJhEXk+uTO0fFuCME5h1yDxbh5+zEz93q+LGOv50WUmStOVZSqkjJyWXJVcRm5LKWM"
+    "3PNURq6iMKfIIpJw9n08Hg8Gg36/3wL4+eu3iHpykcWTS5pElCWJpMiJWaIk4RQ5RRERda4S"
+    "UWbhpCmllDQA0+k0pZQFVwF3bzEAZ5N3jgje+0COnPVknbUAdm5cW5/1/eGPxcuL2saoAczC"
+    "DQWAV0/fr1c/HxcBFNC8QGEMMu3NuyddAfIjG9QLjKJTB3NIHV050EZuoQI6+93q4P7B6TYA"
+    "A2gW1xlC61K0OXi492HZ6EbAnGFqEmBmhlYc7A9HutRq/wgA5plSwDT9tORgfzgCNsmv2QfQ"
+    "OvEwps7BooOPpwebxFsB83wazdWdl321BjOGWWejrciZ0+wBMwef76LPnx6trXFrivIfVOsl"
+    "P2V7FwH4MhpuCTBLX7mjckU628naTImlrdDdLDJ59OT+XDDU8SwyTX+Y2bC7hIPVA+fty6/b"
+    "SmwBODreHY/H0+n0P0WLomjegJYAIYTBYNAcp5cOa20IoQXgnMuvAh0GATg8scAEmHQrneMv"
+    "3LAo6X/e0vAAAAAASUVORK5CYII=")
+""" VS2005 focused docking guide window left bitmap. """
+
+#----------------------------------------------------------------------
+right = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACMklE"
+    "QVRIibWWvY7TUBCFz83vojSuKNiShgdAol8hQYWQkJaKAuUNtqWmoeANFgoqhJAQHRLaB6BA"
+    "orC0HWnSUEURK2LPmRmKayeO4wTysydWbI+c+e7xzDgOo9EIK0rTdDW4m0Ij4FBK07R1fdmj"
+    "rh3QqZ6cPf965+ENAKbWardMTZWkUoVCUuIniiSFnW6HQqqQpkpVvfnn3uu395sBAG7fPSXZ"
+    "73ezTPr9rqqTzGm5aJ5rJswy5jkzYZZpJux3O5kwFyVNqKqGb9/H4/Hx8XEz4PLnL1XvdtpC"
+    "7Xba5qbqVFM1oZEqakoTmqiqerudqzqpNDczM+8Bs9lsrYNXw1ub7+nl+DcAVaOa0HJVESM1"
+    "VzVzAG9+LF2/dZFfPHsPAAgIAQAcgDsQ1ly/NeDlu6cAQnC4V7L6/GtfQHTgXuSONopdk4sd"
+    "HRS5vFy0l6EVE5sAD4YXq8GyBh4xwZcTr5jY6CDg0eMPtVjhAPBQ5HXEW9RUgX8A3AE8OTlv"
+    "chACAhy+WHJzH/1XDaqM0oFHPGKHxo7aoYviTz5eDOeRxRwsjUIoSVsCAryaveIACNVkPi/7"
+    "VoDw+dNpLbTURfNlrNcmwJfzk9Vg4cCrzekbEDs/i7x4AMWt3B0AsDTJUR7LscMcNGkxByVj"
+    "7YztBljMAYq1V8ahQfU/nNrc7q/6e9FkMplOpyKyT9Kjo6MkSQaDQZqmdQdJkiRJsk92AFdX"
+    "V71eLx7XAQfRYDCYH68FHOr19C8Ad0k9S0aHzwAAAABJRU5ErkJggg==")
+""" VS2005 unfocused docking guide window right bitmap. """
+
+#----------------------------------------------------------------------
+right_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACWElE"
+    "QVRIibWWv2/TQBTHv3e+uyRbJwZWFv4AJNSRLjChSkhlYqrEzFZVDAwVC3PXsrAUISTExlKJ"
+    "tQMSWzcmFqaqQqT2+8VwtuMkbiBp+mzF0pPz/dzX7z373IMXp7jJCABebf8JIXjvvffrVd8/"
+    "9gFACGE4HMYY1w4AxgGA9z7GmFIKIdwUwHsfQth7/vXuoxEAFfWFV1ERZhYWYmJmykcOZmbi"
+    "EAMTsxCzirCI3BrfPzjcTCkVRYFcg27cubfDzINBLEsaDKKIMXPFWpFUlZTEZclVxSVxWUpJ"
+    "PIihJK5ImJVYRBSn387Pzzc2NkajUQ/g7McvEYuhIJYYCjUVMRYVUWJlFhIVVmIlERErikrE"
+    "mIXVVFXVEnB5eamqWXAW8Gb39uKHevbzNwARZVFirUSIlFkqEVUD8Pb71P1Lt83LZ+8BAA7O"
+    "AYABMAPcFfcvDXj97ikA5wxmHVVrf64LyA7Mau1so770uVjRQa1lzaKtSc2ZWAR4uHsyn2xq"
+    "YBnjbFp4zsRCBw6Ptz/M5GoHgLla15AfUV8F/gEwA/Bk66jPgXNwMNhkyf199F816DIaB5bx"
+    "yB2aO2qFLsp/+Xiy22YmczA1Cq4hLQlwsK56xwHgumLWln0pgPv8aWcmNdVF7TKujkWAL0db"
+    "88nagXWb0xYgVn4XWf0CymdzWQNgapJzWC7HCnPQF5M5aBhXzthqgMkcoF57Zxx6YvaDMzO3"
+    "148pwMHhJhFdXFwQ0XVEh8NhuwOaAqSUUkoxxvaLulp471NKPYC80ci7gXVFALB/7IExMF6j"
+    "bht/AXIQRaTUgkiHAAAAAElFTkSuQmCC")
+""" VS2005 focused docking guide window right bitmap. """
+
+#----------------------------------------------------------------------
+tab = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAACq0lE"
+    "QVRIidWWTWgTQRTHJ+3ETEugERrtF6QhFhKsIlgQRITm5LkBvdiDhBZKc5DiRXryoAEPPRUi"
+    "pTnVi4cee5NePAitFtFoVxSyheYDa02KCd3deW/Gw2Cy7MZaIz307TK7/Gfeb9587Nvx6LpO"
+    "TsA6TgJ6glyqHgcHB4/ub0ZvdRFCBApCCCIAICAHDgBcXcoAADhQLwUOgBxAIAIinju89iRz"
+    "gzHW5Pb09BBCImO3AcDn8xJCECUAWCAsjpaFJgfTBMsCk4NposnB56UmB4sjgOCAiIJsbJXL"
+    "5b6+PsYYtQev5b8hSi/tJIQIKRAloEAUHAQAchQIgoPgiIiys9NClAAIQgohhJBnCKnX6wDQ"
+    "jFfZ0+TA/8xpIv6+8e5cN61Qm05ltEJtOvVMK9QS8ewRpWqj2js4nsb+nbv3cnU9OZ3KzD2c"
+    "/NdIF9IrS4sziXg2+aA/FAr5/X5nvG1AW3o5ufOTL9rgur2c3Mcrd9rgur1Oe7wL6edtcN1e"
+    "7v1wtw2u2+u0z2978S6kV/7CbRmv6sxdquVSH7HTR/9tE+PLUsqp2cz27k/7PTWbkcezifHl"
+    "tbW1XC6n6zp1dONeWaUk4tnjTwtx5F81KEcSaQxzdT1p1xPxrFtpwY3d7C6WKkuLMypVqg4U"
+    "tFiqBEfNYqmi57er1WogEBgOx1oqDVoz/77e2Onu6hq7emGg/6w9imKp8ubt149a/mI0rGqV"
+    "8u7DlyuXRuzKp8/5yzG/yr9NrmEYm1uFba2svTq0c0eu+2LR88z7Qy905PW9vZwvOGqGQ73D"
+    "Q1Lf9eR3vitlONQbHpLBYHBwcJAx5rGfd6rV6v7+vmEY7nVgjDHGDMNo1LZUIpGIc34ppYFA"
+    "gDGmfqgOo5RSSgGgUdtSUSUANLmqWp0q/mTK82hFcX4Bm24GMv+uL+EAAAAASUVORK5CYII=")
+""" VS2005 unfocused docking guide window center bitmap. """
+
+#----------------------------------------------------------------------
+tab_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAAC10lE"
+    "QVRIidWWT0gUcRTH387+ZveXZgzsbmvSsmqEfzBJSYz+gUsHCYJgISPytCQKFhJdpIN0qIUO"
+    "ezIUaU/roQ5eEzp46ZT/DhG4haCXdSUPK+Wuzvze+02HgdFmFqMtD76Bx8yb3/v8vr/3Zn4z"
+    "np6ReTgCYwAwdqfEGFMURVGU/wIdfaswAGCMcc5VVf1fXIBdBgCKoqiq+nxkobn3BABIkgBA"
+    "hIiEJFAgorAOyxARBTKVoUAkgSiJkIhO73a/nLjGOd/nWkrPXbqLiH6/CgBEJiIaKA1BhkG6"
+    "QF1Hw0BdoK6TLtCvMl2gIQhRCiQiCfPLm5ubtbW1YNXXtuzadyJTZV4AkKYkMpEkkRQoEUmQ"
+    "JJQCpSAiMr1eg8hEJJSmlFJK0wdQLBYR0cl9laj7l6LGY5/tc2ejsrmdgeGJbG5nYHgym9uJ"
+    "x9KHeGuMNd7B8fSMzCfvyerq6rHHn2bmEgPDE09G+/9WaSqZmRofisfSiadnotHoozclp94K"
+    "oGWznNxn/e8q4LqznNwXmb4KuO6s4643lZyugOvOcj8PDyrgurOOe30r05tKZv7ALavXmszt"
+    "rXZZL7EjhTmuU8lpRxNSyemZuUEAmJlLOPzU+CAAuKFluO7OWpF4LO1OPsTcejOOTcRepqXR"
+    "tngs7Y6U4bbcqNrIF6bGh6yt0prAgm7kC6E2fSNfWF9b2d7e1jStvqGlbMSmeRsuP7zZZvp8"
+    "PvCoW1s/a2qq7vddD57y3b7VZfmNfGFxadUQBgqztbWps7Pdy04uLq0WSyVJnoMRgUY45NM0"
+    "bXZZ7OvtaA8vLOdeT85mP+4eXN35K/6W5nBjxFz5tv7+w8LWF3+oTW+IBpsavStf1+xIfTTY"
+    "cNbknDPGfqsD5/xCa6AuDFe791xtEJyHIhHedTGw17tnj49EeFdH8GAkEAhwzgF+7HMZY5qm"
+    "cc6tD6rDGGOMMUS075aN2Ho9R/R/9gsXZ7dKHM+ODQAAAABJRU5ErkJggg==")
+""" VS2005 focused docking guide window center bitmap. """
+
+#----------------------------------------------------------------------
+up = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACHUlE"
+    "QVRIidWWP4vUQBjGn8mfcyGQYiM2W8mWsRcLm22uWw6uFpQt7WwVLPwKVsp+gFMsAwqynY2F"
+    "oLAgNu4HsEiz3E7mfee1yN9Lcueu7oo+IcPMZN4fz7yZzEQlSYIDyAMQx/F+ocvl0tkvsdKh"
+    "uF6z8eLsAwDLlpmImNiQISKTX7mIiAx5vkeGiA2RZSZmvnF++9nzO0EQ9HC/vj2fPr0PgFmI"
+    "KCObGc4y1oa0piwjbUhr1oau+Z42lBkmsoaY2eLjpzRN+7kAvn3/wVasWGYhtszWkCViw5bJ"
+    "GrKGmVlcN2MWIiYr1lpr5QjYbDb9eQBw95YBIBBVdDiAC/iAAAoKEOQ3AJRtQL38/OXS/ALw"
+    "XKcxXKBUAVIOAIjUDxUApaQcecV7A3DkuYJG8EVX7VpdtNXm+p4jjfjcrsotdQFlslQH3OH6"
+    "bj2tPCx3Dyk7S5jU3K7hHr91vNTDRUFBFfkt7Uk5p6763lsxYaWUiKjCbOFf6llImd2+DLe5"
+    "ruM0UlA5uazS7S/Usz88vnf2G2VLKkmSap989OD9m8WsO2gbnU7mD5/cHI/H+C/3yR24p5P5"
+    "/rk5dHv0VtzpyWsThiYMszCcnrzaD/d4ttDXIx0NdTTMoqGOouPZ4pdR7e+iq3fzyTYGWzrY"
+    "etj7zwOAOI7/yjmPHRfpFVKr1apqrNfrNE2bx+pOGgwGo9Eor1/wGwRB9QPwh/oH9oed9BPW"
+    "YyQlBOJt4AAAAABJRU5ErkJggg==")
+""" VS2005 unfocused docking guide window up bitmap. """
+#----------------------------------------------------------------------
+up_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACTUlE"
+    "QVRIic2WP28TMRjGH/85c1miqEF8CnbUgSFdukVRmZGQ+gW6Vgwd+hW60Yq1gMQMQzpHGZAg"
+    "C6JS+QIMmUju/L5+Ge6ulzoRTcMh5TmdZfv8/vT4Pcu26h2N8R9kAZwMfltrtdZa60agx5fa"
+    "ArDWpmmaJElTXGBmAWitkyRxzllrG+Zqra21bz+OAQQOzETExJ48EfniKURE5MkmljwRe6LA"
+    "TMz8ZPbs9GzXOWeMQZHfW33/NOufvALALESUU8g95zlnnrKM8pwyT1nGmadHic085Z6Jgidm"
+    "Dhh/mU6nnU6n1WrFXAA/fv7iIEECsxAH5uApELHnwBQ8Bc/MLMbkzELEFCSEEII4YD6fhxAK"
+    "Tsx9/tQDEIgqOzRggAQQQEEBguIFgKoNqDdfvy1yYq41emG4QKkSpDQAiNQfFQClpBoZcaK2"
+    "s0awEHzXVVyri1gxN7FaFuILu6qwtAyokqWWwEvcxNTTKsIK95Cqs4JJzV02vMJvHS/1cFFQ"
+    "UGV+K3tSzWlZq/5bOWGllIio0mzpX+pZSJXdVRmOuabcItRC+ZfKcn+pFRvN65fvNihj9Y7G"
+    "o9FoMplcX18f9M5lUx30zofD4WQyubm56R2Nm9oYY20B98XeRfPcAro+ei1uf/DBt9u+3c7b"
+    "7f7gfTPc/cOr7HE36+5k3Z28u5N1u/uHV/dG3X+gfb7YW8dgpC1YD1vBjfP7oEW6Lvf0bHc6"
+    "nc7n881YaZre3pjucJ1znU7n9qx+qLTWzrkVXGNMcav4d1kAx5camAGzRoiF/gCKPmudbgYP"
+    "HQAAAABJRU5ErkJggg==")
+""" VS2005 focused docking guide window up bitmap. """
+
+#----------------------------------------------------------------------
+aero_dock_pane = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAMAAABnVw3AAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAb3WKdHqPdnyRd3+deYGge4OifISifoallZaWgIy1g463hZC5hZG6iJO8o6Sk"
+    "pKSkpKWlpaampqenqKmpqaqqqqurq6ysrKysra6urq+vr7CwsLGxsbKysrOzs7S0tLS0tLW1"
+    "tba2tre3t7i4uLm5uru7vLy8vL29vr6+iZfLjJrNjpzPjpzQkZ7PkJ/SlKHSkaHek6Pgk6Th"
+    "labjmKjlnqzhnqzjoa/npbPov8DAwMDAwMHBwsLCwsPDw8TExMXFxsbGycnJycrKysvLzMzM"
+    "zM3Nzc7Ozs/Pz9DQ0NDQ0NHR0dLS0tPT09TU1NTU1tbW1tfX0tTY19jY1tjd2NjY2dnZ2dra"
+    "2tvb29zc29zf3Nzc3N3d3d7e3t/fxs7szNPt0NXo0dfu1djk09js2tzk3d/k3d/m2Nzv3N/r"
+    "1Nr02N713OH13OL23+X43+X54ODg4eHh4eLi4+Pj4uPm4uPn4+Tk5OTk5OXl5ubm5+fn4eLo"
+    "4uTs5eXp5efv5+jo6Ojo6enp6urq6+vr6Onv7Ozs7O3t7e7u7u/v4Ob55Oj16Ov37e/26+/9"
+    "7/D28PDw8fHx8vLy8/Pz8/P09PT09fX19vb29vf38vT89ff9+Pj4+Pj5+vr6+vr7+/v8/Pz8"
+    "/f39/v7+////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAsPpcmgAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAf+SURBVGhD7Zr7d9tEGoa9UKBZCiapneBQN3bUQlgo13DbhXBrnRQnS0LJNhDbUO7s"
+    "ErCtZWWZm2Rj2YHdbWQsCSQL2/yjZkaypBlpdKH14XA4vL8kkuebx3PR6HtnHBtHkfxyZoGs"
+    "zMtR4sfjWJRi0mJRHZGlFhej1BCNs1XyocDbpa0ooEjtSfcDOHp6apyFAMzop4XfF2f0K7Vn"
+    "qpyhr0bT5AwHvhpOkzPQ/TVNjt73lT6c4jzQNV/1p8npq77SBlNsj6b4Sr1Ozmtr99xpvQpm"
+    "6LKvquyMVezOe9Ze81uDfNbRHLUtiPaqNi8KvrqqztvlRGGbypFJRM7mMoOtnPNHDV8JisOB"
+    "QczyJolE4qy/MMAX6Pl23VdNGeeMBi+sE0AEzsYl92tgXqj5ipNcnNHo0oYX5OVsnfe8beab"
+    "VVQcelHveTij895XrJdD6SGc4b+HCIglcHTK0yAPJ4dPAYOJtUd/78b3dAdE4owYz6zzcM4Q"
+    "3tEop/v18ePHv+7aICJndMbdIDdn93Iwp/vh7VAf2iAy5/KuC+TmPN0J5HQ+eNDUB51Ji8ic"
+    "zjMhnAwpIbT7TfjXU4+ZeuqfbRNE5miZEE5qGNSe2g//s/RDLYgzSoVwiKlammMmvVTjLE0w"
+    "NH+UJmV37peFe3yInM3NZp0liz/azk+NM0ptt3tkdXZSxGQ1vD3EDOpiep6s9EVSeW+y5e03"
+    "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"
+    "XFekjMjBOHUAAAAASUVORK5CYII=")
+
+#----------------------------------------------------------------------
+aero_dock_pane_denied = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "ABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2qefiJQAAELhJREFUeF7tnfmPHNURx81v"
+    "hEsCIQQCxCnu60d+AH5BCCGBAAkEP/AHABKKkEhCCErCHcA4WGAIYJwYbOMrGHzgE9vYxvje"
+    "9drYa+99etd7zHov766PSn3avFFvu3v6dU9Pz2Q9K5Vmtt9VVd9X76zqOWtSCf4NDw9LfX39"
+    "pMbGxklHR0YKxuHvzj570tVXXz3ptttuO6tgjUykioeGhuTbRYukrr5eRkZG5OTJkwUj6qcd"
+    "2ptIOiyYLFV79khDQ0PBAPEDm/Zot2BCTZSKFy9eLGNjY6mCc+zYMaHdiaLDgsmxYOHCVIHB"
+    "kvij3YIJNVEqLoNTwkgWAxysp2w5Fp2iDI6FkoqVxYBz4sQJSYPM6q1sORaIoyRAOX78eCpE"
+    "W+VhzQIYsgAOwLC8TYvK4EQAB1DY66RBtIX1lIc1C4BQEgobHR1NhegAZXAsgDHDGgrj3CsN"
+    "ohMwjJYtxwIglITCjh49mgrRAc5YcGpqa2Xjxo2yZs0aWaiKR/m5aNonn0hLS4vodUEq1NTc"
+    "LO3t7UK7YbzBP3IgD3JZ9LXSzLJj505Zvny57Nu3T7p7eqS/v9/qzGzBggVO3h4tkwb19fU5"
+    "wyft2lxPGN6QC/mQszQR8OGqqqpKlv3wg7S2tloJ61UISjpy5IgcPnw4FaIDMITaguPlFzmR"
+    "F7lLGqRdu3bJ1q1bnTHcphf65UFJvb29cujQoVSoq6tLuHmNCw4yIC9yI39JAlRRUSH7q6tj"
+    "g5I9RlFw6M1tbW2pUEdHh3D7mg84hnfkRw8lBRC3iNu3b88bGGenruDQm5t1oo5KKDpqGSx0"
+    "cHAwEXDgHz2U1K0qEyMbx7hDmbtcXHDYSDa3tDsbyigAsVJLEhz0gD5KwnpYrcSd/IPmnKiW"
+    "MzZ2TOoaWuWPr051PvnfFqCkwUEm9FESq7jlK1YkYjHuOScKOAMDA9LRmZG/vj07S/zPcxuA"
+    "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"
+    "VvwtWIicAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_dock_pane_bottom = PyEmbeddedImage(
+    "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")
+
+#----------------------------------------------------------------------
+aero_dock_pane_center = PyEmbeddedImage(
+    "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"
+    "AAAASUVORK5CYII=")
+
+#----------------------------------------------------------------------
+aero_dock_pane_left = PyEmbeddedImage(
+    "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")
+
+#----------------------------------------------------------------------
+aero_dock_pane_right = PyEmbeddedImage(
+    "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"
+    "SBhbDwAAAABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_dock_pane_top = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzoyMTozMiArMDEwMExUiZ4AAAAHdElNRQfZAxkQKSNpU8hr"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAEFhJREFUeNrtXWlsXNUV"
+    "Pm8W22OPYzu24yXxEscxzk621kDaAGVTFVqxCoRaxJ9WlSr6j1+V2p+tVLX9U1URUlNVXdgK"
+    "EhRCgYKgSShtFpw4qx3I6iReEie2x57tvZ7vzVz7eebNzNtm3kPyJ109+828e885313Oucsb"
+    "iTyISCSiHDzyOf3peIKGp+SildMa9tH31wVoZXvbi21tbT9wW+9MSG4LkInp6Wnl8Rc/J2XN"
+    "nXRfn0JdIYlCfL+MJS3ja4Cvfr76DOancEoi8R8Jvkb5OsvXKU6DEYU+/UQi3xcHaPdj7S8x"
+    "QU+7rb8WAbcFyMR/j/STtKqPfnFHkqoUifxszYAPZPDfTIwkpWqUmVoFgtD+ZAVJoQSI4hvb"
+    "JYUeu8dHL8z00dD5z57ir3iKHKMVsGTYcyxOnTskKkumjFpMgKRgUqa6h1Lleg2eI2dsRqGm"
+    "ComKN9IsBMppDfnUcr0Gz5GziHl4bswBUJuVHAmQyFyXp+j8LcYhtbxSNVOT8GTLwcCtKGlC"
+    "cE0bT0kzZLYDUpSFSc7436vwZMsBGXE2mo+vki/loamMpK+Skr5nEHKa0KQiPLa0ay0vbEFe"
+    "gyfJgbsrswVlad6YPjajTCk/WnWlTdR4lQC1lShz+Qm3mtSy/G6rrAtvkiOn3Fw/SEmnpOZz"
+    "lRwTLUd0ZSIYVVtNOikWuslSwZPkoLtJLqjhCwNPswOldvyaD0ZTZah5erRf8yQ5MFxc03Ik"
+    "zXiDq3oxUd0XEJJulXE5lZBfwqNNx5PkJLj/iSdT82gQEC1lriuT0/9bcQjSLVJc0ULVLBdb"
+    "jnGkxgSFr0gStyApVfPF6CCZdwiSmi5NzRctSE5l4lFuik/O4NCQcvXKFYpGozQxMVFw8N1z"
+    "gY2WSNVqdezxpQyrOgWa6NNnsuVox5lk2jlIpLtM0XJefe21vOKhyNraWiovL6fmlhZa3d1d"
+    "1Fn9opCze/fu3q3btp0cHRmheCxGa9aupbJgkMLhcMFn9/z2E3rpukJN3K8tLZeoOihRlV+i"
+    "CvZ2y5iooC81O+03YRYxCx1jdqJ8neYbk3GiGzE45xL9jfPayd977NFHC+Y1NTVF8Xicrl27"
+    "Rnv37lUaly2jbVu3FoUkx8k5evSocvHSJWpuaqItmzdbymOWW84UG66cI1AI6FfdLYkUf8rj"
+    "MkOO6NJATpTJmeUmM8PkRNjjmI4paqwTjyeNZcYQFayuro56e3tpeHiY3n7nHaVtxQrauHGj"
+    "oyQ5Ss7hw4eVmZkZevCBB8jnsz4zFOVaHWGCKlm6crYbNx61GxNdGRwF2SQ58MxinFc0nWaS"
+    "qTJAdtI4N1lobW2l5uZmOnTokKr/li1bHCPIsbm1I0eOKKHKStq+fbstYlRwTZ7mqj7Do/Ys"
+    "J9T4WDKV4rL5pD7LA4varaXzRIpwGRG+2iFHNSLrC72hP+zglE0dIefosWNKgkfx23p6nJEq"
+    "keraoolUbVdTOi5BDyScBW2C9xXmJpaU9T9X3XNZ04I0ZZBNcgSgP+wAeziRnyPkXOYx5vbb"
+    "b3dGwzRkTVIKJHR33+0I0IrpS+rVJxV+Rpu/k4AdYA8nYJucg4cOKRs2bCC/353JQzgG326V"
+    "6PjJL+gnL/xaveJ/M96co/KwHWAP2MVuXrbJGR0dVQdFt7BxaYCuXJugn//yVaqsblWv+B/3"
+    "3QLsAbvYhS1yTp06pazq6nLNCJvrAzR58Sr97FfvU3Vdx1zC/7iPz90C7AL72MnDFjlXORBr"
+    "bGx0RfmeGj9dPzdOL77yBYVr27MS7uPz2/h7bvRwDWyXEQ7C7cBW1ZqanKRQKFRyxTurfRQd"
+    "jtAHn82oXVku4PNvJqepu62KTtxIlFTGKnarb926ZSsPW+REYzEKBoPOa+bL36SvRhS6t6uK"
+    "WpsqC2YVrpToo7HcvnKxNlHALrCPHdgiR+bATjIzd28ADSGJqhCzlPlyGm6Wg8qP2eAhA9LP"
+    "jKema/RQwc9XBX1UnS7Xacg21yI8t2Tw3PoAfXTMT8u/wcbnCh8OSBxcEoXYNy73pyY+A+m5"
+    "tYQB3bGVd0mZxMGnRBWyQuX8fNCnUJlfoUbmrIpJqd8r0fc2e84U3iNn51130LqDn9Kfj/fR"
+    "mq8ptLrSR7VMSpjJCLGhy/mKjjRgYm4NDSfGCZs6p5nQCU7XufWdmeUAeh9Rr/wf+taOO9xW"
+    "PQuOkKM4vPnr7ef76P1/H6CX35NpKFK8NeTVPB79tNdH9z9zp6M6ONXVe67lCNz/jTs5uS2F"
+    "u/Dkjs+vOpxqhbZbDgRxulv7qsOpbm0ul4GBAeXcuXM0Mztr+GFEwGZnCCoqKqijvZ3Wrl1b"
+    "IlPZx4kTJ+j8hQs0a8I2MOzI6CgtW7bM8DMhtk1nZyetX79eEnnQ62+8oWzatImWt7ZSWVmZ"
+    "4cwwuQdyzLScGAdml4eHqb+/n77z8MNZn2N9/tjAgJo3ZnidjqMyEQgEqH7pUhhE9/M333qL"
+    "rNgGcgv7WLHNo488IklYGKoOh6mjo8O0Yii8oaHBklHOnz+vTm+sW7duwf19+/ereXavWmV/"
+    "RdUAUBkGBwfVvzMJOn78OC1ZssSSbayQo7XN5NQU+c59+SUtX7686EbIxIoVK+gcC6EFdrZg"
+    "D8I67vKw/QhTIMVOlZWVtHr1ahodG8uSEfK5ZhvmJYD5HzTtUgNlxqLRBV0i/nZjBhktNJlI"
+    "ZHXPkM8t24CXRVfaw3AtCFVdcFoYE7jtkGe2HLfkEXLYIsdOjJPPC1O7tyJ7aWb1LOVzAnPk"
+    "WMlIsfhcTgUyxp9SQ69MOxXQqn1ExQwIAaysPSj8jFHhMeiK76JwvZYh8rG7DmLWEPnk19pG"
+    "yF1IPqEb7GNWF61tfFqjmIUZYs4Px2g25iv4nBOt0awOotx8nwOQH3oUir+EfpZ6I81zgcwb"
+    "pjKiwoZElH/q7E06fDJOO7++lFrqKct9zmeQUiJft4bafP1WkvYfvsWxWJB6V9VQssA+XisV"
+    "Tduj2BpzxBiR69lAIEgjY5P08WfD5AvWLVBWSZ9k1iOq1OTkLDerBUg0PZNgfUZpaY2fljVU"
+    "UyIRz5exLV3mujUrSU73qXpJknx04dII/fGV/1FMs55spJXKmrGsVCkfcUIeAegDvaAf9MzU"
+    "XWsfKzYVZfm0AphNuQRAhDs+PkF7/vLBgrPkipJRETIqhhg8rcpjJWUSkU++OX7SR7OhH/SE"
+    "vnqV1ooe2hZsu+VkCoA+8/Tgl/Sb3/1V4xkrJIbdzNqhV3tL2XJyyaK9N/+deT1EZYOe0Fd4"
+    "cYUqrhF5BNQxB1PVMQt7rDBJOT09ndUtdLa30vM/eop+/4d/ZtUMrImIgVT8P9ddsAyKetIs"
+    "XjJ3Gp4XykO5mes1Qj7IheUCWQ5l6QM9a2uqFmwgBFHIF/ZBMgM4UMIbVMmBsQp5HnoQz2WS"
+    "Mzk5SQ31dfTcM/fRy28ey1I4sw8XELUHeZaKHCPjXy55oF9DfQ3duHFjQT4idrJq1yxX2hI5"
+    "eQTHWkb7imZ69snt9MZ7F+c8O3wfB4y0TV9rCK1BSoFcXYr4DPcg79zsNN8LBnz0JOsFb+3a"
+    "tatZBIMctICkRT2EHAE7xpBztByB4eHLVFNTw/FNixrnKEp2y9F71mqNs4tcsszLjE2Iftqy"
+    "pUXdjAj99CBiFdmCHtoA114QmqPGaYEm39q4hCLREIVZoWgkviDO0Ws5pdw0kumIZHw4px/G"
+    "Jey77u0KsT6yqlcuiCkYK3pkudLFBlY4u1fITMyIqqQwSrar6u6igZ4rLQC5IT/0gD6lQEm2"
+    "RqFp37x5M+fzc3+nbpRE8UKy6Olnxqt1oqK5vuMz15KB67J4AK6QM2eEHHNrrkCvB3CZLNdb"
+    "TibMmEMMvHZWTeHyxtlVdus0eD4EhJKlhtYh0N4zChFLIHJHHGIVCR4PsU+sesmSrPLd7uQC"
+    "5awcBmz416WIyucCNC5T78ii0WqCfLC3bf+BA7m7H82qpU+vAqbd3RompkvnVDjkc8s24CXQ"
+    "uXKl+noqnJ0Xc0xGgagZyYzgKBxGxduWGnPsFjXSVcFgeIcbrvfec0/OKH1gYEDdONje3p71"
+    "PGT/14cfUktLi24ZkO/ayAi18ucJnX1t+YwsbGNm3xvkxV7yy5cvq3umAxs3bJD+/vrrCjLB"
+    "24/M7AeeZeNgu6qZKBhKDl+5QidPnqQdO3Ys+AyCof+H4QrJge9gRybkRg3XGzMg39jYGPX1"
+    "9eme+kYgGYlE1MqiB+wE3bdvHwW5jKamJsO2EeTEuLLDPkaBxqHa5tQpvPttvnr29/crFy5e"
+    "NLWTHqcM6mpr1Tkko8BL8eq5Rvaw4nq4dOmS+n6DgIEBuoINDkIxj6fXepFHkA2aa2Y4XFVF"
+    "y9jojQX2e58ZHKRxJjkWN/ZLIYKc8fFxU6cMoEt7Wxs2zs+fMrAKvHbx7p07TU+LG4ERQ5QV"
+    "45i9AwAxaDF7332Xnnj8ccs29pwrLeBVw5cSi3ulPQzPtpyhoSH1WIaVFVqjwACP8aa7u9tt"
+    "dXXhSXJwgAovldu6dasp79EsxEkylLfjrrvcVjsLniMHp8zwVl0rp8nMAsSv5HgCASrKXZ3D"
+    "g3QLnhtz0JWV+uV6OL2md7LNbdhqOWJzeqHN4GaAQMzIm6hmowpNzxYuM1QuUWVFfm8W5cUN"
+    "xjBGIOxh90yrLXLKbU462sGFK7N06PgkTU7nnp2orvLTxtvCtK678Ku/nILYFgWyy22Ol7bI"
+    "CVdXqwEoIttSb8jo6QwRyTF695OLOb9z97Y26ukqTIzT60ggB/v5zEzd6MEWOXgl/sTNm7S8"
+    "qspxcowYrKerhgL+BL36j/6sz57YtYm6OmoM5ePkkomYUB2/ft3U1I1uXnYe7u3tlfALHxDG"
+    "SQXNbF3t6qin557cSjOTV+cS/sd9I9thnYSYU4MXiJll2MdOfra9tabmZvU1IhDIKYLMGA0E"
+    "LK0L07NP302zkXH1iv+NLmM4RZB28Q+xE2ax7cI2Ofh5krNnz6qCOfk6FDObv1FkZ3sL/fiH"
+    "T6hX/O/UERAz5IilizOnTzvysy2OBKF40RDWZ9asWaNG3fl2gRolxuzKI77f3NRg2nu0GwaI"
+    "hUEQA8fo8/7+rIU9q3AkCMXvxlSxU4C3TmHhyukxyCis7lq1CtGVQWestg4ODamvLHbqd3Qc"
+    "myHA78bAU8Hrr1CDBEm4Z3aHTKkOTlnZFyB0EeMLVlihK1oM9jI4+fs5js6tQTD88hQmEnt6"
+    "elRXG92MWH83Ygy7W52sQJRZaL1fBJggRiyPYy/EaR5j0JV5+penACHgwYMHlcEzZ9R9CXit"
+    "FRQxEpSJ1lYqCIOL1ctC38XZIwTeWKK/wmEE9Nu1a1dRalPRq6j21w5vTEwU/D6UfujBBx2d"
+    "68oHseMFL70zEjTWfdV/7VALswpgXwJehgcySwGQg8EcxNhZ7y8GPLeeA5TyZJuTM+pOw7Pk"
+    "lOpMaK7zqV6AJ8mxEoRaxSI5JuHWsUOvwXPL1IuYxyI5HsYiOR7GIjkexiI5HoYnyfHSm3Hd"
+    "hOfI0R6DLDYyj/l5DZ6Lc+wcgzSLzGN+XoMn+w8cg1zT22v6GKRZgHycosMCIY75ua13Jjwn"
+    "kICVY5BmkXnMz2v4P+EM9joepX/9AAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_down = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo1MTo0MyArMDEwMMndnrAAAAAHdElNRQfZAxkQNALaVrQp"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAhJJREFUeNrtl01v2kAQ"
+    "ht81FgECjUQUyeKjBrfi0EOJktxzg0uOSaWe0lNP/Wk99lBy7A+oSiO1ORE+BChSTjGfBuPs"
+    "rATCNSkmyHtpX2ll2czOs+OdWTMMXIPBwKnVaqjX6xiORghK0UgEuVwOhmEgFosx1u/3ncrV"
+    "FYrFItKpFMLhcGBwy7LQ7nRQrVZRLpXAfl5fO4l4HLquBwb9U41GA2avB6V+e4t0Oi0NTMpk"
+    "MiCuOuavQlXVtRNGFs+NobPWLhphiO783YZ4gut3tc3OEN9/9fDQt5+0ebEbwttCHG9eR335"
+    "9A0v5LhDx0LlW+tJm6OTLAr59WDHcTaDiwXk96AqNj5/+eH57fzsEIa+t4k7KMur8TMMPYkP"
+    "744xMO8Wg+7puZ/5HrhfMI3ZbIb9ZByX708xHt6LK93Tc78+XHu+alXrlNdT+PTxgpepBtu2"
+    "fc8nu1AotB18Op1C0w7EdRMxxrwJtyn8uXOW9ezIt5ErctlwT+SUrTKkKIo7cvrUTSYTKXDK"
+    "dEo6V+RULrLkipxeuSy4p9QILmvP5yfhAi4z4VbCZZXaMkfZws/W+g//R+Hz4046fIe3R3S6"
+    "0YEftChIOtuJR1zRLvHiQ4r3afRxCbLeCRzhzWK73Rb/gNRXvGP8WqmILkLTtEAbRQqu0+3i"
+    "980NyuUyxGabpila5GarhVGALTJF/TKbFS1yIpFgj6VqglrJraorAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_down_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo1NDo1OSArMDEwMEcuCiQAAAAHdElNRQfZAxkQNxVyqGIt"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAABENJREFUeNrtV02IHEUU"
+    "/qq6529nFnezLtGNEEk0O5NZI4GoQaLxoCJ4NgjBgAe9K/5c9SToQbx6UaJgQLyJXgIRDUkk"
+    "t+iS1YDgwSWHMGOyO7Mz0z/l97qqZ3vGnd0ZYb1oDY9XXT39vve+eu9VtwJHo9H4+ufrK8+f"
+    "XQ6xuh5jt8ZCReNM3Ue9uvjl3NzcKUXgH06fvX7C1B7H08cNDpQUSvxjXlGofWqPWo8JYCiR"
+    "CCchdZe6Q71OudE2uPy9gv7tEj57qXpeXbh4yXzQfAzvnTQoGwWPKL4WMM4JrERgZdwhDgh/"
+    "sRExCMURLhjOu1rjrW8M3tz3I/QnPwW4/4RCPrIPjRpaWad2Er2Nl+JELoox+xwguP6tDYOD"
+    "RYW4sz1wnjzeaW3nnh2VKQXDvYpH/FUYWShpLBPXH4fGPCNaudHC+ctNNG6HI/+35y4fTx6b"
+    "wZGlaYTRznb91BszQmR0aKhWrUDo+fSrX0YaO/XsImqHp9HK+GcyOq2jOM6CG0kGByhabmo7"
+    "ly1kHqJNg/X6PF7xAnz48Xd/A37t1adwqDqP9cAM2jIZ+0NbkVSQgAUuI6VE0lLpZ2xs9Z2e"
+    "waHFBbz7xjNYa/7eF7mWdbkfG/QlGpqL/SDeZEDbyPlQbKx2YuhRMocTt367F+PevTN45+0X"
+    "0F5bTbRcy3r/WQzZyNplJIO0x7YMPIp2ks2XpM4zJXQr9FCvHcBH77+OBw7ux83OYJmmVKcM"
+    "JlE7SbekD57SnaUs21iGu5s8vLoBzNy3P9HDI7vnm83GYqg0w7MJF2QiV8YhO52oLep2Y0Q5"
+    "DQA6VgO332IvNNnIaSSIbB/3XaR9qmN3PUF/jV3kUZrA8WbCqeFSs3tiqEXY043tUHG6O2rr"
+    "yEcNM1QtiV1hwLW9NNtt5KH1Ktl7bR9Mki6lHtv37K0iz+5zWr6h29KByM81DPaS9z0Fhemc"
+    "QpnHWdGzbTWn7enmTQCenmI9onepW1xYC4Amy1Hx9wVtnUzBO4x8nTcKSicLXpKuPCA8m7GT"
+    "gKeUC3iX4NKaNwjeZka3erbWgyDajLwb2PY5xasC1xl8QnNKtSRiPCG4ZHaPtrpOpDIEQ4KJ"
+    "ogztkuotulrmYpEbnReqo836NhOCJ22UKD2JPpLorbRDY50bAA8t9V1Kj1T3tHt9cm8xySEz"
+    "IXjax/sMOIxkDIDDlQV2Pl7HAd9KUtvZMe574a6M/8H/q+D63/Mii+Pfzc+jMmugwka+2w4U"
+    "WdjlnMY054Lrv/xQDheuedj3RIQSi7/C7lLJASV2mIJnDxb/H/T2gC2xyN5e4PM5HpF5vqnM"
+    "c71M0LlvFc4c9eEfXTq8Ur96pfr58nHUHjV4cEpjhqAVgvHDgocNHYDteOOCy6nGMwT8KEGL"
+    "rP5JadCjX/mu98dFoBpfwbGHl2z3bDab5uq1ZZxbiXGztXufyPeUNV6sajxypI7Z2Vn1F7X+"
+    "m7ZM/KBNAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_down_focus_single = aero_down_focus
+
+#----------------------------------------------------------------------
+aero_down_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo1MTo0MyArMDEwMMndnrAAAAAHdElNRQfZAxkQNALaVrQp"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAhJJREFUeNrtl01v2kAQ"
+    "ht81FgECjUQUyeKjBrfi0EOJktxzg0uOSaWe0lNP/Wk99lBy7A+oSiO1ORE+BChSTjGfBuPs"
+    "rATCNSkmyHtpX2ll2czOs+OdWTMMXIPBwKnVaqjX6xiORghK0UgEuVwOhmEgFosx1u/3ncrV"
+    "FYrFItKpFMLhcGBwy7LQ7nRQrVZRLpXAfl5fO4l4HLquBwb9U41GA2avB6V+e4t0Oi0NTMpk"
+    "MiCuOuavQlXVtRNGFs+NobPWLhphiO783YZ4gut3tc3OEN9/9fDQt5+0ebEbwttCHG9eR335"
+    "9A0v5LhDx0LlW+tJm6OTLAr59WDHcTaDiwXk96AqNj5/+eH57fzsEIa+t4k7KMur8TMMPYkP"
+    "744xMO8Wg+7puZ/5HrhfMI3ZbIb9ZByX708xHt6LK93Tc78+XHu+alXrlNdT+PTxgpepBtu2"
+    "fc8nu1AotB18Op1C0w7EdRMxxrwJtyn8uXOW9ezIt5ErctlwT+SUrTKkKIo7cvrUTSYTKXDK"
+    "dEo6V+RULrLkipxeuSy4p9QILmvP5yfhAi4z4VbCZZXaMkfZws/W+g//R+Hz4046fIe3R3S6"
+    "0YEftChIOtuJR1zRLvHiQ4r3afRxCbLeCRzhzWK73Rb/gNRXvGP8WqmILkLTtEAbRQqu0+3i"
+    "980NyuUyxGabpila5GarhVGALTJF/TKbFS1yIpFgj6VqglrJraorAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_left = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo0NDo0MCArMDEwMN+SkKkAAAAHdElNRQfZAxkQMBKjjWFJ"
+    "AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAABGdBTUEAALGPC/xhBQAAAkJJREFUeNrtV02P0lAU"
+    "PS2lUEIlkxlHpCAEZ89Ol27M8A/czMK4duO/caeJiSZu3SgTN25M3DhBFkMmDhQJEK0apnwM"
+    "0wK1t+Z1YOqyr2w8yWuT95qcc9+97/UeAS6m06nTarWg6zrOZzPwhJJMolQqoVwuI5VKCcJk"
+    "MnFqh4eoVCrQcjnIssxVgGVZ6PX7qNfrqO7vQ/jSaDhqOo1isciV+Co6nQ5G4zFEvd2GpmmR"
+    "khPy+TyIW7xwt0SSpMgFECdxi5EzX8HGBDiOs1kBDH7ymaKoIAjCpQAiXy6XXAlFUfR4aBA5"
+    "EyBGET2R630LM+tvxpmQNQG8BpE3T8/w8cjEb3MREMe1BuLxOL4bY3z4NIAob/nzq1x+DYQt"
+    "IBaLodM18PpNA0p6Fwn5kpzqjXZmTUCYRUiR//x1hucv3yOl3lhbY4Gyd+g7QJGffG3jxau3"
+    "SCg7gXUWLH3nC6BfJI2wUC4V8OTxAZ4+qwXWiGexWPgp8J40EeYwTRM72xk8OrgfEMC+CRzD"
+    "sEUYhoFi4ToePriDuBTzBdD20zqrOWl1Mmz0ej1kMhncu3sTn5u2XwORHEOG4XAIbfcazm0F"
+    "aUXExdQO3oS8MXZbrz1t6ZL/gG3ba2uRtEKUYirMf2Hj/cB/AZ4A1hxsREDCdUKrVyNvULD0"
+    "HyBO4vackXsokXNtGR0R3t0RkSddf0iX1Hw+h3TbNYnvajXPKGSzWe7ekILsDwY4bjZRrVbh"
+    "JX80Gnnu+Fu3ixlnd0zR3yoUPHesqqrwB18A5ik1mQXQAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_left_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo0NjozNCArMDEwMCXtbZ4AAAAHdElNRQfZAxkQLw561jOY"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAABAVJREFUeNrtV02IHEUY"
+    "fVXTO70/M+yOExNd4oIRkgljDIiyQZR4FD0rQlDw6E1RDwkoIqiHXLzlKK4Iwb2peFDJHgxx"
+    "dS+LcTMhhw0qJkvG7Jjsz8xOd1f5qqu6p9eNMB2Y9WLBm6+nf+p79X2vvqoSYFtdXf3ql8bl"
+    "52aWQlxbVxhkmyxJvFz3UK8dmq1Wqy8IOv/+xEzjSV17AsePaTw0KjDCF4cFUKQtEB6vJSz6"
+    "bWYYERFqoEvbpW3TXm1rfDsvIBsX8OlLte/E3PkL+vTqNN4/rlGCQEE6hzGEta5TkYOATsCf"
+    "SBtCGqGy9wJ2+vo5jbcqP0J+fDHA/qcEisqyHnSL6MTjz+GnBYxv+SdDso/x1rvgPBudvb6A"
+    "8Z0nrQNpXsJIZaxBNt/a/c8bJf0vME3pDAGlbG4ieikYLUgrPOV6MULU4i5EqK0j7XyYazMz"
+    "RGYkXsImhbAvpIJ0Q8/jHM55MmLl+out6hFMCUR8OyCksiMX0kYj7gV26CInCZVxbvofKQhs"
+    "0Jq6IPkkISKTFKQRcB9plWGtt+ujH8QRcBgfEmj+3sYe1hVTY0J3PyUQhYiLhHkQa8Hlalvo"
+    "7hITRYErl5r44txNrNyMUGQkEpKZFLBUKiu2AjKhduKLLXKKkB9MjQn89kcLs18vo+Dvi++b"
+    "gQZRTwtecjMk3UiaHAlb97VlGidfO2306dy8N+krNK5cx+kz51GamMKo77TB3Ea6Nw1lEoFA"
+    "WSKR00SaBpU/Dff4EteuN/HOB5/dUZyh01hKwITEpMDAEAl0EpV/6KIPDDPHlxYX8eprH94x"
+    "Oqb/bmT7TFMw09SodgJUWJ/HKZoSpWqmjU9BDMWrI1dJt0L20w7Wj+LMRyfxxtuf7Hi2fFvh"
+    "V+45vuTYp9IUBMAaZ8IGmW0SbaKjLLZULzr9ovFXhMn778V7p07sIGD62wyxvQ6ABDZC+6BD"
+    "bEUWXYdA5UOH33yzAhw++ADeffMZ+MVCSsD013YzIUMgIgHFkWt+TFBJW6TYpQ2IxOaB6efz"
+    "qwHWS+N4/tkDGC95lgCfbdJXkNUA1E7RKbcoZStknqacKBeaIer7q5jurGGC+8Em05Msfr0I"
+    "DLgttRRGDpQxe4Ob3s3tQ/F2g4BJ7Q90fivYuaP4z3dE/xOQye9uMjG+ksrg7RkRGKMwy0W5"
+    "KyR8yr7M+r5GPRrf3itHhjC3WODhJILPyVv27FowSgy7tWAo51pgmqkBoVtlhyPEffmePX+U"
+    "6bg8h/iM6D16pH6jvjC/9+zSMTw4rXGIZ8MJeivTMS/hmzOiMCTypSl2Trulbeldp71NIsu8"
+    "cfEnoHZrHo8dfdjuMVqtll74eQlnLyusbAz2gHbfmMSLNYnHH6mjUqmIvwGdqbciWIcx6wAA"
+    "AABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_left_focus_single = aero_left_focus
+
+#----------------------------------------------------------------------
+aero_left_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo0NDo0MCArMDEwMN+SkKkAAAAHdElNRQfZAxkQMBKjjWFJ"
+    "AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAABGdBTUEAALGPC/xhBQAAAkJJREFUeNrtV02P0lAU"
+    "PS2lUEIlkxlHpCAEZ89Ol27M8A/czMK4duO/caeJiSZu3SgTN25M3DhBFkMmDhQJEK0apnwM"
+    "0wK1t+Z1YOqyr2w8yWuT95qcc9+97/UeAS6m06nTarWg6zrOZzPwhJJMolQqoVwuI5VKCcJk"
+    "MnFqh4eoVCrQcjnIssxVgGVZ6PX7qNfrqO7vQ/jSaDhqOo1isciV+Co6nQ5G4zFEvd2GpmmR"
+    "khPy+TyIW7xwt0SSpMgFECdxi5EzX8HGBDiOs1kBDH7ymaKoIAjCpQAiXy6XXAlFUfR4aBA5"
+    "EyBGET2R630LM+tvxpmQNQG8BpE3T8/w8cjEb3MREMe1BuLxOL4bY3z4NIAob/nzq1x+DYQt"
+    "IBaLodM18PpNA0p6Fwn5kpzqjXZmTUCYRUiR//x1hucv3yOl3lhbY4Gyd+g7QJGffG3jxau3"
+    "SCg7gXUWLH3nC6BfJI2wUC4V8OTxAZ4+qwXWiGexWPgp8J40EeYwTRM72xk8OrgfEMC+CRzD"
+    "sEUYhoFi4ToePriDuBTzBdD20zqrOWl1Mmz0ej1kMhncu3sTn5u2XwORHEOG4XAIbfcazm0F"
+    "aUXExdQO3oS8MXZbrz1t6ZL/gG3ba2uRtEKUYirMf2Hj/cB/AZ4A1hxsREDCdUKrVyNvULD0"
+    "HyBO4vackXsokXNtGR0R3t0RkSddf0iX1Hw+h3TbNYnvajXPKGSzWe7ekILsDwY4bjZRrVbh"
+    "JX80Gnnu+Fu3ixlnd0zR3yoUPHesqqrwB18A5ik1mQXQAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_right = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo0NToxOCArMDEwMEtfu5QAAAAHdElNRQfZAxkQLyM/CW/t"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAkpJREFUeNrtVz2PEkEY"
+    "fnbZQ+AgGD+R5YSAxVkRLfwF5vgH11xlbeNPsbE2Ftf4C+RiY2OijeGu8GIusEjgiJ4Ej689"
+    "YHedd8zgsBgt3Fkan+TNZnY3eZ55v2ZeDQzj8dir1+uwLAsT24ZKxGMxFAoFFItFJBIJTRuN"
+    "Rl714ADlchlmNotoNKpUwHQ6RbvTQa1WQ2VnB9rh0ZGXSiaRz+eVEvvRbDYxGA6hW40GTNMM"
+    "lZyQy+VA3PoFc4lhGKELIE7i1kNn9mFtAjzPW68AgUXwhaKwoGnaLwFE7rru4gOZWKsiFwJ0"
+    "/+7tqQ6rw7JTVxcd4hOchvyCVPXOHbz9cA57soHtUhqO4yjxgMBSDogPo4mDN+/OcCVt4Ob1"
+    "JGazmTJvLEIgu4Uwmzt48fI9mq2vPBzyP/9qlF9LZeh/KeP5/mucffuOSCTC/wnCBOcfPSDj"
+    "6bN9fDppBOYJucJ4DtARSfbzKI6vCHjyeA+X05sYstMrCJA3RZVxAZTpwvx4tPcQ166m0ev1"
+    "Ak2+lTIkctk1G0YEu7sPeBV0u91AyQmCyxALEiBUbcYjuH/vFnsC7XY7cHK5yS01Iqr3ZELH"
+    "3VIc5g0X/X4/cHKx4d+ehiTgYvwFd0w3sIT7G1auQiRCZefzY+33gf8CuAD5eAxdwCXWfqkH"
+    "qLyAyKDNUismTuLmkxErSmTZWEbZr/puSOQxNh9Sg5vP5zBKbEh8Va3yQSGTySifDWmTndNT"
+    "fDw+RqVSAQ/+YDDg0/HnVgu24umYdn97a4tPx6lUSvsBjEDOU65zEi4AAAAASUVORK5CYII=")
+
+#----------------------------------------------------------------------
+aero_right_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo0ODo0NiArMDEwMKZ+RR0AAAAHdElNRQfZAxkQMQU5RdXP"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAA/ZJREFUeNrtV09oVEcY"
+    "/83sy27UfZhtNLWxKNaDK6sNlJZIabHgpdB7KYiCR28W7EEPIkLbgz1481hIaSt4a6UUWkyh"
+    "Imm9hKbpSg7pIUVjotnGJG5235uZft+bmc1bk8A+NTn1W743b98bvt9vvn9vRoBkbm7uxp/V"
+    "ux8Mjce4t6ixkdJflDhZCVApH7je29v7oSDwX48PVd8x5bdx9IjB/q0CW2hitwDyNOZIA7qX"
+    "sNqp8DIUaWyAJo1NGus0/l03+GlEQFZv46sT5Z/F8K3b5vLcID49alCEQE46wESFHZ1RkYGA"
+    "8UoXZZiQQazts4iMfnzT4JPSb5BfjkV49V2BvLasN1oUgQR0OfieAGPLh+SSl8nfZhPA097p"
+    "KwgwdpawbogEnpFOjazpeBv3P6uXzDrKok2KgNY2NopQcpwL0iaedlY4EY14hiQ0Fsg4DL7n"
+    "yhCplQSeTUuFndBKSLf0LOBw4H7F2tlLRr1CsEVA0eyIVNLLAi19K9VhnWvHOOc7UllI6BQ4"
+    "21euHLkvSHrjiUgfAp7I9d9H/n44VUdPl1hhbdrzoxM1ZrV6W7FfmyegYiRNIp8TmH6k8N3N"
+    "R5j4axalvGwj8TyqUupJrhDgdqktCZb5xRjXf5jEvw9q2EutudXNMgKyPT96jVgV2kNgX1Jc"
+    "Ur2w0VS4+MWPqE5Mob+giAS9z6j84/jrVC7ERrcW0+aByJXi03Lhs69x7/4sXqLszOIBg7Xd"
+    "7xPRpD3ALklCsE6nOX3mc1RHR9FNOaLWMLiWxs5e7O4jF+amsuoXm5Th0KxB73JEEwMMyNXF"
+    "dvXKOQQ7dmFiXnVchp5IRC5oENgy/VmiZJ+n7zKtA9/T2ve0+kAELNDLZY1VH/1L54+j/5Wd"
+    "+GVGZWrF3tVRAm71CWEsKQuq0x4AEWB2DdV6gkI+h7Nn38ee3SXcmIptvDJ0Ik8gcbu2thMi"
+    "ZIr3HJFqI6CIgKaJtvNtLwY4duw1LBS349vJJgJC9puULASiBNwkMW/QAw4Dd1jpynGFgKvR"
+    "Wfo+9+yUGBwIgd0hRmbipDXL9LehQ1mvCTEOL0alq8DLP080vpmOkd8XYqzWecI9j6zakEzX"
+    "NW49iFGPs6TcCySw2fI/Aemvm8mEsXLuPtixRWAblURI3/7NIFGgwg+7JBYoxxk7OHW4C8Oj"
+    "OTqcKBSoaEMq0iIpb8u6iSbNRRedkHLP0Ih8K+6mimZbhcCeP0ICDoeRnBGDNw5XZip3Rvqu"
+    "jR/BvkGDA7QB6SG0kPeGBFjgM6JgEtnClIDT2OAzIZFYpPExEZmkB2O/A+X5Ebw5cMjuM2u1"
+    "mrnzxziu3dWYXtrYA9qubRIflSXeer2CUqkk/gNN/sDRnOMoBAAAAABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_right_focus_single = aero_right_focus
+
+#----------------------------------------------------------------------
+aero_right_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo0NToxOCArMDEwMEtfu5QAAAAHdElNRQfZAxkQLyM/CW/t"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAkpJREFUeNrtVz2PEkEY"
+    "fnbZQ+AgGD+R5YSAxVkRLfwF5vgH11xlbeNPsbE2Ftf4C+RiY2OijeGu8GIusEjgiJ4Ej689"
+    "YHedd8zgsBgt3Fkan+TNZnY3eZ55v2ZeDQzj8dir1+uwLAsT24ZKxGMxFAoFFItFJBIJTRuN"
+    "Rl714ADlchlmNotoNKpUwHQ6RbvTQa1WQ2VnB9rh0ZGXSiaRz+eVEvvRbDYxGA6hW40GTNMM"
+    "lZyQy+VA3PoFc4lhGKELIE7i1kNn9mFtAjzPW68AgUXwhaKwoGnaLwFE7rru4gOZWKsiFwJ0"
+    "/+7tqQ6rw7JTVxcd4hOchvyCVPXOHbz9cA57soHtUhqO4yjxgMBSDogPo4mDN+/OcCVt4Ob1"
+    "JGazmTJvLEIgu4Uwmzt48fI9mq2vPBzyP/9qlF9LZeh/KeP5/mucffuOSCTC/wnCBOcfPSDj"
+    "6bN9fDppBOYJucJ4DtARSfbzKI6vCHjyeA+X05sYstMrCJA3RZVxAZTpwvx4tPcQ166m0ev1"
+    "Ak2+lTIkctk1G0YEu7sPeBV0u91AyQmCyxALEiBUbcYjuH/vFnsC7XY7cHK5yS01Iqr3ZELH"
+    "3VIc5g0X/X4/cHKx4d+ehiTgYvwFd0w3sIT7G1auQiRCZefzY+33gf8CuAD5eAxdwCXWfqkH"
+    "qLyAyKDNUismTuLmkxErSmTZWEbZr/puSOQxNh9Sg5vP5zBKbEh8Va3yQSGTySifDWmTndNT"
+    "fDw+RqVSAQ/+YDDg0/HnVgu24umYdn97a4tPx6lUSvsBjEDOU65zEi4AAAAASUVORK5CYII=")
+
+#----------------------------------------------------------------------
+aero_tab = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAMAAACxiD++AAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFq6ysra6urq+vr7CwsLGxsbKysrOzs7S0tLS0tLW1tba2tre3t7i4uLm5uru7vL29"
+    "v8DAwMDAwsPDxMXFxsbGycrKzc3Nzc7Ozs/P09TU19fX2dnZ2tra29vb3Nzc3N3d3t7e4ODg"
+    "4uLi4+Pj4+Tk5OTk5OXl5ubm5+fn6Ojo6enp6+vr7Ozs7e3t7e7u7+/v8fHx8vLy8/Pz9PT0"
+    "9fX19vb29vf3+Pj4+fn5+vr6+/v7/Pz8/f39/v7+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAA0PbvAwAAABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2"
+    "qefiJQAAAP9JREFUOE+t0tlSwjAUgOFjZQuxuOBSFURSSOyq0qYNEd//tUzCaIeLk9743Zyb"
+    "f5LOSUH3AC3vyEWIuIw06KvHRmGqKIJ3+u1RzaD0BpL+S3DwfIO5oqAHDxPk1LOpr9oGe0/h"
+    "ArXHmSCjLbpIpSobyBa3o5DSWqJaF+xqlPykEE/LHFWmU2AkS1GZCdYkFajkjZhAxCghCLwS"
+    "zlCcE1j1BpOeE176gqU/mMBy3F0Rb/mpZENh0QWxyJNTfD6HRXfFthgNndFgcJzDa2aCv0WZ"
+    "tUj7blLdP9nZ6PCZATtPft+qjELt/vAm/HCzCNYmuA2O5xqzmzOwAuIG0AfGfgDFvqY+8bKe"
+    "lgAAAABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_tab_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAIAAAAJNFjbAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "ABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2qefiJQAABPtJREFUSEu9ldtPI2UYxovR"
+    "jZd65Z3xxv/AO2/0wnihiZpodgV21cSsiyYbs8ZkiQQSDUaynBaIB0ACLOsegJaWlkNpObSW"
+    "XQ5dlgUqPQ3DtPRIW9pO5/DNtPGZFjeVte2F4uTtxcz3e96n7/t+802VJEkqlapx2LQXE589"
+    "80xVVRVu//319FO5F587c/Xc6yoYXOrW983vzrqOrExqPcBuRTLOQ94T5/cSApMU/EnxIFUh"
+    "wIAEDxW0jyKZRSr+Vv3d724YFYPaDn2Iyy5H5I2Y/MeR7EllaTbrz2QDXC7E5yJ8LlopwIAE"
+    "DxW0yOBOylOO8CedOlUikfio0wAD239tYPEkatu0qng8/j8ZWCPyg5i8cyS78y3y/dWicL5L"
+    "5QNMoUVQQYsMzqR8XEEsHr/QaQhksosheS0qbyVkZzJLpbP7yhgUTYjLQV8+wOQHkIMKWmTA"
+    "LJcKLSoYYDimgHw/Ij9U5qxMiU5nGTZ3AI+M4lE+wIAEDxW0yLCdkBeODWIxGDCsPOUn1jBZ"
+    "P5TyRcjelEynZaawnSoFGJDgoYIWGTZjktkTUyo4PDw832nA2iRDFoNkNSptxpXNin1GpeX9"
+    "dNaX9ygfYECChwpaZNiISXPuWM1jAyolj9NkLkCWIxJGjQLxRzwpeS9d6FWFAAMSPFTQIsPa"
+    "oTRbbADnmx5iYMhSUFqJKpPYgQdeOgw8P4/yAQYkeKigRYZ7EWnala8gGo2iRVgbdAvafdGc"
+    "L8KOSaBRCdmFOtCrVIUAAxI8VNAigzVE9LtFBljrdQpjtDjrJ5aQhEngj6BYNLTgUT6U7EcK"
+    "DxW0yLAQJLqCQTgcru00bMXk6zvCTY+oY4g5INnC0nq+Udv5OlBf+QADEjxU0CKD0U/UO48N"
+    "Ogy2kPTGdPKilW20cx3b/K9O4bZXnKDFKYYANR+Q+dKBVTAgwUMFLTK0bPENJqamVavy+Xy1"
+    "7YbFgPSKNnl2gb2ywjVv8j0OYdAl3qZEDU30DJn2kZnSgVUwIMFDBS0yNG3wXxvzBgzD1LQb"
+    "5vzSy2PJt43sJRvXYOdbt4RfdsVht3iXUpS6fTJZOrAKBiR4qKBFhqtr/JUZprp1QkXTdE27"
+    "Hv/ihd8SrxlSF5bYr1YzzQ+5rh2+3ymMeIQ7XnF8T1SXDqyCAQkeKmiR4fI9rq7YAG/A8yOJ"
+    "VydT1Qvsl/cz325wndt8764w7BJuecRRShwrHVgFAxI8VNAiw+c27jNDvgKKolDBKRp4vd7T"
+    "NfCcuoHHc0oV1GEG1yZUbrf7w7YKM8A+0dGifp/8Y2AHT9BklCI33GLvrti+JTTa+QY7V6dz"
+    "fdyhrWyALYhNvIrzi8mUiqX9zDzNGilW706P7aZGHMn+9eC7Tepv+iZVLperfIvUlLgWlc61"
+    "6j5o0TwZ7/+gQTz5vLZVU//zxO82m2JQ3aaf9ZGX7iTenEl9amXr1zMtj7gfHfwgXgKvoHwk"
+    "9pK1rdp0Op0qunDL87zJZFpZWSl+zrKsKIqDQ0MWiwXHhGLw3vdqq5//YjnTZOe6d/ght/Lq"
+    "4vAyHSjfHxyQP5kcl7vVhJDc3680yw4NDeGje+J5MBjs6u52OByKAX5N/bp3mtVnr2lLxcUu"
+    "3a1R9fWurvaOjuLo7unp6+8/8RC3AwMDJrMZh9CxwfLyslqj0ZW+jHNzFqt1XK0eHRsrDo1G"
+    "ozcYTjzE7fT0tP3BA2TH9Sf2aVnapn4zWAAAAABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_tab_focus_single = aero_tab_focus
+
+#----------------------------------------------------------------------
+aero_tab_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAMAAACxiD++AAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFq6ysra6urq+vr7CwsLGxsbKysrOzs7S0tLS0tLW1tba2tre3t7i4uLm5uru7vL29"
+    "v8DAwMDAwsPDxMXFxsbGycrKzc3Nzc7Ozs/P09TU19fX2dnZ2tra29vb3Nzc3N3d3t7e4ODg"
+    "4uLi4+Pj4+Tk5OTk5OXl5ubm5+fn6Ojo6enp6+vr7Ozs7e3t7e7u7+/v8fHx8vLy8/Pz9PT0"
+    "9fX19vb29vf3+Pj4+fn5+vr6+/v7/Pz8/f39/v7+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAA0PbvAwAAABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2"
+    "qefiJQAAAP9JREFUOE+t0tlSwjAUgOFjZQuxuOBSFURSSOyq0qYNEd//tUzCaIeLk9743Zyb"
+    "f5LOSUH3AC3vyEWIuIw06KvHRmGqKIJ3+u1RzaD0BpL+S3DwfIO5oqAHDxPk1LOpr9oGe0/h"
+    "ArXHmSCjLbpIpSobyBa3o5DSWqJaF+xqlPykEE/LHFWmU2AkS1GZCdYkFajkjZhAxCghCLwS"
+    "zlCcE1j1BpOeE176gqU/mMBy3F0Rb/mpZENh0QWxyJNTfD6HRXfFthgNndFgcJzDa2aCv0WZ"
+    "tUj7blLdP9nZ6PCZATtPft+qjELt/vAm/HCzCNYmuA2O5xqzmzOwAuIG0AfGfgDFvqY+8bKe"
+    "lgAAAABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_up = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo1MToxNCArMDEwMESarloAAAAHdElNRQfZAxkQMyBAd2MK"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAh9JREFUeNrFl0tv2kAU"
+    "hY+NBXbAElS0QTwColKX4Q+gbvmDXXXVriq160olq7b7Rk2zICsejWyUqkmQgEIMxvWxZAti"
+    "0eCoHo40ssZj+5vrO3fmXgmuut2u4zb0+33MZjPEJU3TUKvVUK/X2SRlOp067ZMTNBoNNJtN"
+    "JJPJ2OCWZcEwTXw/OwO50o/zc0fPZFCtVmOD3tdgMMB4MoHc7/VQKpWEgalyuQxy5Tv3VyiK"
+    "IhROHrmyUOo97QXuOM7+4L4CZ/uziVuSJG3CCRYFX5+AcDg5iURiP3Ba7bOE+3xde/H5huWi"
+    "4SHLV6uVEKAsy5uW86hbLBZC4FzpoVCzbVsI3OcFcP5yUfBQqBEuyufkhFb7Y+BMubheHguX"
+    "fXiURjH7sSw7yIKivh/Ao4g+KxQK6A1MvHr9wbuyv35a7arI8Gw2i+ubCd6++4KUlveu7PN+"
+    "rPBcLoer33d48/4bDvTDoLHP+xyPop0zR13XYfxaov3VhJZ5Fhr/+NlE62UFh090jMfj/wdP"
+    "p9O4uk3itDNB6iC/9bnTjoXjFxmUnu42AQ/+0GKZz+c4KuaQz6kPflBTJYxuRrtZnnJjlbsb"
+    "N/xtsc7x2+thkIH8S6M/9tbdkkbyGxwn1yuX3OBDsVj0Dpc4j1aCVVWFYRhYLpdQnrsV46d2"
+    "26siGK9xFoo0zhwO0bm4QKvVgudsd3F4JfLPy0vPv3GJVh9VKl6J7EaP9Be4+2JJRD7+lAAA"
+    "AABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_up_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo1NTo1MyArMDEwMAycPlQAAAAHdElNRQfZAxkQOBMcU9vX"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAABFhJREFUeNq1V82LHEUU"
+    "/1VNz863yWyUyCSaEPzYuGtkwY8QYwLiQfTgwYsgBPMXeDJXvYmo+Qc8KEFIULyJHhQWNcSE"
+    "3KLrLgqLoMYVkplIdmZ2PrrL36uqnulOsu50YB68ed3V3fV771fvvZpSoDSbzS9/Xll9+czy"
+    "EFc3IkxLGlWNE/MBjj17RBljPlQE/uH1MytHzcEjeOGwwYGSQokvzigqbUCbo9UTAhhqKMqL"
+    "IW2PdpN2g/pbx+DH7xX02gWcPblwWi2dv2Debz2Dd48bVIxCjiiBFjBeE1iJwumkIg4If5ER"
+    "NRiKIxxgtOhpjVNfGby15xL0xz8NsP+owkzoPpqmiBP5MEL9RUBw9bWuwe6iwvRWOi2C0yhp"
+    "CO6kSzkVCWJvzBYqopBtScwdruM8sHj+wkYuiWGMBxTrHxrvQdZcMCat0S33qcgFbMBBTau0"
+    "y3CL6K0yfmxCibzDoYkz3pdelGbA0U53Ir4RqfHLmq9FcHVmSy1D+GbEphnNF5cdLFYuAR65"
+    "MsgJqNcwMZkFzxB5THXcbGzUXk1iGS240BGmPEw3lqwlkcyfcbNxGHbOKEW7W/M4cpVYb7Em"
+    "I+0pQM/qIHIq8w1NMnLyMwhdHw98pCOqI39/NwnnGY2tMKwwLjUL7tbE0Iqyp1Ot5/HqqOwJ"
+    "FyYot/MKA5EZMTOOfOi8smuv3Yc26RLdRWeMPLnOoU++oV/SVOTnmuzv5H22oFDLK1S4nRVZ"
+    "DTN0JK/d7pbLAB7vYn2i92jbHLg5AFp9KV6Fs5zreAy+ycg3+KDADiMDOZuuCibnMjYLeEy5"
+    "gPcIvsmQuwTvMKPbfWNrfTAIx5H36FWHDpR5V+A4g7c0x1RLIkYZwSWz+5yr57UbOgwJJgwT"
+    "tEuqt+lqhYNFLvSMUB2O69tkBB/adm1IuwBL9E47ZMA6lwIfOup71D6p7mv/98m3VvHC3AIu"
+    "tzuYI//2zG27WJy8cW1bBjyGFQ8+al5RQs02Ksvxyr4Ae9t/WqvV9t8k548l858JYeOlhsLy"
+    "yhrePHXaWrnPUg13DX5oNsDf/9zAO+99jnKtYa3cy/hUwRd3Bbj5xzre/uAb1Or7Rir3Mi7P"
+    "s8jEbz+yI4fm79fxyRdrqO588LbnH322hjdezePRvbP4pRVONOdE4PtrGr2rHXx7qWup3krk"
+    "+bGwjYceqNCB4bbzOnD9//yv86Tx/IEKGrvL205YLSssXds68iROcC+PRxXmf5WNfCsHpEF8"
+    "xwlLE/DUve7a6Z2kyO8reY0arwU3OPl4HktXctjzHCenw1V2l2oeKLF2Cjm3scQNZzjByUKO"
+    "WvfwoDdgSyyytxf4fZ5b5Az/qdxHnyoE3fW1wonFAMHiwmOr85cvzn26fBgHnzZ4uKyxk6BV"
+    "gvFgwc2GDsB1vEnEdjj+cA8BDyVo0+Eb1CbZ+5Unxr/OA3PRRTz5xILrnq1Wy1y+soxzqxHW"
+    "29M7ON1f0XhtTuOpQ/Oo1+vqPxxtdiUOpmR7AAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+aero_up_focus_single = aero_up_focus
+
+#----------------------------------------------------------------------
+aero_up_single = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l"
+    "AG1lciAyNSBtYXIgMjAwOSAxNzo1MToxNCArMDEwMESarloAAAAHdElNRQfZAxkQMyBAd2MK"
+    "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAh9JREFUeNrFl0tv2kAU"
+    "hY+NBXbAElS0QTwColKX4Q+gbvmDXXXVriq160olq7b7Rk2zICsejWyUqkmQgEIMxvWxZAti"
+    "0eCoHo40ssZj+5vrO3fmXgmuut2u4zb0+33MZjPEJU3TUKvVUK/X2SRlOp067ZMTNBoNNJtN"
+    "JJPJ2OCWZcEwTXw/OwO50o/zc0fPZFCtVmOD3tdgMMB4MoHc7/VQKpWEgalyuQxy5Tv3VyiK"
+    "IhROHrmyUOo97QXuOM7+4L4CZ/uziVuSJG3CCRYFX5+AcDg5iURiP3Ba7bOE+3xde/H5huWi"
+    "4SHLV6uVEKAsy5uW86hbLBZC4FzpoVCzbVsI3OcFcP5yUfBQqBEuyufkhFb7Y+BMubheHguX"
+    "fXiURjH7sSw7yIKivh/Ao4g+KxQK6A1MvHr9wbuyv35a7arI8Gw2i+ubCd6++4KUlveu7PN+"
+    "rPBcLoer33d48/4bDvTDoLHP+xyPop0zR13XYfxaov3VhJZ5Fhr/+NlE62UFh090jMfj/wdP"
+    "p9O4uk3itDNB6iC/9bnTjoXjFxmUnu42AQ/+0GKZz+c4KuaQz6kPflBTJYxuRrtZnnJjlbsb"
+    "N/xtsc7x2+thkIH8S6M/9tbdkkbyGxwn1yuX3OBDsVj0Dpc4j1aCVVWFYRhYLpdQnrsV46d2"
+    "26siGK9xFoo0zhwO0bm4QKvVgudsd3F4JfLPy0vPv3GJVh9VKl6J7EaP9Be4+2JJRD7+lAAA"
+    "AABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+aero_denied = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAADxklEQVQ4jbWUzWuUVxTGn3Pe"
+    "+955k8nMJE5m0vqRZCaUYomG0uJGjDR0UXBRUj+6Kqg7kSy6SBf5A7ropiB07aK4qIsWIYsu"
+    "ioXBQoRKqWhJ1eq0sWqSmWQyk8y8H/e+p4t8oJ2YuPHA2dzD+fHwnHMuiQheR/BroQJQOxWv"
+    "Z7N9cRB8nAA+dIEBAIiAvwPgJ04kro1Vq/Mv66XtrCgVi9osLEx1K/V57+HD6a5Dh8B9fSDH"
+    "ga1WsXr7Niq3btVrUfS1yue/HH34MNwV/HM+n1HN5vd7+/vHsmfPQu3bt60i8+wZli5fxr/l"
+    "8nXT2fnJBwsLK8/XX/B4ZnhYqWbzyv5icaz34kXwnj2IrYUoBXge4HkQpRBbC85kkL1wAfuH"
+    "hsZUs3llZnhYvRQclMvnsqnUidTp04DWoEwGnE6DEwmQ44AcB5xIgNNpUCYDaI3UqVPIplIn"
+    "gnL53LbgmULB9YCp9LFjcHM5KM8D+z6o0QD+l9RogH0fyvPg5nLIHD8OD5iaKRTcTd6W/KhS"
+    "OZJOJgc7R0ag4ngd8gqhAHSOjMArlQbrlcoRAL+8oJhFjiaLRWhmrN29ixYzfNdF6LqIXBdG"
+    "a1itEWsNaA24LoQZ5s4duAC6hobAIkfbFDOQ78jlQPU6zNIS3jh/Hqz1jmolDFE7eRIqk4GX"
+    "zYKBfDtYJGDfB9VqkNXVV7IBAOT+fYjrrs9DJGgDE/Ns+OABkExCBQHmL10CM4OMAVkLAkAb"
+    "3hEAIgJZC7YW9OgRwnodzDy7xds8kF97et70iMrFfF6T1gAzEEWAMburBvBwcTH0RQbfX15+"
+    "Cjw3vIOl0tMgiq7VVlbA9Tq4VgOvrYGDYNes1esIoujawVLpaZtiAPitu/sta8yt/o6OVI/a"
+    "8X/aimVj8E+r1XCUeu/dWu3+tmAA+D2dHvetvdqtlDrgOEgQbQsMRDBnLWrGGM9xzozU6z88"
+    "X28D29VV/LF370d+HH/bFOntIkKGCJuLFwJYEcGqCDqJKh7zZ+88efKj09WFHcFbtuTzOW61"
+    "vghEPo1EDtiNdweASzSnib6Tjo6vum/eXCwUCm39dO/ePUxMTDizs7Oq0WjoMAy1tVbHceyK"
+    "iJsFOs4wv32AqF8AzMXx3FWRP5cAn4hCZo6YOdRah8lkMhwYGDCTk5NGzc/PY21tDcYYiuOY"
+    "RIQ30gGgKiL4xpi/AJSxvsIWAIjIAaBEJBYRx1rLxhhqtVqoVqu0rRXT09N048YNPH78mKrV"
+    "KjWbTfi+TwDgeZ4kEgn09vZKX1+fjI6OYnx8vA3yHxWIwp50Lj49AAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+auinotebook_preview = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0"
+    "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJXSURBVHjahFJRSBNxGP/d/+52"
+    "W66ildPKJB9EMSwjFSNoUkS+GYg9pi9R9tJeopcgC3yKYvRUMHA+VBJUmpQPQSySKINqEGSB"
+    "Np3aNjs3N8+7285d/7sxa9yw3/G777v/932/+76PP6PrOgw8D876dYImWJAEZPpW8l89nYea"
+    "i8KGgMHRYPitvgkCw0G9qaNXD4x80Qs1BknRnzaBEfX1e+G758PQaEgvnP8VULA5lCS8/T7T"
+    "NUQK4ApO4j/1l3s6N/zA8MiGTxiGgUGowGwkhqkfc5Bl1SKwlM6i90y75dzsoKX9fNPLF2Mt"
+    "sZVGuMt3YPDpK7jsDnj7uiEIfH6ClAjF5rAKHD1xcW99a927C5e6hP3luwCGwONpRjwm4tqA"
+    "H7du9pmJDG9HrsSeSE3dvmdnz512tFZVQaGjaCyBjedRubscxzva8PrNJzNR0xmsKsQq4KzY"
+    "fqDW7UY8o4KjxRzLmpYlBLUNNZj48BVRMQlWA7I5yTqCvcyuq+s0qmkQiC1/QeiTo1ajNpWS"
+    "oMoMVJVyXbZ2sDj9S5sMh2l7CjJUJGswq0HNZBCNLmEhPA0xsQpJUSHJJUZILCbuxuZF7fv8"
+    "ApbTaaysrSEpSVgURdy//RDJxAp2RvzgMgkQzbpEziVEbgQfBeuXPY1dqcMS4W08cnIWY0Pj"
+    "iIXjuNI2A0dsDmXyT3yUTtESZ5EAU3CuDvhD7ydDB1mWg6zQWelSj2ydwbE9v1Fd4TQZmHLj"
+    "yTfBzP88PsgUCZTCne4qFycID7Zt4TuqK50TFaTmZMP1x5l/c/4IMABbKBvEcRELXgAAAABJ"
+    "RU5ErkJggg==")
+
+#----------------------------------------------------------------------
+whidbey_down = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAaHWVZ3egZ3e1cYCncYa0dpC4cYXGcpDBc5fWd6Dld6Pwi5OzgJbUkJjQkqHC"
+    "hafggqfwh7Dwk6Xgl7fwoKjWp7fXsbbWoLfnoLjwpMLwscHnsMfxtdD0wMHg5eTo5/D49/f3"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAverH2wAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAF4SURBVDhPbZTpYoIwEITRGqAQ1ChqOFrx/R8y3SObq8yvsHwZhglaOdH7HZbJIp1W"
+    "YW7t7w68LOcwDaxd5+lhC3q18zwOMhTWIjtZ+3wGfFmWFYZjgJl9vWC/1x30AI2zzExzIcqz"
+    "a2RxC2Ak2n4zJmEx1TgaY8R7AtHsdgMS1IivJRZHyN5lA6PMEgwZ2JVYs23bxwuWG3PGdF3X"
+    "ImvtBO/KqAl38ytgO+WqMz1SDDz7KXaCbatU5YYARt+SbUHg61zT9/iMHsQZKHBI9A1S6njk"
+    "fpuCRTjmJVQBymfxlfuCc5IX0cMhnhvCMYO8KCdCV0L9GbMz8Fhqous1ugbWw/32k2oDtFUn"
+    "do2sz1ywqWvCElz6pq4pS3CRVxooMvjqsI2+v5LwXCVrljfrGclhqH2v5e+Nr6VnYltgBct7"
+    "iDDExm+grvm0ouL/QwrjN1CHXvczYAz0xF5Pp9w168zfAhjeH9gSle8hnWutldL6H7rHOq2P"
+    "agd1f/M7VhKuYPh3AAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_down_single = whidbey_down
+
+#----------------------------------------------------------------------
+whidbey_down_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw"
+    "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI"
+    "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAGeSURBVDhPfdOLUsIwEAVQCCixFSggVfBFQWpVjKJo+f8fi3ezSZq2jDsDhHB62Wyh"
+    "o319Vctg9V2tO34p5H0bHw5D4Xe9FULK5bKhb6UcDs/cprNdMYiprhee30khaStx2NpudwCb"
+    "JHG8WAhbEkU0cZgtUge0iYrjCEUuilheOWysS2U9GpluGJJ1mKyg1LHZn6NYNNYUCWuozSjr"
+    "FVxnLGQUjZPJlLJKCk7piar0Nk2zS90RAhINVDZN5yUeNZuhbjq6BzmZomYoICr/Yr5mtcry"
+    "fL2mfnvjSd2anvkSsqBZUazN2XS/YVNLrc2Qut3yHAj/10OWFwVRtrpPvZo5cL+28A7fnxfv"
+    "G6Ps74GwsfXCsXKkMnWWko39DKukAbjUygKfskFqYLnnKvcHdQT9sA0EPdgD1ts9Vr2G/fpp"
+    "pDMeAg3gWe2fgn9V9d+0yW5edCylQurnwJejZ/7VPJpZ7V+C1PBsFrPFXAul6rSRi2S2uFmq"
+    "kdrK1frcWOq1kXrC6osHulnq963Wa3Nm9kOySrVpq1/yr5vNbtdK1foPGIxy6qmqIg0AAAAA"
+    "SUVORK5CYII=")
+
+#----------------------------------------------------------------------
+whidbey_down_focus_single = whidbey_down_focus
+
+#----------------------------------------------------------------------
+whidbey_dock_pane = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAaHWVcHiYZ3egZ3e1cHilcYCncYa0dpC4ZobHcYXGcpDBc5fWcZjgd6Dld6Pw"
+    "i5Ozl6e3q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dwk6Xgk7Tkl7fw"
+    "oKjAoKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo"
+    "4Of35/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAA1jVbdgAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAdFSURBVGhDtZpxe6I4EMbtbQVXrHJuaY8KWq/XW3Sr196u8v0/GTfzThICRIh9nssf"
+    "u4rw42UyM5kJHVVXjDQah/EV51ejK05+SKMwjK/BX0Gfzu9ms2kY3PgL8qd/nc/vCB+GN/54"
+    "b/p0sVjMaRA+9Mb70hku9GvUe9IBV3TC+9rejy5wTfdX70VneJ7LHRaLu7uIPNPL9j50hp+a"
+    "w9NzPOhQfvrHHqeZn/phOmzeofvZfpA+zTFa2rNsFk2GPWeIruB5y+5En00mg1E7QNfw/CSP"
+    "oEaZ51kWDavvpxu4phOWB+hJMqi+l17DFb0sBa+eJB3KOX30xLIFeAQXvKYTvtf2PfTVbrtd"
+    "6xsonrKMoafhJAwu5/vL9NWO6Rp/iZ5OJsFlfI/2onh7oxvQYKOsaeALjTV944fK2DFn489o"
+    "ryqmA69NDrtjWPSwZyHs9RlWr+h5Qzt9UdqzPvhATTBMn/Uu4QOxut9r24vFdzSUvUh+lk37"
+    "6wMXfVNf8sF0mdrt9nGF8YbB3ppNl/WpK8eNHPTNxuCXHx/a9q+vZz3exZvW6+m5NPhi58B3"
+    "6Yfj2zYRHcuSgOI5Bi0fDgeiT/nT8oxTi2K3U1dZz9ChH5gu+GXJ9HNRvP/dgoOfyEGox/Tn"
+    "nVlo04kNm34DHPRfv7psxuujywqm4rBo41t0Vs4uvl4/PXHUNLj7/f6VRvte5RJTjxBo4Zv0"
+    "A3sDxw2d+EeTcnzd4qnIdR43zZ/EbSUjNfEN+oHppFsiEZOmxn5/ZJOBvt1uNivrNyvk2nib"
+    "fmA6W0W0Z6FGkL0sNvLYt0L/aKeLtnqLTvCD2FzRNR53VelSZ8l1IfhfdqqDbRaWcWo6nWZs"
+    "zrk1SZLVvww40oBeZTG9oDwbOm6pDy8svKHzA9Y2Z3oUgU5WOSIXdOjAv/Nv1hLJ5aZRr+lQ"
+    "XhNYevSEZye6ZJo2PZNpd9ANXtFFuYtOM0p50UnP4Dm2VeQZavVCZ6cqudziCOL/szSKYkh7"
+    "hReu62UJv/MyS8+HM2AZuUwNgwcdTlVSkasrrppOgSL0Rg2ME9l6uD8/cqmWd643T0Y90xEO"
+    "azku48RzCu0vau1z0lNEhJu++Epkoks4dOhjPPaL+Hl+gf4upmlplzaIPGdUIbewXls7OTvo"
+    "xktbdK6auNyAWz266fOHaoQ4ZKNpOl940vRXHQN99BU9XMkzqylo3+7u0nTEdkHkKzoKRUNH"
+    "tccxeoEOwxs6XQqK0GdRNFoVKkqEDo+8lk4Syq2UsDWd2ubxKHtm5dzVid1Fe5bOjCx4kUt7"
+    "mohf8QPCMg3ttGERjp4z1Yk27O5HV15r6MbuVF1S2xbHo+pRNblNf88SaN9sVIpyaSfDYhnU"
+    "dEQK7A54ELO/f6VJqC2joknF4bmfPgadw4UtY+hmo4Vj9ZanWNtd07PsRfmDuYqTgc43nAei"
+    "e8TEu4OuWh7kGcb70kViKfR7phdvVA808gw34thHkBzJ+EZHSquH5NfzN5p1ZU+S/kM3fZxE"
+    "owBnCF2lWFAivcWi8jvUYydDBujAZ0JX7XD5Q0yTMT0EnVf6emHh9FC3anptgu3nc5ueppC2"
+    "0nfT//OdqRcOA5HeoVsbFGZdFbxFJ3/7C3ShyTPoz/C4PwHnhau+rLmxVdcEwNunRdEYNcFK"
+    "8Wv6jO4cBL8DfuC1xbqssbVi1TOMN6chHoSu1Ws6ByLZBfDzObEX8yRqNvd2LaZsLzt3k8lY"
+    "1g8aDw+Ukc3gfatAzMJjapTnOdEb2yqNOtLgSdwkMHBWGEIxxmQS/iYTqvAyGSmN9rZEswZW"
+    "eJkaC0Af4/ieBrPHY6kWWniCh+0NoVb9DjzbPLhZNhH07f4+CIK4heYbT0V7d0ui3XvcSvLk"
+    "QEbXROPnz859zFGOLGptZhRDru2UTt9EeB3ISj31TQ784fBIRwVeVTQtrq2gbs93G0Vfvtg9"
+    "3/Ft92KqdXWfI1cpVCspOOMnjg3QLr0aRwpOxuGOj+i7orD6JarnqVugEE2sfnXs2khx0CsD"
+    "r6rv33U3w/3MZvNCQ/dP3EI+1c2pa5fGRbfa2e/SApohXbw6RmFk0a2rzMd+ujRclAI0XnYh"
+    "pBRH1ujfhuil6yZX6LTEmlEnl158H91uFVVtr+t7ne0o9iKXSdSxHjpvLJieqLmXar5xaPfs"
+    "Ll2mP8IMWqRzTy/PSTplzIvqe7Qndit3gc4581Paq4p23lHpYP+dH6K5lyoZSce1U3+vz0xb"
+    "dMZLgcD/AB5aode9Qb+/S5VmtEsDUNMH334MxKqpcxw+4/HWbIAuNSbXgc3RLIo+4zNyjeBR"
+    "ZdbjRKuFKec+F03qqrpCtuieb/uGLGNXyDbdR7mugXsezlUhn06D3iJED+2qvkcDpCpUvzdl"
+    "nnTVnSg6vavxfT/spb1Wz9qpnPN7Q+mrXTsmF1I+78j0PHpq13jOLR7v966mV6jS0BX0vAJq"
+    "OZ+3dlLP8UnDH+7nkUpRHMf/399CVFUcf7nu7zj+A8yummsi9EdGAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_dock_pane_bottom = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw"
+    "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3"
+    "q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjA"
+    "oKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of3"
+    "5/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAaHenigAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAejSURBVGhDpZkLe9o2FIYpTVeWrG3Srmy9stk0LTPJMKMhmYM9KOuSERqydAX8//+H"
+    "dy6SLF+QRXeepwtg+9XnT+fotlqyRQRey+1vcX9S2+Lm08Bz3f42+C3ond5xt9txnRf2guzp"
+    "b3u9Y8C77gt7vDW94/t+DwLwrjXelo5wpm+j3pJOcEEHvK33dnSGS7q9eis6wqOIW/D942MP"
+    "MtPKexs6wlfZsMwcCzopX/2jx6prp76aTp4X6HbeV9I7EUVOexh2vXZ15lTRBTzK+Q70brtd"
+    "WbUVdAmPVvwKIuIoCkOvWr2ZruCSDlgMog+HleqN9BQu6HHMePEmQdWYY6IPNS+IB3DGSzrg"
+    "jd4b6KOr6XQsGxA84YyiB27bdTaP95vpoyukS/wmetBuO5vxBu2z2fU1NACBpowh6AvEGL7h"
+    "S4WYmN3W12hPEqQTXlpOvlNodNcwERpzBtULepTRDl+E9tAEr1gTVNO7xim8olbnc+k9O34F"
+    "IfwC+WHYMa8PyuiT9JHPSOeunU7PRhTXFJitYWeQ3joqaaiEPpko/ODzZ+n9xcVaxi1n03jc"
+    "WccKP7sqwRfpi5vr6ZB1DGIAcuYoNH9YLIDewU+DNd06m11diae0dyjQF0hn/CBG+no2u73M"
+    "wYk/5B9JPXV/VOiFPB3Y5Ol7ghN9uSyyES9/HSRkFZZFHp+jo3JM8fH4/ByrJsOdz+cXEPm2"
+    "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")
+
+#----------------------------------------------------------------------
+whidbey_dock_pane_center = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAGDeAJUqQIEOkIkewJFKlJlayMlSiMle1K2G0LmnSNnDgR2OkQ2O1UGagUHCo"
+    "VXSzaHWVZ3egZ3e1cHilQ2TAQHDAQnLSVnfFQXfgcYCncYa0dpC4VYTTRIDjVYbgZobHYIfT"
+    "ZpPXcYXGcpDBc5fWYIjgYZHgcZjgd6Dld6Pwi5Ozq62xgIjQgJbUkJjAkJjQgJjggKDXkqHC"
+    "k6TWlrDXhafggqfwh7Dwk6Xgk7Tkl7fwoKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjpMLwscHn"
+    "sMfxtdD0wMHg6tTN4Njk5eTo4Of35/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAXehG6QAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAdqSURBVGhDtZoNW9pIEMc5emrB651VUDRUpEkqb5d6SBOUXq9Q8dprke//aXLzsrvZ"
+    "hGWz+NzN87RCzP74M5mZzGyspDvYOGh4wx3OTys7nPx+HHjecBf8DnS/3wtD37t47S7InX7V"
+    "7/cA73mv3fHOdH8wGPTBAO85413pCGf6Luod6QQXdMC7+t6NznBJd1fvREd4kvAnDAa9XgCR"
+    "6eR7FzrCV3lzjBwHOilf/a3bKnRTX04nn2/Q3XxfSvcTsoL2OA6DdnnklNEFPCn4Hehhu12a"
+    "tSV0CU9W/BWErZMkjoNy9Xa6gks6YNGIHkWl6q30DC7o6zXjxTcZl9UcGz3SfEE8gDNe0gFv"
+    "9b2FPlnMZlP5AYInPKPoY6/tXWyv99vpkwXSJX4bfdxuX2zHW7TP5w8P8AFg6JQpGL0Bm8I7"
+    "/FIxBmbYeI72NEU64aXLye9kGt2z3AitMYPqBT3JaYc3Qntsg5f0BOX00HoLL8nVL1+k79nj"
+    "CzDhL5Afx769PzDR77Il35DOl3Y2u5mQPZBhtMb+KDt1YvggA/3uTuFH375J33/69CTtK0fT"
+    "dOo/rRV+vjDgN+nLx4dZxDpGawBy5Cg0v1guge7jq9ETnTqfLxZilfYdNuhLpDN+tEb603z+"
+    "9a8CnPgRHyT1dPmTjatQpAObfPo7wYn+48cmG/Hy6CglV2FaFPEFOirHEJ9Ob28xazRuFIYt"
+    "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")
+
+#----------------------------------------------------------------------
+whidbey_dock_pane_left = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw"
+    "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3"
+    "q62xgIjQgpXEgJbUkJjAkJjQgKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjAoKjW"
+    "qLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of35/D4"
+    "8Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAA+wCLtAAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAeDSURBVGhDtZr/f9JGGMdprZPJnHSKm9OKI4DG0K5kWAptGIw5FGqpdQL5//+Q7Ply"
+    "d7kkR3L4ms8PWmjyzifP3T33PM+1FO1gQ6/u+DtcH5V2uPh86DmOvwt+B7p7etLpuE7jmb0g"
+    "e/qr09MTwDvOM3u8Nd3tdrunYIB3rPG2dIQzfRf1lnSCCzrgbX1vR2e4pNurt6IjfDTiJ3S7"
+    "JycezEwr39vQEb5OmuXMsaCT8vUn3dYdO/XFdPJ5hm7n+0K6OyJLaQ+CjtcsnjlFdAEfpfwO"
+    "9E6zWbhqC+gSPlrzKwgLR6Mg8IrV59MVXNIBi0b0fr9QfS49hgt6GDJevMmwKObk0fuaL4gH"
+    "cMZLOuBzfZ9Dv1xMp2P5AMETnlH0odN0Gtvj/Xb65QLpEr+NPmw2G9vxOdrn8+treAAYOmUM"
+    "Rh/AxvAJXyrAidmpf432KEI64aXLye9kGt3J2Qhz5wyqF/RRQjt8ENqDPHhBTlBM7+Ru4QVr"
+    "9epK+p49vgAT/gL5QeDm5wcm+n58y2ek89BOp4NLsmsynK2B24svvTQ8yEC/s6/wvc+fpe9n"
+    "s420W55N47G7CRV+vjDgs/Q7D+/fE/heCECeOQrNPyyXQHfxp96GNM/ni0U/oz5DP3iIdML3"
+    "QqRv5vPb9yk48fv8Jamn4R9lRiFNPzg8rCJ+j+BEX62ybMTLb3sRuQqXRRqfogP88BDo9/b2"
+    "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"
+    "RK5CYII=")
+
+#----------------------------------------------------------------------
+whidbey_dock_pane_right = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw"
+    "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3"
+    "q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjA"
+    "oKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of3"
+    "5/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAaHenigAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAe+SURBVGhDtZr/W9pWFMYtW1en67RzunWdpUvQlgWdMCoyJFkotbaRCrMryP//f2Tn"
+    "yz25N19ILn2enV8Qkn7y5s2555570414jRh4dbezxvnxxhonXww81+2sg1+D3jw7bbWarvPM"
+    "XpA9/eXZ2SngXfeZPd6a3my322cQgHet8bZ0hDN9HfWWdIIrOuBtvbejM1zo9uqt6AgPAr5C"
+    "u3166kFmWnlvQ0f4Ih2WmWNBJ+WLf8xYtOzUV9PJ8xzdzvtKejOgyGj3/ZbXqM6cKrqCBxnf"
+    "gd5qNCpHbQVd4MGCb0HFMgh836tWX05P4EIHLAbRe71K9aV0DVf05ZLx6k4GVTWnjN4zvCAe"
+    "wBkvdMCXel9CH96Mx6FcQPGUMwl94DZcZ3W9X00f3iBd8Kvog0bDWY0v0R5Ft7dwAQg0JYSg"
+    "LxAhfMOb8jExW/Uv0R7HSCe8WE6+Uxh0t2QiLM0ZVK/oQUo7fFHa/TJ4RU9QTW+VTuEVY3Uy"
+    "Ee/Z8RsI5RfI9/1meX9QRB/pf/IJ6fxox+P+kOKWArPVb3b1qT8XXKiAPhol+O6nT+L99fW9"
+    "xB1nUxg275cJ/rvjV3l8nj6d3Y57fGJ3CUDOnATNf0ynQG/iX917OjU6Pn6Vx+foU6QzvrtE"
+    "+n0U3b3PwInf4x9JfbR/cHzSzj3iLB3Y5OlrghN9Ps+zES+/duO7h/tMz+IzdFSOKR6Gl5c4"
+    "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"
+    "AABJRU5ErkJggg==")
+
+#----------------------------------------------------------------------
+whidbey_dock_pane_top = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw"
+    "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3"
+    "q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjA"
+    "oKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of3"
+    "5/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAaHenigAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAe1SURBVGhDpZkNexJHEMcxrTVNao3G0PoSaXmJ4l1soBhCCUdBmkaPCDFWCN//e1z/"
+    "M7O7t/fC3aHzPMqFu/3t/2ZnZmeTUrCBnZ83m2cbPB+UNni4NxweHx/9tsGIDei92bBF9B+L"
+    "44vTu6T8AFb+oTC+ML07gfIjppe/L4ovSofy1nGjIfT9oviC9O6kBZ83flf0ovhi9NccLY2y"
+    "sv39gvhC9NeT4R/HR5q+Xwa9GL4IvQmvLBcRK4gvQG/+DZcvP8JG2hYF1efTSflxY2HIdLHY"
+    "gxVwTi696VGCptLz8Xl0Ud4oR90u2vOXNodOyjlYFjoa+VPT89Rn010ol+xXdP1Bq/oI9jA7"
+    "azPprguX23T4R7QbejY+i/6q1YJXpLYwlZ0foz/4LqOkZdBfvaJgaZQzPbP3IAu/nv7rEYxi"
+    "g+xgIfVrgX+44FV99HAP7J2dra216jO0/3RULkfpPAP9p+lg37u3Hp65r/oHByE9GvDy/e4u"
+    "2Bnw7F3bD+kQbGbS1w/y4Dk9wd29vcePtc5dtp9/1rOQ8jt3MjfBnFwlPLtgd2dnG7YD291V"
+    "88Et2fBU7eNQz2fgiU3kLWVPnhBflHfCRwcpb5GifTw2+M5n4Mkf21vbh7fanvzCPoLy25XB"
+    "+9MUfJI+v55NuqKjswLw7v3729vPDVounj6ld6Grzi0/6vvTqRplvUOCPie64Dsrot9u3X//"
+    "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"
+    "gg==")
+
+#----------------------------------------------------------------------
+whidbey_left = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAaHWVZ3egZ3e1cHilcYCncYa0dpC4ZobHcYXGcpDBc5fWd6Dld6Pwi5OzgIjQ"
+    "gJbUkJjQgJjggKDXkqHCk6TWhafggqfwh7Dwk6Xgk7Tkl7fwoKjWqLDIoLfnpMLwscHnsMfx"
+    "tdD04Njk5/D49/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAQ3JLMwAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAF4SURBVDhPfdTbdoIwEAVQL6htAi0tElBaoVb+/xPTM5M7wc6LLvc6GTIJbnRel/DT"
+    "ZkUvwXOefsahdqGMJ2LvSwaO4P7d5BdMWejQ9+dzzhOiY4/quu4z44kYSebudbH4REwLm7Q6"
+    "Jr2hk+lrGR4e7Rb17ZRSdV23v55vxL4vsRCBOesXRrquBbZm0yb7jIHD/EDNKPpUjRBvbmOU"
+    "Heb7/f6g/aISJhz6R8J4MJvmbM6FGSrPmRaM09i0YZ4zDdHxTN8909I8RMtzyu3NztgwbyxK"
+    "qytlq6pK0qqROC/0vipGzx0v7ll/MAY2Y1G1SWv9UpXlCvNlpiPZlyjX2w4VJ/rlZk7+D3Oe"
+    "DsoXwqoNV5HzKHtidJlUC3eXifuXZcxNE91U4xFLIb6jm8oeWIKLcFPN/jxLKY/HhM3+TUl5"
+    "OhU48eQN9Y6VTwe6D+kLbJ0W3m5X3m926ntgXb7+eg/z2ZzJhcuusN4Lsds9/WfSuhBes94U"
+    "C6r/AM3yZVcU56/qAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_left_single = whidbey_left
+
+#----------------------------------------------------------------------
+whidbey_left_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw"
+    "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI"
+    "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAGNSURBVDhPfdRrW8IgFAdwLyuXZLIUy67D6dK0pd3w+38xOuewAYOMN3ue/fbnwHZG"
+    "R8ej5251Yu33nMfcHw8H1iNOxsiNh5xkGUfvmqIBg2YZ8KBrvM3J5BoGH7NBnW9xMjHMGTjl"
+    "fQYlxvKYh/V5jErc5MEdJxMOAx/BKxZI0w/LkI340aZx5jZzdmdrU92TjKr8IbB2szHKqv1+"
+    "r2Y4hFDINzWf082A2Xxu+II0TDNU4KcnAcNPz4TiV0P6pp1XKduM9R0XZdlipXBpnNXpgGl3"
+    "Hu+qdSnzZ1sb0libpab2rqrKMs/d0tqstz+QhwfUt/dabFrrbYXzy1OsNwf0Fgs2TB+ad77B"
+    "6SNOba9B/uV49D6ZqIvX3bJp1m++mEBO710rLg8wv8wNmVZj6ZdrxeWatmcZW9FjXbxj3ufR"
+    "6NPr8wLyHnM28vtc6+INX08+w9LTKednwS9I+TwnJg3+UMoTGw3/7wKndxqyXq3gAdg9ZaO0"
+    "1oab8yo+mRYLKe1p9se5tpCX/7G+dUfhL8vucupsrDz0AAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_left_focus_single = whidbey_left_focus
+
+#----------------------------------------------------------------------
+whidbey_right = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAaHWVcHilcYCncYa0dpC4ZobHcYXGcpDBc5fWcZjgd6Dld6Pwi5OzgJbUkJjA"
+    "kJjQgKDXk6TWhafggqfwh7Dwl7fwp7fXoLfnoLjwsLjjpMLwscHntdD0wMHg4Of35/D49/f3"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAWZqHkAAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAFySURBVDhPddPbeoIwDABglDqoFDcVGBVw8P4PyXJoQ0sxN+L3m0NDzVaJx/YoT5k8"
+    "9fbAhfve2luS77kfhq5rir077pkTZ34Ng7Vt2yRO/ELuUPeOTIWxdOrA3Fc46p/9AVobsgnm"
+    "Z0b1xRsTeLa+EV1f+jCBQ+8DlnzgsDBX2fLxYFR8WeYtxJF/u65tF95KM0/TNEv+ZzZfkElL"
+    "TbKhuDEVnJ/4Z1+cufpmfsBwC47newNV1fV6v8cMTqMx67Jkhs0s3YIRsNbqHDCePczWhVIx"
+    "S28NoVRdRyxrMaR5zZPjdcDJha+opxOf+33ACthtrR/glkY7LzmXs5npjbn3VqqcFHmE2i0E"
+    "934+fd9PjKXdvylbR7yn/q7FuVB8HOF9uMJUOsjF3retb9PcysuFZ+aA0QrJJXYzC6/Fk+IO"
+    "Eee628IOquJcx5wP6nYV9cYvGpYBKucNRqNHpfW+r9+580uS63vjD855vvXcF4fvB7r+A9+i"
+    "Xf4K/oDaAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_right_single = whidbey_right
+
+#----------------------------------------------------------------------
+whidbey_right_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw"
+    "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI"
+    "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAGXSURBVDhPdZTZVoNADEDpaC2CFSqC1hVaxWoVqdv0/39szDIraF7gcHuTTCankbJx"
+    "6V7tW2TfTprVmDvcNKsxt7ismnbzOPQ1npaMh5zxNMdo4Afr0CfMNK8Bv4UcMdBzwshDHzBS"
+    "wlWN6QM/UmKecu68hBj40ed8nmrOuN28u/qR+op9XNfANw+mf8asow31ge8Mh9au4zhlRIF+"
+    "1z2zjwcTiKWL/f6p2zFHHMdJWkpty77/lpCffcQ3IwzHY5+GitkDG8fTddv/MB2v+9n6dlVJ"
+    "aBxq9/Dk/l+95IDgu8b3eD0GJ1ibTmYwzqFt12wTLn07xKc51XW16XqaF20D1jPVtRHf3XHn"
+    "Sxyqm1ovC5r+MZ97OcJEj/TULuA+B3ZRFIdm5njd/o1JaSgmvzK7Bh8LXAt8kku1/8KaAr61"
+    "u+ZsQ1X0Aauks1tsKdhCzGb4gzMKr66uTTzLFwuNnctjmUycb3t2m6om7JPtu3qZyE+yBURI"
+    "+UogvwAM5QfUYOw/ybIhtVghPuBUXrg/LiHG1NmwcSNXqV+4tHLqnJPo+QAAAABJRU5ErkJg"
+    "gg==")
+
+#----------------------------------------------------------------------
+whidbey_right_focus_single = whidbey_right_focus
+
+#----------------------------------------------------------------------
+whidbey_up = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAaHWVcHilcYCncYa0dpC4ZobHcYXGcpDBc5fWcZjgd6Dld6Pwi5OzgJbUkJjA"
+    "kJjQgKDXk6TWhafggqfwh7Dwl7fwp7fXoLfnoLjwsLjjpMLwscHntdD0wMHg4Of35/D49/f3"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAWZqHkAAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAFmSURBVDhPhdTtdoMgDAZgW3GKWjsL2i/X2vu/SJaEBBXcWf6Jz3l5i9bMpdNXR3Xa"
+    "Wc/StXNfKXXawaktm1rrUuWHJCWxX01TA1bqkODYlm3bNjCAVYwji9TbneStJcoWcNR5Yz0V"
+    "mySvLVJrvW/buq7g7NadVxbpvJ3taSyWUuef9cx6kxwsdU3sprPY0tJEucboqginwZapjfqC"
+    "1UUhT9BboXb28Twfa42pQjLZQMUCwiHbdZKMdqFsPx+PeZee3w2w3WpXugvUY7GAsXPmLvdx"
+    "HITzXe4QbK8Klbvsckcr+C/bF0WeZ+52ez6Bw+D2AwxdwAxwhRsaPDp9hA4OLWGpSn1pVlZh"
+    "X8Cg2dpNLlxwrgFKFpP/sRqZf26Ph3T2Te8w3AyijSlJ8fuA1v/Acfy+0Dxp8DyZig2dr9fw"
+    "WXj5ExoGnxpy5TSi78c0gRUacvE0XjvfsGnqwuryH3q/d6hz07L6CxOEXf5LAPv7AAAAAElF"
+    "TkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_up_single = whidbey_up
+
+#----------------------------------------------------------------------
+whidbey_up_focus = PyEmbeddedImage(
+    "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B"
+    "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA"
+    "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR"
+    "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw"
+    "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI"
+    "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////////////////////////////////////////////////////////"
+    "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn"
+    "4iUAAAGTSURBVDhPfdQNV4IwFAZgpEyCVBRZaR8OUcI0yrLw//8xuvfuy22e7jkKZz68uxtg"
+    "0Pm135fl24XxwB/bNU1VFS/+D77d/TY12lsPe3aLqTkUu3Gxa7cHSC3IsmsHOxZS64pzYTMH"
+    "23Z7qKFXvpTWwZZd0w5wJivLbHxu14fmtSqUzRhYC5/ZEuY/tVbZ2NjyA1o9/UB9qmrtZG0x"
+    "teKtdnjSplCmDWXLd7xZF63G0opUzux2Ra5eoLCYShvQqv2io7IymewGUsV9lVYdcG1TqAnd"
+    "QbSbDbR6bqETkastYbCruob5xTNAhpp27PgK7WqFG8DZvz2kY8DBQwGF68XKW/HUtPCBE1rb"
+    "dJKCjOMwDLq7gjHbkscvZUEOBiGtLc+NtTdYjCcJyFDsQ2cshOnr1PlYUmH7aTqbqYyEajRS"
+    "12Bqr6f2V2CaLInjCCqGShJ5NTRAVOQSRokulDWfozap2gLGmaMwetIv7/yeulGpxnb94TCK"
+    "Hp23fLHAedSgeS/C4fHo/y89R5qqfhF9+xJGvszoH5Xccuo6pVT3AAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+whidbey_up_focus_single = whidbey_up_focus
+
+#----------------------------------------------------------------------
+
+whidbey_denied = aero_denied
+
+#----------------------------------------------------------------------
+
+# ------------------------ #
+# - AuiToolBar Constants - #
+# ------------------------ #
+
+ITEM_CONTROL = wx.ITEM_MAX
+""" The item in the AuiToolBar is a control. """
+ITEM_LABEL = ITEM_CONTROL + 1
+""" The item in the AuiToolBar is a text label. """
+ITEM_SPACER = ITEM_CONTROL + 2
+""" The item in the AuiToolBar is a spacer. """
+ITEM_SEPARATOR = wx.ITEM_SEPARATOR
+""" The item in the AuiToolBar is a separator. """
+ITEM_CHECK = wx.ITEM_CHECK
+""" The item in the AuiToolBar is a toolbar check item. """
+ITEM_NORMAL = wx.ITEM_NORMAL
+""" The item in the AuiToolBar is a standard toolbar item. """
+ITEM_RADIO = wx.ITEM_RADIO
+""" The item in the AuiToolBar is a toolbar radio item. """
+ID_RESTORE_FRAME = wx.ID_HIGHEST + 10000
+""" Identifier for restoring a minimized pane. """
+
+BUTTON_DROPDOWN_WIDTH = 10
+""" Width of the drop-down button in AuiToolBar. """
+
+DISABLED_TEXT_GREY_HUE = 153.0
+""" Hue text colour for the disabled text in AuiToolBar. """
+DISABLED_TEXT_COLOUR = wx.Colour(DISABLED_TEXT_GREY_HUE,
+                                 DISABLED_TEXT_GREY_HUE,
+                                 DISABLED_TEXT_GREY_HUE)
+""" Text colour for the disabled text in AuiToolBar. """
+
+AUI_TB_TEXT             = 1 << 0
+""" Shows the text in the toolbar buttons; by default only icons are shown. """
+AUI_TB_NO_TOOLTIPS      = 1 << 1
+""" Don't show tooltips on `AuiToolBar` items. """
+AUI_TB_NO_AUTORESIZE    = 1 << 2
+""" Do not auto-resize the `AuiToolBar`. """
+AUI_TB_GRIPPER          = 1 << 3
+""" Shows a gripper on the `AuiToolBar`. """
+AUI_TB_OVERFLOW         = 1 << 4
+""" The `AuiToolBar` can contain overflow items. """
+AUI_TB_VERTICAL         = 1 << 5
+""" The `AuiToolBar` is vertical. """
+AUI_TB_HORZ_LAYOUT      = 1 << 6
+""" Shows the text and the icons alongside, not vertically stacked.
+This style must be used with ``AUI_TB_TEXT``. """
+AUI_TB_PLAIN_BACKGROUND = 1 << 7
+""" Don't draw a gradient background on the toolbar. """
+AUI_TB_CLOCKWISE        = 1 << 8
+AUI_TB_COUNTERCLOCKWISE = 1 << 9
+
+AUI_TB_HORZ_TEXT        = AUI_TB_HORZ_LAYOUT | AUI_TB_TEXT
+""" Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``. """
+AUI_TB_VERT_TEXT        = AUI_TB_VERTICAL | AUI_TB_CLOCKWISE | AUI_TB_TEXT
+
+AUI_TB_DEFAULT_STYLE    = 0
+""" `AuiToolBar` default style. """
+
+# AuiToolBar settings
+AUI_TBART_SEPARATOR_SIZE = 0
+""" Separator size in AuiToolBar. """
+AUI_TBART_GRIPPER_SIZE = 1
+""" Gripper size in AuiToolBar. """
+AUI_TBART_OVERFLOW_SIZE = 2
+""" Overflow button size in AuiToolBar. """
+
+# AuiToolBar text orientation
+AUI_TBTOOL_TEXT_LEFT = 0     # unused/unimplemented
+""" Text in AuiToolBar items is aligned left. """
+AUI_TBTOOL_TEXT_RIGHT = 1
+""" Text in AuiToolBar items is aligned right. """
+AUI_TBTOOL_TEXT_TOP = 2      # unused/unimplemented
+""" Text in AuiToolBar items is aligned top. """
+AUI_TBTOOL_TEXT_BOTTOM = 3
+""" Text in AuiToolBar items is aligned bottom. """
+
+# AuiToolBar tool orientation
+AUI_TBTOOL_HORIZONTAL = 0             # standard
+AUI_TBTOOL_VERT_CLOCKWISE = 1         # rotation of 90 on the right
+AUI_TBTOOL_VERT_COUNTERCLOCKWISE = 2  # rotation of 90 on the left
+
+
+# --------------------- #
+# - AuiMDI* Constants - #
+# --------------------- #
+
+wxWINDOWCLOSE = 4001
+""" Identifier for the AuiMDI "close window" menu. """
+wxWINDOWCLOSEALL = 4002
+""" Identifier for the AuiMDI "close all windows" menu. """
+wxWINDOWNEXT = 4003
+""" Identifier for the AuiMDI "next window" menu. """
+wxWINDOWPREV = 4004
+""" Identifier for the AuiMDI "previous window" menu. """
+
+# ----------------------------- #
+# - AuiDockingGuide Constants - #
+# ----------------------------- #
+
+colourTargetBorder = wx.Colour(180, 180, 180)
+colourTargetShade = wx.Colour(206, 206, 206)
+colourTargetBackground = wx.Colour(224, 224, 224)
+colourIconBorder = wx.Colour(82, 65, 156)
+colourIconBackground = wx.Colour(255, 255, 255)
+colourIconDockingPart1 = wx.Colour(215, 228, 243)
+colourIconDockingPart2 = wx.Colour(180, 201, 225)
+colourIconShadow = wx.Colour(198, 198, 198)
+colourIconArrow = wx.Colour(77, 79, 170)
+colourHintBackground = wx.Colour(0, 64, 255)
+guideSizeX, guideSizeY = 29, 32
+aeroguideSizeX, aeroguideSizeY = 31, 32
+whidbeySizeX, whidbeySizeY = 43, 30
+
+# ------------------------------- #
+# - AuiSwitcherDialog Constants - #
+# ------------------------------- #
+
+SWITCHER_TEXT_MARGIN_X = 4
+SWITCHER_TEXT_MARGIN_Y = 1
diff --git a/aui/aui_switcherdialog.py b/aui/aui_switcherdialog.py
new file mode 100644 (file)
index 0000000..552cb84
--- /dev/null
@@ -0,0 +1,1216 @@
+"""
+Description
+===========
+
+The idea of `SwitcherDialog` is to make it easier to implement keyboard
+navigation in AUI and other applications that have multiple panes and
+tabs.
+
+A key combination with a modifier (such as ``Ctrl`` + ``Tab``) shows the
+dialog, and the user holds down the modifier whilst navigating with
+``Tab`` and arrow keys before releasing the modifier to dismiss the dialog
+and activate the selected pane.
+
+The switcher dialog is a multi-column menu with no scrolling, implemented
+by the `MultiColumnListCtrl` class. You can have headings for your items
+for logical grouping, and you can force a column break if you need to.
+
+The modifier used for invoking and dismissing the dialog can be customised,
+as can the colours, number of rows, and the key used for cycling through
+the items. So you can use different keys on different platforms if
+required (especially since ``Ctrl`` + ``Tab`` is reserved on some platforms).
+
+Items are shown as names and optional 16x16 images.
+
+
+Base Functionalities
+====================
+
+To use the dialog, you set up the items in a `SwitcherItems` object,
+before passing this to the `SwitcherDialog` instance.
+
+Call L{SwitcherItems.AddItem} and optionally L{SwitcherItems.AddGroup} to add items and headings. These
+functions take a label (to be displayed to the user), an identifying name,
+an integer id, and a bitmap. The name and id are purely for application-defined
+identification. You may also set a description to be displayed when each
+item is selected; and you can set a window pointer for convenience when
+activating the desired window after the dialog returns.
+
+Have created the dialog, you call `ShowModal()`, and if the return value is
+``wx.ID_OK``, retrieve the selection from the dialog and activate the pane.
+
+The sample code below shows a generic method of finding panes and notebook
+tabs within the current L{AuiManager}, and using the pane name or notebook
+tab position to display the pane.
+
+The only other code to add is a menu item with the desired accelerator,
+whose modifier matches the one you pass to L{SwitcherDialog.SetModifierKey} 
+(the default being ``wx.WXK_CONTROL``).
+
+
+Usage
+=====
+
+Menu item::
+
+    if wx.Platform == "__WXMAC__":
+        switcherAccel = "Alt+Tab"
+    elif wx.Platform == "__WXGTK__":
+        switcherAccel = "Ctrl+/"
+    else:
+        switcherAccel = "Ctrl+Tab"
+
+    view_menu.Append(ID_SwitchPane, _("S&witch Window...") + "\t" + switcherAccel)
+
+
+Event handler::
+
+    def OnSwitchPane(self, event):
+
+        items = SwitcherItems()
+        items.SetRowCount(12)
+
+        # Add the main windows and toolbars, in two separate columns
+        # We'll use the item 'id' to store the notebook selection, or -1 if not a page
+
+        for k in xrange(2):
+            if k == 0:
+                items.AddGroup(_("Main Windows"), "mainwindows")
+            else:
+                items.AddGroup(_("Toolbars"), "toolbars").BreakColumn()
+
+            for pane in self._mgr.GetAllPanes():
+                name = pane.name
+                caption = pane.caption
+
+                toolbar = isinstance(info.window, wx.ToolBar) or isinstance(info.window, aui.AuiToolBar)
+                if caption and (toolBar  and k == 1) or (not toolBar and k == 0):
+                    items.AddItem(caption, name, -1).SetWindow(pane.window)
+
+        # Now add the wxAuiNotebook pages
+
+        items.AddGroup(_("Notebook Pages"), "pages").BreakColumn()
+
+        for pane in self._mgr.GetAllPanes():
+            nb = pane.window
+            if isinstance(nb, aui.AuiNotebook):
+                for j in xrange(nb.GetPageCount()):
+
+                    name = nb.GetPageText(j)
+                    win = nb.GetPage(j)
+
+                    items.AddItem(name, name, j, nb.GetPageBitmap(j)).SetWindow(win)
+
+        # Select the focused window
+
+        idx = items.GetIndexForFocus()
+        if idx != wx.NOT_FOUND:
+            items.SetSelection(idx)
+
+        if wx.Platform == "__WXMAC__":
+            items.SetBackgroundColour(wx.WHITE)
+        
+        # Show the switcher dialog
+
+        dlg = SwitcherDialog(items, wx.GetApp().GetTopWindow())
+
+        # In GTK+ we can't use Ctrl+Tab; we use Ctrl+/ instead and tell the switcher
+        # to treat / in the same was as tab (i.e. cycle through the names)
+
+        if wx.Platform == "__WXGTK__":
+            dlg.SetExtraNavigationKey(wxT('/'))
+
+        if wx.Platform == "__WXMAC__":
+            dlg.SetBackgroundColour(wx.WHITE)
+            dlg.SetModifierKey(wx.WXK_ALT)
+
+        ans = dlg.ShowModal()
+
+        if ans == wx.ID_OK and dlg.GetSelection() != -1:
+            item = items.GetItem(dlg.GetSelection())
+
+            if item.GetId() == -1:
+                info = self._mgr.GetPane(item.GetName())
+                info.Show()
+                self._mgr.Update()
+                info.window.SetFocus()
+
+            else:
+                nb = item.GetWindow().GetParent()
+                win = item.GetWindow();
+                if isinstance(nb, aui.AuiNotebook):
+                    nb.SetSelection(item.GetId())
+                    win.SetFocus()
+
+
+"""
+
+import wx
+
+import auibook
+from aui_utilities import FindFocusDescendant
+from aui_constants import SWITCHER_TEXT_MARGIN_X, SWITCHER_TEXT_MARGIN_Y
+
+
+# Define a translation function
+_ = wx.GetTranslation
+
+    
+class SwitcherItem(object):
+    """ An object containing information about one item. """
+    
+    def __init__(self, item=None):
+        """ Default class constructor. """
+
+        self._id = 0
+        self._isGroup = False
+        self._breakColumn = False
+        self._rowPos = 0
+        self._colPos = 0
+        self._window = None
+        self._description = ""
+
+        self._textColour = wx.NullColour
+        self._bitmap = wx.NullBitmap
+        self._font = wx.NullFont
+        
+        if item:
+            self.Copy(item)
+
+
+    def Copy(self, item):
+        """
+        Copy operator between 2 L{SwitcherItem} instances.
+
+        :param `item`: another instance of L{SwitcherItem}.
+        """
+
+        self._id = item._id
+        self._name = item._name
+        self._title = item._title
+        self._isGroup = item._isGroup
+        self._breakColumn = item._breakColumn
+        self._rect = item._rect
+        self._font = item._font
+        self._textColour = item._textColour
+        self._bitmap = item._bitmap
+        self._description = item._description
+        self._rowPos = item._rowPos
+        self._colPos = item._colPos
+        self._window = item._window
+
+
+    def SetTitle(self, title):
+
+        self._title = title
+        return self
+    
+
+    def GetTitle(self):
+        
+        return self._title
+
+
+    def SetName(self, name):
+
+        self._name = name
+        return self
+
+    
+    def GetName(self):
+
+        return self._name
+
+
+    def SetDescription(self, descr):
+
+        self._description = descr
+        return self
+
+
+    def GetDescription(self):
+
+        return self._description
+    
+
+    def SetId(self, id):
+
+        self._id = id
+        return self
+
+    
+    def GetId(self):
+
+        return self._id
+
+
+    def SetIsGroup(self, isGroup):
+
+        self._isGroup = isGroup
+        return self
+
+    
+    def GetIsGroup(self):
+
+        return self._isGroup
+    
+
+    def BreakColumn(self, breakCol=True):
+
+        self._breakColumn = breakCol
+        return self
+
+    
+    def GetBreakColumn(self):
+
+        return self._breakColumn
+
+
+    def SetRect(self, rect):
+
+        self._rect = rect
+        return self
+
+    
+    def GetRect(self):
+        
+        return self._rect
+
+
+    def SetTextColour(self, colour):
+
+        self._textColour = colour
+        return self
+
+    
+    def GetTextColour(self):
+
+        return self._textColour
+    
+
+    def SetFont(self, font):
+
+        self._font = font
+        return self
+
+    
+    def GetFont(self):
+
+        return self._font
+    
+
+    def SetBitmap(self, bitmap):
+
+        self._bitmap = bitmap
+        return self
+
+    
+    def GetBitmap(self):
+
+        return self._bitmap
+
+
+    def SetRowPos(self, pos):
+
+        self._rowPos = pos
+        return self
+
+    
+    def GetRowPos(self):
+
+        return self._rowPos
+    
+
+    def SetColPos(self, pos):
+
+        self._colPos = pos
+        return self
+
+    
+    def GetColPos(self):
+
+        return self._colPos
+    
+
+    def SetWindow(self, win):
+
+        self._window = win
+        return self
+    
+
+    def GetWindow(self):
+
+        return self._window
+
+    
+class SwitcherItems(object):
+    """ An object containing switcher items. """
+
+    def __init__(self, items=None):
+        """ Default class constructor. """
+
+        self._selection = -1
+        self._rowCount = 10
+        self._columnCount = 0
+
+        self._backgroundColour = wx.NullColour
+        self._textColour = wx.NullColour
+        self._selectionColour = wx.NullColour
+        self._selectionOutlineColour = wx.NullColour
+        self._itemFont = wx.NullFont
+
+        self._items = []        
+        
+        if wx.Platform == "__WXMSW__":
+            # If on Windows XP/Vista, use more appropriate colours
+            self.SetSelectionOutlineColour(wx.Colour(49, 106, 197))
+            self.SetSelectionColour(wx.Colour(193, 210, 238))
+
+        if items:
+            self.Copy(items)
+            
+
+    def Copy(self, items):
+        """
+        Copy operator between 2 L{SwitcherItems}.
+
+        :param `items`: another instance of L{SwitcherItems}.
+        """
+        
+        self.Clear()
+
+        for item in items._items:
+            self._items.append(item)
+        
+        self._selection = items._selection
+        self._rowCount = items._rowCount
+        self._columnCount = items._columnCount
+
+        self._backgroundColour = items._backgroundColour
+        self._textColour = items._textColour
+        self._selectionColour = items._selectionColour
+        self._selectionOutlineColour = items._selectionOutlineColour
+        self._itemFont = items._itemFont
+
+
+    def AddItem(self, titleOrItem, name=None, id=0, bitmap=wx.NullBitmap):
+
+        if isinstance(titleOrItem, SwitcherItem):
+            self._items.append(titleOrItem)
+            return self._items[-1]
+        
+        item = SwitcherItem()
+        item.SetTitle(titleOrItem)
+        item.SetName(name)
+        item.SetId(id)
+        item.SetBitmap(bitmap)
+
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def AddGroup(self, title, name, id=0, bitmap=wx.NullBitmap):
+
+        item = self.AddItem(title, name, id, bitmap)
+        item.SetIsGroup(True)
+
+        return item
+
+
+    def Clear(self):
+
+        self._items = []
+
+
+    def FindItemByName(self, name):
+
+        for i in xrange(len(self._items)):
+            if self._items[i].GetName() == name:
+                return i
+        
+        return wx.NOT_FOUND
+
+
+    def FindItemById(self, id):
+
+        for i in xrange(len(self._items)):
+            if self._items[i].GetId() == id:
+                return i
+        
+        return wx.NOT_FOUND
+
+
+    def SetSelection(self, sel):
+
+        self._selection = sel
+
+
+    def SetSelectionByName(self, name):
+
+        idx = self.FindItemByName(name)
+        if idx != wx.NOT_FOUND:
+            self.SetSelection(idx)
+
+
+    def GetSelection(self):
+
+        return self._selection
+    
+
+    def GetItem(self, i):
+
+        return self._items[i]
+
+
+    def GetItemCount(self):
+
+        return len(self._items)
+    
+
+    def SetRowCount(self, rows):
+
+        self._rowCount = rows
+
+        
+    def GetRowCount(self):
+
+        return self._rowCount
+
+
+    def SetColumnCount(self, cols):
+
+        self._columnCount = cols
+
+        
+    def GetColumnCount(self):
+
+        return self._columnCount
+    
+
+    def SetBackgroundColour(self, colour):
+
+        self._backgroundColour = colour
+
+        
+    def GetBackgroundColour(self):
+
+        return self._backgroundColour
+    
+
+    def SetTextColour(self, colour):
+
+        self._textColour = colour
+
+        
+    def GetTextColour(self):
+
+        return self._textColour
+    
+
+    def SetSelectionColour(self, colour):
+
+        self._selectionColour = colour
+
+        
+    def GetSelectionColour(self):
+
+        return self._selectionColour
+    
+
+    def SetSelectionOutlineColour(self, colour):
+
+        self._selectionOutlineColour = colour
+
+        
+    def GetSelectionOutlineColour(self):
+
+        return self._selectionOutlineColour
+    
+
+    def SetItemFont(self, font):
+
+        self._itemFont = font
+
+        
+    def GetItemFont(self):
+
+        return self._itemFont 
+    
+
+    def PaintItems(self, dc, win):
+
+        backgroundColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)
+        standardTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
+        selectionColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+        selectionOutlineColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
+        standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        groupFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        groupFont.SetWeight(wx.BOLD)
+
+        if self.GetBackgroundColour().IsOk():
+            backgroundColour = self.GetBackgroundColour()
+
+        if self.GetTextColour().IsOk():
+            standardTextColour = self.GetTextColour()
+
+        if self.GetSelectionColour().IsOk():
+            selectionColour = self.GetSelectionColour()
+
+        if self.GetSelectionOutlineColour().IsOk():
+            selectionOutlineColour = self.GetSelectionOutlineColour()
+
+        if self.GetItemFont().IsOk():
+        
+            standardFont = self.GetItemFont()   
+            groupFont = wx.Font(standardFont.GetPointSize(), standardFont.GetFamily(), standardFont.GetStyle(),
+                                wx.BOLD, standardFont.GetUnderlined(), standardFont.GetFaceName())
+        
+        textMarginX = SWITCHER_TEXT_MARGIN_X
+
+        dc.SetLogicalFunction(wx.COPY)
+        dc.SetBrush(wx.Brush(backgroundColour))
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        dc.DrawRectangleRect(win.GetClientRect())
+        dc.SetBackgroundMode(wx.TRANSPARENT)
+
+        for i in xrange(len(self._items)):
+            item = self._items[i]
+            if i == self._selection:
+                dc.SetPen(wx.Pen(selectionOutlineColour))
+                dc.SetBrush(wx.Brush(selectionColour))
+                dc.DrawRectangleRect(item.GetRect())
+            
+            clippingRect = wx.Rect(*item.GetRect())
+            clippingRect.Deflate(1, 1)
+
+            dc.SetClippingRect(clippingRect)
+
+            if item.GetTextColour().IsOk():
+                dc.SetTextForeground(item.GetTextColour())
+            else:
+                dc.SetTextForeground(standardTextColour)
+            
+            if item.GetFont().IsOk():
+                dc.SetFont(item.GetFont())
+            else:
+                if item.GetIsGroup():
+                    dc.SetFont(groupFont)
+                else:
+                    dc.SetFont(standardFont)
+            
+            w, h = dc.GetTextExtent(item.GetTitle())
+            x = item.GetRect().x
+
+            x += textMarginX
+
+            if not item.GetIsGroup():
+                if item.GetBitmap().IsOk() and item.GetBitmap().GetWidth() <= 16 \
+                   and item.GetBitmap().GetHeight() <= 16:
+                    x -= textMarginX
+                    dc.DrawBitmap(item.GetBitmap(), x, item.GetRect().y + \
+                                  (item.GetRect().height - item.GetBitmap().GetHeight())/2,
+                                  True)
+                    x += 16 + textMarginX
+                #x += textMarginX
+            
+            y = item.GetRect().y + (item.GetRect().height - h)/2
+            dc.DrawText(item.GetTitle(), x, y)
+            dc.DestroyClippingRegion()
+    
+
+    def CalculateItemSize(self, dc):
+
+        # Start off allowing for an icon
+        sz = wx.Size(150, 16)
+        standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        groupFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        groupFont.SetWeight(wx.BOLD)
+
+        textMarginX = SWITCHER_TEXT_MARGIN_X
+        textMarginY = SWITCHER_TEXT_MARGIN_Y
+        maxWidth = 300
+        maxHeight = 40
+
+        if self.GetItemFont().IsOk():
+            standardFont = self.GetItemFont()   
+
+        for item in self._items:
+            if item.GetFont().IsOk():
+                dc.SetFont(item.GetFont())
+            else:
+                if item.GetIsGroup():
+                    dc.SetFont(groupFont)
+                else:
+                    dc.SetFont(standardFont)
+
+            w, h = dc.GetTextExtent(item.GetTitle())
+            w += 16 + 2*textMarginX
+
+            if w > sz.x:
+                sz.x = min(w, maxWidth)
+            if h > sz.y:
+                sz.y = min(h, maxHeight)
+        
+        if sz == wx.Size(16, 16):
+            sz = wx.Size(100, 25)
+        else:
+            sz.x += textMarginX*2
+            sz.y += textMarginY*2
+        
+        return sz
+
+
+    def GetIndexForFocus(self):
+
+        for i, item in enumerate(self._items):        
+            if item.GetWindow():
+            
+                if FindFocusDescendant(item.GetWindow()):
+                    return i
+            
+        return wx.NOT_FOUND
+
+
+class MultiColumnListCtrl(wx.PyControl):
+    """ A control for displaying several columns (not scrollable). """
+
+    def __init__(self, parent, aui_manager, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=0, validator=wx.DefaultValidator, name="MultiColumnListCtrl"):
+
+        wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
+
+        self._overallSize = wx.Size(200, 100)
+        self._modifierKey = wx.WXK_CONTROL
+        self._extraNavigationKey = 0
+        self._aui_manager = aui_manager
+        
+        self.SetInitialSize(size)
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
+        self.Bind(wx.EVT_KEY_UP, self.OnKey)
+
+
+    def __del__(self):
+
+        self._aui_manager.HideHint()
+
+        
+    def DoGetBestSize(self):
+
+        return self._overallSize
+
+
+    def OnEraseBackground(self, event):
+        
+        pass
+
+
+    def OnPaint(self, event):
+
+        dc = wx.AutoBufferedPaintDC(self)
+        rect = self.GetClientRect()
+
+        if self._items.GetColumnCount() == 0:
+            self.CalculateLayout(dc)
+
+        if self._items.GetColumnCount() == 0:
+            return
+
+        self._items.PaintItems(dc, self)
+
+
+    def OnMouseEvent(self, event):
+
+        if event.LeftDown():
+            self.SetFocus()
+    
+
+    def OnChar(self, event):
+
+        event.Skip()        
+
+
+    def OnKey(self, event):
+
+        if event.GetEventType() == wx.wxEVT_KEY_UP:
+            if event.GetKeyCode() == self.GetModifierKey():
+                topLevel = wx.GetTopLevelParent(self)
+                closeEvent = wx.CloseEvent(wx.wxEVT_CLOSE_WINDOW, topLevel.GetId())
+                closeEvent.SetEventObject(topLevel)
+                closeEvent.SetCanVeto(False)
+                
+                topLevel.GetEventHandler().ProcessEvent(closeEvent)
+                return
+                
+            event.Skip()
+            return
+
+        keyCode = event.GetKeyCode()
+        
+        if keyCode in [wx.WXK_ESCAPE, wx.WXK_RETURN]:
+            if keyCode == wx.WXK_ESCAPE:
+                self._items.SetSelection(-1)
+
+            topLevel = wx.GetTopLevelParent(self)
+            closeEvent = wx.CloseEvent(wx.wxEVT_CLOSE_WINDOW, topLevel.GetId())
+            closeEvent.SetEventObject(topLevel)
+            closeEvent.SetCanVeto(False)
+            
+            topLevel.GetEventHandler().ProcessEvent(closeEvent)
+            return
+        
+        elif keyCode in [wx.WXK_TAB, self.GetExtraNavigationKey()]:
+            if event.ShiftDown():
+            
+                self._items.SetSelection(self._items.GetSelection() - 1)
+                if self._items.GetSelection() < 0:
+                    self._items.SetSelection(self._items.GetItemCount() - 1)
+
+                self.AdvanceToNextSelectableItem(-1)
+            
+            else:
+            
+                self._items.SetSelection(self._items.GetSelection() + 1)
+                if self._items.GetSelection() >= self._items.GetItemCount():
+                    self._items.SetSelection(0)
+
+                self.AdvanceToNextSelectableItem(1)
+            
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        elif keyCode in [wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN]:
+            self._items.SetSelection(self._items.GetSelection() + 1)
+            if self._items.GetSelection() >= self._items.GetItemCount():
+                self._items.SetSelection(0)
+            
+            self.AdvanceToNextSelectableItem(1)
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        elif keyCode in [wx.WXK_UP, wx.WXK_NUMPAD_UP]:
+            self._items.SetSelection(self._items.GetSelection() - 1)
+            if self._items.GetSelection() < 0:
+                self._items.SetSelection(self._items.GetItemCount() - 1)
+            
+            self.AdvanceToNextSelectableItem(-1)
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        elif keyCode in [wx.WXK_HOME, wx.WXK_NUMPAD_HOME]:
+            self._items.SetSelection(0)
+            self.AdvanceToNextSelectableItem(1)
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        elif keyCode in [wx.WXK_END, wx.WXK_NUMPAD_END]:
+            self._items.SetSelection(self._items.GetItemCount() - 1)
+            self.AdvanceToNextSelectableItem(-1)
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        elif keyCode in [wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT]:
+            item = self._items.GetItem(self._items.GetSelection())
+
+            row = item.GetRowPos()
+            newCol = item.GetColPos() - 1
+            if newCol < 0:
+                newCol = self._items.GetColumnCount() - 1
+
+            # Find the first item from the end whose row matches and whose column is equal or lower
+            for i in xrange(self._items.GetItemCount()-1, -1, -1):
+                item2 = self._items.GetItem(i)
+                if item2.GetColPos() == newCol and item2.GetRowPos() <= row:
+                    self._items.SetSelection(i)
+                    break
+
+            self.AdvanceToNextSelectableItem(-1)
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        elif keyCode in [wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT]:
+            item = self._items.GetItem(self._items.GetSelection())
+
+            row = item.GetRowPos()
+            newCol = item.GetColPos() + 1
+            if newCol >= self._items.GetColumnCount():
+                newCol = 0
+
+            # Find the first item from the end whose row matches and whose column is equal or lower
+            for i in xrange(self._items.GetItemCount()-1, -1, -1):
+                item2 = self._items.GetItem(i)
+                if item2.GetColPos() == newCol and item2.GetRowPos() <= row:
+                    self._items.SetSelection(i)
+                    break
+
+            self.AdvanceToNextSelectableItem(1)
+            self.GenerateSelectionEvent()
+            self.Refresh()
+        
+        else:
+            event.Skip()
+
+
+    def AdvanceToNextSelectableItem(self, direction):
+
+        if self._items.GetItemCount() < 2:
+            return
+
+        if self._items.GetSelection() == -1:
+            self._items.SetSelection(0)
+
+        oldSel = self._items.GetSelection()
+
+        while 1:
+        
+            if self._items.GetItem(self._items.GetSelection()).GetIsGroup():
+            
+                self._items.SetSelection(self._items.GetSelection() + direction)
+                if self._items.GetSelection() == -1:
+                    self._items.SetSelection(self._items.GetItemCount()-1)
+                elif self._items.GetSelection() == self._items.GetItemCount():
+                    self._items.SetSelection(0)
+                if self._items.GetSelection() == oldSel:
+                    break
+            
+            else:
+                break
+
+        self.SetTransparency()
+        selection = self._items.GetItem(self._items.GetSelection()).GetWindow()
+        pane = self._aui_manager.GetPane(selection)
+
+        if not pane.IsOk():
+            if isinstance(selection.GetParent(), auibook.AuiNotebook):
+                self.SetTransparency(selection)
+                self._aui_manager.ShowHint(selection.GetScreenRect())
+                wx.CallAfter(self.SetFocus)
+                self.SetFocus()
+                return
+            else:
+                self._aui_manager.HideHint()
+                return
+        if not pane.IsShown():
+            self._aui_manager.HideHint()
+            return
+
+        self.SetTransparency(selection)
+        self._aui_manager.ShowHint(selection.GetScreenRect())
+        # NOTE: this is odd but it is the only way for the focus to
+        #       work correctly on wxMac...
+        wx.CallAfter(self.SetFocus)
+        self.SetFocus()        
+    
+
+    def SetTransparency(self, selection=None):
+
+        if not self.GetParent().CanSetTransparent():
+            return
+        
+        if selection is not None:
+            intersects = False
+            if selection.GetScreenRect().Intersects(self.GetParent().GetScreenRect()):
+                intersects = True
+                self.GetParent().SetTransparent(200)
+                return
+
+        self.GetParent().SetTransparent(255)
+
+
+    def GenerateSelectionEvent(self):
+
+        event = wx.CommandEvent(wx.wxEVT_COMMAND_LISTBOX_SELECTED, self.GetId())
+        event.SetEventObject(self)
+        event.SetInt(self._items.GetSelection())
+        self.GetEventHandler().ProcessEvent(event)
+
+
+    def CalculateLayout(self, dc=None):
+
+        if dc is None:
+            dc = wx.ClientDC(self)
+
+        if self._items.GetSelection() == -1:
+            self._items.SetSelection(0)
+
+        columnCount = 1
+
+        # Spacing between edge of window or between columns
+        xMargin = 4
+        yMargin = 4
+
+        # Inter-row spacing
+        rowSpacing = 2
+
+        itemSize = self._items.CalculateItemSize(dc)
+        self._overallSize = wx.Size(350, 200)
+
+        currentRow = 0
+        x = xMargin
+        y = yMargin
+
+        breaking = False
+        i = 0
+        
+        while 1:
+        
+            oldOverallSize = self._overallSize
+            item = self._items.GetItem(i)
+            
+            item.SetRect(wx.Rect(x, y, itemSize.x, itemSize.y))
+            item.SetColPos(columnCount-1)
+            item.SetRowPos(currentRow)
+
+            if item.GetRect().GetBottom() > self._overallSize.y:
+                self._overallSize.y = item.GetRect().GetBottom() + yMargin
+
+            if item.GetRect().GetRight() > self._overallSize.x:
+                self._overallSize.x = item.GetRect().GetRight() + xMargin
+
+            currentRow += 1
+
+            y += rowSpacing + itemSize.y
+            stopBreaking = breaking
+
+            if currentRow > self._items.GetRowCount() or (item.GetBreakColumn() and not breaking and currentRow != 1):
+                currentRow = 0
+                columnCount += 1
+                x += xMargin + itemSize.x
+                y = yMargin
+
+                # Make sure we don't orphan a group
+                if item.GetIsGroup() or (item.GetBreakColumn() and not breaking):
+                    self._overallSize = oldOverallSize
+
+                    if item.GetBreakColumn():
+                        breaking = True
+
+                    # Repeat the last item, in the next column
+                    i -= 1
+                
+            if stopBreaking:
+                breaking = False
+
+            i += 1
+            
+            if i >= self._items.GetItemCount():
+                break
+            
+        self._items.SetColumnCount(columnCount)
+        self.InvalidateBestSize()
+
+
+    def SetItems(self, items):
+        
+        self._items = items
+
+        
+    def GetItems(self):
+
+        return self._items
+
+    def SetExtraNavigationKey(self, keyCode):
+        """
+        Set an extra key that can be used to cycle through items,
+        in case not using the ``Ctrl`` + ``Tab`` combination.
+        """
+
+        self._extraNavigationKey = keyCode
+
+
+    def GetExtraNavigationKey(self):
+
+        return self._extraNavigationKey
+
+
+    def SetModifierKey(self, modifierKey):
+        """
+        Set the modifier used to invoke the dialog, and therefore to test for
+        release.
+        """
+
+        self._modifierKey = modifierKey
+
+        
+    def GetModifierKey(self):
+
+        return self._modifierKey
+
+    
+
+class SwitcherDialog(wx.Dialog):
+    """
+    SwitcherDialog shows a L{MultiColumnListCtrl} with a list of panes
+    and tabs for the user to choose. ``Ctrl`` + ``Tab`` cycles through them.
+    """
+
+    def __init__(self, items, parent, aui_manager, id=wx.ID_ANY, title=_("Pane Switcher"), pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.STAY_ON_TOP|wx.DIALOG_NO_PARENT|wx.BORDER_SIMPLE):
+        """ Default class constructor. """
+        
+        self._switcherBorderStyle = (style & wx.BORDER_MASK)
+        if self._switcherBorderStyle == wx.BORDER_NONE:
+            self._switcherBorderStyle = wx.BORDER_SIMPLE
+
+        style &= wx.BORDER_MASK
+        style |= wx.BORDER_NONE
+
+        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+
+        self._listCtrl = MultiColumnListCtrl(self, aui_manager,
+                                             style=wx.WANTS_CHARS|wx.NO_BORDER)
+        self._listCtrl.SetItems(items)
+        self._listCtrl.CalculateLayout()
+
+        self._descriptionCtrl = wx.html.HtmlWindow(self, size=(-1, 100), style=wx.BORDER_NONE)
+        self._descriptionCtrl.SetBackgroundColour(self.GetBackgroundColour())
+
+        if wx.Platform == "__WXGTK__":
+            fontSize = 11
+            self._descriptionCtrl.SetStandardFonts(fontSize)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        self.SetSizer(sizer)
+        sizer.Add(self._listCtrl, 1, wx.ALL|wx.EXPAND, 10)
+        sizer.Add(self._descriptionCtrl, 0, wx.ALL|wx.EXPAND, 10)
+        sizer.SetSizeHints(self)
+
+        self._listCtrl.SetFocus()
+
+        self.Centre(wx.BOTH)
+
+        if self._listCtrl.GetItems().GetSelection() == -1:
+            self._listCtrl.GetItems().SetSelection(0)
+
+        self._listCtrl.AdvanceToNextSelectableItem(1)
+
+        self.ShowDescription(self._listCtrl.GetItems().GetSelection())
+
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
+        self.Bind(wx.EVT_LISTBOX, self.OnSelectItem)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+
+        # Attributes
+        self._closing = False
+        if wx.Platform == "__WXMSW__":
+            self._borderColour = wx.Colour(49, 106, 197)
+        else:
+            self._borderColour = wx.BLACK
+
+        self._aui_manager = aui_manager
+        
+
+    def OnCloseWindow(self, event):
+
+        if self._closing:
+            return
+
+        if self.IsModal():
+            self._closing = True
+
+            if self.GetSelection() == -1:
+                self.EndModal(wx.ID_CANCEL)
+            else:
+                self.EndModal(wx.ID_OK)
+    
+        self._aui_manager.HideHint()
+
+
+    def GetSelection(self):
+
+        return self._listCtrl.GetItems().GetSelection()
+
+
+    def OnActivate(self, event):
+
+        if not event.GetActive():
+            if not self._closing:
+                self._closing = True
+                self.EndModal(wx.ID_CANCEL)
+            
+
+    def OnPaint(self, event):
+
+        dc = wx.PaintDC(self)
+
+        if self._switcherBorderStyle == wx.BORDER_SIMPLE:
+        
+            dc.SetPen(wx.Pen(self._borderColour))
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+            rect = self.GetClientRect()
+            dc.DrawRectangleRect(rect)
+
+            # Draw border around the HTML control
+            rect = wx.Rect(*self._descriptionCtrl.GetRect())
+            rect.Inflate(1, 1)
+            dc.DrawRectangleRect(rect)
+
+    
+    def OnSelectItem(self, event):
+
+        self.ShowDescription(event.GetSelection())
+
+
+# Convert a colour to a 6-digit hex string
+    def ColourToHexString(self, col):
+
+        hx = '%02x%02x%02x' % tuple([int(c) for c in col])
+        return hx
+
+
+    def ShowDescription(self, i):
+
+        item = self._listCtrl.GetItems().GetItem(i)
+        colour = self._listCtrl.GetItems().GetBackgroundColour()
+        
+        if not colour.IsOk():
+            colour = self.GetBackgroundColour()
+
+        backgroundColourHex = self.ColourToHexString(colour)
+        html = _("<body bgcolor=\"#") + backgroundColourHex + _("\"><b>") + item.GetTitle() + _("</b>")
+
+        if item.GetDescription():
+            html += _("<p>")
+            html += item.GetDescription()
+        
+        html += _("</body>")
+        self._descriptionCtrl.SetPage(html)
+
+
+    def SetExtraNavigationKey(self, keyCode):
+
+        self._extraNavigationKey = keyCode
+        if self._listCtrl:
+            self._listCtrl.SetExtraNavigationKey(keyCode)
+
+
+    def GetExtraNavigationKey(self):
+
+        return self._extraNavigationKey
+    
+        
+    def SetModifierKey(self, modifierKey):
+
+        self._modifierKey = modifierKey
+        if self._listCtrl:
+            self._listCtrl.SetModifierKey(modifierKey)
+
+
+    def GetModifierKey(self):
+
+        return self._modifierKey        
+
+
+    def SetBorderColour(self, colour):
+
+        self._borderColour = colour
+
+        
\ No newline at end of file
diff --git a/aui/aui_utilities.py b/aui/aui_utilities.py
new file mode 100644 (file)
index 0000000..d6c701a
--- /dev/null
@@ -0,0 +1,678 @@
+"""
+This module contains some common functions used by wxPython-AUI to
+manipulate colours, bitmaps, text, gradient shadings and custom
+dragging images for AuiNotebook tabs.
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+
+from aui_constants import *
+
+
+if wx.Platform == "__WXMAC__":
+    import Carbon.Appearance
+    
+    
+def BlendColour(fg, bg, alpha):
+    """
+    Blends the two colour component `fg` and `bg` into one colour component, adding
+    an optional alpha channel.
+
+    :param `fg`: the first colour component;
+    :param `bg`: the second colour component;
+    :param `alpha`: an optional transparency value.
+    """
+    
+    result = bg + (alpha*(fg - bg))
+    
+    if result < 0.0:
+        result = 0.0
+    if result > 255:
+        result = 255
+        
+    return result
+
+
+def StepColour(c, ialpha):
+    """
+    Darken/lighten the input colour `c`.
+
+    :param `c`: a colour to darken/lighten;
+    :param `ialpha`: a transparency value.
+    """
+    
+    if ialpha == 100:
+        return c
+        
+    r, g, b = c.Red(), c.Green(), c.Blue()
+
+    # ialpha is 0..200 where 0 is completely black
+    # and 200 is completely white and 100 is the same
+    # convert that to normal alpha 0.0 - 1.0
+    ialpha = min(ialpha, 200)
+    ialpha = max(ialpha, 0)
+    alpha = (ialpha - 100.0)/100.0
+
+    if ialpha > 100:
+    
+        # blend with white
+        bg = 255
+        alpha = 1.0 - alpha  # 0 = transparent fg 1 = opaque fg
+    
+    else:
+    
+        # blend with black
+        bg = 0
+        alpha = 1.0 + alpha  # 0 = transparent fg 1 = opaque fg
+    
+    r = BlendColour(r, bg, alpha)
+    g = BlendColour(g, bg, alpha)
+    b = BlendColour(b, bg, alpha)
+
+    return wx.Colour(r, g, b)
+
+
+def LightContrastColour(c):
+    """
+    Creates a new, lighter colour based on the input colour `c`.
+
+    :param `c`: the input colour to analyze.
+    """
+
+    amount = 120
+
+    # if the colour is especially dark, then
+    # make the contrast even lighter
+    if c.Red() < 128 and c.Green() < 128 and c.Blue() < 128:
+        amount = 160
+
+    return StepColour(c, amount)
+
+
+def ChopText(dc, text, max_size):
+    """
+    Chops the input `text` if its size does not fit in `max_size`, by cutting the
+    text and adding ellipsis at the end.
+
+    :param `dc`: a `wx.DC` device context;
+    :param `text`: the text to chop;
+    :param `max_size`: the maximum size in which the text should fit.
+    """
+    
+    # first check if the text fits with no problems
+    x, y, dummy = dc.GetMultiLineTextExtent(text)
+    
+    if x <= max_size:
+        return text
+
+    textLen = len(text)
+    last_good_length = 0
+    
+    for i in xrange(textLen, -1, -1):
+        s = text[0:i]
+        s += "..."
+
+        x, y = dc.GetTextExtent(s)
+        last_good_length = i
+        
+        if x < max_size:
+            break
+
+    ret = text[0:last_good_length] + "..."    
+    return ret
+
+
+def BitmapFromBits(bits, w, h, colour):
+    """
+    BitmapFromBits() is a utility function that creates a
+    masked bitmap from raw bits (XBM format).
+
+    :param `bits`: a string containing the raw bits of the bitmap;
+    :param `w`: the bitmap width;
+    :param `h`: the bitmap height;
+    :param `colour`: the colour which will replace all white pixels in the
+     raw bitmap.
+    """
+
+    img = wx.BitmapFromBits(bits, w, h).ConvertToImage()
+    img.Replace(0, 0, 0, 123, 123, 123)
+    img.Replace(255, 255, 255, colour.Red(), colour.Green(), colour.Blue())
+    img.SetMaskColour(123, 123, 123)
+    return wx.BitmapFromImage(img)
+
+
+def IndentPressedBitmap(rect, button_state):
+    """
+    Indents the input rectangle `rect` based on the value of `button_state`.
+
+    :param `rect`: an instance of wx.Rect;
+    :param `button_state`: an L{AuiNotebook} button state.
+    """
+
+    if button_state == AUI_BUTTON_STATE_PRESSED:
+        rect.x += 1
+        rect.y += 1
+
+    return rect
+
+
+def GetBaseColour():
+    """
+    Returns the face shading colour on push buttons/backgrounds, mimicking as closely
+    as possible the platform UI colours.
+    """
+
+    if wx.Platform == "__WXMAC__":
+
+        if hasattr(wx, 'MacThemeColour'):
+            base_colour = wx.MacThemeColour(Carbon.Appearance.kThemeBrushToolbarBackground)
+        else:
+            brush = wx.Brush(wx.BLACK)
+            brush.MacSetTheme(Carbon.Appearance.kThemeBrushToolbarBackground)
+            base_colour = brush.GetColour()
+
+    else:
+        
+        base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)
+
+    # the base_colour is too pale to use as our base colour,
+    # so darken it a bit
+    if ((255-base_colour.Red()) +
+        (255-base_colour.Green()) +
+        (255-base_colour.Blue()) < 60):
+    
+        base_colour = StepColour(base_colour, 92)
+    
+    return base_colour
+
+
+def MakeDisabledBitmap(bitmap):
+    """
+    Convert the given image (in place) to a grayed-out version,
+    appropriate for a 'disabled' appearance.
+
+    :param `bitmap`: the bitmap to gray-out.
+    """
+
+    anImage = bitmap.ConvertToImage()    
+    factor = 0.7        # 0 < f < 1.  Higher Is Grayer
+    
+    if anImage.HasMask():
+        maskColour = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
+    else:
+        maskColour = None
+        
+    data = map(ord, list(anImage.GetData()))
+
+    for i in range(0, len(data), 3):
+        
+        pixel = (data[i], data[i+1], data[i+2])
+        pixel = MakeGray(pixel, factor, maskColour)
+
+        for x in range(3):
+            data[i+x] = pixel[x]
+
+    anImage.SetData(''.join(map(chr, data)))
+    
+    return anImage.ConvertToBitmap()
+
+
+def MakeGray(rgbTuple, factor, maskColour):
+    """
+    Make a pixel grayed-out. If the pixel matches the `maskColour`, it won't be
+    changed.
+
+    :param `rgbTuple`: a tuple representing a pixel colour;
+    :param `factor`: a graying-out factor;
+    :param `maskColour`: a colour mask.
+    """
+
+    if rgbTuple != maskColour:
+        r, g, b = rgbTuple
+        return map(lambda x: int((230 - x) * factor) + x, (r, g, b))
+    else:
+        return rgbTuple
+
+
+def Clip(a, b, c):
+    """
+    Clips the value in `a` based on the extremes `b` and `c`.
+
+    :param `a`: the value to analyze;
+    :param `b`: a minimum value;
+    :param `c`: a maximum value.
+    """
+
+    return ((a < b and [b]) or [(a > c and [c] or [a])[0]])[0]
+
+
+def LightColour(colour, percent):
+    """
+    Brighten input `colour` by `percent`.
+
+    :param `colour`: the colour to be brightened;
+    :param `percent`: brightening percentage.
+    """
+    
+    end_colour = wx.WHITE
+    
+    rd = end_colour.Red() - colour.Red()
+    gd = end_colour.Green() - colour.Green()
+    bd = end_colour.Blue() - colour.Blue()
+
+    high = 100
+
+    # We take the percent way of the colour from colour -. white
+    i = percent
+    r = colour.Red() + ((i*rd*100)/high)/100
+    g = colour.Green() + ((i*gd*100)/high)/100
+    b = colour.Blue() + ((i*bd*100)/high)/100
+    return wx.Colour(r, g, b)
+
+
+def PaneCreateStippleBitmap():
+    """
+    Creates a stipple bitmap to be used in a `wx.Brush`.
+    This is used to draw sash resize hints.
+    """
+
+    data = [0, 0, 0, 192, 192, 192, 192, 192, 192, 0, 0, 0]
+    img = wx.EmptyImage(2, 2)
+    counter = 0
+    
+    for ii in xrange(2):
+        for jj in xrange(2):
+            img.SetRGB(ii, jj, data[counter], data[counter+1], data[counter+2])
+            counter = counter + 3
+    
+    return img.ConvertToBitmap()
+
+
+def DrawMACCloseButton(colour, backColour=None):
+    """
+    Draws the wxMAC tab close button using `wx.GraphicsContext`.
+
+    :param `colour`: the colour to use to draw the circle;
+    :param `backColour`: the optional background colour for the circle.
+    """
+
+    bmp = wx.EmptyBitmapRGBA(16, 16)
+    dc = wx.MemoryDC()
+    dc.SelectObject(bmp)
+
+    gc = wx.GraphicsContext.Create(dc)    
+    gc.SetBrush(wx.Brush(colour))
+    path = gc.CreatePath()
+    path.AddCircle(6.5, 7, 6.5)
+    path.CloseSubpath()
+    gc.FillPath(path)
+    
+    path = gc.CreatePath()
+    if backColour is not None:
+        pen = wx.Pen(backColour, 2)
+    else:
+        pen = wx.Pen("white", 2)
+        
+    pen.SetCap(wx.CAP_BUTT)
+    pen.SetJoin(wx.JOIN_BEVEL)
+    gc.SetPen(pen)
+    path.MoveToPoint(3.5, 4)
+    path.AddLineToPoint(9.5, 10)
+    path.MoveToPoint(3.5, 10)
+    path.AddLineToPoint(9.5, 4)
+    path.CloseSubpath()
+    gc.DrawPath(path)
+
+    dc.SelectObject(wx.NullBitmap)
+    return bmp
+
+
+def DarkenBitmap(bmp, caption_colour, new_colour):
+    """
+    Darkens the input bitmap on wxMAC using the input colour.
+    
+    :param `bmp`: the bitmap to be manipulated;
+    :param `caption_colour`: the colour of the pane caption;
+    :param `new_colour`: the colour used to darken the bitmap.
+    """
+
+    image = bmp.ConvertToImage()
+    red = caption_colour.Red()/float(new_colour.Red())
+    green = caption_colour.Green()/float(new_colour.Green())
+    blue = caption_colour.Blue()/float(new_colour.Blue())
+    image = image.AdjustChannels(red, green, blue)
+    return image.ConvertToBitmap()
+
+    
+def DrawGradientRectangle(dc, rect, start_colour, end_colour, direction, offset=0, length=0):
+    """
+    Draws a gradient-shaded rectangle.
+
+    :param `dc`: a `wx.DC` device context;
+    :param `rect`: the rectangle in which to draw the gradient;
+    :param `start_colour`: the first colour of the gradient;
+    :param `end_colour`: the second colour of the gradient;
+    :param `direction`: the gradient direction (horizontal or vertical).
+    """
+    
+    if direction == AUI_GRADIENT_VERTICAL:
+        dc.GradientFillLinear(rect, start_colour, end_colour, wx.SOUTH)
+    else:
+        dc.GradientFillLinear(rect, start_colour, end_colour, wx.EAST)
+        
+
+def FindFocusDescendant(ancestor):
+    """
+    Find a window with the focus, that is also a descendant of the given window.
+    This is used to determine the window to initially send commands to.
+
+    :param `ancestor`: the window to check for ancestry.    
+    """
+
+    # Process events starting with the window with the focus, if any.
+    focusWin = wx.Window.FindFocus()
+    win = focusWin
+
+    # Check if this is a descendant of this frame.
+    # If not, win will be set to NULL.
+    while win:
+        if win == ancestor:
+            break
+        else:
+            win = win.GetParent()
+
+    if win is None:
+        focusWin = None
+
+    return focusWin
+
+
+def GetLabelSize(dc, label, vertical):
+    """
+    Returns the L{AuiToolBar} item label size.
+
+    :param `label`: the toolbar tool label;
+    :param `vertical`: whether the toolbar tool orientation is vertical or not.
+    """
+
+    text_width = text_height = 0
+
+    # get the text height
+    dummy, text_height = dc.GetTextExtent("ABCDHgj")
+    # get the text width
+    if label.strip():
+        text_width, dummy = dc.GetTextExtent(label)
+
+    if vertical:
+        tmp = text_height
+        text_height = text_width
+        text_width = tmp
+
+    return wx.Size(text_width, text_height)
+
+
+#---------------------------------------------------------------------------
+# TabDragImage implementation
+# This class handles the creation of a custom image when dragging
+# AuiNotebook tabs
+#---------------------------------------------------------------------------
+
+class TabDragImage(wx.DragImage):
+    """
+    This class handles the creation of a custom image in case of drag and
+    drop of a notebook tab.
+    """
+
+    def __init__(self, notebook, page, button_state, tabArt):
+        """
+        Default class constructor.
+        
+        For internal use: do not call it in your code!
+
+        :param `notebook`: an instance of L{AuiNotebook};
+        :param `page`: the dragged L{AuiNotebook} page;
+        :param `button_state`: the state of the close button on the tab;
+        :param `tabArt`: an instance of L{AuiDefaultTabArt} or one of its derivations.
+        """
+
+        self._backgroundColour = wx.NamedColour("pink")        
+        self._bitmap = self.CreateBitmap(notebook, page, button_state, tabArt)
+        wx.DragImage.__init__(self, self._bitmap)
+
+
+    def CreateBitmap(self, notebook, page, button_state, tabArt):
+        """
+        Actually creates the drag and drop bitmap.
+
+        :param `notebook`: an instance of L{AuiNotebook};
+        :param `page`: the dragged L{AuiNotebook} page;
+        :param `button_state`: the state of the close button on the tab;
+        :param `tabArt`: an instance of L{AuiDefaultTabArt} or one of its derivations.
+        """
+
+        control = page.control
+        memory = wx.MemoryDC(wx.EmptyBitmap(1, 1))
+
+        tab_size, x_extent = tabArt.GetTabSize(memory, notebook, page.caption, page.bitmap, page.active,
+                                               button_state, control)
+            
+        tab_width, tab_height = tab_size
+        rect = wx.Rect(0, 0, tab_width, tab_height)
+
+        bitmap = wx.EmptyBitmap(tab_width+1, tab_height+1)
+        memory.SelectObject(bitmap)
+
+        if wx.Platform == "__WXMAC__":
+            memory.SetBackground(wx.TRANSPARENT_BRUSH)
+        else:
+            memory.SetBackground(wx.Brush(self._backgroundColour))
+            
+        memory.SetBackgroundMode(wx.TRANSPARENT)
+        memory.Clear()
+
+        paint_control = wx.Platform != "__WXMAC__"
+        tabArt.DrawTab(memory, notebook, page, rect, button_state, paint_control=paint_control)
+        
+        memory.SetBrush(wx.TRANSPARENT_BRUSH)
+        memory.SetPen(wx.BLACK_PEN)
+        memory.DrawRoundedRectangle(0, 0, tab_width+1, tab_height+1, 2)
+
+        memory.SelectObject(wx.NullBitmap)
+        
+        # Gtk and Windows unfortunatly don't do so well with transparent
+        # drawing so this hack corrects the image to have a transparent
+        # background.
+        if wx.Platform != '__WXMAC__':
+            timg = bitmap.ConvertToImage()
+            if not timg.HasAlpha():
+                timg.InitAlpha()
+            for y in xrange(timg.GetHeight()):
+                for x in xrange(timg.GetWidth()):
+                    pix = wx.Colour(timg.GetRed(x, y),
+                                    timg.GetGreen(x, y),
+                                    timg.GetBlue(x, y))
+                    if pix == self._backgroundColour:
+                        timg.SetAlpha(x, y, 0)
+            bitmap = timg.ConvertToBitmap()
+        return bitmap        
+
+
+def GetDockingImage(direction, useAero, center):
+    """
+    Returns the correct name of the docking bitmap depending on the input parameters.
+
+    :param `useAero`: whether L{AuiManager} is using Aero-style or Whidbey-style docking
+     images or not;
+    :param `center`: whether we are looking for the center diamond-shaped bitmap or not. 
+    """
+
+    suffix = (center and [""] or ["_single"])[0]
+    prefix = ""
+    if useAero == 2:
+        # Whidbey docking guides
+        prefix = "whidbey_"
+    elif useAero == 1:
+        # Aero docking style
+        prefix = "aero_"
+        
+    if direction == wx.TOP:
+        bmp_unfocus = eval("%sup%s"%(prefix, suffix)).GetBitmap()
+        bmp_focus = eval("%sup_focus%s"%(prefix, suffix)).GetBitmap()
+    elif direction == wx.BOTTOM:
+        bmp_unfocus = eval("%sdown%s"%(prefix, suffix)).GetBitmap()
+        bmp_focus = eval("%sdown_focus%s"%(prefix, suffix)).GetBitmap()
+    elif direction == wx.LEFT:
+        bmp_unfocus = eval("%sleft%s"%(prefix, suffix)).GetBitmap()
+        bmp_focus = eval("%sleft_focus%s"%(prefix, suffix)).GetBitmap()
+    elif direction == wx.RIGHT:
+        bmp_unfocus = eval("%sright%s"%(prefix, suffix)).GetBitmap()
+        bmp_focus = eval("%sright_focus%s"%(prefix, suffix)).GetBitmap()
+    else:
+        bmp_unfocus = eval("%stab%s"%(prefix, suffix)).GetBitmap()
+        bmp_focus = eval("%stab_focus%s"%(prefix, suffix)).GetBitmap()
+
+    return bmp_unfocus, bmp_focus
+
+
+def TakeScreenShot(rect):
+    """
+    Takes a screenshot of the screen at given position and size (rect).
+
+    :param `rect`: the screen rectangle for which we want to take a screenshot.
+    """
+
+    # Create a DC for the whole screen area
+    dcScreen = wx.ScreenDC()
+
+    # Create a Bitmap that will later on hold the screenshot image
+    # Note that the Bitmap must have a size big enough to hold the screenshot
+    # -1 means using the current default colour depth
+    bmp = wx.EmptyBitmap(rect.width, rect.height)
+
+    # Create a memory DC that will be used for actually taking the screenshot
+    memDC = wx.MemoryDC()
+
+    # Tell the memory DC to use our Bitmap
+    # all drawing action on the memory DC will go to the Bitmap now
+    memDC.SelectObject(bmp)
+
+    # Blit (in this case copy) the actual screen on the memory DC
+    # and thus the Bitmap
+    memDC.Blit( 0,            # Copy to this X coordinate
+                0,            # Copy to this Y coordinate
+                rect.width,   # Copy this width
+                rect.height,  # Copy this height
+                dcScreen,     # From where do we copy?
+                rect.x,       # What's the X offset in the original DC?
+                rect.y        # What's the Y offset in the original DC?
+                )
+
+    # Select the Bitmap out of the memory DC by selecting a new
+    # uninitialized Bitmap
+    memDC.SelectObject(wx.NullBitmap)
+
+    return bmp
+
+
+def RescaleScreenShot(bmp, thumbnail_size=200):
+    """
+    Rescales a bitmap to be 300 pixels wide (or tall) at maximum.
+
+    :param `bmp`: the bitmap to rescale;
+    :param `thumbnail_size`: the maximum size of every page thumbnail.
+    """
+
+    bmpW, bmpH = bmp.GetWidth(), bmp.GetHeight()
+    img = bmp.ConvertToImage()
+
+    newW, newH = bmpW, bmpH
+    
+    if bmpW > bmpH:
+        if bmpW > thumbnail_size:
+            ratio = bmpW/float(thumbnail_size)
+            newW, newH = int(bmpW/ratio), int(bmpH/ratio)
+            img.Rescale(newW, newH, wx.IMAGE_QUALITY_HIGH)
+    else:
+        if bmpH > thumbnail_size:
+            ratio = bmpH/float(thumbnail_size)
+            newW, newH = int(bmpW/ratio), int(bmpH/ratio)
+            img.Rescale(newW, newH, wx.IMAGE_QUALITY_HIGH)
+
+    newBmp = img.ConvertToBitmap()
+    otherBmp = wx.EmptyBitmap(newW+5, newH+5)    
+
+    memDC = wx.MemoryDC()
+    memDC.SelectObject(otherBmp)
+    memDC.SetBackground(wx.WHITE_BRUSH)
+    memDC.Clear()
+    
+    memDC.SetPen(wx.TRANSPARENT_PEN)
+
+    pos = 0
+    for i in xrange(5, 0, -1):
+        brush = wx.Brush(wx.Colour(50*i, 50*i, 50*i))
+        memDC.SetBrush(brush)
+        memDC.DrawRoundedRectangle(0, 0, newW+5-pos, newH+5-pos, 2)
+        pos += 1
+
+    memDC.DrawBitmap(newBmp, 0, 0, True)
+     
+    # Select the Bitmap out of the memory DC by selecting a new
+    # uninitialized Bitmap
+    memDC.SelectObject(wx.NullBitmap)
+
+    return otherBmp
+
+
+def GetSlidingPoints(rect, size, direction):
+    """
+    Returns the point at which the sliding in and out of a minimized pane begins.
+
+    :param `rect`: the L{AuiToolBar} tool screen rectangle;
+    :param `size`: the pane window size;
+    :param `direction`: the pane docking direction.
+    """
+
+    if direction == AUI_DOCK_LEFT:
+        startX, startY = rect.x + rect.width + 2, rect.y
+    elif direction == AUI_DOCK_TOP:
+        startX, startY = rect.x, rect.y + rect.height + 2
+    elif direction == AUI_DOCK_RIGHT:
+        startX, startY = rect.x - size.x - 2, rect.y
+    elif direction == AUI_DOCK_BOTTOM:
+        startX, startY = rect.x, rect.y - size.y - 2
+    else:
+        raise Exception("How did we get here?")
+
+    caption_height = wx.SystemSettings.GetMetric(wx.SYS_CAPTION_Y)
+    frame_border_x = wx.SystemSettings.GetMetric(wx.SYS_FRAMESIZE_X)
+    frame_border_y = wx.SystemSettings.GetMetric(wx.SYS_FRAMESIZE_Y)
+    
+    stopX = size.x + caption_height + frame_border_x
+    stopY = size.x + frame_border_y
+    
+    return startX, startY, stopX, stopY
+
+
+def CopyAttributes(newArt, oldArt):
+    """
+    Copies pens, brushes, colours and fonts from the old tab art to the new one.
+
+    :param `newArt`: the new instance of L{AuiDefaultTabArt};
+    :param `oldArt`: the old instance of L{AuiDefaultTabArt}.
+    """    
+    
+    attrs = dir(oldArt)
+
+    for attr in attrs:
+        if attr.startswith("_") and (attr.endswith("_colour") or attr.endswith("_font") or \
+                                     attr.endswith("_font") or attr.endswith("_brush") or \
+                                     attr.endswith("Pen") or attr.endswith("_pen")):
+            setattr(newArt, attr, getattr(oldArt, attr))
+
+    return newArt            
+
diff --git a/aui/auibar.py b/aui/auibar.py
new file mode 100644 (file)
index 0000000..88bb509
--- /dev/null
@@ -0,0 +1,3926 @@
+"""
+auibar contains an implementation of L{AuiToolBar}, which is a completely owner-drawn
+toolbar perfectly integrated with the AUI layout system. This allows drag and drop of
+toolbars, docking/floating behaviour and the possibility to define "overflow" items
+in the toolbar itself.
+
+The default theme that is used is L{AuiDefaultToolBarArt}, which provides a modern,
+glossy look and feel. The theme can be changed by calling L{AuiToolBar.SetArtProvider}.
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+import types
+
+from aui_utilities import BitmapFromBits, StepColour, GetLabelSize
+from aui_utilities import GetBaseColour, MakeDisabledBitmap
+
+import framemanager
+from aui_constants import *
+
+# wxPython version string
+_VERSION_STRING = wx.VERSION_STRING
+
+# AuiToolBar events
+wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN = wx.NewEventType()
+wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK = wx.NewEventType()
+wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK = wx.NewEventType()
+wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK = wx.NewEventType()
+wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG = wx.NewEventType()
+
+EVT_AUITOOLBAR_TOOL_DROPDOWN = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, 1)
+""" A dropdown `AuiToolBarItem` is being shown. """
+EVT_AUITOOLBAR_OVERFLOW_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, 1)
+""" The user left-clicked on the overflow button in `AuiToolBar`. """
+EVT_AUITOOLBAR_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, 1)
+""" Fires an event when the user right-clicks on a `AuiToolBarItem`. """
+EVT_AUITOOLBAR_MIDDLE_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, 1)
+""" Fires an event when the user middle-clicks on a `AuiToolBarItem`. """
+EVT_AUITOOLBAR_BEGIN_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, 1)
+""" A drag operation involving a toolbar item has started. """
+
+# ----------------------------------------------------------------------
+
+class CommandToolBarEvent(wx.PyCommandEvent):
+    """ A specialized command event class for events sent by L{AuiToolBar}. """
+    
+    def __init__(self, command_type, win_id):
+        """
+        Default class constructor.
+
+        :param `command_type`: the event kind or an instance of `wx.PyCommandEvent`.
+        :param `win_id`: the window identification number.
+        """
+        
+        if type(command_type) == types.IntType:    
+            wx.PyCommandEvent.__init__(self, command_type, win_id)
+        else:
+            wx.PyCommandEvent.__init__(self, command_type.GetEventType(), command_type.GetId())
+            
+        self.is_dropdown_clicked = False
+        self.click_pt = wx.Point(-1, -1)
+        self.rect = wx.Rect(-1, -1, 0, 0)
+        self.tool_id = -1
+
+
+    def IsDropDownClicked(self):
+        """ Returns whether the drop down menu has been clicked. """
+
+        return self.is_dropdown_clicked
+    
+
+    def SetDropDownClicked(self, c):
+        """
+        Sets whether the drop down menu has been clicked.
+
+        :param `c`: ``True`` to set the drop down as clicked, ``False`` otherwise.
+        """
+
+        self.is_dropdown_clicked = c    
+
+
+    def GetClickPoint(self):
+        """ Returns the point where the user clicked with the mouse. """
+
+        return self.click_pt
+
+    
+    def SetClickPoint(self, p):
+        """
+        Sets the clicking point.
+
+        :param `p`: a `wx.Point` object.
+        """
+        
+        self.click_pt = p    
+
+
+    def GetItemRect(self):
+        """ Returns the L{AuiToolBarItem} rectangle. """
+
+        return self.rect
+
+    
+    def SetItemRect(self, r):
+        """
+        Sets the L{AuiToolBarItem} rectangle.
+
+        :param `r`: an instance of `wx.Rect`.
+        """
+
+        self.rect = r    
+
+
+    def GetToolId(self):
+        """ Returns the L{AuiToolBarItem} identifier. """
+
+        return self.tool_id
+
+    
+    def SetToolId(self, id):
+        """
+        Sets the L{AuiToolBarItem} identifier.
+
+        :param `id`: the toolbar item identifier.
+        """
+
+        self.tool_id = id   
+
+
+# ----------------------------------------------------------------------
+
+class AuiToolBarEvent(CommandToolBarEvent):
+    """ A specialized command event class for events sent by L{AuiToolBar}. """
+    
+    def __init__(self, command_type=None, win_id=0):
+        """
+        Default class constructor.
+
+        :param `command_type`: the event kind or an instance of `wx.PyCommandEvent`.
+        :param `win_id`: the window identification number.
+        """
+
+        CommandToolBarEvent.__init__(self, command_type, win_id)
+
+        if type(command_type) == types.IntType:
+            self.notify = wx.NotifyEvent(command_type, win_id)
+        else:
+            self.notify = wx.NotifyEvent(command_type.GetEventType(), command_type.GetId())
+
+        
+    def GetNotifyEvent(self):
+        """ Returns the actual `wx.NotifyEvent`. """
+        
+        return self.notify
+
+
+    def IsAllowed(self):
+        """ Returns whether the event is allowed or not. """
+
+        return self.notify.IsAllowed()
+
+
+    def Veto(self):
+        """
+        Prevents the change announced by this event from happening.
+
+        It is in general a good idea to notify the user about the reasons for
+        vetoing the change because otherwise the applications behaviour (which
+        just refuses to do what the user wants) might be quite surprising.
+        """
+
+        self.notify.Veto()
+
+
+    def Allow(self):
+        """
+        This is the opposite of L{Veto}: it explicitly allows the event to be
+        processed. For most events it is not necessary to call this method as the
+        events are allowed anyhow but some are forbidden by default (this will
+        be mentioned in the corresponding event description).
+        """
+
+        self.notify.Allow()
+
+
+# ----------------------------------------------------------------------
+
+class ToolbarCommandCapture(wx.PyEvtHandler):
+    """ A class to handle the dropdown window menu. """
+    
+    def __init__(self):
+        """ Default class constructor. """
+        
+        wx.PyEvtHandler.__init__(self)
+        self._last_id = 0
+
+
+    def GetCommandId(self):
+        """ Returns the event command identifier. """
+        
+        return self._last_id 
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more suitable
+        event handler function(s).
+
+        :param `event`: the event to process.
+
+        :note: Normally, your application would not call this function: it is called
+         in the wxPython implementation to dispatch incoming user interface events
+         to the framework (and application).
+         However, you might need to call it if implementing new functionality (such as
+         a new control) where you define new event types, as opposed to allowing the
+         user to override functions.
+
+         An instance where you might actually override the L{ProcessEvent} function is where
+         you want to direct event processing to event handlers not normally noticed by
+         wxPython. For example, in the document/view architecture, documents and views
+         are potential event handlers. When an event reaches a frame, L{ProcessEvent} will
+         need to be called on the associated document and view in case event handler
+         functions are associated with these objects. 
+
+         The normal order of event table searching is as follows:
+
+         1. If the object is disabled (via a call to `SetEvtHandlerEnabled`) the function
+            skips to step (6).
+         2. If the object is a `wx.Window`, L{ProcessEvent} is recursively called on the window's 
+            `wx.Validator`. If this returns ``True``, the function exits.
+         3. wxWidgets `SearchEventTable` is called for this event handler. If this fails, the
+            base class table is tried, and so on until no more tables exist or an appropriate
+            function was found, in which case the function exits.
+         4. The search is applied down the entire chain of event handlers (usually the chain
+            has a length of one). If this succeeds, the function exits.
+         5. If the object is a `wx.Window` and the event is a `wx.CommandEvent`, L{ProcessEvent} is
+            recursively applied to the parent window's event handler. If this returns ``True``,
+            the function exits.
+         6. Finally, L{ProcessEvent} is called on the `wx.App` object.
+        """
+        
+        if event.GetEventType() == wx.wxEVT_COMMAND_MENU_SELECTED:
+            self._last_id = event.GetId()
+            return True
+        
+        if self.GetNextHandler():
+            return self.GetNextHandler().ProcessEvent(event)
+
+        return False
+
+
+# ----------------------------------------------------------------------
+
+class AuiToolBarItem(object):
+    """
+    AuiToolBarItem is a toolbar element.
+    
+    It has a unique id (except for the separators which always have id = -1), the
+    style (telling whether it is a normal button, separator or a control), the
+    state (toggled or not, enabled or not) and short and long help strings. The
+    default implementations use the short help string for the tooltip text which
+    is popped up when the mouse pointer enters the tool and the long help string
+    for the applications status bar.
+    """
+
+    def __init__(self, item=None):
+        """
+        Default class constructor.
+
+        :param `item`: another instance of L{AuiToolBarItem}.
+        """
+
+        if item:
+            self.Assign(item)
+            return
+        
+        self.window = None
+        self.clockwisebmp = wx.NullBitmap
+        self.counterclockwisebmp = wx.NullBitmap
+        self.clockwisedisbmp = wx.NullBitmap
+        self.counterclockwisedisbmp = wx.NullBitmap
+        self.sizer_item = None
+        self.spacer_pixels = 0
+        self.id = 0
+        self.kind = ITEM_NORMAL
+        self.state = 0   # normal, enabled
+        self.proportion = 0
+        self.active = True
+        self.dropdown = True
+        self.sticky = True
+        self.user_data = 0
+
+        self.label = ""
+        self.bitmap = wx.NullBitmap
+        self.disabled_bitmap = wx.NullBitmap
+        self.hover_bitmap = wx.NullBitmap
+        self.short_help = ""
+        self.long_help = ""
+        self.min_size = wx.Size(-1, -1)
+        self.alignment = wx.ALIGN_CENTER
+        self.orientation = AUI_TBTOOL_HORIZONTAL
+        
+
+    def Assign(self, c):
+        """
+        Assigns the properties of the L{AuiToolBarItem} `c` to `self`.
+
+        :param `c`: another instance of L{AuiToolBarItem}.
+        """
+
+        self.window = c.window
+        self.label = c.label
+        self.bitmap = c.bitmap
+        self.disabled_bitmap = c.disabled_bitmap
+        self.hover_bitmap = c.hover_bitmap
+        self.short_help = c.short_help
+        self.long_help = c.long_help
+        self.sizer_item = c.sizer_item
+        self.min_size = c.min_size
+        self.spacer_pixels = c.spacer_pixels
+        self.id = c.id
+        self.kind = c.kind
+        self.state = c.state
+        self.proportion = c.proportion
+        self.active = c.active
+        self.dropdown = c.dropdown
+        self.sticky = c.sticky
+        self.user_data = c.user_data
+        self.alignment = c.alignment
+        self.orientation = c.orientation
+
+
+    def SetWindow(self, w):
+        """
+        Assigns a window to the toolbar item.
+
+        :param `w`: an instance of `wx.Window`.
+        """
+
+        self.window = w
+
+        
+    def GetWindow(self):
+        """ Returns window associated to the toolbar item. """
+
+        return self.window        
+
+
+    def SetId(self, new_id):
+        """
+        Sets the toolbar item identifier.
+
+        :param `new_id`: the new tool id.
+        """
+
+        self.id = new_id
+
+        
+    def GetId(self):
+        """ Returns the toolbar item identifier. """
+
+        return self.id 
+
+
+    def SetKind(self, new_kind):
+        """
+        Sets the L{AuiToolBarItem} kind.
+
+        :param `new_kind`: can be one of the following items:
+
+         ========================  =============================
+         Item Kind                 Description
+         ========================  =============================
+         ``ITEM_CONTROL``          The item in the `AuiToolBar` is a control
+         ``ITEM_LABEL``            The item in the `AuiToolBar` is a text label
+         ``ITEM_SPACER``           The item in the `AuiToolBar` is a spacer
+         ``ITEM_SEPARATOR``        The item in the `AuiToolBar` is a separator
+         ``ITEM_CHECK``            The item in the `AuiToolBar` is a toolbar check item
+         ``ITEM_NORMAL``           The item in the `AuiToolBar` is a standard toolbar item
+         ``ITEM_RADIO``            The item in the `AuiToolBar` is a toolbar radio item
+         ========================  =============================
+        """
+
+        self.kind = new_kind
+
+
+    def GetKind(self):
+        """ Returns the toolbar item kind. See L{SetKind} for more details. """
+
+        return self.kind
+        
+
+    def SetState(self, new_state):
+        """
+        Sets the toolbar item state.
+
+        :param `new_state`: can be one of the following states:
+
+         ============================================  ======================================
+         Button State Constant                         Description     
+         ============================================  ======================================
+         ``AUI_BUTTON_STATE_NORMAL``                   Normal button state
+         ``AUI_BUTTON_STATE_HOVER``                    Hovered button state
+         ``AUI_BUTTON_STATE_PRESSED``                  Pressed button state
+         ``AUI_BUTTON_STATE_DISABLED``                 Disabled button state
+         ``AUI_BUTTON_STATE_HIDDEN``                   Hidden button state
+         ``AUI_BUTTON_STATE_CHECKED``                  Checked button state
+         ============================================  ======================================
+    
+        """
+
+        self.state = new_state
+
+        
+    def GetState(self):
+        """
+        Returns the toolbar item state. See L{SetState} for more details.
+
+        :see: L{SetState}
+        """
+        
+        return self.state 
+
+
+    def SetSizerItem(self, s):
+        """
+        Associates a sizer item to this toolbar item.
+
+        :param `s`: an instance of `wx.SizerItem`.
+        """
+
+        self.sizer_item = s
+
+        
+    def GetSizerItem(self):
+        """ Returns the associated sizer item. """
+
+        return self.sizer_item 
+
+
+    def SetLabel(self, s):
+        """
+        Sets the toolbar item label.
+
+        :param `s`: a string specifying the toolbar item label.
+        """
+
+        self.label = s
+
+        
+    def GetLabel(self):
+        """ Returns the toolbar item label. """
+
+        return self.label 
+
+
+    def SetBitmap(self, bmp):
+        """
+        Sets the toolbar item bitmap.
+
+        :param `bmp`: an instance of `wx.Bitmap`.
+        """
+        
+        self.bitmap = bmp
+
+        
+    def GetBitmap(self):
+        """ Returns the toolbar item bitmap. """
+
+        return self.GetRotatedBitmap(False)
+
+
+    def SetDisabledBitmap(self, bmp):
+        """
+        Sets the toolbar item disabled bitmap.
+
+        :param `bmp`: an instance of `wx.Bitmap`.
+        """
+        
+        self.disabled_bitmap = bmp
+
+        
+    def GetDisabledBitmap(self):
+        """ Returns the toolbar item disabled bitmap. """
+        
+        return self.GetRotatedBitmap(True)
+
+
+    def SetHoverBitmap(self, bmp):
+        """
+        Sets the toolbar item hover bitmap.
+
+        :param `bmp`: an instance of `wx.Bitmap`.
+        """
+        
+        self.hover_bitmap = bmp
+
+
+    def SetOrientation(self, a):
+        """
+        Sets the toolbar tool orientation.
+
+        :param `a`: one of ``AUI_TBTOOL_HORIZONTAL``, ``AUI_TBTOOL_VERT_CLOCKWISE`` or
+         ``AUI_TBTOOL_VERT_COUNTERCLOCKWISE``.
+        """
+
+        self.orientation = a
+
+
+    def GetOrientation(self):
+        """ Returns the toolbar tool orientation. """
+
+        return self.orientation
+    
+        
+    def GetHoverBitmap(self):
+        """ Returns the toolbar item hover bitmap. """
+        
+        return self.hover_bitmap 
+
+
+    def GetRotatedBitmap(self, disabled):
+        """
+        Returns the correct bitmap depending on the tool orientation.
+
+        :param `disabled`: whether to return the disabled bitmap or not.
+        """
+        
+        bitmap_to_rotate = (disabled and [self.disabled_bitmap] or [self.bitmap])[0]
+        if not bitmap_to_rotate.IsOk() or self.orientation == AUI_TBTOOL_HORIZONTAL:
+            return bitmap_to_rotate
+
+        rotated_bitmap = wx.NullBitmap
+        clockwise = True
+        if self.orientation == AUI_TBTOOL_VERT_CLOCKWISE:
+            rotated_bitmap = (disabled and [self.clockwisedisbmp] or [self.clockwisebmp])[0]
+
+        elif self.orientation == AUI_TBTOOL_VERT_COUNTERCLOCKWISE:
+            rotated_bitmap = (disabled and [self.counterclockwisedisbmp] or [self.counterclockwisebmp])[0]
+            clockwise = False
+
+        if not rotated_bitmap.IsOk():
+            rotated_bitmap = wx.BitmapFromImage(bitmap_to_rotate.ConvertToImage().Rotate90(clockwise))
+
+        return rotated_bitmap
+
+
+    def SetShortHelp(self, s):
+        """
+        Sets the short help string for the L{AuiToolBarItem}, to be displayed in a
+        `wx.ToolTip` when the mouse hover over the toolbar item.
+
+        :param `s`: the tool short help string.
+        """
+
+        self.short_help = s
+
+        
+    def GetShortHelp(self):
+        """ Returns the short help string for the L{AuiToolBarItem}. """
+
+        return self.short_help 
+
+
+    def SetLongHelp(self, s):
+        """
+        Sets the long help string for the toolbar item. This string is shown in the
+        statusbar (if any) of the parent frame when the mouse pointer is inside the
+        tool.
+
+        :param `s`: the tool long help string.
+        """
+
+        self.long_help = s
+
+        
+    def GetLongHelp(self):
+        """ Returns the long help string for the L{AuiToolBarItem}. """
+
+        return self.long_help 
+
+
+    def SetMinSize(self, s):
+        """
+        Sets the toolbar item minimum size.
+
+        :param `s`: an instance of `wx.Size`.
+        """
+
+        self.min_size = wx.Size(*s)
+
+        
+    def GetMinSize(self):
+        """ Returns the toolbar item minimum size. """
+
+        return self.min_size 
+
+
+    def SetSpacerPixels(self, s):
+        """
+        Sets the number of pixels for a toolbar item with kind = ``ITEM_SEPARATOR``.
+
+        :param `s`: number of pixels.
+        """
+
+        self.spacer_pixels = s
+
+        
+    def GetSpacerPixels(self):
+        """ Returns the number of pixels for a toolbar item with kind = ``ITEM_SEPARATOR``. """
+
+        return self.spacer_pixels 
+
+
+    def SetProportion(self, p):
+        """
+        Sets the L{AuiToolBarItem} proportion in the toolbar.
+
+        :param `p`: the item proportion.
+        """
+
+        self.proportion = p
+
+        
+    def GetProportion(self):
+        """ Returns the L{AuiToolBarItem} proportion in the toolbar. """
+
+        return self.proportion 
+
+
+    def SetActive(self, b):
+        """
+        Activates/deactivates the toolbar item.
+
+        :param `b`: ``True`` to activate the item, ``False`` to deactivate it.
+        """
+
+        self.active = b
+
+        
+    def IsActive(self):
+        """ Returns whether the toolbar item is active or not. """
+
+        return self.active
+    
+
+    def SetHasDropDown(self, b):
+        """
+        Sets whether the toolbar item has an associated dropdown menu.
+
+        :param `b`: ``True`` to set a dropdown menu, ``False`` otherwise.
+        """
+
+        self.dropdown = b
+
+        
+    def HasDropDown(self):
+        """ Returns whether the toolbar item has an associated dropdown menu or not. """
+
+        return self.dropdown 
+
+
+    def SetSticky(self, b):
+        """
+        Sets whether the toolbar item is sticky (permanent highlight after mouse enter)
+        or not.
+
+        :param `b`: ``True`` to set the item as sticky, ``False`` otherwise.
+        """
+
+        self.sticky = b
+
+        
+    def IsSticky(self):
+        """ Returns whether the toolbar item has a sticky behaviour or not. """
+
+        return self.sticky 
+
+
+    def SetUserData(self, l):
+        """
+        Associates some kind of user data to the toolbar item.
+        
+        :param `l`: a Python object.
+
+        :note: The user data can be any Python object.
+        """
+
+        self.user_data = l
+
+        
+    def GetUserData(self):
+        """ Returns the associated user data. """
+
+        return self.user_data
+    
+
+    def SetAlignment(self, l):
+        """
+        Sets the toolbar item alignment.
+
+        :param `l`: the item alignment, which can be one of the available `wx.Sizer`
+         alignments.
+        """
+
+        self.alignment = l
+
+        
+    def GetAlignment(self):
+        """ Returns the toolbar item alignment. """
+
+        return self.alignment        
+
+
+# ----------------------------------------------------------------------
+
+class AuiDefaultToolBarArt(object):
+    """
+    Toolbar art provider code - a tab provider provides all drawing functionality to
+    the L{AuiToolBar}. This allows the L{AuiToolBar} to have a plugable look-and-feel.
+
+    By default, a L{AuiToolBar} uses an instance of this class called L{AuiDefaultToolBarArt}
+    which provides bitmap art and a colour scheme that is adapted to the major platforms'
+    look. You can either derive from that class to alter its behaviour or write a
+    completely new tab art class. Call L{AuiToolBar.SetArtProvider} to make use this
+    new tab art.
+    """
+
+    def __init__(self):
+        """ Default class constructor. """
+        
+        self._base_colour = GetBaseColour()
+
+        self._agwFlags = 0
+        self._text_orientation = AUI_TBTOOL_TEXT_BOTTOM
+        self._highlight_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+
+        self._separator_size = 7
+        self._orientation = AUI_TBTOOL_HORIZONTAL
+        self._gripper_size = 7
+        self._overflow_size = 16
+
+        darker1_colour = StepColour(self._base_colour, 85)
+        darker2_colour = StepColour(self._base_colour, 75)
+        darker3_colour = StepColour(self._base_colour, 60)
+        darker4_colour = StepColour(self._base_colour, 50)
+        darker5_colour = StepColour(self._base_colour, 40)
+
+        self._gripper_pen1 = wx.Pen(darker5_colour)
+        self._gripper_pen2 = wx.Pen(darker3_colour)
+        self._gripper_pen3 = wx.WHITE_PEN
+
+        button_dropdown_bits = "\xe0\xf1\xfb"
+        overflow_bits = "\x80\xff\x80\xc1\xe3\xf7"
+
+        self._button_dropdown_bmp = BitmapFromBits(button_dropdown_bits, 5, 3, wx.BLACK)
+        self._disabled_button_dropdown_bmp = BitmapFromBits(button_dropdown_bits, 5, 3,
+                                                            wx.Colour(128, 128, 128))
+        self._overflow_bmp = BitmapFromBits(overflow_bits, 7, 6, wx.BLACK)
+        self._disabled_overflow_bmp = BitmapFromBits(overflow_bits, 7, 6, wx.Colour(128, 128, 128))
+
+        self._font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+
+
+    def Clone(self):
+        """ Clones the L{AuiToolBar} art. """
+
+        return AuiDefaultToolBarArt()
+
+
+    def SetAGWFlags(self, agwFlags):
+        """
+        Sets the toolbar art flags.
+
+        :param `agwFlags`: a combination of the following values:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_TB_TEXT``                      Shows the text in the toolbar buttons; by default only icons are shown
+         ``AUI_TB_NO_TOOLTIPS``               Don't show tooltips on `AuiToolBar` items
+         ``AUI_TB_NO_AUTORESIZE``             Do not auto-resize the `AuiToolBar`
+         ``AUI_TB_GRIPPER``                   Shows a gripper on the `AuiToolBar`
+         ``AUI_TB_OVERFLOW``                  The `AuiToolBar` can contain overflow items
+         ``AUI_TB_VERTICAL``                  The `AuiToolBar` is vertical
+         ``AUI_TB_HORZ_LAYOUT``               Shows the text and the icons alongside, not vertically stacked. This style must be used with ``AUI_TB_TEXT``
+         ``AUI_TB_PLAIN_BACKGROUND``          Don't draw a gradient background on the toolbar
+         ``AUI_TB_HORZ_TEXT``                 Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``
+         ==================================== ==================================
+        
+        """
+        
+        self._agwFlags = agwFlags
+
+
+    def GetAGWFlags(self):
+        """
+        Returns the L{AuiDefaultToolBarArt} flags. See L{SetAGWFlags} for more
+        details.
+
+        :see: L{SetAGWFlags}
+        """
+
+        return self._agwFlags
+
+
+    def SetFont(self, font):
+        """
+        Sets the L{AuiDefaultToolBarArt} font.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._font = font
+
+
+    def SetTextOrientation(self, orientation):
+        """
+        Sets the text orientation.
+
+        :param `orientation`: can be one of the following constants:
+
+         ==================================== ==================================
+         Orientation Switches                 Description
+         ==================================== ==================================
+         ``AUI_TBTOOL_TEXT_LEFT``             Text in `AuiToolBar` items is aligned left
+         ``AUI_TBTOOL_TEXT_RIGHT``            Text in `AuiToolBar` items is aligned right
+         ``AUI_TBTOOL_TEXT_TOP``              Text in `AuiToolBar` items is aligned top
+         ``AUI_TBTOOL_TEXT_BOTTOM``           Text in `AuiToolBar` items is aligned bottom
+         ==================================== ==================================
+        
+        """
+
+        self._text_orientation = orientation
+
+
+    def GetFont(self):
+        """ Returns the L{AuiDefaultToolBarArt} font. """
+
+        return self._font
+
+
+    def GetTextOrientation(self):
+        """
+        Returns the L{AuiDefaultToolBarArt} text orientation. See
+        L{SetTextOrientation} for more details.
+
+        :see: L{SetTextOrientation}
+        """
+
+        return self._text_orientation
+
+
+    def SetOrientation(self, orientation):
+        """
+        Sets the toolbar tool orientation.
+
+        :param `orientation`: one of ``AUI_TBTOOL_HORIZONTAL``, ``AUI_TBTOOL_VERT_CLOCKWISE`` or
+         ``AUI_TBTOOL_VERT_COUNTERCLOCKWISE``.
+        """
+
+        self._orientation = orientation
+
+
+    def GetOrientation(self):
+        """ Returns the toolbar orientation. """
+
+        return self._orientation        
+
+
+    def DrawBackground(self, dc, wnd, _rect, horizontal=True):
+        """
+        Draws a toolbar background with a gradient shading.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `_rect`: the L{AuiToolBar} rectangle;
+        :param `horizontal`: ``True`` if the toolbar is horizontal, ``False`` if it is vertical.
+        """
+
+        rect = wx.Rect(*_rect)
+
+        start_colour = StepColour(self._base_colour, 180)
+        end_colour = StepColour(self._base_colour, 85)
+        reflex_colour = StepColour(self._base_colour, 95)
+        
+        dc.GradientFillLinear(rect, start_colour, end_colour,
+                              (horizontal and [wx.SOUTH] or [wx.EAST])[0])
+
+        left = rect.GetLeft()
+        right = rect.GetRight()
+        top = rect.GetTop()
+        bottom = rect.GetBottom()
+
+        dc.SetPen(wx.Pen(reflex_colour))
+        if horizontal:
+            dc.DrawLine(left, bottom, right+1, bottom)
+        else:
+            dc.DrawLine(right, top, right, bottom+1)
+            
+
+    def DrawPlainBackground(self, dc, wnd, _rect):
+        """
+        Draws a toolbar background with a plain colour.
+
+        This method contrasts with the default behaviour of the L{AuiToolBar} that
+        draws a background gradient and this break the window design when putting
+        it within a control that has margin between the borders and the toolbar
+        (example: put L{AuiToolBar} within a `wx.StaticBoxSizer` that has a plain background).
+      
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `_rect`: the L{AuiToolBar} rectangle.
+        """
+        
+        rect = wx.Rect(*_rect)
+        rect.height += 1
+
+        dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
+        dc.DrawRectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 1)
+
+
+    def DrawLabel(self, dc, wnd, item, rect):
+        """
+        Draws a toolbar item label.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `item`: an instance of L{AuiToolBarItem};
+        :param `rect`: the L{AuiToolBarItem} rectangle.
+        """
+        
+        dc.SetFont(self._font)
+        dc.SetTextForeground(wx.BLACK)
+        orient = item.GetOrientation()
+
+        horizontal = orient == AUI_TBTOOL_HORIZONTAL
+        # we only care about the text height here since the text
+        # will get cropped based on the width of the item
+        label_size = GetLabelSize(dc, item.GetLabel(), not horizontal)
+        text_width = label_size.GetWidth()
+        text_height = label_size.GetHeight()
+
+        if orient == AUI_TBTOOL_HORIZONTAL:
+            text_x = rect.x
+            text_y = rect.y + (rect.height-text_height)/2
+            dc.DrawText(item.GetLabel(), text_x, text_y)
+
+        elif orient == AUI_TBTOOL_VERT_CLOCKWISE:
+            text_x = rect.x + (rect.width+text_width)/2
+            text_y = rect.y
+            dc.DrawRotatedText(item.GetLabel(), text_x, text_y, 270)
+
+        elif AUI_TBTOOL_VERT_COUNTERCLOCKWISE:
+            text_x = rect.x + (rect.width-text_width)/2
+            text_y = rect.y + text_height
+            dc.DrawRotatedText(item.GetLabel(), text_x, text_y, 90)
+
+
+    def DrawButton(self, dc, wnd, item, rect):
+        """
+        Draws a toolbar item button.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `item`: an instance of L{AuiToolBarItem};
+        :param `rect`: the L{AuiToolBarItem} rectangle.
+        """
+
+        bmp_rect, text_rect = self.GetToolsPosition(dc, item, rect)
+        
+        if not item.GetState() & AUI_BUTTON_STATE_DISABLED:
+        
+            if item.GetState() & AUI_BUTTON_STATE_PRESSED:
+            
+                dc.SetPen(wx.Pen(self._highlight_colour))
+                dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 150)))
+                dc.DrawRectangleRect(rect)
+            
+            elif item.GetState() & AUI_BUTTON_STATE_HOVER or item.IsSticky():
+            
+                dc.SetPen(wx.Pen(self._highlight_colour))
+                dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
+
+                # draw an even lighter background for checked item hovers (since
+                # the hover background is the same colour as the check background)
+                if item.GetState() & AUI_BUTTON_STATE_CHECKED:
+                    dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 180)))
+
+                dc.DrawRectangleRect(rect)
+            
+            elif item.GetState() & AUI_BUTTON_STATE_CHECKED:
+            
+                # it's important to put this code in an else statment after the
+                # hover, otherwise hovers won't draw properly for checked items
+                dc.SetPen(wx.Pen(self._highlight_colour))
+                dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
+                dc.DrawRectangleRect(rect)
+            
+        if item.GetState() & AUI_BUTTON_STATE_DISABLED:
+            bmp = item.GetDisabledBitmap()
+        else:
+            bmp = item.GetBitmap()
+
+        if bmp.IsOk():
+            dc.DrawBitmap(bmp, bmp_rect.x, bmp_rect.y, True)
+
+        # set the item's text colour based on if it is disabled
+        dc.SetTextForeground(wx.BLACK)
+        if item.GetState() & AUI_BUTTON_STATE_DISABLED:
+            dc.SetTextForeground(DISABLED_TEXT_COLOUR)
+
+        if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "":
+            self.DrawLabel(dc, wnd, item, text_rect)
+        
+
+    def DrawDropDownButton(self, dc, wnd, item, rect):
+        """
+        Draws a toolbar dropdown button.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `item`: an instance of L{AuiToolBarItem};
+        :param `rect`: the L{AuiToolBarItem} rectangle.
+        """
+        
+        dropbmp_x = dropbmp_y = 0
+
+        button_rect = wx.Rect(rect.x, rect.y, rect.width-BUTTON_DROPDOWN_WIDTH, rect.height)
+        dropdown_rect = wx.Rect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, rect.y, BUTTON_DROPDOWN_WIDTH+1, rect.height)
+
+        horizontal = item.GetOrientation() == AUI_TBTOOL_HORIZONTAL
+        
+        if horizontal:
+            button_rect = wx.Rect(rect.x, rect.y, rect.width-BUTTON_DROPDOWN_WIDTH, rect.height)
+            dropdown_rect = wx.Rect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, rect.y, BUTTON_DROPDOWN_WIDTH+1, rect.height)
+        else:
+            button_rect = wx.Rect(rect.x, rect.y, rect.width, rect.height-BUTTON_DROPDOWN_WIDTH)
+            dropdown_rect = wx.Rect(rect.x, rect.y+rect.height-BUTTON_DROPDOWN_WIDTH-1, rect.width, BUTTON_DROPDOWN_WIDTH+1)
+
+        dropbmp_width = self._button_dropdown_bmp.GetWidth()
+        dropbmp_height = self._button_dropdown_bmp.GetHeight()
+        if not horizontal:
+            tmp = dropbmp_width
+            dropbmp_width = dropbmp_height
+            dropbmp_height = tmp
+
+        dropbmp_x = dropdown_rect.x + (dropdown_rect.width/2) - dropbmp_width/2
+        dropbmp_y = dropdown_rect.y + (dropdown_rect.height/2) - dropbmp_height/2
+
+        bmp_rect, text_rect = self.GetToolsPosition(dc, item, button_rect)
+        
+        if item.GetState() & AUI_BUTTON_STATE_PRESSED:
+        
+            dc.SetPen(wx.Pen(self._highlight_colour))
+            dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 140)))
+            dc.DrawRectangleRect(button_rect)
+            dc.DrawRectangleRect(dropdown_rect)
+        
+        elif item.GetState() & AUI_BUTTON_STATE_HOVER or item.IsSticky():
+        
+            dc.SetPen(wx.Pen(self._highlight_colour))
+            dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
+            dc.DrawRectangleRect(button_rect)
+            dc.DrawRectangleRect(dropdown_rect)
+
+        elif item.GetState() & AUI_BUTTON_STATE_CHECKED:
+            # it's important to put this code in an else statment after the 
+            # hover, otherwise hovers won't draw properly for checked items 
+            dc.SetPen(wx.Pen(self._highlight_colour))
+            dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
+            dc.DrawRectangle(button_rect)
+            dc.DrawRectangle(dropdown_rect)
+            
+        if item.GetState() & AUI_BUTTON_STATE_DISABLED:
+        
+            bmp = item.GetDisabledBitmap()
+            dropbmp = self._disabled_button_dropdown_bmp
+        
+        else:
+        
+            bmp = item.GetBitmap()
+            dropbmp = self._button_dropdown_bmp
+        
+        if not bmp.IsOk():
+            return
+
+        dc.DrawBitmap(bmp, bmp_rect.x, bmp_rect.y, True)
+        if horizontal:
+            dc.DrawBitmap(dropbmp, dropbmp_x, dropbmp_y, True)
+        else:
+            dc.DrawBitmap(wx.BitmapFromImage(dropbmp.ConvertToImage().Rotate90(item.GetOrientation() == AUI_TBTOOL_VERT_CLOCKWISE)),
+                          dropbmp_x, dropbmp_y, True)
+            
+        # set the item's text colour based on if it is disabled
+        dc.SetTextForeground(wx.BLACK)
+        if item.GetState() & AUI_BUTTON_STATE_DISABLED:
+            dc.SetTextForeground(DISABLED_TEXT_COLOUR)
+
+        if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "":  
+            self.DrawLabel(dc, wnd, item, text_rect)
+        
+
+    def DrawControlLabel(self, dc, wnd, item, rect):
+        """
+        Draws a label for a toolbar control.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `item`: an instance of L{AuiToolBarItem};
+        :param `rect`: the L{AuiToolBarItem} rectangle.
+        """
+
+        label_size = GetLabelSize(dc, item.GetLabel(), item.GetOrientation() != AUI_TBTOOL_HORIZONTAL)
+        text_height = label_size.GetHeight()
+        text_width = label_size.GetWidth()
+
+        dc.SetFont(self._font)
+
+        if self._agwFlags & AUI_TB_TEXT:
+        
+            tx, text_height = dc.GetTextExtent("ABCDHgj")        
+
+        text_width, ty = dc.GetTextExtent(item.GetLabel())
+
+        # don't draw the label if it is wider than the item width
+        if text_width > rect.width:
+            return
+
+        # set the label's text colour
+        dc.SetTextForeground(wx.BLACK)
+
+        text_x = rect.x + (rect.width/2) - (text_width/2) + 1
+        text_y = rect.y + rect.height - text_height - 1
+
+        if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "": 
+            dc.DrawText(item.GetLabel(), text_x, text_y)
+    
+
+    def GetLabelSize(self, dc, wnd, item):
+        """
+        Returns the label size for a toolbar item.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `item`: an instance of L{AuiToolBarItem}.
+        """
+
+        dc.SetFont(self._font)
+        label_size = GetLabelSize(dc, item.GetLabel(), self._orientation != AUI_TBTOOL_HORIZONTAL)
+
+        return wx.Size(item.GetMinSize().GetWidth(), label_size.GetHeight())
+
+
+    def GetToolSize(self, dc, wnd, item):
+        """
+        Returns the toolbar item size.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `item`: an instance of L{AuiToolBarItem}.
+        """
+        
+        if not item.GetBitmap().IsOk() and not self._agwFlags & AUI_TB_TEXT:
+            return wx.Size(16, 16)
+
+        width = item.GetBitmap().GetWidth()
+        height = item.GetBitmap().GetHeight()
+
+        if self._agwFlags & AUI_TB_TEXT:
+        
+            dc.SetFont(self._font)
+            label_size = GetLabelSize(dc, item.GetLabel(), self.GetOrientation() != AUI_TBTOOL_HORIZONTAL)
+            padding = 6
+            
+            if self._text_orientation == AUI_TBTOOL_TEXT_BOTTOM:
+            
+                if self.GetOrientation() != AUI_TBTOOL_HORIZONTAL:
+                    height += 3   # space between top border and bitmap
+                    height += 3   # space between bitmap and text
+                    padding = 0
+
+                height += label_size.GetHeight()
+            
+                if item.GetLabel() != "":
+                    width = max(width, label_size.GetWidth()+padding)
+                
+            elif self._text_orientation == AUI_TBTOOL_TEXT_RIGHT and item.GetLabel() != "":
+            
+                if self.GetOrientation() == AUI_TBTOOL_HORIZONTAL:
+                    
+                    width += 3  # space between left border and bitmap
+                    width += 3  # space between bitmap and text
+                    padding = 0
+
+                width += label_size.GetWidth()
+                height = max(height, label_size.GetHeight()+padding)
+                
+        # if the tool has a dropdown button, add it to the width
+        if item.HasDropDown():
+            if item.GetOrientation() == AUI_TBTOOL_HORIZONTAL:
+                width += BUTTON_DROPDOWN_WIDTH+4
+            else:
+                height += BUTTON_DROPDOWN_WIDTH+4
+
+        return wx.Size(width, height)
+
+
+    def DrawSeparator(self, dc, wnd, _rect):
+        """
+        Draws a toolbar separator.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `_rect`: the L{AuiToolBarItem} rectangle.
+        """
+        
+        horizontal = True
+        if self._agwFlags & AUI_TB_VERTICAL:
+            horizontal = False
+
+        rect = wx.Rect(*_rect)
+
+        if horizontal:
+        
+            rect.x += (rect.width/2)
+            rect.width = 1
+            new_height = (rect.height*3)/4
+            rect.y += (rect.height/2) - (new_height/2)
+            rect.height = new_height
+        
+        else:
+        
+            rect.y += (rect.height/2)
+            rect.height = 1
+            new_width = (rect.width*3)/4
+            rect.x += (rect.width/2) - (new_width/2)
+            rect.width = new_width
+        
+        start_colour = StepColour(self._base_colour, 80)
+        end_colour = StepColour(self._base_colour, 80)
+        dc.GradientFillLinear(rect, start_colour, end_colour, (horizontal and [wx.SOUTH] or [wx.EAST])[0])
+
+
+    def DrawGripper(self, dc, wnd, rect):
+        """
+        Draws the toolbar gripper.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `rect`: the L{AuiToolBar} rectangle.
+        """
+        
+        i = 0
+        while 1:
+        
+            if self._agwFlags & AUI_TB_VERTICAL:
+            
+                x = rect.x + (i*4) + 4
+                y = rect.y + 3
+                if x > rect.GetWidth() - 4:
+                    break
+            
+            else:
+            
+                x = rect.x + 3
+                y = rect.y + (i*4) + 4
+                if y > rect.GetHeight() - 4:
+                    break
+            
+            dc.SetPen(self._gripper_pen1)
+            dc.DrawPoint(x, y)
+            dc.SetPen(self._gripper_pen2)
+            dc.DrawPoint(x, y+1)
+            dc.DrawPoint(x+1, y)
+            dc.SetPen(self._gripper_pen3)
+            dc.DrawPoint(x+2, y+1)
+            dc.DrawPoint(x+2, y+2)
+            dc.DrawPoint(x+1, y+2)
+
+            i += 1
+
+
+    def DrawOverflowButton(self, dc, wnd, rect, state):
+        """
+        Draws the overflow button for the L{AuiToolBar}.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` derived window;
+        :param `rect`: the L{AuiToolBar} rectangle;
+        :param `state`: the overflow button state.
+        """
+        
+        if state & AUI_BUTTON_STATE_HOVER or  state & AUI_BUTTON_STATE_PRESSED:
+        
+            cli_rect = wnd.GetClientRect()
+            light_gray_bg = StepColour(self._highlight_colour, 170)
+
+            if self._agwFlags & AUI_TB_VERTICAL:
+            
+                dc.SetPen(wx.Pen(self._highlight_colour))
+                dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y)
+                dc.SetPen(wx.Pen(light_gray_bg))
+                dc.SetBrush(wx.Brush(light_gray_bg))
+                dc.DrawRectangle(rect.x, rect.y+1, rect.width, rect.height)
+            
+            else:
+            
+                dc.SetPen(wx.Pen(self._highlight_colour))
+                dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height)
+                dc.SetPen(wx.Pen(light_gray_bg))
+                dc.SetBrush(wx.Brush(light_gray_bg))
+                dc.DrawRectangle(rect.x+1, rect.y, rect.width, rect.height)
+            
+        x = rect.x + 1 + (rect.width-self._overflow_bmp.GetWidth())/2
+        y = rect.y + 1 + (rect.height-self._overflow_bmp.GetHeight())/2
+        dc.DrawBitmap(self._overflow_bmp, x, y, True)
+
+
+    def GetElementSize(self, element_id):
+        """
+        Returns the size of a UI element in the L{AuiToolBar}.
+
+        :param `element_id`: can be one of the following:
+
+         ==================================== ==================================
+         Element Identifier                   Description
+         ==================================== ==================================
+         ``AUI_TBART_SEPARATOR_SIZE``         Separator size in `AuiToolBar`
+         ``AUI_TBART_GRIPPER_SIZE``           Gripper size in `AuiToolBar`
+         ``AUI_TBART_OVERFLOW_SIZE``          Overflow button size in `AuiToolBar`
+         ==================================== ==================================        
+        """
+        
+        if element_id == AUI_TBART_SEPARATOR_SIZE:
+            return self._separator_size
+        elif element_id == AUI_TBART_GRIPPER_SIZE:
+            return self._gripper_size
+        elif element_id == AUI_TBART_OVERFLOW_SIZE:
+            return self._overflow_size
+
+        return 0
+
+
+    def SetElementSize(self, element_id, size):
+        """
+        Sets the size of a UI element in the L{AuiToolBar}.
+
+        :param `element_id`: can be one of the following:
+
+         ==================================== ==================================
+         Element Identifier                   Description
+         ==================================== ==================================
+         ``AUI_TBART_SEPARATOR_SIZE``         Separator size in `AuiToolBar`
+         ``AUI_TBART_GRIPPER_SIZE``           Gripper size in `AuiToolBar`
+         ``AUI_TBART_OVERFLOW_SIZE``          Overflow button size in `AuiToolBar`
+         ==================================== ==================================
+
+        :param `size`: the new size of the UI element.        
+        """
+        
+        if element_id == AUI_TBART_SEPARATOR_SIZE:
+            self._separator_size = size
+        elif element_id == AUI_TBART_GRIPPER_SIZE:
+            self._gripper_size = size
+        elif element_id == AUI_TBART_OVERFLOW_SIZE:
+            self._overflow_size = size
+
+
+    def ShowDropDown(self, wnd, items):
+        """
+        Shows the drop down window menu for overflow items.
+
+        :param `wnd`: an instance of `wx.Window`;
+        :param `items`: the overflow toolbar items (a Python list).
+        """
+
+        menuPopup = wx.Menu()
+        items_added = 0
+
+        for item in items:
+
+            if item.GetKind() not in [ITEM_SEPARATOR, ITEM_SPACER, ITEM_CONTROL]:
+            
+                text = item.GetShortHelp()
+                if text == "":
+                    text = item.GetLabel()
+                if text == "":
+                    text = " "
+
+                kind = item.GetKind()
+                m = wx.MenuItem(menuPopup, item.GetId(), text, item.GetShortHelp(), kind)
+                orientation = item.GetOrientation()
+                item.SetOrientation(AUI_TBTOOL_HORIZONTAL)
+                
+                if kind not in [ITEM_CHECK, ITEM_RADIO]:
+                    m.SetBitmap(item.GetBitmap())
+
+                item.SetOrientation(orientation)                    
+                    
+                menuPopup.AppendItem(m)
+                if kind in [ITEM_CHECK, ITEM_RADIO]:            
+                    state = (item.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
+                    m.Check(state)
+
+                items_added += 1
+            
+            else:
+            
+                if items_added > 0 and item.GetKind() == ITEM_SEPARATOR:
+                    menuPopup.AppendSeparator()
+            
+        # find out where to put the popup menu of window items
+        pt = wx.GetMousePosition()
+        pt = wnd.ScreenToClient(pt)
+
+        # find out the screen coordinate at the bottom of the tab ctrl
+        cli_rect = wnd.GetClientRect()
+        pt.y = cli_rect.y + cli_rect.height
+
+        cc = ToolbarCommandCapture()
+        wnd.PushEventHandler(cc)
+
+        # Adjustments to get slightly better menu placement
+        if wx.Platform == "__WXMAC__":
+            pt.y += 5
+            pt.x -= 5
+
+        wnd.PopupMenu(menuPopup, pt)
+        command = cc.GetCommandId()
+        wnd.PopEventHandler(True)
+
+        return command
+
+
+    def GetToolsPosition(self, dc, item, rect):
+        """
+        Returns the bitmap and text rectangles for a toolbar item.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `item`: an instance of L{AuiToolBarItem};
+        :param `rect`: the tool rect.
+        """
+        
+        text_width = text_height = 0
+        horizontal = self._orientation == AUI_TBTOOL_HORIZONTAL
+        text_bottom = self._text_orientation == AUI_TBTOOL_TEXT_BOTTOM
+        text_right = self._text_orientation == AUI_TBTOOL_TEXT_RIGHT
+        bmp_width = item.GetBitmap().GetWidth()
+        bmp_height = item.GetBitmap().GetHeight()
+     
+        if self._agwFlags & AUI_TB_TEXT:        
+            dc.SetFont(self._font)
+            label_size = GetLabelSize(dc, item.GetLabel(), not horizontal)
+            text_height = label_size.GetHeight()
+            text_width = label_size.GetWidth()
+        
+        bmp_x = bmp_y = text_x = text_y = 0
+
+        if horizontal and text_bottom:
+            bmp_x = rect.x + (rect.width/2) - (bmp_width/2)
+            bmp_y = rect.y + 3
+            text_x = rect.x + (rect.width/2) - (text_width/2)
+            text_y = rect.y + ((bmp_y - rect.y) * 2) + bmp_height
+        
+        elif horizontal and text_right:
+            bmp_x = rect.x + 3
+            bmp_y = rect.y + (rect.height/2) - (bmp_height / 2)
+            text_x = rect.x + ((bmp_x - rect.x) * 2) + bmp_width
+            text_y = rect.y + (rect.height/2) - (text_height/2)
+        
+        elif not horizontal and text_bottom:
+            bmp_x = rect.x + (rect.width / 2) - (bmp_width / 2)
+            bmp_y = rect.y + 3
+            text_x = rect.x + (rect.width / 2) - (text_width / 2)
+            text_y = rect.y + ((bmp_y - rect.y) * 2) + bmp_height
+        
+        bmp_rect = wx.Rect(bmp_x, bmp_y, bmp_width, bmp_height)
+        text_rect = wx.Rect(text_x, text_y, text_width, text_height)
+
+        return bmp_rect, text_rect
+
+    
+class AuiToolBar(wx.PyControl):
+    """
+    AuiToolBar is a completely owner-drawn toolbar perfectly integrated with the
+    AUI layout system. This allows drag and drop of toolbars, docking/floating
+    behaviour and the possibility to define "overflow" items in the toolbar itself.
+
+    The default theme that is used is L{AuiDefaultToolBarArt}, which provides a modern,
+    glossy look and feel. The theme can be changed by calling L{AuiToolBar.SetArtProvider}.
+    """
+
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=0, agwStyle=AUI_TB_DEFAULT_STYLE):
+        """
+        Default class constructor.
+
+        :param `parent`: the L{AuiToolBar} parent;
+        :param `id`: an identifier for the control: a value of -1 is taken to mean a default;
+        :param `pos`: the control position. A value of (-1, -1) indicates a default position,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `size`: the control size. A value of (-1, -1) indicates a default size,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `style`: the control window style;
+        :param `agwStyle`: the AGW-specific window style. This can be a combination of the
+         following bits:
+        
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_TB_TEXT``                      Shows the text in the toolbar buttons; by default only icons are shown
+         ``AUI_TB_NO_TOOLTIPS``               Don't show tooltips on `AuiToolBar` items
+         ``AUI_TB_NO_AUTORESIZE``             Do not auto-resize the `AuiToolBar`
+         ``AUI_TB_GRIPPER``                   Shows a gripper on the `AuiToolBar`
+         ``AUI_TB_OVERFLOW``                  The `AuiToolBar` can contain overflow items
+         ``AUI_TB_VERTICAL``                  The `AuiToolBar` is vertical
+         ``AUI_TB_HORZ_LAYOUT``               Shows the text and the icons alongside, not vertically stacked. This style must be used with ``AUI_TB_TEXT``
+         ``AUI_TB_PLAIN_BACKGROUND``          Don't draw a gradient background on the toolbar
+         ``AUI_TB_HORZ_TEXT``                 Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``
+         ==================================== ==================================
+
+         The default value for `agwStyle` is: ``AUI_TB_DEFAULT_STYLE`` = 0
+
+        """
+        
+        wx.PyControl.__init__(self, parent, id, pos, size, style|wx.BORDER_NONE)
+
+        self._sizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.SetSizer(self._sizer)
+        self._button_width = -1
+        self._button_height = -1
+        self._sizer_element_count = 0
+        self._action_pos = wx.Point(-1, -1)
+        self._action_item = None
+        self._tip_item = None
+        self._art = AuiDefaultToolBarArt()
+        self._tool_packing = 2
+        self._tool_border_padding = 3
+        self._tool_text_orientation = AUI_TBTOOL_TEXT_BOTTOM
+        self._tool_orientation = AUI_TBTOOL_HORIZONTAL
+        self._tool_alignment = wx.EXPAND
+        self._gripper_sizer_item = None
+        self._overflow_sizer_item = None
+        self._dragging = False
+
+        self._agwStyle = self._originalStyle = agwStyle
+
+        self._gripper_visible = (self._agwStyle & AUI_TB_GRIPPER and [True] or [False])[0]
+        self._overflow_visible = (self._agwStyle & AUI_TB_OVERFLOW and [True] or [False])[0]
+        self._overflow_state = 0
+        self._custom_overflow_prepend = []
+        self._custom_overflow_append = []
+
+        self._items = []
+        
+        self.SetMargins(5, 5, 2, 2)
+        self.SetFont(wx.NORMAL_FONT)
+        self._art.SetAGWFlags(self._agwStyle)
+        self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE)
+        
+        if agwStyle & AUI_TB_HORZ_LAYOUT:
+            self.SetToolTextOrientation(AUI_TBTOOL_TEXT_RIGHT)
+        elif agwStyle & AUI_TB_VERTICAL:
+            if agwStyle & AUI_TB_CLOCKWISE:
+                self.SetToolOrientation(AUI_TBTOOL_VERT_CLOCKWISE)
+            elif agwStyle & AUI_TB_COUNTERCLOCKWISE:
+                self.SetToolOrientation(AUI_TBTOOL_VERT_COUNTERCLOCKWISE)
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown)
+        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
+        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+        self.Bind(wx.EVT_RIGHT_DCLICK, self.OnRightDown)
+        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
+        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
+        self.Bind(wx.EVT_MIDDLE_DCLICK, self.OnMiddleDown)
+        self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)
+        self.Bind(wx.EVT_MOTION, self.OnMotion)
+        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
+        self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor)
+
+
+    def SetWindowStyleFlag(self, style):
+        """
+        Sets the style of the window.
+        
+        :param `style`: the new window style. 
+
+        :note: Please note that some styles cannot be changed after the window
+         creation and that `Refresh` might need to be be called after changing the
+         others for the change to take place immediately.
+
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        wx.PyControl.SetWindowStyleFlag(self, style|wx.BORDER_NONE)
+        
+
+    def SetAGWWindowStyleFlag(self, agwStyle):
+        """
+        Sets the AGW-specific style of the window.
+        
+        :param `agwStyle`: the new window style. This can be a combination of the
+         following bits:
+        
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_TB_TEXT``                      Shows the text in the toolbar buttons; by default only icons are shown
+         ``AUI_TB_NO_TOOLTIPS``               Don't show tooltips on `AuiToolBar` items
+         ``AUI_TB_NO_AUTORESIZE``             Do not auto-resize the `AuiToolBar`
+         ``AUI_TB_GRIPPER``                   Shows a gripper on the `AuiToolBar`
+         ``AUI_TB_OVERFLOW``                  The `AuiToolBar` can contain overflow items
+         ``AUI_TB_VERTICAL``                  The `AuiToolBar` is vertical
+         ``AUI_TB_HORZ_LAYOUT``               Shows the text and the icons alongside, not vertically stacked. This style must be used with ``AUI_TB_TEXT``
+         ``AUI_TB_PLAIN_BACKGROUND``          Don't draw a gradient background on the toolbar
+         ``AUI_TB_HORZ_TEXT``                 Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``
+         ==================================== ==================================
+
+        :note: Please note that some styles cannot be changed after the window
+         creation and that `Refresh` might need to be be called after changing the
+         others for the change to take place immediately.
+        """
+        
+        self._agwStyle = self._originalStyle = agwStyle
+
+        if self._art:
+            self._art.SetAGWFlags(self._agwStyle)
+        
+        if agwStyle & AUI_TB_GRIPPER:
+            self._gripper_visible = True
+        else:
+            self._gripper_visible = False
+
+        if agwStyle & AUI_TB_OVERFLOW:
+            self._overflow_visible = True
+        else:
+            self._overflow_visible = False
+
+        if agwStyle & AUI_TB_HORZ_LAYOUT:
+            self.SetToolTextOrientation(AUI_TBTOOL_TEXT_RIGHT)
+        else:
+            self.SetToolTextOrientation(AUI_TBTOOL_TEXT_BOTTOM)
+
+        if agwStyle & AUI_TB_VERTICAL:
+            if agwStyle & AUI_TB_CLOCKWISE:
+                self.SetToolOrientation(AUI_TBTOOL_VERT_CLOCKWISE)
+            elif agwStyle & AUI_TB_COUNTERCLOCKWISE:
+                self.SetToolOrientation(AUI_TBTOOL_VERT_COUNTERCLOCKWISE)
+
+                
+    def GetAGWWindowStyleFlag(self):
+        """
+        Returns the AGW-specific window style flag.
+
+        :see: L{SetAGWWindowStyleFlag} for an explanation of various AGW-specific style.
+        """
+
+        return self._agwStyle
+    
+
+    def SetArtProvider(self, art):
+        """
+        Instructs L{AuiToolBar} to use art provider specified by parameter `art`
+        for all drawing calls. This allows plugable look-and-feel features. 
+
+        :param `art`: an art provider.
+
+        :note: The previous art provider object, if any, will be deleted by L{AuiToolBar}.
+        """
+        
+        del self._art
+        self._art = art
+
+        if self._art:
+            self._art.SetAGWFlags(self._agwStyle)
+            self._art.SetTextOrientation(self._tool_text_orientation)
+            self._art.SetOrientation(self._tool_orientation)
+        
+
+    def GetArtProvider(self):
+        """ Returns the current art provider being used. """
+
+        return self._art
+
+
+    def AddSimpleTool(self, tool_id, label, bitmap, short_help_string="", kind=ITEM_NORMAL):
+        """
+        Adds a tool to the toolbar. This is the simplest method you can use to
+        ass an item to the L{AuiToolBar}.
+
+        :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
+        :param `label`: the toolbar tool label;
+        :param `bitmap`: the primary tool bitmap;
+        :param `short_help_string`: this string is used for the tools tooltip;
+        :param `kind`: the item kind. Can be one of the following:
+
+         ========================  =============================
+         Item Kind                 Description
+         ========================  =============================
+         ``ITEM_CONTROL``          The item in the `AuiToolBar` is a control
+         ``ITEM_LABEL``            The item in the `AuiToolBar` is a text label
+         ``ITEM_SPACER``           The item in the `AuiToolBar` is a spacer
+         ``ITEM_SEPARATOR``        The item in the `AuiToolBar` is a separator
+         ``ITEM_CHECK``            The item in the `AuiToolBar` is a toolbar check item
+         ``ITEM_NORMAL``           The item in the `AuiToolBar` is a standard toolbar item
+         ``ITEM_RADIO``            The item in the `AuiToolBar` is a toolbar radio item
+         ========================  =============================
+        """
+        
+        return self.AddTool(tool_id, label, bitmap, wx.NullBitmap, kind, short_help_string, "", None)
+
+
+    def AddToggleTool(self, tool_id, bitmap, disabled_bitmap, toggle=False, client_data=None, short_help_string="", long_help_string=""):
+        """
+        Adds a toggle tool to the toolbar. 
+
+        :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
+        :param `bitmap`: the primary tool bitmap;
+        :param `disabled_bitmap`: the bitmap to use when the tool is disabled. If it is equal to
+         `wx.NullBitmap`, the disabled bitmap is automatically generated by greing the normal one;
+        :param `client_data`: whatever Python object to associate with the toolbar item;
+        :param `short_help_string`: this string is used for the tools tooltip;
+        :param `long_help_string`: this string is shown in the statusbar (if any) of the parent
+         frame when the mouse pointer is inside the tool.
+        """
+
+        kind = (toggle and [ITEM_CHECK] or [ITEM_NORMAL])[0]
+        return self.AddTool(tool_id, "", bitmap, disabled_bitmap, kind, short_help_string, long_help_string, client_data)
+
+
+    def AddTool(self, tool_id, label, bitmap, disabled_bitmap, kind, short_help_string, long_help_string, client_data):
+        """
+        Adds a tool to the toolbar. This is the full feature version of L{AddTool}.
+
+        :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
+        :param `label`: the toolbar tool label;
+        :param `bitmap`: the primary tool bitmap;
+        :param `disabled_bitmap`: the bitmap to use when the tool is disabled. If it is equal to
+         `wx.NullBitmap`, the disabled bitmap is automatically generated by greing the normal one;
+        :param `kind`: the item kind. Can be one of the following:
+
+         ========================  =============================
+         Item Kind                 Description
+         ========================  =============================
+         ``ITEM_CONTROL``          The item in the `AuiToolBar` is a control
+         ``ITEM_LABEL``            The item in the `AuiToolBar` is a text label
+         ``ITEM_SPACER``           The item in the `AuiToolBar` is a spacer
+         ``ITEM_SEPARATOR``        The item in the `AuiToolBar` is a separator
+         ``ITEM_CHECK``            The item in the `AuiToolBar` is a toolbar check item
+         ``ITEM_NORMAL``           The item in the `AuiToolBar` is a standard toolbar item
+         ``ITEM_RADIO``            The item in the `AuiToolBar` is a toolbar radio item
+         ========================  =============================
+
+        :param `short_help_string`: this string is used for the tools tooltip;
+        :param `long_help_string`: this string is shown in the statusbar (if any) of the parent
+         frame when the mouse pointer is inside the tool.
+        :param `client_data`: whatever Python object to associate with the toolbar item.
+        """
+        
+        item = AuiToolBarItem()
+        item.window = None
+        item.label = label
+        item.bitmap = bitmap
+        item.disabled_bitmap = disabled_bitmap
+        item.short_help = short_help_string
+        item.long_help = long_help_string
+        item.active = True
+        item.dropdown = False
+        item.spacer_pixels = 0
+
+        if tool_id == wx.ID_ANY:
+            tool_id = wx.NewId()
+            
+        item.id = tool_id
+        item.state = 0
+        item.proportion = 0
+        item.kind = kind
+        item.sizer_item = None
+        item.min_size = wx.Size(-1, -1)
+        item.user_data = 0
+        item.sticky = False
+        item.orientation = self._tool_orientation
+
+        if not item.disabled_bitmap.IsOk():
+            # no disabled bitmap specified, we need to make one
+            if item.bitmap.IsOk():
+                item.disabled_bitmap = MakeDisabledBitmap(item.bitmap)
+        
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def AddCheckTool(self, tool_id, label, bitmap, disabled_bitmap, short_help_string="", long_help_string="", client_data=None):
+        """
+        Adds a new check (or toggle) tool to the L{AuiToolBar}.
+        
+        :see: L{AddTool}.
+        """
+
+        return self.AddTool(tool_id, label, bitmap, disabled_bitmap, ITEM_CHECK, short_help_string, long_help_string, client_data) 
+
+
+    def AddRadioTool(self, tool_id, label, bitmap, disabled_bitmap, short_help_string="", long_help_string="", client_data=None):
+        """
+        Adds a new radio tool to the toolbar.
+
+        Consecutive radio tools form a radio group such that exactly one button
+        in the group is pressed at any moment, in other words whenever a button
+        in the group is pressed the previously pressed button is automatically
+        released. You should avoid having the radio groups of only one element
+        as it would be impossible for the user to use such button.
+
+        :note: By default, the first button in the radio group is initially pressed,
+         the others are not.
+
+        :see: L{AddTool}.
+        """
+
+        return self.AddTool(tool_id, label, bitmap, disabled_bitmap, ITEM_RADIO, short_help_string, long_help_string, client_data)
+
+    
+    def AddControl(self, control, label=""):
+        """
+        Adds any control to the toolbar, typically e.g. a combobox.
+
+        :param `control`: the control to be added;
+        :param `label`: the label which appears if the control goes into the
+         overflow items in the toolbar.
+        """
+
+        item = AuiToolBarItem()
+        item.window = control
+        item.label = label
+        item.bitmap = wx.NullBitmap
+        item.disabled_bitmap = wx.NullBitmap
+        item.active = True
+        item.dropdown = False
+        item.spacer_pixels = 0
+        item.id = control.GetId()
+        item.state = 0
+        item.proportion = 0
+        item.kind = ITEM_CONTROL
+        item.sizer_item = None
+        item.min_size = control.GetEffectiveMinSize()
+        item.user_data = 0
+        item.sticky = False
+        item.orientation = self._tool_orientation
+
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def AddLabel(self, tool_id, label="", width=0):
+        """
+        Adds a label tool to the L{AuiToolBar}.
+
+        :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
+        :param `label`: the toolbar tool label;
+        :param `width`: the tool width.
+        """
+
+        min_size = wx.Size(-1, -1)
+        
+        if width != -1:
+            min_size.x = width
+
+        item = AuiToolBarItem()
+        item.window = None
+        item.label = label
+        item.bitmap = wx.NullBitmap
+        item.disabled_bitmap = wx.NullBitmap
+        item.active = True
+        item.dropdown = False
+        item.spacer_pixels = 0
+
+        if tool_id == wx.ID_ANY:
+            tool_id = wx.NewId()
+        
+        item.id = tool_id
+        item.state = 0
+        item.proportion = 0
+        item.kind = ITEM_LABEL
+        item.sizer_item = None
+        item.min_size = min_size
+        item.user_data = 0
+        item.sticky = False
+        item.orientation = self._tool_orientation
+
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def AddSeparator(self):
+        """ Adds a separator for spacing groups of tools. """
+        
+        item = AuiToolBarItem()
+        item.window = None
+        item.label = ""
+        item.bitmap = wx.NullBitmap
+        item.disabled_bitmap = wx.NullBitmap
+        item.active = True
+        item.dropdown = False
+        item.id = -1
+        item.state = 0
+        item.proportion = 0
+        item.kind = ITEM_SEPARATOR
+        item.sizer_item = None
+        item.min_size = wx.Size(-1, -1)
+        item.user_data = 0
+        item.sticky = False
+        item.orientation = self._tool_orientation
+
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def AddSpacer(self, pixels):
+        """
+        Adds a spacer for spacing groups of tools.
+
+        :param `pixels`: the width of the spacer.
+        """
+
+        item = AuiToolBarItem()
+        item.window = None
+        item.label = ""
+        item.bitmap = wx.NullBitmap
+        item.disabled_bitmap = wx.NullBitmap
+        item.active = True
+        item.dropdown = False
+        item.spacer_pixels = pixels
+        item.id = -1
+        item.state = 0
+        item.proportion = 0
+        item.kind = ITEM_SPACER
+        item.sizer_item = None
+        item.min_size = wx.Size(-1, -1)
+        item.user_data = 0
+        item.sticky = False
+        item.orientation = self._tool_orientation
+
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def AddStretchSpacer(self, proportion=1):
+        """
+        Adds a stretchable spacer for spacing groups of tools.
+
+        :param `proportion`: the stretchable spacer proportion.
+        """
+        
+        item = AuiToolBarItem()
+        item.window = None
+        item.label = ""
+        item.bitmap = wx.NullBitmap
+        item.disabled_bitmap = wx.NullBitmap
+        item.active = True
+        item.dropdown = False
+        item.spacer_pixels = 0
+        item.id = -1
+        item.state = 0
+        item.proportion = proportion
+        item.kind = ITEM_SPACER
+        item.sizer_item = None
+        item.min_size = wx.Size(-1, -1)
+        item.user_data = 0
+        item.sticky = False
+        item.orientation = self._tool_orientation
+
+        self._items.append(item)
+        return self._items[-1]
+
+
+    def Clear(self):
+        """ Deletes all the tools in the L{AuiToolBar}. """
+
+        self._items = []
+        self._sizer_element_count = 0
+
+
+    def ClearTools(self):
+        """ Deletes all the tools in the L{AuiToolBar}. """
+
+        self.Clear()
+        
+
+    def DeleteTool(self, tool_id):
+        """
+        Removes the specified tool from the toolbar and deletes it.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier.
+
+        :returns: ``True`` if the tool was deleted, ``False`` otherwise.
+        
+        :note: Note that it is unnecessary to call L{Realize} for the change to
+         take place, it will happen immediately.
+        """
+
+        idx = self.GetToolIndex(tool_id)
+        
+        if idx >= 0 and idx < len(self._items):
+            self._items.pop(idx)
+            self.Realize()
+            return True
+        
+        return False
+
+
+    def DeleteToolByPos(self, pos):
+        """
+        This function behaves like L{DeleteTool} but it deletes the tool at the
+        specified position and not the one with the given id.
+
+        :param `pos`: the tool position.
+
+        :see: L{DeleteTool}        
+        """
+        
+        if pos >= 0 and pos < len(self._items):
+            
+            self._items.pop(pos)
+            self.Realize()
+            return True
+
+        return False
+
+
+    def FindControl(self, id):
+        """
+        Returns a pointer to the control identified by `id` or ``None`` if no corresponding
+        control is found.
+
+        :param `id`: the control identifier.        
+        """
+        
+        wnd = self.FindWindow(id)
+        return wnd
+
+
+    def FindTool(self, tool_id):
+        """
+        Finds a tool for the given tool id.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier.
+        """
+        
+        for item in self._items:
+            if item.id == tool_id:
+                return item
+    
+        return None
+
+
+    def FindToolForPosition(self, x, y):
+        """
+        Finds a tool for the given mouse position.
+
+        :param `x`: mouse `x` position;
+        :param `y`: mouse `y` position.
+
+        :returns: a pointer to a L{AuiToolBarItem} if a tool is found, or ``None`` otherwise.
+        """
+
+        for i, item in enumerate(self._items):
+            if not item.sizer_item:
+                continue
+
+            rect = item.sizer_item.GetRect()
+            if rect.Contains((x,y)):
+            
+                # if the item doesn't fit on the toolbar, return None
+                if not self.GetToolFitsByIndex(i):
+                    return None
+
+                return item
+            
+        return None
+
+
+    def FindToolForPositionWithPacking(self, x, y):
+        """
+        Finds a tool for the given mouse position, taking into account also the
+        tool packing.
+
+        :param `x`: mouse `x` position;
+        :param `y`: mouse `y` position.
+
+        :returns: a pointer to a L{AuiToolBarItem} if a tool is found, or ``None`` otherwise.
+        """
+        
+        count = len(self._items)
+        
+        for i, item in enumerate(self._items):
+            if not item.sizer_item:
+                continue
+
+            rect = item.sizer_item.GetRect()
+
+            # apply tool packing
+            if i+1 < count:
+                rect.width += self._tool_packing
+
+            if rect.Contains((x,y)):
+            
+                # if the item doesn't fit on the toolbar, return None
+                if not self.GetToolFitsByIndex(i):
+                    return None
+
+                return item
+
+        return None
+
+
+    def FindToolByIndex(self, pos):
+        """
+        Finds a tool for the given tool position in the L{AuiToolBar}.
+
+        :param `pos`: the tool position in the toolbar.
+
+        :returns: a pointer to a L{AuiToolBarItem} if a tool is found, or ``None`` otherwise.        
+        """
+        
+        if pos < 0 or pos >= len(self._items):
+            return None
+
+        return self._items[pos]
+
+
+    def SetToolBitmapSize(self, size):
+        """
+        Sets the default size of each tool bitmap. The default bitmap size is
+        16 by 15 pixels.
+
+        :param `size`: the size of the bitmaps in the toolbar.
+
+        :note: This should be called to tell the toolbar what the tool bitmap
+         size is. Call it before you add tools.
+
+        :note: Note that this is the size of the bitmap you pass to L{AddTool},
+         and not the eventual size of the tool button.
+
+        :todo: Add `wx.ToolBar` compatibility, actually implementing this method.
+        """
+
+        # TODO: wx.ToolBar compatibility
+        pass
+
+
+    def GetToolBitmapSize(self):
+        """
+        Returns the size of bitmap that the toolbar expects to have. The default
+        bitmap size is 16 by 15 pixels.
+
+        :note: Note that this is the size of the bitmap you pass to L{AddTool},
+         and not the eventual size of the tool button.
+
+        :todo: Add `wx.ToolBar` compatibility, actually implementing this method.
+        """
+        
+        # TODO: wx.ToolBar compatibility
+        return wx.Size(16, 15)
+
+
+    def SetToolProportion(self, tool_id, proportion):
+        """
+        Sets the tool proportion in the toolbar.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier;
+        :param `proportion`: the tool proportion in the toolbar.
+        """
+
+        item = self.FindTool(tool_id)
+        if not item:
+            return
+
+        item.proportion = proportion
+
+
+    def GetToolProportion(self, tool_id):
+        """
+        Returns the tool proportion in the toolbar.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier.
+        """
+
+        item = self.FindTool(tool_id)
+        if not item:
+            return
+
+        return item.proportion
+
+
+    def SetToolSeparation(self, separation):
+        """
+        Sets the separator size for the toolbar.
+
+        :param `separation`: the separator size in pixels.
+        """
+
+        if self._art:
+            self._art.SetElementSize(AUI_TBART_SEPARATOR_SIZE, separation)
+
+
+    def GetToolSeparation(self):
+        """ Returns the separator size for the toolbar, in pixels. """
+        
+        if self._art:
+            return self._art.GetElementSize(AUI_TBART_SEPARATOR_SIZE)
+
+        return 5
+
+
+    def SetToolDropDown(self, tool_id, dropdown):
+        """
+        Assigns a drop down window menu to the toolbar item.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier;
+        :param `dropdown`: whether to assign a drop down menu or not.
+        """
+
+        item = self.FindTool(tool_id)
+        if not item:
+            return
+
+        item.dropdown = dropdown
+
+
+    def GetToolDropDown(self, tool_id):
+        """
+        Returns whether the toolbar item identified by `tool_id` has an associated
+        drop down window menu or not.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier.
+        """
+
+        item = self.FindTool(tool_id)
+        if not item:
+            return
+
+        return item.dropdown
+
+
+    def SetToolSticky(self, tool_id, sticky):
+        """
+        Sets the toolbar item as sticky or non-sticky.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier;
+        :param `sticky`: whether the tool should be sticky or not.
+        """
+
+        # ignore separators
+        if tool_id == -1:
+            return
+
+        item = self.FindTool(tool_id)
+        if not item:
+            return
+
+        if item.sticky == sticky:
+            return
+
+        item.sticky = sticky
+
+        self.Refresh(False)
+        self.Update()
+
+
+    def GetToolSticky(self, tool_id):
+        """
+        Returns whether the toolbar item identified by `tool_id` has a sticky
+        behaviour or not.
+
+        :param `tool_id`: the L{AuiToolBarItem} identifier.
+        """
+
+        item = self.FindTool(tool_id)
+        if not item:
+            return
+
+        return item.sticky
+
+
+    def SetToolBorderPadding(self, padding):
+        """
+        Sets the padding between the tool border and the label.
+
+        :param `padding`: the padding in pixels.
+        """
+
+        self._tool_border_padding = padding
+
+
+    def GetToolBorderPadding(self):
+        """ Returns the padding between the tool border and the label, in pixels. """
+
+        return self._tool_border_padding
+
+
+    def SetToolTextOrientation(self, orientation):
+        """
+        Sets the label orientation for the toolbar items.
+
+        :param `orientation`: the L{AuiToolBarItem} label orientation.
+        """
+
+        self._tool_text_orientation = orientation
+
+        if self._art:
+            self._art.SetTextOrientation(orientation)
+    
+
+    def GetToolTextOrientation(self):
+        """ Returns the label orientation for the toolbar items. """
+
+        return self._tool_text_orientation
+
+
+    def SetToolOrientation(self, orientation):
+        """
+        Sets the tool orientation for the toolbar items.
+
+        :param `orientation`: the L{AuiToolBarItem} orientation.
+        """
+
+        self._tool_orientation = orientation
+        if self._art:
+            self._art.SetOrientation(orientation)
+
+
+    def GetToolOrientation(self):
+        """ Returns the orientation for the toolbar items. """
+
+        return self._tool_orientation        
+
+
+    def SetToolPacking(self, packing):
+        """
+        Sets the value used for spacing tools. The default value is 1 pixel.
+
+        :param `packing`: the value for packing.
+        """
+
+        self._tool_packing = packing
+
+
+    def GetToolPacking(self):
+        """ Returns the value used for spacing tools. The default value is 1 pixel. """
+
+        return self._tool_packing
+
+
+    def SetOrientation(self, orientation):
+        """
+        Sets the toolbar orientation.
+
+        :param `orientation`: either ``wx.VERTICAL`` or ``wx.HORIZONTAL``.
+
+        :note: This can be temporarily overridden by L{AuiManager} when floating and
+         docking a L{AuiToolBar}.
+        """
+
+        pass
+    
+
+    def SetMargins(self, left=-1, right=-1, top=-1, bottom=-1):
+        """
+        Set the values to be used as margins for the toolbar.
+
+        :param `left`: the left toolbar margin;
+        :param `right`: the right toolbar margin;
+        :param `top`: the top toolbar margin;
+        :param `bottom`: the bottom toolbar margin.
+        """
+
+        if left != -1:
+            self._left_padding = left
+        if right != -1:
+            self._right_padding = right
+        if top != -1:
+            self._top_padding = top
+        if bottom != -1:
+            self._bottom_padding = bottom
+
+
+    def SetMarginsSize(self, size):
+        """
+        Set the values to be used as margins for the toolbar.
+
+        :param `size`: the margin size (an instance of `wx.Size`).
+        """
+        
+        self.SetMargins(size.x, size.x, size.y, size.y)
+
+
+    def SetMarginsXY(self, x, y):
+        """
+        Set the values to be used as margins for the toolbar.
+        
+        :param `x`: left margin, right margin and inter-tool separation value;
+        :param `y`: top margin, bottom margin and inter-tool separation value.
+        """
+        
+        self.SetMargins(x, x, y, y)        
+
+            
+    def GetGripperVisible(self):
+        """ Returns whether the toolbar gripper is visible or not. """
+
+        return self._gripper_visible
+
+
+    def SetGripperVisible(self, visible):
+        """
+        Sets whether the toolbar gripper is visible or not.
+
+        :param `visible`: ``True`` for a visible gripper, ``False`` otherwise.
+        """
+
+        self._gripper_visible = visible
+        if visible:
+            self._agwStyle |= AUI_TB_GRIPPER
+        else:
+            self._agwStyle &= ~AUI_TB_GRIPPER
+            
+        self.Realize()
+        self.Refresh(False)
+
+
+    def GetOverflowVisible(self):
+        """ Returns whether the overflow button is visible or not. """
+
+        return self._overflow_visible
+
+
+    def SetOverflowVisible(self, visible):
+        """
+        Sets whether the overflow button is visible or not.
+
+        :param `visible`: ``True`` for a visible overflow button, ``False`` otherwise.
+        """
+
+        self._overflow_visible = visible
+        if visible:
+            self._agwStyle |= AUI_TB_OVERFLOW
+        else:
+            self._agwStyle &= ~AUI_TB_OVERFLOW
+
+        self.Refresh(False)
+
+
+    def SetFont(self, font):
+        """
+        Sets the L{AuiToolBar} font.
+
+        :param `font`: a `wx.Font` object.
+
+        :note: Overridden from `wx.PyControl`.
+        """        
+
+        res = wx.PyControl.SetFont(self, font)
+
+        if self._art:
+            self._art.SetFont(font)
+    
+        return res
+
+
+    def SetHoverItem(self, pitem):
+        """
+        Sets a toolbar item to be currently hovered by the mouse.
+
+        :param `pitem`: an instance of L{AuiToolBarItem}.
+        """
+
+        former_hover = None
+
+        for item in self._items:
+        
+            if item.state & AUI_BUTTON_STATE_HOVER:
+                former_hover = item
+                
+            item.state &= ~AUI_BUTTON_STATE_HOVER
+
+        if pitem:
+            pitem.state |= AUI_BUTTON_STATE_HOVER
+        
+        if former_hover != pitem:
+            self.Refresh(False)
+            self.Update()
+        
+
+    def SetPressedItem(self, pitem):
+        """
+        Sets a toolbar item to be currently in a "pressed" state.
+
+        :param `pitem`: an instance of L{AuiToolBarItem}.
+        """
+
+        former_item = None
+
+        for item in self._items:
+        
+            if item.state & AUI_BUTTON_STATE_PRESSED:
+                former_item = item
+                
+            item.state &= ~AUI_BUTTON_STATE_PRESSED
+        
+        if pitem:
+            pitem.state &= ~AUI_BUTTON_STATE_HOVER
+            pitem.state |= AUI_BUTTON_STATE_PRESSED
+        
+        if former_item != pitem:
+            self.Refresh(False)
+            self.Update()
+    
+
+    def RefreshOverflowState(self):
+        """ Refreshes the overflow button. """
+
+        if not self._overflow_sizer_item:
+            self._overflow_state = 0
+            return
+        
+        overflow_state = 0
+        overflow_rect = self.GetOverflowRect()
+
+        # find out the mouse's current position
+        pt = wx.GetMousePosition()
+        pt = self.ScreenToClient(pt)
+
+        # find out if the mouse cursor is inside the dropdown rectangle
+        if overflow_rect.Contains((pt.x, pt.y)):
+
+            if _VERSION_STRING < "2.9":
+                leftDown = wx.GetMouseState().LeftDown()
+            else:
+                leftDown = wx.GetMouseState().LeftIsDown()
+        
+            if leftDown:
+                overflow_state = AUI_BUTTON_STATE_PRESSED
+            else:
+                overflow_state = AUI_BUTTON_STATE_HOVER
+        
+        if overflow_state != self._overflow_state:
+            self._overflow_state = overflow_state
+            self.Refresh(False)
+            self.Update()
+        
+        self._overflow_state = overflow_state
+
+
+    def ToggleTool(self, tool_id, state):
+        """
+        Toggles a tool on or off. This does not cause any event to get emitted.
+
+        :param `tool_id`: tool in question.
+        :param `state`: if ``True``, toggles the tool on, otherwise toggles it off.
+
+        :note: This only applies to a tool that has been specified as a toggle tool.
+        """
+        
+        tool = self.FindTool(tool_id)
+
+        if tool:
+            if tool.kind not in [ITEM_CHECK, ITEM_RADIO]:
+                return
+
+            if tool.kind == ITEM_RADIO:
+                idx = self.GetToolIndex(tool_id)
+                if idx >= 0 and idx < len(self._items):
+                    for i in xrange(idx, len(self._items)):
+                        tool = self.FindToolByIndex(i)
+                        if tool.kind != ITEM_RADIO:
+                            break
+                        tool.state &= ~AUI_BUTTON_STATE_CHECKED
+
+                    for i in xrange(idx, -1, -1):
+                        tool = self.FindToolByIndex(i)
+                        if tool.kind != ITEM_RADIO:
+                            break
+                        tool.state &= ~AUI_BUTTON_STATE_CHECKED 
+
+                    tool = self.FindTool(tool_id)
+                    tool.state |= AUI_BUTTON_STATE_CHECKED
+            else:
+                if state == True:
+                    tool.state |= AUI_BUTTON_STATE_CHECKED
+                else:
+                    tool.state &= ~AUI_BUTTON_STATE_CHECKED 
+
+
+    def GetToolToggled(self, tool_id):
+        """
+        Returns whether a tool is toggled or not.
+
+        :param `tool_id`: the toolbar item identifier.
+
+        :note: This only applies to a tool that has been specified as a toggle tool.
+        """        
+
+        tool = self.FindTool(tool_id)
+
+        if tool:
+            if tool.kind not in [ITEM_CHECK, ITEM_RADIO]:
+                return False
+
+            return (tool.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
+        
+        return False
+
+
+    def EnableTool(self, tool_id, state):
+        """
+        Enables or disables the tool.
+
+        :param `tool_id`: identifier for the tool to enable or disable.
+        :param `state`: if ``True``, enables the tool, otherwise disables it.
+        """
+
+        tool = self.FindTool(tool_id)
+
+        if tool:
+        
+            if state == True:
+                tool.state &= ~AUI_BUTTON_STATE_DISABLED
+            else:
+                tool.state |= AUI_BUTTON_STATE_DISABLED
+        
+
+    def GetToolEnabled(self, tool_id):
+        """
+        Returns whether the tool identified by `tool_id` is enabled or not.
+
+        :param `tool_id`: the tool identifier.
+        """
+
+        tool = self.FindTool(tool_id)
+
+        if tool:
+            return (tool.state & AUI_BUTTON_STATE_DISABLED and [False] or [True])[0]
+
+        return False
+
+
+    def GetToolLabel(self, tool_id):
+        """
+        Returns the tool label for the tool identified by `tool_id`.
+
+        :param `tool_id`: the tool identifier.
+        """
+
+        tool = self.FindTool(tool_id)
+        if not tool:
+            return ""
+        
+        return tool.label
+
+
+    def SetToolLabel(self, tool_id, label):
+        """
+        Sets the tool label for the tool identified by `tool_id`.
+
+        :param `tool_id`: the tool identifier;
+        :param `label`: the new toolbar item label.
+        """
+        
+        tool = self.FindTool(tool_id)
+        if tool:    
+            tool.label = label
+    
+
+    def GetToolBitmap(self, tool_id):
+        """
+        Returns the tool bitmap for the tool identified by `tool_id`.
+
+        :param `tool_id`: the tool identifier.
+        """
+        
+        tool = self.FindTool(tool_id)
+        if not tool:
+            return wx.NullBitmap
+
+        return tool.bitmap
+
+
+    def SetToolBitmap(self, tool_id, bitmap):
+        """
+        Sets the tool bitmap for the tool identified by `tool_id`.
+
+        :param `tool_id`: the tool identifier;
+        :param `bitmap`: the new bitmap for the toolbar item (an instance of `wx.Bitmap`).
+        """
+        
+        tool = self.FindTool(tool_id)
+        if tool:
+            tool.bitmap = bitmap
+
+
+    def SetToolNormalBitmap(self, tool_id, bitmap):
+        """
+        Sets the tool bitmap for the tool identified by `tool_id`.
+
+        :param `tool_id`: the tool identifier;
+        :param `bitmap`: the new bitmap for the toolbar item (an instance of `wx.Bitmap`).
+        """
+        
+        self.SetToolBitmap(tool_id, bitmap)
+
+
+    def SetToolDisabledBitmap(self, tool_id, bitmap):
+        """
+        Sets the tool disabled bitmap for the tool identified by `tool_id`.
+
+        :param `tool_id`: the tool identifier;
+        :param `bitmap`: the new disabled bitmap for the toolbar item (an instance of `wx.Bitmap`).
+        """
+        
+        tool = self.FindTool(tool_id)
+        if tool:
+            tool.disabled_bitmap = bitmap
+
+
+    def GetToolShortHelp(self, tool_id):
+        """
+        Returns the short help for the given tool.
+
+        :param `tool_id`: the tool identifier.
+        """
+
+        tool = self.FindTool(tool_id)
+        if not tool:
+            return ""
+
+        return tool.short_help
+
+
+    def SetToolShortHelp(self, tool_id, help_string):
+        """
+        Sets the short help for the given tool.
+
+        :param `tool_id`: the tool identifier;
+        :param `help_string`: the string for the short help.
+        """
+        
+        tool = self.FindTool(tool_id)
+        if tool:
+            tool.short_help = help_string
+
+
+    def GetToolLongHelp(self, tool_id):
+        """
+        Returns the long help for the given tool.
+
+        :param `tool_id`: the tool identifier.
+        """
+
+        tool = self.FindTool(tool_id)
+        if not tool:
+            return ""
+
+        return tool.long_help
+
+
+    def SetToolAlignment(self, alignment=wx.EXPAND):
+        """
+        This sets the alignment for all of the tools within the
+        toolbar (only has an effect when the toolbar is expanded).
+
+        :param `alignment`: `wx.Sizer` alignment value
+         (``wx.ALIGN_CENTER_HORIZONTAL`` or ``wx.ALIGN_CENTER_VERTICAL``).
+        """
+
+        self._tool_alignment = alignment
+
+
+
+    def SetToolLongHelp(self, tool_id, help_string):
+        """
+        Sets the long help for the given tool.
+
+        :param `tool_id`: the tool identifier;
+        :param `help_string`: the string for the long help.
+        """
+        
+        tool = self.FindTool(tool_id)
+        if tool:
+            tool.long_help = help_string
+    
+
+    def SetCustomOverflowItems(self, prepend, append):
+        """
+        Sets the two lists `prepend` and `append` as custom overflow items.
+
+        :param `prepend`: a list of L{AuiToolBarItem} to be prepended;
+        :param `append`: a list of L{AuiToolBarItem} to be appended.
+        """
+
+        self._custom_overflow_prepend = prepend
+        self._custom_overflow_append = append
+
+
+    def GetToolCount(self):
+        """ Returns the number of tools in the L{AuiToolBar}. """
+
+        return len(self._items)
+
+
+    def GetToolIndex(self, tool_id):
+        """
+        Returns the position of the tool in the toolbar given its identifier.
+
+        :param `tool_id`: the toolbar item identifier.
+        """
+
+        # this will prevent us from returning the index of the
+        # first separator in the toolbar since its id is equal to -1
+        if tool_id == -1:
+            return wx.NOT_FOUND
+
+        for i, item in enumerate(self._items):
+            if item.id == tool_id:
+                return i
+        
+        return wx.NOT_FOUND
+
+
+    def GetToolPos(self, tool_id):
+        """
+        Returns the position of the tool in the toolbar given its identifier.
+
+        :param `tool_id`: the toolbar item identifier.
+        """
+        
+        return self.GetToolIndex(tool_id)
+                                
+
+    def GetToolFitsByIndex(self, tool_id):
+        """
+        Returns whether the tool identified by `tool_id` fits into the toolbar or not.
+
+        :param `tool_id`: the toolbar item identifier.
+        """
+        
+        if tool_id < 0 or tool_id >= len(self._items):
+            return False
+
+        if not self._items[tool_id].sizer_item:
+            return False
+
+        cli_w, cli_h = self.GetClientSize()
+        rect = self._items[tool_id].sizer_item.GetRect()
+
+        if self._agwStyle & AUI_TB_VERTICAL:
+            # take the dropdown size into account
+            if self._overflow_visible:
+                cli_h -= self._overflow_sizer_item.GetSize().y
+
+            if rect.y+rect.height < cli_h:
+                return True
+        
+        else:
+        
+            # take the dropdown size into account
+            if self._overflow_visible:
+                cli_w -= self._overflow_sizer_item.GetSize().x
+
+            if rect.x+rect.width < cli_w:
+                return True
+        
+        return False
+
+
+    def GetToolFits(self, tool_id):
+        """
+        Returns whether the tool identified by `tool_id` fits into the toolbar or not.
+
+        :param `tool_id`: the toolbar item identifier.
+        """
+        
+        return self.GetToolFitsByIndex(self.GetToolIndex(tool_id))
+
+
+    def GetToolRect(self, tool_id):
+        """
+        Returns the toolbar item rectangle
+
+        :param `tool_id`: the toolbar item identifier.
+        """
+
+        tool = self.FindTool(tool_id)
+        if tool and tool.sizer_item:
+            return tool.sizer_item.GetRect()
+
+        return wx.Rect()
+
+
+    def GetToolBarFits(self):
+        """ Returns whether the L{AuiToolBar} size fits in a specified size. """
+
+        if len(self._items) == 0:
+            # empty toolbar always 'fits'
+            return True
+        
+        # entire toolbar content fits if the last tool fits
+        return self.GetToolFitsByIndex(len(self._items) - 1)
+
+
+    def Realize(self):
+        """ Realizes the toolbar. This function should be called after you have added tools. """
+
+        dc = wx.ClientDC(self)
+        
+        if not dc.IsOk():
+            return False
+
+        horizontal = True
+        if self._agwStyle & AUI_TB_VERTICAL:
+            horizontal = False
+
+        # create the new sizer to add toolbar elements to
+        sizer = wx.BoxSizer((horizontal and [wx.HORIZONTAL] or [wx.VERTICAL])[0])
+
+        # add gripper area
+        separator_size = self._art.GetElementSize(AUI_TBART_SEPARATOR_SIZE)
+        gripper_size = self._art.GetElementSize(AUI_TBART_GRIPPER_SIZE)
+        
+        if gripper_size > 0 and self._gripper_visible:        
+            if horizontal:
+                self._gripper_sizer_item = sizer.Add((gripper_size, 1), 0, wx.EXPAND)
+            else:
+                self._gripper_sizer_item = sizer.Add((1, gripper_size), 0, wx.EXPAND)
+        else:
+            self._gripper_sizer_item = None
+        
+        # add "left" padding
+        if self._left_padding > 0:
+            if horizontal:
+                sizer.Add((self._left_padding, 1))
+            else:
+                sizer.Add((1, self._left_padding))
+        
+        count = len(self._items)
+        for i, item in enumerate(self._items):
+        
+            sizer_item = None
+            kind = item.kind
+
+            if kind == ITEM_LABEL:
+                
+                size = self._art.GetLabelSize(dc, self, item)
+                sizer_item = sizer.Add((size.x + (self._tool_border_padding*2),
+                                        size.y + (self._tool_border_padding*2)),
+                                       item.proportion,
+                                       item.alignment)
+                if i+1 < count:
+                    sizer.AddSpacer(self._tool_packing)
+                
+
+            elif kind in [ITEM_CHECK, ITEM_NORMAL, ITEM_RADIO]:
+                
+                size = self._art.GetToolSize(dc, self, item)
+                sizer_item = sizer.Add((size.x + (self._tool_border_padding*2),
+                                        size.y + (self._tool_border_padding*2)),
+                                       0,
+                                       item.alignment)
+                # add tool packing
+                if i+1 < count:
+                    sizer.AddSpacer(self._tool_packing)
+
+            elif kind == ITEM_SEPARATOR:
+                
+                if horizontal:
+                    sizer_item = sizer.Add((separator_size, 1), 0, wx.EXPAND)
+                else:
+                    sizer_item = sizer.Add((1, separator_size), 0, wx.EXPAND)
+
+                # add tool packing
+                if i+1 < count:
+                    sizer.AddSpacer(self._tool_packing)
+
+            elif kind == ITEM_SPACER:
+                
+                if item.proportion > 0:
+                    sizer_item = sizer.AddStretchSpacer(item.proportion)
+                else:
+                    sizer_item = sizer.Add((item.spacer_pixels, 1))
+                    
+            elif kind == ITEM_CONTROL:
+                
+                vert_sizer = wx.BoxSizer(wx.VERTICAL)
+                vert_sizer.AddStretchSpacer(1)
+                ctrl_sizer_item = vert_sizer.Add(item.window, 0, wx.EXPAND)
+                vert_sizer.AddStretchSpacer(1)
+                
+                if self._agwStyle & AUI_TB_TEXT and \
+                    self._tool_text_orientation == AUI_TBTOOL_TEXT_BOTTOM and \
+                    item.GetLabel() != "":
+                
+                    s = self.GetLabelSize(item.GetLabel())
+                    vert_sizer.Add((1, s.y))
+
+                sizer_item = sizer.Add(vert_sizer, item.proportion, wx.EXPAND)
+                min_size = item.min_size
+
+                # proportional items will disappear from the toolbar if
+                # their min width is not set to something really small
+                if item.proportion != 0:
+                    min_size.x = 1
+                
+                if min_size.IsFullySpecified():
+                    sizer.SetItemMinSize(vert_sizer, min_size)
+                    vert_sizer.SetItemMinSize(item.window, min_size)
+                
+                # add tool packing
+                if i+1 < count:
+                    sizer.AddSpacer(self._tool_packing)
+                
+            item.sizer_item = sizer_item
+        
+
+        # add "right" padding
+        if self._right_padding > 0:
+            if horizontal:
+                sizer.Add((self._right_padding, 1))
+            else:
+                sizer.Add((1, self._right_padding))
+        
+        # add drop down area
+        self._overflow_sizer_item = None
+
+        if self._agwStyle & AUI_TB_OVERFLOW:
+        
+            overflow_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
+            if overflow_size > 0 and self._overflow_visible:
+            
+                if horizontal:
+                    self._overflow_sizer_item = sizer.Add((overflow_size, 1), 0, wx.EXPAND)
+                else:
+                    self._overflow_sizer_item = sizer.Add((1, overflow_size), 0, wx.EXPAND)
+            
+            else:
+            
+                self._overflow_sizer_item = None
+            
+        # the outside sizer helps us apply the "top" and "bottom" padding
+        outside_sizer = wx.BoxSizer((horizontal and [wx.VERTICAL] or [wx.HORIZONTAL])[0])
+
+        # add "top" padding
+        if self._top_padding > 0:
+        
+            if horizontal:
+                outside_sizer.Add((1, self._top_padding))
+            else:
+                outside_sizer.Add((self._top_padding, 1))
+        
+        # add the sizer that contains all of the toolbar elements
+        outside_sizer.Add(sizer, 1, self._tool_alignment)
+
+        # add "bottom" padding
+        if self._bottom_padding > 0:
+        
+            if horizontal:
+                outside_sizer.Add((1, self._bottom_padding))
+            else:
+                outside_sizer.Add((self._bottom_padding, 1))
+
+        del self._sizer # remove old sizer
+        self._sizer = outside_sizer
+        self.SetSizer(outside_sizer)
+
+        # calculate the rock-bottom minimum size
+        for item in self._items:
+        
+            if item.sizer_item and item.proportion > 0 and item.min_size.IsFullySpecified():
+                item.sizer_item.SetMinSize((0, 0))
+        
+        self._absolute_min_size = self._sizer.GetMinSize()
+
+        # reset the min sizes to what they were
+        for item in self._items:
+        
+            if item.sizer_item and item.proportion > 0 and item.min_size.IsFullySpecified():
+                item.sizer_item.SetMinSize(item.min_size)
+        
+        # set control size
+        size = self._sizer.GetMinSize()
+        self.SetMinSize(size)
+        self._minWidth = size.x
+        self._minHeight = size.y
+
+        if self._agwStyle & AUI_TB_NO_AUTORESIZE == 0:
+        
+            cur_size = self.GetClientSize()
+            new_size = self.GetMinSize()
+
+            if new_size != cur_size:
+            
+                self.SetClientSize(new_size)
+            
+            else:
+            
+                self._sizer.SetDimension(0, 0, cur_size.x, cur_size.y)
+            
+        else:
+        
+            cur_size = self.GetClientSize()
+            self._sizer.SetDimension(0, 0, cur_size.x, cur_size.y)
+                    
+        self.Refresh(False)
+        return True
+
+
+    def GetOverflowState(self):
+        """ Returns the state of the overflow button. """
+
+        return self._overflow_state
+
+
+    def GetOverflowRect(self):
+        """ Returns the rectangle of the overflow button. """
+
+        cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
+        overflow_rect = wx.Rect(*self._overflow_sizer_item.GetRect())
+        overflow_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
+
+        if self._agwStyle & AUI_TB_VERTICAL:
+        
+            overflow_rect.y = cli_rect.height - overflow_size
+            overflow_rect.x = 0
+            overflow_rect.width = cli_rect.width
+            overflow_rect.height = overflow_size
+        
+        else:
+        
+            overflow_rect.x = cli_rect.width - overflow_size
+            overflow_rect.y = 0
+            overflow_rect.width = overflow_size
+            overflow_rect.height = cli_rect.height
+        
+        return overflow_rect
+
+
+    def GetLabelSize(self, label):
+        """
+        Returns the standard size of a toolbar item.
+
+        :param `label`: a test label.
+        """
+
+        dc = wx.ClientDC(self)
+        dc.SetFont(self._font)
+
+        return GetLabelSize(dc, label, self._tool_orientation != AUI_TBTOOL_HORIZONTAL)
+
+
+    def GetAuiManager(self):
+        """ Returns the L{AuiManager} which manages the toolbar. """
+
+        try:
+            return self._auiManager
+        except AttributeError:
+            return False
+
+
+    def SetAuiManager(self, auiManager):
+        """ Sets the L{AuiManager} which manages the toolbar. """
+        
+        self._auiManager = auiManager        
+
+        
+    def DoIdleUpdate(self):
+        """ Updates the toolbar during idle times. """
+
+        handler = self.GetEventHandler()
+        if not handler:
+            return
+        
+        need_refresh = False
+
+        for item in self._items:
+                
+            if item.id == -1:
+                continue
+
+            evt = wx.UpdateUIEvent(item.id)
+            evt.SetEventObject(self)
+
+            if handler.ProcessEvent(evt):
+            
+                if evt.GetSetEnabled():
+                
+                    if item.window:
+                        is_enabled = item.window.IsEnabled()
+                    else:
+                        is_enabled = (item.state & AUI_BUTTON_STATE_DISABLED and [False] or [True])[0]
+
+                    new_enabled = evt.GetEnabled()
+                    if new_enabled != is_enabled:
+                    
+                        if item.window:
+                            item.window.Enable(new_enabled)
+                        else:
+                            if new_enabled:
+                                item.state &= ~AUI_BUTTON_STATE_DISABLED
+                            else:
+                                item.state |= AUI_BUTTON_STATE_DISABLED
+                        
+                        need_refresh = True
+                    
+                if evt.GetSetChecked():
+                
+                    # make sure we aren't checking an item that can't be
+                    if item.kind != ITEM_CHECK and item.kind != ITEM_RADIO:
+                        continue
+
+                    is_checked = (item.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
+                    new_checked = evt.GetChecked()
+
+                    if new_checked != is_checked:
+                    
+                        if new_checked:
+                            item.state |= AUI_BUTTON_STATE_CHECKED
+                        else:
+                            item.state &= ~AUI_BUTTON_STATE_CHECKED
+
+                        need_refresh = True
+                    
+        if need_refresh:
+            self.Refresh(False)
+
+        
+    def OnSize(self, event):
+        """
+        Handles the ``wx.EVT_SIZE`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.SizeEvent` event to be processed.        
+        """
+        
+        x, y = self.GetClientSize()
+        realize = False
+
+        if x > y:
+            self.SetOrientation(wx.HORIZONTAL)
+        else:
+            self.SetOrientation(wx.VERTICAL)
+
+        if (x >= y and self._absolute_min_size.x > x) or (y > x and self._absolute_min_size.y > y):
+        
+            # hide all flexible items
+            for item in self._items:
+                if item.sizer_item and item.proportion > 0 and item.sizer_item.IsShown():
+                    item.sizer_item.Show(False)
+                    item.sizer_item.SetProportion(0)
+
+            if self._originalStyle & AUI_TB_OVERFLOW:
+                if not self.GetOverflowVisible():
+                    self.SetOverflowVisible(True)
+                    realize = True
+                       
+        else:
+
+            if self._originalStyle & AUI_TB_OVERFLOW and not self._custom_overflow_append and \
+               not self._custom_overflow_prepend:
+                if self.GetOverflowVisible():
+                    self.SetOverflowVisible(False)
+                    realize = True
+
+            # show all flexible items
+            for item in self._items:
+                if item.sizer_item and item.proportion > 0 and not item.sizer_item.IsShown():
+                    item.sizer_item.Show(True)
+                    item.sizer_item.SetProportion(item.proportion)
+                
+        self._sizer.SetDimension(0, 0, x, y)
+
+        if realize:
+            self.Realize()
+        else:
+            self.Refresh(False)
+            
+        self.Update()
+
+        
+    def DoSetSize(self, x, y, width, height, sizeFlags=wx.SIZE_AUTO):
+        """        
+        Sets the position and size of the window in pixels. The `sizeFlags`
+        parameter indicates the interpretation of the other params if they are
+        equal to -1.
+
+        :param `x`: the window `x` position;
+        :param `y`: the window `y` position;
+        :param `width`: the window width;
+        :param `height`: the window height;
+        :param `sizeFlags`: may have one of this bit set:
+   
+         ===================================  ======================================
+         Size Flags                           Description
+         ===================================  ======================================
+         ``wx.SIZE_AUTO``                     A -1 indicates that a class-specific default should be used.
+         ``wx.SIZE_AUTO_WIDTH``               A -1 indicates that a class-specific default should be used for the width.
+         ``wx.SIZE_AUTO_HEIGHT``              A -1 indicates that a class-specific default should be used for the height.
+         ``wx.SIZE_USE_EXISTING``             Existing dimensions should be used if -1 values are supplied.
+         ``wx.SIZE_ALLOW_MINUS_ONE``          Allow dimensions of -1 and less to be interpreted as real dimensions, not default values.
+         ``wx.SIZE_FORCE``                    Normally, if the position and the size of the window are already the same as the parameters of this function, nothing is done. but with this flag a window resize may be forced even in this case (supported in wx 2.6.2 and later and only implemented for MSW and ignored elsewhere currently) 
+         ===================================  ======================================
+
+        :note: Overridden from `wx.PyControl`.
+        """
+        
+        parent_size = self.GetParent().GetClientSize()
+        if x + width > parent_size.x:
+            width = max(0, parent_size.x - x)
+        if y + height > parent_size.y:
+            height = max(0, parent_size.y - y)
+
+        wx.PyControl.DoSetSize(self, x, y, width, height, sizeFlags)
+
+
+    def OnIdle(self, event):
+        """
+        Handles the ``wx.EVT_IDLE`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.IdleEvent` event to be processed.        
+        """
+        
+        self.DoIdleUpdate()
+        event.Skip()
+
+
+    def DoGetBestSize(self):
+        """
+        Gets the size which best suits the window: for a control, it would be the
+        minimal size which doesn't truncate the control, for a panel - the same
+        size as it would have after a call to `Fit()`.
+        
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        return self._absolute_min_size
+    
+
+    def OnPaint(self, event):
+        """
+        Handles the ``wx.EVT_PAINT`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.PaintEvent` event to be processed.        
+        """
+
+        dc = wx.AutoBufferedPaintDC(self)
+        cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
+
+        horizontal = True
+        if self._agwStyle & AUI_TB_VERTICAL:
+            horizontal = False
+
+        if self._agwStyle & AUI_TB_PLAIN_BACKGROUND:
+            self._art.DrawPlainBackground(dc, self, cli_rect)
+        else:
+            self._art.DrawBackground(dc, self, cli_rect, horizontal)
+
+        gripper_size = self._art.GetElementSize(AUI_TBART_GRIPPER_SIZE)
+        dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
+
+        # paint the gripper
+        if gripper_size > 0 and self._gripper_sizer_item:
+            gripper_rect = wx.Rect(*self._gripper_sizer_item.GetRect())
+            if horizontal:
+                gripper_rect.width = gripper_size
+            else:
+                gripper_rect.height = gripper_size
+                
+            self._art.DrawGripper(dc, self, gripper_rect)
+        
+        # calculated how far we can draw items
+        if horizontal:
+            last_extent = cli_rect.width
+        else:
+            last_extent = cli_rect.height
+            
+        if self._overflow_visible:
+            last_extent -= dropdown_size
+
+        # paint each individual tool
+        for item in self._items:
+
+            if not item.sizer_item:
+                continue
+
+            item_rect = wx.Rect(*item.sizer_item.GetRect())
+
+            if (horizontal and item_rect.x + item_rect.width >= last_extent) or \
+               (not horizontal and item_rect.y + item_rect.height >= last_extent):
+
+                break
+            
+            if item.kind == ITEM_SEPARATOR:
+                # draw a separator
+                self._art.DrawSeparator(dc, self, item_rect)
+            
+            elif item.kind == ITEM_LABEL:
+                # draw a text label only
+                self._art.DrawLabel(dc, self, item, item_rect)
+            
+            elif item.kind == ITEM_NORMAL:
+                # draw a regular button or dropdown button
+                if not item.dropdown:
+                    self._art.DrawButton(dc, self, item, item_rect)
+                else:
+                    self._art.DrawDropDownButton(dc, self, item, item_rect)
+            
+            elif item.kind == ITEM_CHECK:
+                # draw a regular toggle button or a dropdown one
+                if not item.dropdown:
+                    self._art.DrawButton(dc, self, item, item_rect)
+                else:
+                    self._art.DrawDropDownButton(dc, self, item, item_rect)
+
+            elif item.kind == ITEM_RADIO:
+                # draw a toggle button
+                self._art.DrawButton(dc, self, item, item_rect)
+            
+            elif item.kind == ITEM_CONTROL:
+                # draw the control's label
+                self._art.DrawControlLabel(dc, self, item, item_rect)
+            
+            # fire a signal to see if the item wants to be custom-rendered
+            self.OnCustomRender(dc, item, item_rect)
+        
+        # paint the overflow button
+        if dropdown_size > 0 and self._overflow_sizer_item:
+            dropdown_rect = self.GetOverflowRect()
+            self._art.DrawOverflowButton(dc, self, dropdown_rect, self._overflow_state)
+
+        
+    def OnEraseBackground(self, event):
+        """
+        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.EraseEvent` event to be processed.
+
+        :note: This is intentionally empty, to reduce flicker.
+        """
+
+        pass
+    
+
+    def OnLeftDown(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_DOWN`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
+        self.StopPreviewTimer()
+
+        if self._gripper_sizer_item:
+        
+            gripper_rect = wx.Rect(*self._gripper_sizer_item.GetRect())
+            if gripper_rect.Contains(event.GetPosition()):
+            
+                # find aui manager
+                manager = self.GetAuiManager()
+                if not manager:
+                    return
+
+                x_drag_offset = event.GetX() - gripper_rect.GetX()
+                y_drag_offset = event.GetY() - gripper_rect.GetY()
+
+                clientPt = wx.Point(*event.GetPosition())
+                screenPt = self.ClientToScreen(clientPt)
+                managedWindow = manager.GetManagedWindow()
+                managerClientPt = managedWindow.ScreenToClient(screenPt)
+
+                # gripper was clicked
+                manager.OnGripperClicked(self, managerClientPt, wx.Point(x_drag_offset, y_drag_offset))            
+                return
+
+        if self._overflow_sizer_item:
+            overflow_rect = self.GetOverflowRect()
+
+            if self._art and self._overflow_visible and overflow_rect.Contains(event.GetPosition()):
+            
+                e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, -1)
+                e.SetEventObject(self)
+                e.SetToolId(-1)
+                e.SetClickPoint(event.GetPosition())
+                processed = self.ProcessEvent(e)
+
+                if processed:
+                    self.DoIdleUpdate()
+                else:                
+                    overflow_items = []
+
+                    # add custom overflow prepend items, if any
+                    count = len(self._custom_overflow_prepend)
+                    for i in xrange(count):
+                        overflow_items.append(self._custom_overflow_prepend[i])
+
+                    # only show items that don't fit in the dropdown
+                    count = len(self._items)
+                    for i in xrange(count):
+                    
+                        if not self.GetToolFitsByIndex(i):
+                            overflow_items.append(self._items[i])
+                    
+                    # add custom overflow append items, if any
+                    count = len(self._custom_overflow_append)
+                    for i in xrange(count):
+                        overflow_items.append(self._custom_overflow_append[i])
+
+                    res = self._art.ShowDropDown(self, overflow_items)
+                    self._overflow_state = 0
+                    self.Refresh(False)
+                    if res != -1:
+                        e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, res)
+                        e.SetEventObject(self)
+                        if not self.GetParent().ProcessEvent(e):
+                            tool = self.FindTool(res)
+                            if tool:
+                                state = (tool.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
+                                self.ToggleTool(res, not state)
+                    
+                return
+            
+        self._dragging = False
+        self._action_pos = wx.Point(*event.GetPosition())
+        self._action_item = self.FindToolForPosition(*event.GetPosition())
+
+        if self._action_item:
+        
+            if self._action_item.state & AUI_BUTTON_STATE_DISABLED:
+            
+                self._action_pos = wx.Point(-1, -1)
+                self._action_item = None
+                return
+            
+            self.SetPressedItem(self._action_item)
+
+            # fire the tool dropdown event
+            e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, self._action_item.id)
+            e.SetEventObject(self)
+            e.SetToolId(self._action_item.id)
+            e.SetDropDownClicked(False)
+
+            mouse_x, mouse_y = event.GetX(), event.GetY()
+            rect = wx.Rect(*self._action_item.sizer_item.GetRect())
+
+            if self._action_item.dropdown:
+                if (self._action_item.orientation == AUI_TBTOOL_HORIZONTAL and \
+                    mouse_x >= (rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1) and \
+                    mouse_x < (rect.x+rect.width)) or \
+                    (self._action_item.orientation != AUI_TBTOOL_HORIZONTAL and \
+                     mouse_y >= (rect.y+rect.height-BUTTON_DROPDOWN_WIDTH-1) and \
+                     mouse_y < (rect.y+rect.height)):
+                    
+                    e.SetDropDownClicked(True)            
+            
+            e.SetClickPoint(event.GetPosition())
+            e.SetItemRect(rect)
+            self.ProcessEvent(e)
+            self.DoIdleUpdate()
+        
+
+    def OnLeftUp(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_UP`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        self.SetPressedItem(None)
+
+        hit_item = self.FindToolForPosition(*event.GetPosition())
+        
+        if hit_item and not hit_item.state & AUI_BUTTON_STATE_DISABLED:
+            self.SetHoverItem(hit_item)
+
+        if self._dragging:
+            # reset drag and drop member variables
+            self._dragging = False
+            self._action_pos = wx.Point(-1, -1)
+            self._action_item = None
+        
+        else:
+
+            if self._action_item and hit_item == self._action_item:
+                self.SetToolTipString("")
+
+                if hit_item.kind in [ITEM_CHECK, ITEM_RADIO]:
+                    toggle = not (self._action_item.state & AUI_BUTTON_STATE_CHECKED)
+                    self.ToggleTool(self._action_item.id, toggle)
+
+                    # repaint immediately
+                    self.Refresh(False)
+                    self.Update()
+                    
+                    e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._action_item.id)
+                    e.SetEventObject(self)
+                    e.SetInt(toggle)
+                    self._action_pos = wx.Point(-1, -1)
+                    self._action_item = None
+                    
+                    self.ProcessEvent(e)
+                    self.DoIdleUpdate()
+                    
+                else:
+
+                    if self._action_item.id == ID_RESTORE_FRAME:
+                        # find aui manager
+                        manager = self.GetAuiManager()
+
+                        if not manager:
+                            return
+
+                        pane = manager.GetPane(self)
+                        e = framemanager.AuiManagerEvent(framemanager.wxEVT_AUI_PANE_MIN_RESTORE)
+
+                        e.SetManager(manager)
+                        e.SetPane(pane)
+
+                        manager.ProcessEvent(e)
+                        self.DoIdleUpdate()
+
+                    else:
+
+                        e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._action_item.id)
+                        e.SetEventObject(self)
+                        self.ProcessEvent(e)
+                        self.DoIdleUpdate()
+                
+        # reset drag and drop member variables
+        self._dragging = False
+        self._action_pos = wx.Point(-1, -1)
+        self._action_item = None
+
+
+    def OnRightDown(self, event):
+        """
+        Handles the ``wx.EVT_RIGHT_DOWN`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
+
+        if self._gripper_sizer_item:
+            gripper_rect = self._gripper_sizer_item.GetRect()
+            if gripper_rect.Contains(event.GetPosition()):
+                return
+        
+        if self._overflow_sizer_item:
+        
+            dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
+            if dropdown_size > 0 and event.GetX() > cli_rect.width - dropdown_size and \
+               event.GetY() >= 0 and event.GetY() < cli_rect.height and self._art:
+                return
+            
+        self._action_pos = wx.Point(*event.GetPosition())
+        self._action_item = self.FindToolForPosition(*event.GetPosition())
+
+        if self._action_item:
+            if self._action_item.state & AUI_BUTTON_STATE_DISABLED:
+            
+                self._action_pos = wx.Point(-1, -1)
+                self._action_item = None
+                return
+
+
+    def OnRightUp(self, event):
+        """
+        Handles the ``wx.EVT_RIGHT_UP`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        hit_item = self.FindToolForPosition(*event.GetPosition())
+
+        if self._action_item and hit_item == self._action_item:
+            
+            e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, self._action_item.id)
+            e.SetEventObject(self)
+            e.SetToolId(self._action_item.id)
+            e.SetClickPoint(self._action_pos)
+            self.ProcessEvent(e)
+            self.DoIdleUpdate()
+            
+        else:
+        
+            # right-clicked on the invalid area of the toolbar
+            e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, -1)
+            e.SetEventObject(self)
+            e.SetToolId(-1)
+            e.SetClickPoint(self._action_pos)
+            self.ProcessEvent(e)
+            self.DoIdleUpdate()
+        
+        # reset member variables
+        self._action_pos = wx.Point(-1, -1)
+        self._action_item = None
+
+
+    def OnMiddleDown(self, event):
+        """
+        Handles the ``wx.EVT_MIDDLE_DOWN`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
+
+        if self._gripper_sizer_item:
+        
+            gripper_rect = self._gripper_sizer_item.GetRect()
+            if gripper_rect.Contains(event.GetPosition()):
+                return
+        
+        if self._overflow_sizer_item:
+        
+            dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
+            if dropdown_size > 0 and event.GetX() > cli_rect.width - dropdown_size and \
+               event.GetY() >= 0 and event.GetY() < cli_rect.height and self._art:            
+                return
+            
+        self._action_pos = wx.Point(*event.GetPosition())
+        self._action_item = self.FindToolForPosition(*event.GetPosition())
+
+        if self._action_item:
+            if self._action_item.state & AUI_BUTTON_STATE_DISABLED:
+            
+                self._action_pos = wx.Point(-1, -1)
+                self._action_item = None
+                return
+
+
+    def OnMiddleUp(self, event):
+        """
+        Handles the ``wx.EVT_MIDDLE_UP`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        hit_item = self.FindToolForPosition(*event.GetPosition())
+
+        if self._action_item and hit_item == self._action_item:        
+            if hit_item.kind == ITEM_NORMAL:
+            
+                e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, self._action_item.id)
+                e.SetEventObject(self)
+                e.SetToolId(self._action_item.id)
+                e.SetClickPoint(self._action_pos)
+                self.ProcessEvent(e)
+                self.DoIdleUpdate()
+            
+        # reset member variables
+        self._action_pos = wx.Point(-1, -1)
+        self._action_item = None
+
+
+    def OnMotion(self, event):
+        """
+        Handles the ``wx.EVT_MOTION`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+        
+        # start a drag event
+        if not self._dragging and self._action_item != None and self._action_pos != wx.Point(-1, -1) and \
+           abs(event.GetX() - self._action_pos.x) + abs(event.GetY() - self._action_pos.y) > 5:
+        
+            self.SetToolTipString("")
+            self._dragging = True
+
+            e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, self.GetId())
+            e.SetEventObject(self)
+            e.SetToolId(self._action_item.id)
+            self.ProcessEvent(e)
+            self.DoIdleUpdate()
+            return
+        
+        hit_item = self.FindToolForPosition(*event.GetPosition())
+        
+        if hit_item:        
+            if not hit_item.state & AUI_BUTTON_STATE_DISABLED:
+                self.SetHoverItem(hit_item)
+            else:
+                self.SetHoverItem(None)
+        
+        else:        
+            # no hit item, remove any hit item
+            self.SetHoverItem(hit_item)
+        
+        # figure out tooltips
+        packing_hit_item = self.FindToolForPositionWithPacking(*event.GetPosition())
+        
+        if packing_hit_item:
+        
+            if packing_hit_item != self._tip_item:
+                self._tip_item = packing_hit_item
+
+                if packing_hit_item.short_help != "":
+                    self.StartPreviewTimer()
+                    self.SetToolTipString(packing_hit_item.short_help)
+                else:
+                    self.SetToolTipString("")
+                    self.StopPreviewTimer()
+            
+        else:
+        
+            self.SetToolTipString("")
+            self._tip_item = None
+            self.StopPreviewTimer()
+        
+        # if we've pressed down an item and we're hovering
+        # over it, make sure it's state is set to pressed
+        if self._action_item:
+        
+            if self._action_item == hit_item:
+                self.SetPressedItem(self._action_item)
+            else:
+                self.SetPressedItem(None)
+        
+        # figure out the dropdown button state (are we hovering or pressing it?)
+        self.RefreshOverflowState()
+
+
+    def OnLeaveWindow(self, event):
+        """
+        Handles the ``wx.EVT_LEAVE_WINDOW`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.        
+        """
+
+        self.RefreshOverflowState()
+        self.SetHoverItem(None)
+        self.SetPressedItem(None)
+
+        self._tip_item = None
+        self.StopPreviewTimer()
+
+
+    def OnSetCursor(self, event):
+        """
+        Handles the ``wx.EVT_SET_CURSOR`` event for L{AuiToolBar}.
+
+        :param `event`: a `wx.SetCursorEvent` event to be processed.        
+        """
+        
+        cursor = wx.NullCursor
+
+        if self._gripper_sizer_item:
+        
+            gripper_rect = self._gripper_sizer_item.GetRect()
+            if gripper_rect.Contains((event.GetX(), event.GetY())):
+                cursor = wx.StockCursor(wx.CURSOR_SIZING)
+            
+        event.SetCursor(cursor)
+
+
+    def OnCustomRender(self, dc, item, rect):
+        """
+        Handles custom render for single L{AuiToolBar} items.
+        
+        :param `dc`: a `wx.DC` device context;
+        :param `item`: an instance of L{AuiToolBarItem};
+        :param `rect`: the toolbar item rect.
+
+        :note: This method must be overridden to provide custom rendering of items.
+        """
+        
+        pass
+
+
+    def IsPaneMinimized(self):
+        """ Returns whether this L{AuiToolBar} contains a minimized pane tool. """
+        
+        manager = self.GetAuiManager()
+        if not manager:
+            return False
+        
+        if manager.GetAGWFlags() & AUI_MGR_PREVIEW_MINIMIZED_PANES == 0:
+            # No previews here
+            return False
+
+        self_name = manager.GetPane(self).name
+        
+        if not self_name.endswith("_min"):
+            # Wrong tool name
+            return False
+
+        return self_name[0:-4]
+    
+        
+    def StartPreviewTimer(self):
+        """ Starts a timer in L{AuiManager} to slide-in/slide-out the minimized pane. """
+
+        self_name = self.IsPaneMinimized()
+        if not self_name:
+            return
+
+        manager = self.GetAuiManager()        
+        manager.StartPreviewTimer(self)
+
+
+    def StopPreviewTimer(self):
+        """ Stops a timer in L{AuiManager} to slide-in/slide-out the minimized pane. """
+
+        self_name = self.IsPaneMinimized()
+        if not self_name:
+            return
+
+        manager = self.GetAuiManager()        
+        manager.StopPreviewTimer()
+            
diff --git a/aui/auibook.py b/aui/auibook.py
new file mode 100644 (file)
index 0000000..62ae00c
--- /dev/null
@@ -0,0 +1,5737 @@
+"""
+auibook contains a notebook control which implements many features common in
+applications with dockable panes. Specifically, L{AuiNotebook} implements functionality
+which allows the user to rearrange tab order via drag-and-drop, split the tab window
+into many different splitter configurations, and toggle through different themes to
+customize the control's look and feel.
+
+An effort has been made to try to maintain an API as similar to that of `wx.Notebook`.
+
+The default theme that is used is L{AuiDefaultTabArt}, which provides a modern, glossy
+look and feel. The theme can be changed by calling L{AuiNotebook.SetArtProvider}.
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+import types
+import datetime
+
+from wx.lib.expando import ExpandoTextCtrl
+
+import framemanager
+import tabart as TA
+
+from aui_utilities import LightColour, MakeDisabledBitmap, TabDragImage
+from aui_utilities import TakeScreenShot, RescaleScreenShot
+
+from aui_constants import *
+
+# AuiNotebook events
+wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BUTTON = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_END_DRAG = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_DOWN = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_UP = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_DOWN = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_UP = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK = wx.NewEventType()
+
+# Define a new event for a drag cancelled
+wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG = wx.NewEventType()
+
+# Define events for editing a tab label
+wxEVT_COMMAND_AUINOTEBOOK_BEGIN_LABEL_EDIT = wx.NewEventType()
+wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT = wx.NewEventType()
+
+# Create event binders
+EVT_AUINOTEBOOK_PAGE_CLOSE = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 1)
+""" A tab in `AuiNotebook` is being closed. Can be vetoed by calling `Veto()`. """
+EVT_AUINOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 1)
+""" A tab in `AuiNotebook` has been closed. """
+EVT_AUINOTEBOOK_PAGE_CHANGED = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 1)
+""" The page selection was changed. """
+EVT_AUINOTEBOOK_PAGE_CHANGING = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 1)
+""" The page selection is being changed. """
+EVT_AUINOTEBOOK_BUTTON = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 1)
+""" The user clicked on a button in the `AuiNotebook` tab area. """
+EVT_AUINOTEBOOK_BEGIN_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 1)
+""" A drag-and-drop operation on a notebook tab has started. """
+EVT_AUINOTEBOOK_END_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 1)
+""" A drag-and-drop operation on a notebook tab has finished. """
+EVT_AUINOTEBOOK_DRAG_MOTION = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 1)
+""" A drag-and-drop operation on a notebook tab is ongoing. """
+EVT_AUINOTEBOOK_ALLOW_DND = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 1)
+""" Fires an event asking if it is OK to drag and drop a tab. """
+EVT_AUINOTEBOOK_DRAG_DONE = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 1)
+""" A drag-and-drop operation on a notebook tab has finished. """
+EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 1)
+""" The user clicked with the middle mouse button on a tab. """
+EVT_AUINOTEBOOK_TAB_MIDDLE_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 1)
+""" The user clicked with the middle mouse button on a tab. """
+EVT_AUINOTEBOOK_TAB_RIGHT_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 1)
+""" The user clicked with the right mouse button on a tab. """
+EVT_AUINOTEBOOK_TAB_RIGHT_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 1)
+""" The user clicked with the right mouse button on a tab. """
+EVT_AUINOTEBOOK_BG_MIDDLE_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_DOWN, 1)
+""" The user middle-clicked in the tab area but not over a tab or a button. """
+EVT_AUINOTEBOOK_BG_MIDDLE_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_UP, 1)
+""" The user middle-clicked in the tab area but not over a tab or a button. """
+EVT_AUINOTEBOOK_BG_RIGHT_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_DOWN, 1)
+""" The user right-clicked in the tab area but not over a tab or a button. """
+EVT_AUINOTEBOOK_BG_RIGHT_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_UP, 1)
+""" The user right-clicked in the tab area but not over a tab or a button. """
+EVT_AUINOTEBOOK_BG_DCLICK = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 1)
+""" The user left-clicked on the tab area not occupied by `AuiNotebook` tabs. """
+EVT_AUINOTEBOOK_CANCEL_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG, 1)
+""" A drag and drop operation has been cancelled. """
+EVT_AUINOTEBOOK_TAB_DCLICK = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK, 1)
+""" The user double-clicked with the left mouse button on a tab. """
+EVT_AUINOTEBOOK_BEGIN_LABEL_EDIT = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_LABEL_EDIT, 1)
+""" The user double-clicked with the left mouse button on a tab which text is editable. """
+EVT_AUINOTEBOOK_END_LABEL_EDIT = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT, 1)
+""" The user finished editing a tab label. """
+
+
+# -----------------------------------------------------------------------------
+# Auxiliary class: TabTextCtrl
+# This is the temporary ExpandoTextCtrl created when you edit the text of a tab
+# -----------------------------------------------------------------------------
+
+class TabTextCtrl(ExpandoTextCtrl):
+    """ Control used for in-place edit. """
+
+    def __init__(self, owner, tab, page_index):
+        """
+        Default class constructor.
+        For internal use: do not call it in your code!
+
+        :param `owner`: the L{AuiTabCtrl} owning the tab;
+        :param `tab`: the actual L{AuiNotebookPage} tab;
+        :param `page_index`: the L{AuiNotebook} page index for the tab.
+        """
+
+        self._owner = owner
+        self._tabEdited = tab
+        self._pageIndex = page_index
+        self._startValue = tab.caption
+        self._finished = False
+        self._aboutToFinish = False
+        self._currentValue = self._startValue
+
+        x, y, w, h = self._tabEdited.rect
+
+        wnd = self._tabEdited.control
+        if wnd:
+            x += wnd.GetSize()[0] + 2
+            h = 0
+
+        image_h = 0
+        image_w = 0
+
+        image = tab.bitmap
+
+        if image.IsOk():
+            image_w, image_h = image.GetWidth(), image.GetHeight()
+            image_w += 6
+
+        dc = wx.ClientDC(self._owner)
+        h = max(image_h, dc.GetMultiLineTextExtent(tab.caption)[1])
+        h = h + 2
+
+        # FIXME: what are all these hardcoded 4, 8 and 11s really?
+        x += image_w
+        w -= image_w + 4
+
+        y = (self._tabEdited.rect.height - h)/2 + 1
+
+        expandoStyle = wx.WANTS_CHARS
+        if wx.Platform in ["__WXGTK__", "__WXMAC__"]:
+            expandoStyle |= wx.SIMPLE_BORDER
+            xSize, ySize = w + 2, h
+        else:
+            expandoStyle |= wx.SUNKEN_BORDER
+            xSize, ySize = w + 2, h+2
+
+        ExpandoTextCtrl.__init__(self, self._owner, wx.ID_ANY, self._startValue,
+                                 wx.Point(x, y), wx.Size(xSize, ySize),
+                                 expandoStyle)
+
+        if wx.Platform == "__WXMAC__":
+            self.SetFont(owner.GetFont())
+            bs = self.GetBestSize()
+            self.SetSize((-1, bs.height))
+
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+
+
+    def AcceptChanges(self):
+        """ Accepts/refuses the changes made by the user. """
+
+        value = self.GetValue()
+        notebook = self._owner.GetParent()
+
+        if value == self._startValue:
+            # nothing changed, always accept
+            # when an item remains unchanged, the owner
+            # needs to be notified that the user decided
+            # not to change the tree item label, and that
+            # the edit has been cancelled
+            notebook.OnRenameCancelled(self._pageIndex)
+            return True
+
+        if not notebook.OnRenameAccept(self._pageIndex, value):
+            # vetoed by the user
+            return False
+
+        # accepted, do rename the item
+        notebook.SetPageText(self._pageIndex, value)
+
+        return True
+
+
+    def Finish(self):
+        """ Finish editing. """
+
+        if not self._finished:
+
+            notebook = self._owner.GetParent()
+
+            self._finished = True
+            self._owner.SetFocus()
+            notebook.ResetTextControl()
+
+
+    def OnChar(self, event):
+        """
+        Handles the ``wx.EVT_CHAR`` event for L{TabTextCtrl}.
+
+        :param `event`: a `wx.KeyEvent` event to be processed.
+        """
+
+        keycode = event.GetKeyCode()
+        shiftDown = event.ShiftDown()
+
+        if keycode == wx.WXK_RETURN:
+            if shiftDown and self._tabEdited.IsMultiline():
+                event.Skip()
+            else:
+                self._aboutToFinish = True
+                self.SetValue(self._currentValue)
+                # Notify the owner about the changes
+                self.AcceptChanges()
+                # Even if vetoed, close the control (consistent with MSW)
+                wx.CallAfter(self.Finish)
+
+        elif keycode == wx.WXK_ESCAPE:
+            self.StopEditing()
+
+        else:
+            event.Skip()
+
+
+    def OnKeyUp(self, event):
+        """
+        Handles the ``wx.EVT_KEY_UP`` event for L{TabTextCtrl}.
+
+        :param `event`: a `wx.KeyEvent` event to be processed.
+        """
+
+        if not self._finished:
+
+            # auto-grow the textctrl:
+            mySize = self.GetSize()
+
+            dc = wx.ClientDC(self)
+            sx, sy, dummy = dc.GetMultiLineTextExtent(self.GetValue() + "M")
+
+            self.SetSize((sx, -1))
+            self._currentValue = self.GetValue()
+
+        event.Skip()
+
+
+    def OnKillFocus(self, event):
+        """
+        Handles the ``wx.EVT_KILL_FOCUS`` event for L{TabTextCtrl}.
+
+        :param `event`: a `wx.FocusEvent` event to be processed.
+        """
+
+        if not self._finished and not self._aboutToFinish:
+
+            # We must finish regardless of success, otherwise we'll get
+            # focus problems:
+            if not self.AcceptChanges():
+                self._owner.GetParent().OnRenameCancelled(self._pageIndex)
+
+        # We must let the native text control handle focus, too, otherwise
+        # it could have problems with the cursor (e.g., in wxGTK).
+        event.Skip()
+        wx.CallAfter(self._owner.GetParent().ResetTextControl)
+
+
+    def StopEditing(self):
+        """ Suddenly stops the editing. """
+
+        self._owner.GetParent().OnRenameCancelled(self._pageIndex)
+        self.Finish()
+
+
+    def item(self):
+        """ Returns the item currently edited. """
+
+        return self._tabEdited
+
+
+# ----------------------------------------------------------------------
+
+class AuiNotebookPage(object):
+    """
+    A simple class which holds information about tab captions, bitmaps and
+    colours.
+    """
+
+    def __init__(self):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+        """
+
+        self.window = None              # page's associated window
+        self.caption = ""               # caption displayed on the tab
+        self.bitmap = wx.NullBitmap     # tab's bitmap
+        self.dis_bitmap = wx.NullBitmap # tab's disabled bitmap
+        self.rect = wx.Rect()           # tab's hit rectangle
+        self.active = False             # True if the page is currently active
+        self.enabled = True             # True if the page is currently enabled
+        self.hasCloseButton = True      # True if the page has a close button using the style
+                                        # AUI_NB_CLOSE_ON_ALL_TABS
+        self.control = None             # A control can now be inside a tab
+        self.renamable = False          # If True, a tab can be renamed by a left double-click
+
+        self.text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT)
+
+        self.access_time = datetime.datetime.now() # Last time this page was selected
+
+
+    def IsMultiline(self):
+        """ Returns whether the tab contains multiline text. """
+
+        return "\n" in self.caption
+
+
+# ----------------------------------------------------------------------
+
+class AuiTabContainerButton(object):
+    """
+    A simple class which holds information about tab buttons and their state.
+    """
+
+    def __init__(self):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+        """
+
+        self.id = -1                                      # button's id
+        self.cur_state = AUI_BUTTON_STATE_NORMAL          # current state (normal, hover, pressed, etc.)
+        self.location = wx.LEFT                           # buttons location (wxLEFT, wxRIGHT, or wxCENTER)
+        self.bitmap = wx.NullBitmap                       # button's hover bitmap
+        self.dis_bitmap = wx.NullBitmap                   # button's disabled bitmap
+        self.rect = wx.Rect()                             # button's hit rectangle
+
+
+# ----------------------------------------------------------------------
+
+class CommandNotebookEvent(wx.PyCommandEvent):
+    """ A specialized command event class for events sent by L{AuiNotebook} . """
+
+    def __init__(self, command_type=None, win_id=0):
+        """
+        Default class constructor.
+
+        :param `command_type`: the event kind or an instance of `wx.PyCommandEvent`.
+        :param `win_id`: the window identification number.
+        """
+
+        if type(command_type) == types.IntType:
+            wx.PyCommandEvent.__init__(self, command_type, win_id)
+        else:
+            wx.PyCommandEvent.__init__(self, command_type.GetEventType(), command_type.GetId())
+
+        self.old_selection = -1
+        self.selection = -1
+        self.drag_source = None
+        self.dispatched = 0
+        self.label = ""
+        self.editCancelled = False
+
+
+    def SetSelection(self, s):
+        """
+        Sets the selection member variable.
+
+        :param `s`: the new selection.
+        """
+
+        self.selection = s
+        self._commandInt = s
+
+
+    def GetSelection(self):
+        """ Returns the currently selected page, or -1 if none was selected. """
+
+        return self.selection
+
+
+    def SetOldSelection(self, s):
+        """
+        Sets the id of the page selected before the change.
+
+        :param `s`: the old selection.
+        """
+
+        self.old_selection = s
+
+
+    def GetOldSelection(self):
+        """
+        Returns the page that was selected before the change, or -1 if none was
+        selected.
+        """
+
+        return self.old_selection
+
+
+    def SetDragSource(self, s):
+        """
+        Sets the drag and drop source.
+
+        :param `s`: the drag source.
+        """
+
+        self.drag_source = s
+
+
+    def GetDragSource(self):
+        """ Returns the drag and drop source. """
+
+        return self.drag_source
+
+
+    def SetDispatched(self, b):
+        """
+        Sets the event as dispatched (used for automatic L{AuiNotebook} ).
+
+        :param `b`: whether the event was dispatched or not.
+        """
+
+        self.dispatched = b
+
+
+    def GetDispatched(self):
+        """ Returns whether the event was dispatched (used for automatic L{AuiNotebook} ). """
+
+        return self.dispatched
+
+
+    def IsEditCancelled(self):
+        """ Returns the edit cancel flag (for ``EVT_AUINOTEBOOK_BEGIN`` | ``END_LABEL_EDIT`` only)."""
+
+        return self.editCancelled
+
+
+    def SetEditCanceled(self, editCancelled):
+        """
+        Sets the edit cancel flag (for ``EVT_AUINOTEBOOK_BEGIN`` | ``END_LABEL_EDIT`` only).
+
+        :param `editCancelled`: whether the editing action has been cancelled or not.
+        """
+
+        self.editCancelled = editCancelled
+
+
+    def GetLabel(self):
+        """Returns the label-itemtext (for ``EVT_AUINOTEBOOK_BEGIN`` | ``END_LABEL_EDIT`` only)."""
+
+        return self.label
+
+
+    def SetLabel(self, label):
+        """
+        Sets the label. Useful only for ``EVT_AUINOTEBOOK_END_LABEL_EDIT``.
+
+        :param `label`: the new label.
+        """
+
+        self.label = label
+
+
+# ----------------------------------------------------------------------
+
+class AuiNotebookEvent(CommandNotebookEvent):
+    """ A specialized command event class for events sent by L{AuiNotebook}. """
+
+    def __init__(self, command_type=None, win_id=0):
+        """
+        Default class constructor.
+
+        :param `command_type`: the event kind or an instance of `wx.PyCommandEvent`.
+        :param `win_id`: the window identification number.
+        """
+
+        CommandNotebookEvent.__init__(self, command_type, win_id)
+
+        if type(command_type) == types.IntType:
+            self.notify = wx.NotifyEvent(command_type, win_id)
+        else:
+            self.notify = wx.NotifyEvent(command_type.GetEventType(), command_type.GetId())
+
+
+    def GetNotifyEvent(self):
+        """ Returns the actual `wx.NotifyEvent`. """
+
+        return self.notify
+
+
+    def IsAllowed(self):
+        """ Returns whether the event is allowed or not. """
+
+        return self.notify.IsAllowed()
+
+
+    def Veto(self):
+        """
+        Prevents the change announced by this event from happening.
+
+        It is in general a good idea to notify the user about the reasons for
+        vetoing the change because otherwise the applications behaviour (which
+        just refuses to do what the user wants) might be quite surprising.
+        """
+
+        self.notify.Veto()
+
+
+    def Allow(self):
+        """
+        This is the opposite of L{Veto}: it explicitly allows the event to be
+        processed. For most events it is not necessary to call this method as the
+        events are allowed anyhow but some are forbidden by default (this will
+        be mentioned in the corresponding event description).
+        """
+
+        self.notify.Allow()
+
+
+# ---------------------------------------------------------------------------- #
+# Class TabNavigatorWindow
+# ---------------------------------------------------------------------------- #
+
+class TabNavigatorWindow(wx.Dialog):
+    """
+    This class is used to create a modal dialog that enables "Smart Tabbing",
+    similar to what you would get by hitting ``Alt`` + ``Tab`` on Windows.
+    """
+
+    def __init__(self, parent=None, icon=None):
+        """
+        Default class constructor. Used internally.
+
+        :param `parent`: the L{TabNavigatorWindow} parent;
+        :param `icon`: the L{TabNavigatorWindow} icon.
+        """
+
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, "", style=0)
+
+        self._selectedItem = -1
+        self._indexMap = []
+
+        if icon is None:
+            self._bmp = Mondrian.GetBitmap()
+        else:
+            self._bmp = icon
+
+        if self._bmp.GetSize() != (16, 16):
+            img = self._bmp.ConvertToImage()
+            img.Rescale(16, 16, wx.IMAGE_QUALITY_HIGH)
+            self._bmp = wx.BitmapFromImage(img)
+
+        sz = wx.BoxSizer(wx.VERTICAL)
+
+        self._listBox = wx.ListBox(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, 150), [], wx.LB_SINGLE | wx.NO_BORDER)
+
+        mem_dc = wx.MemoryDC()
+        mem_dc.SelectObject(wx.EmptyBitmap(1,1))
+        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        font.SetWeight(wx.BOLD)
+        mem_dc.SetFont(font)
+
+        panelHeight = mem_dc.GetCharHeight()
+        panelHeight += 4 # Place a spacer of 2 pixels
+
+        # Out signpost bitmap is 24 pixels
+        if panelHeight < 24:
+            panelHeight = 24
+
+        self._panel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, panelHeight))
+
+        sz.Add(self._panel)
+        sz.Add(self._listBox, 1, wx.EXPAND)
+
+        self.SetSizer(sz)
+
+        # Connect events to the list box
+        self._listBox.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        self._listBox.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
+        self._listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnItemSelected)
+
+        # Connect paint event to the panel
+        self._panel.Bind(wx.EVT_PAINT, self.OnPanelPaint)
+        self._panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnPanelEraseBg)
+
+        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
+        self._listBox.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
+        self.PopulateListControl(parent)
+
+        self.GetSizer().Fit(self)
+        self.GetSizer().SetSizeHints(self)
+        self.GetSizer().Layout()
+        self.Centre()
+
+        # Set focus on the list box to avoid having to click on it to change
+        # the tab selection under GTK.
+        self._listBox.SetFocus()
+
+
+    def OnKeyUp(self, event):
+        """
+        Handles the ``wx.EVT_KEY_UP`` for the L{TabNavigatorWindow}.
+
+        :param `event`: a `wx.KeyEvent` event to be processed.
+        """
+
+        if event.GetKeyCode() == wx.WXK_CONTROL:
+            self.CloseDialog()
+
+
+    def OnNavigationKey(self, event):
+        """
+        Handles the ``wx.EVT_NAVIGATION_KEY`` for the L{TabNavigatorWindow}.
+
+        :param `event`: a `wx.NavigationKeyEvent` event to be processed.
+        """
+
+        selected = self._listBox.GetSelection()
+        bk = self.GetParent()
+        maxItems = bk.GetPageCount()
+
+        if event.GetDirection():
+
+            # Select next page
+            if selected == maxItems - 1:
+                itemToSelect = 0
+            else:
+                itemToSelect = selected + 1
+
+        else:
+
+            # Previous page
+            if selected == 0:
+                itemToSelect = maxItems - 1
+            else:
+                itemToSelect = selected - 1
+
+        self._listBox.SetSelection(itemToSelect)
+
+
+    def PopulateListControl(self, book):
+        """
+        Populates the L{TabNavigatorWindow} listbox with a list of tabs.
+
+        :param `book`: the actual L{AuiNotebook}.
+        """
+        # Index of currently selected page
+        selection = book.GetSelection()
+        # Total number of pages
+        count = book.GetPageCount()
+        # List of (index, AuiNotebookPage)
+        pages = list(enumerate(book.GetTabContainer().GetPages()))
+        if book.GetAGWWindowStyleFlag() & AUI_NB_ORDER_BY_ACCESS:
+            # Sort pages using last access time. Most recently used is the
+            # first in line
+            pages.sort(
+                key = lambda element: element[1].access_time,
+                reverse = True
+            )
+        else:
+            # Manually add the current selection as first item
+            # Remaining ones are added in the next loop
+            del pages[selection]
+            self._listBox.Append(book.GetPageText(selection))
+            self._indexMap.append(selection)
+
+        for (index, page) in pages:
+            self._listBox.Append(book.GetPageText(index))
+            self._indexMap.append(index)
+
+        # Select the next entry after the current selection
+        self._listBox.SetSelection(0)
+        dummy = wx.NavigationKeyEvent()
+        dummy.SetDirection(True)
+        self.OnNavigationKey(dummy)
+
+
+    def OnItemSelected(self, event):
+        """
+        Handles the ``wx.EVT_LISTBOX_DCLICK`` event for the wx.ListBox inside L{TabNavigatorWindow}.
+
+        :param `event`: a `wx.ListEvent` event to be processed.
+        """
+
+        self.CloseDialog()
+
+
+    def CloseDialog(self):
+        """ Closes the L{TabNavigatorWindow} dialog, setting selection in L{AuiNotebook}. """
+
+        bk = self.GetParent()
+        self._selectedItem = self._listBox.GetSelection()
+        self.EndModal(wx.ID_OK)
+
+
+    def GetSelectedPage(self):
+        """ Gets the page index that was selected when the dialog was closed. """
+
+        return self._indexMap[self._selectedItem]
+
+
+    def OnPanelPaint(self, event):
+        """
+        Handles the ``wx.EVT_PAINT`` event for L{TabNavigatorWindow} top panel.
+
+        :param `event`: a `wx.PaintEvent` event to be processed.
+        """
+
+        dc = wx.PaintDC(self._panel)
+        rect = self._panel.GetClientRect()
+
+        bmp = wx.EmptyBitmap(rect.width, rect.height)
+
+        mem_dc = wx.MemoryDC()
+        mem_dc.SelectObject(bmp)
+
+        endColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
+        startColour = LightColour(endColour, 50)
+        mem_dc.GradientFillLinear(rect, startColour, endColour, wx.SOUTH)
+
+        # Draw the caption title and place the bitmap
+        # get the bitmap optimal position, and draw it
+        bmpPt, txtPt = wx.Point(), wx.Point()
+        bmpPt.y = (rect.height - self._bmp.GetHeight())/2
+        bmpPt.x = 3
+        mem_dc.DrawBitmap(self._bmp, bmpPt.x, bmpPt.y, True)
+
+        # get the text position, and draw it
+        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        font.SetWeight(wx.BOLD)
+        mem_dc.SetFont(font)
+        fontHeight = mem_dc.GetCharHeight()
+
+        txtPt.x = bmpPt.x + self._bmp.GetWidth() + 4
+        txtPt.y = (rect.height - fontHeight)/2
+        mem_dc.SetTextForeground(wx.WHITE)
+        mem_dc.DrawText("Opened tabs:", txtPt.x, txtPt.y)
+        mem_dc.SelectObject(wx.NullBitmap)
+
+        dc.DrawBitmap(bmp, 0, 0)
+
+
+    def OnPanelEraseBg(self, event):
+        """
+        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{TabNavigatorWindow} top panel.
+
+        :param `event`: a `wx.EraseEvent` event to be processed.
+
+        :note: This is intentionally empty, to reduce flicker.
+        """
+
+        pass
+
+
+# ----------------------------------------------------------------------
+# -- AuiTabContainer class implementation --
+
+class AuiTabContainer(object):
+    """
+    AuiTabContainer is a class which contains information about each
+    tab. It also can render an entire tab control to a specified DC.
+    It's not a window class itself, because this code will be used by
+    the L{AuiManager}, where it is disadvantageous to have separate
+    windows for each tab control in the case of "docked tabs".
+
+    A derived class, L{AuiTabCtrl}, is an actual `wx.Window`-derived window
+    which can be used as a tab control in the normal sense.
+    """
+
+    def __init__(self, auiNotebook):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+
+        :param `auiNotebook`: the parent L{AuiNotebook} window.        
+        """
+
+        self._tab_offset = 0
+        self._agwFlags = 0
+        self._art = TA.AuiDefaultTabArt()
+
+        self._buttons = []
+        self._pages = []
+        self._tab_close_buttons = []
+
+        self._rect = wx.Rect()
+        self._auiNotebook = auiNotebook
+
+        self.AddButton(AUI_BUTTON_LEFT, wx.LEFT)
+        self.AddButton(AUI_BUTTON_RIGHT, wx.RIGHT)
+        self.AddButton(AUI_BUTTON_WINDOWLIST, wx.RIGHT)
+        self.AddButton(AUI_BUTTON_CLOSE, wx.RIGHT)
+
+
+    def SetArtProvider(self, art):
+        """
+        Instructs L{AuiTabContainer} to use art provider specified by parameter `art`
+        for all drawing calls. This allows plugable look-and-feel features.
+
+        :param `art`: an art provider.
+
+        :note: The previous art provider object, if any, will be deleted by L{AuiTabContainer}.
+        """
+
+        del self._art
+        self._art = art
+
+        if self._art:
+            self._art.SetAGWFlags(self._agwFlags)
+
+
+    def GetArtProvider(self):
+        """ Returns the current art provider being used. """
+
+        return self._art
+
+
+    def SetAGWFlags(self, agwFlags):
+        """
+        Sets the tab art flags.
+
+        :param `agwFlags`: a combination of the following values:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by L{AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
+         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
+         ==================================== ==================================
+
+        :todo: Implementation of flags ``AUI_NB_RIGHT`` and ``AUI_NB_LEFT``.
+
+        """
+
+        self._agwFlags = agwFlags
+
+        # check for new close button settings
+        self.RemoveButton(AUI_BUTTON_LEFT)
+        self.RemoveButton(AUI_BUTTON_RIGHT)
+        self.RemoveButton(AUI_BUTTON_WINDOWLIST)
+        self.RemoveButton(AUI_BUTTON_CLOSE)
+
+        if agwFlags & AUI_NB_SCROLL_BUTTONS:
+            self.AddButton(AUI_BUTTON_LEFT, wx.LEFT)
+            self.AddButton(AUI_BUTTON_RIGHT, wx.RIGHT)
+
+        if agwFlags & AUI_NB_WINDOWLIST_BUTTON:
+            self.AddButton(AUI_BUTTON_WINDOWLIST, wx.RIGHT)
+
+        if agwFlags & AUI_NB_CLOSE_BUTTON:
+            self.AddButton(AUI_BUTTON_CLOSE, wx.RIGHT)
+
+        if self._art:
+            self._art.SetAGWFlags(self._agwFlags)
+
+
+    def GetAGWFlags(self):
+        """
+        Returns the tab art flags.
+
+        See L{SetAGWFlags} for a list of possible return values.
+
+        :see: L{SetAGWFlags}
+        """
+
+        return self._agwFlags
+
+
+    def SetNormalFont(self, font):
+        """
+        Sets the normal font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._art.SetNormalFont(font)
+
+
+    def SetSelectedFont(self, font):
+        """
+        Sets the selected tab font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._art.SetSelectedFont(font)
+
+
+    def SetMeasuringFont(self, font):
+        """
+        Sets the font for calculating text measurements.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._art.SetMeasuringFont(font)
+
+
+    def SetTabRect(self, rect):
+        """
+        Sets the tab area rectangle.
+
+        :param `rect`: an instance of `wx.Rect`, specifying the available area for L{AuiTabContainer}.
+        """
+
+        self._rect = rect
+
+        if self._art:
+            minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth()
+            self._art.SetSizingInfo(rect.GetSize(), len(self._pages), minMaxTabWidth)
+
+
+    def AddPage(self, page, info):
+        """
+        Adds a page to the tab control.
+
+        :param `page`: the window associated with this tab;
+        :param `info`: an instance of L{AuiNotebookPage}.
+        """
+
+        page_info = info
+        page_info.window = page
+
+        self._pages.append(page_info)
+
+        # let the art provider know how many pages we have
+        if self._art:
+            minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth()
+            self._art.SetSizingInfo(self._rect.GetSize(), len(self._pages), minMaxTabWidth)
+
+        return True
+
+
+    def InsertPage(self, page, info, idx):
+        """
+        Inserts a page in the tab control in the position specified by `idx`.
+
+        :param `page`: the window associated with this tab;
+        :param `info`: an instance of L{AuiNotebookPage};
+        :param `idx`: the page insertion index.
+        """
+
+        page_info = info
+        page_info.window = page
+
+        if idx >= len(self._pages):
+            self._pages.append(page_info)
+        else:
+            self._pages.insert(idx, page_info)
+
+        # let the art provider know how many pages we have
+        if self._art:
+            minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth()
+            self._art.SetSizingInfo(self._rect.GetSize(), len(self._pages), minMaxTabWidth)
+
+        return True
+
+
+    def MovePage(self, page, new_idx):
+        """
+        Moves a page in a new position specified by `new_idx`.
+
+        :param `page`: the window associated with this tab;
+        :param `new_idx`: the new page position.
+        """
+
+        idx = self.GetIdxFromWindow(page)
+        if idx == -1:
+            return False
+
+        # get page entry, make a copy of it
+        p = self.GetPage(idx)
+
+        # remove old page entry
+        self.RemovePage(page)
+
+        # insert page where it should be
+        self.InsertPage(page, p, new_idx)
+
+        return True
+
+
+    def RemovePage(self, wnd):
+        """
+        Removes a page from the tab control.
+
+        :param `wnd`: an instance of `wx.Window`, a window associated with this tab.
+        """
+
+        minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth()
+
+        for page in self._pages:
+            if page.window == wnd:
+                self._pages.remove(page)
+                self._tab_offset = min(self._tab_offset, len(self._pages) - 1)
+
+                # let the art provider know how many pages we have
+                if self._art:
+                    self._art.SetSizingInfo(self._rect.GetSize(), len(self._pages), minMaxTabWidth)
+
+                return True
+
+        return False
+
+
+    def SetActivePage(self, wndOrInt):
+        """
+        Sets the L{AuiTabContainer} active page.
+
+        :param `wndOrInt`: an instance of `wx.Window` or an integer specifying a tab index.
+        """
+
+        if type(wndOrInt) == types.IntType:
+
+            if wndOrInt >= len(self._pages):
+                return False
+
+            wnd = self._pages[wndOrInt].window
+
+        else:
+            wnd = wndOrInt
+
+        found = False
+
+        for indx, page in enumerate(self._pages):
+            if page.window == wnd:
+                page.active = True
+                found = True
+            else:
+                page.active = False
+
+        return found
+
+
+    def SetNoneActive(self):
+        """ Sets all the tabs as inactive (non-selected). """
+
+        for page in self._pages:
+            page.active = False
+
+
+    def GetActivePage(self):
+        """ Returns the current selected tab or ``wx.NOT_FOUND`` if none is selected. """
+
+        for indx, page in enumerate(self._pages):
+            if page.active:
+                return indx
+
+        return wx.NOT_FOUND
+
+
+    def GetWindowFromIdx(self, idx):
+        """
+        Returns the window associated with the tab with index `idx`.
+
+        :param `idx`: the tab index.
+        """
+
+        if idx >= len(self._pages):
+            return None
+
+        return self._pages[idx].window
+
+
+    def GetIdxFromWindow(self, wnd):
+        """
+        Returns the tab index based on the window `wnd` associated with it.
+
+        :param `wnd`: an instance of `wx.Window`.
+        """
+
+        for indx, page in enumerate(self._pages):
+            if page.window == wnd:
+                return indx
+
+        return wx.NOT_FOUND
+
+
+    def GetPage(self, idx):
+        """
+        Returns the page specified by the given index.
+
+        :param `idx`: the tab index.
+        """
+
+        if idx < 0 or idx >= len(self._pages):
+            raise Exception("Invalid Page index")
+
+        return self._pages[idx]
+
+
+    def GetPages(self):
+        """ Returns a list of all the pages in this L{AuiTabContainer}. """
+
+        return self._pages
+
+
+    def GetPageCount(self):
+        """ Returns the number of pages in the L{AuiTabContainer}. """
+
+        return len(self._pages)
+
+
+    def GetEnabled(self, idx):
+        """
+        Returns whether a tab is enabled or not.
+
+        :param `idx`: the tab index.
+        """
+
+        if idx < 0 or idx >= len(self._pages):
+            return False
+
+        return self._pages[idx].enabled
+
+
+    def EnableTab(self, idx, enable=True):
+        """
+        Enables/disables a tab in the L{AuiTabContainer}.
+
+        :param `idx`: the tab index;
+        :param `enable`: ``True`` to enable a tab, ``False`` to disable it.
+        """
+
+        if idx < 0 or idx >= len(self._pages):
+            raise Exception("Invalid Page index")
+
+        self._pages[idx].enabled = enable
+        wnd = self.GetWindowFromIdx(idx)
+        wnd.Enable(enable)
+
+
+    def AddButton(self, id, location, normal_bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap):
+        """
+        Adds a button in the tab area.
+
+        :param `id`: the button identifier. This can be one of the following:
+
+         ==============================  =================================
+         Button Identifier               Description
+         ==============================  =================================
+         ``AUI_BUTTON_CLOSE``            Shows a close button on the tab area
+         ``AUI_BUTTON_WINDOWLIST``       Shows a window list button on the tab area
+         ``AUI_BUTTON_LEFT``             Shows a left button on the tab area
+         ``AUI_BUTTON_RIGHT``            Shows a right button on the tab area
+         ==============================  =================================
+
+        :param `location`: the button location. Can be ``wx.LEFT`` or ``wx.RIGHT``;
+        :param `normal_bitmap`: the bitmap for an enabled tab;
+        :param `disabled_bitmap`: the bitmap for a disabled tab.
+        """
+
+        button = AuiTabContainerButton()
+        button.id = id
+        button.bitmap = normal_bitmap
+        button.dis_bitmap = disabled_bitmap
+        button.location = location
+        button.cur_state = AUI_BUTTON_STATE_NORMAL
+
+        self._buttons.append(button)
+
+
+    def RemoveButton(self, id):
+        """
+        Removes a button from the tab area.
+
+        :param `id`: the button identifier. See L{AddButton} for a list of button identifiers.
+
+        :see: L{AddButton}
+        """
+
+        for button in self._buttons:
+            if button.id == id:
+                self._buttons.remove(button)
+                return
+
+
+    def GetTabOffset(self):
+        """ Returns the tab offset. """
+
+        return self._tab_offset
+
+
+    def SetTabOffset(self, offset):
+        """
+        Sets the tab offset.
+
+        :param `offset`: the tab offset.
+        """
+
+        self._tab_offset = offset
+
+
+    def MinimizeTabOffset(self, dc, wnd, max_width):
+        """
+        Minimize `self._tab_offset` to fit as many tabs as possible in the available space.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: an instance of `wx.Window`;
+        :param `max_width`: the maximum available width for the tabs.
+        """
+
+        total_width = 0
+
+        for i, page in reversed(list(enumerate(self._pages))):
+
+            tab_button = self._tab_close_buttons[i]
+            (tab_width, tab_height), x_extent = self._art.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, tab_button.cur_state, page.control)
+            total_width += tab_width
+
+            if total_width > max_width:
+
+                tab_offset = i + 1
+
+                if tab_offset < self._tab_offset and tab_offset < len(self._pages):
+                    self._tab_offset = tab_offset
+
+                break
+
+        if i == 0:
+            self._tab_offset = 0
+
+
+    def Render(self, raw_dc, wnd):
+        """
+        Renders the tab catalog to the specified `wx.DC`.
+
+        It is a virtual function and can be overridden to provide custom drawing
+        capabilities.
+
+        :param `raw_dc`: a `wx.DC` device context;
+        :param `wnd`: an instance of `wx.Window`.
+        """
+
+        if not raw_dc or not raw_dc.IsOk():
+            return
+
+        dc = wx.MemoryDC()
+
+        # use the same layout direction as the window DC uses to ensure that the
+        # text is rendered correctly
+        dc.SetLayoutDirection(raw_dc.GetLayoutDirection())
+
+        page_count = len(self._pages)
+        button_count = len(self._buttons)
+
+        # create off-screen bitmap
+        bmp = wx.EmptyBitmap(self._rect.GetWidth(), self._rect.GetHeight())
+        dc.SelectObject(bmp)
+
+        if not dc.IsOk():
+            return
+
+        # find out if size of tabs is larger than can be
+        # afforded on screen
+        total_width = visible_width = 0
+
+        for i in xrange(page_count):
+            page = self._pages[i]
+
+            # determine if a close button is on this tab
+            close_button = False
+            if (self._agwFlags & AUI_NB_CLOSE_ON_ALL_TABS and page.hasCloseButton) or \
+               (self._agwFlags & AUI_NB_CLOSE_ON_ACTIVE_TAB and page.active and page.hasCloseButton):
+
+                close_button = True
+
+            control = page.control
+            if control:
+                try:
+                    control.GetSize()
+                except wx.PyDeadObjectError:
+                    page.control = None
+
+            size, x_extent = self._art.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active,
+                                                  (close_button and [AUI_BUTTON_STATE_NORMAL] or \
+                                                   [AUI_BUTTON_STATE_HIDDEN])[0], page.control)
+
+            if i+1 < page_count:
+                total_width += x_extent
+            else:
+                total_width += size[0]
+
+            if i >= self._tab_offset:
+                if i+1 < page_count:
+                    visible_width += x_extent
+                else:
+                    visible_width += size[0]
+
+        if total_width > self._rect.GetWidth() or self._tab_offset != 0:
+
+            # show left/right buttons
+            for button in self._buttons:
+                if button.id == AUI_BUTTON_LEFT or \
+                   button.id == AUI_BUTTON_RIGHT:
+
+                    button.cur_state &= ~AUI_BUTTON_STATE_HIDDEN
+
+        else:
+
+            # hide left/right buttons
+            for button in self._buttons:
+                if button.id == AUI_BUTTON_LEFT or \
+                   button.id == AUI_BUTTON_RIGHT:
+
+                    button.cur_state |= AUI_BUTTON_STATE_HIDDEN
+
+        # determine whether left button should be enabled
+        for button in self._buttons:
+            if button.id == AUI_BUTTON_LEFT:
+                if self._tab_offset == 0:
+                    button.cur_state |= AUI_BUTTON_STATE_DISABLED
+                else:
+                    button.cur_state &= ~AUI_BUTTON_STATE_DISABLED
+
+            if button.id == AUI_BUTTON_RIGHT:
+                if visible_width < self._rect.GetWidth() - 16*button_count:
+                    button.cur_state |= AUI_BUTTON_STATE_DISABLED
+                else:
+                    button.cur_state &= ~AUI_BUTTON_STATE_DISABLED
+
+        # draw background
+        self._art.DrawBackground(dc, wnd, self._rect)
+
+        # draw buttons
+        left_buttons_width = 0
+        right_buttons_width = 0
+
+        # draw the buttons on the right side
+        offset = self._rect.x + self._rect.width
+
+        for i in xrange(button_count):
+            button = self._buttons[button_count - i - 1]
+
+            if button.location != wx.RIGHT:
+                continue
+            if button.cur_state & AUI_BUTTON_STATE_HIDDEN:
+                continue
+
+            button_rect = wx.Rect(*self._rect)
+            button_rect.SetY(1)
+            button_rect.SetWidth(offset)
+
+            button.rect = self._art.DrawButton(dc, wnd, button_rect, button, wx.RIGHT)
+
+            offset -= button.rect.GetWidth()
+            right_buttons_width += button.rect.GetWidth()
+
+        offset = 0
+
+        # draw the buttons on the left side
+        for i in xrange(button_count):
+            button = self._buttons[button_count - i - 1]
+
+            if button.location != wx.LEFT:
+                continue
+            if button.cur_state & AUI_BUTTON_STATE_HIDDEN:
+                continue
+
+            button_rect = wx.Rect(offset, 1, 1000, self._rect.height)
+
+            button.rect = self._art.DrawButton(dc, wnd, button_rect, button, wx.LEFT)
+
+            offset += button.rect.GetWidth()
+            left_buttons_width += button.rect.GetWidth()
+
+        offset = left_buttons_width
+
+        if offset == 0:
+            offset += self._art.GetIndentSize()
+
+        # prepare the tab-close-button array
+        # make sure tab button entries which aren't used are marked as hidden
+        for i in xrange(page_count, len(self._tab_close_buttons)):
+            self._tab_close_buttons[i].cur_state = AUI_BUTTON_STATE_HIDDEN
+
+        # make sure there are enough tab button entries to accommodate all tabs
+        while len(self._tab_close_buttons) < page_count:
+            tempbtn = AuiTabContainerButton()
+            tempbtn.id = AUI_BUTTON_CLOSE
+            tempbtn.location = wx.CENTER
+            tempbtn.cur_state = AUI_BUTTON_STATE_HIDDEN
+            self._tab_close_buttons.append(tempbtn)
+
+        # buttons before the tab offset must be set to hidden
+        for i in xrange(self._tab_offset):
+            self._tab_close_buttons[i].cur_state = AUI_BUTTON_STATE_HIDDEN
+            if self._pages[i].control:
+                if self._pages[i].control.IsShown():
+                    self._pages[i].control.Hide()
+
+        self.MinimizeTabOffset(dc, wnd, self._rect.GetWidth() - right_buttons_width - offset - 2)
+
+        # draw the tabs
+        active = 999
+        active_offset = 0
+
+        rect = wx.Rect(*self._rect)
+        rect.y = 0
+        rect.height = self._rect.height
+
+        for i in xrange(self._tab_offset, page_count):
+
+            page = self._pages[i]
+            tab_button = self._tab_close_buttons[i]
+
+            # determine if a close button is on this tab
+            if (self._agwFlags & AUI_NB_CLOSE_ON_ALL_TABS and page.hasCloseButton) or \
+               (self._agwFlags & AUI_NB_CLOSE_ON_ACTIVE_TAB and page.active and page.hasCloseButton):
+
+                if tab_button.cur_state == AUI_BUTTON_STATE_HIDDEN:
+
+                    tab_button.id = AUI_BUTTON_CLOSE
+                    tab_button.cur_state = AUI_BUTTON_STATE_NORMAL
+                    tab_button.location = wx.CENTER
+
+            else:
+
+                tab_button.cur_state = AUI_BUTTON_STATE_HIDDEN
+
+            rect.x = offset
+            rect.width = self._rect.width - right_buttons_width - offset - 2
+
+            if rect.width <= 0:
+                break
+
+            page.rect, tab_button.rect, x_extent = self._art.DrawTab(dc, wnd, page, rect, tab_button.cur_state)
+
+            if page.active:
+                active = i
+                active_offset = offset
+                active_rect = wx.Rect(*rect)
+
+            offset += x_extent
+
+        lenPages = len(self._pages)
+        # make sure to deactivate buttons which are off the screen to the right
+        for j in xrange(i+1, len(self._tab_close_buttons)):
+            self._tab_close_buttons[j].cur_state = AUI_BUTTON_STATE_HIDDEN
+            if j > 0 and j <= lenPages:
+                if self._pages[j-1].control:
+                    if self._pages[j-1].control.IsShown():
+                        self._pages[j-1].control.Hide()
+
+        # draw the active tab again so it stands in the foreground
+        if active >= self._tab_offset and active < len(self._pages):
+
+            page = self._pages[active]
+            tab_button = self._tab_close_buttons[active]
+
+            rect.x = active_offset
+            dummy = self._art.DrawTab(dc, wnd, page, active_rect, tab_button.cur_state)
+
+        raw_dc.Blit(self._rect.x, self._rect.y, self._rect.GetWidth(), self._rect.GetHeight(), dc, 0, 0)
+
+
+    def IsTabVisible(self, tabPage, tabOffset, dc, wnd):
+        """
+        Returns whether a tab is visible or not.
+
+        :param `tabPage`: the tab index;
+        :param `tabOffset`: the tab offset;
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: an instance of `wx.Window` derived window.
+        """
+
+        if not dc or not dc.IsOk():
+            return False
+
+        page_count = len(self._pages)
+        button_count = len(self._buttons)
+        self.Render(dc, wnd)
+
+        # Hasn't been rendered yet assume it's visible
+        if len(self._tab_close_buttons) < page_count:
+            return True
+
+        if self._agwFlags & AUI_NB_SCROLL_BUTTONS:
+            # First check if both buttons are disabled - if so, there's no need to
+            # check further for visibility.
+            arrowButtonVisibleCount = 0
+            for i in xrange(button_count):
+
+                button = self._buttons[i]
+                if button.id == AUI_BUTTON_LEFT or \
+                   button.id == AUI_BUTTON_RIGHT:
+
+                    if button.cur_state & AUI_BUTTON_STATE_HIDDEN == 0:
+                        arrowButtonVisibleCount += 1
+
+            # Tab must be visible
+            if arrowButtonVisibleCount == 0:
+                return True
+
+        # If tab is less than the given offset, it must be invisible by definition
+        if tabPage < tabOffset:
+            return False
+
+        # draw buttons
+        left_buttons_width = 0
+        right_buttons_width = 0
+
+        offset = 0
+
+        # calculate size of the buttons on the right side
+        offset = self._rect.x + self._rect.width
+
+        for i in xrange(button_count):
+            button = self._buttons[button_count - i - 1]
+
+            if button.location != wx.RIGHT:
+                continue
+            if button.cur_state & AUI_BUTTON_STATE_HIDDEN:
+                continue
+
+            offset -= button.rect.GetWidth()
+            right_buttons_width += button.rect.GetWidth()
+
+        offset = 0
+
+        # calculate size of the buttons on the left side
+        for i in xrange(button_count):
+            button = self._buttons[button_count - i - 1]
+
+            if button.location != wx.LEFT:
+                continue
+            if button.cur_state & AUI_BUTTON_STATE_HIDDEN:
+                continue
+
+            offset += button.rect.GetWidth()
+            left_buttons_width += button.rect.GetWidth()
+
+        offset = left_buttons_width
+
+        if offset == 0:
+            offset += self._art.GetIndentSize()
+
+        rect = wx.Rect(*self._rect)
+        rect.y = 0
+        rect.height = self._rect.height
+
+        # See if the given page is visible at the given tab offset (effectively scroll position)
+        for i in xrange(tabOffset, page_count):
+
+            page = self._pages[i]
+            tab_button = self._tab_close_buttons[i]
+
+            rect.x = offset
+            rect.width = self._rect.width - right_buttons_width - offset - 2
+
+            if rect.width <= 0:
+                return False # haven't found the tab, and we've run out of space, so return False
+
+            size, x_extent = self._art.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, tab_button.cur_state, page.control)
+            offset += x_extent
+
+            if i == tabPage:
+
+                # If not all of the tab is visible, and supposing there's space to display it all,
+                # we could do better so we return False.
+                if (self._rect.width - right_buttons_width - offset - 2) <= 0 and (self._rect.width - right_buttons_width - left_buttons_width) > x_extent:
+                    return False
+                else:
+                    return True
+
+        # Shouldn't really get here, but if it does, assume the tab is visible to prevent
+        # further looping in calling code.
+        return True
+
+
+    def MakeTabVisible(self, tabPage, win):
+        """
+        Make the tab visible if it wasn't already.
+
+        :param `tabPage`: the tab index;
+        :param `win`: an instance of `wx.Window` derived window.
+        """
+
+        dc = wx.ClientDC(win)
+
+        if not self.IsTabVisible(tabPage, self.GetTabOffset(), dc, win):
+            for i in xrange(len(self._pages)):
+                if self.IsTabVisible(tabPage, i, dc, win):
+                    self.SetTabOffset(i)
+                    win.Refresh()
+                    return
+
+
+    def TabHitTest(self, x, y):
+        """
+        TabHitTest() tests if a tab was hit, passing the window pointer
+        back if that condition was fulfilled.
+
+        :param `x`: the mouse `x` position;
+        :param `y`: the mouse `y` position.
+        """
+
+        if not self._rect.Contains((x,y)):
+            return None
+
+        btn = self.ButtonHitTest(x, y)
+        if btn:
+            if btn in self._buttons:
+                return None
+
+        for i in xrange(self._tab_offset, len(self._pages)):
+            page = self._pages[i]
+            if page.rect.Contains((x,y)):
+                return page.window
+
+        return None
+
+
+    def ButtonHitTest(self, x, y):
+        """
+        Tests if a button was hit.
+
+        :param `x`: the mouse `x` position;
+        :param `y`: the mouse `y` position.
+
+        :returns: and instance of L{AuiTabContainerButton} if a button was hit, ``None`` otherwise.
+        """
+
+        if not self._rect.Contains((x,y)):
+            return None
+
+        for button in self._buttons:
+            if button.rect.Contains((x,y)) and \
+               (button.cur_state & (AUI_BUTTON_STATE_HIDDEN|AUI_BUTTON_STATE_DISABLED)) == 0:
+                return button
+
+        for button in self._tab_close_buttons:
+            if button.rect.Contains((x,y)) and \
+               (button.cur_state & (AUI_BUTTON_STATE_HIDDEN|AUI_BUTTON_STATE_DISABLED)) == 0:
+                return button
+
+        return None
+
+
+    def DoShowHide(self):
+        """
+        This function shows the active window, then hides all of the other windows
+        (in that order).
+        """
+
+        pages = self.GetPages()
+
+        # show new active page first
+        for page in pages:
+            if page.active:
+                page.window.Show(True)
+                break
+
+        # hide all other pages
+        for page in pages:
+            if not page.active:
+                page.window.Show(False)
+
+
+# ----------------------------------------------------------------------
+# -- AuiTabCtrl class implementation --
+
+class AuiTabCtrl(wx.PyControl, AuiTabContainer):
+    """
+    This is an actual `wx.Window`-derived window which can be used as a tab
+    control in the normal sense.
+    """
+
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.NO_BORDER|wx.WANTS_CHARS|wx.TAB_TRAVERSAL):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiTabCtrl} parent;
+        :param `id`: an identifier for the control: a value of -1 is taken to mean a default;
+        :param `pos`: the control position. A value of (-1, -1) indicates a default position,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `size`: the control size. A value of (-1, -1) indicates a default size,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `style`: the window style.
+        """
+
+        wx.PyControl.__init__(self, parent, id, pos, size, style, name="AuiTabCtrl")
+        AuiTabContainer.__init__(self, parent)
+
+        self._click_pt = wx.Point(-1, -1)
+        self._is_dragging = False
+        self._hover_button = None
+        self._pressed_button = None
+        self._drag_image = None
+        self._drag_img_offset = (0, 0)
+        self._on_button = False
+
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
+        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
+        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
+        self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)
+        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
+        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+        self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost)
+        self.Bind(wx.EVT_MOTION, self.OnMotion)
+        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
+        self.Bind(EVT_AUINOTEBOOK_BUTTON, self.OnButton)
+
+
+    def IsDragging(self):
+        """ Returns whether the user is dragging a tab with the mouse or not. """
+
+        return self._is_dragging
+
+
+    def GetDefaultBorder(self):
+        """ Returns the default border style for L{AuiTabCtrl}. """
+
+        return wx.BORDER_NONE
+
+
+    def OnPaint(self, event):
+        """
+        Handles the ``wx.EVT_PAINT`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.PaintEvent` event to be processed.
+        """
+
+        dc = wx.PaintDC(self)
+        dc.SetFont(self.GetFont())
+
+        if self.GetPageCount() > 0:
+            self.Render(dc, self)
+
+
+    def OnEraseBackground(self, event):
+        """
+        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.EraseEvent` event to be processed.
+
+        :note: This is intentionally empty, to reduce flicker.
+        """
+
+        pass
+
+
+    def DoGetBestSize(self):
+        """
+        Gets the size which best suits the window: for a control, it would be the
+        minimal size which doesn't truncate the control, for a panel - the same
+        size as it would have after a call to `Fit()`.
+
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        return wx.Size(self._rect.width, self._rect.height)
+
+
+    def OnSize(self, event):
+        """
+        Handles the ``wx.EVT_SIZE`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.SizeEvent` event to be processed.
+        """
+
+        s = event.GetSize()
+        self.SetTabRect(wx.Rect(0, 0, s.GetWidth(), s.GetHeight()))
+
+
+    def OnLeftDown(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_DOWN`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        self.CaptureMouse()
+        self._click_pt = wx.Point(-1, -1)
+        self._is_dragging = False
+        self._click_tab = None
+        self._pressed_button = None
+
+        wnd = self.TabHitTest(event.GetX(), event.GetY())
+
+        if wnd is not None:
+            new_selection = self.GetIdxFromWindow(wnd)
+
+            # AuiNotebooks always want to receive this event
+            # even if the tab is already active, because they may
+            # have multiple tab controls
+            if new_selection != self.GetActivePage() or isinstance(self.GetParent(), AuiNotebook):
+
+                e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId())
+                e.SetSelection(new_selection)
+                e.SetOldSelection(self.GetActivePage())
+                e.SetEventObject(self)
+                self.GetEventHandler().ProcessEvent(e)
+
+            self._click_pt.x = event.GetX()
+            self._click_pt.y = event.GetY()
+            self._click_tab = wnd
+        else:
+            page_index = self.GetActivePage()
+            if page_index != wx.NOT_FOUND:
+                self.GetWindowFromIdx(page_index).SetFocus()
+
+        if self._hover_button:
+            self._pressed_button = self._hover_button
+            self._pressed_button.cur_state = AUI_BUTTON_STATE_PRESSED
+            self._on_button = True
+            self.Refresh()
+            self.Update()
+
+
+    def OnCaptureLost(self, event):
+        """
+        Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseCaptureLostEvent` event to be processed.
+        """
+
+        if self._is_dragging:
+            self._is_dragging = False
+            self._on_button = False
+
+            if self._drag_image:
+                self._drag_image.EndDrag()
+                del self._drag_image
+                self._drag_image = None
+
+            event = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG, self.GetId())
+            event.SetSelection(self.GetIdxFromWindow(self._click_tab))
+            event.SetOldSelection(event.GetSelection())
+            event.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(event)
+
+
+    def OnLeftUp(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_UP`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        self._on_button = False
+
+        if self._is_dragging:
+
+            if self.HasCapture():
+                self.ReleaseMouse()
+
+            self._is_dragging = False
+            if self._drag_image:
+                self._drag_image.EndDrag()
+                del self._drag_image
+                self._drag_image = None
+                self.GetParent().Refresh()
+
+            evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, self.GetId())
+            evt.SetSelection(self.GetIdxFromWindow(self._click_tab))
+            evt.SetOldSelection(evt.GetSelection())
+            evt.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(evt)
+
+            return
+
+        self.GetParent()._mgr.HideHint()
+
+        if self.HasCapture():
+            self.ReleaseMouse()
+
+        if self._hover_button:
+            self._pressed_button = self._hover_button
+
+        if self._pressed_button:
+
+            # make sure we're still clicking the button
+            button = self.ButtonHitTest(event.GetX(), event.GetY())
+
+            if button is None:
+                return
+
+            if button != self._pressed_button:
+                self._pressed_button = None
+                return
+
+            self.Refresh()
+            self.Update()
+
+            if self._pressed_button.cur_state & AUI_BUTTON_STATE_DISABLED == 0:
+
+                evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, self.GetId())
+                evt.SetSelection(self.GetIdxFromWindow(self._click_tab))
+                evt.SetInt(self._pressed_button.id)
+                evt.SetEventObject(self)
+                eventHandler = self.GetEventHandler()
+
+                if eventHandler is not None:
+                    eventHandler.ProcessEvent(evt)
+
+            self._pressed_button = None
+
+        self._click_pt = wx.Point(-1, -1)
+        self._is_dragging = False
+        self._click_tab = None
+
+
+    def OnMiddleUp(self, event):
+        """
+        Handles the ``wx.EVT_MIDDLE_UP`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        eventHandler = self.GetEventHandler()
+        if not isinstance(eventHandler, AuiTabCtrl):
+            event.Skip()
+            return
+
+        x, y = event.GetX(), event.GetY()
+        wnd = self.TabHitTest(x, y)
+
+        if wnd:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, self.GetId())
+            e.SetEventObject(self)
+            e.SetSelection(self.GetIdxFromWindow(wnd))
+            self.GetEventHandler().ProcessEvent(e)
+        elif not self.ButtonHitTest(x, y):
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_UP, self.GetId())
+            e.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnMiddleDown(self, event):
+        """
+        Handles the ``wx.EVT_MIDDLE_DOWN`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        eventHandler = self.GetEventHandler()
+        if not isinstance(eventHandler, AuiTabCtrl):
+            event.Skip()
+            return
+        
+        x, y = event.GetX(), event.GetY()
+        wnd = self.TabHitTest(x, y)
+
+        if wnd:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, self.GetId())
+            e.SetEventObject(self)
+            e.SetSelection(self.GetIdxFromWindow(wnd))
+            self.GetEventHandler().ProcessEvent(e)
+        elif not self.ButtonHitTest(x, y):
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_DOWN, self.GetId())
+            e.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnRightUp(self, event):
+        """
+        Handles the ``wx.EVT_RIGHT_UP`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        x, y = event.GetX(), event.GetY()
+        wnd = self.TabHitTest(x, y)
+
+        if wnd:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, self.GetId())
+            e.SetEventObject(self)
+            e.SetSelection(self.GetIdxFromWindow(wnd))
+            self.GetEventHandler().ProcessEvent(e)
+        elif not self.ButtonHitTest(x, y):
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_UP, self.GetId())
+            e.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnRightDown(self, event):
+        """
+        Handles the ``wx.EVT_RIGHT_DOWN`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        x, y = event.GetX(), event.GetY()
+        wnd = self.TabHitTest(x, y)
+
+        if wnd:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, self.GetId())
+            e.SetEventObject(self)
+            e.SetSelection(self.GetIdxFromWindow(wnd))
+            self.GetEventHandler().ProcessEvent(e)
+        elif not self.ButtonHitTest(x, y):
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_DOWN, self.GetId())
+            e.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnLeftDClick(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_DCLICK`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        x, y = event.GetX(), event.GetY()
+        wnd = self.TabHitTest(x, y)
+
+        if wnd:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK, self.GetId())
+            e.SetEventObject(self)
+            e.SetSelection(self.GetIdxFromWindow(wnd))
+            self.GetEventHandler().ProcessEvent(e)
+        elif not self.ButtonHitTest(x, y):
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, self.GetId())
+            e.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnMotion(self, event):
+        """
+        Handles the ``wx.EVT_MOTION`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        pos = event.GetPosition()
+
+        # check if the mouse is hovering above a button
+
+        button = self.ButtonHitTest(pos.x, pos.y)
+        wnd = self.TabHitTest(pos.x, pos.y)
+
+        if wnd is not None:
+            mouse_tab = self.GetIdxFromWindow(wnd)
+            if not self._pages[mouse_tab].enabled:
+                self._hover_button = None
+                return
+
+        if self._on_button:
+            return
+
+        if button:
+
+            if self._hover_button and button != self._hover_button:
+                self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL
+                self._hover_button = None
+                self.Refresh()
+                self.Update()
+
+            if button.cur_state != AUI_BUTTON_STATE_HOVER:
+                button.cur_state = AUI_BUTTON_STATE_HOVER
+                self.Refresh()
+                self.Update()
+                self._hover_button = button
+                return
+
+        else:
+
+            if self._hover_button:
+                self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL
+                self._hover_button = None
+                self.Refresh()
+                self.Update()
+
+        if not event.LeftIsDown() or self._click_pt == wx.Point(-1, -1):
+            return
+
+        if not self.HasCapture():
+            return
+
+        wnd = self.TabHitTest(pos.x, pos.y)
+
+        if not self._is_dragging:
+
+            drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X)
+            drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y)
+
+            if abs(pos.x - self._click_pt.x) > drag_x_threshold or \
+               abs(pos.y - self._click_pt.y) > drag_y_threshold:
+
+                self._is_dragging = True
+
+                if self._drag_image:
+                    self._drag_image.EndDrag()
+                    del self._drag_image
+                    self._drag_image = None
+
+                if self._agwFlags & AUI_NB_DRAW_DND_TAB:
+                    # Create the custom draw image from the icons and the text of the item
+                    mouse_tab = self.GetIdxFromWindow(wnd)
+                    page = self._pages[mouse_tab]
+                    tab_button = self._tab_close_buttons[mouse_tab]
+                    self._drag_image = TabDragImage(self, page, tab_button.cur_state, self._art)
+
+                    if self._agwFlags & AUI_NB_TAB_FLOAT:
+                        self._drag_image.BeginDrag(wx.Point(0,0), self, fullScreen=True)
+                    else:
+                        self._drag_image.BeginDragBounded(wx.Point(0,0), self, self.GetParent())
+
+                    # Capture the mouse cursor position offset relative to
+                    # The tab image location
+                    self._drag_img_offset = (pos[0] - page.rect.x,
+                                             pos[1] - page.rect.y)
+
+                    self._drag_image.Show()
+
+        if not wnd:
+            evt2 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, self.GetId())
+            evt2.SetSelection(self.GetIdxFromWindow(self._click_tab))
+            evt2.SetOldSelection(evt2.GetSelection())
+            evt2.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(evt2)
+            if evt2.GetDispatched():
+                return
+
+        evt3 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, self.GetId())
+        evt3.SetSelection(self.GetIdxFromWindow(self._click_tab))
+        evt3.SetOldSelection(evt3.GetSelection())
+        evt3.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(evt3)
+
+        if self._drag_image:
+            # Apply the drag images offset
+            pos -= self._drag_img_offset
+            self._drag_image.Move(pos)
+
+
+    def OnLeaveWindow(self, event):
+        """
+        Handles the ``wx.EVT_LEAVE_WINDOW`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.MouseEvent` event to be processed.
+        """
+
+        if self._hover_button:
+            self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL
+            self._hover_button = None
+            self.Refresh()
+            self.Update()
+
+
+    def OnButton(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_BUTTON`` event for L{AuiTabCtrl}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        button = event.GetInt()
+
+        if button == AUI_BUTTON_LEFT or button == AUI_BUTTON_RIGHT:
+            if button == AUI_BUTTON_LEFT:
+                if self.GetTabOffset() > 0:
+
+                    self.SetTabOffset(self.GetTabOffset()-1)
+                    self.Refresh()
+                    self.Update()
+            else:
+                self.SetTabOffset(self.GetTabOffset()+1)
+                self.Refresh()
+                self.Update()
+
+        elif button == AUI_BUTTON_WINDOWLIST:
+            idx = self.GetArtProvider().ShowDropDown(self, self._pages, self.GetActivePage())
+
+            if idx != -1:
+
+                e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId())
+                e.SetSelection(idx)
+                e.SetOldSelection(self.GetActivePage())
+                e.SetEventObject(self)
+                self.GetEventHandler().ProcessEvent(e)
+
+        else:
+            event.Skip()
+
+
+    def OnSetFocus(self, event):
+        """
+        Handles the ``wx.EVT_SET_FOCUS`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.FocusEvent` event to be processed.
+        """
+
+        self.Refresh()
+
+
+    def OnKillFocus(self, event):
+        """
+        Handles the ``wx.EVT_KILL_FOCUS`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.FocusEvent` event to be processed.
+        """
+
+        self.Refresh()
+
+
+    def OnKeyDown(self, event):
+        """
+        Handles the ``wx.EVT_KEY_DOWN`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.KeyEvent` event to be processed.
+        """
+
+        key = event.GetKeyCode()
+        nb = self.GetParent()
+
+        if key == wx.WXK_LEFT:
+            nb.AdvanceSelection(False)
+            self.SetFocus()
+
+        elif key == wx.WXK_RIGHT:
+            nb.AdvanceSelection(True)
+            self.SetFocus()
+
+        elif key == wx.WXK_HOME:
+            newPage = 0
+            nb.SetSelection(newPage)
+            self.SetFocus()
+
+        elif key == wx.WXK_END:
+            newPage = nb.GetPageCount() - 1
+            nb.SetSelection(newPage)
+            self.SetFocus()
+
+        elif key == wx.WXK_TAB:
+            if not event.ControlDown():
+                flags = 0
+                if not event.ShiftDown(): flags |= wx.NavigationKeyEvent.IsForward
+                if event.CmdDown():       flags |= wx.NavigationKeyEvent.WinChange
+                self.Navigate(flags)
+            else:
+
+                if not nb or not isinstance(nb, AuiNotebook):
+                    event.Skip()
+                    return
+
+                bForward = bWindowChange = 0
+                if not event.ShiftDown(): bForward |= wx.NavigationKeyEvent.IsForward
+                if event.CmdDown():       bWindowChange |= wx.NavigationKeyEvent.WinChange
+
+                keyEvent = wx.NavigationKeyEvent()
+                keyEvent.SetDirection(bForward)
+                keyEvent.SetWindowChange(bWindowChange)
+                keyEvent.SetFromTab(True)
+                keyEvent.SetEventObject(nb)
+
+                if not nb.GetEventHandler().ProcessEvent(keyEvent):
+
+                    # Not processed? Do an explicit tab into the page.
+                    win = self.GetWindowFromIdx(self.GetActivePage())
+                    if win:
+                        win.SetFocus()
+
+                self.SetFocus()
+
+                return
+
+        else:
+            event.Skip()
+
+
+    def OnKeyDown2(self, event):
+        """
+        Deprecated.
+
+        Handles the ``wx.EVT_KEY_DOWN`` event for L{AuiTabCtrl}.
+
+        :param `event`: a `wx.KeyEvent` event to be processed.
+
+        :warning: This method implementation is now deprecated. Refer to L{OnKeyDown}
+         for the correct one.
+        """
+
+        if self.GetActivePage() == -1:
+            event.Skip()
+            return
+
+        # We can't leave tab processing to the system on Windows, tabs and keys
+        # get eaten by the system and not processed properly if we specify both
+        # wxTAB_TRAVERSAL and wxWANTS_CHARS. And if we specify just wxTAB_TRAVERSAL,
+        # we don't key arrow key events.
+
+        key = event.GetKeyCode()
+
+        if key == wx.WXK_NUMPAD_PAGEUP:
+            key = wx.WXK_PAGEUP
+        if key == wx.WXK_NUMPAD_PAGEDOWN:
+            key = wx.WXK_PAGEDOWN
+        if key == wx.WXK_NUMPAD_HOME:
+            key = wx.WXK_HOME
+        if key == wx.WXK_NUMPAD_END:
+            key = wx.WXK_END
+        if key == wx.WXK_NUMPAD_LEFT:
+            key = wx.WXK_LEFT
+        if key == wx.WXK_NUMPAD_RIGHT:
+            key = wx.WXK_RIGHT
+
+        if key == wx.WXK_TAB or key == wx.WXK_PAGEUP or key == wx.WXK_PAGEDOWN:
+
+            bCtrlDown = event.ControlDown()
+            bShiftDown = event.ShiftDown()
+
+            bForward = (key == wx.WXK_TAB and not bShiftDown) or (key == wx.WXK_PAGEDOWN)
+            bWindowChange = (key == wx.WXK_PAGEUP) or (key == wx.WXK_PAGEDOWN) or bCtrlDown
+            bFromTab = (key == wx.WXK_TAB)
+
+            nb = self.GetParent()
+            if not nb or not isinstance(nb, AuiNotebook):
+                event.Skip()
+                return
+
+            keyEvent = wx.NavigationKeyEvent()
+            keyEvent.SetDirection(bForward)
+            keyEvent.SetWindowChange(bWindowChange)
+            keyEvent.SetFromTab(bFromTab)
+            keyEvent.SetEventObject(nb)
+
+            if not nb.GetEventHandler().ProcessEvent(keyEvent):
+
+                # Not processed? Do an explicit tab into the page.
+                win = self.GetWindowFromIdx(self.GetActivePage())
+                if win:
+                    win.SetFocus()
+
+            return
+
+        if len(self._pages) < 2:
+            event.Skip()
+            return
+
+        newPage = -1
+
+        if self.GetLayoutDirection() == wx.Layout_RightToLeft:
+            forwardKey = wx.WXK_LEFT
+            backwardKey = wx.WXK_RIGHT
+        else:
+            forwardKey = wx.WXK_RIGHT
+            backwardKey = wx.WXK_LEFT
+
+        if key == forwardKey:
+            if self.GetActivePage() == -1:
+                newPage = 0
+            elif self.GetActivePage() < len(self._pages) - 1:
+                newPage = self.GetActivePage() + 1
+
+        elif key == backwardKey:
+            if self.GetActivePage() == -1:
+                newPage = len(self._pages) - 1
+            elif self.GetActivePage() > 0:
+                newPage = self.GetActivePage() - 1
+
+        elif key == wx.WXK_HOME:
+            newPage = 0
+
+        elif key == wx.WXK_END:
+            newPage = len(self._pages) - 1
+
+        else:
+            event.Skip()
+
+        if newPage != -1:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId())
+            e.SetSelection(newPage)
+            e.SetOldSelection(newPage)
+            e.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(e)
+
+        else:
+            event.Skip()
+
+
+# ----------------------------------------------------------------------
+
+class TabFrame(wx.PyWindow):
+    """
+    TabFrame is an interesting case. It's important that all child pages
+    of the multi-notebook control are all actually children of that control
+    (and not grandchildren). TabFrame facilitates this. There is one
+    instance of TabFrame for each tab control inside the multi-notebook.
+
+    It's important to know that TabFrame is not a real window, but it merely
+    used to capture the dimensions/positioning of the internal tab control and
+    it's managed page windows.
+    """
+
+    def __init__(self, parent):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+        """
+
+        pre = wx.PrePyWindow()
+
+        self._tabs = None
+        self._rect = wx.Rect(0, 0, 200, 200)
+        self._tab_ctrl_height = 20
+        self._tab_rect = wx.Rect()
+        self._parent = parent
+
+        self.PostCreate(pre)
+
+
+    def SetTabCtrlHeight(self, h):
+        """
+        Sets the tab control height.
+
+        :param `h`: the tab area height.
+        """
+
+        self._tab_ctrl_height = h
+
+
+    def DoSetSize(self, x, y, width, height, flags=wx.SIZE_AUTO):
+        """
+        Sets the position and size of the window in pixels. The `flags`
+        parameter indicates the interpretation of the other params if they are
+        equal to -1.
+
+        :param `x`: the window `x` position;
+        :param `y`: the window `y` position;
+        :param `width`: the window width;
+        :param `height`: the window height;
+        :param `flags`: may have one of this bit set:
+
+         ===================================  ======================================
+         Size Flags                           Description
+         ===================================  ======================================
+         ``wx.SIZE_AUTO``                     A -1 indicates that a class-specific default should be used.
+         ``wx.SIZE_AUTO_WIDTH``               A -1 indicates that a class-specific default should be used for the width.
+         ``wx.SIZE_AUTO_HEIGHT``              A -1 indicates that a class-specific default should be used for the height.
+         ``wx.SIZE_USE_EXISTING``             Existing dimensions should be used if -1 values are supplied.
+         ``wx.SIZE_ALLOW_MINUS_ONE``          Allow dimensions of -1 and less to be interpreted as real dimensions, not default values.
+         ``wx.SIZE_FORCE``                    Normally, if the position and the size of the window are already the same as the parameters of this function, nothing is done. but with this flag a window resize may be forced even in this case (supported in wx 2.6.2 and later and only implemented for MSW and ignored elsewhere currently)
+         ===================================  ======================================
+
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        self._rect = wx.Rect(x, y, max(1, width), max(1, height))
+        self.DoSizing()
+
+
+    def DoGetSize(self):
+        """
+        Returns the window size.
+
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        return self._rect.width, self._rect.height
+
+
+    def DoGetClientSize(self):
+        """
+        Returns the window client size.
+
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        return self._rect.width, self._rect.height
+
+
+    def Show(self, show=True):
+        """
+        Shows/hides the window.
+
+        :param `show`: ``True`` to show the window, ``False`` otherwise.
+
+        :note: Overridden from `wx.PyControl`, this method always returns ``False`` as
+         L{TabFrame} should never be phisically shown on screen.
+        """
+
+        return False
+
+
+    def DoSizing(self):
+        """ Does the actual sizing of the tab control. """
+
+        if not self._tabs:
+            return
+
+        hideOnSingle = ((self._tabs.GetAGWFlags() & AUI_NB_HIDE_ON_SINGLE_TAB) and \
+                        self._tabs.GetPageCount() <= 1)
+
+        if not hideOnSingle and not self._parent._hide_tabs:
+            tab_height = self._tab_ctrl_height
+
+            self._tab_rect = wx.Rect(self._rect.x, self._rect.y, self._rect.width, self._tab_ctrl_height)
+
+            if self._tabs.GetAGWFlags() & AUI_NB_BOTTOM:
+                self._tab_rect = wx.Rect(self._rect.x, self._rect.y + self._rect.height - tab_height,
+                                         self._rect.width, tab_height)
+                self._tabs.SetDimensions(self._rect.x, self._rect.y + self._rect.height - tab_height,
+                                         self._rect.width, tab_height)
+                self._tabs.SetTabRect(wx.Rect(0, 0, self._rect.width, tab_height))
+
+            else:
+
+                self._tab_rect = wx.Rect(self._rect.x, self._rect.y, self._rect.width, tab_height)
+                self._tabs.SetDimensions(self._rect.x, self._rect.y, self._rect.width, tab_height)
+                self._tabs.SetTabRect(wx.Rect(0, 0, self._rect.width, tab_height))
+
+            # TODO: elif (GetAGWFlags() & AUI_NB_LEFT)
+            # TODO: elif (GetAGWFlags() & AUI_NB_RIGHT)
+
+            self._tabs.Refresh()
+            self._tabs.Update()
+
+        else:
+
+            tab_height = 0
+            self._tabs.SetDimensions(self._rect.x, self._rect.y, self._rect.width, tab_height)
+            self._tabs.SetTabRect(wx.Rect(0, 0, self._rect.width, tab_height))
+
+        pages = self._tabs.GetPages()
+
+        for page in pages:
+
+            height = self._rect.height - tab_height
+
+            if height < 0:
+                # avoid passing negative height to wx.Window.SetSize(), this
+                # results in assert failures/GTK+ warnings
+                height = 0
+
+            if self._tabs.GetAGWFlags() & AUI_NB_BOTTOM:
+                page.window.SetDimensions(self._rect.x, self._rect.y, self._rect.width, height)
+
+            else:
+                page.window.SetDimensions(self._rect.x, self._rect.y + tab_height,
+                                          self._rect.width, height)
+
+            # TODO: elif (GetAGWFlags() & AUI_NB_LEFT)
+            # TODO: elif (GetAGWFlags() & AUI_NB_RIGHT)
+
+            if repr(page.window.__class__).find("AuiMDIChildFrame") >= 0:
+                page.window.ApplyMDIChildFrameRect()
+
+
+    def Update(self):
+        """
+        Calling this method immediately repaints the invalidated area of the window
+        and all of its children recursively while this would usually only happen when
+        the flow of control returns to the event loop.
+
+        :note: Notice that this function doesn't invalidate any area of the window so
+         nothing happens if nothing has been invalidated (i.e. marked as requiring a redraw).
+         Use `Refresh` first if you want to immediately redraw the window unconditionally.
+
+        :note: Overridden from `wx.PyControl`.
+        """
+
+        # does nothing
+        pass
+
+
+# ----------------------------------------------------------------------
+# -- AuiNotebook class implementation --
+
+class AuiNotebook(wx.PyPanel):
+    """
+    AuiNotebook is a notebook control which implements many features common in
+    applications with dockable panes. Specifically, AuiNotebook implements functionality
+    which allows the user to rearrange tab order via drag-and-drop, split the tab window
+    into many different splitter configurations, and toggle through different themes to
+    customize the control's look and feel.
+
+    An effort has been made to try to maintain an API as similar to that of `wx.Notebook`.
+
+    The default theme that is used is L{AuiDefaultTabArt}, which provides a modern, glossy
+    look and feel. The theme can be changed by calling L{AuiNotebook.SetArtProvider}.
+    """
+
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=0, agwStyle=AUI_NB_DEFAULT_STYLE):
+        """
+        Default class constructor.
+
+        :param `parent`: the L{AuiNotebook} parent;
+        :param `id`: an identifier for the control: a value of -1 is taken to mean a default;
+        :param `pos`: the control position. A value of (-1, -1) indicates a default position,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `size`: the control size. A value of (-1, -1) indicates a default size,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `style`: the underlying `wx.PyPanel` window style;
+        :param `agwStyle`: the AGW-specific window style. This can be a combination of the following bits:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by L{AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
+         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
+         ==================================== ==================================
+
+         Default value for `agwStyle` is:
+         ``AUI_NB_DEFAULT_STYLE`` = ``AUI_NB_TOP`` | ``AUI_NB_TAB_SPLIT`` | ``AUI_NB_TAB_MOVE`` | ``AUI_NB_SCROLL_BUTTONS`` | ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` | ``AUI_NB_MIDDLE_CLICK_CLOSE`` | ``AUI_NB_DRAW_DND_TAB``
+
+        """
+
+        self._curpage = -1
+        self._tab_id_counter = AuiBaseTabCtrlId
+        self._dummy_wnd = None
+        self._hide_tabs = False
+        self._sash_dclick_unsplit = False
+        self._tab_ctrl_height = 20
+        self._requested_bmp_size = wx.Size(-1, -1)
+        self._requested_tabctrl_height = -1
+        self._textCtrl = None
+        self._tabBounds = (-1, -1)
+        self._click_tab = None
+
+        wx.PyPanel.__init__(self, parent, id, pos, size, style|wx.BORDER_NONE|wx.TAB_TRAVERSAL)
+        self._mgr = framemanager.AuiManager()
+        self._tabs = AuiTabContainer(self)
+
+        self.InitNotebook(agwStyle)
+
+
+    def GetTabContainer(self):
+        """ Returns the instance of L{AuiTabContainer}. """
+
+        return self._tabs
+
+
+    def InitNotebook(self, agwStyle):
+        """
+        Contains common initialization code called by all constructors.
+
+        :param `agwStyle`: the notebook style.
+
+        :see: L{__init__}
+        """
+
+        self.SetName("AuiNotebook")
+        self._agwFlags = agwStyle
+
+        self._popupWin = None
+        self._naviIcon = None
+        self._imageList = None
+        self._last_drag_x = 0
+
+        self._normal_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._selected_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._selected_font.SetWeight(wx.BOLD)
+
+        self.SetArtProvider(TA.AuiDefaultTabArt())
+
+        self._dummy_wnd = wx.Window(self, wx.ID_ANY, wx.Point(0, 0), wx.Size(0, 0))
+        self._dummy_wnd.SetSize((200, 200))
+        self._dummy_wnd.Show(False)
+
+        self._mgr.SetManagedWindow(self)
+        self._mgr.SetAGWFlags(AUI_MGR_DEFAULT)
+        self._mgr.SetDockSizeConstraint(1.0, 1.0) # no dock size constraint
+
+        self._mgr.AddPane(self._dummy_wnd, framemanager.AuiPaneInfo().Name("dummy").Bottom().CaptionVisible(False).Show(False))
+        self._mgr.Update()
+
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocusNotebook)
+        self.Bind(EVT_AUINOTEBOOK_PAGE_CHANGING, self.OnTabClicked,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_BEGIN_DRAG, self.OnTabBeginDrag,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_END_DRAG, self.OnTabEndDrag,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_DRAG_MOTION, self.OnTabDragMotion,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_CANCEL_DRAG, self.OnTabCancelDrag,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_BUTTON, self.OnTabButton,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN, self.OnTabMiddleDown,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_TAB_MIDDLE_UP, self.OnTabMiddleUp,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_TAB_RIGHT_DOWN, self.OnTabRightDown,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_TAB_RIGHT_UP, self.OnTabRightUp,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_BG_DCLICK, self.OnTabBgDClick,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+        self.Bind(EVT_AUINOTEBOOK_TAB_DCLICK, self.OnTabDClick,
+                  id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500)
+
+        self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKeyNotebook)
+
+
+    def SetArtProvider(self, art):
+        """
+        Sets the art provider to be used by the notebook.
+
+        :param `art`: an art provider.
+        """
+
+        self._tabs.SetArtProvider(art)
+        self.UpdateTabCtrlHeight(force=True)
+
+
+    def SavePerspective(self):
+        """
+        Saves the entire user interface layout into an encoded string, which can then
+        be stored by the application (probably using `wx.Config`). When a perspective
+        is restored using L{LoadPerspective}, the entire user interface will return
+        to the state it was when the perspective was saved.
+        """
+
+        # Build list of panes/tabs
+        tabs = ""
+        all_panes = self._mgr.GetAllPanes()
+
+        for pane in all_panes:
+
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+
+            if tabs:
+                tabs += "|"
+
+            tabs += pane.name + "="
+
+            # add tab id's
+            page_count = tabframe._tabs.GetPageCount()
+
+            for p in xrange(page_count):
+
+                page = tabframe._tabs.GetPage(p)
+                page_idx = self._tabs.GetIdxFromWindow(page.window)
+
+                if p:
+                    tabs += ","
+
+                if p == tabframe._tabs.GetActivePage():
+                    tabs += "+"
+                elif page_idx == self._curpage:
+                    tabs += "*"
+
+                tabs += "%u"%page_idx
+
+        tabs += "@"
+
+        # Add frame perspective
+        tabs += self._mgr.SavePerspective()
+
+        return tabs
+
+
+    def LoadPerspective(self, layout):
+        """
+        Loads a layout which was saved with L{SavePerspective}.
+
+        :param `layout`: a string which contains a saved L{AuiNotebook} layout.
+        """
+
+        # Remove all tab ctrls (but still keep them in main index)
+        tab_count = self._tabs.GetPageCount()
+        for i in xrange(tab_count):
+            wnd = self._tabs.GetWindowFromIdx(i)
+
+            # find out which onscreen tab ctrl owns this tab
+            ctrl, ctrl_idx = self.FindTab(wnd)
+            if not ctrl:
+                return False
+
+            # remove the tab from ctrl
+            if not ctrl.RemovePage(wnd):
+                return False
+
+        self.RemoveEmptyTabFrames()
+
+        sel_page = 0
+        tabs = layout[0:layout.index("@")]
+        to_break1 = False
+
+        while 1:
+
+            if "|" not in tabs:
+                to_break1 = True
+                tab_part = tabs
+            else:
+                tab_part = tabs[0:tabs.index('|')]
+
+            if "=" not in tab_part:
+                # No pages in this perspective...
+                return False
+
+            # Get pane name
+            pane_name = tab_part[0:tab_part.index("=")]
+
+            # create a new tab frame
+            new_tabs = TabFrame(self)
+            self._tab_id_counter += 1
+            new_tabs._tabs = AuiTabCtrl(self, self._tab_id_counter)
+            new_tabs._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone())
+            new_tabs.SetTabCtrlHeight(self._tab_ctrl_height)
+            new_tabs._tabs.SetAGWFlags(self._agwFlags)
+            dest_tabs = new_tabs._tabs
+
+            # create a pane info structure with the information
+            # about where the pane should be added
+            pane_info = framemanager.AuiPaneInfo().Name(pane_name).Bottom().CaptionVisible(False)
+            self._mgr.AddPane(new_tabs, pane_info)
+
+            # Get list of tab id's and move them to pane
+            tab_list = tab_part[tab_part.index("=")+1:]
+            to_break2, active_found = False, False
+
+            while 1:
+                if "," not in tab_list:
+                    to_break2 = True
+                    tab = tab_list
+                else:
+                    tab = tab_list[0:tab_list.index(",")]
+                    tab_list = tab_list[tab_list.index(",")+1:]
+
+                # Check if this page has an 'active' marker
+                c = tab[0]
+                if c in ['+', '*']:
+                    tab = tab[1:]
+
+                tab_idx = int(tab)
+                if tab_idx >= self.GetPageCount():
+                    to_break1 = True
+                    break
+
+                # Move tab to pane
+                page = self._tabs.GetPage(tab_idx)
+                newpage_idx = dest_tabs.GetPageCount()
+                dest_tabs.InsertPage(page.window, page, newpage_idx)
+
+                if c == '+':
+                    dest_tabs.SetActivePage(newpage_idx)
+                    active_found = True
+                elif c == '*':
+                    sel_page = tab_idx
+
+                if to_break2:
+                    break
+
+            if not active_found:
+                dest_tabs.SetActivePage(0)
+
+            new_tabs.DoSizing()
+            dest_tabs.DoShowHide()
+            dest_tabs.Refresh()
+
+            if to_break1:
+                break
+
+            tabs = tabs[tabs.index('|')+1:]
+
+        # Load the frame perspective
+        frames = layout[layout.index('@')+1:]
+        self._mgr.LoadPerspective(frames)
+
+        # Force refresh of selection
+        self._curpage = -1
+        self.SetSelection(sel_page)
+
+        return True
+
+
+    def SetTabCtrlHeight(self, height):
+        """
+        Sets the tab height.
+
+        By default, the tab control height is calculated by measuring the text
+        height and bitmap sizes on the tab captions.
+
+        Calling this method will override that calculation and set the tab control
+        to the specified height parameter. A call to this method will override
+        any call to L{SetUniformBitmapSize}. Specifying -1 as the height will
+        return the control to its default auto-sizing behaviour.
+
+        :param `height`: the tab control area height.
+        """
+
+        self._requested_tabctrl_height = height
+
+        # if window is already initialized, recalculate the tab height
+        if self._dummy_wnd:
+            self.UpdateTabCtrlHeight()
+
+
+    def SetUniformBitmapSize(self, size):
+        """
+        Ensures that all tabs will have the same height, even if some tabs
+        don't have bitmaps. Passing ``wx.DefaultSize`` to this
+        function will instruct the control to use dynamic tab height, which is
+        the default behaviour. Under the default behaviour, when a tab with a
+        large bitmap is added, the tab control's height will automatically
+        increase to accommodate the larger bitmap.
+
+        :param `size`: an instance of `wx.Size` specifying the tab bitmap size.
+        """
+
+        self._requested_bmp_size = wx.Size(*size)
+
+        # if window is already initialized, recalculate the tab height
+        if self._dummy_wnd:
+            self.UpdateTabCtrlHeight()
+
+
+    def UpdateTabCtrlHeight(self, force=False):
+        """
+        UpdateTabCtrlHeight() does the actual tab resizing. It's meant
+        to be used interally.
+
+        :param `force`: ``True`` to force the tab art to repaint.
+        """
+
+        # get the tab ctrl height we will use
+        height = self.CalculateTabCtrlHeight()
+
+        # if the tab control height needs to change, update
+        # all of our tab controls with the new height
+        if self._tab_ctrl_height != height or force:
+            art = self._tabs.GetArtProvider()
+
+            self._tab_ctrl_height = height
+
+            all_panes = self._mgr.GetAllPanes()
+            for pane in all_panes:
+
+                if pane.name == "dummy":
+                    continue
+
+                tab_frame = pane.window
+                tabctrl = tab_frame._tabs
+                tab_frame.SetTabCtrlHeight(self._tab_ctrl_height)
+                tabctrl.SetArtProvider(art.Clone())
+                tab_frame.DoSizing()
+
+
+    def UpdateHintWindowSize(self):
+        """ Updates the L{AuiManager} hint window size. """
+
+        size = self.CalculateNewSplitSize()
+
+        # the placeholder hint window should be set to this size
+        info = self._mgr.GetPane("dummy")
+
+        if info.IsOk():
+            info.MinSize(size)
+            info.BestSize(size)
+            self._dummy_wnd.SetSize(size)
+
+
+    def CalculateNewSplitSize(self):
+        """ Calculates the size of the new split. """
+
+        # count number of tab controls
+        tab_ctrl_count = 0
+        all_panes = self._mgr.GetAllPanes()
+
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tab_ctrl_count += 1
+
+        # if there is only one tab control, the first split
+        # should happen around the middle
+        if tab_ctrl_count < 2:
+            new_split_size = self.GetClientSize()
+            new_split_size.x /= 2
+            new_split_size.y /= 2
+
+        else:
+
+            # this is in place of a more complicated calculation
+            # that needs to be implemented
+            new_split_size = wx.Size(180, 180)
+
+        return new_split_size
+
+
+    def CalculateTabCtrlHeight(self):
+        """ Calculates the tab control area height. """
+
+        # if a fixed tab ctrl height is specified,
+        # just return that instead of calculating a
+        # tab height
+        if self._requested_tabctrl_height != -1:
+            return self._requested_tabctrl_height
+
+        # find out new best tab height
+        art = self._tabs.GetArtProvider()
+
+        return art.GetBestTabCtrlSize(self, self._tabs.GetPages(), self._requested_bmp_size)
+
+
+    def GetArtProvider(self):
+        """ Returns the associated art provider. """
+
+        return self._tabs.GetArtProvider()
+
+
+    def SetAGWWindowStyleFlag(self, agwStyle):
+        """
+        Sets the AGW-specific style of the window.
+
+        :param `agwStyle`: the new window style. This can be a combination of the following bits:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by L{AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
+         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
+         ==================================== ==================================
+
+        :note: Please note that some styles cannot be changed after the window
+         creation and that `Refresh` might need to be be called after changing the
+         others for the change to take place immediately.
+
+        :todo: Implementation of flags ``AUI_NB_RIGHT`` and ``AUI_NB_LEFT``.
+        """
+
+        self._agwFlags = agwStyle
+
+        # if the control is already initialized
+        if self._mgr.GetManagedWindow() == self:
+
+            # let all of the tab children know about the new style
+
+            all_panes = self._mgr.GetAllPanes()
+            for pane in all_panes:
+                if pane.name == "dummy":
+                    continue
+
+                tabframe = pane.window
+                tabctrl = tabframe._tabs
+                tabctrl.SetAGWFlags(self._agwFlags)
+                tabframe.DoSizing()
+                tabctrl.Refresh()
+                tabctrl.Update()
+
+
+    def GetAGWWindowStyleFlag(self):
+        """
+        Returns the AGW-specific style of the window.
+
+        :see: L{SetAGWWindowStyleFlag} for a list of possible AGW-specific window styles.
+        """
+
+        return self._agwFlags
+
+
+    def AddPage(self, page, caption, select=False, bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap, control=None):
+        """
+        Adds a page. If the `select` parameter is ``True``, calling this will generate a
+        page change event.
+
+        :param `page`: the page to be added;
+        :param `caption`: specifies the text for the new page;
+        :param `select`: specifies whether the page should be selected;
+        :param `bitmap`: the `wx.Bitmap` to display in the enabled tab;
+        :param `disabled_bitmap`: the `wx.Bitmap` to display in the disabled tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+
+        return self.InsertPage(self.GetPageCount(), page, caption, select, bitmap, disabled_bitmap, control)
+
+
+    def InsertPage(self, page_idx, page, caption, select=False, bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap,
+                   control=None):
+        """
+        This is similar to L{AddPage}, but allows the ability to specify the insert location.
+
+        :param `page_idx`: specifies the position for the new page;
+        :param `page`: the page to be added;
+        :param `caption`: specifies the text for the new page;
+        :param `select`: specifies whether the page should be selected;
+        :param `bitmap`: the `wx.Bitmap` to display in the enabled tab;
+        :param `disabled_bitmap`: the `wx.Bitmap` to display in the disabled tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+
+        if not page:
+            return False
+
+        page.Reparent(self)
+        info = AuiNotebookPage()
+        info.window = page
+        info.caption = caption
+        info.bitmap = bitmap
+        info.active = False
+        info.control = control
+
+        originalPaneMgr = framemanager.GetManager(page)
+        if originalPaneMgr:
+            originalPane = originalPaneMgr.GetPane(page)
+
+            if originalPane:
+                info.hasCloseButton = originalPane.HasCloseButton()
+
+        if bitmap.IsOk() and not disabled_bitmap.IsOk():
+            disabled_bitmap = MakeDisabledBitmap(bitmap)
+            info.dis_bitmap = disabled_bitmap
+
+        # if there are currently no tabs, the first added
+        # tab must be active
+        if self._tabs.GetPageCount() == 0:
+            info.active = True
+
+        self._tabs.InsertPage(page, info, page_idx)
+
+        # if that was the first page added, even if
+        # select is False, it must become the "current page"
+        # (though no select events will be fired)
+        if not select and self._tabs.GetPageCount() == 1:
+            select = True
+
+        active_tabctrl = self.GetActiveTabCtrl()
+        if page_idx >= active_tabctrl.GetPageCount():
+            active_tabctrl.AddPage(page, info)
+        else:
+            active_tabctrl.InsertPage(page, info, page_idx)
+
+        force = False
+        if control:
+            force = True
+            control.Reparent(active_tabctrl)
+            control.Show()
+
+        self.UpdateTabCtrlHeight(force=force)
+        self.DoSizing()
+        active_tabctrl.DoShowHide()
+
+        # adjust selected index
+        if self._curpage >= page_idx:
+            self._curpage += 1
+
+        if select:
+            self.SetSelectionToWindow(page)
+
+        return True
+
+
+    def DeletePage(self, page_idx):
+        """
+        Deletes a page at the given index. Calling this method will generate a page
+        change event.
+
+        :param `page_idx`: the page index to be deleted.
+
+        :note: L{DeletePage} removes a tab from the multi-notebook, and destroys the window as well.
+
+        :see: L{RemovePage}
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        wnd = self._tabs.GetWindowFromIdx(page_idx)
+        # hide the window in advance, as this will
+        # prevent flicker
+        wnd.Show(False)
+
+        self.RemoveControlFromPage(page_idx)
+
+        if not self.RemovePage(page_idx):
+            return False
+
+        wnd.Destroy()
+
+        return True
+
+
+    def RemovePage(self, page_idx):
+        """
+        Removes a page, without deleting the window pointer.
+
+        :param `page_idx`: the page index to be removed.
+
+        :note: L{RemovePage} removes a tab from the multi-notebook, but does not destroy the window.
+
+        :see: L{DeletePage}
+        """
+
+        # save active window pointer
+        active_wnd = None
+        if self._curpage >= 0:
+            active_wnd = self._tabs.GetWindowFromIdx(self._curpage)
+
+        # save pointer of window being deleted
+        wnd = self._tabs.GetWindowFromIdx(page_idx)
+        new_active = None
+
+        # make sure we found the page
+        if not wnd:
+            return False
+
+        # find out which onscreen tab ctrl owns this tab
+        ctrl, ctrl_idx = self.FindTab(wnd)
+        if not ctrl:
+            return False
+
+        currentPage = ctrl.GetPage(ctrl_idx)
+        is_curpage = (self._curpage == page_idx)
+        is_active_in_split = currentPage.active
+
+        # remove the tab from main catalog
+        if not self._tabs.RemovePage(wnd):
+            return False
+
+        # remove the tab from the onscreen tab ctrl
+        ctrl.RemovePage(wnd)
+
+        if is_active_in_split:
+
+            ctrl_new_page_count = ctrl.GetPageCount()
+
+            if ctrl_idx >= ctrl_new_page_count:
+                ctrl_idx = ctrl_new_page_count - 1
+
+            if ctrl_idx >= 0 and ctrl_idx < ctrl.GetPageCount():
+
+                ctrl_idx = self.FindNextActiveTab(ctrl_idx, ctrl)
+
+                # set new page as active in the tab split
+                ctrl.SetActivePage(ctrl_idx)
+
+                # if the page deleted was the current page for the
+                # entire tab control, then record the window
+                # pointer of the new active page for activation
+                if is_curpage:
+                    new_active = ctrl.GetWindowFromIdx(ctrl_idx)
+
+        else:
+
+            # we are not deleting the active page, so keep it the same
+            new_active = active_wnd
+
+        if not new_active:
+
+            # we haven't yet found a new page to active,
+            # so select the next page from the main tab
+            # catalogue
+
+            if 0 <= page_idx < self._tabs.GetPageCount():
+                new_active = self._tabs.GetPage(page_idx).window
+            if not new_active and self._tabs.GetPageCount() > 0:
+                new_active = self._tabs.GetPage(0).window
+
+        self.RemoveEmptyTabFrames()
+
+        # set new active pane
+        if new_active:
+            if not self.IsBeingDeleted():
+                self._curpage = -1
+                self.SetSelectionToWindow(new_active)
+        else:
+            self._curpage = -1
+            self._tabs.SetNoneActive()
+
+        return True
+
+
+    def FindNextActiveTab(self, ctrl_idx, ctrl):
+        """
+        Finds the next active tab (used mainly when L{AuiNotebook} has inactive/disabled
+        tabs in it).
+
+        :param `ctrl_idx`: the index of the first (most obvious) tab to check for active status;
+        :param `ctrl`: an instance of L{AuiTabCtrl}.
+        """
+
+        if self.GetEnabled(ctrl_idx):
+            return ctrl_idx
+
+        for indx in xrange(ctrl_idx, ctrl.GetPageCount()):
+            if self.GetEnabled(indx):
+                return indx
+
+        for indx in xrange(ctrl_idx, -1, -1):
+            if self.GetEnabled(indx):
+                return indx
+
+        return 0
+
+
+    def HideAllTabs(self, hidden=True):
+        """
+        Hides all tabs on the L{AuiNotebook} control.
+
+        :param `hidden`: if ``True`` hides all tabs.
+        """
+
+        self._hide_tabs = hidden
+
+
+    def SetSashDClickUnsplit(self, unsplit=True):
+        """
+        Sets whether to unsplit a splitted L{AuiNotebook} when double-clicking on a sash.
+
+        :param `unsplit`: ``True`` to unsplit on sash double-clicking, ``False`` otherwise.
+        """
+
+        self._sash_dclick_unsplit = unsplit
+
+
+    def GetSashDClickUnsplit(self):
+        """
+        Returns whether a splitted L{AuiNotebook} can be unsplitted by double-clicking
+        on the splitter sash.
+        """
+
+        return self._sash_dclick_unsplit
+
+
+    def SetMinMaxTabWidth(self, minTabWidth, maxTabWidth):
+        """
+        Sets the minimum and/or the maximum tab widths for L{AuiNotebook} when the
+        ``AUI_NB_TAB_FIXED_WIDTH`` style is defined.
+
+        Pass -1 to either `minTabWidth` or `maxTabWidth` to reset to the default tab
+        width behaviour for L{AuiNotebook}.
+
+        :param `minTabWidth`: the minimum allowed tab width, in pixels;
+        :param `maxTabWidth`: the maximum allowed tab width, in pixels.
+
+        :note: Minimum and maximum tabs widths are used only when the ``AUI_NB_TAB_FIXED_WIDTH``
+         style is present.
+        """
+
+        if minTabWidth > maxTabWidth:
+            raise Exception("Minimum tab width must be less or equal than maximum tab width")
+
+        self._tabBounds = (minTabWidth, maxTabWidth)
+        self.SetAGWWindowStyleFlag(self._agwFlags)
+
+
+    def GetMinMaxTabWidth(self):
+        """
+        Returns the minimum and the maximum tab widths for L{AuiNotebook} when the
+        ``AUI_NB_TAB_FIXED_WIDTH`` style is defined.
+
+        :note: Minimum and maximum tabs widths are used only when the ``AUI_NB_TAB_FIXED_WIDTH``
+         style is present.
+
+        :see: L{SetMinMaxTabWidth} for more information.
+        """
+
+        return self._tabBounds
+
+
+    def GetPageIndex(self, page_wnd):
+        """
+        Returns the page index for the specified window. If the window is not
+        found in the notebook, ``wx.NOT_FOUND`` is returned.
+        """
+
+        return self._tabs.GetIdxFromWindow(page_wnd)
+
+
+    def SetPageText(self, page_idx, text):
+        """
+        Sets the tab label for the page.
+
+        :param `page_idx`: the page index;
+        :param `text`: the new tab label.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        should_refresh = page_info.caption != text
+        page_info.caption = text
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        info = ctrl.GetPage(ctrl_idx)
+        should_refresh = should_refresh or info.caption != text
+        info.caption = text
+
+        if should_refresh:
+            ctrl.Refresh()
+            ctrl.Update()
+
+        self.UpdateTabCtrlHeight(force=True)
+
+        return True
+
+
+    def GetPageText(self, page_idx):
+        """
+        Returns the tab label for the page.
+
+        :param `page_idx`: the page index.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return ""
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        return page_info.caption
+
+
+    def SetPageBitmap(self, page_idx, bitmap):
+        """
+        Sets the tab bitmap for the page.
+
+        :param `page_idx`: the page index;
+        :param `bitmap`: an instance of `wx.Bitmap`.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        should_refresh = page_info.bitmap is not bitmap
+        page_info.bitmap = bitmap
+        if bitmap.IsOk() and not page_info.dis_bitmap.IsOk():
+            page_info.dis_bitmap = MakeDisabledBitmap(bitmap)
+
+        # tab height might have changed
+        self.UpdateTabCtrlHeight()
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        info = ctrl.GetPage(ctrl_idx)
+        should_refresh = should_refresh or info.bitmap is not bitmap
+        info.bitmap = bitmap
+        info.dis_bitmap = page_info.dis_bitmap
+        if should_refresh:
+            ctrl.Refresh()
+            ctrl.Update()
+
+        return True
+
+
+    def GetPageBitmap(self, page_idx):
+        """
+        Returns the tab bitmap for the page.
+
+        :param `page_idx`: the page index.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return wx.NullBitmap
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        return page_info.bitmap
+
+
+    def SetImageList(self, imageList):
+        """
+        Sets the image list for the L{AuiNotebook} control.
+
+        :param `imageList`: an instance of `wx.ImageList`.
+        """
+
+        self._imageList = imageList
+
+
+    def AssignImageList(self, imageList):
+        """
+        Sets the image list for the L{AuiNotebook} control.
+
+        :param `imageList`: an instance of `wx.ImageList`.
+        """
+
+        self.SetImageList(imageList)
+
+
+    def GetImageList(self):
+        """ Returns the associated image list (if any). """
+
+        return self._imageList
+
+
+    def SetPageImage(self, page, image):
+        """
+        Sets the image index for the given page.
+
+        :param `page`: the page index;
+        :param `image`: an index into the image list which was set with L{SetImageList}.
+        """
+
+        if page >= self._tabs.GetPageCount():
+            return False
+
+        if not isinstance(image, types.IntType):
+            raise Exception("The image parameter must be an integer, you passed " \
+                            "%s"%repr(image))
+
+        if not self._imageList:
+            raise Exception("To use SetPageImage you need to associate an image list " \
+                            "Using SetImageList or AssignImageList")
+
+        if image >= self._imageList.GetImageCount():
+            raise Exception("Invalid image index (%d), the image list contains only" \
+                            " (%d) bitmaps"%(image, self._imageList.GetImageCount()))
+
+        if image == -1:
+            self.SetPageBitmap(page, wx.NullBitmap)
+            return
+
+        bitmap = self._imageList.GetBitmap(image)
+        self.SetPageBitmap(page, bitmap)
+
+
+    def GetPageImage(self, page):
+        """
+        Returns the image index for the given page.
+
+        :param `page`: the given page for which to retrieve the image index.
+        """
+
+        if page >= self._tabs.GetPageCount():
+            return False
+
+        bitmap = self.GetPageBitmap(page)
+        for indx in xrange(self._imageList.GetImageCount()):
+            imgListBmp = self._imageList.GetBitmap(indx)
+            if imgListBmp == bitmap:
+                return indx
+
+        return wx.NOT_FOUND
+
+
+    def SetPageTextColour(self, page_idx, colour):
+        """
+        Sets the tab text colour for the page.
+
+        :param `page_idx`: the page index;
+        :param `colour`: an instance of `wx.Colour`.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        should_refresh = page_info.text_colour != colour
+        page_info.text_colour = colour
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        info = ctrl.GetPage(ctrl_idx)
+        should_refresh = should_refresh or info.text_colour != colour
+        info.text_colour = page_info.text_colour
+
+        if should_refresh:
+            ctrl.Refresh()
+            ctrl.Update()
+
+        return True
+
+
+    def GetPageTextColour(self, page_idx):
+        """
+        Returns the tab text colour for the page.
+
+        :param `page_idx`: the page index.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return wx.NullColour
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        return page_info.text_colour
+
+
+    def AddControlToPage(self, page_idx, control):
+        """
+        Adds a control inside a tab (not in the tab area).
+
+        :param `page_idx`: the page index;
+        :param `control`: an instance of `wx.Window`.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        page_info.control = control
+
+        # tab height might have changed
+        self.UpdateTabCtrlHeight(force=True)
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        control.Reparent(ctrl)
+
+        info = ctrl.GetPage(ctrl_idx)
+        info.control = control
+        ctrl.Refresh()
+        ctrl.Update()
+
+        return True
+
+
+    def RemoveControlFromPage(self, page_idx):
+        """
+        Removes a control from a tab (not from the tab area).
+
+        :param `page_idx`: the page index.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        page_info = self._tabs.GetPage(page_idx)
+        if page_info.control is None:
+            return False
+
+        page_info.control.Destroy()
+        page_info.control = None
+
+        # tab height might have changed
+        self.UpdateTabCtrlHeight(force=True)
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        info = ctrl.GetPage(ctrl_idx)
+        info.control = None
+        ctrl.Refresh()
+        ctrl.Update()
+
+        return True
+
+
+    def SetCloseButton(self, page_idx, hasCloseButton):
+        """
+        Sets whether a tab should display a close button or not.
+
+        :param `page_idx`: the page index;
+        :param `hasCloseButton`: ``True`` if the page displays a close button.
+
+        :note: This can only be called if ``AUI_NB_CLOSE_ON_ALL_TABS`` is specified.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        if self._agwFlags & AUI_NB_CLOSE_ON_ALL_TABS == 0:
+            raise Exception("SetCloseButton can only be used with AUI_NB_CLOSE_ON_ALL_TABS style.")
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        page_info.hasCloseButton = hasCloseButton
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        info = ctrl.GetPage(ctrl_idx)
+        info.hasCloseButton = page_info.hasCloseButton
+        ctrl.Refresh()
+        ctrl.Update()
+
+        return True
+
+
+    def HasCloseButton(self, page_idx):
+        """
+        Returns whether a tab displays a close button or not.
+
+        :param `page_idx`: the page index.
+
+        :note: This can only be called if ``AUI_NB_CLOSE_ON_ALL_TABS`` is specified.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        page_info = self._tabs.GetPage(page_idx)
+        return page_info.hasCloseButton
+
+
+    def GetSelection(self):
+        """ Returns the index of the currently active page, or -1 if none was selected. """
+
+        return self._curpage
+
+
+    def GetCurrentPage(self):
+        """ Returns the currently active page (not the index), or ``None`` if none was selected. """
+
+        if self._curpage >= 0 and self._curpage < self._tabs.GetPageCount():
+            return self.GetPage(self._curpage)
+
+        return None
+
+
+    def EnsureVisible(self, indx):
+        """
+        Ensures the input page index `indx` is visible.
+
+        :param `indx`: the page index.
+        """
+
+        self._tabs.MakeTabVisible(indx, self)
+
+
+    def SetSelection(self, new_page, force=False):
+        """
+        Sets the page selection. Calling this method will generate a page change event.
+
+        :param `new_page`: the index of the new selection;
+        :param `force`: whether to force the selection or not.
+        """
+        wnd = self._tabs.GetWindowFromIdx(new_page)
+
+        #Update page access time
+        self._tabs.GetPages()[new_page].access_time = datetime.datetime.now()
+
+        if not wnd or not self.GetEnabled(new_page):
+            return self._curpage
+
+        # don't change the page unless necessary
+        # however, clicking again on a tab should give it the focus.
+        if new_page == self._curpage and not force:
+
+            ctrl, ctrl_idx = self.FindTab(wnd)
+            if wx.Window.FindFocus() != ctrl:
+                ctrl.SetFocus()
+
+            return self._curpage
+
+        evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId())
+        evt.SetSelection(new_page)
+        evt.SetOldSelection(self._curpage)
+        evt.SetEventObject(self)
+
+        if not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed():
+
+            old_curpage = self._curpage
+            self._curpage = new_page
+
+            # program allows the page change
+            evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
+            self.GetEventHandler().ProcessEvent(evt)
+
+            if not evt.IsAllowed(): # event is no longer allowed after handler
+                return self._curpage
+
+            ctrl, ctrl_idx = self.FindTab(wnd)
+
+            if ctrl:
+                self._tabs.SetActivePage(wnd)
+                ctrl.SetActivePage(ctrl_idx)
+                self.DoSizing()
+                ctrl.DoShowHide()
+                ctrl.MakeTabVisible(ctrl_idx, ctrl)
+
+                # set fonts
+                all_panes = self._mgr.GetAllPanes()
+                for pane in all_panes:
+                    if pane.name == "dummy":
+                        continue
+
+                    tabctrl = pane.window._tabs
+                    if tabctrl != ctrl:
+                        tabctrl.SetSelectedFont(self._normal_font)
+                    else:
+                        tabctrl.SetSelectedFont(self._selected_font)
+
+                    tabctrl.Refresh()
+                    tabctrl.Update()
+
+                # Set the focus to the page if we're not currently focused on the tab.
+                # This is Firefox-like behaviour.
+                if wnd.IsShownOnScreen() and wx.Window.FindFocus() != ctrl:
+                    wnd.SetFocus()
+
+                return old_curpage
+
+        return self._curpage
+
+
+    def SetSelectionToWindow(self, win):
+        """
+        Sets the selection based on the input window `win`.
+
+        :param `win`: a `wx.Window` derived window.
+        """
+
+        idx = self._tabs.GetIdxFromWindow(win)
+
+        if idx == wx.NOT_FOUND:
+            raise Exception("invalid notebook page")
+
+        if not self.GetEnabled(idx):
+            return
+
+        # since a tab was clicked, let the parent know that we received
+        # the focus, even if we will assign that focus immediately
+        # to the child tab in the SetSelection call below
+        # (the child focus event will also let AuiManager, if any,
+        # know that the notebook control has been activated)
+
+        parent = self.GetParent()
+        if parent:
+            eventFocus = wx.ChildFocusEvent(self)
+            parent.GetEventHandler().ProcessEvent(eventFocus)
+
+        self.SetSelection(idx)
+
+
+    def SetSelectionToPage(self, page):
+        """
+        Sets the selection based on the input page.
+
+        :param `page`: an instance of L{AuiNotebookPage}.
+        """
+
+        self.SetSelectionToWindow(page.window)
+
+
+    def GetPageCount(self):
+        """ Returns the number of pages in the notebook. """
+
+        return self._tabs.GetPageCount()
+
+
+    def GetPage(self, page_idx):
+        """
+        Returns the page specified by the given index.
+
+        :param `page_idx`: the page index.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            raise Exception("invalid notebook page")
+
+        return self._tabs.GetWindowFromIdx(page_idx)
+
+
+    def GetPageInfo(self, page_idx):
+        """
+        Returns the L{AuiNotebookPage} info structure specified by the given index.
+
+        :param `page_idx`: the page index.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            raise Exception("invalid notebook page")
+
+        return self._tabs.GetPage(page_idx)
+
+
+    def GetEnabled(self, page_idx):
+        """
+        Returns whether the page specified by the index `page_idx` is enabled.
+
+        :param `page_idx`: the page index.
+        """
+
+        return self._tabs.GetEnabled(page_idx)
+
+
+    def EnableTab(self, page_idx, enable=True):
+        """
+        Enables/disables a page in the notebook.
+
+        :param `page_idx`: the page index;
+        :param `enable`: ``True`` to enable the page, ``False`` to disable it.
+        """
+
+        self._tabs.EnableTab(page_idx, enable)
+        self.Refresh()
+
+
+    def DoSizing(self):
+        """ Performs all sizing operations in each tab control. """
+
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+            tabframe.DoSizing()
+
+
+    def GetAuiManager(self):
+        """ Returns the associated L{AuiManager}. """
+
+        return self._mgr
+
+
+    def GetActiveTabCtrl(self):
+        """
+        Returns the active tab control. It is called to determine which control
+        gets new windows being added.
+        """
+
+        if self._curpage >= 0 and self._curpage < self._tabs.GetPageCount():
+
+            # find the tab ctrl with the current page
+            ctrl, idx = self.FindTab(self._tabs.GetPage(self._curpage).window)
+            if ctrl:
+                return ctrl
+
+        # no current page, just find the first tab ctrl
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+            return tabframe._tabs
+
+        # If there is no tabframe at all, create one
+        tabframe = TabFrame(self)
+        tabframe.SetTabCtrlHeight(self._tab_ctrl_height)
+        self._tab_id_counter += 1
+        tabframe._tabs = AuiTabCtrl(self, self._tab_id_counter)
+
+        tabframe._tabs.SetAGWFlags(self._agwFlags)
+        tabframe._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone())
+        self._mgr.AddPane(tabframe, framemanager.AuiPaneInfo().Center().CaptionVisible(False).
+                          PaneBorder((self._agwFlags & AUI_NB_SUB_NOTEBOOK) == 0))
+
+        self._mgr.Update()
+
+        return tabframe._tabs
+
+
+    def FindTab(self, page):
+        """
+        Finds the tab control that currently contains the window as well
+        as the index of the window in the tab control. It returns ``True`` if the
+        window was found, otherwise ``False``.
+
+        :param `page`: an instance of L{AuiNotebookPage}.
+        """
+
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+
+            page_idx = tabframe._tabs.GetIdxFromWindow(page)
+
+            if page_idx != -1:
+
+                ctrl = tabframe._tabs
+                idx = page_idx
+                return ctrl, idx
+
+        return None, wx.NOT_FOUND
+
+
+    def Split(self, page, direction):
+        """
+        Performs a split operation programmatically.
+
+        :param `page`: indicates the page that will be split off. This page will also become
+         the active page after the split.
+        :param `direction`: specifies where the pane should go, it should be one of the
+         following: ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, or ``wx.RIGHT``.
+        """
+
+        cli_size = self.GetClientSize()
+
+        # get the page's window pointer
+        wnd = self.GetPage(page)
+        if not wnd:
+            return
+
+        # notebooks with 1 or less pages can't be split
+        if self.GetPageCount() < 2:
+            return
+
+        # find out which tab control the page currently belongs to
+
+        src_tabs, src_idx = self.FindTab(wnd)
+        if not src_tabs:
+            return
+
+        # choose a split size
+        if self.GetPageCount() > 2:
+            split_size = self.CalculateNewSplitSize()
+        else:
+            # because there are two panes, always split them
+            # equally
+            split_size = self.GetClientSize()
+            split_size.x /= 2
+            split_size.y /= 2
+
+        # create a new tab frame
+        new_tabs = TabFrame(self)
+        new_tabs._rect = wx.RectPS(wx.Point(0, 0), split_size)
+        new_tabs.SetTabCtrlHeight(self._tab_ctrl_height)
+        self._tab_id_counter += 1
+        new_tabs._tabs = AuiTabCtrl(self, self._tab_id_counter)
+
+        new_tabs._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone())
+        new_tabs._tabs.SetAGWFlags(self._agwFlags)
+        dest_tabs = new_tabs._tabs
+
+        page_info = src_tabs.GetPage(src_idx)
+        if page_info.control:
+            self.ReparentControl(page_info.control, dest_tabs)
+
+        # create a pane info structure with the information
+        # about where the pane should be added
+        pane_info = framemanager.AuiPaneInfo().Bottom().CaptionVisible(False)
+
+        if direction == wx.LEFT:
+
+            pane_info.Left()
+            mouse_pt = wx.Point(0, cli_size.y/2)
+
+        elif direction == wx.RIGHT:
+
+            pane_info.Right()
+            mouse_pt = wx.Point(cli_size.x, cli_size.y/2)
+
+        elif direction == wx.TOP:
+
+            pane_info.Top()
+            mouse_pt = wx.Point(cli_size.x/2, 0)
+
+        elif direction == wx.BOTTOM:
+
+            pane_info.Bottom()
+            mouse_pt = wx.Point(cli_size.x/2, cli_size.y)
+
+        self._mgr.AddPane(new_tabs, pane_info, mouse_pt)
+        self._mgr.Update()
+
+        # remove the page from the source tabs
+        page_info.active = False
+
+        src_tabs.RemovePage(page_info.window)
+
+        if src_tabs.GetPageCount() > 0:
+            src_tabs.SetActivePage(0)
+            src_tabs.DoShowHide()
+            src_tabs.Refresh()
+
+        # add the page to the destination tabs
+        dest_tabs.InsertPage(page_info.window, page_info, 0)
+
+        if src_tabs.GetPageCount() == 0:
+            self.RemoveEmptyTabFrames()
+
+        self.DoSizing()
+        dest_tabs.DoShowHide()
+        dest_tabs.Refresh()
+
+        # force the set selection function reset the selection
+        self._curpage = -1
+
+        # set the active page to the one we just split off
+        self.SetSelectionToPage(page_info)
+
+        self.UpdateHintWindowSize()
+
+
+    def UnSplit(self):
+        """ Restores original view after a tab split. """
+
+        self.Freeze()
+
+        # remember the tab now selected
+        nowSelected = self.GetSelection()
+        # select first tab as destination
+        self.SetSelection(0)
+        # iterate all other tabs
+        for idx in xrange(1, self.GetPageCount()):
+            # get win reference
+            win = self.GetPage(idx)
+            # get tab title
+            title = self.GetPageText(idx)
+            # get page bitmap
+            bmp = self.GetPageBitmap(idx)
+            # remove from notebook
+            self.RemovePage(idx)
+            # re-add in the same position so it will tab
+            self.InsertPage(idx, win, title, False, bmp)
+        # restore orignial selected tab
+        self.SetSelection(nowSelected)
+
+        self.Thaw()
+
+
+    def ReparentControl(self, control, dest_tabs):
+        """
+        Reparents a control added inside a tab.
+
+        :param `control`: an instance of `wx.Window`;
+        :param `dest_tabs`: the destination L{AuiTabCtrl}.
+        """
+
+        control.Hide()
+        control.Reparent(dest_tabs)
+
+
+    def UnsplitDClick(self, part, sash_size, pos):
+        """
+        Unsplit the L{AuiNotebook} on sash double-click.
+
+        :param `part`: an UI part representing the sash;
+        :param `sash_size`: the sash size;
+        :param `pos`: the double-click mouse position.
+
+        :warning: Due to a bug on MSW, for disabled pages `wx.FindWindowAtPoint`
+         returns the wrong window. See http://trac.wxwidgets.org/ticket/2942
+        """
+
+        if not self._sash_dclick_unsplit:
+            # Unsplit not allowed
+            return
+
+        pos1 = wx.Point(*pos)
+        pos2 = wx.Point(*pos)
+        if part.orientation == wx.HORIZONTAL:
+            pos1.y -= 2*sash_size
+            pos2.y += 2*sash_size + self.GetTabCtrlHeight()
+        elif part.orientation == wx.VERTICAL:
+            pos1.x -= 2*sash_size
+            pos2.x += 2*sash_size
+        else:
+            raise Exception("Invalid UI part orientation")
+
+        pos1, pos2 = self.ClientToScreen(pos1), self.ClientToScreen(pos2)
+        win1, win2 = wx.FindWindowAtPoint(pos1), wx.FindWindowAtPoint(pos2)
+
+        if isinstance(win1, wx.ScrollBar):
+            # Hopefully it will work
+            pos1 = wx.Point(*pos)
+            shift = wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) + 2*(sash_size+1)
+            if part.orientation == wx.HORIZONTAL:
+                pos1.y -= shift
+            else:
+                pos1.x -= shift
+
+            pos1 = self.ClientToScreen(pos1)
+            win1 = wx.FindWindowAtPoint(pos1)
+
+        if isinstance(win2, wx.ScrollBar):
+            pos2 = wx.Point(*pos)
+            shift = wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) + 2*(sash_size+1)
+            if part.orientation == wx.HORIZONTAL:
+                pos2.y += shift
+            else:
+                pos2.x += shift
+
+            pos2 = self.ClientToScreen(pos2)
+            win2 = wx.FindWindowAtPoint(pos2)
+
+        if not win1 or not win2:
+            # How did we get here?
+            return
+
+        if isinstance(win1, AuiNotebook) or isinstance(win2, AuiNotebook):
+            # This is a bug on MSW, for disabled pages wx.FindWindowAtPoint
+            # returns the wrong window.
+            # See http://trac.wxwidgets.org/ticket/2942
+            return
+
+        tab_frame1, tab_frame2 = self.GetTabFrameFromWindow(win1), self.GetTabFrameFromWindow(win2)
+
+        if not tab_frame1 or not tab_frame2:
+            return
+
+        tab_ctrl_1, tab_ctrl_2 = tab_frame1._tabs, tab_frame2._tabs
+
+        if tab_ctrl_1.GetPageCount() > tab_ctrl_2.GetPageCount():
+            src_tabs = tab_ctrl_2
+            dest_tabs = tab_ctrl_1
+        else:
+            src_tabs = tab_ctrl_1
+            dest_tabs = tab_ctrl_2
+
+        selection = -1
+        page_count = dest_tabs.GetPageCount()
+
+        for page in xrange(src_tabs.GetPageCount()-1, -1, -1):
+            # remove the page from the source tabs
+            page_info = src_tabs.GetPage(page)
+            if page_info.active:
+                selection = page_count + page
+            src_tabs.RemovePage(page_info.window)
+
+            # add the page to the destination tabs
+            dest_tabs.AddPage(page_info.window, page_info)
+            if page_info.control:
+                self.ReparentControl(page_info.control, dest_tabs)
+
+        self.RemoveEmptyTabFrames()
+
+        dest_tabs.DoShowHide()
+        self.DoSizing()
+        dest_tabs.Refresh()
+        self._mgr.Update()
+        if selection > 0:
+            wx.CallAfter(dest_tabs.MakeTabVisible, selection, self)
+
+
+    def OnSize(self, event):
+        """
+        Handles the ``wx.EVT_SIZE`` event for L{AuiNotebook}.
+
+        :param `event`: a `wx.SizeEvent` event to be processed.
+        """
+
+        self.UpdateHintWindowSize()
+        event.Skip()
+
+
+    def OnTabClicked(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGING`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        if self._textCtrl is not None:
+            self._textCtrl.StopEditing()
+
+        ctrl = event.GetEventObject()
+        assert ctrl != None
+
+        wnd = ctrl.GetWindowFromIdx(event.GetSelection())
+        assert wnd != None
+
+        self.SetSelectionToWindow(wnd)
+
+
+    def OnTabBgDClick(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_BG_DCLICK`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        if self._textCtrl is not None:
+            self._textCtrl.StopEditing()
+
+        # notify owner that the tabbar background has been double-clicked
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, self.GetId())
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnTabDClick(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_TAB_DCLICK`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        # notify owner that the tabbar background has been double-clicked
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK, self.GetId())
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        if not self.IsRenamable(event.GetSelection()):
+            return
+
+        self.EditTab(event.GetSelection())
+
+
+    def OnTabBeginDrag(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        self._last_drag_x = 0
+
+
+    def OnTabDragMotion(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_DRAG_MOTION`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        if self._textCtrl is not None:
+            self._textCtrl.StopEditing()
+
+        screen_pt = wx.GetMousePosition()
+        client_pt = self.ScreenToClient(screen_pt)
+        zero = wx.Point(0, 0)
+
+        src_tabs = event.GetEventObject()
+        dest_tabs = self.GetTabCtrlFromPoint(client_pt)
+
+        if dest_tabs == src_tabs:
+
+            # always hide the hint for inner-tabctrl drag
+            self._mgr.HideHint()
+
+            # if tab moving is not allowed, leave
+            if not self._agwFlags & AUI_NB_TAB_MOVE:
+                return
+
+            pt = dest_tabs.ScreenToClient(screen_pt)
+
+            # this is an inner-tab drag/reposition
+            dest_location_tab = dest_tabs.TabHitTest(pt.x, pt.y)
+
+            if dest_location_tab:
+
+                src_idx = event.GetSelection()
+                dest_idx = dest_tabs.GetIdxFromWindow(dest_location_tab)
+
+                # prevent jumpy drag
+                if (src_idx == dest_idx) or dest_idx == -1 or \
+                   (src_idx > dest_idx and self._last_drag_x <= pt.x) or \
+                   (src_idx < dest_idx and self._last_drag_x >= pt.x):
+
+                    self._last_drag_x = pt.x
+                    return
+
+                src_tab = dest_tabs.GetWindowFromIdx(src_idx)
+                dest_tabs.MovePage(src_tab, dest_idx)
+                self._tabs.MovePage(self._tabs.GetPage(src_idx).window, dest_idx)
+                dest_tabs.SetActivePage(dest_idx)
+                dest_tabs.DoShowHide()
+                dest_tabs.Refresh()
+                self._last_drag_x = pt.x
+
+            return
+
+        # if external drag is allowed, check if the tab is being dragged
+        # over a different AuiNotebook control
+        if self._agwFlags & AUI_NB_TAB_EXTERNAL_MOVE:
+
+            tab_ctrl = wx.FindWindowAtPoint(screen_pt)
+
+            # if we aren't over any window, stop here
+            if not tab_ctrl:
+                if self._agwFlags & AUI_NB_TAB_FLOAT:
+                    if self.IsMouseWellOutsideWindow():
+                        hintRect = wx.RectPS(screen_pt, (400, 300))
+                        # Use CallAfter so we overwrite the hint that might be
+                        # shown by our superclass:
+                        wx.CallAfter(self._mgr.ShowHint, hintRect)
+                return
+
+            # make sure we are not over the hint window
+            if not isinstance(tab_ctrl, wx.Frame):
+                while tab_ctrl:
+                    if isinstance(tab_ctrl, AuiTabCtrl):
+                        break
+
+                    tab_ctrl = tab_ctrl.GetParent()
+
+                if tab_ctrl:
+                    nb = tab_ctrl.GetParent()
+
+                    if nb != self:
+
+                        hint_rect = tab_ctrl.GetClientRect()
+                        hint_rect.x, hint_rect.y = tab_ctrl.ClientToScreenXY(hint_rect.x, hint_rect.y)
+                        self._mgr.ShowHint(hint_rect)
+                        return
+
+            else:
+
+                if not dest_tabs:
+                    # we are either over a hint window, or not over a tab
+                    # window, and there is no where to drag to, so exit
+                    return
+
+        if self._agwFlags & AUI_NB_TAB_FLOAT:
+            if self.IsMouseWellOutsideWindow():
+                hintRect = wx.RectPS(screen_pt, (400, 300))
+                # Use CallAfter so we overwrite the hint that might be
+                # shown by our superclass:
+                wx.CallAfter(self._mgr.ShowHint, hintRect)
+                return
+
+        # if there are less than two panes, split can't happen, so leave
+        if self._tabs.GetPageCount() < 2:
+            return
+
+        # if tab moving is not allowed, leave
+        if not self._agwFlags & AUI_NB_TAB_SPLIT:
+            return
+
+        if dest_tabs:
+
+            hint_rect = dest_tabs.GetRect()
+            hint_rect.x, hint_rect.y = self.ClientToScreenXY(hint_rect.x, hint_rect.y)
+            self._mgr.ShowHint(hint_rect)
+
+        else:
+            rect = self._mgr.CalculateHintRect(self._dummy_wnd, client_pt, zero)
+            if rect.IsEmpty():
+                self._mgr.HideHint()
+                return
+
+            hit_wnd = wx.FindWindowAtPoint(screen_pt)
+            if hit_wnd and not isinstance(hit_wnd, AuiNotebook):
+                tab_frame = self.GetTabFrameFromWindow(hit_wnd)
+                if tab_frame:
+                    hint_rect = wx.Rect(*tab_frame._rect)
+                    hint_rect.x, hint_rect.y = self.ClientToScreenXY(hint_rect.x, hint_rect.y)
+                    rect.Intersect(hint_rect)
+                    self._mgr.ShowHint(rect)
+                else:
+                    self._mgr.DrawHintRect(self._dummy_wnd, client_pt, zero)
+            else:
+                self._mgr.DrawHintRect(self._dummy_wnd, client_pt, zero)
+
+
+    def OnTabEndDrag(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_END_DRAG`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        self._mgr.HideHint()
+
+        src_tabs = event.GetEventObject()
+        if not src_tabs:
+            raise Exception("no source object?")
+
+        # get the mouse position, which will be used to determine the drop point
+        mouse_screen_pt = wx.GetMousePosition()
+        mouse_client_pt = self.ScreenToClient(mouse_screen_pt)
+
+        # check for an external move
+        if self._agwFlags & AUI_NB_TAB_EXTERNAL_MOVE:
+            tab_ctrl = wx.FindWindowAtPoint(mouse_screen_pt)
+
+            while tab_ctrl:
+
+                if isinstance(tab_ctrl, AuiTabCtrl):
+                    break
+
+                tab_ctrl = tab_ctrl.GetParent()
+
+            if tab_ctrl:
+
+                nb = tab_ctrl.GetParent()
+
+                if nb != self:
+
+                    # find out from the destination control
+                    # if it's ok to drop this tab here
+                    e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, self.GetId())
+                    e.SetSelection(event.GetSelection())
+                    e.SetOldSelection(event.GetSelection())
+                    e.SetEventObject(self)
+                    e.SetDragSource(self)
+                    e.Veto() # dropping must be explicitly approved by control owner
+
+                    nb.GetEventHandler().ProcessEvent(e)
+
+                    if not e.IsAllowed():
+
+                        # no answer or negative answer
+                        self._mgr.HideHint()
+                        return
+
+                    # drop was allowed
+                    src_idx = event.GetSelection()
+                    src_page = src_tabs.GetWindowFromIdx(src_idx)
+
+                    # Check that it's not an impossible parent relationship
+                    p = nb
+                    while p and not p.IsTopLevel():
+                        if p == src_page:
+                            return
+
+                        p = p.GetParent()
+
+                    # get main index of the page
+                    main_idx = self._tabs.GetIdxFromWindow(src_page)
+                    if main_idx == wx.NOT_FOUND:
+                        raise Exception("no source page?")
+
+                    # make a copy of the page info
+                    page_info = self._tabs.GetPage(main_idx)
+
+                    # remove the page from the source notebook
+                    self.RemovePage(main_idx)
+
+                    # reparent the page
+                    src_page.Reparent(nb)
+
+                    # Reparent the control in a tab (if any)
+                    if page_info.control:
+                        self.ReparentControl(page_info.control, tab_ctrl)
+
+                    # find out the insert idx
+                    dest_tabs = tab_ctrl
+                    pt = dest_tabs.ScreenToClient(mouse_screen_pt)
+
+                    target = dest_tabs.TabHitTest(pt.x, pt.y)
+                    insert_idx = -1
+                    if target:
+                        insert_idx = dest_tabs.GetIdxFromWindow(target)
+
+                    # add the page to the new notebook
+                    if insert_idx == -1:
+                        insert_idx = dest_tabs.GetPageCount()
+
+                    dest_tabs.InsertPage(page_info.window, page_info, insert_idx)
+                    nb._tabs.AddPage(page_info.window, page_info)
+
+                    nb.DoSizing()
+                    dest_tabs.DoShowHide()
+                    dest_tabs.Refresh()
+
+                    # set the selection in the destination tab control
+                    nb.SetSelectionToPage(page_info)
+
+                    # notify owner that the tab has been dragged
+                    e2 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, self.GetId())
+                    e2.SetSelection(event.GetSelection())
+                    e2.SetOldSelection(event.GetSelection())
+                    e2.SetEventObject(self)
+                    self.GetEventHandler().ProcessEvent(e2)
+
+                    # notify the target notebook that the tab has been dragged
+                    e3 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, nb.GetId())
+                    e3.SetSelection(insert_idx)
+                    e3.SetOldSelection(insert_idx)
+                    e3.SetEventObject(nb)
+                    nb.GetEventHandler().ProcessEvent(e3)
+
+                    return
+
+        if self._agwFlags & AUI_NB_TAB_FLOAT:
+            self._mgr.HideHint()
+            if self.IsMouseWellOutsideWindow():
+                # Use CallAfter so we our superclass can deal with the event first
+                wx.CallAfter(self.FloatPage, self.GetSelection())
+                event.Skip()
+                return
+
+        # only perform a tab split if it's allowed
+        dest_tabs = None
+
+        if self._agwFlags & AUI_NB_TAB_SPLIT and self._tabs.GetPageCount() >= 2:
+
+            # If the pointer is in an existing tab frame, do a tab insert
+            hit_wnd = wx.FindWindowAtPoint(mouse_screen_pt)
+            tab_frame = self.GetTabFrameFromTabCtrl(hit_wnd)
+            insert_idx = -1
+
+            if tab_frame:
+
+                dest_tabs = tab_frame._tabs
+
+                if dest_tabs == src_tabs:
+                    return
+
+                pt = dest_tabs.ScreenToClient(mouse_screen_pt)
+                target = dest_tabs.TabHitTest(pt.x, pt.y)
+
+                if target:
+                    insert_idx = dest_tabs.GetIdxFromWindow(target)
+
+            else:
+
+                zero = wx.Point(0, 0)
+                rect = self._mgr.CalculateHintRect(self._dummy_wnd, mouse_client_pt, zero)
+
+                if rect.IsEmpty():
+                    # there is no suitable drop location here, exit out
+                    return
+
+                # If there is no tabframe at all, create one
+                new_tabs = TabFrame(self)
+                new_tabs._rect = wx.RectPS(wx.Point(0, 0), self.CalculateNewSplitSize())
+                new_tabs.SetTabCtrlHeight(self._tab_ctrl_height)
+                self._tab_id_counter += 1
+                new_tabs._tabs = AuiTabCtrl(self, self._tab_id_counter)
+                new_tabs._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone())
+                new_tabs._tabs.SetAGWFlags(self._agwFlags)
+
+                self._mgr.AddPane(new_tabs, framemanager.AuiPaneInfo().Bottom().CaptionVisible(False), mouse_client_pt)
+                self._mgr.Update()
+                dest_tabs = new_tabs._tabs
+
+            # remove the page from the source tabs
+            page_info = src_tabs.GetPage(event.GetSelection())
+
+            if page_info.control:
+                self.ReparentControl(page_info.control, dest_tabs)
+
+            page_info.active = False
+            src_tabs.RemovePage(page_info.window)
+
+            if src_tabs.GetPageCount() > 0:
+                src_tabs.SetActivePage(0)
+                src_tabs.DoShowHide()
+                src_tabs.Refresh()
+
+            # add the page to the destination tabs
+            if insert_idx == -1:
+                insert_idx = dest_tabs.GetPageCount()
+
+            dest_tabs.InsertPage(page_info.window, page_info, insert_idx)
+
+            if src_tabs.GetPageCount() == 0:
+                self.RemoveEmptyTabFrames()
+
+            self.DoSizing()
+            dest_tabs.DoShowHide()
+            dest_tabs.Refresh()
+
+            # force the set selection function reset the selection
+            self._curpage = -1
+
+            # set the active page to the one we just split off
+            self.SetSelectionToPage(page_info)
+
+            self.UpdateHintWindowSize()
+
+        # notify owner that the tab has been dragged
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, self.GetId())
+        e.SetSelection(event.GetSelection())
+        e.SetOldSelection(event.GetSelection())
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnTabCancelDrag(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_CANCEL_DRAG`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        self._mgr.HideHint()
+
+        src_tabs = event.GetEventObject()
+        if not src_tabs:
+            raise Exception("no source object?")
+
+
+    def IsMouseWellOutsideWindow(self):
+        """ Returns whether the mouse is well outside the L{AuiNotebook} screen rectangle. """
+
+        screen_rect = self.GetScreenRect()
+        screen_rect.Inflate(50, 50)
+
+        return not screen_rect.Contains(wx.GetMousePosition())
+
+
+    def FloatPage(self, page_index):
+        """
+        Float the page in `page_index` by reparenting it to a floating frame.
+
+        :param `page_index`: the index of the page to be floated.
+
+        :warning: When the notebook is more or less full screen, tabs cannot be dragged far
+         enough outside of the notebook to become floating pages.
+        """
+
+        root_manager = framemanager.GetManager(self)
+        page_title = self.GetPageText(page_index)
+        page_contents = self.GetPage(page_index)
+        page_bitmap = self.GetPageBitmap(page_index)
+        text_colour = self.GetPageTextColour(page_index)
+        info = self.GetPageInfo(page_index)
+
+        if root_manager and root_manager != self._mgr:
+            root_manager = framemanager.GetManager(self)
+
+            if hasattr(page_contents, "__floating_size__"):
+                floating_size = wx.Size(*page_contents.__floating_size__)
+            else:
+                floating_size = page_contents.GetBestSize()
+                if floating_size == wx.DefaultSize:
+                    floating_size = wx.Size(300, 200)
+
+            page_contents.__page_index__ = page_index
+            page_contents.__aui_notebook__ = self
+            page_contents.__text_colour__ = text_colour
+            page_contents.__control__ = info.control
+
+            if info.control:
+                info.control.Reparent(page_contents)
+                info.control.Hide()
+                info.control = None
+
+            self.RemovePage(page_index)
+            self.RemoveEmptyTabFrames()
+
+            pane_info = framemanager.AuiPaneInfo().Float().FloatingPosition(wx.GetMousePosition()). \
+                        FloatingSize(floating_size).BestSize(floating_size).Name("__floating__%s"%page_title). \
+                        Caption(page_title).Icon(page_bitmap)
+            root_manager.AddPane(page_contents, pane_info)
+            root_manager.Bind(framemanager.EVT_AUI_PANE_CLOSE, self.OnCloseFloatingPage)
+            self.GetActiveTabCtrl().DoShowHide()
+            self.DoSizing()
+            root_manager.Update()
+
+        else:
+            frame = wx.Frame(self, title=page_title,
+                             style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_TOOL_WINDOW|
+                                   wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR)
+
+            if info.control:
+                info.control.Reparent(frame)
+                info.control.Hide()
+
+            frame.bitmap = page_bitmap
+            frame.page_index = page_index
+            frame.text_colour = text_colour
+            frame.control = info.control
+            page_contents.Reparent(frame)
+            frame.Bind(wx.EVT_CLOSE, self.OnCloseFloatingPage)
+            frame.Move(wx.GetMousePosition())
+            frame.Show()
+            self.RemovePage(page_index)
+
+            self.RemoveEmptyTabFrames()
+
+        wx.CallAfter(self.RemoveEmptyTabFrames)
+
+
+    def OnCloseFloatingPage(self, event):
+        """
+        Handles the ``wx.EVT_CLOSE`` event for a floating page in L{AuiNotebook}.
+
+        :param `event`: a `wx.CloseEvent` event to be processed.
+        """
+
+        root_manager = framemanager.GetManager(self)
+        if root_manager and root_manager != self._mgr:
+            pane = event.pane
+            if pane.name.startswith("__floating__"):
+                self.ReDockPage(pane)
+                return
+
+            event.Skip()
+        else:
+            event.Skip()
+            frame = event.GetEventObject()
+            page_title = frame.GetTitle()
+            page_contents = list(frame.GetChildren())[-1]
+            page_contents.Reparent(self)
+            self.InsertPage(frame.page_index, page_contents, page_title, select=True, bitmap=frame.bitmap, control=frame.control)
+
+            if frame.control:
+                src_tabs, idx = self.FindTab(page_contents)
+                frame.control.Reparent(src_tabs)
+                frame.control.Hide()
+                frame.control = None
+
+            self.SetPageTextColour(frame.page_index, frame.text_colour)
+
+
+    def ReDockPage(self, pane):
+        """
+        Re-docks a floating L{AuiNotebook} tab in the original position, when possible.
+
+        :param `pane`: an instance of L{framemanager.AuiPaneInfo}.
+        """
+
+        root_manager = framemanager.GetManager(self)
+
+        pane.window.__floating_size__ = wx.Size(*pane.floating_size)
+        page_index = pane.window.__page_index__
+        text_colour = pane.window.__text_colour__
+        control = pane.window.__control__
+
+        root_manager.DetachPane(pane.window)
+        self.InsertPage(page_index, pane.window, pane.caption, True, pane.icon, control=control)
+
+        self.SetPageTextColour(page_index, text_colour)
+        self.GetActiveTabCtrl().DoShowHide()
+        self.DoSizing()
+        if control:
+            self.UpdateTabCtrlHeight(force=True)
+
+        self._mgr.Update()
+        root_manager.Update()
+
+
+    def GetTabCtrlFromPoint(self, pt):
+        """
+        Returns the tab control at the specified point.
+
+        :param `pt`: a `wx.Point` object.
+        """
+
+        # if we've just removed the last tab from the source
+        # tab set, the remove the tab control completely
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+            if tabframe._tab_rect.Contains(pt):
+                return tabframe._tabs
+
+        return None
+
+
+    def GetTabFrameFromTabCtrl(self, tab_ctrl):
+        """
+        Returns the tab frame associated with a tab control.
+
+        :param `tab_ctrl`: an instance of L{AuiTabCtrl}.
+        """
+
+        # if we've just removed the last tab from the source
+        # tab set, the remove the tab control completely
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+            if tabframe._tabs == tab_ctrl:
+                return tabframe
+
+        return None
+
+
+    def GetTabFrameFromWindow(self, wnd):
+        """
+        Returns the tab frame associated with a window.
+
+        :param `wnd`: an instance of `wx.Window`.
+        """
+
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            tabframe = pane.window
+            for page in tabframe._tabs.GetPages():
+                if wnd == page.window:
+                    return tabframe
+
+        return None
+
+
+    def RemoveEmptyTabFrames(self):
+        """ Removes all the empty tab frames. """
+
+        # if we've just removed the last tab from the source
+        # tab set, the remove the tab control completely
+        all_panes = self._mgr.GetAllPanes()
+
+        for indx in xrange(len(all_panes)-1, -1, -1):
+            pane = all_panes[indx]
+            if pane.name == "dummy":
+                continue
+
+            tab_frame = pane.window
+            if tab_frame._tabs.GetPageCount() == 0:
+                self._mgr.DetachPane(tab_frame)
+                tab_frame._tabs.Destroy()
+                tab_frame._tabs = None
+                del tab_frame
+
+        # check to see if there is still a center pane
+        # if there isn't, make a frame the center pane
+        first_good = None
+        center_found = False
+
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+
+            if pane.dock_direction == AUI_DOCK_CENTRE:
+                center_found = True
+            if not first_good:
+                first_good = pane.window
+
+        if not center_found and first_good:
+            self._mgr.GetPane(first_good).Centre()
+
+        if not self.IsBeingDeleted():
+            self._mgr.Update()
+
+
+    def OnChildFocusNotebook(self, event):
+        """
+        Handles the ``wx.EVT_CHILD_FOCUS`` event for L{AuiNotebook}.
+
+        :param `event`: a `wx.ChildFocusEvent` event to be processed.
+        """
+
+        # if we're dragging a tab, don't change the current selection.
+        # This code prevents a bug that used to happen when the hint window
+        # was hidden.  In the bug, the focus would return to the notebook
+        # child, which would then enter this handler and call
+        # SetSelection, which is not desired turn tab dragging.
+
+        event.Skip()
+
+        all_panes = self._mgr.GetAllPanes()
+        for pane in all_panes:
+            if pane.name == "dummy":
+                continue
+            tabframe = pane.window
+            if tabframe._tabs.IsDragging():
+                return
+
+##        # change the tab selection to the child
+##        # which was focused
+##        idx = self._tabs.GetIdxFromWindow(event.GetWindow())
+##        if idx != -1 and idx != self._curpage:
+##            self.SetSelection(idx)
+
+
+    def SetNavigatorIcon(self, bmp):
+        """
+        Sets the icon used by the L{TabNavigatorWindow}.
+
+        :param `bmp`: an instance of `wx.Bitmap`.
+        """
+
+        if isinstance(bmp, wx.Bitmap) and bmp.IsOk():
+            # Make sure image is proper size
+            if bmp.GetSize() != (16, 16):
+                img = bmp.ConvertToImage()
+                img.Rescale(16, 16, wx.IMAGE_QUALITY_HIGH)
+                bmp = wx.BitmapFromImage(img)
+            self._naviIcon = bmp
+        else:
+            raise TypeError, "SetNavigatorIcon requires a valid bitmap"
+
+
+    def OnNavigationKeyNotebook(self, event):
+        """
+        Handles the ``wx.EVT_NAVIGATION_KEY`` event for L{AuiNotebook}.
+
+        :param `event`: a `wx.NavigationKeyEvent` event to be processed.
+        """
+
+        if event.IsWindowChange():
+            if self._agwFlags & AUI_NB_SMART_TABS:
+                if not self._popupWin:
+                    self._popupWin = TabNavigatorWindow(self, self._naviIcon)
+                    self._popupWin.SetReturnCode(wx.ID_OK)
+                    self._popupWin.ShowModal()
+                    idx = self._popupWin.GetSelectedPage()
+                    self._popupWin.Destroy()
+                    self._popupWin = None
+                    # Need to do CallAfter so that the selection and its
+                    # associated events get processed outside the context of
+                    # this key event. Not doing so causes odd issues with the
+                    # window focus under certain use cases on Windows.
+                    wx.CallAfter(self.SetSelection, idx, True)
+                else:
+                    # a dialog is already opened
+                    self._popupWin.OnNavigationKey(event)
+                    return
+            else:
+                # change pages
+                # FIXME: the problem with this is that if we have a split notebook,
+                # we selection may go all over the place.
+                self.AdvanceSelection(event.GetDirection())
+
+        else:
+            # we get this event in 3 cases
+            #
+            # a) one of our pages might have generated it because the user TABbed
+            # out from it in which case we should propagate the event upwards and
+            # our parent will take care of setting the focus to prev/next sibling
+            #
+            # or
+            #
+            # b) the parent panel wants to give the focus to us so that we
+            # forward it to our selected page. We can't deal with this in
+            # OnSetFocus() because we don't know which direction the focus came
+            # from in this case and so can't choose between setting the focus to
+            # first or last panel child
+            #
+            # or
+            #
+            # c) we ourselves (see MSWTranslateMessage) generated the event
+            #
+            parent = self.GetParent()
+
+            # the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
+            isFromParent = event.GetEventObject() == parent
+            isFromSelf = event.GetEventObject() == self
+
+            if isFromParent or isFromSelf:
+
+                # no, it doesn't come from child, case (b) or (c): forward to a
+                # page but only if direction is backwards (TAB) or from ourselves,
+                if self.GetSelection() != wx.NOT_FOUND and (not event.GetDirection() or isFromSelf):
+
+                    # so that the page knows that the event comes from it's parent
+                    # and is being propagated downwards
+                    event.SetEventObject(self)
+
+                    page = self.GetPage(self.GetSelection())
+                    if not page.GetEventHandler().ProcessEvent(event):
+                        page.SetFocus()
+
+                    #else: page manages focus inside it itself
+
+                else: # otherwise set the focus to the notebook itself
+
+                    self.SetFocus()
+
+            else:
+
+                # send this event back for the 'wraparound' focus.
+                winFocus = event.GetCurrentFocus()
+
+                if winFocus:
+                    event.SetEventObject(self)
+                    winFocus.GetEventHandler().ProcessEvent(event)
+
+
+    def OnTabButton(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_BUTTON`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        button_id = event.GetInt()
+
+        if button_id == AUI_BUTTON_CLOSE:
+
+            selection = event.GetSelection()
+
+            if selection == -1:
+
+                # if the close button is to the right, use the active
+                # page selection to determine which page to close
+                selection = tabs.GetActivePage()
+
+            if selection == -1 or not tabs.GetEnabled(selection):
+                return
+
+            if selection != -1:
+
+                close_wnd = tabs.GetWindowFromIdx(selection)
+
+                if close_wnd.GetName() == "__fake__page__":
+                    # This is a notebook preview
+                    previous_active, page_status = close_wnd.__previousStatus
+                    for page, status in zip(tabs.GetPages(), page_status):
+                        page.enabled = status
+
+                    main_idx = self._tabs.GetIdxFromWindow(close_wnd)
+                    self.DeletePage(main_idx)
+
+                    if previous_active >= 0:
+                        tabs.SetActivePage(previous_active)
+                        page_count = tabs.GetPageCount()
+                        selection = -1
+
+                        for page in xrange(page_count):
+                            # remove the page from the source tabs
+                            page_info = tabs.GetPage(page)
+                            if page_info.active:
+                                selection = page
+                                break
+
+                        tabs.DoShowHide()
+                        self.DoSizing()
+                        tabs.Refresh()
+
+                        if selection >= 0:
+                            wx.CallAfter(tabs.MakeTabVisible, selection, self)
+
+                    # Don't fire the event
+                    return
+
+                # ask owner if it's ok to close the tab
+                e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, self.GetId())
+                idx = self._tabs.GetIdxFromWindow(close_wnd)
+                e.SetSelection(idx)
+                e.SetOldSelection(event.GetSelection())
+                e.SetEventObject(self)
+                self.GetEventHandler().ProcessEvent(e)
+                if not e.IsAllowed():
+                    return
+
+                if repr(close_wnd.__class__).find("AuiMDIChildFrame") >= 0:
+                    close_wnd.Close()
+
+                else:
+                    main_idx = self._tabs.GetIdxFromWindow(close_wnd)
+                    self.DeletePage(main_idx)
+
+                # notify owner that the tab has been closed
+                e2 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, self.GetId())
+                e2.SetSelection(idx)
+                e2.SetEventObject(self)
+                self.GetEventHandler().ProcessEvent(e2)
+
+                if self.GetPageCount() == 0:
+                    mgr = self.GetAuiManager()
+                    win = mgr.GetManagedWindow()
+                    win.SendSizeEvent()
+
+
+    def OnTabMiddleDown(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        # patch event through to owner
+        wnd = tabs.GetWindowFromIdx(event.GetSelection())
+
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, self.GetId())
+        e.SetSelection(self._tabs.GetIdxFromWindow(wnd))
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnTabMiddleUp(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_TAB_MIDDLE_UP`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        # if the AUI_NB_MIDDLE_CLICK_CLOSE is specified, middle
+        # click should act like a tab close action.  However, first
+        # give the owner an opportunity to handle the middle up event
+        # for custom action
+
+        wnd = tabs.GetWindowFromIdx(event.GetSelection())
+
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, self.GetId())
+        e.SetSelection(self._tabs.GetIdxFromWindow(wnd))
+        e.SetEventObject(self)
+        if self.GetEventHandler().ProcessEvent(e):
+            return
+        if not e.IsAllowed():
+            return
+
+        # check if we are supposed to close on middle-up
+        if self._agwFlags & AUI_NB_MIDDLE_CLICK_CLOSE == 0:
+            return
+
+        # simulate the user pressing the close button on the tab
+        event.SetInt(AUI_BUTTON_CLOSE)
+        self.OnTabButton(event)
+
+
+    def OnTabRightDown(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_TAB_RIGHT_DOWN`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        # patch event through to owner
+        wnd = tabs.GetWindowFromIdx(event.GetSelection())
+
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, self.GetId())
+        e.SetSelection(self._tabs.GetIdxFromWindow(wnd))
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+
+    def OnTabRightUp(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_TAB_RIGHT_UP`` event for L{AuiNotebook}.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        tabs = event.GetEventObject()
+        if not tabs.GetEnabled(event.GetSelection()):
+            return
+
+        # patch event through to owner
+        wnd = tabs.GetWindowFromIdx(event.GetSelection())
+
+        e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, self.GetId())
+        e.SetSelection(self._tabs.GetIdxFromWindow(wnd))
+        e.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(e)
+
+
+    def SetNormalFont(self, font):
+        """
+        Sets the normal font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._normal_font = font
+        self.GetArtProvider().SetNormalFont(font)
+
+
+    def SetSelectedFont(self, font):
+        """
+        Sets the selected tab font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._selected_font = font
+        self.GetArtProvider().SetSelectedFont(font)
+
+
+    def SetMeasuringFont(self, font):
+        """
+        Sets the font for calculating text measurements.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self.GetArtProvider().SetMeasuringFont(font)
+
+
+    def SetFont(self, font):
+        """
+        Sets the tab font.
+
+        :param `font`: a `wx.Font` object.
+
+        :note: Overridden from `wx.PyPanel`.
+        """
+
+        wx.PyPanel.SetFont(self, font)
+
+        selectedFont = wx.Font(font.GetPointSize(), font.GetFamily(),
+                               font.GetStyle(), wx.BOLD, font.GetUnderlined(),
+                               font.GetFaceName(), font.GetEncoding())
+
+        self.SetNormalFont(font)
+        self.SetSelectedFont(selectedFont)
+        self.SetMeasuringFont(selectedFont)
+
+        # Recalculate tab container size based on new font
+        self.UpdateTabCtrlHeight(force=False)
+        self.DoSizing()
+
+        return True
+
+
+    def GetTabCtrlHeight(self):
+        """ Returns the tab control height. """
+
+        return self._tab_ctrl_height
+
+
+    def GetHeightForPageHeight(self, pageHeight):
+        """
+        Gets the height of the notebook for a given page height.
+
+        :param `pageHeight`: the given page height.
+        """
+
+        self.UpdateTabCtrlHeight()
+
+        tabCtrlHeight = self.GetTabCtrlHeight()
+        decorHeight = 2
+        return tabCtrlHeight + pageHeight + decorHeight
+
+
+    def AdvanceSelection(self, forward=True, wrap=True):
+        """
+        Cycles through the tabs.
+
+        :param `forward`: whether to advance forward or backward;
+        :param `wrap`: ``True`` to return to the first tab if we reach the last tab.
+
+        :note: The call to this function generates the page changing events.
+        """
+
+        tabCtrl = self.GetActiveTabCtrl()
+        newPage = -1
+
+        focusWin = tabCtrl.FindFocus()
+        activePage = tabCtrl.GetActivePage()
+        lenPages = len(tabCtrl.GetPages())
+
+        if lenPages == 1:
+            return False
+
+        if forward:
+            if lenPages > 1:
+
+                if activePage == -1 or activePage == lenPages - 1:
+                    if not wrap:
+                        return False
+
+                    newPage = 0
+
+                elif activePage < lenPages - 1:
+                    newPage = activePage + 1
+
+        else:
+
+            if lenPages > 1:
+                if activePage == -1 or activePage == 0:
+                    if not wrap:
+                        return False
+
+                    newPage = lenPages - 1
+
+                elif activePage > 0:
+                    newPage = activePage - 1
+
+
+        if newPage != -1:
+            if not self.GetEnabled(newPage):
+                return False
+
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl.GetId())
+            e.SetSelection(newPage)
+            e.SetOldSelection(activePage)
+            e.SetEventObject(tabCtrl)
+            self.GetEventHandler().ProcessEvent(e)
+
+##        if focusWin:
+##            focusWin.SetFocus()
+
+        return True
+
+
+    def ShowWindowMenu(self):
+        """
+        Shows the window menu for the active tab control associated with this
+        notebook, and returns ``True`` if a selection was made.
+        """
+
+        tabCtrl = self.GetActiveTabCtrl()
+        idx = tabCtrl.GetArtProvider().ShowDropDown(tabCtrl, tabCtrl.GetPages(), tabCtrl.GetActivePage())
+
+        if not self.GetEnabled(idx):
+            return False
+
+        if idx != -1:
+            e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl.GetId())
+            e.SetSelection(idx)
+            e.SetOldSelection(tabCtrl.GetActivePage())
+            e.SetEventObject(tabCtrl)
+            self.GetEventHandler().ProcessEvent(e)
+
+            return True
+
+        else:
+
+            return False
+
+
+    def AddTabAreaButton(self, id, location, normal_bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap):
+        """
+        Adds a button in the tab area.
+
+        :param `id`: the button identifier. This can be one of the following:
+
+         ==============================  =================================
+         Button Identifier               Description
+         ==============================  =================================
+         ``AUI_BUTTON_CLOSE``            Shows a close button on the tab area
+         ``AUI_BUTTON_WINDOWLIST``       Shows a window list button on the tab area
+         ``AUI_BUTTON_LEFT``             Shows a left button on the tab area
+         ``AUI_BUTTON_RIGHT``            Shows a right button on the tab area
+         ==============================  =================================
+
+        :param `location`: the button location. Can be ``wx.LEFT`` or ``wx.RIGHT``;
+        :param `normal_bitmap`: the bitmap for an enabled tab;
+        :param `disabled_bitmap`: the bitmap for a disabled tab.
+        """
+
+        active_tabctrl = self.GetActiveTabCtrl()
+        active_tabctrl.AddButton(id, location, normal_bitmap, disabled_bitmap)
+
+
+    def RemoveTabAreaButton(self, id):
+        """
+        Removes a button from the tab area.
+
+        :param `id`: the button identifier. See L{AddTabAreaButton} for a list of button identifiers.
+
+        :see: L{AddTabAreaButton}
+        """
+
+        active_tabctrl = self.GetActiveTabCtrl()
+        active_tabctrl.RemoveButton(id)
+
+
+    def HasMultiplePages(self):
+        """
+        This method should be overridden to return ``True`` if this window has multiple pages. All
+        standard class with multiple pages such as `wx.Notebook`, `wx.Listbook` and `wx.Treebook`
+        already override it to return ``True`` and user-defined classes with similar behaviour
+        should do it as well to allow the library to handle such windows appropriately.
+
+        :note: Overridden from `wx.PyPanel`.
+        """
+
+        return True
+
+
+    def GetDefaultBorder(self):
+        """ Returns the default border style for L{AuiNotebook}. """
+
+        return wx.BORDER_NONE
+
+
+    def NotebookPreview(self, thumbnail_size=200):
+        """
+        Generates a preview of all the pages in the notebook (MSW and GTK only).
+
+        :param `thumbnail_size`: the maximum size of every page thumbnail.
+
+        :note: this functionality is currently unavailable on wxMac.
+        """
+
+        if wx.Platform == "__WXMAC__":
+            return False
+
+        tabCtrl = self.GetActiveTabCtrl()
+        activePage = tabCtrl.GetActivePage()
+        pages = tabCtrl.GetPages()
+
+        pageStatus, pageText = [], []
+
+        for indx, page in enumerate(pages):
+
+            pageStatus.append(page.enabled)
+
+            if not page.enabled:
+                continue
+
+            self.SetSelectionToPage(page)
+            pageText.append(page.caption)
+
+            rect = page.window.GetScreenRect()
+            bmp = RescaleScreenShot(TakeScreenShot(rect), thumbnail_size)
+
+            page.enabled = False
+            if indx == 0:
+                il = wx.ImageList(bmp.GetWidth(), bmp.GetHeight(), True)
+
+            il.Add(bmp)
+
+        # create the list control
+        listCtrl = wx.ListCtrl(self, style=wx.LC_ICON|wx.LC_AUTOARRANGE|wx.LC_HRULES|wx.LC_VRULES,
+                               name="__fake__page__")
+
+        # assign the image list to it
+        listCtrl.AssignImageList(il, wx.IMAGE_LIST_NORMAL)
+        listCtrl.__previousStatus = [activePage, pageStatus]
+
+        # create some items for the list
+        for indx, text in enumerate(pageText):
+            listCtrl.InsertImageStringItem(10000, text, indx)
+
+        self.AddPage(listCtrl, "AuiNotebook Preview", True, bitmap=auinotebook_preview.GetBitmap(), disabled_bitmap=wx.NullBitmap)
+        return True
+
+
+    def SetRenamable(self, page_idx, renamable):
+        """
+        Sets whether a tab can be renamed via a left double-click or not.
+
+        :param `page_idx`: the page index;
+        :param `renamable`: ``True`` if the page can be renamed.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        # update our own tab catalog
+        page_info = self._tabs.GetPage(page_idx)
+        page_info.renamable = renamable
+
+        # update what's on screen
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        info = ctrl.GetPage(ctrl_idx)
+        info.renamable = page_info.renamable
+
+        return True
+
+
+    def IsRenamable(self, page_idx):
+        """
+        Returns whether a tab can be renamed or not.
+
+        :param `page_idx`: the page index.
+
+        :returns: ``True`` is a page can be renamed, ``False`` otherwise.
+        """
+
+        if page_idx >= self._tabs.GetPageCount():
+            return False
+
+        page_info = self._tabs.GetPage(page_idx)
+        return page_info.renamable
+
+
+    def OnRenameCancelled(self, page_index):
+        """
+        Called by L{TabTextCtrl}, to cancel the changes and to send the
+        `EVT_AUINOTEBOOK_END_LABEL_EDIT` event.
+
+        :param `page_index`: the page index in the notebook.
+        """
+
+        # let owner know that the edit was cancelled
+        evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT, self.GetId())
+
+        evt.SetSelection(page_index)
+        evt.SetEventObject(self)
+        evt.SetLabel("")
+        evt.SetEditCanceled(True)
+        self.GetEventHandler().ProcessEvent(evt)
+
+
+    def OnRenameAccept(self, page_index, value):
+        """
+        Called by L{TabTextCtrl}, to accept the changes and to send the
+        `EVT_AUINOTEBOOK_END_LABEL_EDIT` event.
+
+        :param `page_index`: the page index in the notebook;
+        :param `value`: the new label for the tab.
+        """
+
+        evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT, self.GetId())
+        evt.SetSelection(page_index)
+        evt.SetEventObject(self)
+        evt.SetLabel(value)
+        evt.SetEditCanceled(False)
+
+        return not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed()
+
+
+    def ResetTextControl(self):
+        """ Called by L{TabTextCtrl} when it marks itself for deletion. """
+
+        if not self._textCtrl:
+            return
+
+        self._textCtrl.Destroy()
+        self._textCtrl = None
+
+        # tab height might have changed
+        self.UpdateTabCtrlHeight(force=True)
+
+
+    def EditTab(self, page_index):
+        """
+        Starts the editing of an item label, sending a `EVT_AUINOTEBOOK_BEGIN_LABEL_EDIT` event.
+
+        :param `page_index`: the page index we want to edit.
+        """
+
+        if page_index >= self._tabs.GetPageCount():
+            return False
+
+        if not self.IsRenamable(page_index):
+            return False
+
+        page_info = self._tabs.GetPage(page_index)
+        ctrl, ctrl_idx = self.FindTab(page_info.window)
+        if not ctrl:
+            return False
+
+        evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_LABEL_EDIT, self.GetId())
+        evt.SetSelection(page_index)
+        evt.SetEventObject(self)
+        if self.GetEventHandler().ProcessEvent(evt) and not evt.IsAllowed():
+            # vetoed by user
+            return False
+
+        if self._textCtrl is not None and page_info != self._textCtrl.item():
+            self._textCtrl.StopEditing()
+
+        self._textCtrl = TabTextCtrl(ctrl, page_info, page_index)
+        self._textCtrl.SetFocus()
+
+        return True
diff --git a/aui/dockart.py b/aui/dockart.py
new file mode 100644 (file)
index 0000000..17da477
--- /dev/null
@@ -0,0 +1,1162 @@
+"""
+Dock art provider code - a dock provider provides all drawing functionality to
+the AUI dock manager. This allows the dock manager to have a plugable look-and-feel.
+
+By default, a L{AuiManager} uses an instance of this class called L{AuiDefaultDockArt}
+which provides bitmap art and a colour scheme that is adapted to the major platforms'
+look. You can either derive from that class to alter its behaviour or write a
+completely new dock art class. Call L{AuiManager.SetArtProvider} to make use this
+new dock art.
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+import types
+
+from aui_utilities import BitmapFromBits, StepColour, ChopText, GetBaseColour
+from aui_utilities import DrawGradientRectangle, DrawMACCloseButton
+from aui_utilities import DarkenBitmap, LightContrastColour
+from aui_constants import *
+
+optionActive = 2**14
+
+_ctypes = False
+
+# Try to import winxptheme for ModernDockArt
+if wx.Platform == "__WXMSW__":
+    try:
+        import ctypes
+        import winxptheme
+        _ctypes = True
+    except ImportError:
+        pass
+
+# -- AuiDefaultDockArt class implementation --
+
+class AuiDefaultDockArt(object):
+    """
+    Dock art provider code - a dock provider provides all drawing functionality
+    to the AUI dock manager. This allows the dock manager to have a plugable
+    look-and-feel.
+
+    By default, a L{AuiManager} uses an instance of this class called L{AuiDefaultDockArt}
+    which provides bitmap art and a colour scheme that is adapted to the major
+    platforms' look. You can either derive from that class to alter its behaviour or
+    write a completely new dock art class.
+    
+    Call L{AuiManager.SetArtProvider} to make use this new dock art.
+
+
+    **Metric Ordinals**
+
+    These are the possible pane dock art settings for L{AuiManager}:
+
+    ================================================  ======================================
+    Metric Ordinal Constant                           Description
+    ================================================  ======================================
+    ``AUI_DOCKART_SASH_SIZE``                         Customizes the sash size
+    ``AUI_DOCKART_CAPTION_SIZE``                      Customizes the caption size
+    ``AUI_DOCKART_GRIPPER_SIZE``                      Customizes the gripper size
+    ``AUI_DOCKART_PANE_BORDER_SIZE``                  Customizes the pane border size
+    ``AUI_DOCKART_PANE_BUTTON_SIZE``                  Customizes the pane button size
+    ``AUI_DOCKART_BACKGROUND_COLOUR``                 Customizes the background colour
+    ``AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR``        Customizes the background gradient colour
+    ``AUI_DOCKART_SASH_COLOUR``                       Customizes the sash colour
+    ``AUI_DOCKART_ACTIVE_CAPTION_COLOUR``             Customizes the active caption colour
+    ``AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR``    Customizes the active caption gradient colour
+    ``AUI_DOCKART_INACTIVE_CAPTION_COLOUR``           Customizes the inactive caption colour
+    ``AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR``  Customizes the inactive gradient caption colour
+    ``AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR``        Customizes the active caption text colour
+    ``AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR``      Customizes the inactive caption text colour
+    ``AUI_DOCKART_BORDER_COLOUR``                     Customizes the border colour
+    ``AUI_DOCKART_GRIPPER_COLOUR``                    Customizes the gripper colour
+    ``AUI_DOCKART_CAPTION_FONT``                      Customizes the caption font
+    ``AUI_DOCKART_GRADIENT_TYPE``                     Customizes the gradient type (no gradient, vertical or horizontal)
+    ``AUI_DOCKART_DRAW_SASH_GRIP``                    Draw a sash grip on the sash
+    ================================================  ======================================
+
+
+    **Gradient Types**
+
+    These are the possible gradient dock art settings for L{AuiManager}:
+
+    ============================================  ======================================
+    Gradient Constant                             Description 
+    ============================================  ======================================
+    ``AUI_GRADIENT_NONE``                         No gradient on the captions
+    ``AUI_GRADIENT_VERTICAL``                     Vertical gradient on the captions
+    ``AUI_GRADIENT_HORIZONTAL``                   Horizontal gradient on the captions
+    ============================================  ======================================
+
+
+    **Button States**
+
+    These are the possible pane button / L{AuiNotebook} button / L{AuiToolBar} button states:
+
+    ============================================  ======================================
+    Button State Constant                         Description     
+    ============================================  ======================================
+    ``AUI_BUTTON_STATE_NORMAL``                   Normal button state
+    ``AUI_BUTTON_STATE_HOVER``                    Hovered button state
+    ``AUI_BUTTON_STATE_PRESSED``                  Pressed button state
+    ``AUI_BUTTON_STATE_DISABLED``                 Disabled button state
+    ``AUI_BUTTON_STATE_HIDDEN``                   Hidden button state
+    ``AUI_BUTTON_STATE_CHECKED``                  Checked button state
+    ============================================  ======================================
+
+
+    **Button Identifiers**
+
+    These are the possible pane button / L{AuiNotebook} button / L{AuiToolBar} button identifiers:
+
+    ============================================  ======================================
+    Button Identifier                             Description     
+    ============================================  ======================================
+    ``AUI_BUTTON_CLOSE``                          Shows a close button on the pane
+    ``AUI_BUTTON_MAXIMIZE_RESTORE``               Shows a maximize/restore button on the pane
+    ``AUI_BUTTON_MINIMIZE``                       Shows a minimize button on the pane
+    ``AUI_BUTTON_PIN``                            Shows a pin button on the pane
+    ``AUI_BUTTON_OPTIONS``                        Shows an option button on the pane (not implemented)
+    ``AUI_BUTTON_WINDOWLIST``                     Shows a window list button on the pane (for L{AuiNotebook})
+    ``AUI_BUTTON_LEFT``                           Shows a left button on the pane (for L{AuiNotebook})
+    ``AUI_BUTTON_RIGHT``                          Shows a right button on the pane (for L{AuiNotebook})
+    ``AUI_BUTTON_UP``                             Shows an up button on the pane (not implemented)
+    ``AUI_BUTTON_DOWN``                           Shows a down button on the pane (not implemented)
+    ``AUI_BUTTON_CUSTOM1``                        Shows a custom button on the pane (not implemented)
+    ``AUI_BUTTON_CUSTOM2``                        Shows a custom button on the pane (not implemented)
+    ``AUI_BUTTON_CUSTOM3``                        Shows a custom button on the pane (not implemented)
+    ============================================  ======================================
+    
+    """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        self.Init()
+
+        isMac = wx.Platform == "__WXMAC__"
+        
+        if isMac:
+            self._caption_font = wx.SMALL_FONT
+        else:
+            self._caption_font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False)
+
+        self.SetDefaultPaneBitmaps(isMac)
+        self._restore_bitmap = wx.BitmapFromXPMData(restore_xpm)
+        
+        # default metric values
+        self._sash_size = 4
+
+        if isMac:
+            # This really should be implemented in wx.SystemSettings
+            # There is no way to do this that I am aware outside of using
+            # the cocoa python bindings. 8 pixels looks correct on my system
+            # so hard coding it for now.
+
+            # How do I translate this?!? Not sure of the below implementation...
+            # SInt32 height;
+            # GetThemeMetric( kThemeMetricSmallPaneSplitterHeight , &height );
+            # self._sash_size = height;
+
+            self._sash_size = 8 # Carbon.Appearance.kThemeMetricPaneSplitterHeight            
+            
+        elif wx.Platform == "__WXGTK__":
+            self._sash_size = wx.RendererNative.Get().GetSplitterParams(wx.GetTopLevelWindows()[0]).widthSash
+
+        else:
+            self._sash_size = 4
+        
+        self._caption_size = 19
+        self._border_size = 1
+        self._button_size = 14
+        self._gripper_size = 9
+        self._gradient_type = AUI_GRADIENT_VERTICAL
+        self._draw_sash = False
+        
+
+    def Init(self):
+        """ Initializes the dock art. """
+
+        base_colour = GetBaseColour()
+        darker1_colour = StepColour(base_colour, 85)
+        darker2_colour = StepColour(base_colour, 75)
+        darker3_colour = StepColour(base_colour, 60)
+        darker4_colour = StepColour(base_colour, 40)
+
+        self._background_colour = base_colour
+        self._background_gradient_colour = StepColour(base_colour, 180)
+
+        isMac = wx.Platform == "__WXMAC__"
+
+        if isMac:
+            self._active_caption_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+        else:
+            self._active_caption_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
+
+        self._active_caption_gradient_colour = LightContrastColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+        self._active_caption_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
+        self._inactive_caption_colour = darker1_colour
+        self._inactive_caption_gradient_colour = StepColour(base_colour, 97)
+        self._inactive_caption_text_colour = wx.BLACK
+    
+        self._sash_brush = wx.Brush(base_colour)
+        self._background_brush = wx.Brush(base_colour)
+        self._border_pen = wx.Pen(darker2_colour)
+        self._gripper_brush = wx.Brush(base_colour)
+        self._gripper_pen1 = wx.Pen(darker4_colour)
+        self._gripper_pen2 = wx.Pen(darker3_colour)
+        self._gripper_pen3 = wx.WHITE_PEN
+
+        
+    def GetMetric(self, id):
+        """
+        Gets the value of a certain setting.
+
+        :param `id`: can be one of the size values in `Metric Ordinals`.
+        """
+
+
+        if id == AUI_DOCKART_SASH_SIZE:
+            return self._sash_size
+        elif id == AUI_DOCKART_CAPTION_SIZE:
+            return self._caption_size
+        elif id == AUI_DOCKART_GRIPPER_SIZE:
+            return self._gripper_size
+        elif id == AUI_DOCKART_PANE_BORDER_SIZE:
+            return self._border_size
+        elif id == AUI_DOCKART_PANE_BUTTON_SIZE:
+            return self._button_size
+        elif id == AUI_DOCKART_GRADIENT_TYPE:
+            return self._gradient_type
+        elif id == AUI_DOCKART_DRAW_SASH_GRIP:
+            return self._draw_sash
+        else:
+            raise Exception("Invalid Metric Ordinal.")
+
+
+    def SetMetric(self, id, new_val):
+        """
+        Sets the value of a certain setting using `new_val`
+
+        :param `id`: can be one of the size values in `Metric Ordinals`;
+        :param `new_val`: the new value of the setting.
+        """
+
+        if id == AUI_DOCKART_SASH_SIZE:
+            self._sash_size = new_val
+        elif id == AUI_DOCKART_CAPTION_SIZE:
+            self._caption_size = new_val
+        elif id == AUI_DOCKART_GRIPPER_SIZE:
+            self._gripper_size = new_val
+        elif id == AUI_DOCKART_PANE_BORDER_SIZE:
+            self._border_size = new_val
+        elif id == AUI_DOCKART_PANE_BUTTON_SIZE:
+            self._button_size = new_val
+        elif id == AUI_DOCKART_GRADIENT_TYPE:
+            self._gradient_type = new_val
+        elif id == AUI_DOCKART_DRAW_SASH_GRIP:
+            self._draw_sash = new_val
+        else:
+            raise Exception("Invalid Metric Ordinal.")
+
+
+    def GetColor(self, id):
+        """
+        Gets the colour of a certain setting.
+
+        :param `id`: can be one of the colour values in `Metric Ordinals`.
+        """
+
+        if id == AUI_DOCKART_BACKGROUND_COLOUR:
+            return self._background_brush.GetColour()
+        elif id == AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR:
+            return self._background_gradient_colour
+        elif id == AUI_DOCKART_SASH_COLOUR:
+            return self._sash_brush.GetColour()
+        elif id == AUI_DOCKART_INACTIVE_CAPTION_COLOUR:
+            return self._inactive_caption_colour
+        elif id == AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR:
+            return self._inactive_caption_gradient_colour
+        elif id == AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR:
+            return self._inactive_caption_text_colour
+        elif id == AUI_DOCKART_ACTIVE_CAPTION_COLOUR:
+            return self._active_caption_colour
+        elif id == AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR:
+            return self._active_caption_gradient_colour
+        elif id == AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR:
+            return self._active_caption_text_colour        
+        elif id == AUI_DOCKART_BORDER_COLOUR:
+            return self._border_pen.GetColour()
+        elif id == AUI_DOCKART_GRIPPER_COLOUR:
+            return self._gripper_brush.GetColour()
+        else:
+            raise Exception("Invalid Colour Ordinal.")
+
+
+    def SetColor(self, id, colour):
+        """
+        Sets the colour of a certain setting.
+
+        :param `id`: can be one of the colour values in `Metric Ordinals`;
+        :param `colour`: the new value of the setting.
+        """
+
+        if isinstance(colour, basestring):
+            colour = wx.NamedColour(colour)
+        elif isinstance(colour, types.TupleType):
+            colour = wx.Colour(*colour)
+        elif isinstance(colour, types.IntType):
+            colour = wx.ColourRGB(colour)
+        
+        if id == AUI_DOCKART_BACKGROUND_COLOUR:
+            self._background_brush.SetColour(colour)
+        elif id == AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR:
+            self._background_gradient_colour = colour
+        elif id == AUI_DOCKART_SASH_COLOUR:
+            self._sash_brush.SetColour(colour)
+        elif id == AUI_DOCKART_INACTIVE_CAPTION_COLOUR:
+            self._inactive_caption_colour = colour
+            if not self._custom_pane_bitmaps and wx.Platform == "__WXMAC__":
+                # No custom bitmaps for the pane close button
+                # Change the MAC close bitmap colour
+                self._inactive_close_bitmap = DrawMACCloseButton(wx.WHITE, colour)
+
+        elif id == AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR:
+            self._inactive_caption_gradient_colour = colour
+        elif id == AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR:
+            self._inactive_caption_text_colour = colour
+        elif id == AUI_DOCKART_ACTIVE_CAPTION_COLOUR:
+            self._active_caption_colour = colour
+            if not self._custom_pane_bitmaps and wx.Platform == "__WXMAC__":
+                # No custom bitmaps for the pane close button
+                # Change the MAC close bitmap colour
+                self._active_close_bitmap = DrawMACCloseButton(wx.WHITE, colour)
+                
+        elif id == AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR:
+            self._active_caption_gradient_colour = colour
+        elif id == AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR:
+            self._active_caption_text_colour = colour
+        elif id == AUI_DOCKART_BORDER_COLOUR:
+            self._border_pen.SetColour(colour)
+        elif id == AUI_DOCKART_GRIPPER_COLOUR:
+            self._gripper_brush.SetColour(colour)
+            self._gripper_pen1.SetColour(StepColour(colour, 40))
+            self._gripper_pen2.SetColour(StepColour(colour, 60))
+        else:
+            raise Exception("Invalid Colour Ordinal.")
+        
+
+    GetColour = GetColor
+    SetColour = SetColor
+
+    def SetFont(self, id, font):
+        """
+        Sets a font setting.
+        
+        :param `id`: must be ``AUI_DOCKART_CAPTION_FONT``;
+        :param `font`: an instance of `wx.Font`.
+        """
+        
+        if id == AUI_DOCKART_CAPTION_FONT:
+            self._caption_font = font
+
+
+    def GetFont(self, id):
+        """
+        Gets a font setting.
+        
+        :param `id`: must be ``AUI_DOCKART_CAPTION_FONT``, otherwise `wx.NullFont` is returned.
+        """
+        
+        if id == AUI_DOCKART_CAPTION_FONT:
+            return self._caption_font
+        
+        return wx.NullFont
+
+
+    def DrawSash(self, dc, window, orient, rect):
+        """
+        Draws a sash between two windows.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `orient`: the sash orientation;
+        :param `rect`: the sash rectangle.
+        """                
+
+        # AG: How do we make this work?!?
+        # RendererNative does not use the sash_brush chosen by the user
+        # and the rect.GetSize() is ignored as the sash is always drawn
+        # 3 pixel wide
+        # wx.RendererNative.Get().DrawSplitterSash(window, dc, rect.GetSize(), pos, orient)
+
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        dc.SetBrush(self._sash_brush)
+        dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)        
+
+        draw_sash = self.GetMetric(AUI_DOCKART_DRAW_SASH_GRIP)
+        if draw_sash:
+            self.DrawSashGripper(dc, orient, rect)
+
+
+    def DrawBackground(self, dc, window, orient, rect):
+        """
+        Draws a background.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `orient`: the gradient (if any) orientation;
+        :param `rect`: the background rectangle.
+        """
+
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        if wx.Platform == "__WXMAC__":
+            # we have to clear first, otherwise we are drawing a light striped pattern
+            # over an already darker striped background
+            dc.SetBrush(wx.WHITE_BRUSH)
+            dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
+
+        DrawGradientRectangle(dc, rect, self._background_brush.GetColour(),
+                              self._background_gradient_colour,
+                              AUI_GRADIENT_HORIZONTAL, rect.x, 700)
+
+
+    def DrawBorder(self, dc, window, rect, pane):
+        """
+        Draws the pane border.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `rect`: the border rectangle;
+        :param `pane`: the pane for which the border is drawn.
+        """        
+
+        drect = wx.Rect(*rect)
+        
+        dc.SetPen(self._border_pen)
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+        border_width = self.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
+
+        if pane.IsToolbar():
+        
+            for ii in xrange(0, border_width):
+            
+                dc.SetPen(wx.WHITE_PEN)
+                dc.DrawLine(drect.x, drect.y, drect.x+drect.width, drect.y)
+                dc.DrawLine(drect.x, drect.y, drect.x, drect.y+drect.height)
+                dc.SetPen(self._border_pen)       
+                dc.DrawLine(drect.x, drect.y+drect.height-1,
+                            drect.x+drect.width, drect.y+drect.height-1)
+                dc.DrawLine(drect.x+drect.width-1, drect.y,
+                            drect.x+drect.width-1, drect.y+drect.height)
+                drect.Deflate(1, 1)
+        
+        else:
+        
+            for ii in xrange(0, border_width):
+            
+                dc.DrawRectangle(drect.x, drect.y, drect.width, drect.height)
+                drect.Deflate(1, 1)
+            
+
+    def DrawCaptionBackground(self, dc, rect, pane):
+        """
+        Draws the text caption background in the pane.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `rect`: the text caption rectangle;
+        :param `pane`: the pane for which the text background is drawn.
+        """        
+
+        active = pane.state & optionActive
+        if self._gradient_type == AUI_GRADIENT_NONE:
+            if active:
+                dc.SetBrush(wx.Brush(self._active_caption_colour))
+            else:
+                dc.SetBrush(wx.Brush(self._inactive_caption_colour))
+
+            dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)        
+
+        else:
+
+            switch_gradient = pane.HasCaptionLeft()
+            gradient_type = self._gradient_type
+            if switch_gradient:
+                gradient_type = (self._gradient_type == AUI_GRADIENT_HORIZONTAL and [AUI_GRADIENT_VERTICAL] or \
+                                 [AUI_GRADIENT_HORIZONTAL])[0]
+            
+            if active:
+                if wx.Platform == "__WXMAC__":
+                    DrawGradientRectangle(dc, rect, self._active_caption_colour,
+                                          self._active_caption_gradient_colour,
+                                          gradient_type)                    
+                else:
+                    DrawGradientRectangle(dc, rect, self._active_caption_gradient_colour,
+                                          self._active_caption_colour,
+                                          gradient_type)
+            else:
+                if wx.Platform == "__WXMAC__":
+                    DrawGradientRectangle(dc, rect, self._inactive_caption_gradient_colour,
+                                          self._inactive_caption_colour,
+                                          gradient_type)
+                else:
+                    DrawGradientRectangle(dc, rect, self._inactive_caption_colour,
+                                          self._inactive_caption_gradient_colour,
+                                          gradient_type)
+
+
+    def DrawIcon(self, dc, rect, pane):
+        """
+        Draws the icon in the pane caption area.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the icon is drawn.
+        """        
+        
+        # Draw the icon centered vertically 
+        if pane.icon.Ok():
+            if pane.HasCaptionLeft():
+                bmp = wx.ImageFromBitmap(pane.icon).Rotate90(clockwise=False)
+                dc.DrawBitmap(bmp.ConvertToBitmap(), rect.x+(rect.width-pane.icon.GetWidth())/2, rect.y+rect.height-2-pane.icon.GetHeight(), True)
+            else:
+                dc.DrawBitmap(pane.icon, rect.x+2, rect.y+(rect.height-pane.icon.GetHeight())/2, True)
+
+
+    def DrawCaption(self, dc, window, text, rect, pane):
+        """
+        Draws the text in the pane caption.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `text`: the text to be displayed;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the text is drawn.
+        """        
+
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        dc.SetFont(self._caption_font)
+        
+        self.DrawCaptionBackground(dc, rect, pane)
+
+        if pane.state & optionActive:
+            dc.SetTextForeground(self._active_caption_text_colour)
+        else:
+            dc.SetTextForeground(self._inactive_caption_text_colour)
+
+        w, h = dc.GetTextExtent("ABCDEFHXfgkj")
+
+        clip_rect = wx.Rect(*rect)
+        btns = pane.CountButtons()
+
+        captionLeft = pane.HasCaptionLeft()
+        variable = (captionLeft and [rect.height] or [rect.width])[0]
+
+        variable -= 3      # text offset
+        variable -= 2      # button padding
+
+        caption_offset = 0
+        if pane.icon:
+            if captionLeft:
+                caption_offset += pane.icon.GetHeight() + 3
+            else:
+                caption_offset += pane.icon.GetWidth() + 3
+                
+            self.DrawIcon(dc, rect, pane)
+
+        variable -= caption_offset
+        variable -= btns*(self._button_size + self._border_size)
+        draw_text = ChopText(dc, text, variable)
+
+        if captionLeft:
+            dc.DrawRotatedText(draw_text, rect.x+(rect.width/2)-(h/2)-1, rect.y+rect.height-3-caption_offset, 90)
+        else:
+            dc.DrawText(draw_text, rect.x+3+caption_offset, rect.y+(rect.height/2)-(h/2)-1)
+
+
+    def RequestUserAttention(self, dc, window, text, rect, pane):
+        """
+        Requests the user attention by intermittently highlighting the pane caption.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `text`: the text to be displayed;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the text is drawn.
+        """        
+
+        state = pane.state
+        pane.state &= ~optionActive
+        
+        for indx in xrange(6):
+            active = (indx%2 == 0 and [True] or [False])[0]
+            if active:
+                pane.state |= optionActive
+            else:
+                pane.state &= ~optionActive
+                
+            self.DrawCaptionBackground(dc, rect, pane)
+            self.DrawCaption(dc, window, text, rect, pane)
+            wx.SafeYield()
+            wx.MilliSleep(350)
+
+        pane.state = state
+        
+
+    def DrawGripper(self, dc, window, rect, pane):
+        """
+        Draws a gripper on the pane.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the gripper is drawn.
+        """        
+
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        dc.SetBrush(self._gripper_brush)
+
+        dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
+
+        if not pane.HasGripperTop():
+            y = 4
+            while 1:
+                dc.SetPen(self._gripper_pen1)
+                dc.DrawPoint(rect.x+3, rect.y+y) 
+                dc.SetPen(self._gripper_pen2) 
+                dc.DrawPoint(rect.x+3, rect.y+y+1) 
+                dc.DrawPoint(rect.x+4, rect.y+y) 
+                dc.SetPen(self._gripper_pen3) 
+                dc.DrawPoint(rect.x+5, rect.y+y+1) 
+                dc.DrawPoint(rect.x+5, rect.y+y+2) 
+                dc.DrawPoint(rect.x+4, rect.y+y+2) 
+                y = y + 4 
+                if y > rect.GetHeight() - 4:
+                    break
+        else:
+            x = 4
+            while 1:
+                dc.SetPen(self._gripper_pen1) 
+                dc.DrawPoint(rect.x+x, rect.y+3) 
+                dc.SetPen(self._gripper_pen2) 
+                dc.DrawPoint(rect.x+x+1, rect.y+3) 
+                dc.DrawPoint(rect.x+x, rect.y+4) 
+                dc.SetPen(self._gripper_pen3) 
+                dc.DrawPoint(rect.x+x+1, rect.y+5) 
+                dc.DrawPoint(rect.x+x+2, rect.y+5) 
+                dc.DrawPoint(rect.x+x+2, rect.y+4) 
+                x = x + 4 
+                if x > rect.GetWidth() - 4:
+                    break 
+        
+
+    def DrawPaneButton(self, dc, window, button, button_state, _rect, pane):
+        """
+        Draws a pane button in the pane caption area.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `button`: the button to be drawn;
+        :param `button_state`: the pane button state;
+        :param `_rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the button is drawn.
+        """        
+        
+        if not pane:
+            return
+        
+        if button == AUI_BUTTON_CLOSE:
+            if pane.state & optionActive:
+                bmp = self._active_close_bitmap
+            else:
+                bmp = self._inactive_close_bitmap
+
+        elif button == AUI_BUTTON_PIN:
+            if pane.state & optionActive:
+                bmp = self._active_pin_bitmap
+            else:
+                bmp = self._inactive_pin_bitmap
+
+        elif button == AUI_BUTTON_MAXIMIZE_RESTORE:
+            if pane.IsMaximized():
+                if pane.state & optionActive:
+                    bmp = self._active_restore_bitmap
+                else:
+                    bmp = self._inactive_restore_bitmap
+            else:
+                if pane.state & optionActive:
+                    bmp = self._active_maximize_bitmap
+                else:
+                    bmp = self._inactive_maximize_bitmap
+
+        elif button == AUI_BUTTON_MINIMIZE:
+            if pane.state & optionActive:
+                bmp = self._active_minimize_bitmap
+            else:
+                bmp = self._inactive_minimize_bitmap
+
+        isVertical = pane.HasCaptionLeft()
+        
+        rect = wx.Rect(*_rect)
+
+        if isVertical:
+            old_x = rect.x
+            rect.x = rect.x + (rect.width/2) - (bmp.GetWidth()/2)
+            rect.width = old_x + rect.width - rect.x - 1
+        else:
+            old_y = rect.y
+            rect.y = rect.y + (rect.height/2) - (bmp.GetHeight()/2)
+            rect.height = old_y + rect.height - rect.y - 1
+
+        if button_state == AUI_BUTTON_STATE_PRESSED:
+            rect.x += 1
+            rect.y += 1
+
+        if button_state in [AUI_BUTTON_STATE_HOVER, AUI_BUTTON_STATE_PRESSED]:
+
+            if pane.state & optionActive:
+
+                dc.SetBrush(wx.Brush(StepColour(self._active_caption_colour, 120)))
+                dc.SetPen(wx.Pen(StepColour(self._active_caption_colour, 70)))
+
+            else:
+
+                dc.SetBrush(wx.Brush(StepColour(self._inactive_caption_colour, 120)))
+                dc.SetPen(wx.Pen(StepColour(self._inactive_caption_colour, 70)))
+
+            if wx.Platform != "__WXMAC__":
+                # draw the background behind the button
+                dc.DrawRectangle(rect.x, rect.y, 15, 15)
+            else:
+                # Darker the bitmap a bit
+                bmp = DarkenBitmap(bmp, self._active_caption_colour, StepColour(self._active_caption_colour, 110))
+
+        if isVertical:
+            bmp = wx.ImageFromBitmap(bmp).Rotate90(clockwise=False).ConvertToBitmap()
+            
+        # draw the button itself
+        dc.DrawBitmap(bmp, rect.x, rect.y, True)
+
+
+    def DrawSashGripper(self, dc, orient, rect):
+        """
+        Draws a sash gripper on a sash between two windows.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `orient`: the sash orientation;
+        :param `rect`: the sash rectangle.
+        """
+        
+        dc.SetBrush(self._gripper_brush)
+
+        if orient == wx.HORIZONTAL:  # horizontal sash
+            
+            x = rect.x + int((1.0/4.0)*rect.width)
+            xend = rect.x + int((3.0/4.0)*rect.width)
+            y = rect.y + (rect.height/2) - 1
+
+            while 1:
+                dc.SetPen(self._gripper_pen3)
+                dc.DrawRectangle(x, y, 2, 2)
+                dc.SetPen(self._gripper_pen2) 
+                dc.DrawPoint(x+1, y+1)
+                x = x + 5
+
+                if x >= xend:
+                    break
+
+        else:
+
+            y = rect.y + int((1.0/4.0)*rect.height)
+            yend = rect.y + int((3.0/4.0)*rect.height)
+            x = rect.x + (rect.width/2) - 1
+
+            while 1:
+                dc.SetPen(self._gripper_pen3)
+                dc.DrawRectangle(x, y, 2, 2)
+                dc.SetPen(self._gripper_pen2) 
+                dc.DrawPoint(x+1, y+1)
+                y = y + 5
+
+                if y >= yend:
+                    break
+
+
+    def SetDefaultPaneBitmaps(self, isMac):
+        """
+        Assigns the default pane bitmaps.
+
+        :param `isMac`: whether we are on wxMAC or not.
+        """
+
+        if isMac:
+            self._inactive_close_bitmap = DrawMACCloseButton(wx.WHITE, self._inactive_caption_colour)
+            self._active_close_bitmap = DrawMACCloseButton(wx.WHITE, self._active_caption_colour)
+        else:
+            self._inactive_close_bitmap = BitmapFromBits(close_bits, 16, 16, self._inactive_caption_text_colour)
+            self._active_close_bitmap = BitmapFromBits(close_bits, 16, 16, self._active_caption_text_colour)
+            
+        if isMac:
+            self._inactive_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, wx.WHITE)
+            self._active_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, wx.WHITE)
+        else:
+            self._inactive_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, self._inactive_caption_text_colour)
+            self._active_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, self._active_caption_text_colour)
+
+        if isMac:
+            self._inactive_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, wx.WHITE)
+            self._active_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, wx.WHITE)
+        else:
+            self._inactive_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, self._inactive_caption_text_colour)
+            self._active_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, self._active_caption_text_colour)
+
+        if isMac:
+            self._inactive_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, wx.WHITE)
+            self._active_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, wx.WHITE)
+        else:
+            self._inactive_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, self._inactive_caption_text_colour)
+            self._active_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, self._active_caption_text_colour)
+
+        self._inactive_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, self._inactive_caption_text_colour)
+        self._active_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, self._active_caption_text_colour)
+
+        self._custom_pane_bitmaps = False
+        
+        
+    def SetCustomPaneBitmap(self, bmp, button, active, maximize=False):
+        """
+        Sets a custom button bitmap for the pane button.
+
+        :param `bmp`: the actual bitmap to set;
+        :param `button`: the button identifier;
+        :param `active`: whether it is the bitmap for the active button or not;
+        :param `maximize`: used to distinguish between the maximize and restore bitmaps.
+        """
+
+        if bmp.GetWidth() > 16 or bmp.GetHeight() > 16:
+            raise Exception("The input bitmap is too big")
+
+        if button == AUI_BUTTON_CLOSE:
+            if active:
+                self._active_close_bitmap = bmp
+            else:
+                self._inactive_close_bitmap = bmp
+
+            if wx.Platform == "__WXMAC__":
+                self._custom_pane_bitmaps = True                
+
+        elif button == AUI_BUTTON_PIN:
+            if active:
+                self._active_pin_bitmap = bmp
+            else:
+                self._inactive_pin_bitmap = bmp
+
+        elif button == AUI_BUTTON_MAXIMIZE_RESTORE:
+            if maximize:
+                if active:
+                    self._active_maximize_bitmap = bmp
+                else:
+                    self._inactive_maximize_bitmap = bmp
+            else:
+                if active:
+                    self._active_restore_bitmap = bmp
+                else:
+                    self._inactive_restore_bitmap = bmp
+
+        elif button == AUI_BUTTON_MINIMIZE:
+            if active:
+                self._active_minimize_bitmap = bmp
+            else:
+                self._inactive_minimize_bitmap = bmp
+
+
+if _ctypes:
+    class RECT(ctypes.Structure):
+        """ Used to handle L{ModernDockArt} on Windows XP/Vista/7. """
+        _fields_ = [('left', ctypes.c_ulong),('top', ctypes.c_ulong),('right', ctypes.c_ulong),('bottom', ctypes.c_ulong)]
+
+        def dump(self):
+            """ Dumps `self` as a `wx.Rect`. """
+            return map(int, (self.left, self.top, self.right, self.bottom))
+
+
+    class SIZE(ctypes.Structure):
+        """ Used to handle L{ModernDockArt} on Windows XP/Vista/7. """
+        _fields_ = [('x', ctypes.c_long),('y', ctypes.c_long)]
+
+
+class ModernDockArt(AuiDefaultDockArt):
+    """
+    ModernDockArt is a custom `AuiDockArt` class, that implements a look similar to
+    Firefox and other recents applications. 
+
+    Is uses the `winxptheme` module and XP themes whenever possible, so it should
+    look good even if the user has a custom theme.
+
+    :note: This dock art is Windows only and will only work if you have installed
+     Mark Hammond's `pywin32` module (http://sourceforge.net/projects/pywin32/).
+    """
+
+    def __init__(self, win):
+        """
+        Default class constructor. 
+
+        :param `win`: the window managed by L{AuiManager}. 
+        """
+        
+        AuiDefaultDockArt.__init__(self)
+        
+        self.win = win
+
+        # Get the size of a small close button (themed)
+        hwnd = self.win.GetHandle()
+        
+        self.hTheme1 = winxptheme.OpenThemeData(hwnd, "Window")
+        
+        self.usingTheme = True
+        
+        if not self.hTheme1:
+            self.usingTheme = False
+
+        self._button_size = 13
+
+        self._button_border_size = 3
+        self._caption_text_indent = 6
+        self._caption_size = 22
+        
+        # We only highlight the active pane with the caption text being in bold.
+        # So we do not want a special colour for active elements.        
+        self._active_close_bitmap = self._inactive_close_bitmap
+
+        self.Init()
+        
+
+    def Init(self):
+        """ Initializes the dock art. """
+
+        AuiDefaultDockArt.Init(self)
+        
+        self._active_caption_colour = self._inactive_caption_colour
+        self._active_caption_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_CAPTIONTEXT)
+        self._inactive_caption_text_colour = self._active_caption_text_colour
+
+
+    def DrawCaption(self, dc, window, text, rect, pane):
+        """
+        Draws the text in the pane caption.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `text`: the text to be displayed;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the text is drawn.
+        """        
+
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        self.DrawCaptionBackground(dc, rect, pane)
+
+        active = ((pane.state & optionActive) and [True] or [False])[0]
+
+        self._caption_font.SetWeight(wx.FONTWEIGHT_BOLD)
+        dc.SetFont(self._caption_font)
+        
+        if active:
+            dc.SetTextForeground(self._active_caption_text_colour)
+        else:
+            dc.SetTextForeground(self._inactive_caption_text_colour)
+
+        w, h = dc.GetTextExtent("ABCDEFHXfgkj")
+
+        clip_rect = wx.Rect(*rect)
+        btns = pane.CountButtons()
+
+        captionLeft = pane.HasCaptionLeft()
+        variable = (captionLeft and [rect.height] or [rect.width])[0]
+
+        variable -= 3      # text offset
+        variable -= 2      # button padding
+
+        caption_offset = 0
+        if pane.icon:
+            if captionLeft:
+                caption_offset += pane.icon.GetHeight() + 3
+            else:
+                caption_offset += pane.icon.GetWidth() + 3
+                
+            self.DrawIcon(dc, rect, pane)
+
+        diff = -2
+        if self.usingTheme:
+            diff = -1
+
+        variable -= caption_offset
+        variable -= btns*(self._button_size + self._button_border_size)
+        draw_text = ChopText(dc, text, variable)
+
+        if captionLeft:
+            dc.DrawRotatedText(draw_text, rect.x+(rect.width/2)-(h/2)-diff, rect.y+rect.height-3-caption_offset, 90)
+        else:
+            dc.DrawText(draw_text, rect.x+3+caption_offset, rect.y+(rect.height/2)-(h/2)-diff)
+
+
+    def DrawCaptionBackground(self, dc, rect, pane):
+        """
+        Draws the text caption background in the pane.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `rect`: the text caption rectangle;
+        :param `pane`: the pane for which we are drawing the caption background.
+        """        
+
+        dc.SetBrush(self._background_brush)
+        dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
+
+        active = ((pane.state & optionActive) and [True] or [False])[0]
+
+        if self.usingTheme:
+            
+            rectangle = wx.Rect()
+
+            rc = RECT(rectangle.x, rectangle.y, rectangle.width, rectangle.height)
+
+            # If rect x/y values are negative rc.right/bottom values will overflow and winxptheme.DrawThemeBackground
+            # will raise a TypeError. Ensure they are never negative.
+            rect.x = max(0, rect.x)
+            rect.y = max(0, rect.y)
+
+            rc.top = rect.x
+            rc.left = rect.y
+            rc.right = rect.x + rect.width
+            rc.bottom = rect.y + rect.height
+
+            if active:
+                winxptheme.DrawThemeBackground(self.hTheme1, dc.GetHDC(), 5, 1, (rc.top, rc.left, rc.right, rc.bottom), None)
+            else:
+                winxptheme.DrawThemeBackground(self.hTheme1, dc.GetHDC(), 5, 2, (rc.top, rc.left, rc.right, rc.bottom), None)
+            
+        else:
+
+            AuiDefaultDockArt.DrawCaptionBackground(self, dc, rect, pane)
+
+
+    def RequestUserAttention(self, dc, window, text, rect, pane):
+        """
+        Requests the user attention by intermittently highlighting the pane caption.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `text`: the text to be displayed;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the text is drawn.
+        """        
+    
+        state = pane.state
+        pane.state &= ~optionActive
+        
+        for indx in xrange(6):
+            active = (indx%2 == 0 and [True] or [False])[0]
+            if active:
+                pane.state |= optionActive
+            else:
+                pane.state &= ~optionActive
+                
+            self.DrawCaptionBackground(dc, rect, pane)
+            self.DrawCaption(dc, window, text, rect, pane)
+            wx.SafeYield()
+            wx.MilliSleep(350)
+
+        pane.state = state
+
+
+    def DrawPaneButton(self, dc, window, button, button_state, rect, pane):
+        """
+        Draws a pane button in the pane caption area.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `window`: an instance of `wx.Window`;
+        :param `button`: the button to be drawn;
+        :param `button_state`: the pane button state;
+        :param `rect`: the pane caption rectangle;
+        :param `pane`: the pane for which the button is drawn.
+        """        
+
+        if self.usingTheme:
+
+            hTheme = self.hTheme1            
+                    
+            # Get the real button position (compensating for borders)
+            drect = wx.Rect(rect.x, rect.y, self._button_size, self._button_size)
+            
+            # Draw the themed close button
+            rc = RECT(0, 0, 0, 0)
+            if pane.HasCaptionLeft():
+                rc.top = rect.x + self._button_border_size
+                rc.left = int(rect.y + 1.5*self._button_border_size)
+                rc.right = rect.x + self._button_size + self._button_border_size
+                rc.bottom = int(rect.y + self._button_size + 1.5*self._button_border_size)
+            else:
+                rc.top = rect.x - self._button_border_size
+                rc.left = int(rect.y + 1.5*self._button_border_size)
+                rc.right = rect.x + self._button_size- self._button_border_size
+                rc.bottom = int(rect.y + self._button_size + 1.5*self._button_border_size)
+
+            if button == AUI_BUTTON_CLOSE:
+                btntype = 19
+                
+            elif button == AUI_BUTTON_PIN:
+                btntype = 23
+
+            elif button == AUI_BUTTON_MAXIMIZE_RESTORE:
+                if not pane.IsMaximized():
+                    btntype = 17
+                else:
+                    btntype = 21
+            else:
+                btntype = 15
+
+            state = 4 # CBS_DISABLED
+            
+            if pane.state & optionActive:
+
+                if button_state == AUI_BUTTON_STATE_NORMAL:
+                    state = 1 # CBS_NORMAL
+
+                elif button_state == AUI_BUTTON_STATE_HOVER:
+                    state = 2 # CBS_HOT
+
+                elif button_state == AUI_BUTTON_STATE_PRESSED:
+                    state = 3 # CBS_PUSHED
+
+                else:
+                    raise Exception("ERROR: Unknown State.")
+
+            else: # inactive pane
+
+                if button_state == AUI_BUTTON_STATE_NORMAL:
+                    state = 5 # CBS_NORMAL
+
+                elif button_state == AUI_BUTTON_STATE_HOVER:
+                    state = 6 # CBS_HOT
+
+                elif button_state == AUI_BUTTON_STATE_PRESSED:
+                    state = 7 # CBS_PUSHED
+
+                else:
+                    raise Exception("ERROR: Unknown State.")
+
+            try:
+                winxptheme.DrawThemeBackground(hTheme, dc.GetHDC(), btntype, state, (rc.top, rc.left, rc.right, rc.bottom), None)
+            except TypeError:
+                return
+
+        else:
+
+            # Fallback to default closebutton if themes are not enabled
+            rect2 = wx.Rect(rect.x-4, rect.y+2, rect.width, rect.height)
+            AuiDefaultDockArt.DrawPaneButton(self, dc, window, button, button_state, rect2, pane)
+
diff --git a/aui/framemanager.py b/aui/framemanager.py
new file mode 100644 (file)
index 0000000..9b277bf
--- /dev/null
@@ -0,0 +1,10385 @@
+# --------------------------------------------------------------------------- #
+# AUI Library wxPython IMPLEMENTATION
+#
+# Original C++ Code From Kirix (wxAUI). You Can Find It At:
+#
+#    License: wxWidgets license
+#
+# http:#www.kirix.com/en/community/opensource/wxaui/about_wxaui.html
+#
+# Current wxAUI Version Tracked: wxWidgets 2.9.0 SVN HEAD
+#
+#
+# Python Code By:
+#
+# Andrea Gavana, @ 23 Dec 2005
+# Latest Revision: 10 Mar 2011, 15.00 GMT
+#
+# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
+# Write To Me At:
+#
+# andrea.gavana@gmail.com
+# gavana@kpo.kz
+#
+# Or, Obviously, To The wxPython Mailing List!!!
+#
+# End Of Comments
+# --------------------------------------------------------------------------- #
+
+"""
+Description
+===========
+
+framemanager is the central module of the AUI class framework.
+
+L{AuiManager} manages the panes associated with it for a particular `wx.Frame`, using
+a pane's L{AuiPaneInfo} information to determine each pane's docking and floating
+behavior. AuiManager uses wxPython' sizer mechanism to plan the layout of each frame.
+It uses a replaceable dock art class to do all drawing, so all drawing is localized
+in one area, and may be customized depending on an application's specific needs.
+
+AuiManager works as follows: the programmer adds panes to the class, or makes
+changes to existing pane properties (dock position, floating state, show state, etc...).
+To apply these changes, AuiManager's L{AuiManager.Update} function is called. This batch
+processing can be used to avoid flicker, by modifying more than one pane at a time,
+and then "committing" all of the changes at once by calling `Update()`.
+
+Panes can be added quite easily::
+
+    text1 = wx.TextCtrl(self, -1)
+    text2 = wx.TextCtrl(self, -1)
+    self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
+    self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
+
+    self._mgr.Update()
+
+
+Later on, the positions can be modified easily. The following will float an
+existing pane in a tool window::
+
+    self._mgr.GetPane(text1).Float()
+
+
+Layers, Rows and Directions, Positions
+======================================
+
+Inside AUI, the docking layout is figured out by checking several pane parameters.
+Four of these are important for determining where a pane will end up.
+
+**Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`.
+This is fairly self-explanatory. The pane will be placed in the location specified
+by this variable.
+
+**Position** - More than one pane can be placed inside of a "dock". Imagine two panes
+being docked on the left side of a window. One pane can be placed over another.
+In proportionally managed docks, the pane position indicates it's sequential position,
+starting with zero. So, in our scenario with two panes docked on the left side, the
+top pane in the dock would have position 0, and the second one would occupy position 1. 
+
+**Row** - A row can allow for two docks to be placed next to each other. One of the most
+common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
+the first row being in row 0, and the second in row 1. Rows can also be used on
+vertically docked panes. 
+
+**Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
+Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
+known as the "content window"). Increasing layers "swallow up" all layers of a lower
+value. This can look very similar to multiple rows, but is different because all panes
+in a lower level yield to panes in higher levels. The best way to understand layers
+is by running the AUI sample (`AUI.py`).
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+import time
+import types
+import warnings
+
+import auibar
+import auibook
+import tabmdi
+import dockart
+import tabart
+
+from aui_utilities import Clip, PaneCreateStippleBitmap, GetDockingImage, GetSlidingPoints
+
+from aui_constants import *
+
+# Define this as a translation function
+_ = wx.GetTranslation
+
+_winxptheme = False
+if wx.Platform == "__WXMSW__":
+    try:
+        import winxptheme
+        _winxptheme = True
+    except ImportError:
+        pass
+
+# wxPython version string
+_VERSION_STRING = wx.VERSION_STRING
+
+# AUI Events
+wxEVT_AUI_PANE_BUTTON = wx.NewEventType()
+wxEVT_AUI_PANE_CLOSE = wx.NewEventType()
+wxEVT_AUI_PANE_MAXIMIZE = wx.NewEventType()
+wxEVT_AUI_PANE_RESTORE = wx.NewEventType()
+wxEVT_AUI_RENDER = wx.NewEventType()
+wxEVT_AUI_FIND_MANAGER = wx.NewEventType()
+wxEVT_AUI_PANE_MINIMIZE = wx.NewEventType()
+wxEVT_AUI_PANE_MIN_RESTORE = wx.NewEventType()
+wxEVT_AUI_PANE_FLOATING = wx.NewEventType()
+wxEVT_AUI_PANE_FLOATED = wx.NewEventType()
+wxEVT_AUI_PANE_DOCKING = wx.NewEventType()
+wxEVT_AUI_PANE_DOCKED = wx.NewEventType()
+wxEVT_AUI_PANE_ACTIVATED = wx.NewEventType()
+wxEVT_AUI_PERSPECTIVE_CHANGED = wx.NewEventType()
+
+EVT_AUI_PANE_BUTTON = wx.PyEventBinder(wxEVT_AUI_PANE_BUTTON, 0)
+""" Fires an event when the user left-clicks on a pane button. """
+EVT_AUI_PANE_CLOSE = wx.PyEventBinder(wxEVT_AUI_PANE_CLOSE, 0)
+""" A pane in `AuiManager` has been closed. """
+EVT_AUI_PANE_MAXIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MAXIMIZE, 0)
+""" A pane in `AuiManager` has been maximized. """
+EVT_AUI_PANE_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_RESTORE, 0)
+""" A pane in `AuiManager` has been restored from a maximized state. """
+EVT_AUI_RENDER = wx.PyEventBinder(wxEVT_AUI_RENDER, 0)
+""" Fires an event every time the AUI frame is being repainted. """
+EVT_AUI_FIND_MANAGER = wx.PyEventBinder(wxEVT_AUI_FIND_MANAGER, 0)
+""" Used to find which AUI manager is controlling a certain pane. """
+EVT_AUI_PANE_MINIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MINIMIZE, 0)
+""" A pane in `AuiManager` has been minimized. """
+EVT_AUI_PANE_MIN_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_MIN_RESTORE, 0)
+""" A pane in `AuiManager` has been restored from a minimized state. """
+EVT_AUI_PANE_FLOATING = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATING, 0)
+""" A pane in `AuiManager` is about to be floated. """
+EVT_AUI_PANE_FLOATED = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATED, 0)
+""" A pane in `AuiManager` has been floated. """
+EVT_AUI_PANE_DOCKING = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKING, 0)
+""" A pane in `AuiManager` is about to be docked. """
+EVT_AUI_PANE_DOCKED = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKED, 0)
+""" A pane in `AuiManager` has been docked. """
+EVT_AUI_PANE_ACTIVATED = wx.PyEventBinder(wxEVT_AUI_PANE_ACTIVATED, 0)
+""" A pane in `AuiManager` has been activated. """
+EVT_AUI_PERSPECTIVE_CHANGED = wx.PyEventBinder(wxEVT_AUI_PERSPECTIVE_CHANGED, 0)
+""" The layout in `AuiManager` has been changed. """
+
+# ---------------------------------------------------------------------------- #
+
+class AuiDockInfo(object):
+    """ A class to store all properties of a dock. """
+
+    def __init__(self):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+        """
+
+        object.__init__(self)
+        
+        self.dock_direction = 0
+        self.dock_layer = 0
+        self.dock_row = 0
+        self.size = 0
+        self.min_size = 0
+        self.resizable = True
+        self.fixed = False
+        self.toolbar = False
+        self.rect = wx.Rect()
+        self.panes = []
+
+
+    def IsOk(self):
+        """
+        Returns whether a dock is valid or not.
+
+        In order to be valid, a dock needs to have a non-zero `dock_direction`.
+        """
+
+        return self.dock_direction != 0
+
+    
+    def IsHorizontal(self):
+        """ Returns whether the dock is horizontal or not. """
+
+        return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
+
+
+    def IsVertical(self):
+        """ Returns whether the dock is vertical or not. """
+
+        return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]
+    
+
+# ---------------------------------------------------------------------------- #
+
+class AuiDockingGuideInfo(object):
+    """ A class which holds information about VS2005 docking guide windows. """
+
+    def __init__(self, other=None):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+
+        :param `other`: another instance of L{AuiDockingGuideInfo}.
+        """
+
+        if other:
+            self.Assign(other)
+        else:
+            # window representing the docking target
+            self.host = None
+            # dock direction (top, bottom, left, right, center)
+            self.dock_direction = AUI_DOCK_NONE
+
+
+    def Assign(self, other):
+        """
+        Assigns the properties of the `other` L{AuiDockingGuideInfo} to `self`.
+
+        :param `other`: another instance of L{AuiDockingGuideInfo}.
+        """
+
+        self.host = other.host
+        self.dock_direction = other.dock_direction
+
+
+    def Host(self, h):
+        """
+        Hosts a docking guide window.
+
+        :param `h`: an instance of L{AuiSingleDockingGuide} or L{AuiCenterDockingGuide}.
+        """
+
+        self.host = h
+        return self
+    
+
+    def Left(self):
+        """ Sets the guide window to left docking. """
+
+        self.dock_direction = AUI_DOCK_LEFT
+        return self
+
+    
+    def Right(self):
+        """ Sets the guide window to right docking. """
+
+        self.dock_direction = AUI_DOCK_RIGHT
+        return self 
+
+
+    def Top(self):
+        """ Sets the guide window to top docking. """
+
+        self.dock_direction = AUI_DOCK_TOP
+        return self 
+
+
+    def Bottom(self):
+        """ Sets the guide window to bottom docking. """
+
+        self.dock_direction = AUI_DOCK_BOTTOM
+        return self 
+
+
+    def Center(self):
+        """ Sets the guide window to center docking. """
+
+        self.dock_direction = AUI_DOCK_CENTER
+        return self 
+
+
+    def Centre(self):
+        """ Sets the guide window to centre docking. """
+        
+        self.dock_direction = AUI_DOCK_CENTRE
+        return self
+
+
+# ---------------------------------------------------------------------------- #
+
+class AuiDockUIPart(object):
+    """ A class which holds attributes for a UI part in the interface. """
+    
+    typeCaption = 0
+    typeGripper = 1
+    typeDock = 2
+    typeDockSizer = 3
+    typePane = 4
+    typePaneSizer = 5
+    typeBackground = 6
+    typePaneBorder = 7
+    typePaneButton = 8
+
+    def __init__(self):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+        """
+        
+        self.orientation = wx.VERTICAL
+        self.type = 0
+        self.rect = wx.Rect()
+
+
+# ---------------------------------------------------------------------------- #
+
+class AuiPaneButton(object):
+    """ A simple class which describes the caption pane button attributes. """
+
+    def __init__(self, button_id):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+
+        :param `button_id`: the pane button identifier.
+        """
+
+        self.button_id = button_id
+
+
+# ---------------------------------------------------------------------------- #
+
+# event declarations/classes
+
+class AuiManagerEvent(wx.PyCommandEvent):
+    """ A specialized command event class for events sent by L{AuiManager}. """
+
+    def __init__(self, eventType, id=1):
+        """
+        Default class constructor.
+
+        :param `eventType`: the event kind;
+        :param `id`: the event identification number.
+        """
+
+        wx.PyCommandEvent.__init__(self, eventType, id)
+
+        self.manager = None
+        self.pane = None
+        self.button = 0
+        self.veto_flag = False
+        self.canveto_flag = True
+        self.dc = None
+
+
+    def SetManager(self, mgr):
+        """
+        Associates a L{AuiManager} to the current event.
+
+        :param `mgr`: an instance of L{AuiManager}.
+        """
+
+        self.manager = mgr
+
+
+    def SetDC(self, pdc):
+        """
+        Associates a `wx.DC` device context to this event.
+
+        :param `pdc`: a `wx.DC` device context object. 
+        """
+
+        self.dc = pdc
+
+
+    def SetPane(self, p):
+        """
+        Associates a L{AuiPaneInfo} instance to this event.
+
+        :param `p`: a L{AuiPaneInfo} instance.
+        """
+        
+        self.pane = p
+
+        
+    def SetButton(self, b):
+        """
+        Associates a L{AuiPaneButton} instance to this event.
+
+        :param `b`: a L{AuiPaneButton} instance.
+        """
+        
+        self.button = b
+
+        
+    def GetManager(self):
+        """ Returns the associated L{AuiManager} (if any). """
+
+        return self.manager
+
+
+    def GetDC(self):
+        """ Returns the associated `wx.DC` device context (if any). """
+
+        return self.dc
+    
+
+    def GetPane(self):
+        """ Returns the associated L{AuiPaneInfo} structure (if any). """
+        
+        return self.pane
+
+
+    def GetButton(self):
+        """ Returns the associated L{AuiPaneButton} instance (if any). """
+
+        return self.button
+
+
+    def Veto(self, veto=True):
+        """
+        Prevents the change announced by this event from happening.
+
+        It is in general a good idea to notify the user about the reasons for
+        vetoing the change because otherwise the applications behaviour (which
+        just refuses to do what the user wants) might be quite surprising.
+
+        :param `veto`: ``True`` to veto the event, ``False`` otherwise.
+        """
+
+        self.veto_flag = veto
+
+        
+    def GetVeto(self):
+        """ Returns whether the event has been vetoed or not. """
+
+        return self.veto_flag
+
+    
+    def SetCanVeto(self, can_veto):
+        """
+        Sets whether the event can be vetoed or not.
+
+        :param `can_veto`: a bool flag. ``True`` if the event can be vetoed, ``False`` otherwise.
+        """
+
+        self.canveto_flag = can_veto
+
+        
+    def CanVeto(self):
+        """ Returns whether the event can be vetoed and has been vetoed. """
+
+        return  self.canveto_flag and self.veto_flag
+
+
+# ---------------------------------------------------------------------------- #
+
+class AuiPaneInfo(object):
+    """
+    AuiPaneInfo specifies all the parameters for a pane. These parameters specify where
+    the pane is on the screen, whether it is docked or floating, or hidden. In addition,
+    these parameters specify the pane's docked position, floating position, preferred
+    size, minimum size, caption text among many other parameters.
+    """
+    
+    optionFloating         = 2**0
+    optionHidden           = 2**1
+    optionLeftDockable     = 2**2
+    optionRightDockable    = 2**3
+    optionTopDockable      = 2**4
+    optionBottomDockable   = 2**5
+    optionFloatable        = 2**6
+    optionMovable          = 2**7
+    optionResizable        = 2**8
+    optionPaneBorder       = 2**9
+    optionCaption          = 2**10
+    optionGripper          = 2**11
+    optionDestroyOnClose   = 2**12
+    optionToolbar          = 2**13
+    optionActive           = 2**14
+    optionGripperTop       = 2**15
+    optionMaximized        = 2**16
+    optionDockFixed        = 2**17
+    optionNotebookDockable = 2**18
+    optionMinimized        = 2**19
+    optionLeftSnapped      = 2**20
+    optionRightSnapped     = 2**21
+    optionTopSnapped       = 2**22
+    optionBottomSnapped    = 2**23
+    optionFlyOut           = 2**24
+    optionCaptionLeft      = 2**25
+
+    buttonClose            = 2**26
+    buttonMaximize         = 2**27
+    buttonMinimize         = 2**28
+    buttonPin              = 2**29
+    
+    buttonCustom1          = 2**30
+    buttonCustom2          = 2**31
+    buttonCustom3          = 2**32
+
+    savedHiddenState       = 2**33    # used internally
+    actionPane             = 2**34    # used internally
+    wasMaximized           = 2**35    # used internally
+    needsRestore           = 2**36    # used internally
+
+
+    def __init__(self):
+        """ Default class constructor. """
+        
+        self.window = None
+        self.frame = None
+        self.state = 0
+        self.dock_direction = AUI_DOCK_LEFT
+        self.dock_layer = 0
+        self.dock_row = 0
+        self.dock_pos = 0
+        self.minimize_mode = AUI_MINIMIZE_POS_SMART
+        self.floating_pos = wx.Point(-1, -1)
+        self.floating_size = wx.Size(-1, -1)
+        self.best_size = wx.Size(-1, -1)
+        self.min_size = wx.Size(-1, -1)
+        self.max_size = wx.Size(-1, -1)
+        self.dock_proportion = 0
+        self.caption = ""
+        self.buttons = []
+        self.name = ""
+        self.icon = wx.NullIcon
+        self.rect = wx.Rect()
+        self.notebook_id = -1
+        self.transparent = 255
+        self.needsTransparency = False
+        self.previousDockPos = None
+        self.previousDockSize = 0
+        self.snapped = 0
+        
+        self.DefaultPane()
+        
+    
+    def dock_direction_get(self):
+        """
+        Getter for the `dock_direction`.
+
+        :see: L{dock_direction_set} for a set of valid docking directions.
+        """
+        
+        if self.IsMaximized():
+            return AUI_DOCK_CENTER
+        else:
+            return self._dock_direction
+
+
+    def dock_direction_set(self, value):
+        """
+        Setter for the `dock_direction`.
+
+        :param `value`: the docking direction. This cab ne one of the following bits:
+
+        ============================ ======= =============================================
+        Dock Flag                     Value  Description
+        ============================ ======= =============================================
+        ``AUI_DOCK_NONE``                  0 No docking direction.
+        ``AUI_DOCK_TOP``                   1 Top docking direction.
+        ``AUI_DOCK_RIGHT``                 2 Right docking direction.
+        ``AUI_DOCK_BOTTOM``                3 Bottom docking direction.
+        ``AUI_DOCK_LEFT``                  4 Left docking direction.
+        ``AUI_DOCK_CENTER``                5 Center docking direction.
+        ``AUI_DOCK_CENTRE``                5 Centre docking direction.
+        ``AUI_DOCK_NOTEBOOK_PAGE``         6 Automatic AuiNotebooks docking style.
+        ============================ ======= =============================================
+        
+        """
+        
+        self._dock_direction = value
+        
+    dock_direction = property(dock_direction_get, dock_direction_set)
+
+    def IsOk(self):
+        """
+        Returns ``True`` if the L{AuiPaneInfo} structure is valid.
+
+        :note: A pane structure is valid if it has an associated window.
+        """
+        
+        return self.window != None
+
+
+    def IsMaximized(self):
+        """ Returns ``True`` if the pane is maximized. """
+        
+        return self.HasFlag(self.optionMaximized)
+
+
+    def IsMinimized(self):
+        """ Returns ``True`` if the pane is minimized. """
+
+        return self.HasFlag(self.optionMinimized)
+
+
+    def IsFixed(self):
+        """ Returns ``True`` if the pane cannot be resized. """
+        
+        return not self.HasFlag(self.optionResizable)
+
+    
+    def IsResizeable(self):
+        """ Returns ``True`` if the pane can be resized. """
+        
+        return self.HasFlag(self.optionResizable)
+
+    
+    def IsShown(self):
+        """ Returns ``True`` if the pane is currently shown. """
+        
+        return not self.HasFlag(self.optionHidden)
+
+    
+    def IsFloating(self):
+        """ Returns ``True`` if the pane is floating. """
+
+        return self.HasFlag(self.optionFloating)
+
+    
+    def IsDocked(self):
+        """ Returns ``True`` if the pane is docked. """
+        
+        return not self.HasFlag(self.optionFloating)
+
+    
+    def IsToolbar(self):
+        """ Returns ``True`` if the pane contains a toolbar. """
+
+        return self.HasFlag(self.optionToolbar)
+
+    
+    def IsTopDockable(self):
+        """
+        Returns ``True`` if the pane can be docked at the top
+        of the managed frame.
+        """
+        
+        return self.HasFlag(self.optionTopDockable)
+
+    
+    def IsBottomDockable(self):
+        """
+        Returns ``True`` if the pane can be docked at the bottom
+        of the managed frame.
+        """
+        
+        return self.HasFlag(self.optionBottomDockable)
+
+    
+    def IsLeftDockable(self):
+        """
+        Returns ``True`` if the pane can be docked at the left
+        of the managed frame.
+        """
+        
+        return self.HasFlag(self.optionLeftDockable) 
+
+
+    def IsRightDockable(self):
+        """
+        Returns ``True`` if the pane can be docked at the right
+        of the managed frame.
+        """
+        
+        return self.HasFlag(self.optionRightDockable)
+
+
+    def IsDockable(self):
+        """ Returns ``True`` if the pane can be docked. """
+        
+        return self.IsTopDockable() or self.IsBottomDockable() or self.IsLeftDockable() or \
+               self.IsRightDockable() or self.IsNotebookDockable()
+    
+    
+    def IsFloatable(self):
+        """
+        Returns ``True`` if the pane can be undocked and displayed as a
+        floating window.
+        """
+
+        return self.HasFlag(self.optionFloatable)
+
+    
+    def IsMovable(self):
+        """
+        Returns ``True`` if the docked frame can be undocked or moved to
+        another dock position.
+        """
+        
+        return self.HasFlag(self.optionMovable)
+
+
+    def IsDestroyOnClose(self):
+        """
+        Returns ``True`` if the pane should be destroyed when it is closed.
+        
+        Normally a pane is simply hidden when the close button is clicked. Calling L{DestroyOnClose}
+        with a ``True`` input parameter will cause the window to be destroyed when the user clicks
+        the pane's close button.
+        """
+        
+        return self.HasFlag(self.optionDestroyOnClose)
+    
+
+    def IsNotebookDockable(self):
+        """
+        Returns ``True`` if a pane can be docked on top to another to create a
+        L{AuiNotebook}.
+        """
+
+        return self.HasFlag(self.optionNotebookDockable)
+    
+
+    def IsTopSnappable(self):
+        """ Returns ``True`` if the pane can be snapped at the top of the managed frame. """
+        
+        return self.HasFlag(self.optionTopSnapped)
+
+    
+    def IsBottomSnappable(self):
+        """ Returns ``True`` if the pane can be snapped at the bottom of the managed frame. """
+        
+        return self.HasFlag(self.optionBottomSnapped)
+
+    
+    def IsLeftSnappable(self):
+        """ Returns ``True`` if the pane can be snapped on the left of the managed frame. """
+        
+        return self.HasFlag(self.optionLeftSnapped) 
+
+
+    def IsRightSnappable(self):
+        """ Returns ``True`` if the pane can be snapped on the right of the managed frame. """
+        
+        return self.HasFlag(self.optionRightSnapped)
+
+
+    def IsSnappable(self):
+        """ Returns ``True`` if the pane can be snapped. """
+        
+        return self.IsTopSnappable() or self.IsBottomSnappable() or self.IsLeftSnappable() or \
+               self.IsRightSnappable()
+
+
+    def IsFlyOut(self):
+        """ Returns ``True`` if the floating pane has a "fly-out" effect. """
+
+        return self.HasFlag(self.optionFlyOut)        
+            
+
+    def HasCaption(self):
+        """ Returns ``True`` if the pane displays a caption. """
+        
+        return self.HasFlag(self.optionCaption)
+
+    
+    def HasCaptionLeft(self):
+        """ Returns ``True`` if the pane displays a caption on the left (rotated by 90 degrees). """
+        
+        return self.HasFlag(self.optionCaptionLeft)
+
+
+    def HasGripper(self):
+        """ Returns ``True`` if the pane displays a gripper. """
+        
+        return self.HasFlag(self.optionGripper) 
+
+
+    def HasBorder(self):
+        """ Returns ``True`` if the pane displays a border. """
+        
+        return self.HasFlag(self.optionPaneBorder)
+
+    
+    def HasCloseButton(self):
+        """ Returns ``True`` if the pane displays a button to close the pane. """
+
+        return self.HasFlag(self.buttonClose) 
+
+
+    def HasMaximizeButton(self):
+        """ Returns ``True`` if the pane displays a button to maximize the pane. """
+        
+        return self.HasFlag(self.buttonMaximize)
+
+    
+    def HasMinimizeButton(self):
+        """ Returns ``True`` if the pane displays a button to minimize the pane. """
+        
+        return self.HasFlag(self.buttonMinimize) 
+
+
+    def GetMinimizeMode(self):
+        """
+        Returns the minimization style for this pane.
+
+        Possible return values are:
+
+        ============================== ========= ==============================
+        Minimize Mode Flag             Hex Value Description
+        ============================== ========= ==============================
+        ``AUI_MINIMIZE_POS_SMART``          0x01 Minimizes the pane on the closest tool bar
+        ``AUI_MINIMIZE_POS_TOP``            0x02 Minimizes the pane on the top tool bar
+        ``AUI_MINIMIZE_POS_LEFT``           0x03 Minimizes the pane on its left tool bar
+        ``AUI_MINIMIZE_POS_RIGHT``          0x04 Minimizes the pane on its right tool bar
+        ``AUI_MINIMIZE_POS_BOTTOM``         0x05 Minimizes the pane on its bottom tool bar
+        ``AUI_MINIMIZE_POS_MASK``           0x07 Mask to filter the position flags
+        ``AUI_MINIMIZE_CAPT_HIDE``           0x0 Hides the caption of the minimized pane
+        ``AUI_MINIMIZE_CAPT_SMART``         0x08 Displays the caption in the best rotation (horizontal or clockwise)
+        ``AUI_MINIMIZE_CAPT_HORZ``          0x10 Displays the caption horizontally
+        ``AUI_MINIMIZE_CAPT_MASK``          0x18 Mask to filter the caption flags
+        ============================== ========= ==============================
+
+        The flags can be filtered with the following masks:
+
+        ============================== ========= ==============================
+        Minimize Mask Flag             Hex Value Description
+        ============================== ========= ==============================        
+        ``AUI_MINIMIZE_POS_MASK``           0x07 Filters the position flags
+        ``AUI_MINIMIZE_CAPT_MASK``          0x18 Filters the caption flags
+        ============================== ========= ==============================
+
+        """
+        
+        return self.minimize_mode
+    
+
+    def HasPinButton(self):
+        """ Returns ``True`` if the pane displays a button to float the pane. """
+        
+        return self.HasFlag(self.buttonPin) 
+
+
+    def HasGripperTop(self):
+        """ Returns ``True`` if the pane displays a gripper at the top. """
+
+        return self.HasFlag(self.optionGripperTop)
+
+
+    def Window(self, w):
+        """
+        Associate a `wx.Window` derived window to this pane.
+
+        This normally does not need to be specified, as the window pointer is
+        automatically assigned to the L{AuiPaneInfo} structure as soon as it is
+        added to the manager.
+
+        :param `w`: a `wx.Window` derived window.
+        """
+
+        self.window = w
+        return self
+
+    
+    def Name(self, name):
+        """
+        Sets the name of the pane so it can be referenced in lookup functions.
+
+        If a name is not specified by the user, a random name is assigned to the pane
+        when it is added to the manager.
+
+        :param `name`: a string specifying the pane name.
+
+        :warning: If you are using L{AuiManager.SavePerspective} and L{AuiManager.LoadPerspective}, you will have
+         to specify a name for your pane using L{Name}, as randomly generated names can
+         not be properly restored.
+        """
+
+        self.name = name
+        return self
+
+    
+    def Caption(self, caption):
+        """
+        Sets the caption of the pane.
+
+        :param `caption`: a string specifying the pane caption.
+        """
+        
+        self.caption = caption
+        return self
+
+    
+    def Left(self):
+        """ 
+        Sets the pane dock position to the left side of the frame.
+
+        :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_LEFT`` as
+         parameter.
+        """
+        
+        self.dock_direction = AUI_DOCK_LEFT
+        return self
+
+    
+    def Right(self):
+        """
+        Sets the pane dock position to the right side of the frame.
+
+        :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_RIGHT`` as
+         parameter.
+        """
+        
+        self.dock_direction = AUI_DOCK_RIGHT
+        return self
+
+    
+    def Top(self):
+        """
+        Sets the pane dock position to the top of the frame.
+
+        :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_TOP`` as
+         parameter.
+        """
+
+        self.dock_direction = AUI_DOCK_TOP
+        return self
+
+    
+    def Bottom(self):
+        """
+        Sets the pane dock position to the bottom of the frame.
+
+        :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_BOTTOM`` as
+         parameter.
+        """
+
+        self.dock_direction = AUI_DOCK_BOTTOM
+        return self
+
+    
+    def Center(self):
+        """
+        Sets the pane to the center position of the frame.
+
+        The centre pane is the space in the middle after all border panes (left, top,
+        right, bottom) are subtracted from the layout.
+
+        :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_CENTER`` as
+         parameter.
+        """
+        
+        self.dock_direction = AUI_DOCK_CENTER
+        return self
+
+        
+    def Centre(self):
+        """
+        Sets the pane to the center position of the frame.
+
+        The centre pane is the space in the middle after all border panes (left, top,
+        right, bottom) are subtracted from the layout.
+
+        :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_CENTRE`` as
+         parameter.
+        """
+        
+        self.dock_direction = AUI_DOCK_CENTRE
+        return self
+
+    
+    def Direction(self, direction):
+        """
+        Determines the direction of the docked pane. It is functionally the
+        same as calling L{Left}, L{Right}, L{Top} or L{Bottom}, except that docking direction
+        may be specified programmatically via the parameter `direction`.
+
+        :param `direction`: the direction of the docked pane.
+
+        :see: L{dock_direction_set} for a list of valid docking directions.        
+        """
+        
+        self.dock_direction = direction
+        return self
+
+    
+    def Layer(self, layer):
+        """
+        Determines the layer of the docked pane.
+
+        The dock layer is similar to an onion, the inner-most layer being layer 0. Each
+        shell moving in the outward direction has a higher layer number. This allows for
+        more complex docking layout formation.
+
+        :param `layer`: the layer of the docked pane.
+        """
+        
+        self.dock_layer = layer
+        return self
+
+    
+    def Row(self, row):
+        """
+        Determines the row of the docked pane.
+
+        :param `row`: the row of the docked pane.
+        """
+        
+        self.dock_row = row
+        return self
+
+    
+    def Position(self, pos):
+        """
+        Determines the position of the docked pane.
+
+        :param `pos`: the position of the docked pane.
+        """
+
+        self.dock_pos = pos
+        return self
+
+
+    def MinSize(self, arg1=None, arg2=None):
+        """
+        Sets the minimum size of the pane.
+
+        This method is split in 2 versions depending on the input type. If `arg1` is
+        a `wx.Size` object, then L{MinSize1} is called. Otherwise, L{MinSize2} is called.
+
+        :param `arg1`: a `wx.Size` object, a (x, y) tuple or or a `x` coordinate.
+        :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
+        """
+        
+        if isinstance(arg1, wx.Size):
+            ret = self.MinSize1(arg1)
+        elif isinstance(arg1, types.TupleType):
+            ret = self.MinSize1(wx.Size(*arg1))
+        else:
+            ret = self.MinSize2(arg1, arg2)
+
+        return ret
+
+    
+    def MinSize1(self, size):
+        """
+        Sets the minimum size of the pane.
+
+        :see: L{MinSize} for an explanation of input parameters.
+        """
+        self.min_size = size
+        return self
+
+
+    def MinSize2(self, x, y):
+        """
+        Sets the minimum size of the pane.
+
+        :see: L{MinSize} for an explanation of input parameters.
+        """
+
+        self.min_size = wx.Size(x, y)
+        return self
+
+
+    def MaxSize(self, arg1=None, arg2=None):
+        """
+        Sets the maximum size of the pane.
+
+        This method is split in 2 versions depending on the input type. If `arg1` is
+        a `wx.Size` object, then L{MaxSize1} is called. Otherwise, L{MaxSize2} is called.
+
+        :param `arg1`: a `wx.Size` object, a (x, y) tuple or a `x` coordinate.
+        :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
+        """
+        
+        if isinstance(arg1, wx.Size):
+            ret = self.MaxSize1(arg1)
+        elif isinstance(arg1, types.TupleType):
+            ret = self.MaxSize1(wx.Size(*arg1))
+        else:
+            ret = self.MaxSize2(arg1, arg2)
+
+        return ret
+    
+    
+    def MaxSize1(self, size):
+        """
+        Sets the maximum size of the pane.
+
+        :see: L{MaxSize} for an explanation of input parameters.
+        """
+
+        self.max_size = size
+        return self
+
+
+    def MaxSize2(self, x, y):
+        """
+        Sets the maximum size of the pane.
+
+        :see: L{MaxSize} for an explanation of input parameters.
+        """
+
+        self.max_size.Set(x,y)
+        return self
+
+
+    def BestSize(self, arg1=None, arg2=None):
+        """
+        Sets the ideal size for the pane. The docking manager will attempt to use
+        this size as much as possible when docking or floating the pane.
+
+        This method is split in 2 versions depending on the input type. If `arg1` is
+        a `wx.Size` object, then L{BestSize1} is called. Otherwise, L{BestSize2} is called.
+
+        :param `arg1`: a `wx.Size` object, a (x, y) tuple or a `x` coordinate.
+        :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
+        """
+        
+        if isinstance(arg1, wx.Size):
+            ret = self.BestSize1(arg1)
+        elif isinstance(arg1, types.TupleType):
+            ret = self.BestSize1(wx.Size(*arg1))
+        else:
+            ret = self.BestSize2(arg1, arg2)
+
+        return ret
+    
+            
+    def BestSize1(self, size):
+        """
+        Sets the best size of the pane.
+
+        :see: L{BestSize} for an explanation of input parameters.
+        """
+
+        self.best_size = size
+        return self
+
+    
+    def BestSize2(self, x, y):
+        """
+        Sets the best size of the pane.
+
+        :see: L{BestSize} for an explanation of input parameters.
+        """
+
+        self.best_size.Set(x,y)
+        return self
+    
+    
+    def FloatingPosition(self, pos):
+        """
+        Sets the position of the floating pane.
+
+        :param `pos`: a `wx.Point` or a tuple indicating the pane floating position.
+        """
+        
+        self.floating_pos = wx.Point(*pos)
+        return self
+
+    
+    def FloatingSize(self, size):
+        """
+        Sets the size of the floating pane.
+
+        :param `size`: a `wx.Size` or a tuple indicating the pane floating size.
+        """
+        
+        self.floating_size = wx.Size(*size)
+        return self
+
+
+    def Maximize(self):
+        """ Makes the pane take up the full area."""
+
+        return self.SetFlag(self.optionMaximized, True)
+
+
+    def Minimize(self):
+        """
+        Makes the pane minimized in a L{AuiToolBar}.
+
+        Clicking on the minimize button causes a new L{AuiToolBar} to be created
+        and added to the frame manager, (currently the implementation is such that
+        panes at West will have a toolbar at the right, panes at South will have
+        toolbars at the bottom etc...) and the pane is hidden in the manager.
+        
+        Clicking on the restore button on the newly created toolbar will result in the
+        toolbar being removed and the original pane being restored.
+        """
+        
+        return self.SetFlag(self.optionMinimized, True)
+
+
+    def MinimizeMode(self, mode):
+        """
+        Sets the expected minimized mode if the MinimizeButton() is visible.
+
+        The minimized pane can have a specific position in the work space:
+
+        ============================== ========= ==============================
+        Minimize Mode Flag             Hex Value Description
+        ============================== ========= ==============================
+        ``AUI_MINIMIZE_POS_SMART``          0x01 Minimizes the pane on the closest tool bar
+        ``AUI_MINIMIZE_POS_TOP``            0x02 Minimizes the pane on the top tool bar
+        ``AUI_MINIMIZE_POS_LEFT``           0x03 Minimizes the pane on its left tool bar
+        ``AUI_MINIMIZE_POS_RIGHT``          0x04 Minimizes the pane on its right tool bar
+        ``AUI_MINIMIZE_POS_BOTTOM``         0x05 Minimizes the pane on its bottom tool bar
+        ============================== ========= ==============================
+
+        The caption of the minimized pane can be displayed in different modes:
+
+        ============================== ========= ==============================
+        Caption Mode Flag              Hex Value Description
+        ============================== ========= ==============================
+        ``AUI_MINIMIZE_CAPT_HIDE``           0x0 Hides the caption of the minimized pane
+        ``AUI_MINIMIZE_CAPT_SMART``         0x08 Displays the caption in the best rotation (horizontal in the top and in the bottom tool bar or clockwise in the right and in the left tool bar)
+        ``AUI_MINIMIZE_CAPT_HORZ``          0x10 Displays the caption horizontally
+        ============================== ========= ==============================
+        
+        """
+        
+        self.minimize_mode = mode
+        return self
+    
+
+    def Restore(self):
+        """ Is the reverse of L{Maximize} and L{Minimize}."""
+        
+        return self.SetFlag(self.optionMaximized or self.optionMinimized, False)
+
+    
+    def Fixed(self):
+        """
+        Forces a pane to be fixed size so that it cannot be resized.
+        After calling L{Fixed}, L{IsFixed} will return ``True``.
+        """
+        
+        return self.SetFlag(self.optionResizable, False)
+
+    
+    def Resizable(self, resizable=True):
+        """
+        Allows a pane to be resizable if `resizable` is ``True``, and forces
+        it to be a fixed size if `resizeable` is ``False``.
+
+        If `resizable` is ``False``, this is simply an antonym for L{Fixed}.
+
+        :param `resizable`: whether the pane will be resizeable or not.
+        """
+        
+        return self.SetFlag(self.optionResizable, resizable)
+
+
+    def Transparent(self, alpha):
+        """
+        Makes the pane transparent when floating.
+
+        :param `alpha`: an integer value between 0 and 255 for pane transparency.
+        """
+
+        if alpha < 0 or alpha > 255:
+            raise Exception("Invalid transparency value (%s)"%repr(alpha))
+                            
+        self.transparent = alpha
+        self.needsTransparency = True
+
+    
+    def Dock(self):
+        """
+        Indicates that a pane should be docked. It is the opposite of L{Float}.
+        """
+
+        if self.IsNotebookPage():
+            self.notebook_id = -1
+            self.dock_direction = AUI_DOCK_NONE
+        
+        return self.SetFlag(self.optionFloating, False)
+
+    
+    def Float(self):
+        """
+        Indicates that a pane should be floated. It is the opposite of L{Dock}.
+        """
+
+        if self.IsNotebookPage():
+            self.notebook_id = -1
+            self.dock_direction = AUI_DOCK_NONE
+
+        return self.SetFlag(self.optionFloating, True)
+
+    
+    def Hide(self):
+        """
+        Indicates that a pane should be hidden.
+
+        Calling L{Show} (``False``) achieve the same effect.
+        """
+        
+        return self.SetFlag(self.optionHidden, True)
+
+    
+    def Show(self, show=True):
+        """
+        Indicates that a pane should be shown.
+
+        :param `show`: whether the pane should be shown or not.
+        """
+        
+        return self.SetFlag(self.optionHidden, not show)
+    
+
+    # By defaulting to 1000, the tab will get placed at the end
+    def NotebookPage(self, id, tab_position=1000):
+        """
+        Forces a pane to be a notebook page, so that the pane can be
+        docked on top to another to create a L{AuiNotebook}.
+
+        :param `id`: the notebook id;
+        :param `tab_position`: the tab number of the pane once docked in a notebook.
+        """
+        
+        # Remove any floating frame
+        self.Dock()
+        self.notebook_id = id
+        self.dock_pos = tab_position
+        self.dock_row = 0
+        self.dock_layer = 0
+        self.dock_direction = AUI_DOCK_NOTEBOOK_PAGE
+
+        return self
+
+
+    def NotebookControl(self, id):
+        """
+        Forces a pane to be a notebook control (L{AuiNotebook}).
+
+        :param `id`: the notebook id.
+        """
+
+        self.notebook_id = id
+        self.window = None
+        self.buttons = []
+        
+        if self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE:
+            self.dock_direction = AUI_DOCK_NONE
+            
+        return self
+    
+
+    def HasNotebook(self):
+        """ Returns whether a pane has a L{AuiNotebook} or not. """
+
+        return self.notebook_id >= 0
+
+
+    def IsNotebookPage(self):
+        """ Returns whether the pane is a notebook page in a L{AuiNotebook}. """
+
+        return self.notebook_id >= 0 and self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE
+
+
+    def IsNotebookControl(self):
+        """ Returns whether the pane is a notebook control (L{AuiNotebook}). """
+
+        return not self.IsNotebookPage() and self.HasNotebook()
+
+
+    def SetNameFromNotebookId(self):
+        """ Sets the pane name once docked in a L{AuiNotebook} using the notebook id. """
+
+        if self.notebook_id >= 0:
+            self.name = "__notebook_%d"%self.notebook_id
+            
+        return self
+
+
+    def CaptionVisible(self, visible=True, left=False):
+        """
+        Indicates that a pane caption should be visible. If `visible` is ``False``, no pane
+        caption is drawn.
+
+        :param `visible`: whether the caption should be visible or not;
+        :param `left`: whether the caption should be drawn on the left (rotated by 90 degrees) or not.
+        """
+
+        if left:
+            self.SetFlag(self.optionCaption, False)
+            return self.SetFlag(self.optionCaptionLeft, visible)
+
+        self.SetFlag(self.optionCaptionLeft, False)
+        return self.SetFlag(self.optionCaption, visible)
+
+    
+    def PaneBorder(self, visible=True):
+        """
+        Indicates that a border should be drawn for the pane.
+
+        :param `visible`: whether the pane border should be visible or not.
+        """
+        
+        return self.SetFlag(self.optionPaneBorder, visible)
+
+    
+    def Gripper(self, visible=True):
+        """
+        Indicates that a gripper should be drawn for the pane.
+
+        :param `visible`: whether the gripper should be visible or not.
+        """
+        
+        return self.SetFlag(self.optionGripper, visible)
+
+
+    def GripperTop(self, attop=True):
+        """
+        Indicates that a gripper should be drawn at the top of the pane.
+
+        :param `attop`: whether the gripper should be drawn at the top or not.
+        """
+        
+        return self.SetFlag(self.optionGripperTop, attop)
+
+    
+    def CloseButton(self, visible=True):
+        """
+        Indicates that a close button should be drawn for the pane.
+
+        :param `visible`: whether the close button should be visible or not.
+        """
+        
+        return self.SetFlag(self.buttonClose, visible)
+
+    
+    def MaximizeButton(self, visible=True):
+        """
+        Indicates that a maximize button should be drawn for the pane.
+
+        :param `visible`: whether the maximize button should be visible or not.
+        """
+        
+        return self.SetFlag(self.buttonMaximize, visible)
+
+    
+    def MinimizeButton(self, visible=True):
+        """
+        Indicates that a minimize button should be drawn for the pane.
+
+        :param `visible`: whether the minimize button should be visible or not.
+        """
+
+        return self.SetFlag(self.buttonMinimize, visible)
+
+    
+    def PinButton(self, visible=True):
+        """
+        Indicates that a pin button should be drawn for the pane.
+
+        :param `visible`: whether the pin button should be visible or not.
+        """
+        
+        return self.SetFlag(self.buttonPin, visible)
+
+    
+    def DestroyOnClose(self, b=True):
+        """
+        Indicates whether a pane should be destroyed when it is closed.
+
+        Normally a pane is simply hidden when the close button is clicked. Setting
+        `b` to ``True`` will cause the window to be destroyed when the user clicks
+        the pane's close button.
+
+        :param `b`: whether the pane should be destroyed when it is closed or not.
+        """
+        
+        return self.SetFlag(self.optionDestroyOnClose, b)
+
+    
+    def TopDockable(self, b=True):
+        """
+        Indicates whether a pane can be docked at the top of the frame.
+
+        :param `b`: whether the pane can be docked at the top or not.
+        """
+        
+        return self.SetFlag(self.optionTopDockable, b)
+
+    
+    def BottomDockable(self, b=True):
+        """
+        Indicates whether a pane can be docked at the bottom of the frame.
+
+        :param `b`: whether the pane can be docked at the bottom or not.
+        """
+        
+        return self.SetFlag(self.optionBottomDockable, b)
+
+    
+    def LeftDockable(self, b=True):
+        """
+        Indicates whether a pane can be docked on the left of the frame.
+
+        :param `b`: whether the pane can be docked at the left or not.
+        """
+
+        return self.SetFlag(self.optionLeftDockable, b)
+
+    
+    def RightDockable(self, b=True):
+        """
+        Indicates whether a pane can be docked on the right of the frame.
+
+        :param `b`: whether the pane can be docked at the right or not.
+        """
+        
+        return self.SetFlag(self.optionRightDockable, b)
+
+    
+    def Floatable(self, b=True):
+        """
+        Sets whether the user will be able to undock a pane and turn it
+        into a floating window.
+
+        :param `b`: whether the pane can be floated or not.
+        """
+        
+        return self.SetFlag(self.optionFloatable, b)
+
+    
+    def Movable(self, b=True):
+        """
+        Indicates whether a pane can be moved.
+
+        :param `b`: whether the pane can be moved or not.
+        """
+        
+        return self.SetFlag(self.optionMovable, b)
+
+
+    def NotebookDockable(self, b=True):
+        """
+        Indicates whether a pane can be docked in an automatic L{AuiNotebook}.
+
+        :param `b`: whether the pane can be docked in a notebook or not.
+        """
+        
+        return self.SetFlag(self.optionNotebookDockable, b)
+                                  
+
+    def DockFixed(self, b=True):
+        """
+        Causes the containing dock to have no resize sash. This is useful
+        for creating panes that span the entire width or height of a dock, but should
+        not be resizable in the other direction.
+
+        :param `b`: whether the pane will have a resize sash or not.
+        """
+
+        return self.SetFlag(self.optionDockFixed, b)
+
+                                   
+    def Dockable(self, b=True):
+        """
+        Specifies whether a frame can be docked or not. It is the same as specifying
+        L{TopDockable} . L{BottomDockable} . L{LeftDockable} . L{RightDockable} .
+
+        :param `b`: whether the frame can be docked or not.
+        """
+
+        return self.TopDockable(b).BottomDockable(b).LeftDockable(b).RightDockable(b)
+    
+
+    def TopSnappable(self, b=True):
+        """
+        Indicates whether a pane can be snapped at the top of the main frame.
+
+        :param `b`: whether the pane can be snapped at the top of the main frame or not.
+        """
+        
+        return self.SetFlag(self.optionTopSnapped, b)
+
+    
+    def BottomSnappable(self, b=True):
+        """
+        Indicates whether a pane can be snapped at the bottom of the main frame.
+
+        :param `b`: whether the pane can be snapped at the bottom of the main frame or not.
+        """
+        
+        return self.SetFlag(self.optionBottomSnapped, b)
+
+    
+    def LeftSnappable(self, b=True):
+        """
+        Indicates whether a pane can be snapped on the left of the main frame.
+
+        :param `b`: whether the pane can be snapped at the left of the main frame or not.
+        """
+
+        return self.SetFlag(self.optionLeftSnapped, b)
+
+    
+    def RightSnappable(self, b=True):
+        """
+        Indicates whether a pane can be snapped on the right of the main frame.
+
+        :param `b`: whether the pane can be snapped at the right of the main frame or not.
+        """
+        
+        return self.SetFlag(self.optionRightSnapped, b)
+
+
+    def Snappable(self, b=True):
+        """
+        Indicates whether a pane can be snapped on the main frame. This is
+        equivalent as calling L{TopSnappable} . L{BottomSnappable} . L{LeftSnappable} . L{RightSnappable} .
+
+        :param `b`: whether the pane can be snapped on the main frame or not.
+        """
+    
+        return self.TopSnappable(b).BottomSnappable(b).LeftSnappable(b).RightSnappable(b)
+
+
+    def FlyOut(self, b=True):
+        """
+        Indicates whether a pane, when floating, has a "fly-out" effect
+        (i.e., floating panes which only show themselves when moused over).
+
+        :param `b`: whether the pane can be snapped on the main frame or not.
+        """
+
+        return self.SetFlag(self.optionFlyOut, b)
+    
+    
+    # Copy over the members that pertain to docking position
+    def SetDockPos(self, source):
+        """
+        Copies the `source` pane members that pertain to docking position to `self`.
+
+        :param `source`: the source pane from where to copy the attributes.
+        """
+        
+        self.dock_direction = source.dock_direction
+        self.dock_layer = source.dock_layer
+        self.dock_row = source.dock_row
+        self.dock_pos = source.dock_pos
+        self.dock_proportion = source.dock_proportion
+        self.floating_pos = wx.Point(*source.floating_pos)
+        self.floating_size = wx.Size(*source.floating_size)
+        self.rect = wx.Rect(*source.rect)
+        
+        return self
+
+
+    def DefaultPane(self):
+        """ Specifies that the pane should adopt the default pane settings. """
+        
+        state = self.state    
+        state |= self.optionTopDockable | self.optionBottomDockable | \
+                 self.optionLeftDockable | self.optionRightDockable | \
+                 self.optionNotebookDockable | \
+                 self.optionFloatable | self.optionMovable | self.optionResizable | \
+                 self.optionCaption | self.optionPaneBorder | self.buttonClose
+
+        self.state = state
+        
+        return self
+    
+    
+    def CentrePane(self):
+        """
+        Specifies that the pane should adopt the default center pane settings.
+
+        Centre panes usually do not have caption bars. This function provides an easy way of
+        preparing a pane to be displayed in the center dock position.
+        """
+        
+        return self.CenterPane()
+
+    
+    def CenterPane(self):
+        """
+        Specifies that the pane should adopt the default center pane settings.
+
+        Centre panes usually do not have caption bars. This function provides an easy way of
+        preparing a pane to be displayed in the center dock position.
+        """
+        
+        self.state = 0
+        return self.Center().PaneBorder().Resizable()
+    
+     
+    def ToolbarPane(self):
+        """ Specifies that the pane should adopt the default toolbar pane settings. """
+        
+        self.DefaultPane()
+        state = self.state
+        
+        state |= (self.optionToolbar | self.optionGripper)
+        state &= ~(self.optionResizable | self.optionCaption | self.optionCaptionLeft)
+        
+        if self.dock_layer == 0:
+            self.dock_layer = 10
+
+        self.state = state
+        
+        return self
+
+
+    def Icon(self, icon):
+        """
+        Specifies whether an icon is drawn on the left of the caption text when
+        the pane is docked. If `icon` is ``None`` or `wx.NullIcon`, no icon is drawn on
+        the caption space.
+
+        :param icon: an icon to draw on the caption space, or ``None``.
+        """
+
+        if icon is None:
+            icon = wx.NullIcon
+            
+        self.icon = icon
+        return self        
+    
+
+    def SetFlag(self, flag, option_state):
+        """
+        Turns the property given by `flag` on or off with the `option_state`
+        parameter.
+
+        :param `flag`: the property to set;
+        :param `option_state`: either ``True`` or ``False``.
+        """
+        
+        state = self.state
+        
+        if option_state:
+            state |= flag
+        else:
+            state &= ~flag
+
+        self.state = state
+
+        if flag in [self.buttonClose, self.buttonMaximize, self.buttonMinimize, self.buttonPin]:
+            self.ResetButtons()
+            
+        return self
+    
+    
+    def HasFlag(self, flag):
+        """
+        Returns ``True`` if the the property specified by flag is active for the pane.
+
+        :param `flag`: the property to check for activity.
+        """
+        
+        return (self.state & flag and [True] or [False])[0]
+
+
+    def ResetButtons(self):
+        """
+        Resets all the buttons and recreates them from scratch depending on the
+        L{AuiPaneInfo} flags.
+        """
+
+        floating = self.HasFlag(self.optionFloating)
+        self.buttons = []
+
+        if not floating and self.HasMinimizeButton():
+            button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
+            self.buttons.append(button)
+    
+        if not floating and self.HasMaximizeButton():
+            button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
+            self.buttons.append(button)
+
+        if not floating and self.HasPinButton():
+            button = AuiPaneButton(AUI_BUTTON_PIN)
+            self.buttons.append(button)
+
+        if self.HasCloseButton():
+            button = AuiPaneButton(AUI_BUTTON_CLOSE)
+            self.buttons.append(button)
+        
+
+    def CountButtons(self):
+        """ Returns the number of visible buttons in the docked pane. """
+
+        n = 0
+        
+        if self.HasCaption() or self.HasCaptionLeft():
+            if isinstance(wx.GetTopLevelParent(self.window), AuiFloatingFrame):
+                return 1
+            
+            if self.HasCloseButton():
+                n += 1
+            if self.HasMaximizeButton():
+                n += 1
+            if self.HasMinimizeButton():
+                n += 1
+            if self.HasPinButton():
+                n += 1
+
+        return n
+    
+
+    def IsHorizontal(self):
+        """ Returns ``True`` if the pane `dock_direction` is horizontal. """
+
+        return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
+
+    def IsVertical(self):
+        """ Returns ``True`` if the pane `dock_direction` is vertical. """
+
+        return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
+
+
+# Null AuiPaneInfo reference
+NonePaneInfo = AuiPaneInfo()
+
+
+# ---------------------------------------------------------------------------- #
+
+class AuiDockingGuide(wx.Frame):
+    """ Base class for L{AuiCenterDockingGuide} and L{AuiSingleDockingGuide}."""
+
+    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
+                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER, name="AuiDockingGuide"):
+        """
+        Default class constructor. Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiDockingGuide} parent;
+        :param `id`: the window identifier. It may take a value of -1 to indicate a default value.
+        :param `title`: the caption to be displayed on the frame's title bar.
+        :param `pos`: the window position. A value of (-1, -1) indicates a default position,
+         chosen by either the windowing system or wxPython, depending on platform.
+        :param `size`: the window size. A value of (-1, -1) indicates a default size, chosen by
+         either the windowing system or wxPython, depending on platform.
+        :param `style`: the window style. 
+        :param `name`: the name of the window. This parameter is used to associate a name with the
+         item, allowing the application user to set Motif resource values for individual windows.
+        """
+
+        wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
+
+
+    def HitTest(self, x, y):
+        """
+        To be overridden by parent classes.
+
+        :param `x`: the `x` mouse position;
+        :param `y`: the `y` mouse position.
+        """
+
+        return 0
+
+    
+    def ValidateNotebookDocking(self, valid):
+        """
+        To be overridden by parent classes.
+
+        :param `valid`: whether a pane can be docked on top to another to form an automatic
+         L{AuiNotebook}.
+        """
+        
+        return 0
+
+# ============================================================================
+# implementation
+# ============================================================================
+
+# ---------------------------------------------------------------------------
+# AuiDockingGuideWindow
+# ---------------------------------------------------------------------------
+
+class AuiDockingGuideWindow(wx.Window):
+    """ Target class for L{AuiSingleDockingGuide} and L{AuiCenterDockingGuide}. """
+
+    def __init__(self, parent, rect, direction=0, center=False, useAero=False):
+        """
+        Default class constructor. Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiDockingGuideWindow} parent;
+        :param `rect`: the window rect;
+        :param `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``,
+         ``wx.CENTER``;
+        :param `center`: whether the calling class is a L{AuiCenterDockingGuide};
+        :param `useAero`: whether to use the new Aero-style bitmaps or Whidbey-style bitmaps
+         for the docking guide.
+        """
+
+        wx.Window.__init__(self, parent, -1, rect.GetPosition(), rect.GetSize(), wx.NO_BORDER)
+
+        self._direction = direction
+        self._center = center
+        self._valid = True
+        self._useAero = useAero
+        
+        self._bmp_unfocus, self._bmp_focus = GetDockingImage(direction, useAero, center)
+        
+        self._currentImage = self._bmp_unfocus
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+
+
+    def SetValid(self, valid):
+        """
+        Sets the docking direction as valid or invalid.
+
+        :param `valid`: whether the docking direction is allowed or not.
+        """
+
+        self._valid = valid
+
+
+    def IsValid(self):
+        """ Returns whether the docking direction is valid. """
+        
+        return self._valid
+
+
+    def OnEraseBackground(self, event):
+        """
+        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiDockingGuideWindow}.
+
+        :param `event`: a `wx.EraseEvent` to be processed.
+
+        :note: This is intentionally empty to reduce flickering while drawing.
+        """
+
+        pass
+
+
+    def DrawBackground(self, dc):
+        """
+        Draws the docking guide background.
+
+        :param `dc`: a `wx.DC` device context object.
+        """
+
+        rect = self.GetClientRect()
+
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        dc.SetBrush(wx.Brush(colourTargetBackground))
+        dc.DrawRectangleRect(rect)
+
+        dc.SetPen(wx.Pen(colourTargetBorder))
+
+        left = rect.GetLeft()
+        top = rect.GetTop()
+        right = rect.GetRight()
+        bottom = rect.GetBottom()
+
+        if self._direction != wx.CENTER:
+        
+            if not self._center or self._direction != wx.BOTTOM:
+                dc.DrawLine(left, top, right+1, top)
+            if not self._center or self._direction != wx.RIGHT:
+                dc.DrawLine(left, top, left, bottom+1)
+            if not self._center or self._direction != wx.LEFT:
+                dc.DrawLine(right, top, right, bottom+1)
+            if not self._center or self._direction != wx.TOP:
+                dc.DrawLine(left, bottom, right+1, bottom)
+
+            dc.SetPen(wx.Pen(colourTargetShade))
+
+            if self._direction != wx.RIGHT:
+                dc.DrawLine(left + 1, top + 1, left + 1, bottom)
+            if self._direction != wx.BOTTOM:
+                dc.DrawLine(left + 1, top + 1, right, top + 1)
+
+        
+    def DrawDottedLine(self, dc, point, length, vertical):
+        """
+        Draws a dotted line (not used if the docking guide images are ok).
+
+        :param `dc`: a `wx.DC` device context object;
+        :param `point`: a `wx.Point` where to start drawing the dotted line;
+        :param `length`: the length of the dotted line;
+        :param `vertical`: whether it is a vertical docking guide window or not.
+        """
+
+        for i in xrange(0, length, 2):
+            dc.DrawPoint(point.x, point.y)
+            if vertical:
+                point.y += 2
+            else:
+                point.x += 2
+        
+
+    def DrawIcon(self, dc):
+        """
+        Draws the docking guide icon (not used if the docking guide images are ok).
+
+        :param `dc`: a `wx.DC` device context object.
+        """
+
+        rect = wx.Rect(*self.GetClientRect())
+        point = wx.Point()
+        length = 0
+
+        rect.Deflate(4, 4)
+        dc.SetPen(wx.Pen(colourIconBorder))
+        dc.SetBrush(wx.Brush(colourIconBackground))
+        dc.DrawRectangleRect(rect)
+
+        right1 = rect.GetRight() + 1
+        bottom1 = rect.GetBottom() + 1
+
+        dc.SetPen(wx.Pen(colourIconShadow))
+        dc.DrawLine(rect.x + 1, bottom1, right1 + 1, bottom1)
+        dc.DrawLine(right1, rect.y + 1, right1, bottom1 + 1)
+
+        rect.Deflate(1, 1)
+
+        if self._direction == wx.TOP:
+            rect.height -= rect.height / 2
+            point = rect.GetBottomLeft()
+            length = rect.width
+
+        elif self._direction == wx.LEFT:
+            rect.width -= rect.width / 2
+            point = rect.GetTopRight()
+            length = rect.height
+
+        elif self._direction == wx.RIGHT:
+            rect.x += rect.width / 2
+            rect.width -= rect.width / 2
+            point = rect.GetTopLeft()
+            length = rect.height
+
+        elif self._direction == wx.BOTTOM:
+            rect.y += rect.height / 2
+            rect.height -= rect.height / 2
+            point = rect.GetTopLeft()
+            length = rect.width
+
+        elif self._direction == wx.CENTER:
+            rect.Deflate(1, 1)
+            point = rect.GetTopLeft()
+            length = rect.width
+
+        dc.GradientFillLinear(rect, colourIconDockingPart1,
+                              colourIconDockingPart2, self._direction)
+
+        dc.SetPen(wx.Pen(colourIconBorder))
+
+        if self._direction == wx.CENTER:        
+            self.DrawDottedLine(dc, rect.GetTopLeft(), rect.width, False)
+            self.DrawDottedLine(dc, rect.GetTopLeft(), rect.height, True)
+            self.DrawDottedLine(dc, rect.GetBottomLeft(), rect.width, False)
+            self.DrawDottedLine(dc, rect.GetTopRight(), rect.height, True)
+        
+        elif self._direction in [wx.TOP, wx.BOTTOM]:
+            self.DrawDottedLine(dc, point, length, False)
+        
+        else:
+            self.DrawDottedLine(dc, point, length, True)
+        
+
+    def DrawArrow(self, dc):
+        """
+        Draws the docking guide arrow icon (not used if the docking guide images are ok).
+
+        :param `dc`: a `wx.DC` device context object.
+        """
+
+        rect = self.GetClientRect()
+        point = wx.Point()
+
+        point.x = (rect.GetLeft() + rect.GetRight()) / 2
+        point.y = (rect.GetTop() + rect.GetBottom()) / 2
+        rx, ry = wx.Size(), wx.Size()
+        
+        if self._direction == wx.TOP:
+            rx = wx.Size(1, 0)
+            ry = wx.Size(0, 1)
+
+        elif self._direction == wx.LEFT:
+            rx = wx.Size(0, -1)
+            ry = wx.Size(1, 0)
+
+        elif self._direction == wx.RIGHT:
+            rx = wx.Size(0, 1)
+            ry = wx.Size(-1, 0)
+
+        elif self._direction == wx.BOTTOM:
+            rx = wx.Size(-1, 0)
+            ry = wx.Size(0, -1)        
+
+        point.x += ry.x*3
+        point.y += ry.y*3
+
+        dc.SetPen(wx.Pen(colourIconArrow))
+
+        for i in xrange(4):
+            pt1 = wx.Point(point.x - rx.x*i, point.y - rx.y*i)
+            pt2 = wx.Point(point.x + rx.x*(i+1), point.y + rx.y*(i+1))
+            dc.DrawLinePoint(pt1, pt2)
+            point.x += ry.x
+            point.y += ry.y
+
+    
+    def OnPaint(self, event):
+        """
+        Handles the ``wx.EVT_PAINT`` event for L{AuiDockingGuideWindow}.
+
+        :param `event`: a `wx.PaintEvent` to be processed.
+        """
+
+        dc = wx.AutoBufferedPaintDC(self)
+        if self._currentImage.IsOk() and self._valid:
+            dc.DrawBitmap(self._currentImage, 0, 0, True)
+        else:
+            self.Draw(dc)
+
+
+    def Draw(self, dc):
+        """
+        Draws the whole docking guide window (not used if the docking guide images are ok).
+
+        :param `dc`: a `wx.DC` device context object.
+        """
+
+        self.DrawBackground(dc)
+
+        if self._valid:
+            self.DrawIcon(dc)
+            self.DrawArrow(dc)
+
+
+    def UpdateDockGuide(self, pos):
+        """
+        Updates the docking guide images depending on the mouse position, using focused
+        images if the mouse is inside the docking guide or unfocused images if it is
+        outside.
+
+        :param `pos`: a `wx.Point` mouse position.
+        """
+
+        inside = self.GetScreenRect().Contains(pos)
+        
+        if inside:
+            image = self._bmp_focus
+        else:
+            image = self._bmp_unfocus
+
+        if image != self._currentImage:
+            self._currentImage = image
+            self.Refresh()
+            self.Update()
+
+
+# ---------------------------------------------------------------------------
+# AuiSingleDockingGuide
+# ---------------------------------------------------------------------------
+
+class AuiSingleDockingGuide(AuiDockingGuide):
+    """ A docking guide window for single docking hint (not diamond-shaped HUD). """
+    
+    def __init__(self, parent, direction=0):
+        """
+        Default class constructor. Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiSingleDockingGuide} parent;
+        :param `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``.
+        """
+
+        self._direction = direction
+
+        style = wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | \
+                wx.FRAME_NO_TASKBAR | wx.NO_BORDER
+
+        # Use of FRAME_SHAPED on wxMac causes the frame to be visible
+        # breaking the docking hints.
+        if wx.Platform != '__WXMAC__':
+            style |= wx.FRAME_SHAPED
+
+        AuiDockingGuide.__init__(self, parent, style=style, name="auiSingleDockTarget")
+        
+        self.Hide()
+
+        useAero = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES
+        useWhidbey = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES
+        
+        self._useAero = useAero or useWhidbey
+        self._valid = True
+        
+        if useAero:
+            sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
+        elif useWhidbey:
+            sizeX, sizeY = whidbeySizeX, whidbeySizeY
+        else:
+            sizeX, sizeY = guideSizeX, guideSizeY
+
+        if direction not in [wx.TOP, wx.BOTTOM]:
+            sizeX, sizeY = sizeY, sizeX
+
+        if self._useAero:
+            self.CreateShapesWithStyle(useWhidbey)
+            
+            if wx.Platform == "__WXGTK__":
+                self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
+            else:
+                self.SetGuideShape()
+            
+            self.SetSize(self.region.GetBox().GetSize())
+        else:
+            self.SetSize((sizeX, sizeY))
+            
+        self.rect = wx.Rect(0, 0, sizeX, sizeY)
+
+        if self._useAero:
+            useAero = (useWhidbey and [2] or [1])[0]
+        else:
+            useAero = 0
+            
+        self.target = AuiDockingGuideWindow(self, self.rect, direction, False, useAero)
+
+
+    def CreateShapesWithStyle(self, useWhidbey):
+        """
+        Creates the docking guide window shape based on which docking bitmaps are used.
+
+        :param `useWhidbey`: if ``True``, use Whidbey-style bitmaps; if ``False``, use the
+         Aero-style bitmaps.
+         """
+
+        sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
+        if useWhidbey:
+            sizeX, sizeY = whidbeySizeX, whidbeySizeY
+
+        if self._direction not in [wx.TOP, wx.BOTTOM]:
+            sizeX, sizeY = sizeY, sizeX
+
+        useAero = (useWhidbey and [2] or [1])[0]      
+        bmp, dummy = GetDockingImage(self._direction, useAero, False)
+        region = wx.RegionFromBitmap(bmp)
+            
+        self.region = region
+        
+
+    def AeroMove(self, pos):
+        """
+        Moves the docking window to the new position. Overridden in children classes.
+
+        :param `pos`: the new docking guide position.
+        """
+
+        pass
+    
+
+    def SetGuideShape(self, event=None):
+        """
+        Sets the correct shape for the docking guide window.
+
+        :param `event`: on wxGTK, a `wx.WindowCreateEvent` event to process.
+        """
+
+        self.SetShape(self.region)        
+                
+        if event is not None:
+            # Skip the event on wxGTK
+            event.Skip()
+            wx.CallAfter(wx.SafeYield, self, True)
+
+
+    def SetShape(self, region):
+        """
+        If the platform supports it, sets the shape of the window to that depicted by `region`.
+        The system will not display or respond to any mouse event for the pixels that lie
+        outside of the region. To reset the window to the normal rectangular shape simply call
+        L{SetShape} again with an empty region. 
+
+        :param `region`: the shape of the frame.
+
+        :note: Overridden for wxMac.        
+        """
+        
+        if wx.Platform == '__WXMAC__':
+            # HACK so we don't crash when SetShape is called
+            return
+        else:
+            super(AuiSingleDockingGuide, self).SetShape(region)
+
+
+    def SetValid(self, valid):
+        """
+        Sets the docking direction as valid or invalid.
+
+        :param `valid`: whether the docking direction is allowed or not.
+        """
+
+        self._valid = valid
+
+
+    def IsValid(self):
+        """ Returns whether the docking direction is valid. """
+        
+        return self._valid
+
+
+    def UpdateDockGuide(self, pos):
+        """
+        Updates the docking guide images depending on the mouse position, using focused
+        images if the mouse is inside the docking guide or unfocused images if it is
+        outside.
+
+        :param `pos`: a `wx.Point` mouse position.
+        """
+
+        self.target.UpdateDockGuide(pos)
+
+        
+    def HitTest(self, x, y):
+        """
+        Checks if the mouse position is inside the target window rect.
+
+        :param `x`: the `x` mouse position;
+        :param `y`: the `y` mouse position.
+        """
+
+        if self.target.GetScreenRect().Contains((x, y)):
+            return wx.ALL
+
+        return -1
+
+
+# ---------------------------------------------------------------------------
+# AuiCenterDockingGuide
+# ---------------------------------------------------------------------------
+
+class AuiCenterDockingGuide(AuiDockingGuide):
+    """ A docking guide window for multiple docking hint (diamond-shaped HUD). """
+    
+    def __init__(self, parent):
+        """
+        Default class constructor.
+        Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiCenterDockingGuide} parent.
+        """
+
+        AuiDockingGuide.__init__(self, parent, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
+                                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED,
+                                 name="auiCenterDockTarget")
+
+        self.Hide()
+
+        self.CreateShapesWithStyle()
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        
+        if wx.Platform == "__WXGTK__":
+            self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
+        else:
+            self.SetGuideShape()
+            
+        self.SetSize(self.region.GetBox().GetSize())
+
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+
+
+    def CreateShapesWithStyle(self):
+        """ Creates the docking guide window shape based on which docking bitmaps are used. """
+
+        useAero = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES) != 0
+        useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
+
+        self._useAero = 0
+        if useAero:
+            self._useAero = 1
+        elif useWhidbey:
+            self._useAero = 2
+        
+        if useAero:
+            sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
+        elif useWhidbey:
+            sizeX, sizeY = whidbeySizeX, whidbeySizeY          
+        else:
+            sizeX, sizeY = guideSizeX, guideSizeY
+
+        rectLeft = wx.Rect(0, sizeY, sizeY, sizeX)
+        rectTop = wx.Rect(sizeY, 0, sizeX, sizeY)
+        rectRight = wx.Rect(sizeY+sizeX, sizeY, sizeY, sizeX)
+        rectBottom = wx.Rect(sizeY, sizeX + sizeY, sizeX, sizeY)
+        rectCenter = wx.Rect(sizeY, sizeY, sizeX, sizeX)
+            
+        if not self._useAero:
+
+            self.targetLeft = AuiDockingGuideWindow(self, rectLeft, wx.LEFT, True, useAero)
+            self.targetTop = AuiDockingGuideWindow(self, rectTop, wx.TOP, True, useAero)
+            self.targetRight = AuiDockingGuideWindow(self, rectRight, wx.RIGHT, True, useAero)
+            self.targetBottom = AuiDockingGuideWindow(self, rectBottom, wx.BOTTOM, True, useAero)
+            self.targetCenter = AuiDockingGuideWindow(self, rectCenter, wx.CENTER, True, useAero)
+
+            
+            # top-left diamond
+            tld = [wx.Point(rectTop.x, rectTop.y+rectTop.height-8),
+                   wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y),
+                   rectTop.GetBottomLeft()]
+            # bottom-left diamond
+            bld = [wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y+rectLeft.height),
+                   wx.Point(rectBottom.x, rectBottom.y+8),
+                   rectBottom.GetTopLeft()]
+            # top-right diamond
+            trd = [wx.Point(rectTop.x+rectTop.width, rectTop.y+rectTop.height-8),
+                   wx.Point(rectRight.x+8, rectRight.y),
+                   rectRight.GetTopLeft()]        
+            # bottom-right diamond
+            brd = [wx.Point(rectRight.x+8, rectRight.y+rectRight.height),
+                   wx.Point(rectBottom.x+rectBottom.width, rectBottom.y+8),
+                   rectBottom.GetTopRight()]
+
+            self._triangles = [tld[0:2], bld[0:2],
+                               [wx.Point(rectTop.x+rectTop.width-1, rectTop.y+rectTop.height-8),
+                                wx.Point(rectRight.x+7, rectRight.y)],
+                               [wx.Point(rectRight.x+7, rectRight.y+rectRight.height),
+                                wx.Point(rectBottom.x+rectBottom.width-1, rectBottom.y+8)]]
+            
+            region = wx.Region()
+            region.UnionRect(rectLeft)
+            region.UnionRect(rectTop)
+            region.UnionRect(rectRight)
+            region.UnionRect(rectBottom)
+            region.UnionRect(rectCenter)
+            region.UnionRegion(wx.RegionFromPoints(tld))
+            region.UnionRegion(wx.RegionFromPoints(bld))
+            region.UnionRegion(wx.RegionFromPoints(trd))
+            region.UnionRegion(wx.RegionFromPoints(brd))
+
+        elif useAero:
+
+            self._aeroBmp = aero_dock_pane.GetBitmap()
+            region = wx.RegionFromBitmap(self._aeroBmp)
+
+            self._allAeroBmps = [aero_dock_pane_left.GetBitmap(), aero_dock_pane_top.GetBitmap(),
+                                 aero_dock_pane_right.GetBitmap(), aero_dock_pane_bottom.GetBitmap(),
+                                 aero_dock_pane_center.GetBitmap(), aero_dock_pane.GetBitmap()]
+            self._deniedBitmap = aero_denied.GetBitmap()
+            self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter]
+            self._valid = True
+
+        elif useWhidbey:
+
+            self._aeroBmp = whidbey_dock_pane.GetBitmap()
+            region = wx.RegionFromBitmap(self._aeroBmp)
+
+            self._allAeroBmps = [whidbey_dock_pane_left.GetBitmap(), whidbey_dock_pane_top.GetBitmap(),
+                                 whidbey_dock_pane_right.GetBitmap(), whidbey_dock_pane_bottom.GetBitmap(),
+                                 whidbey_dock_pane_center.GetBitmap(), whidbey_dock_pane.GetBitmap()]
+            self._deniedBitmap = whidbey_denied.GetBitmap()
+            self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter]
+            self._valid = True
+            
+            
+        self.region = region
+        
+
+    def SetGuideShape(self, event=None):
+        """
+        Sets the correct shape for the docking guide window.
+
+        :param `event`: on wxGTK, a `wx.WindowCreateEvent` event to process.
+        """
+
+        self.SetShape(self.region)        
+
+        if event is not None:
+            # Skip the event on wxGTK
+            event.Skip()
+            wx.CallAfter(wx.SafeYield, self, True)
+
+            
+    def UpdateDockGuide(self, pos):
+        """
+        Updates the docking guides images depending on the mouse position, using focused
+        images if the mouse is inside the docking guide or unfocused images if it is
+        outside.
+
+        :param `pos`: a `wx.Point` mouse position.
+        """
+
+        if not self._useAero:
+            for target in self.GetChildren():
+                target.UpdateDockGuide(pos)
+        else:
+            lenRects = len(self._aeroRects)
+            for indx, rect in enumerate(self._aeroRects):
+                if rect.Contains(pos):
+                    if self._allAeroBmps[indx] != self._aeroBmp:
+                        if indx < lenRects - 1 or (indx == lenRects - 1 and self._valid):
+                            self._aeroBmp = self._allAeroBmps[indx]
+                            self.Refresh()
+                        else:
+                            self._aeroBmp = self._allAeroBmps[-1]
+                            self.Refresh()
+                            
+                    return
+
+            if self._aeroBmp != self._allAeroBmps[-1]:
+                self._aeroBmp = self._allAeroBmps[-1]
+                self.Refresh()
+
+
+    def HitTest(self, x, y):
+        """
+        Checks if the mouse position is inside the target windows rect.
+
+        :param `x`: the `x` mouse position;
+        :param `y`: the `y` mouse position.
+        """
+
+        if not self._useAero:
+            if self.targetLeft.GetScreenRect().Contains((x, y)):
+                return wx.LEFT
+            if self.targetTop.GetScreenRect().Contains((x, y)):
+                return wx.UP
+            if self.targetRight.GetScreenRect().Contains((x, y)):
+                return wx.RIGHT
+            if self.targetBottom.GetScreenRect().Contains((x, y)):
+                return wx.DOWN
+            if self.targetCenter.IsValid() and self.targetCenter.GetScreenRect().Contains((x, y)):
+                return wx.CENTER
+        else:
+            constants = [wx.LEFT, wx.UP, wx.RIGHT, wx.DOWN, wx.CENTER]
+            lenRects = len(self._aeroRects)
+            for indx, rect in enumerate(self._aeroRects):
+                if rect.Contains((x, y)):
+                    if indx < lenRects or (indx == lenRects-1 and self._valid):
+                        return constants[indx]
+
+        return -1
+
+
+    def ValidateNotebookDocking(self, valid):
+        """
+        Sets whether a pane can be docked on top of another to create an automatic
+        L{AuiNotebook}.
+
+        :param `valid`: whether a pane can be docked on top to another to form an automatic
+         L{AuiNotebook}.
+        """
+
+        if not self._useAero:
+            if self.targetCenter.IsValid() != valid:        
+                self.targetCenter.SetValid(valid)
+                self.targetCenter.Refresh()
+        else:
+            if self._valid != valid:
+                self._valid = valid
+                self.Refresh()
+    
+
+    def AeroMove(self, pos):
+        """
+        Moves the docking guide window to the new position.
+
+        :param `pos`: the new docking guide position.
+        """
+
+        if not self._useAero:
+            return
+
+        useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
+
+        if useWhidbey:
+            sizeX, sizeY = whidbeySizeX, whidbeySizeY            
+        else:
+            sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
+            
+        size = self.GetSize()
+        
+        leftRect, topRect, rightRect, bottomRect, centerRect = self._aeroRects
+        thePos = pos + wx.Point((size.x-sizeY)/2, (size.y-sizeX)/2)
+        
+        centerRect.SetPosition(thePos)
+
+        leftRect.SetPosition(thePos + wx.Point(-sizeY, 0))
+        topRect.SetPosition(thePos + wx.Point(0, -sizeY))
+        rightRect.SetPosition(thePos + wx.Point(sizeX, 0))
+        bottomRect.SetPosition(thePos + wx.Point(0, sizeX))
+        
+        
+    def OnEraseBackground(self, event):
+        """
+        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiCenterDockingGuide}.
+
+        :param `event`: `wx.EraseEvent` to be processed.
+
+        :note: This is intentionally empty to reduce flickering while drawing.
+        """
+        
+        pass
+
+
+    def OnPaint(self, event):
+        """
+        Handles the ``wx.EVT_PAINT`` event for L{AuiCenterDockingGuide}.
+
+        :param `event`: a `wx.PaintEvent` to be processed.
+        """
+
+        dc = wx.AutoBufferedPaintDC(self)
+
+        if self._useAero:
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+            dc.SetPen(wx.TRANSPARENT_PEN)
+        else:
+            dc.SetBrush(wx.Brush(colourTargetBackground))
+            dc.SetPen(wx.Pen(colourTargetBorder))
+
+        rect = self.GetClientRect()
+        dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
+
+        if self._useAero:
+            dc.DrawBitmap(self._aeroBmp, 0, 0, True)
+            if not self._valid:
+                diff = (self._useAero == 2 and [1] or [0])[0]
+                bmpX, bmpY = self._deniedBitmap.GetWidth(), self._deniedBitmap.GetHeight()
+                xPos, yPos = (rect.x + (rect.width)/2 - bmpX/2), (rect.y + (rect.height)/2 - bmpY/2)
+                dc.DrawBitmap(self._deniedBitmap, xPos+1, yPos+diff, True)
+                
+            return
+        
+        dc.SetPen(wx.Pen(colourTargetBorder, 2))
+        for pts in self._triangles:
+            dc.DrawLinePoint(pts[0], pts[1])
+            
+
+# ----------------------------------------------------------------------------
+# AuiDockingHintWindow
+# ----------------------------------------------------------------------------
+
+class AuiDockingHintWindow(wx.Frame):
+    """ The original wxAUI docking window hint. """
+
+    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
+                 size=wx.Size(1, 1), style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT |
+                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED,
+                 name="auiHintWindow"):
+        """
+        Default class constructor. Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiDockingGuide} parent;
+        :param `id`: the window identifier. It may take a value of -1 to indicate a default value.
+        :param `title`: the caption to be displayed on the frame's title bar;
+        :param `pos`: the window position. A value of (-1, -1) indicates a default position,
+         chosen by either the windowing system or wxPython, depending on platform;
+        :param `size`: the window size. A value of (-1, -1) indicates a default size, chosen by
+         either the windowing system or wxPython, depending on platform;
+        :param `style`: the window style;
+        :param `name`: the name of the window. This parameter is used to associate a name with the
+         item, allowing the application user to set Motif resource values for individual windows.
+        """
+        if wx.Platform == '__WXMAC__' and style & wx.FRAME_SHAPED:
+            # Having the shaped frame causes the frame to not be visible
+            # with the transparent style hints.
+            style -= wx.FRAME_SHAPED
+
+        wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
+        
+        self._blindMode = False
+        self.SetBackgroundColour(colourHintBackground)
+        
+        # Can't set background colour on a frame on wxMac
+        # so add a panel to set the colour on.
+        if wx.Platform == '__WXMAC__':
+            sizer = wx.BoxSizer(wx.HORIZONTAL)
+            self.panel = wx.Panel(self)
+            sizer.Add(self.panel, 1, wx.EXPAND)
+            self.SetSizer(sizer)
+            self.panel.SetBackgroundColour(colourHintBackground)
+
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        
+
+    def MakeVenetianBlinds(self):
+        """
+        Creates the "venetian blind" effect if L{AuiManager} has the ``AUI_MGR_VENETIAN_BLINDS_HINT``
+        flag set.
+        """
+
+        amount = 128
+        size = self.GetClientSize()
+        region = wx.Region(0, 0, size.x, 1)
+
+        for y in xrange(size.y):
+
+            # Reverse the order of the bottom 4 bits
+            j = (y & 8 and [1] or [0])[0] | (y & 4 and [2] or [0])[0] | \
+                (y & 2 and [4] or [0])[0] | (y & 1 and [8] or [0])[0]
+            
+            if 16*j+8 < amount:
+                region.Union(0, y, size.x, 1)
+                        
+        self.SetShape(region)
+
+
+    def SetBlindMode(self, agwFlags):
+        """
+        Sets whether venetian blinds or transparent hints will be shown as docking hint.
+        This depends on the L{AuiManager} flags.
+
+        :param `agwFlags`: the L{AuiManager} flags.
+        """
+
+        self._blindMode = (agwFlags & AUI_MGR_VENETIAN_BLINDS_HINT) != 0
+
+        if self._blindMode or not self.CanSetTransparent():
+            self.MakeVenetianBlinds()
+            self.SetTransparent(255)
+        
+        else:
+            self.SetShape(wx.Region())
+            if agwFlags & AUI_MGR_HINT_FADE == 0:                
+                self.SetTransparent(80)
+            else:
+                self.SetTransparent(0)
+
+
+    def SetShape(self, region):
+        """
+        If the platform supports it, sets the shape of the window to that depicted by `region`.
+        The system will not display or respond to any mouse event for the pixels that lie
+        outside of the region. To reset the window to the normal rectangular shape simply call
+        L{SetShape} again with an empty region. 
+
+        :param `region`: the shape of the frame (an instance of `wx.Region`).
+
+        :note: Overridden for wxMac.        
+        """
+        
+        if wx.Platform == '__WXMAC__':
+            # HACK so we don't crash when SetShape is called
+            return
+        else:
+            super(AuiDockingHintWindow, self).SetShape(region)
+
+
+    def Show(self, show=True):
+        """
+        Show the hint window.
+
+        :param `show`: whether to show or hide the hint docking window.
+        """
+        
+        super(AuiDockingHintWindow, self).Show(show)
+        if wx.Platform == '__WXMAC__':
+            # Need to manually do layout since its a borderless frame.
+            self.Layout()
+
+
+    def OnSize(self, event):
+        """
+        Handles the ``wx.EVT_SIZE`` event for L{AuiDockingHintWindow}.
+
+        :param `event`: a `wx.SizeEvent` to be processed.
+        """
+
+        if self._blindMode or not self.CanSetTransparent():
+            self.MakeVenetianBlinds()
+
+
+# ---------------------------------------------------------------------------- #
+
+# -- AuiFloatingFrame class implementation --            
+
+class AuiFloatingFrame(wx.MiniFrame):
+    """ AuiFloatingFrame is the frame class that holds floating panes. """
+
+    def __init__(self, parent, owner_mgr, pane=None, id=wx.ID_ANY, title="",
+                 style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT |
+                 wx.FRAME_NO_TASKBAR | wx.CLIP_CHILDREN):
+        """
+        Default class constructor. Used internally, do not call it in your code!
+
+        :param `parent`: the L{AuiFloatingFrame} parent;
+        :param `owner_mgr`: the L{AuiManager} that manages the floating pane;
+        :param `pane`: the L{AuiPaneInfo} pane that is about to float;
+        :param `id`: the window identifier. It may take a value of -1 to indicate a default value.
+        :param `title`: the caption to be displayed on the frame's title bar.
+        :param `style`: the window style.
+        """
+            
+        if pane and pane.IsResizeable():
+            style += wx.RESIZE_BORDER
+        if pane:
+            self._is_toolbar = pane.IsToolbar()
+
+        self._useNativeMiniframes = False
+        if AuiManager_UseNativeMiniframes(owner_mgr):
+            # On wxMac we always use native miniframes
+            self._useNativeMiniframes = True
+            style += wx.CAPTION + wx.SYSTEM_MENU
+            if pane.HasCloseButton():
+                style += wx.CLOSE_BOX
+            if pane.HasMaximizeButton():
+                style += wx.MAXIMIZE_BOX
+            if pane.HasMinimizeButton():
+                style += wx.MINIMIZE_BOX
+            
+        wx.MiniFrame.__init__(self, parent, id, title, pos=pane.floating_pos,
+                              size=pane.floating_size, style=style, name="auiFloatingFrame")
+
+        self._fly_timer = wx.Timer(self, wx.ID_ANY)
+        self._check_fly_timer = wx.Timer(self, wx.ID_ANY)
+        
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
+        self.Bind(wx.EVT_TIMER, self.OnCheckFlyTimer, self._check_fly_timer)
+        self.Bind(wx.EVT_TIMER, self.OnFlyTimer, self._fly_timer)
+        self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager)
+
+        if self._useNativeMiniframes:
+            self.Bind(wx.EVT_MOVE, self.OnMoveEvent)
+            self.Bind(wx.EVT_MOVING, self.OnMoveEvent)
+            self.Bind(wx.EVT_IDLE, self.OnIdle)
+            self._useNativeMiniframes = True
+            self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE)
+        else:
+            self.Bind(wx.EVT_MOVE, self.OnMove)
+
+        self._fly = False
+        self._send_size = True
+        self._alpha_amount = 255
+        
+        self._owner_mgr = owner_mgr
+        self._moving = False
+        self._lastDirection = None
+        self._transparent = 255
+
+        self._last_rect = wx.Rect()
+        self._last2_rect = wx.Rect()
+        self._last3_rect = wx.Rect()
+
+        self._mgr = AuiManager()
+        self._mgr.SetManagedWindow(self)
+        self._mgr.SetArtProvider(owner_mgr.GetArtProvider())
+        self._mgr.SetAGWFlags(owner_mgr.GetAGWFlags())
+
+
+    def CopyAttributes(self, pane):
+        """
+        Copies all the attributes of the input `pane` into another L{AuiPaneInfo}.
+
+        :param `pane`: the source L{AuiPaneInfo} from where to copy attributes.
+        """
+
+        contained_pane = AuiPaneInfo()
+
+        contained_pane.name = pane.name
+        contained_pane.caption = pane.caption
+        contained_pane.window = pane.window
+        contained_pane.frame = pane.frame
+        contained_pane.state = pane.state
+        contained_pane.dock_direction = pane.dock_direction
+        contained_pane.dock_layer = pane.dock_layer
+        contained_pane.dock_row = pane.dock_row
+        contained_pane.dock_pos = pane.dock_pos
+        contained_pane.best_size = wx.Size(*pane.best_size)
+        contained_pane.min_size = wx.Size(*pane.min_size)
+        contained_pane.max_size = wx.Size(*pane.max_size)
+        contained_pane.floating_pos = wx.Point(*pane.floating_pos)
+        contained_pane.floating_size = wx.Size(*pane.floating_size)
+        contained_pane.dock_proportion = pane.dock_proportion
+        contained_pane.buttons = pane.buttons
+        contained_pane.rect = wx.Rect(*pane.rect)
+        contained_pane.icon = pane.icon
+        contained_pane.notebook_id = pane.notebook_id
+        contained_pane.transparent = pane.transparent
+        contained_pane.snapped = pane.snapped
+        contained_pane.minimize_mode = pane.minimize_mode
+
+        return contained_pane
+    
+
+    def SetPaneWindow(self, pane):
+        """
+        Sets all the properties of a pane.
+
+        :param `pane`: the L{AuiPaneInfo} to analyze.
+        """
+
+        self._is_toolbar = pane.IsToolbar()
+        self._pane_window = pane.window
+
+        if isinstance(pane.window, auibar.AuiToolBar):
+            pane.window.SetAuiManager(self._mgr)
+        
+        self._pane_window.Reparent(self)
+        
+        contained_pane = self.CopyAttributes(pane)
+        
+        contained_pane.Dock().Center().Show(). \
+                       CaptionVisible(False). \
+                       PaneBorder(False). \
+                       Layer(0).Row(0).Position(0)
+
+        if not contained_pane.HasGripper() and not self._useNativeMiniframes:
+            contained_pane.CaptionVisible(True)
+
+        indx = self._owner_mgr._panes.index(pane)
+
+        # Carry over the minimum size
+        pane_min_size = pane.window.GetMinSize()
+
+        # if the best size is smaller than the min size
+        # then set the min size to the best size as well
+        pane_best_size = contained_pane.best_size
+        if pane_best_size.IsFullySpecified() and (pane_best_size.x < pane_min_size.x or \
+                                                  pane_best_size.y < pane_min_size.y):
+
+            pane_min_size = pane_best_size
+            self._pane_window.SetMinSize(pane_min_size)
+    
+        # if the frame window's max size is greater than the min size
+        # then set the max size to the min size as well
+        cur_max_size = self.GetMaxSize()
+        if cur_max_size.IsFullySpecified() and  (cur_max_size.x < pane_min_size.x or \
+                                                 cur_max_size.y < pane_min_size.y):
+            self.SetMaxSize(pane_min_size)
+
+        art_provider = self._mgr.GetArtProvider()
+        caption_size = art_provider.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        button_size = art_provider.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE) + \
+                      4*art_provider.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
+
+        min_size = pane.window.GetMinSize()
+
+        if min_size.y < caption_size or min_size.x < button_size:
+            new_x, new_y = min_size.x, min_size.y
+            if min_size.y < caption_size:
+                new_y = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)+caption_size] or [1])[0]
+            if min_size.x < button_size:
+                new_x = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_X)+button_size] or [1])[0]
+                
+            self.SetMinSize((new_x, new_y))
+        else:
+            self.SetMinSize(min_size)
+
+        self._mgr.AddPane(self._pane_window, contained_pane)
+        self._mgr.Update()           
+
+        if pane.min_size.IsFullySpecified():
+            # because SetSizeHints() calls Fit() too (which sets the window
+            # size to its minimum allowed), we keep the size before calling
+            # SetSizeHints() and reset it afterwards...
+            tmp = self.GetSize()
+            self.GetSizer().SetSizeHints(self)
+            self.SetSize(tmp)
+        
+        self.SetTitle(pane.caption)
+
+        if pane.floating_size != wx.Size(-1, -1):
+            self.SetSize(pane.floating_size)
+        else:
+            size = pane.best_size
+            if size == wx.Size(-1, -1):
+                size = pane.min_size
+            if size == wx.Size(-1, -1):
+                size = self._pane_window.GetSize()
+            if self._owner_mgr and pane.HasGripper():
+                if pane.HasGripperTop():
+                    size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
+                else:
+                    size.x += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
+
+            if not self._useNativeMiniframes:
+                size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+                
+            pane.floating_size = size
+            
+            self.SetClientSize(size)
+
+        self._owner_mgr._panes[indx] = pane
+
+        self._fly_step = abs(pane.floating_size.y - \
+                             (caption_size + 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)))/10
+
+        self._floating_size = wx.Size(*self.GetSize())
+
+        if pane.IsFlyOut():
+            self._check_fly_timer.Start(50)
+
+        
+    def GetOwnerManager(self):
+        """ Returns the L{AuiManager} that manages the pane. """
+
+        return self._owner_mgr
+
+
+    def OnSize(self, event):
+        """
+        Handles the ``wx.EVT_SIZE`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.SizeEvent` to be processed.
+        """
+
+        if self._owner_mgr and self._send_size:
+            self._owner_mgr.OnFloatingPaneResized(self._pane_window, event.GetSize())
+
+    
+    def OnClose(self, event):
+        """
+        Handles the ``wx.EVT_CLOSE`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.CloseEvent` to be processed.
+        """
+
+        if self._owner_mgr:
+            self._owner_mgr.OnFloatingPaneClosed(self._pane_window, event)
+
+        if not event.GetVeto():
+            self._mgr.DetachPane(self._pane_window)
+
+            if isinstance(self._pane_window, auibar.AuiToolBar):
+                self._pane_window.SetAuiManager(self._owner_mgr)
+
+            # if we do not do this, then we can crash...
+            if self._owner_mgr and self._owner_mgr._action_window == self:
+                self._owner_mgr._action_window = None
+
+            self.Destroy()
+    
+
+    def OnActivate(self, event):
+        """
+        Handles the ``wx.EVT_ACTIVATE`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.ActivateEvent` to be processed.
+        """
+
+        if self._owner_mgr and event.GetActive():
+            self._owner_mgr.OnFloatingPaneActivated(self._pane_window)
+
+
+    def OnMove(self, event):
+        """
+        Handles the ``wx.EVT_MOVE`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.MoveEvent` to be processed.
+
+        :note: This event is not processed on wxMAC or if L{AuiManager} is not using the
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
+        """
+
+        if self._owner_mgr:
+            self._owner_mgr.OnFloatingPaneMoved(self._pane_window, event)
+                
+
+    def OnMoveEvent(self, event):
+        """
+        Handles the ``wx.EVT_MOVE`` and ``wx.EVT_MOVING`` events for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.MoveEvent` to be processed.
+
+        :note: This event is only processed on wxMAC or if L{AuiManager} is using the
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
+        """
+
+        win_rect = self.GetRect()
+
+        if win_rect == self._last_rect:
+            return
+
+        # skip the first move event
+        if self._last_rect.IsEmpty():        
+            self._last_rect = wx.Rect(*win_rect)
+            return
+        
+        # skip if moving too fast to avoid massive redraws and
+        # jumping hint windows
+        if abs(win_rect.x - self._last_rect.x) > 3 or abs(win_rect.y - self._last_rect.y) > 3:
+            self._last3_rect = wx.Rect(*self._last2_rect)
+            self._last2_rect = wx.Rect(*self._last_rect)
+            self._last_rect = wx.Rect(*win_rect)
+            return
+
+        # prevent frame redocking during resize
+        if self._last_rect.GetSize() != win_rect.GetSize():
+            self._last3_rect = wx.Rect(*self._last2_rect)
+            self._last2_rect = wx.Rect(*self._last_rect)
+            self._last_rect = wx.Rect(*win_rect)
+            return
+
+        self._last3_rect = wx.Rect(*self._last2_rect)
+        self._last2_rect = wx.Rect(*self._last_rect)
+        self._last_rect = wx.Rect(*win_rect)
+
+        if _VERSION_STRING < "2.9":
+            leftDown = wx.GetMouseState().LeftDown()
+        else:
+            leftDown = wx.GetMouseState().LeftIsDown()
+
+        if not leftDown:
+            return
+
+        if not self._moving:        
+            self.OnMoveStart(event)
+            self._moving = True
+
+        if self._last3_rect.IsEmpty():
+            return
+
+        self.OnMoving(event)
+
+
+    def OnIdle(self, event):
+        """
+        Handles the ``wx.EVT_IDLE`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.IdleEvent` event to be processed.
+
+        :note: This event is only processed on wxMAC or if L{AuiManager} is using the
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.        
+        """
+
+        if self._moving:        
+            if _VERSION_STRING < "2.9":
+                leftDown = wx.GetMouseState().LeftDown()
+            else:
+                leftDown = wx.GetMouseState().LeftIsDown()
+
+            if not leftDown:
+                self._moving = False
+                self.OnMoveFinished()
+            else:            
+                event.RequestMore()
+
+        
+    def OnMoveStart(self, event):
+        """
+        The user has just started moving the floating pane.
+
+        :param `event`: an instance of `wx.MouseEvent`.
+    
+        :note: This method is used only on wxMAC or if L{AuiManager} is using the
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
+        """
+
+        # notify the owner manager that the pane has started to move
+        if self._owner_mgr:
+            if self._owner_mgr._from_move:
+                return
+            self._owner_mgr._action_window = self._pane_window
+            point = wx.GetMousePosition()
+            action_offset = point - self.GetPosition()
+
+            if self._is_toolbar:
+                self._owner_mgr._toolbar_action_offset = action_offset
+                self._owner_mgr.OnMotion_DragToolbarPane(point)
+            else:
+                self._owner_mgr._action_offset = action_offset
+                self._owner_mgr.OnMotion_DragFloatingPane(point)
+
+    
+    def OnMoving(self, event):
+        """
+        The user is moving the floating pane.
+
+        :param `event`: an instance of `wx.MouseEvent`.
+        
+        :note: This method is used only on wxMAC or if L{AuiManager} is using the
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
+        """
+
+        # notify the owner manager that the pane is moving
+        self.OnMoveStart(event)
+        
+
+    def OnMoveFinished(self):
+        """
+        The user has just finished moving the floating pane.
+
+        :note: This method is used only on wxMAC or if L{AuiManager} is using the
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
+        """
+
+        # notify the owner manager that the pane has finished moving
+        if self._owner_mgr:
+            self._owner_mgr._action_window = self._pane_window
+            point = wx.GetMousePosition()
+            if self._is_toolbar:
+                self._owner_mgr.OnLeftUp_DragToolbarPane(point)
+            else:
+                self._owner_mgr.OnLeftUp_DragFloatingPane(point)
+
+            self._owner_mgr.OnFloatingPaneMoved(self._pane_window, point)
+    
+
+    def OnCheckFlyTimer(self, event):
+        """
+        Handles the ``wx.EVT_TIMER`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.TimerEvent` to be processed.
+
+        :note: This is used solely for "fly-out" panes.        
+        """
+        
+        if self._owner_mgr:
+            pane = self._mgr.GetPane(self._pane_window)
+            if pane.IsFlyOut():
+                if self.IsShownOnScreen():
+                    self.FlyOut()
+                        
+
+    def OnFindManager(self, event):
+        """
+        Handles the ``EVT_AUI_FIND_MANAGER`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a L{AuiManagerEvent} event to be processed.
+        """
+        
+        event.SetManager(self._owner_mgr)
+
+
+    def FlyOut(self):
+        """ Starts the flying in and out of a floating pane. """
+
+        if self._fly_timer.IsRunning():
+            return
+
+        if _VERSION_STRING < "2.9":
+            leftDown = wx.GetMouseState().LeftDown()
+        else:
+            leftDown = wx.GetMouseState().LeftIsDown()
+
+        if leftDown:
+            return
+        
+        rect = wx.Rect(*self.GetScreenRect())
+        rect.Inflate(10, 10)
+
+        if rect.Contains(wx.GetMousePosition()):
+            if not self._fly:
+                return
+            self._send_size = False
+            self._fly_timer.Start(5)
+        else:
+            if self._fly:
+                return
+            self._send_size = False
+            self._fly_timer.Start(5)
+
+
+    def OnFlyTimer(self, event):            
+        """
+        Handles the ``wx.EVT_TIMER`` event for L{AuiFloatingFrame}.
+
+        :param `event`: a `wx.TimerEvent` to be processed.
+        """
+
+        current_size = self.GetClientSize()
+        floating_size = wx.Size(*self._owner_mgr.GetPane(self._pane_window).floating_size)
+
+        if floating_size.y == -1:
+            floating_size = self._floating_size
+        
+        if not self._fly:
+            min_size = self._mgr.GetArtProvider().GetMetric(AUI_DOCKART_CAPTION_SIZE)
+
+            if wx.Platform != "__WXMSW__":
+                min_size += 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)
+
+            if current_size.y - self._fly_step <= min_size:
+                self.SetClientSize((current_size.x, min_size))
+                self._fly = True
+                self._fly_timer.Stop()
+                self._send_size = True
+            else:
+                self.SetClientSize((current_size.x, current_size.y-self._fly_step))
+
+        else:
+            if current_size.y + self._fly_step >= floating_size.y:
+                self.SetClientSize((current_size.x, floating_size.y))
+                self._fly = False
+                self._fly_timer.Stop()
+                self._send_size = True
+            else:
+                self.SetClientSize((current_size.x, current_size.y+self._fly_step))
+
+        self.Update()
+        self.Refresh()
+
+
+    def FadeOut(self):
+        """ Actually starts the fading out of the floating pane. """
+
+        while 1:
+            self._alpha_amount -= 10
+            if self._alpha_amount <= 0:
+                self._alpha_amount = 255
+                return
+
+            self.SetTransparent(self._alpha_amount)
+            wx.SafeYield()
+            wx.MilliSleep(15)
+
+    
+# -- static utility functions --
+
+def DrawResizeHint(dc, rect):
+    """
+    Draws a resize hint while a sash is dragged.
+
+    :param `rect`: a `wx.Rect` rectangle which specifies the sash dimensions.
+    """
+        
+    if wx.Platform == "__WXMSW__" and wx.App.GetComCtl32Version() >= 600:
+        if wx.GetOsVersion()[1] > 5:
+            # Windows Vista
+            dc.SetPen(wx.Pen("black", 2, wx.SOLID))
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        else:
+            # Draw the nice XP style splitter
+            dc.SetPen(wx.TRANSPARENT_PEN)
+            dc.SetBrush(wx.BLACK_BRUSH)
+        dc.SetLogicalFunction(wx.INVERT)
+        dc.DrawRectangleRect(rect)
+        dc.SetLogicalFunction(wx.COPY)
+    else:
+        stipple = PaneCreateStippleBitmap()
+        brush = wx.BrushFromBitmap(stipple)
+        dc.SetBrush(brush)
+        dc.SetPen(wx.TRANSPARENT_PEN)
+
+        dc.SetLogicalFunction(wx.XOR)
+        dc.DrawRectangleRect(rect)    
+
+
+def CopyDocksAndPanes(src_docks, src_panes):
+    """
+    This utility function creates shallow copies of
+    the dock and pane info. L{AuiDockInfo} usually contain pointers
+    to L{AuiPaneInfo} classes, thus this function is necessary to reliably
+    reconstruct that relationship in the new dock info and pane info arrays.
+
+    :param `src_docks`: a list of L{AuiDockInfo} classes;
+    :param `src_panes`: a list of L{AuiPaneInfo} classes.
+    """
+    
+    dest_docks = src_docks
+    dest_panes = src_panes
+
+    for ii in xrange(len(dest_docks)):
+        dock = dest_docks[ii]
+        for jj in xrange(len(dock.panes)):
+            for kk in xrange(len(src_panes)):
+                if dock.panes[jj] == src_panes[kk]:
+                    dock.panes[jj] = dest_panes[kk]
+
+    return dest_docks, dest_panes
+
+
+def CopyDocksAndPanes2(src_docks, src_panes):
+    """
+    This utility function creates full copies of
+    the dock and pane info. L{AuiDockInfo} usually contain pointers
+    to L{AuiPaneInfo} classes, thus this function is necessary to reliably
+    reconstruct that relationship in the new dock info and pane info arrays.
+
+    :param `src_docks`: a list of L{AuiDockInfo} classes;
+    :param `src_panes`: a list of L{AuiPaneInfo} classes.
+    """
+    
+    dest_docks = []
+
+    for ii in xrange(len(src_docks)):
+        dest_docks.append(AuiDockInfo())
+        dest_docks[ii].dock_direction = src_docks[ii].dock_direction
+        dest_docks[ii].dock_layer = src_docks[ii].dock_layer
+        dest_docks[ii].dock_row = src_docks[ii].dock_row
+        dest_docks[ii].size = src_docks[ii].size
+        dest_docks[ii].min_size = src_docks[ii].min_size
+        dest_docks[ii].resizable = src_docks[ii].resizable
+        dest_docks[ii].fixed = src_docks[ii].fixed
+        dest_docks[ii].toolbar = src_docks[ii].toolbar
+        dest_docks[ii].panes = src_docks[ii].panes
+        dest_docks[ii].rect = wx.Rect(*src_docks[ii].rect)
+
+    dest_panes = []
+
+    for ii in xrange(len(src_panes)):
+        dest_panes.append(AuiPaneInfo())
+        dest_panes[ii].name = src_panes[ii].name
+        dest_panes[ii].caption = src_panes[ii].caption
+        dest_panes[ii].window = src_panes[ii].window
+        dest_panes[ii].frame = src_panes[ii].frame
+        dest_panes[ii].state = src_panes[ii].state
+        dest_panes[ii].dock_direction = src_panes[ii].dock_direction
+        dest_panes[ii].dock_layer = src_panes[ii].dock_layer
+        dest_panes[ii].dock_row = src_panes[ii].dock_row
+        dest_panes[ii].dock_pos = src_panes[ii].dock_pos
+        dest_panes[ii].best_size = wx.Size(*src_panes[ii].best_size)
+        dest_panes[ii].min_size = wx.Size(*src_panes[ii].min_size)
+        dest_panes[ii].max_size = wx.Size(*src_panes[ii].max_size)
+        dest_panes[ii].floating_pos = wx.Point(*src_panes[ii].floating_pos)
+        dest_panes[ii].floating_size = wx.Size(*src_panes[ii].floating_size)
+        dest_panes[ii].dock_proportion = src_panes[ii].dock_proportion
+        dest_panes[ii].buttons = src_panes[ii].buttons
+        dest_panes[ii].rect = wx.Rect(*src_panes[ii].rect)
+        dest_panes[ii].icon = src_panes[ii].icon
+        dest_panes[ii].notebook_id = src_panes[ii].notebook_id
+        dest_panes[ii].transparent = src_panes[ii].transparent
+        dest_panes[ii].snapped = src_panes[ii].snapped
+        dest_panes[ii].minimize_mode = src_panes[ii].minimize_mode
+
+    for ii in xrange(len(dest_docks)):
+        dock = dest_docks[ii]
+        for jj in xrange(len(dock.panes)):
+            for kk in xrange(len(src_panes)):
+                if dock.panes[jj] == src_panes[kk]:
+                    dock.panes[jj] = dest_panes[kk]
+
+        dest_docks[ii] = dock
+        
+    return dest_docks, dest_panes
+
+
+def GetMaxLayer(docks, dock_direction):
+    """
+    This is an internal function which returns
+    the highest layer inside the specified dock.
+
+    :param `docks`: a list of L{AuiDockInfo};
+    :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze.
+    """
+    
+    max_layer = 0
+
+    for dock in docks:
+        if dock.dock_direction == dock_direction and dock.dock_layer > max_layer and not dock.fixed:
+            max_layer = dock.dock_layer
+    
+    return max_layer
+
+
+def GetMaxRow(panes, dock_direction, dock_layer):
+    """
+    This is an internal function which returns
+    the highest layer inside the specified dock.
+
+    :param `panes`: a list of L{AuiPaneInfo};
+    :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
+    :param `dock_layer`: the L{AuiPaneInfo} layer to analyze.
+    """
+    
+    max_row = 0
+
+    for pane in panes:
+        if pane.dock_direction == dock_direction and pane.dock_layer == dock_layer and \
+           pane.dock_row > max_row:
+            max_row = pane.dock_row
+    
+    return max_row
+
+
+def DoInsertDockLayer(panes, dock_direction, dock_layer):
+    """
+    This is an internal function that inserts a new dock
+    layer by incrementing all existing dock layer values by one.
+    
+    :param `panes`: a list of L{AuiPaneInfo};
+    :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
+    :param `dock_layer`: the L{AuiPaneInfo} layer to analyze.
+    """
+    
+    for ii in xrange(len(panes)):
+        pane = panes[ii]
+        if not pane.IsFloating() and pane.dock_direction == dock_direction and pane.dock_layer >= dock_layer:
+            pane.dock_layer = pane.dock_layer + 1
+
+        panes[ii] = pane
+
+    return panes
+
+
+def DoInsertDockRow(panes, dock_direction, dock_layer, dock_row):
+    """
+    This is an internal function that inserts a new dock
+    row by incrementing all existing dock row values by one.
+    
+    :param `panes`: a list of L{AuiPaneInfo};
+    :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
+    :param `dock_layer`: the L{AuiPaneInfo} layer to analyze;
+    :param `dock_row`: the L{AuiPaneInfo} row to analyze.
+    """
+    
+    for pane in panes:
+        if not pane.IsFloating() and pane.dock_direction == dock_direction and \
+           pane.dock_layer == dock_layer and pane.dock_row >= dock_row:
+            pane.dock_row += 1
+
+    return panes
+
+    
+def DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos):
+    """
+    This is an internal function that inserts a new pane
+    by incrementing all existing dock position values by one.
+    
+    :param `panes`: a list of L{AuiPaneInfo};
+    :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
+    :param `dock_layer`: the L{AuiPaneInfo} layer to analyze;
+    :param `dock_row`: the L{AuiPaneInfo} row to analyze;
+    :param `dock_pos`: the L{AuiPaneInfo} row to analyze.
+    """
+
+    for ii in xrange(len(panes)):
+        pane = panes[ii]
+        if not pane.IsFloating() and pane.dock_direction == dock_direction and \
+           pane.dock_layer == dock_layer and  pane.dock_row == dock_row and \
+           pane.dock_pos >= dock_pos:
+            pane.dock_pos = pane.dock_pos + 1
+
+        panes[ii] = pane
+
+    return panes
+
+
+def FindDocks(docks, dock_direction, dock_layer=-1, dock_row=-1, reverse=False):
+    """
+    This is an internal function that returns a list of docks which meet
+    the specified conditions in the parameters and returns a sorted array
+    (sorted by layer and then row).
+    
+    :param `docks`: a list of L{AuiDockInfo};
+    :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze;
+    :param `dock_layer`: the L{AuiDockInfo} layer to analyze;
+    :param `dock_row`: the L{AuiDockInfo} row to analyze;
+    """
+    
+    matchDocks = [(d.dock_layer, d.dock_row, d.dock_direction, d) for d in docks if \
+                  (dock_direction == -1 or dock_direction == d.dock_direction) and \
+                  ((dock_layer == -1 or dock_layer == d.dock_layer) and \
+                  (dock_row == -1 or dock_row == d.dock_row))]
+    
+    arr = [x[-1] for x in sorted(matchDocks, reverse=reverse)]
+    
+    return arr
+
+
+def FindOppositeDocks(docks, dock_direction):
+    """
+    This is an internal function that returns a list of docks
+    which is related to the opposite direction.
+
+    :param `docks`: a list of L{AuiDockInfo};
+    :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze;
+    """
+
+    if dock_direction == AUI_DOCK_LEFT:
+        arr = FindDocks(docks, AUI_DOCK_RIGHT, -1, -1)
+    elif dock_direction == AUI_DOCK_TOP:
+        arr = FindDocks(docks, AUI_DOCK_BOTTOM, -1, -1)
+    elif dock_direction == AUI_DOCK_RIGHT:
+        arr = FindDocks(docks, AUI_DOCK_LEFT, -1, -1)
+    elif dock_direction == AUI_DOCK_BOTTOM:
+        arr = FindDocks(docks, AUI_DOCK_TOP, -1, -1)
+
+    return arr    
+
+
+def FindPaneInDock(dock, window):
+    """
+    This method looks up a specified window pointer inside a dock.
+    If found, the corresponding L{AuiPaneInfo} pointer is returned, otherwise ``None``.
+
+    :param `dock`: a L{AuiDockInfo} structure;
+    :param `window`: a `wx.Window` derived window (associated to a pane).
+    """
+
+    for p in dock.panes:
+        if p.window == window:
+            return p
+    
+    return None
+
+
+def GetToolBarDockOffsets(docks):
+    """
+    Returns the toolbar dock offsets (top-left and bottom-right).
+
+    :param `docks`: a list of L{AuiDockInfo} to analyze.
+    """
+
+    top_left = wx.Size(0, 0)
+    bottom_right = wx.Size(0, 0)
+
+    for dock in docks:
+        if dock.toolbar:
+            dock_direction = dock.dock_direction
+            if dock_direction == AUI_DOCK_LEFT:
+                top_left.x += dock.rect.width
+                bottom_right.x += dock.rect.width
+
+            elif dock_direction == AUI_DOCK_TOP:
+                top_left.y += dock.rect.height
+                bottom_right.y += dock.rect.height
+
+            elif dock_direction == AUI_DOCK_RIGHT:
+                bottom_right.x += dock.rect.width
+            
+            elif dock_direction == AUI_DOCK_BOTTOM:
+                bottom_right.y += dock.rect.height
+
+    return top_left, bottom_right        
+    
+
+def GetInternalFrameRect(window, docks):
+    """
+    Returns the window rectangle excluding toolbars.
+
+    :param `window`: a `wx.Window` derived window;
+    :param `docks`: a list of L{AuiDockInfo} structures.
+    """
+
+    frameRect = wx.Rect()
+
+    frameRect.SetTopLeft(window.ClientToScreen(window.GetClientAreaOrigin()))
+    frameRect.SetSize(window.GetClientSize())
+
+    top_left, bottom_right = GetToolBarDockOffsets(docks)
+
+    # make adjustments for toolbars
+    frameRect.x += top_left.x
+    frameRect.y += top_left.y
+    frameRect.width -= bottom_right.x
+    frameRect.height -= bottom_right.y
+
+    return frameRect
+
+
+def CheckOutOfWindow(window, pt):
+    """
+    Checks if a point is outside the window rectangle.
+    
+    :param `window`: a `wx.Window` derived window;
+    :param `pt`: a `wx.Point` object.
+    """
+
+    auiWindowMargin = 30
+    marginRect = wx.Rect(*window.GetClientRect())
+    marginRect.Inflate(auiWindowMargin, auiWindowMargin)
+
+    return not marginRect.Contains(pt)
+
+
+def CheckEdgeDrop(window, docks, pt):
+    """
+    Checks on which edge of a window the drop action has taken place.
+
+    :param `window`: a `wx.Window` derived window;
+    :param `docks`: a list of L{AuiDockInfo} structures;
+    :param `pt`: a `wx.Point` object.
+    """
+
+    screenPt = window.ClientToScreen(pt)
+    clientSize = window.GetClientSize()
+    frameRect = GetInternalFrameRect(window, docks)
+
+    if screenPt.y >= frameRect.GetTop() and screenPt.y < frameRect.GetBottom():
+        if pt.x < auiLayerInsertOffset and pt.x > auiLayerInsertOffset - auiLayerInsertPixels:
+            return wx.LEFT
+        
+        if pt.x >= clientSize.x - auiLayerInsertOffset and \
+           pt.x < clientSize.x - auiLayerInsertOffset + auiLayerInsertPixels:
+            return wx.RIGHT
+        
+    if screenPt.x >= frameRect.GetLeft() and screenPt.x < frameRect.GetRight():
+        if pt.y < auiLayerInsertOffset and pt.y > auiLayerInsertOffset - auiLayerInsertPixels:
+            return wx.TOP
+        
+        if pt.y >= clientSize.y - auiLayerInsertOffset and \
+           pt.y < clientSize.y - auiLayerInsertOffset + auiLayerInsertPixels:
+            return wx.BOTTOM
+
+    return -1
+
+
+def RemovePaneFromDocks(docks, pane, exc=None):
+    """
+    Removes a pane window from all docks
+    with a possible exception specified by parameter `exc`.
+
+    :param `docks`: a list of L{AuiDockInfo} structures;
+    :param `pane`: the L{AuiPaneInfo} pane to be removed;
+    :param `exc`: the possible pane exception.
+    """
+    
+    for ii in xrange(len(docks)):
+        d = docks[ii]
+        if d == exc:
+            continue
+        pi = FindPaneInDock(d, pane.window)
+        if pi:
+            d.panes.remove(pi)
+
+        docks[ii] = d            
+
+    return docks
+
+
+def RenumberDockRows(docks):
+    """
+    Takes a dock and assigns sequential numbers
+    to existing rows.  Basically it takes out the gaps so if a
+    dock has rows with numbers 0, 2, 5, they will become 0, 1, 2.
+
+    :param `docks`: a list of L{AuiDockInfo} structures.    
+    """
+    
+    for ii in xrange(len(docks)):
+        dock = docks[ii]
+        dock.dock_row = ii
+        for jj in xrange(len(dock.panes)):
+            dock.panes[jj].dock_row = ii
+
+        docks[ii] = dock
+        
+    return docks
+
+
+def SetActivePane(panes, active_pane):
+    """
+    Sets the active pane, as well as cycles through
+    every other pane and makes sure that all others' active flags
+    are turned off.
+
+    :param `panes`: a list of L{AuiPaneInfo} structures;
+    :param `active_pane`: the pane to be made active (if found).
+    """
+
+    for pane in panes:
+        pane.state &= ~AuiPaneInfo.optionActive
+
+    for pane in panes:
+        if pane.window == active_pane and not pane.IsNotebookPage():
+            pane.state |= AuiPaneInfo.optionActive
+            return True, panes
+            
+    return False, panes
+        
+
+def ShowDockingGuides(guides, show):
+    """
+    Shows or hide the docking guide windows.
+
+    :param `guides`: a list of L{AuiDockingGuideInfo} classes;
+    :param `show`: whether to show or hide the docking guide windows.
+    """
+
+    for target in guides:
+        
+        if show and not target.host.IsShown():
+            target.host.Show()
+            target.host.Update()
+        
+        elif not show and target.host.IsShown():        
+            target.host.Hide()
+        
+
+def RefreshDockingGuides(guides):
+    """
+    Refreshes the docking guide windows.
+
+    :param `guides`: a list of L{AuiDockingGuideInfo} classes;
+    """
+    
+    for target in guides:
+        if target.host.IsShown():
+            target.host.Refresh()
+        
+    
+def PaneSortFunc(p1, p2):
+    """
+    This function is used to sort panes by dock position.
+
+    :param `p1`: a L{AuiPaneInfo} instance;
+    :param `p2`: another L{AuiPaneInfo} instance.    
+    """
+    
+    return (p1.dock_pos < p2.dock_pos and [-1] or [1])[0]
+
+
+def GetNotebookRoot(panes, notebook_id):
+    """
+    Returns the L{AuiPaneInfo} which has the specified `notebook_id`.
+
+    :param `panes`: a list of L{AuiPaneInfo} instances;
+    :param `notebook_id`: the target notebook id.
+    """    
+
+    for paneInfo in panes:
+        if paneInfo.IsNotebookControl() and paneInfo.notebook_id == notebook_id:
+            return paneInfo
+        
+    return None
+
+
+def EscapeDelimiters(s):
+    """
+    Changes ``;`` into ``\`` and ``|`` into ``\|`` in the input string.  
+
+    :param `s`: the string to be analyzed.
+
+    :note: This is an internal functions which is used for saving perspectives.    
+    """
+    
+    result = s.replace(";", "\\")
+    result = result.replace("|", "|\\")
+    
+    return result
+
+
+def IsDifferentDockingPosition(pane1, pane2):
+    """
+    Returns whether `pane1` and `pane2` are in a different docking position
+    based on pane status, docking direction, docking layer and docking row.
+
+    :param `pane1`: a L{AuiPaneInfo} instance;
+    :param `pane2`: another L{AuiPaneInfo} instance.
+    """
+
+    return pane1.IsFloating() != pane2.IsFloating() or \
+           pane1.dock_direction != pane2.dock_direction or \
+           pane1.dock_layer != pane2.dock_layer or \
+           pane1.dock_row != pane2.dock_row
+
+
+# Convenience function
+def AuiManager_HasLiveResize(manager):
+    """
+    Static function which returns if the input `manager` should have "live resize"
+    behaviour.
+
+    :param `manager`: an instance of L{AuiManager}.
+
+    :note: This method always returns ``True`` on wxMac as this platform doesn't have
+     the ability to use `wx.ScreenDC` to draw sashes.
+    """
+
+    # With Core Graphics on Mac, it's not possible to show sash feedback,
+    # so we'll always use live update instead.
+    
+    if wx.Platform == "__WXMAC__":
+        return True
+    else:
+        return (manager.GetAGWFlags() & AUI_MGR_LIVE_RESIZE) == AUI_MGR_LIVE_RESIZE
+
+
+# Convenience function
+def AuiManager_UseNativeMiniframes(manager):
+    """
+    Static function which returns if the input `manager` should use native `wx.MiniFrame` as
+    floating panes.
+
+    :param `manager`: an instance of L{AuiManager}.
+
+    :note: This method always returns ``True`` on wxMac as this platform doesn't have
+     the ability to use custom drawn miniframes.
+    """
+
+    # With Core Graphics on Mac, it's not possible to show sash feedback,
+    # so we'll always use live update instead.
+    
+    if wx.Platform == "__WXMAC__":
+        return True
+    else:
+        return (manager.GetAGWFlags() & AUI_MGR_USE_NATIVE_MINIFRAMES) == AUI_MGR_USE_NATIVE_MINIFRAMES
+
+
+def GetManager(window):
+    """
+    This function will return the aui manager for a given window.
+    
+    :param `window`: this parameter should be any child window or grand-child
+     window (and so on) of the frame/window managed by L{AuiManager}. The window
+     does not need to be managed by the manager itself, nor does it even need
+     to be a child or sub-child of a managed window. It must however be inside
+     the window hierarchy underneath the managed window.
+    """
+    
+    if not isinstance(wx.GetTopLevelParent(window), AuiFloatingFrame):
+        if isinstance(window, auibar.AuiToolBar):
+            return window.GetAuiManager()
+    
+    evt = AuiManagerEvent(wxEVT_AUI_FIND_MANAGER)
+    evt.SetManager(None)
+    evt.ResumePropagation(wx.EVENT_PROPAGATE_MAX)
+
+    if not window.GetEventHandler().ProcessEvent(evt):
+        return None
+
+    return evt.GetManager()
+
+
+# ---------------------------------------------------------------------------- #
+
+class AuiManager(wx.EvtHandler):
+    """
+    AuiManager manages the panes associated with it for a particular `wx.Frame`,
+    using a pane's L{AuiPaneInfo} information to determine each pane's docking and
+    floating behavior. L{AuiManager} uses wxPython's sizer mechanism to plan the
+    layout of each frame. It uses a replaceable dock art class to do all drawing,
+    so all drawing is localized in one area, and may be customized depending on an
+    applications' specific needs.
+
+    L{AuiManager} works as follows: the programmer adds panes to the class, or makes
+    changes to existing pane properties (dock position, floating state, show state, etc...).
+    To apply these changes, the L{AuiManager.Update} function is called. This batch
+    processing can be used to avoid flicker, by modifying more than one pane at a time,
+    and then "committing" all of the changes at once by calling `Update()`.
+
+    Panes can be added quite easily::
+
+        text1 = wx.TextCtrl(self, -1)
+        text2 = wx.TextCtrl(self, -1)
+        self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
+        self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
+
+        self._mgr.Update()
+
+
+    Later on, the positions can be modified easily. The following will float an
+    existing pane in a tool window::
+
+        self._mgr.GetPane(text1).Float()
+
+
+    **Layers, Rows and Directions, Positions:**
+    
+    Inside AUI, the docking layout is figured out by checking several pane parameters.
+    Four of these are important for determining where a pane will end up.
+
+    **Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`.
+    This is fairly self-explanatory. The pane will be placed in the location specified
+    by this variable.
+
+    **Position** - More than one pane can be placed inside of a "dock". Imagine two panes
+    being docked on the left side of a window. One pane can be placed over another.
+    In proportionally managed docks, the pane position indicates it's sequential position,
+    starting with zero. So, in our scenario with two panes docked on the left side, the
+    top pane in the dock would have position 0, and the second one would occupy position 1. 
+
+    **Row** - A row can allow for two docks to be placed next to each other. One of the most
+    common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
+    the first row being in row 0, and the second in row 1. Rows can also be used on
+    vertically docked panes. 
+
+    **Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
+    Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
+    known as the "content window"). Increasing layers "swallow up" all layers of a lower
+    value. This can look very similar to multiple rows, but is different because all panes
+    in a lower level yield to panes in higher levels. The best way to understand layers
+    is by running the AUI sample (`AUI.py`).
+    """
+
+    def __init__(self, managed_window=None, agwFlags=None):
+        """
+        Default class constructor.
+        
+        :param `managed_window`: specifies the window which should be managed;
+        :param `agwFlags`: specifies options which allow the frame management behavior to be
+         modified. `agwFlags` can be a combination of the following style bits:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_MGR_ALLOW_FLOATING``           Allow floating of panes
+         ``AUI_MGR_ALLOW_ACTIVE_PANE``        If a pane becomes active, "highlight" it in the interface
+         ``AUI_MGR_TRANSPARENT_DRAG``         If the platform supports it, set transparency on a floating pane while it is dragged by the user
+         ``AUI_MGR_TRANSPARENT_HINT``         If the platform supports it, show a transparent hint window when the user is about to dock a floating pane
+         ``AUI_MGR_VENETIAN_BLINDS_HINT``     Show a "venetian blind" effect when the user is about to dock a floating pane
+         ``AUI_MGR_RECTANGLE_HINT``           Show a rectangle hint effect when the user is about to dock a floating pane
+         ``AUI_MGR_HINT_FADE``                If the platform supports it, the hint window will fade in and out
+         ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``  Disables the "venetian blind" fade in and out
+         ``AUI_MGR_LIVE_RESIZE``              Live resize when the user drag a sash
+         ``AUI_MGR_ANIMATE_FRAMES``           Fade-out floating panes when they are closed (all platforms which support frames transparency) and show a moving rectangle when they are docked (Windows < Vista and GTK only)
+         ``AUI_MGR_AERO_DOCKING_GUIDES``      Use the new Aero-style bitmaps as docking guides
+         ``AUI_MGR_PREVIEW_MINIMIZED_PANES``  Slide in and out minimized panes to preview them
+         ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``   Use the new Whidbey-style bitmaps as docking guides
+         ``AUI_MGR_SMOOTH_DOCKING``           Performs a "smooth" docking of panes (a la PyQT)
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES``    Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMac)
+         ``AUI_MGR_AUTONB_NO_CAPTION``        Panes that merge into an automatic notebook will not have the pane caption visible
+         ==================================== ==================================
+
+         Default value for `agwFlags` is:
+         ``AUI_MGR_DEFAULT`` = ``AUI_MGR_ALLOW_FLOATING`` | ``AUI_MGR_TRANSPARENT_HINT`` | ``AUI_MGR_HINT_FADE`` | ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``
+
+         :note: If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a
+          floating pane caption will not re-dock the pane, but simply maximize it (if
+          L{AuiPaneInfo.MaximizeButton} has been set to ``True``) or do nothing.
+        """
+
+        wx.EvtHandler.__init__(self)
+        
+        self._action = actionNone
+        self._action_window = None
+        self._hover_button = None
+        self._art = dockart.AuiDefaultDockArt()
+        self._hint_window = None
+        self._active_pane = None
+        self._has_maximized = False
+        self._has_minimized = False
+
+        self._frame = None
+        self._dock_constraint_x = 0.3
+        self._dock_constraint_y = 0.3
+        self._reserved = None
+    
+        self._panes = []
+        self._docks = []
+        self._uiparts = []
+        
+        self._guides = []
+        self._notebooks = []
+
+        self._masterManager = None
+        self._currentDragItem = -1
+        self._lastknowndocks = {}
+
+        self._hint_fadetimer = wx.Timer(self, wx.ID_ANY)
+        self._hint_fademax = 50
+        self._last_hint = wx.Rect()
+
+        self._from_move = False
+        self._last_rect = wx.Rect()
+        
+        if agwFlags is None:
+            agwFlags = AUI_MGR_DEFAULT
+            
+        self._agwFlags = agwFlags
+        self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
+        self._snap_limits = (15, 15)
+
+        if wx.Platform == "__WXMSW__":
+            self._animation_step = 30.0
+        else:
+            self._animation_step = 5.0
+
+        self._hint_rect = wx.Rect()
+
+        self._preview_timer = wx.Timer(self, wx.ID_ANY)
+        self._sliding_frame = None
+
+        self._autoNBTabArt = tabart.AuiDefaultTabArt()
+        self._autoNBStyle = AUI_NB_DEFAULT_STYLE | AUI_NB_BOTTOM | \
+                            AUI_NB_SUB_NOTEBOOK | AUI_NB_TAB_EXTERNAL_MOVE
+        self._autoNBStyle -= AUI_NB_DRAW_DND_TAB
+
+        if managed_window:
+            self.SetManagedWindow(managed_window)
+
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor)
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
+        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
+        self.Bind(wx.EVT_MOTION, self.OnMotion)
+        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
+        self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus)
+        self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost)
+        self.Bind(wx.EVT_TIMER, self.OnHintFadeTimer, self._hint_fadetimer)
+        self.Bind(wx.EVT_TIMER, self.SlideIn, self._preview_timer)
+
+        self.Bind(wx.EVT_MOVE, self.OnMove)
+        self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged)
+        
+        self.Bind(EVT_AUI_PANE_BUTTON, self.OnPaneButton)
+        self.Bind(EVT_AUI_RENDER, self.OnRender)
+        self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager)
+        self.Bind(EVT_AUI_PANE_MIN_RESTORE, self.OnRestoreMinimizedPane)
+        self.Bind(EVT_AUI_PANE_DOCKED, self.OnPaneDocked)
+
+        self.Bind(auibook.EVT_AUINOTEBOOK_BEGIN_DRAG, self.OnTabBeginDrag)
+        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnTabPageClose)
+        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnTabSelected)
+        
+
+    def CreateFloatingFrame(self, parent, pane_info):
+        """
+        Creates a floating frame for the windows.
+
+        :param `parent`: the floating frame parent;
+        :param `pane_info`: the L{AuiPaneInfo} class with all the pane's information.
+        """
+
+        return AuiFloatingFrame(parent, self, pane_info)
+
+
+    def CanDockPanel(self, p):
+        """
+        Returns whether a pane can be docked or not.
+
+        :param `p`: the L{AuiPaneInfo} class with all the pane's information.
+        """        
+
+        # is the pane dockable?
+        if not p.IsDockable():
+            return False
+
+        # if a key modifier is pressed while dragging the frame,
+        # don't dock the window
+        return not (wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT))
+
+
+    def GetPaneByWidget(self, window):
+        """
+        This version of L{GetPane} looks up a pane based on a
+        'pane window'.
+
+        :param `window`: a `wx.Window` derived window.
+
+        :see: L{GetPane}
+        """
+
+        for p in self._panes:
+            if p.window == window:
+                return p
+
+        return NonePaneInfo
+
+
+    def GetPaneByName(self, name):
+        """
+        This version of L{GetPane} looks up a pane based on a
+        'pane name'.
+
+        :param `name`: the pane name.
+
+        :see: L{GetPane}        
+        """
+        
+        for p in self._panes:
+            if p.name == name:
+                return p
+        
+        return NonePaneInfo
+
+
+    def GetPane(self, item):
+        """
+        Looks up a L{AuiPaneInfo} structure based
+        on the supplied window pointer. Upon failure, L{GetPane}
+        returns an empty L{AuiPaneInfo}, a condition which can be checked
+        by calling L{AuiPaneInfo.IsOk}.
+
+        The pane info's structure may then be modified. Once a pane's
+        info is modified, L{Update} must be called to
+        realize the changes in the UI.
+
+        :param `item`: either a pane name or a `wx.Window`.        
+        """
+
+        if isinstance(item, basestring):
+            return self.GetPaneByName(item)
+        else:
+            return self.GetPaneByWidget(item)
+
+
+    def GetAllPanes(self):
+        """ Returns a reference to all the pane info structures. """
+        
+        return self._panes
+
+
+    def ShowPane(self, window, show):
+        """
+        Shows or hides a pane based on the window passed as input.
+
+        :param `window`: a `wx.Window` derived window;
+        :param `show`: ``True`` to show the pane, ``False`` otherwise.
+        """
+
+        p = self.GetPane(window)
+        
+        if p.IsOk():
+            if p.IsNotebookPage():
+                if show:
+                
+                    notebook = self._notebooks[p.notebook_id]
+                    id = notebook.GetPageIndex(p.window)
+                    if id >= 0:
+                        notebook.SetSelection(id)
+                    self.ShowPane(notebook, True)
+                
+            else:
+                p.Show(show)
+                
+            if p.frame:
+                p.frame.Raise()
+                
+            self.Update()
+
+            
+    def HitTest(self, x, y):
+        """
+        This is an internal function which determines
+        which UI item the specified coordinates are over.
+        
+        :param `x`: specifies a x position in client coordinates;
+        :param `y`: specifies a y position in client coordinates.
+        """
+
+        result = None
+
+        for item in self._uiparts:
+            # we are not interested in typeDock, because this space 
+            # isn't used to draw anything, just for measurements
+            # besides, the entire dock area is covered with other
+            # rectangles, which we are interested in.
+            if item.type == AuiDockUIPart.typeDock:
+                continue
+
+            # if we already have a hit on a more specific item, we are not
+            # interested in a pane hit.  If, however, we don't already have
+            # a hit, returning a pane hit is necessary for some operations
+            if item.type in [AuiDockUIPart.typePane, AuiDockUIPart.typePaneBorder] and result:
+                continue
+        
+            # if the point is inside the rectangle, we have a hit
+            if item.rect.Contains((x, y)):
+                result = item
+        
+        return result
+
+
+    def PaneHitTest(self, panes, pt):
+        """
+        Similar to L{HitTest}, but it checks in which L{AuiPaneInfo} rectangle the
+        input point belongs to.
+
+        :param `panes`: a list of L{AuiPaneInfo} instances;
+        :param `pt`: a `wx.Point` object.
+        """
+
+        for paneInfo in panes:
+            if paneInfo.IsDocked() and paneInfo.IsShown() and paneInfo.rect.Contains(pt):
+                return paneInfo
+
+        return NonePaneInfo
+
+
+    # SetAGWFlags() and GetAGWFlags() allow the owner to set various
+    # options which are global to AuiManager
+
+    def SetAGWFlags(self, agwFlags):
+        """
+        This method is used to specify L{AuiManager}'s settings flags.
+
+        :param `agwFlags`: specifies options which allow the frame management behavior
+         to be modified. `agwFlags` can be one of the following style bits:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_MGR_ALLOW_FLOATING``           Allow floating of panes
+         ``AUI_MGR_ALLOW_ACTIVE_PANE``        If a pane becomes active, "highlight" it in the interface
+         ``AUI_MGR_TRANSPARENT_DRAG``         If the platform supports it, set transparency on a floating pane while it is dragged by the user
+         ``AUI_MGR_TRANSPARENT_HINT``         If the platform supports it, show a transparent hint window when the user is about to dock a floating pane
+         ``AUI_MGR_VENETIAN_BLINDS_HINT``     Show a "venetian blind" effect when the user is about to dock a floating pane
+         ``AUI_MGR_RECTANGLE_HINT``           Show a rectangle hint effect when the user is about to dock a floating pane
+         ``AUI_MGR_HINT_FADE``                If the platform supports it, the hint window will fade in and out
+         ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``  Disables the "venetian blind" fade in and out
+         ``AUI_MGR_LIVE_RESIZE``              Live resize when the user drag a sash
+         ``AUI_MGR_ANIMATE_FRAMES``           Fade-out floating panes when they are closed (all platforms which support frames transparency) and show a moving rectangle when they are docked (Windows < Vista and GTK only)
+         ``AUI_MGR_AERO_DOCKING_GUIDES``      Use the new Aero-style bitmaps as docking guides
+         ``AUI_MGR_PREVIEW_MINIMIZED_PANES``  Slide in and out minimized panes to preview them
+         ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``   Use the new Whidbey-style bitmaps as docking guides        
+         ``AUI_MGR_SMOOTH_DOCKING``           Performs a "smooth" docking of panes (a la PyQT)
+         ``AUI_MGR_USE_NATIVE_MINIFRAMES``    Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMac)
+         ``AUI_MGR_AUTONB_NO_CAPTION``        Panes that merge into an automatic notebook will not have the pane caption visible
+         ==================================== ==================================
+
+         :note: If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a
+          floating pane caption will not re-dock the pane, but simply maximize it (if
+          L{AuiPaneInfo.MaximizeButton} has been set to ``True``) or do nothing.
+        
+        """
+        
+        self._agwFlags = agwFlags
+
+        if len(self._guides) > 0:
+            self.CreateGuideWindows()
+
+        if self._hint_window and agwFlags & AUI_MGR_RECTANGLE_HINT == 0:
+            self.CreateHintWindow()
+
+
+    def GetAGWFlags(self):
+        """
+        Returns the current manager's flags.
+
+        :see: L{SetAGWFlags} for a list of possible L{AuiManager} flags.
+        """
+        
+        return self._agwFlags
+        
+
+    def SetManagedWindow(self, managed_window):
+        """
+        Called to specify the frame or window which is to be managed by L{AuiManager}.
+        Frame management is not restricted to just frames. Child windows or custom
+        controls are also allowed.
+
+        :param `managed_window`: specifies the window which should be managed by
+         the AUI manager.
+        """
+
+        if not managed_window:
+            raise Exception("Specified managed window must be non-null. ")
+        
+        self._frame = managed_window
+        self._frame.PushEventHandler(self)
+
+        # if the owner is going to manage an MDI parent frame,
+        # we need to add the MDI client window as the default
+        # center pane
+
+        if isinstance(self._frame, wx.MDIParentFrame):
+            mdi_frame = self._frame
+            client_window = mdi_frame.GetClientWindow()
+
+            if not client_window:
+                raise Exception("Client window is None!")
+
+            self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
+                         CenterPane().PaneBorder(False))
+
+        elif isinstance(self._frame, tabmdi.AuiMDIParentFrame):
+
+            mdi_frame = self._frame
+            client_window = mdi_frame.GetClientWindow()
+
+            if not client_window:
+                raise Exception("Client window is None!")
+
+            self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
+                         CenterPane().PaneBorder(False))
+
+
+    def GetManagedWindow(self):
+        """ Returns the window being managed by L{AuiManager}. """
+        
+        return self._frame
+
+
+    def SetFrame(self, managed_window):
+        """
+        Called to specify the frame or window which is to be managed by L{AuiManager}.
+        Frame management is not restricted to just frames. Child windows or custom
+        controls are also allowed.
+
+        :param `managed_window`: specifies the window which should be managed by
+         the AUI manager.
+
+        :warning: This method is now deprecated, use L{SetManagedWindow} instead.
+        """
+
+        DeprecationWarning("This method is deprecated, use SetManagedWindow instead.")
+        return self.SetManagedWindow(managed_window)
+    
+        
+    def GetFrame(self):
+        """
+        Returns the window being managed by L{AuiManager}.
+
+        :warning: This method is now deprecated, use L{GetManagedWindow} instead.
+        """
+
+        DeprecationWarning("This method is deprecated, use GetManagedWindow instead.")        
+        return self._frame
+
+
+    def CreateGuideWindows(self):
+        """ Creates the VS2005 HUD guide windows. """
+
+        self.DestroyGuideWindows()
+
+        self._guides.append(AuiDockingGuideInfo().Left().
+                            Host(AuiSingleDockingGuide(self._frame, wx.LEFT)))
+        self._guides.append(AuiDockingGuideInfo().Top().
+                            Host(AuiSingleDockingGuide(self._frame, wx.TOP)))
+        self._guides.append(AuiDockingGuideInfo().Right().
+                            Host(AuiSingleDockingGuide(self._frame, wx.RIGHT)))
+        self._guides.append(AuiDockingGuideInfo().Bottom().
+                            Host(AuiSingleDockingGuide(self._frame, wx.BOTTOM)))
+        self._guides.append(AuiDockingGuideInfo().Centre().
+                            Host(AuiCenterDockingGuide(self._frame)))
+
+
+    def DestroyGuideWindows(self):
+        """ Destroys the VS2005 HUD guide windows. """
+
+        for guide in self._guides:
+            if guide.host:
+                guide.host.Destroy()
+        
+        self._guides = []
+    
+
+    def CreateHintWindow(self):
+        """ Creates the standard wxAUI hint window. """
+
+        self.DestroyHintWindow()
+
+        self._hint_window = AuiDockingHintWindow(self._frame)
+        self._hint_window.SetBlindMode(self._agwFlags)
+
+
+    def DestroyHintWindow(self):
+        """ Destroys the standard wxAUI hint window. """
+
+        if self._hint_window:
+
+            self._hint_window.Destroy()
+            self._hint_window = None
+
+
+    def UnInit(self):
+        """
+        Uninitializes the framework and should be called before a managed frame or
+        window is destroyed. L{UnInit} is usually called in the managed `wx.Frame`/`wx.Window`
+        destructor.
+
+        It is necessary to call this function before the managed frame or window is
+        destroyed, otherwise the manager cannot remove its custom event handlers
+        from a window.
+        """
+
+        if self._frame:
+            self._frame.RemoveEventHandler(self)
+
+
+    def GetArtProvider(self):
+        """ Returns the current art provider being used. """
+        
+        return self._art
+
+
+    def ProcessMgrEvent(self, event):
+        """
+        Process the AUI events sent to the manager.
+
+        :param `event`: the event to process, an instance of L{AuiManagerEvent}.
+        """
+
+        # first, give the owner frame a chance to override
+        if self._frame:
+            if self._frame.GetEventHandler().ProcessEvent(event):
+                return
+        
+        self.ProcessEvent(event)
+
+
+    def FireEvent(self, evtType, pane, canVeto=False):
+        """
+        Fires one of the ``EVT_AUI_PANE_FLOATED``/``FLOATING``/``DOCKING``/``DOCKED``/``ACTIVATED`` event. 
+
+        :param `evtType`: one of the aforementioned events;
+        :param `pane`: the L{AuiPaneInfo} instance associated to this event;
+        :param `canVeto`: whether the event can be vetoed or not.
+        """        
+
+        event = AuiManagerEvent(evtType)
+        event.SetPane(pane)
+        event.SetCanVeto(canVeto)
+        self.ProcessMgrEvent(event)
+
+        return event
+
+    
+    def CanUseModernDockArt(self):
+        """
+        Returns whether L{ModernDockArt} can be used (Windows XP / Vista / 7 only,
+        requires Mark Hammonds's `pywin32` package).
+        """
+
+        if not _winxptheme:
+            return False
+
+        # Get the size of a small close button (themed)
+        hwnd = self._frame.GetHandle()
+        hTheme = winxptheme.OpenThemeData(hwnd, "Window")
+
+        if not hTheme:
+            return False
+
+        return True
+            
+    
+    def SetArtProvider(self, art_provider):
+        """
+        Instructs L{AuiManager} to use art provider specified by the parameter
+        `art_provider` for all drawing calls. This allows plugable look-and-feel
+        features.
+
+        :param `art_provider`: a AUI dock art provider.
+
+        :note: The previous art provider object, if any, will be deleted by L{AuiManager}.
+        """
+
+        # delete the last art provider, if any
+        del self._art
+        
+        # assign the new art provider
+        self._art = art_provider
+
+        for pane in self.GetAllPanes():
+            if pane.IsFloating() and pane.frame:                
+                pane.frame._mgr.SetArtProvider(art_provider)
+                pane.frame._mgr.Update()
+
+
+    def AddPane(self, window, arg1=None, arg2=None, target=None):
+        """
+        Tells the frame manager to start managing a child window. There
+        are four versions of this function. The first verison allows the full spectrum
+        of pane parameter possibilities (L{AddPane1}). The second version is used for
+        simpler user interfaces which do not require as much configuration (L{AddPane2}).
+        The L{AddPane3} version allows a drop position to be specified, which will determine
+        where the pane will be added. The L{AddPane4} version allows to turn the target
+        L{AuiPaneInfo} pane into a notebook and the added pane into a page.
+
+        In wxPython, simply call L{AddPane}.
+
+        :param `window`: the child window to manage;
+        :param `arg1`: a L{AuiPaneInfo} or an integer value (direction);
+        :param `arg2`: a L{AuiPaneInfo} or a `wx.Point` (drop position);
+        :param `target`: a L{AuiPaneInfo} to be turned into a notebook
+         and new pane added to it as a page. (additionally, target can be any pane in 
+         an existing notebook)
+         """
+        if target in self._panes:
+            return self.AddPane4(window, arg1, target)
+
+        if type(arg1) == type(1):
+            # This Is Addpane2
+            if arg1 is None:
+                arg1 = wx.LEFT
+            if arg2 is None:
+                arg2 = ""
+            return self.AddPane2(window, arg1, arg2)
+        else:
+            if isinstance(arg2, wx.Point):
+                return self.AddPane3(window, arg1, arg2)
+            else:
+                return self.AddPane1(window, arg1)
+        
+
+    def AddPane1(self, window, pane_info):
+        """ See comments on L{AddPane}. """
+
+        # check if the pane has a valid window
+        if not window:
+            return False
+
+        # check if the pane already exists
+        if self.GetPane(pane_info.window).IsOk():
+            return False
+
+        # check if the pane name already exists, this could reveal a
+        # bug in the library user's application
+        already_exists = False
+        if pane_info.name != "" and self.GetPane(pane_info.name).IsOk():
+            warnings.warn("A pane with the name '%s' already exists in the manager!"%pane_info.name)
+            already_exists = True
+
+        # if the new pane is docked then we should undo maximize
+        if pane_info.IsDocked():
+            self.RestoreMaximizedPane()
+
+        self._panes.append(pane_info)
+        pinfo = self._panes[-1]
+
+        # set the pane window
+        pinfo.window = window
+
+        # if the pane's name identifier is blank, create a random string
+        if pinfo.name == "" or already_exists:
+            pinfo.name = ("%s%08x%08x%08x")%(pinfo.window.GetName(), time.time(),
+                                             time.clock(), len(self._panes))
+
+        # set initial proportion (if not already set)
+        if pinfo.dock_proportion == 0:
+            pinfo.dock_proportion = 100000
+
+        floating = isinstance(self._frame, AuiFloatingFrame)
+
+        pinfo.buttons = []
+
+        if not floating and pinfo.HasMinimizeButton():
+            button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
+            pinfo.buttons.append(button)
+    
+        if not floating and pinfo.HasMaximizeButton():
+            button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
+            pinfo.buttons.append(button)
+
+        if not floating and pinfo.HasPinButton():
+            button = AuiPaneButton(AUI_BUTTON_PIN)
+            pinfo.buttons.append(button)
+
+        if pinfo.HasCloseButton():
+            button = AuiPaneButton(AUI_BUTTON_CLOSE)
+            pinfo.buttons.append(button)
+
+        if pinfo.HasGripper():
+            if isinstance(pinfo.window, auibar.AuiToolBar):
+                # prevent duplicate gripper -- both AuiManager and AuiToolBar
+                # have a gripper control.  The toolbar's built-in gripper
+                # meshes better with the look and feel of the control than ours,
+                # so turn AuiManager's gripper off, and the toolbar's on.
+
+                tb = pinfo.window
+                pinfo.SetFlag(AuiPaneInfo.optionGripper, False)
+                tb.SetGripperVisible(True)
+
+        if pinfo.window:
+            if pinfo.best_size == wx.Size(-1, -1):
+                pinfo.best_size = pinfo.window.GetClientSize()
+
+            if isinstance(pinfo.window, wx.ToolBar):
+                # GetClientSize() doesn't get the best size for
+                # a toolbar under some newer versions of wxWidgets,
+                # so use GetBestSize()
+                pinfo.best_size = pinfo.window.GetBestSize()
+
+                # this is needed for Win2000 to correctly fill toolbar backround
+                # it should probably be repeated once system colour change happens
+                if wx.Platform == "__WXMSW__" and pinfo.window.UseBgCol():
+                    pinfo.window.SetBackgroundColour(self.GetArtProvider().GetColour(AUI_DOCKART_BACKGROUND_COLOUR))
+                
+            if pinfo.min_size != wx.Size(-1, -1):
+                if pinfo.best_size.x < pinfo.min_size.x:
+                    pinfo.best_size.x = pinfo.min_size.x
+                if pinfo.best_size.y < pinfo.min_size.y:
+                    pinfo.best_size.y = pinfo.min_size.y
+
+        self._panes[-1] = pinfo
+        if isinstance(window, auibar.AuiToolBar):
+            window.SetAuiManager(self)
+
+        return True
+
+
+    def AddPane2(self, window, direction, caption):
+        """ See comments on L{AddPane}. """
+        
+        pinfo = AuiPaneInfo()
+        pinfo.Caption(caption)
+        
+        if direction == wx.TOP:
+            pinfo.Top()
+        elif direction == wx.BOTTOM:
+            pinfo.Bottom()
+        elif direction == wx.LEFT:
+            pinfo.Left()
+        elif direction == wx.RIGHT:
+            pinfo.Right()
+        elif direction == wx.CENTER:
+            pinfo.CenterPane()
+        
+        return self.AddPane(window, pinfo)
+
+
+    def AddPane3(self, window, pane_info, drop_pos):
+        """ See comments on L{AddPane}. """
+        
+        if not self.AddPane(window, pane_info):
+            return False
+
+        pane = self.GetPane(window)
+        indx = self._panes.index(pane)
+
+        ret, pane = self.DoDrop(self._docks, self._panes, pane, drop_pos, wx.Point(0, 0))
+        self._panes[indx] = pane
+
+        return True
+
+
+    def AddPane4(self, window, pane_info, target):
+        """ See comments on L{AddPane}. """
+        
+        if not self.AddPane(window, pane_info):
+            return False
+               
+        paneInfo = self.GetPane(window)
+        
+        if not paneInfo.IsNotebookDockable():
+            return self.AddPane1(window, pane_info)
+        if not target.IsNotebookDockable() and not target.IsNotebookControl():
+            return self.AddPane1(window, pane_info)
+
+        if not target.HasNotebook():
+            self.CreateNotebookBase(self._panes, target)
+        
+        # Add new item to notebook
+        paneInfo.NotebookPage(target.notebook_id)
+
+        # we also want to remove our captions sometimes
+        self.RemoveAutoNBCaption(paneInfo)
+        self.UpdateNotebook()
+        
+        return True
+
+
+    def InsertPane(self, window, pane_info, insert_level=AUI_INSERT_PANE):
+        """
+        This method is used to insert either a previously unmanaged pane window
+        into the frame manager, or to insert a currently managed pane somewhere else.
+        L{InsertPane} will push all panes, rows, or docks aside and insert the window
+        into the position specified by `pane_info`.
+
+        Because `pane_info` can specify either a pane, dock row, or dock layer, the
+        `insert_level` parameter is used to disambiguate this. The parameter `insert_level`
+        can take a value of ``AUI_INSERT_PANE``, ``AUI_INSERT_ROW`` or ``AUI_INSERT_DOCK``.
+
+        :param `window`: the window to be inserted and managed;
+        :param `pane_info`: the insert location for the new window;
+        :param `insert_level`: the insertion level of the new pane.
+        """
+
+        if not window:
+            raise Exception("Invalid window passed to InsertPane.")
+                            
+        # shift the panes around, depending on the insert level
+        if insert_level == AUI_INSERT_PANE:
+            self._panes = DoInsertPane(self._panes, pane_info.dock_direction,
+                                       pane_info.dock_layer, pane_info.dock_row,
+                                       pane_info.dock_pos)
+
+        elif insert_level == AUI_INSERT_ROW:
+            self._panes = DoInsertDockRow(self._panes, pane_info.dock_direction,
+                                          pane_info.dock_layer, pane_info.dock_row)
+
+        elif insert_level == AUI_INSERT_DOCK:
+            self._panes = DoInsertDockLayer(self._panes, pane_info.dock_direction,
+                                            pane_info.dock_layer)
+        
+        # if the window already exists, we are basically just moving/inserting the
+        # existing window.  If it doesn't exist, we need to add it and insert it
+        existing_pane = self.GetPane(window)
+        indx = self._panes.index(existing_pane)
+        
+        if not existing_pane.IsOk():
+        
+            return self.AddPane(window, pane_info)
+        
+        else:
+        
+            if pane_info.IsFloating():
+                existing_pane.Float()
+                if pane_info.floating_pos != wx.Point(-1, -1):
+                    existing_pane.FloatingPosition(pane_info.floating_pos)
+                if pane_info.floating_size != wx.Size(-1, -1):
+                    existing_pane.FloatingSize(pane_info.floating_size)
+            else:
+                # if the new pane is docked then we should undo maximize
+                self.RestoreMaximizedPane()
+
+                existing_pane.Direction(pane_info.dock_direction)
+                existing_pane.Layer(pane_info.dock_layer)
+                existing_pane.Row(pane_info.dock_row)
+                existing_pane.Position(pane_info.dock_pos)
+
+            self._panes[indx] = existing_pane                
+            
+        return True
+
+    
+    def DetachPane(self, window):
+        """
+        Tells the L{AuiManager} to stop managing the pane specified
+        by `window`. The window, if in a floated frame, is reparented to the frame
+        managed by L{AuiManager}.
+
+        :param `window`: the window to be un-managed.
+        """
+        
+        for p in self._panes:
+            if p.window == window:
+                if p.frame:
+                    # we have a floating frame which is being detached. We need to
+                    # reparent it to self._frame and destroy the floating frame
+
+                    # reduce flicker
+                    p.window.SetSize((1, 1))
+                    if p.frame.IsShown():
+                        p.frame.Show(False)
+
+                    if self._action_window == p.frame:
+                        self._action_window = None
+                        
+                    # reparent to self._frame and destroy the pane
+                    p.window.Reparent(self._frame)
+                    p.frame.SetSizer(None)
+                    p.frame.Destroy()
+                    p.frame = None
+
+                elif p.IsNotebookPage():
+                    notebook = self._notebooks[p.notebook_id]
+                    id = notebook.GetPageIndex(p.window)
+                    notebook.RemovePage(id)
+                
+                # make sure there are no references to this pane in our uiparts,
+                # just in case the caller doesn't call Update() immediately after
+                # the DetachPane() call.  This prevets obscure crashes which would
+                # happen at window repaint if the caller forgets to call Update()
+                counter = 0
+                for pi in xrange(len(self._uiparts)):
+                    part = self._uiparts[counter]
+                    if part.pane == p:
+                        self._uiparts.pop(counter)
+                        counter -= 1
+
+                    counter += 1
+            
+                self._panes.remove(p)
+                return True
+        
+        return False
+
+
+    def ClosePane(self, pane_info):
+        """
+        Destroys or hides the pane depending on its flags.
+
+        :param `pane_info`: a L{AuiPaneInfo} instance.
+        """
+
+        # if we were maximized, restore
+        if pane_info.IsMaximized():
+            self.RestorePane(pane_info)
+
+        if pane_info.frame:
+            if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
+                pane_info.frame.FadeOut()
+
+        # first, hide the window
+        if pane_info.window and pane_info.window.IsShown():
+            pane_info.window.Show(False)
+
+        # make sure that we are the parent of this window
+        if pane_info.window and pane_info.window.GetParent() != self._frame:
+            pane_info.window.Reparent(self._frame)
+
+        # if we have a frame, destroy it
+        if pane_info.frame:
+            pane_info.frame.Destroy()
+            pane_info.frame = None
+            
+        elif pane_info.IsNotebookPage():
+            # if we are a notebook page, remove ourselves...
+            # the  code would index out of bounds 
+            # if the last page of a sub-notebook was closed
+            # because the notebook would be deleted, before this
+            # code is executed.
+            # This code just prevents an out-of bounds error.
+            if self._notebooks:
+                nid = pane_info.notebook_id
+                if nid >= 0 and nid < len(self._notebooks):
+                    notebook = self._notebooks[nid]
+                    page_idx = notebook.GetPageIndex(pane_info.window)
+                    if page_idx >= 0:
+                        notebook.RemovePage(page_idx)
+                                
+        # now we need to either destroy or hide the pane
+        to_destroy = 0
+        if pane_info.IsDestroyOnClose():
+            to_destroy = pane_info.window
+            self.DetachPane(to_destroy)
+        else:
+            if isinstance(pane_info.window, auibar.AuiToolBar) and pane_info.IsFloating():
+                tb = pane_info.window
+                if pane_info.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]:
+                    tb.SetAGWWindowStyleFlag(tb.GetAGWWindowStyleFlag() | AUI_TB_VERTICAL)
+                
+            pane_info.Dock().Hide()
+
+        if pane_info.IsNotebookControl():
+
+            notebook = self._notebooks[pane_info.notebook_id]
+            while notebook.GetPageCount():
+                window = notebook.GetPage(0)
+                notebook.RemovePage(0)
+                info = self.GetPane(window)
+                if info.IsOk():
+                    info.notebook_id = -1
+                    info.dock_direction = AUI_DOCK_NONE
+                    # Note: this could change our paneInfo reference ...
+                    self.ClosePane(info)
+
+        if to_destroy:
+            to_destroy.Destroy()
+
+
+    def MaximizePane(self, pane_info, savesizes=True):
+        """
+        Maximizes the input pane.
+
+        :param `pane_info`: a L{AuiPaneInfo} instance.
+        :param `savesizes`: whether to save previous dock sizes.
+        """
+
+        if savesizes:
+            self.SavePreviousDockSizes(pane_info)
+                
+        for p in self._panes:
+            
+            # save hidden state
+            p.SetFlag(p.savedHiddenState, p.HasFlag(p.optionHidden))
+
+            if not p.IsToolbar() and not p.IsFloating():
+                p.Restore()
+        
+                # hide the pane, because only the newly
+                # maximized pane should show
+                p.Hide()
+
+        pane_info.previousDockPos = pane_info.dock_pos
+
+        # mark ourselves maximized
+        pane_info.Maximize()
+        pane_info.Show()
+        self._has_maximized = True
+
+        # last, show the window
+        if pane_info.window and not pane_info.window.IsShown():
+            pane_info.window.Show(True)
+
+            
+    def SavePreviousDockSizes(self, pane_info):
+        """
+        Stores the previous dock sizes, to be used in a "restore" action later.
+
+        :param `pane_info`: a L{AuiPaneInfo} instance.
+        """
+
+        for d in self._docks:
+            if not d.toolbar:
+                for p in d.panes:
+                    p.previousDockSize = d.size
+                    if pane_info is not p:
+                        p.SetFlag(p.needsRestore, True)
+
+        
+    def RestorePane(self, pane_info):
+        """
+        Restores the input pane from a previous maximized or minimized state.
+
+        :param `pane_info`: a L{AuiPaneInfo} instance.
+        """
+        
+        # restore all the panes
+        for p in self._panes:
+            if not p.IsToolbar():
+                p.SetFlag(p.optionHidden, p.HasFlag(p.savedHiddenState))
+
+        pane_info.SetFlag(pane_info.needsRestore, True)
+
+        # mark ourselves non-maximized
+        pane_info.Restore()
+        self._has_maximized = False
+        self._has_minimized = False
+
+        # last, show the window
+        if pane_info.window and not pane_info.window.IsShown():
+            pane_info.window.Show(True)
+
+
+    def RestoreMaximizedPane(self):
+        """ Restores the current maximized pane (if any). """
+        
+        # restore all the panes
+        for p in self._panes:
+            if p.IsMaximized():
+                self.RestorePane(p)
+                break
+
+
+    def ActivatePane(self, window):
+        """
+        Activates the pane to which `window` is associated.
+
+        :param `window`: a `wx.Window` derived window.
+        """
+
+        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
+            while window:
+                ret, self._panes = SetActivePane(self._panes, window)
+                if ret:
+                    break
+
+                window = window.GetParent()
+
+            self.RefreshCaptions()
+            self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, window, canVeto=False)
+            
+
+    def CreateNotebook(self):
+        """
+        Creates an automatic L{AuiNotebook} when a pane is docked on
+        top of another pane.
+        """
+
+        notebook = auibook.AuiNotebook(self._frame, -1, wx.Point(0, 0), wx.Size(0, 0), agwStyle=self._autoNBStyle)
+
+        # This is so we can get the tab-drag event.
+        notebook.GetAuiManager().SetMasterManager(self)
+        notebook.SetArtProvider(self._autoNBTabArt.Clone())
+        self._notebooks.append(notebook)
+
+        return notebook
+
+
+    def SetAutoNotebookTabArt(self, art):
+        """
+        Sets the default tab art provider for automatic notebooks.
+
+        :param `art`: a tab art provider.
+        """
+
+        for nb in self._notebooks:
+            nb.SetArtProvider(art.Clone())
+            nb.Refresh()
+            nb.Update()
+
+        self._autoNBTabArt = art
+
+
+    def GetAutoNotebookTabArt(self):
+        """ Returns the default tab art provider for automatic notebooks. """
+
+        return self._autoNBTabArt        
+        
+
+    def SetAutoNotebookStyle(self, agwStyle):
+        """
+        Sets the default AGW-specific window style for automatic notebooks.
+
+        :param `agwStyle`: the underlying L{AuiNotebook} window style.
+         This can be a combination of the following bits:
+        
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by {AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ==================================== ==================================
+
+        """
+
+        for nb in self._notebooks:
+            nb.SetAGWWindowStyleFlag(agwStyle)
+            nb.Refresh()
+            nb.Update()
+
+        self._autoNBStyle = agwStyle
+
+
+    def GetAutoNotebookStyle(self):
+        """
+        Returns the default AGW-specific window style for automatic notebooks.
+
+        :see: L{SetAutoNotebookStyle} method for a list of possible styles.
+        """
+
+        return self._autoNBStyle
+
+
+    def SavePaneInfo(self, pane):
+        """
+        This method is similar to L{SavePerspective}, with the exception
+        that it only saves information about a single pane. It is used in
+        combination with L{LoadPaneInfo}.
+
+        :param `pane`: a L{AuiPaneInfo} instance to save.        
+        """
+
+        result = "name=" + EscapeDelimiters(pane.name) + ";"
+        result += "caption=" + EscapeDelimiters(pane.caption) + ";"
+
+        result += "state=%u;"%pane.state
+        result += "dir=%d;"%pane.dock_direction
+        result += "layer=%d;"%pane.dock_layer
+        result += "row=%d;"%pane.dock_row
+        result += "pos=%d;"%pane.dock_pos
+        result += "prop=%d;"%pane.dock_proportion
+        result += "bestw=%d;"%pane.best_size.x
+        result += "besth=%d;"%pane.best_size.y
+        result += "minw=%d;"%pane.min_size.x
+        result += "minh=%d;"%pane.min_size.y
+        result += "maxw=%d;"%pane.max_size.x
+        result += "maxh=%d;"%pane.max_size.y
+        result += "floatx=%d;"%pane.floating_pos.x
+        result += "floaty=%d;"%pane.floating_pos.y
+        result += "floatw=%d;"%pane.floating_size.x
+        result += "floath=%d;"%pane.floating_size.y
+        result += "notebookid=%d;"%pane.notebook_id
+        result += "transparent=%d"%pane.transparent
+
+        return result
+
+
+    def LoadPaneInfo(self, pane_part, pane):
+        """
+        This method is similar to to L{LoadPerspective}, with the exception that
+        it only loads information about a single pane. It is used in combination
+        with L{SavePaneInfo}.
+
+        :param `pane_part`: the string to analyze;
+        :param `pane`: the L{AuiPaneInfo} structure in which to load `pane_part`.
+        """
+
+        # replace escaped characters so we can
+        # split up the string easily
+        pane_part = pane_part.replace("\\|", "\a")
+        pane_part = pane_part.replace("\\;", "\b")
+
+        options = pane_part.split(";")
+        for items in options:
+
+            val_name, value = items.split("=")
+            val_name = val_name.strip()
+
+            if val_name == "name":
+                pane.name = value
+            elif val_name == "caption":
+                pane.caption = value
+            elif val_name == "state":
+                pane.state = int(value)
+            elif val_name == "dir":
+                pane.dock_direction = int(value)
+            elif val_name == "layer":
+                pane.dock_layer = int(value)
+            elif val_name == "row":
+                pane.dock_row = int(value)
+            elif val_name == "pos":
+                pane.dock_pos = int(value)
+            elif val_name == "prop":
+                pane.dock_proportion = int(value)
+            elif val_name == "bestw":
+                pane.best_size.x = int(value)
+            elif val_name == "besth":
+                pane.best_size.y = int(value)
+                pane.best_size = wx.Size(pane.best_size.x, pane.best_size.y)
+            elif val_name == "minw":
+                pane.min_size.x = int(value)
+            elif val_name == "minh":
+                pane.min_size.y = int(value)
+                pane.min_size = wx.Size(pane.min_size.x, pane.min_size.y)
+            elif val_name == "maxw":
+                pane.max_size.x = int(value)
+            elif val_name == "maxh":
+                pane.max_size.y = int(value)
+                pane.max_size = wx.Size(pane.max_size.x, pane.max_size.y)
+            elif val_name == "floatx":
+                pane.floating_pos.x = int(value)
+            elif val_name == "floaty":
+                pane.floating_pos.y = int(value)
+                pane.floating_pos = wx.Point(pane.floating_pos.x, pane.floating_pos.y)
+            elif val_name == "floatw":
+                pane.floating_size.x = int(value)
+            elif val_name == "floath":
+                pane.floating_size.y = int(value)
+                pane.floating_size = wx.Size(pane.floating_size.x, pane.floating_size.y)
+            elif val_name == "notebookid":
+                pane.notebook_id = int(value)
+            elif val_name == "transparent":
+                pane.transparent = int(value)
+            else:
+                raise Exception("Bad perspective string")
+
+        # replace escaped characters so we can
+        # split up the string easily
+        pane.name = pane.name.replace("\a", "|")
+        pane.name = pane.name.replace("\b", ";")
+        pane.caption = pane.caption.replace("\a", "|")
+        pane.caption = pane.caption.replace("\b", ";")
+        pane_part = pane_part.replace("\a", "|")
+        pane_part = pane_part.replace("\b", ";")
+
+        return pane
+    
+
+    def SavePerspective(self):
+        """
+        Saves the entire user interface layout into an encoded string, which can then
+        be stored by the application (probably using `wx.Config`).
+
+        When a perspective is restored using L{LoadPerspective}, the entire user
+        interface will return to the state it was when the perspective was saved.
+        """
+
+        result = "layout2|"
+
+        for pane in self._panes:
+            result += self.SavePaneInfo(pane) + "|"
+        
+        for dock in self._docks:
+            result = result + ("dock_size(%d,%d,%d)=%d|")%(dock.dock_direction,
+                                                           dock.dock_layer,
+                                                           dock.dock_row,
+                                                           dock.size)
+        return result
+
+
+    def LoadPerspective(self, layout, update=True):
+        """
+        Loads a layout which was saved with L{SavePerspective}.
+        
+        If the `update` flag parameter is ``True``, L{Update} will be
+        automatically invoked, thus realizing the saved perspective on screen.
+
+        :param `layout`: a string which contains a saved AUI layout;
+        :param `update`: whether to update immediately the window or not.
+        """
+
+        input = layout
+
+        # check layout string version
+        #    'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2
+        #    'layout2' = wxAUI 0.9.2 (wxWidgets 2.8)
+        index = input.find("|")
+        part = input[0:index].strip()
+        input = input[index+1:]
+        
+        if part != "layout2":
+            return False
+
+        # mark all panes currently managed as docked and hidden
+        for pane in self._panes:
+            pane.Dock().Hide()
+
+        # clear out the dock array; this will be reconstructed
+        self._docks = []
+
+        # replace escaped characters so we can
+        # split up the string easily
+        input = input.replace("\\|", "\a")
+        input = input.replace("\\;", "\b")
+
+        while 1:
+
+            pane = AuiPaneInfo()
+            index = input.find("|")
+            pane_part = input[0:index].strip()
+            input = input[index+1:]
+
+            # if the string is empty, we're done parsing
+            if pane_part == "":
+                break
+
+            if pane_part[0:9] == "dock_size":
+                index = pane_part.find("=")
+                val_name = pane_part[0:index]
+                value = pane_part[index+1:]
+
+                index = val_name.find("(")
+                piece = val_name[index+1:]
+                index = piece.find(")")
+                piece = piece[0:index]
+
+                vals = piece.split(",")
+                dir = int(vals[0])
+                layer = int(vals[1])
+                row = int(vals[2])
+                size = int(value)
+                
+                dock = AuiDockInfo()
+                dock.dock_direction = dir
+                dock.dock_layer = layer
+                dock.dock_row = row
+                dock.size = size
+                self._docks.append(dock)
+                
+                continue
+
+            # Undo our escaping as LoadPaneInfo needs to take an unescaped
+            # name so it can be called by external callers
+            pane_part = pane_part.replace("\a", "|")
+            pane_part = pane_part.replace("\b", ";")
+
+            pane = self.LoadPaneInfo(pane_part, pane)
+
+            p = self.GetPane(pane.name)
+                
+            if not p.IsOk():
+                if pane.IsNotebookControl():
+                    # notebook controls - auto add...
+                    self._panes.append(pane)
+                    indx = self._panes.index(pane)
+                else:
+                    # the pane window couldn't be found
+                    # in the existing layout -- skip it
+                    continue
+
+            else:
+                indx = self._panes.index(p)
+            pane.window = p.window
+            pane.frame = p.frame
+            pane.buttons = p.buttons
+            self._panes[indx] = pane
+
+            if isinstance(pane.window, auibar.AuiToolBar) and (pane.IsFloatable() or pane.IsDockable()):
+                pane.window.SetGripperVisible(True)
+            
+        if update:
+            self.Update()
+
+        return True
+
+
+    def GetPanePositionsAndSizes(self, dock):
+        """
+        Returns all the panes positions and sizes in a dock.
+
+        :param `dock`: a L{AuiDockInfo} instance.
+        """
+        
+        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
+        gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
+
+        positions = []
+        sizes = []
+
+        action_pane = -1
+        pane_count = len(dock.panes)
+
+        # find the pane marked as our action pane
+        for pane_i in xrange(pane_count):
+            pane = dock.panes[pane_i]
+            if pane.HasFlag(AuiPaneInfo.actionPane):
+                if action_pane != -1:
+                    raise Exception("Too many action panes!")
+                action_pane = pane_i
+            
+        # set up each panes default position, and
+        # determine the size (width or height, depending
+        # on the dock's orientation) of each pane
+        for pane in dock.panes:
+            positions.append(pane.dock_pos)
+            size = 0
+            
+            if pane.HasBorder():
+                size += pane_border_size*2
+                    
+            if dock.IsHorizontal():
+                if pane.HasGripper() and not pane.HasGripperTop():
+                    size += gripper_size
+
+                if pane.HasCaptionLeft():
+                    size += caption_size
+                    
+                size += pane.best_size.x
+                 
+            else:
+                if pane.HasGripper() and pane.HasGripperTop():
+                    size += gripper_size
+
+                if pane.HasCaption() and not pane.HasCaptionLeft():
+                    size += caption_size
+                    
+                size += pane.best_size.y
+       
+            sizes.append(size)
+
+        # if there is no action pane, just return the default
+        # positions (as specified in pane.pane_pos)
+        if action_pane == -1:
+            return positions, sizes
+
+        offset = 0
+        for pane_i in xrange(action_pane-1, -1, -1):
+            amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i])
+            if amount >= 0:
+                offset += amount
+            else:
+                positions[pane_i] -= -amount
+
+            offset += sizes[pane_i]
+        
+        # if the dock mode is fixed, make sure none of the panes
+        # overlap we will bump panes that overlap
+        offset = 0
+        for pane_i in xrange(action_pane, pane_count):
+            amount = positions[pane_i] - offset
+            if amount >= 0:
+                offset += amount
+            else:
+                positions[pane_i] += -amount
+
+            offset += sizes[pane_i]
+
+        return positions, sizes
+    
+
+    def LayoutAddPane(self, cont, dock, pane, uiparts, spacer_only):
+        """
+        Adds a pane into the existing layout (in an existing dock).
+
+        :param `cont`: a `wx.Sizer` object;
+        :param `dock`: the L{AuiDockInfo} structure in which to add the pane;
+        :param `pane`: the L{AuiPaneInfo} instance to add to the dock;
+        :param `uiparts`: a list of UI parts in the interface;
+        :param `spacer_only`: whether to add a simple spacer or a real window.
+        """
+        
+        sizer_item = wx.SizerItem()
+        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
+        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
+        pane_button_size = self._art.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE)
+
+        # find out the orientation of the item (orientation for panes
+        # is the same as the dock's orientation)
+
+        if dock.IsHorizontal():
+            orientation = wx.HORIZONTAL
+        else:
+            orientation = wx.VERTICAL
+
+        # this variable will store the proportion
+        # value that the pane will receive
+        pane_proportion = pane.dock_proportion
+
+        horz_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
+        vert_pane_sizer = wx.BoxSizer(wx.VERTICAL)
+
+        if pane.HasGripper():
+            
+            part = AuiDockUIPart()
+            if pane.HasGripperTop():
+                sizer_item = vert_pane_sizer.Add((1, gripper_size), 0, wx.EXPAND)
+            else:
+                sizer_item = horz_pane_sizer.Add((gripper_size, 1), 0, wx.EXPAND)
+
+            part.type = AuiDockUIPart.typeGripper
+            part.dock = dock
+            part.pane = pane
+            part.button = None
+            part.orientation = orientation
+            part.cont_sizer = horz_pane_sizer
+            part.sizer_item = sizer_item
+            uiparts.append(part)
+
+        button_count = len(pane.buttons)
+        button_width_total = button_count*pane_button_size
+        if button_count >= 1:
+            button_width_total += 3
+
+        caption, captionLeft = pane.HasCaption(), pane.HasCaptionLeft()
+        button_count = len(pane.buttons)
+
+        if captionLeft:
+            caption_sizer = wx.BoxSizer(wx.VERTICAL)
+
+            # add pane buttons to the caption
+            dummy_parts = []
+            for btn_id in xrange(len(pane.buttons)-1, -1, -1):
+                sizer_item = caption_sizer.Add((caption_size, pane_button_size), 0, wx.EXPAND)
+                part = AuiDockUIPart()
+                part.type = AuiDockUIPart.typePaneButton
+                part.dock = dock
+                part.pane = pane
+                part.button = pane.buttons[btn_id]
+                part.orientation = orientation
+                part.cont_sizer = caption_sizer
+                part.sizer_item = sizer_item
+                dummy_parts.append(part)
+            
+            sizer_item = caption_sizer.Add((caption_size, 1), 1, wx.EXPAND)
+            vert_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+            # create the caption sizer
+            part = AuiDockUIPart()
+
+            part.type = AuiDockUIPart.typeCaption
+            part.dock = dock
+            part.pane = pane
+            part.button = None
+            part.orientation = orientation
+            part.cont_sizer = vert_pane_sizer
+            part.sizer_item = sizer_item
+            caption_part_idx = len(uiparts)
+            uiparts.append(part)
+            uiparts.extend(dummy_parts)
+
+        elif caption:
+
+            caption_sizer = wx.BoxSizer(wx.HORIZONTAL)
+            sizer_item = caption_sizer.Add((1, caption_size), 1, wx.EXPAND)
+
+            # create the caption sizer
+            part = AuiDockUIPart()
+
+            part.type = AuiDockUIPart.typeCaption
+            part.dock = dock
+            part.pane = pane
+            part.button = None
+            part.orientation = orientation
+            part.cont_sizer = vert_pane_sizer
+            part.sizer_item = sizer_item
+            caption_part_idx = len(uiparts)
+            uiparts.append(part)
+
+            # add pane buttons to the caption
+            for button in pane.buttons:
+                sizer_item = caption_sizer.Add((pane_button_size, caption_size), 0, wx.EXPAND)                        
+                part = AuiDockUIPart()
+                part.type = AuiDockUIPart.typePaneButton
+                part.dock = dock
+                part.pane = pane
+                part.button = button
+                part.orientation = orientation
+                part.cont_sizer = caption_sizer
+                part.sizer_item = sizer_item
+                uiparts.append(part)
+
+        if caption or captionLeft:
+            # if we have buttons, add a little space to the right
+            # of them to ease visual crowding
+            if button_count >= 1:
+                if captionLeft:
+                    caption_sizer.Add((caption_size, 3), 0, wx.EXPAND)
+                else:
+                    caption_sizer.Add((3, caption_size), 0, wx.EXPAND)
+
+            # add the caption sizer
+            sizer_item = vert_pane_sizer.Add(caption_sizer, 0, wx.EXPAND)
+            uiparts[caption_part_idx].sizer_item = sizer_item
+                    
+        # add the pane window itself
+        if spacer_only or not pane.window:
+            sizer_item = vert_pane_sizer.Add((1, 1), 1, wx.EXPAND)
+        else:
+            sizer_item = vert_pane_sizer.Add(pane.window, 1, wx.EXPAND)
+            vert_pane_sizer.SetItemMinSize(pane.window, (1, 1))
+
+        part = AuiDockUIPart()        
+        part.type = AuiDockUIPart.typePane
+        part.dock = dock
+        part.pane = pane
+        part.button = None
+        part.orientation = orientation
+        part.cont_sizer = vert_pane_sizer
+        part.sizer_item = sizer_item
+        uiparts.append(part)
+
+        # determine if the pane should have a minimum size if the pane is
+        # non-resizable (fixed) then we must set a minimum size. Alternatively,
+        # if the pane.min_size is set, we must use that value as well
+        
+        min_size = pane.min_size
+        if pane.IsFixed():
+            if min_size == wx.Size(-1, -1):
+                min_size = pane.best_size
+                pane_proportion = 0
+
+        if min_size != wx.Size(-1, -1):
+            vert_pane_sizer.SetItemMinSize(len(vert_pane_sizer.GetChildren())-1, (min_size.x, min_size.y))
+        
+        # add the vertical/horizontal sizer (caption, pane window) to the
+        # horizontal sizer (gripper, vertical sizer)
+        horz_pane_sizer.Add(vert_pane_sizer, 1, wx.EXPAND)
+
+        # finally, add the pane sizer to the dock sizer
+        if pane.HasBorder():
+            # allowing space for the pane's border
+            sizer_item = cont.Add(horz_pane_sizer, pane_proportion,
+                                  wx.EXPAND | wx.ALL, pane_border_size)
+            part = AuiDockUIPart()
+            part.type = AuiDockUIPart.typePaneBorder
+            part.dock = dock
+            part.pane = pane
+            part.button = None
+            part.orientation = orientation
+            part.cont_sizer = cont
+            part.sizer_item = sizer_item
+            uiparts.append(part)
+        else:
+            sizer_item = cont.Add(horz_pane_sizer, pane_proportion, wx.EXPAND)
+        
+        return uiparts
+        
+        
+    def LayoutAddDock(self, cont, dock, uiparts, spacer_only):
+        """
+        Adds a dock into the existing layout.
+
+        :param `cont`: a `wx.Sizer` object;
+        :param `dock`: the L{AuiDockInfo} structure to add to the layout;
+        :param `uiparts`: a list of UI parts in the interface;
+        :param `spacer_only`: whether to add a simple spacer or a real window.
+        """
+        
+        sizer_item = wx.SizerItem()
+        part = AuiDockUIPart()
+
+        sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+        orientation = (dock.IsHorizontal() and [wx.HORIZONTAL] or [wx.VERTICAL])[0]
+
+        # resizable bottom and right docks have a sash before them
+        if not self._has_maximized and not dock.fixed and \
+           dock.dock_direction in [AUI_DOCK_BOTTOM, AUI_DOCK_RIGHT]:
+        
+            sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
+
+            part.type = AuiDockUIPart.typeDockSizer
+            part.orientation = orientation
+            part.dock = dock
+            part.pane = None
+            part.button = None
+            part.cont_sizer = cont
+            part.sizer_item = sizer_item
+            uiparts.append(part)
+        
+        # create the sizer for the dock
+        dock_sizer = wx.BoxSizer(orientation)
+
+        # add each pane to the dock
+        has_maximized_pane = False
+        pane_count = len(dock.panes)
+
+        if dock.fixed:
+        
+            # figure out the real pane positions we will
+            # use, without modifying the each pane's pane_pos member
+            pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
+
+            offset = 0
+            for pane_i in xrange(pane_count):
+            
+                pane = dock.panes[pane_i]
+                pane_pos = pane_positions[pane_i]
+
+                if pane.IsMaximized():
+                    has_maximized_pane = True
+
+                amount = pane_pos - offset
+                if amount > 0:
+                
+                    if dock.IsVertical():
+                        sizer_item = dock_sizer.Add((1, amount), 0, wx.EXPAND)
+                    else:
+                        sizer_item = dock_sizer.Add((amount, 1), 0, wx.EXPAND)
+
+                    part = AuiDockUIPart()
+                    part.type = AuiDockUIPart.typeBackground
+                    part.dock = dock
+                    part.pane = None
+                    part.button = None
+                    part.orientation = (orientation==wx.HORIZONTAL and \
+                                        [wx.VERTICAL] or [wx.HORIZONTAL])[0]
+                    part.cont_sizer = dock_sizer
+                    part.sizer_item = sizer_item
+                    uiparts.append(part)
+
+                    offset = offset + amount
+                
+                uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
+
+                offset = offset + pane_sizes[pane_i]
+            
+            # at the end add a very small stretchable background area
+            sizer_item = dock_sizer.Add((0, 0), 1, wx.EXPAND)
+            part = AuiDockUIPart()
+            part.type = AuiDockUIPart.typeBackground
+            part.dock = dock
+            part.pane = None
+            part.button = None
+            part.orientation = orientation
+            part.cont_sizer = dock_sizer
+            part.sizer_item = sizer_item
+            uiparts.append(part)
+        
+        else:
+        
+            for pane_i in xrange(pane_count):
+            
+                pane = dock.panes[pane_i]
+
+                if pane.IsMaximized():
+                    has_maximized_pane = True
+
+                # if this is not the first pane being added,
+                # we need to add a pane sizer
+                if not self._has_maximized and pane_i > 0:
+                    sizer_item = dock_sizer.Add((sash_size, sash_size), 0, wx.EXPAND)
+                    part = AuiDockUIPart()
+                    part.type = AuiDockUIPart.typePaneSizer
+                    part.dock = dock
+                    part.pane = dock.panes[pane_i-1]
+                    part.button = None
+                    part.orientation = (orientation==wx.HORIZONTAL and \
+                                        [wx.VERTICAL] or [wx.HORIZONTAL])[0]
+                    part.cont_sizer = dock_sizer
+                    part.sizer_item = sizer_item
+                    uiparts.append(part)
+                
+                uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
+            
+        if dock.dock_direction == AUI_DOCK_CENTER or has_maximized_pane:
+            sizer_item = cont.Add(dock_sizer, 1, wx.EXPAND)
+        else:
+            sizer_item = cont.Add(dock_sizer, 0, wx.EXPAND)
+
+        part = AuiDockUIPart()
+        part.type = AuiDockUIPart.typeDock
+        part.dock = dock
+        part.pane = None
+        part.button = None
+        part.orientation = orientation
+        part.cont_sizer = cont
+        part.sizer_item = sizer_item
+        uiparts.append(part)
+
+        if dock.IsHorizontal():
+            cont.SetItemMinSize(dock_sizer, (0, dock.size))
+        else:
+            cont.SetItemMinSize(dock_sizer, (dock.size, 0))
+
+        #  top and left docks have a sash after them
+        if not self._has_maximized and not dock.fixed and \
+           dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
+        
+            sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
+
+            part = AuiDockUIPart()
+            part.type = AuiDockUIPart.typeDockSizer
+            part.dock = dock
+            part.pane = None
+            part.button = None
+            part.orientation = orientation
+            part.cont_sizer = cont
+            part.sizer_item = sizer_item
+            uiparts.append(part)
+        
+        return uiparts
+    
+
+    def LayoutAll(self, panes, docks, uiparts, spacer_only=False, oncheck=True):
+        """
+        Layouts all the UI structures in the interface.
+
+        :param `panes`: a list of L{AuiPaneInfo} instances;
+        :param `docks`: a list of L{AuiDockInfo} classes;
+        :param `uiparts`: a list of UI parts in the interface;
+        :param `spacer_only`: whether to add a simple spacer or a real window;
+        :param `oncheck`: whether to store the results in a class member or not.
+        """
+        
+        container = wx.BoxSizer(wx.VERTICAL)
+
+        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
+        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        cli_size = self._frame.GetClientSize()
+        
+        # empty all docks out
+        for dock in docks:
+            dock.panes = []
+            if dock.fixed:
+                # always reset fixed docks' sizes, because
+                # the contained windows may have been resized
+                dock.size = 0
+            
+        dock_count = len(docks)
+        
+        # iterate through all known panes, filing each
+        # of them into the appropriate dock. If the
+        # pane does not exist in the dock, add it
+        for p in panes:
+
+            # don't layout hidden panes.
+            if p.IsShown():
+                
+                # find any docks with the same dock direction, dock layer, and
+                # dock row as the pane we are working on
+                arr = FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row)
+
+                if arr:
+                    dock = arr[0]
+
+                else:
+                    # dock was not found, so we need to create a new one
+                    d = AuiDockInfo()
+                    d.dock_direction = p.dock_direction
+                    d.dock_layer = p.dock_layer
+                    d.dock_row = p.dock_row
+                    docks.append(d)
+                    dock = docks[-1]
+
+                    if p.HasFlag(p.needsRestore) and not p.HasFlag(p.wasMaximized):
+                   
+                        isHor = dock.IsHorizontal()
+                        sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+
+                        # get the sizes of any docks that might 
+                        # overlap with our restored dock
+
+                        # make list of widths or heights from the size in the dock rects
+                        sizes = [d.rect[2:][isHor] for \
+                                 d in docks if d.IsOk() and \
+                                 (d.IsHorizontal() == isHor) and \
+                                 not d.toolbar and \
+                                 d.dock_direction != AUI_DOCK_CENTER]
+                        
+                        frameRect = GetInternalFrameRect(self._frame, self._docks)
+
+                        # set max size allowing for sashes and absolute minimum
+                        maxsize = frameRect[2:][isHor] - sum(sizes) - (len(sizes)*10) - (sashSize*len(sizes))
+                        dock.size = min(p.previousDockSize,maxsize)
+
+                    else:
+                        dock.size = 0
+
+                if p.HasFlag(p.wasMaximized):
+                    self.MaximizePane(p, savesizes=False)
+                    p.SetFlag(p.wasMaximized, False)
+
+                if p.HasFlag(p.needsRestore):
+                    if p.previousDockPos is not None:
+                        DoInsertPane(dock.panes, dock.dock_direction, dock.dock_layer, dock.dock_row, p.previousDockPos)
+                        p.dock_pos = p.previousDockPos
+                        p.previousDockPos = None
+                    p.SetFlag(p.needsRestore, False)
+
+                if p.IsDocked():
+                    # remove the pane from any existing docks except this one
+                    docks = RemovePaneFromDocks(docks, p, dock)
+
+                    # pane needs to be added to the dock,
+                    # if it doesn't already exist 
+                    if not FindPaneInDock(dock, p.window):
+                        dock.panes.append(p)
+                else:
+                    # remove the pane from any existing docks
+                    docks = RemovePaneFromDocks(docks, p)
+                
+        # remove any empty docks
+        docks = [dock for dock in docks if dock.panes]
+
+        dock_count = len(docks)
+        # configure the docks further
+        for ii, dock in enumerate(docks):
+            # sort the dock pane array by the pane's
+            # dock position (dock_pos), in ascending order
+            dock.panes.sort(PaneSortFunc)
+            dock_pane_count = len(dock.panes)
+            
+            # for newly created docks, set up their initial size
+            if dock.size == 0:
+                size = 0
+                for pane in dock.panes:
+                    pane_size = pane.best_size
+                    if pane_size == wx.Size(-1, -1):
+                        pane_size = pane.min_size
+                    if pane_size == wx.Size(-1, -1) and pane.window:
+                        pane_size = pane.window.GetSize()
+                    if dock.IsHorizontal():
+                        size = max(pane_size.y, size)
+                    else:
+                        size = max(pane_size.x, size)
+                
+                # add space for the border (two times), but only
+                # if at least one pane inside the dock has a pane border
+                for pane in dock.panes:
+                    if pane.HasBorder():
+                        size = size + pane_border_size*2
+                        break
+                    
+                # if pane is on the top or bottom, add the caption height,
+                # but only if at least one pane inside the dock has a caption
+                if dock.IsHorizontal():
+                    for pane in dock.panes:
+                        if pane.HasCaption() and not pane.HasCaptionLeft():
+                            size = size + caption_size
+                            break
+                else:
+                    for pane in dock.panes:
+                        if pane.HasCaptionLeft() and not pane.HasCaption():
+                            size = size + caption_size
+                            break
+                    
+                # new dock's size may not be more than the dock constraint
+                # parameter specifies.  See SetDockSizeConstraint()
+                max_dock_x_size = int(self._dock_constraint_x*float(cli_size.x))
+                max_dock_y_size = int(self._dock_constraint_y*float(cli_size.y))
+                if cli_size <= wx.Size(20, 20):
+                    max_dock_x_size = 10000
+                    max_dock_y_size = 10000
+
+                if dock.IsHorizontal():
+                    size = min(size, max_dock_y_size)
+                else:
+                    size = min(size, max_dock_x_size)
+
+                # absolute minimum size for a dock is 10 pixels
+                if size < 10:
+                    size = 10
+
+                dock.size = size
+
+            # determine the dock's minimum size
+            plus_border = False
+            plus_caption = False
+            plus_caption_left = False
+            dock_min_size = 0
+            for pane in dock.panes:
+                if pane.min_size != wx.Size(-1, -1):
+                    if pane.HasBorder():
+                        plus_border = True
+                    if pane.HasCaption():
+                        plus_caption = True
+                    if pane.HasCaptionLeft():
+                        plus_caption_left = True
+                    if dock.IsHorizontal():
+                        if pane.min_size.y > dock_min_size:
+                            dock_min_size = pane.min_size.y
+                    else:
+                        if pane.min_size.x > dock_min_size:
+                            dock_min_size = pane.min_size.x
+                    
+            if plus_border:
+                dock_min_size += pane_border_size*2
+            if plus_caption and dock.IsHorizontal():
+                dock_min_size += caption_size
+            if plus_caption_left and dock.IsVertical():
+                dock_min_size += caption_size
+               
+            dock.min_size = dock_min_size
+            
+            # if the pane's current size is less than it's
+            # minimum, increase the dock's size to it's minimum
+            if dock.size < dock.min_size:
+                dock.size = dock.min_size
+
+            # determine the dock's mode (fixed or proportional)
+            # determine whether the dock has only toolbars
+            action_pane_marked = False
+            dock.fixed = True
+            dock.toolbar = True
+            for pane in dock.panes:
+                if not pane.IsFixed():
+                    dock.fixed = False
+                if not pane.IsToolbar():
+                    dock.toolbar = False
+                if pane.HasFlag(AuiPaneInfo.optionDockFixed):
+                    dock.fixed = True
+                if pane.HasFlag(AuiPaneInfo.actionPane):
+                    action_pane_marked = True
+
+            # if the dock mode is proportional and not fixed-pixel,
+            # reassign the dock_pos to the sequential 0, 1, 2, 3
+            # e.g. remove gaps like 1, 2, 30, 500
+            if not dock.fixed:
+                for jj in xrange(dock_pane_count):
+                    pane = dock.panes[jj]
+                    pane.dock_pos = jj
+                
+            # if the dock mode is fixed, and none of the panes
+            # are being moved right now, make sure the panes
+            # do not overlap each other.  If they do, we will
+            # adjust the panes' positions
+            if dock.fixed and not action_pane_marked:
+                pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
+                offset = 0
+                for jj in xrange(dock_pane_count):
+                    pane = dock.panes[jj]
+                    pane.dock_pos = pane_positions[jj]
+                    amount = pane.dock_pos - offset
+                    if amount >= 0:
+                        offset += amount
+                    else:
+                        pane.dock_pos += -amount
+
+                    offset += pane_sizes[jj]
+                    dock.panes[jj] = pane
+
+            if oncheck:
+                self._docks[ii] = dock                    
+
+        # shrink docks if needed 
+##        docks = self.SmartShrink(docks, AUI_DOCK_TOP)
+##        docks = self.SmartShrink(docks, AUI_DOCK_LEFT)
+
+        if oncheck:
+            self._docks = docks
+            
+        # discover the maximum dock layer
+        max_layer = 0
+        dock_count = len(docks)
+        
+        for ii in xrange(dock_count):
+            max_layer = max(max_layer, docks[ii].dock_layer)
+
+        # clear out uiparts
+        uiparts = []
+
+        # create a bunch of box sizers,
+        # from the innermost level outwards.
+        cont = None
+        middle = None
+
+        if oncheck:
+            docks = self._docks
+        
+        for layer in xrange(max_layer+1):
+            # find any docks in this layer
+            arr = FindDocks(docks, -1, layer, -1)
+            # if there aren't any, skip to the next layer
+            if not arr:
+                continue
+
+            old_cont = cont
+
+            # create a container which will hold this layer's
+            # docks (top, bottom, left, right)
+            cont = wx.BoxSizer(wx.VERTICAL)
+
+            # find any top docks in this layer
+            arr = FindDocks(docks, AUI_DOCK_TOP, layer, -1)
+            for row in arr:
+                uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
+            
+            # fill out the middle layer (which consists
+            # of left docks, content area and right docks)
+            
+            middle = wx.BoxSizer(wx.HORIZONTAL)
+
+            # find any left docks in this layer
+            arr = FindDocks(docks, AUI_DOCK_LEFT, layer, -1)
+            for row in arr:
+                uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
+            
+            # add content dock (or previous layer's sizer
+            # to the middle
+            if not old_cont:
+                # find any center docks
+                arr = FindDocks(docks, AUI_DOCK_CENTER, -1, -1)
+                if arr:
+                    for row in arr:
+                       uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
+                       
+                elif not self._has_maximized:
+                    # there are no center docks, add a background area
+                    sizer_item = middle.Add((1, 1), 1, wx.EXPAND)
+                    part = AuiDockUIPart()
+                    part.type = AuiDockUIPart.typeBackground
+                    part.pane = None
+                    part.dock = None
+                    part.button = None
+                    part.cont_sizer = middle
+                    part.sizer_item = sizer_item
+                    uiparts.append(part)
+            else:
+                middle.Add(old_cont, 1, wx.EXPAND)
+            
+            # find any right docks in this layer
+            arr = FindDocks(docks, AUI_DOCK_RIGHT, layer, -1, reverse=True)
+            for row in arr:
+                uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
+                    
+            if len(middle.GetChildren()) > 0:
+                cont.Add(middle, 1, wx.EXPAND)
+
+            # find any bottom docks in this layer
+            arr = FindDocks(docks, AUI_DOCK_BOTTOM, layer, -1, reverse=True)
+            for row in arr:
+                    uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
+
+        if not cont:
+            # no sizer available, because there are no docks,
+            # therefore we will create a simple background area
+            cont = wx.BoxSizer(wx.VERTICAL)
+            sizer_item = cont.Add((1, 1), 1, wx.EXPAND)
+            part = AuiDockUIPart()
+            part.type = AuiDockUIPart.typeBackground
+            part.pane = None
+            part.dock = None
+            part.button = None
+            part.cont_sizer = middle
+            part.sizer_item = sizer_item
+            uiparts.append(part)
+
+        if oncheck:
+            self._uiparts = uiparts
+            self._docks = docks
+
+        container.Add(cont, 1, wx.EXPAND)
+
+        if oncheck:
+            return container
+        else:
+            return container, panes, docks, uiparts
+
+
+    def SetDockSizeConstraint(self, width_pct, height_pct):
+        """
+        When a user creates a new dock by dragging a window into a docked position,
+        often times the large size of the window will create a dock that is unwieldly
+        large.
+
+        L{AuiManager} by default limits the size of any new dock to 1/3 of the window
+        size. For horizontal docks, this would be 1/3 of the window height. For vertical
+        docks, 1/3 of the width. Calling this function will adjust this constraint value.
+
+        The numbers must be between 0.0 and 1.0. For instance, calling L{SetDockSizeConstraint}
+        with (0.5, 0.5) will cause new docks to be limited to half of the size of the entire
+        managed window.
+
+        :param `width_pct`: a float number representing the x dock size constraint;
+        :param `width_pct`: a float number representing the y dock size constraint.
+        """
+
+        self._dock_constraint_x = max(0.0, min(1.0, width_pct))
+        self._dock_constraint_y = max(0.0, min(1.0, height_pct))
+
+
+    def GetDockSizeConstraint(self):
+        """
+        Returns the current dock constraint values.
+
+        :see: L{SetDockSizeConstraint}
+        """
+
+        return self._dock_constraint_x, self._dock_constraint_y
+
+
+    def Update(self):
+        """
+        This method is called after any number of changes are made to any of the
+        managed panes. L{Update} must be invoked after L{AddPane} or L{InsertPane} are
+        called in order to "realize" or "commit" the changes.
+
+        In addition, any number of changes may be made to L{AuiPaneInfo} structures
+        (retrieved with L{GetPane}), but to realize the changes, L{Update}
+        must be called. This construction allows pane flicker to be avoided by updating
+        the whole layout at one time.
+        """
+
+        self._hover_button = None
+        self._action_part = None
+        
+        # destroy floating panes which have been
+        # redocked or are becoming non-floating
+        for p in self._panes:
+            if p.IsFloating() or not p.frame:
+                continue
+            
+            # because the pane is no longer in a floating, we need to
+            # reparent it to self._frame and destroy the floating frame
+            # reduce flicker
+            p.window.SetSize((1, 1))
+
+            # the following block is a workaround for bug #1531361
+            # (see wxWidgets sourceforge page).  On wxGTK (only), when
+            # a frame is shown/hidden, a move event unfortunately
+            # also gets fired.  Because we may be dragging around
+            # a pane, we need to cancel that action here to prevent
+            # a spurious crash.
+            if self._action_window == p.frame:
+                if self._frame.HasCapture():
+                    self._frame.ReleaseMouse()
+                self._action = actionNone
+                self._action_window = None
+
+            # hide the frame
+            if p.frame.IsShown():
+                p.frame.Show(False)
+
+            if self._action_window == p.frame:
+                self._action_window = None
+        
+            # reparent to self._frame and destroy the pane
+            p.window.Reparent(self._frame)
+            if isinstance(p.window, auibar.AuiToolBar):
+                p.window.SetAuiManager(self)
+
+            if p.frame:
+                p.frame.SetSizer(None)
+                p.frame.Destroy()
+            p.frame = None
+
+        # Only the master manager should create/destroy notebooks...
+        if not self._masterManager:
+            self.UpdateNotebook()
+        
+        # delete old sizer first
+        self._frame.SetSizer(None)
+
+        # create a layout for all of the panes
+        sizer = self.LayoutAll(self._panes, self._docks, self._uiparts, False)
+
+        # hide or show panes as necessary,
+        # and float panes as necessary
+        
+        pane_count = len(self._panes)
+        
+        for ii in xrange(pane_count):
+            p = self._panes[ii]
+            pFrame = p.frame
+
+            if p.IsFloating():
+                if pFrame is None:
+                    # we need to create a frame for this
+                    # pane, which has recently been floated
+                    frame = self.CreateFloatingFrame(self._frame, p)
+
+                    # on MSW and Mac, if the owner desires transparent dragging, and
+                    # the dragging is happening right now, then the floating
+                    # window should have this style by default
+                    if self._action in [actionDragFloatingPane, actionDragToolbarPane] and \
+                       self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
+                        frame.SetTransparent(150)
+
+                    if p.IsToolbar():
+                        bar = p.window
+                        if isinstance(bar, auibar.AuiToolBar):
+                            bar.SetGripperVisible(False)
+                            agwStyle = bar.GetAGWWindowStyleFlag()
+                            bar.SetAGWWindowStyleFlag(agwStyle & ~AUI_TB_VERTICAL)
+                            bar.Realize()
+
+                        s = p.window.GetMinSize()
+                        p.BestSize(s)
+                        p.FloatingSize(wx.DefaultSize)
+
+                    frame.SetPaneWindow(p)
+                    p.needsTransparency = True
+                    p.frame = pFrame = frame
+                    if p.IsShown() and not frame.IsShown():
+                        frame.Show()
+                        frame.Update()
+                else:
+
+                    # frame already exists, make sure it's position
+                    # and size reflect the information in AuiPaneInfo
+                    if pFrame.GetPosition() != p.floating_pos or pFrame.GetSize() != p.floating_size:
+                        pFrame.SetDimensions(p.floating_pos.x, p.floating_pos.y,
+                                             p.floating_size.x, p.floating_size.y, wx.SIZE_USE_EXISTING)
+
+                    # update whether the pane is resizable or not
+                    style = p.frame.GetWindowStyleFlag()
+                    if p.IsFixed():
+                        style &= ~wx.RESIZE_BORDER
+                    else:
+                        style |= wx.RESIZE_BORDER
+
+                    p.frame.SetWindowStyleFlag(style)
+
+                    if pFrame.IsShown() != p.IsShown():
+                        p.needsTransparency = True
+                        pFrame.Show(p.IsShown())
+
+                if pFrame.GetTitle() != p.caption:
+                    pFrame.SetTitle(p.caption)
+                if p.icon.IsOk():
+                    pFrame.SetIcon(wx.IconFromBitmap(p.icon))
+                    
+            else:
+
+                if p.IsToolbar():
+#                    self.SwitchToolBarOrientation(p)
+                    p.best_size = p.window.GetBestSize()
+
+                if p.window and not p.IsNotebookPage() and p.window.IsShown() != p.IsShown():
+                    p.window.Show(p.IsShown())
+
+            if pFrame and p.needsTransparency:
+                if pFrame.IsShown() and pFrame._transparent != p.transparent:
+                    pFrame.SetTransparent(p.transparent)
+                    pFrame._transparent = p.transparent
+                    
+                p.needsTransparency = False
+
+            # if "active panes" are no longer allowed, clear
+            # any optionActive values from the pane states
+            if self._agwFlags & AUI_MGR_ALLOW_ACTIVE_PANE == 0:
+                p.state &= ~AuiPaneInfo.optionActive
+
+            self._panes[ii] = p
+
+        old_pane_rects = []
+        pane_count = len(self._panes)
+        
+        for p in self._panes:
+            r = wx.Rect()
+            if p.window and p.IsShown() and p.IsDocked():
+                r = p.rect
+
+            old_pane_rects.append(r)    
+            
+        # apply the new sizer
+        self._frame.SetSizer(sizer)
+        self._frame.SetAutoLayout(False)
+        self.DoFrameLayout()
+        
+        # now that the frame layout is done, we need to check
+        # the new pane rectangles against the old rectangles that
+        # we saved a few lines above here.  If the rectangles have
+        # changed, the corresponding panes must also be updated
+        for ii in xrange(pane_count):
+            p = self._panes[ii]
+            if p.window and p.IsShown() and p.IsDocked():
+                if p.rect != old_pane_rects[ii]:
+                    p.window.Refresh()
+                    p.window.Update()
+
+        if wx.Platform == "__WXMAC__":
+            self._frame.Refresh()
+        else:
+            self.Repaint()
+
+        if not self._masterManager:
+            e = self.FireEvent(wxEVT_AUI_PERSPECTIVE_CHANGED, None, canVeto=False)    
+
+
+    def UpdateNotebook(self):
+        """ Updates the automatic L{AuiNotebook} in the layout (if any exists). """
+
+        # Workout how many notebooks we need.
+        max_notebook = -1
+
+        # destroy floating panes which have been
+        # redocked or are becoming non-floating
+        for paneInfo in self._panes:
+            if max_notebook < paneInfo.notebook_id:
+                max_notebook = paneInfo.notebook_id
+        
+        # We are the master of our domain
+        extra_notebook = len(self._notebooks)
+        max_notebook += 1
+        
+        for i in xrange(extra_notebook, max_notebook):
+            self.CreateNotebook()
+
+        # Remove pages from notebooks that no-longer belong there ...
+        for nb, notebook in enumerate(self._notebooks):
+            pages = notebook.GetPageCount()
+            pageCounter, allPages = 0, pages
+
+            # Check each tab ...
+            for page in xrange(pages):
+
+                if page >= allPages:
+                    break
+                
+                window = notebook.GetPage(pageCounter)
+                paneInfo = self.GetPane(window)
+                if paneInfo.IsOk() and paneInfo.notebook_id != nb:
+                    notebook.RemovePage(pageCounter)
+                    window.Hide()
+                    window.Reparent(self._frame)
+                    pageCounter -= 1
+                    allPages -= 1
+
+                pageCounter += 1
+
+            notebook.DoSizing()
+
+        # Add notebook pages that aren't there already...
+        for paneInfo in self._panes:
+            if paneInfo.IsNotebookPage():
+            
+                title = (paneInfo.caption == "" and [paneInfo.name] or [paneInfo.caption])[0]
+
+                notebook = self._notebooks[paneInfo.notebook_id]
+                page_id = notebook.GetPageIndex(paneInfo.window)
+
+                if page_id < 0:
+                
+                    paneInfo.window.Reparent(notebook)
+                    notebook.AddPage(paneInfo.window, title, True, paneInfo.icon)
+                
+                # Update title and icon ...
+                else:
+                
+                    notebook.SetPageText(page_id, title)
+                    notebook.SetPageBitmap(page_id, paneInfo.icon)
+
+                notebook.DoSizing()
+                
+            # Wire-up newly created notebooks
+            elif paneInfo.IsNotebookControl() and not paneInfo.window:
+                paneInfo.window = self._notebooks[paneInfo.notebook_id]
+            
+        # Delete empty notebooks, and convert notebooks with 1 page to
+        # normal panes...
+        remap_ids = [-1]*len(self._notebooks)
+        nb_idx = 0
+
+        for nb, notebook in enumerate(self._notebooks): 
+            if notebook.GetPageCount() == 1:
+            
+                # Convert notebook page to pane...
+                window = notebook.GetPage(0)
+                child_pane = self.GetPane(window)
+                notebook_pane = self.GetPane(notebook)
+                if child_pane.IsOk() and notebook_pane.IsOk():
+                
+                    child_pane.SetDockPos(notebook_pane)
+                    child_pane.window.Hide()
+                    child_pane.window.Reparent(self._frame)
+                    child_pane.frame = None
+                    child_pane.notebook_id = -1
+                    if notebook_pane.IsFloating():
+                        child_pane.Float()
+
+                    self.DetachPane(notebook)
+
+                    notebook.RemovePage(0)
+                    notebook.Destroy()
+                
+                else:
+                
+                    raise Exception("Odd notebook docking")
+                
+            elif notebook.GetPageCount() == 0:
+            
+                self.DetachPane(notebook)
+                notebook.Destroy()
+            
+            else:
+            
+                # Correct page ordering. The original wxPython code
+                # for this did not work properly, and would misplace 
+                # windows causing errors.
+                notebook.Freeze()
+                self._notebooks[nb_idx] = notebook
+                pages = notebook.GetPageCount()
+                selected = notebook.GetPage(notebook.GetSelection())
+
+                # Take each page out of the notebook, group it with
+                # its current pane, and sort the list by pane.dock_pos
+                # order
+                pages_and_panes = []
+                for idx in reversed(range(pages)):
+                    page = notebook.GetPage(idx)
+                    pane = self.GetPane(page)
+                    pages_and_panes.append((page, pane))
+                    notebook.RemovePage(idx)
+                sorted_pnp = sorted(pages_and_panes, key=lambda tup: tup[1].dock_pos)
+
+                # Grab the attributes from the panes which are ordered
+                # correctly, and copy those attributes to the original
+                # panes. (This avoids having to change the ordering
+                # of self._panes) Then, add the page back into the notebook
+                sorted_attributes = [self.GetAttributes(tup[1])
+                                     for tup in sorted_pnp]
+                for attrs, tup in zip(sorted_attributes, pages_and_panes):
+                    pane = tup[1]
+                    self.SetAttributes(pane, attrs)
+                    notebook.AddPage(pane.window, pane.caption)
+
+                notebook.SetSelection(notebook.GetPageIndex(selected), True)
+                notebook.DoSizing()
+                notebook.Thaw()
+
+                # It's a keeper.
+                remap_ids[nb] = nb_idx
+                nb_idx += 1
+
+        # Apply remap...
+        nb_count = len(self._notebooks)
+        
+        if nb_count != nb_idx:
+        
+            self._notebooks = self._notebooks[0:nb_idx]
+            for p in self._panes:
+                if p.notebook_id >= 0:                
+                    p.notebook_id = remap_ids[p.notebook_id]
+                    if p.IsNotebookControl():
+                        p.SetNameFromNotebookId()
+                
+        # Make sure buttons are correct ...
+        for notebook in self._notebooks:
+            want_max = True
+            want_min = True
+            want_close = True
+
+            pages = notebook.GetPageCount()
+            for page in xrange(pages):
+            
+                win = notebook.GetPage(page)
+                pane = self.GetPane(win)
+                if pane.IsOk():
+                
+                    if not pane.HasCloseButton():
+                        want_close = False
+                    if not pane.HasMaximizeButton():
+                        want_max = False
+                    if not pane.HasMinimizeButton():
+                        want_min = False
+                
+            notebook_pane = self.GetPane(notebook)
+            if notebook_pane.IsOk():
+                if notebook_pane.HasMinimizeButton() != want_min:
+                    if want_min:
+                        button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
+                        notebook_pane.state |= AuiPaneInfo.buttonMinimize
+                        notebook_pane.buttons.append(button)
+
+                    # todo: remove min/max
+            
+                if notebook_pane.HasMaximizeButton() != want_max:
+                    if want_max:
+                        button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
+                        notebook_pane.state |= AuiPaneInfo.buttonMaximize
+                        notebook_pane.buttons.append(button)
+                    
+                    # todo: remove min/max
+                
+                if notebook_pane.HasCloseButton() != want_close:
+                    if want_close:
+                        button = AuiPaneButton(AUI_BUTTON_CLOSE)
+                        notebook_pane.state |= AuiPaneInfo.buttonClose
+                        notebook_pane.buttons.append(button)
+                    
+                    # todo: remove close
+
+
+    def SmartShrink(self, docks, direction):
+        """
+        Used to intelligently shrink the docks' size (if needed).
+
+        :param `docks`: a list of L{AuiDockInfo} instances;
+        :param `direction`: the direction in which to shrink.
+        """
+
+        sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        clientSize = self._frame.GetClientSize()
+        ourDocks = FindDocks(docks, direction, -1, -1)
+        oppositeDocks = FindOppositeDocks(docks, direction)
+        oppositeSize = self.GetOppositeDockTotalSize(docks, direction)
+        ourSize = 0
+
+        for dock in ourDocks:
+            ourSize += dock.size
+
+            if not dock.toolbar:
+                ourSize += sashSize
+        
+        shrinkSize = ourSize + oppositeSize
+
+        if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
+            shrinkSize -= clientSize.y
+        else:
+            shrinkSize -= clientSize.x
+
+        if shrinkSize <= 0:
+            return docks
+
+        # Combine arrays
+        for dock in oppositeDocks:
+            ourDocks.append(dock)
+            
+        oppositeDocks = []
+
+        for dock in ourDocks:
+            if dock.toolbar or not dock.resizable:
+                continue
+
+            dockRange = dock.size - dock.min_size
+
+            if dock.min_size == 0:
+                dockRange -= sashSize
+                if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
+                    dockRange -= caption_size
+            
+            if dockRange >= shrinkSize:
+            
+                dock.size -= shrinkSize
+                return docks
+            
+            else:
+            
+                dock.size -= dockRange
+                shrinkSize -= dockRange
+            
+        return docks
+    
+
+    def UpdateDockingGuides(self, paneInfo):
+        """
+        Updates the docking guide windows positions and appearance.
+
+        :param `paneInfo`: a L{AuiPaneInfo} instance.
+        """
+
+        if len(self._guides) == 0:
+            self.CreateGuideWindows()
+
+        captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        frameRect = GetInternalFrameRect(self._frame, self._docks)
+        mousePos = wx.GetMousePosition()
+
+        for indx, guide in enumerate(self._guides):
+        
+            pt = wx.Point()
+            guide_size = guide.host.GetSize()
+            if not guide.host:
+                raise Exception("Invalid docking host")
+
+            direction = guide.dock_direction
+
+            if direction == AUI_DOCK_LEFT:
+                pt.x = frameRect.x + guide_size.x / 2 + 16
+                pt.y = frameRect.y + frameRect.height / 2
+
+            elif direction == AUI_DOCK_TOP:
+                pt.x = frameRect.x + frameRect.width / 2
+                pt.y = frameRect.y + guide_size.y / 2 + 16
+
+            elif direction == AUI_DOCK_RIGHT:
+                pt.x = frameRect.x + frameRect.width - guide_size.x / 2 - 16
+                pt.y = frameRect.y + frameRect.height / 2
+
+            elif direction == AUI_DOCK_BOTTOM:
+                pt.x = frameRect.x + frameRect.width / 2
+                pt.y = frameRect.y + frameRect.height - guide_size.y / 2 - 16
+
+            elif direction == AUI_DOCK_CENTER:
+                rc = paneInfo.window.GetScreenRect()
+                pt.x = rc.x + rc.width / 2
+                pt.y = rc.y + rc.height / 2
+                if paneInfo.HasCaption():
+                    pt.y -= captionSize / 2
+                elif paneInfo.HasCaptionLeft():
+                    pt.x -= captionSize / 2
+
+            # guide will be centered around point 'pt'
+            targetPosition = wx.Point(pt.x - guide_size.x / 2, pt.y - guide_size.y / 2)
+
+            if guide.host.GetPosition() != targetPosition:
+                guide.host.Move(targetPosition)
+                
+            guide.host.AeroMove(targetPosition)
+
+            if guide.dock_direction == AUI_DOCK_CENTER:
+                guide.host.ValidateNotebookDocking(paneInfo.IsNotebookDockable())
+
+            guide.host.UpdateDockGuide(mousePos)
+        
+        paneInfo.window.Lower()
+
+                        
+    def DoFrameLayout(self):
+        """
+        This is an internal function which invokes `wx.Sizer.Layout`
+        on the frame's main sizer, then measures all the various UI items
+        and updates their internal rectangles.
+
+        :note: This should always be called instead of calling
+         `self._managed_window.Layout()` directly.
+        """
+
+        self._frame.Layout()
+        
+        for part in self._uiparts:            
+            # get the rectangle of the UI part
+            # originally, this code looked like this:
+            #    part.rect = wx.Rect(part.sizer_item.GetPosition(),
+            #                       part.sizer_item.GetSize())
+            # this worked quite well, with one exception: the mdi
+            # client window had a "deferred" size variable 
+            # that returned the wrong size.  It looks like
+            # a bug in wx, because the former size of the window
+            # was being returned.  So, we will retrieve the part's
+            # rectangle via other means
+
+            part.rect = part.sizer_item.GetRect()
+            flag = part.sizer_item.GetFlag()
+            border = part.sizer_item.GetBorder()
+            
+            if flag & wx.TOP:
+                part.rect.y -= border
+                part.rect.height += border
+            if flag & wx.LEFT:
+                part.rect.x -= border
+                part.rect.width += border
+            if flag & wx.BOTTOM:
+                part.rect.height += border
+            if flag & wx.RIGHT:
+                part.rect.width += border
+
+            if part.type == AuiDockUIPart.typeDock:
+                part.dock.rect = part.rect
+            if part.type == AuiDockUIPart.typePane:
+                part.pane.rect = part.rect
+
+
+    def GetPanePart(self, wnd):
+        """
+        Looks up the pane border UI part of the
+        pane specified. This allows the caller to get the exact rectangle
+        of the pane in question, including decorations like caption and border.
+
+        :param `wnd`: the window to which the pane border belongs to.        
+        """
+
+        for part in self._uiparts:
+            if part.type == AuiDockUIPart.typePaneBorder and \
+               part.pane and part.pane.window == wnd:
+                return part
+
+        for part in self._uiparts:
+            if part.type == AuiDockUIPart.typePane and \
+               part.pane and part.pane.window == wnd:
+                return part
+    
+        return None
+
+
+    def GetDockPixelOffset(self, test):
+        """
+        This is an internal function which returns
+        a dock's offset in pixels from the left side of the window
+        (for horizontal docks) or from the top of the window (for
+        vertical docks).
+
+        This value is necessary for calculating fixed-pane/toolbar offsets
+        when they are dragged.
+
+        :param `test`: a fake L{AuiPaneInfo} for testing purposes.
+        """
+
+        # the only way to accurately calculate the dock's
+        # offset is to actually run a theoretical layout
+        docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
+        panes.append(test)
+
+        sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
+        client_size = self._frame.GetClientSize()
+        sizer.SetDimension(0, 0, client_size.x, client_size.y)
+        sizer.Layout()
+
+        for part in uiparts:
+            pos = part.sizer_item.GetPosition()
+            size = part.sizer_item.GetSize()
+            part.rect = wx.RectPS(pos, size)
+            if part.type == AuiDockUIPart.typeDock:
+                part.dock.rect = part.rect
+
+        sizer.Destroy()
+
+        for dock in docks:
+            if test.dock_direction == dock.dock_direction and \
+               test.dock_layer == dock.dock_layer and  \
+               test.dock_row == dock.dock_row:
+            
+                if dock.IsVertical():
+                    return dock.rect.y
+                else:
+                    return dock.rect.x
+            
+        return 0
+    
+
+    def GetPartnerDock(self, dock):
+        """
+        Returns the partner dock for the input dock.
+
+        :param `dock`: a L{AuiDockInfo} instance.
+        """
+
+        for layer in xrange(dock.dock_layer, -1, -1):
+        
+            bestDock = None
+
+            for tmpDock in self._docks:
+            
+                if tmpDock.dock_layer != layer:
+                    continue
+                
+                if tmpDock.dock_direction != dock.dock_direction:
+                    continue
+
+                if tmpDock.dock_layer < dock.dock_layer:
+                
+                    if not bestDock or tmpDock.dock_row < bestDock.dock_row:
+                        bestDock = tmpDock
+                
+                elif tmpDock.dock_row > dock.dock_row:
+                
+                    if not bestDock or tmpDock.dock_row > bestDock.dock_row:
+                        bestDock = tmpDock
+                
+            if bestDock:
+                return bestDock
+        
+        return None
+
+
+    def GetPartnerPane(self, dock, pane):
+        """
+        Returns the partner pane for the input pane. They both need to live
+        in the same L{AuiDockInfo}.
+
+        :param `dock`: a L{AuiDockInfo} instance;
+        :param `pane`: a L{AuiPaneInfo} class.
+        """
+        
+        panePosition = -1
+
+        for i, tmpPane in enumerate(dock.panes):        
+            if tmpPane.window == pane.window:
+                panePosition = i
+            elif not tmpPane.IsFixed() and panePosition != -1:
+                return tmpPane
+        
+        return None
+
+
+    def GetTotalPixSizeAndProportion(self, dock):
+        """
+        Returns the dimensions and proportion of the input dock.
+
+        :param `dock`: the L{AuiDockInfo} structure to analyze.
+        """
+
+        totalPixsize = 0
+        totalProportion = 0
+
+        # determine the total proportion of all resizable panes,
+        # and the total size of the dock minus the size of all
+        # the fixed panes
+        for tmpPane in dock.panes:
+        
+            if tmpPane.IsFixed():
+                continue
+
+            totalProportion += tmpPane.dock_proportion
+
+            if dock.IsHorizontal():
+                totalPixsize += tmpPane.rect.width
+            else:
+                totalPixsize += tmpPane.rect.height
+
+##            if tmpPane.min_size.IsFullySpecified():
+##            
+##                if dock.IsHorizontal():
+##                    totalPixsize -= tmpPane.min_size.x
+##                else:
+##                    totalPixsize -= tmpPane.min_size.y
+            
+        return totalPixsize, totalProportion
+
+
+    def GetOppositeDockTotalSize(self, docks, direction):
+        """
+        Returns the dimensions of the dock which lives opposite of the input dock.
+
+        :param `docks`: a list of L{AuiDockInfo} structures to analyze;
+        :param `direction`: the direction in which to look for the opposite dock.
+        """
+        
+        sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
+        minSizeMax = 0
+        result = sash_size
+        vertical = False
+
+        if direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
+            vertical = True
+
+        # Get minimum size of the most inner area
+        for tmpDock in docks:
+        
+            if tmpDock.dock_layer != 0:
+                continue
+
+            if tmpDock.dock_direction != AUI_DOCK_CENTER and tmpDock.IsVertical() != vertical:
+                continue
+
+            for tmpPane in tmpDock.panes:
+            
+                minSize = pane_border_size*2 - sash_size
+
+                if vertical:
+                    minSize += tmpPane.min_size.y + caption_size
+                else:
+                    minSize += tmpPane.min_size.x
+
+                if minSize > minSizeMax:
+                    minSizeMax = minSize
+            
+        result += minSizeMax
+
+        # Get opposite docks
+        oppositeDocks = FindOppositeDocks(docks, direction)
+
+        # Sum size of the opposite docks and their sashes
+        for dock in oppositeDocks:
+            result += dock.size
+            # if it's not a toolbar add the sash_size too
+            if not dock.toolbar:
+                result += sash_size
+        
+        return result
+
+
+    def CalculateDockSizerLimits(self, dock):
+        """
+        Calculates the minimum and maximum sizes allowed for the input dock.
+
+        :param `dock`: the L{AuiDockInfo} structure to analyze.
+        """
+
+        docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
+
+        sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+        caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+        opposite_size = self.GetOppositeDockTotalSize(docks, dock.dock_direction)
+
+        for tmpDock in docks:
+        
+            if tmpDock.dock_direction == dock.dock_direction and \
+               tmpDock.dock_layer == dock.dock_layer and \
+               tmpDock.dock_row == dock.dock_row:
+        
+                tmpDock.size = 1
+                break
+        
+        sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
+        client_size = self._frame.GetClientSize()
+        sizer.SetDimension(0, 0, client_size.x, client_size.y)
+        sizer.Layout()
+
+        for part in uiparts:
+        
+            part.rect = wx.RectPS(part.sizer_item.GetPosition(), part.sizer_item.GetSize())
+            if part.type == AuiDockUIPart.typeDock:
+                part.dock.rect = part.rect
+        
+        sizer.Destroy()
+        new_dock = None
+
+        for tmpDock in docks:
+            if tmpDock.dock_direction == dock.dock_direction and \
+               tmpDock.dock_layer == dock.dock_layer and \
+               tmpDock.dock_row == dock.dock_row:
+            
+                new_dock = tmpDock
+                break
+            
+        partnerDock = self.GetPartnerDock(dock)
+
+        if partnerDock:
+            partnerRange = partnerDock.size - partnerDock.min_size
+            if partnerDock.min_size == 0:
+                partnerRange -= sash_size
+                if dock.IsHorizontal():
+                    partnerRange -= caption_size
+            
+            direction = dock.dock_direction
+            
+            if direction == AUI_DOCK_LEFT:
+                minPix = new_dock.rect.x + new_dock.rect.width
+                maxPix = dock.rect.x + dock.rect.width
+                maxPix += partnerRange
+
+            elif direction == AUI_DOCK_TOP:
+                minPix = new_dock.rect.y + new_dock.rect.height
+                maxPix = dock.rect.y + dock.rect.height
+                maxPix += partnerRange
+
+            elif direction == AUI_DOCK_RIGHT:
+                minPix = dock.rect.x - partnerRange - sash_size
+                maxPix = new_dock.rect.x - sash_size
+
+            elif direction == AUI_DOCK_BOTTOM:
+                minPix = dock.rect.y - partnerRange - sash_size
+                maxPix = new_dock.rect.y - sash_size
+
+            return minPix, maxPix
+        
+        direction = new_dock.dock_direction
+        
+        if direction == AUI_DOCK_LEFT:
+            minPix = new_dock.rect.x + new_dock.rect.width
+            maxPix = client_size.x - opposite_size - sash_size
+
+        elif direction == AUI_DOCK_TOP:
+            minPix = new_dock.rect.y + new_dock.rect.height
+            maxPix = client_size.y - opposite_size - sash_size
+
+        elif direction == AUI_DOCK_RIGHT:
+            minPix = opposite_size
+            maxPix = new_dock.rect.x - sash_size
+
+        elif direction == AUI_DOCK_BOTTOM:
+            minPix = opposite_size
+            maxPix = new_dock.rect.y - sash_size
+
+        return minPix, maxPix
+
+
+    def CalculatePaneSizerLimits(self, dock, pane):
+        """
+        Calculates the minimum and maximum sizes allowed for the input pane.
+
+        :param `dock`: the L{AuiDockInfo} structure to which `pane` belongs to;
+        :param `pane`: a L{AuiPaneInfo} class for which calculation are requested.
+        """
+        
+        if pane.IsFixed():
+            if dock.IsHorizontal():
+                minPix = maxPix = pane.rect.x + 1 + pane.rect.width
+            else:
+                minPix = maxPix = pane.rect.y + 1 + pane.rect.height
+
+            return minPix, maxPix
+        
+        totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
+        partnerPane = self.GetPartnerPane(dock, pane)
+
+        if dock.IsHorizontal():
+        
+            minPix = pane.rect.x + 1
+            maxPix = pane.rect.x + 1 + pane.rect.width
+
+            if pane.min_size.IsFullySpecified():
+                minPix += pane.min_size.x
+            else:
+                minPix += 1
+
+            if partnerPane:
+                maxPix += partnerPane.rect.width
+
+                if partnerPane.min_size.IsFullySpecified():
+                    maxPix -= partnerPane.min_size.x - 1
+            
+            else:
+                minPix = maxPix
+        
+        else:
+        
+            minPix = pane.rect.y + 1
+            maxPix = pane.rect.y + 1 + pane.rect.height
+
+            if pane.min_size.IsFullySpecified():
+                minPix += pane.min_size.y
+            else:
+                minPix += 1
+
+            if partnerPane:            
+                maxPix += partnerPane.rect.height
+
+                if partnerPane.min_size.IsFullySpecified():
+                    maxPix -= partnerPane.min_size.y - 1
+            
+            else:            
+                minPix = maxPix
+            
+        return minPix, maxPix
+
+
+    def CheckMovableSizer(self, part):
+        """
+        Checks if a UI part can be actually resized.
+
+        :param `part`: a UI part.
+        """
+
+        # a dock may not be resized if it has a single
+        # pane which is not resizable
+        if part.type == AuiDockUIPart.typeDockSizer and part.dock and \
+           len(part.dock.panes) == 1 and part.dock.panes[0].IsFixed():
+        
+            return False
+        
+        if part.pane:
+        
+            # panes that may not be resized should be ignored here
+            minPix, maxPix = self.CalculatePaneSizerLimits(part.dock, part.pane)
+
+            if minPix == maxPix:
+                return False
+        
+        return True
+
+
+    def PaneFromTabEvent(self, event):
+        """
+        Returns a L{AuiPaneInfo} from a L{AuiNotebookEvent} event.
+
+        :param `event`: a L{AuiNotebookEvent} event.
+        """
+
+        obj = event.GetEventObject()
+
+        if obj and isinstance(obj, auibook.AuiTabCtrl):
+        
+            page_idx = obj.GetActivePage()
+
+            if page_idx >= 0:
+                page = obj.GetPage(page_idx)
+                window = page.window
+                if window:
+                    return self.GetPane(window)
+            
+        elif obj and isinstance(obj, auibook.AuiNotebook):
+        
+            page_idx = event.GetSelection()
+            
+            if page_idx >= 0:
+                window = obj.GetPage(page_idx)
+                if window:
+                    return self.GetPane(window)
+            
+        return NonePaneInfo
+
+
+    def OnTabBeginDrag(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        if self._masterManager:
+            self._masterManager.OnTabBeginDrag(event)
+        
+        else:
+            paneInfo = self.PaneFromTabEvent(event)
+            
+            if paneInfo.IsOk():
+            
+                # It's one of ours!
+                self._action = actionDragFloatingPane
+                mouse = wx.GetMousePosition()
+
+                # set initial float position - may have to think about this
+                # offset a bit more later ...
+                self._action_offset = wx.Point(20, 10)
+                self._toolbar_action_offset = wx.Point(20, 10)
+                
+                paneInfo.floating_pos = mouse - self._action_offset
+                paneInfo.dock_pos = AUI_DOCK_NONE
+                paneInfo.notebook_id = -1
+
+                tab = event.GetEventObject()
+
+                if tab.HasCapture():
+                    tab.ReleaseMouse()
+
+                # float the window
+                if paneInfo.IsMaximized():
+                    self.RestorePane(paneInfo)
+                paneInfo.Float()
+                self.Update()
+
+                self._action_window = paneInfo.window
+                    
+                self._frame.CaptureMouse()
+                event.SetDispatched(True)
+            
+            else:
+            
+                # not our window
+                event.Skip()
+            
+
+    def OnTabPageClose(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_PAGE_CLOSE`` event.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+
+        if self._masterManager:
+            self._masterManager.OnTabPageClose(event)
+        
+        else:
+        
+            p = self.PaneFromTabEvent(event)
+            if p.IsOk():
+            
+                # veto it because we will call "RemovePage" ourselves
+                event.Veto()
+
+                # Now ask the app if they really want to close...
+                # fire pane close event
+                e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
+                e.SetPane(p)
+                e.SetCanVeto(True)
+                self.ProcessMgrEvent(e)
+
+                if e.GetVeto():
+                    return
+
+                self.ClosePane(p)
+                self.Update()
+            else:
+                event.Skip()
+            
+
+    def OnTabSelected(self, event):
+        """
+        Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGED`` event.
+
+        :param `event`: a L{AuiNotebookEvent} event to be processed.
+        """
+        
+        if self._masterManager:
+            self._masterManager.OnTabSelected(event)
+            return
+        
+        obj = event.GetEventObject()
+
+        if obj and isinstance(obj, auibook.AuiNotebook):
+        
+            notebook = obj
+            page = notebook.GetPage(event.GetSelection())
+            paneInfo = self.GetPane(page)
+
+            if paneInfo.IsOk():
+                notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
+                if notebookRoot:
+                
+                    notebookRoot.Caption(paneInfo.caption)
+                    self.RefreshCaptions()
+                
+        event.Skip()
+
+
+    def GetNotebooks(self):
+        """ Returns all the automatic L{AuiNotebook} in the L{AuiManager}. """
+
+        if self._masterManager:
+            return self._masterManager.GetNotebooks()
+        
+        return self._notebooks
+
+
+    def SetMasterManager(self, manager):
+        """
+        Sets the master manager for an automatic L{AuiNotebook}.
+
+        :param `manager`: an instance of L{AuiManager}.
+        """
+
+        self._masterManager = manager
+
+        
+    def ProcessDockResult(self, target, new_pos):
+        """
+        This is a utility function used by L{DoDrop} - it checks
+        if a dock operation is allowed, the new dock position is copied into
+        the target info. If the operation was allowed, the function returns ``True``.
+
+        :param `target`: the L{AuiPaneInfo} instance to be docked;
+        :param `new_pos`: the new docking position if the docking operation is allowed.
+        """
+
+        allowed = False
+        direction = new_pos.dock_direction
+        
+        if direction == AUI_DOCK_TOP:
+            allowed = target.IsTopDockable()
+        elif direction == AUI_DOCK_BOTTOM:
+            allowed = target.IsBottomDockable()
+        elif direction == AUI_DOCK_LEFT:
+            allowed = target.IsLeftDockable()
+        elif direction == AUI_DOCK_RIGHT:
+            allowed = target.IsRightDockable()
+
+        if allowed:
+            target = new_pos
+
+            if target.IsToolbar():
+                self.SwitchToolBarOrientation(target)
+
+        return allowed, target
+
+
+    def SwitchToolBarOrientation(self, pane):
+        """
+        Switches the toolbar orientation from vertical to horizontal and vice-versa.
+        This is especially useful for vertical docked toolbars once they float.
+
+        :param `pane`: an instance of L{AuiPaneInfo}, which may have a L{AuiToolBar}
+         window associated with it.
+        """
+
+        if not isinstance(pane.window, auibar.AuiToolBar):
+            return pane
+        
+        if pane.IsFloating():
+            return pane
+
+        toolBar = pane.window
+        direction = pane.dock_direction
+        vertical = direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
+
+        agwStyle = toolBar.GetAGWWindowStyleFlag()
+        new_agwStyle = agwStyle
+
+        if vertical:
+            new_agwStyle |= AUI_TB_VERTICAL
+        else:
+            new_agwStyle &= ~(AUI_TB_VERTICAL)
+
+        if agwStyle != new_agwStyle:
+            toolBar.SetAGWWindowStyleFlag(new_agwStyle)
+        if not toolBar.GetGripperVisible():
+            toolBar.SetGripperVisible(True)
+
+        s = pane.window.GetMinSize()
+        pane.BestSize(s)
+
+        if new_agwStyle != agwStyle:
+            toolBar.Realize()
+        
+        return pane
+
+
+    def DoDrop(self, docks, panes, target, pt, offset=wx.Point(0, 0)):
+        """
+        This is an important function. It basically takes a mouse position,
+        and determines where the panes new position would be. If the pane is to be
+        dropped, it performs the drop operation using the specified dock and pane
+        arrays. By specifying copy dock and pane arrays when calling, a "what-if"
+        scenario can be performed, giving precise coordinates for drop hints.
+
+        :param `docks`: a list of L{AuiDockInfo} classes;
+        :param `panes`: a list of L{AuiPaneInfo} instances;
+        :param `pt`: a mouse position to check for a drop operation;
+        :param `offset`: a possible offset from the input point `pt`.
+        """
+
+        if target.IsToolbar():
+            return self.DoDropToolbar(docks, panes, target, pt, offset)
+        elif target.IsFloating():
+            return self.DoDropFloatingPane(docks, panes, target, pt)
+        else:
+            return self.DoDropNonFloatingPane(docks, panes, target, pt)
+    
+
+    def CopyTarget(self, target):
+        """
+        Copies all the attributes of the input `target` into another L{AuiPaneInfo}.
+
+        :param `target`: the source L{AuiPaneInfo} from where to copy attributes.
+        """
+
+        drop = AuiPaneInfo()
+        drop.name = target.name
+        drop.caption = target.caption
+        drop.window = target.window
+        drop.frame = target.frame
+        drop.state = target.state
+        drop.dock_direction = target.dock_direction
+        drop.dock_layer = target.dock_layer
+        drop.dock_row = target.dock_row
+        drop.dock_pos = target.dock_pos
+        drop.best_size = wx.Size(*target.best_size)
+        drop.min_size = wx.Size(*target.min_size)
+        drop.max_size = wx.Size(*target.max_size)
+        drop.floating_pos = wx.Point(*target.floating_pos)
+        drop.floating_size = wx.Size(*target.floating_size)
+        drop.dock_proportion = target.dock_proportion
+        drop.buttons = target.buttons
+        drop.rect = wx.Rect(*target.rect)
+        drop.icon = target.icon
+        drop.notebook_id = target.notebook_id
+        drop.transparent = target.transparent
+        drop.snapped = target.snapped
+        drop.minimize_mode = target.minimize_mode
+
+        return drop        
+
+
+    def DoDropToolbar(self, docks, panes, target, pt, offset):
+        """
+        Handles the situation in which the dropped pane contains a toolbar.
+
+        :param `docks`: a list of L{AuiDockInfo} classes;
+        :param `panes`: a list of L{AuiPaneInfo} instances;
+        :param `target`: the target pane containing the toolbar;
+        :param `pt`: a mouse position to check for a drop operation;
+        :param `offset`: a possible offset from the input point `pt`.        
+        """
+        
+        drop = self.CopyTarget(target)
+
+        # The result should always be shown
+        drop.Show()
+
+        # Check to see if the toolbar has been dragged out of the window
+        if CheckOutOfWindow(self._frame, pt):
+            if self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable():
+                drop.Float()
+
+            return self.ProcessDockResult(target, drop)
+
+        # Allow directional change when the cursor leaves this rect
+        safeRect = wx.Rect(*target.rect)
+        if target.IsHorizontal():
+            safeRect.Inflate(100, 50)
+        else:
+            safeRect.Inflate(50, 100)
+        
+        # Check to see if the toolbar has been dragged to edge of the frame
+        dropDir = CheckEdgeDrop(self._frame, docks, pt)
+
+        if dropDir != -1:
+        
+            if dropDir == wx.LEFT:
+                drop.Dock().Left().Layer(auiToolBarLayer).Row(0). \
+                    Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
+
+            elif dropDir == wx.RIGHT:
+                drop.Dock().Right().Layer(auiToolBarLayer).Row(0). \
+                    Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
+
+            elif dropDir == wx.TOP:
+                drop.Dock().Top().Layer(auiToolBarLayer).Row(0). \
+                    Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
+
+            elif dropDir == wx.BOTTOM:
+                drop.Dock().Bottom().Layer(auiToolBarLayer).Row(0). \
+                    Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
+
+            if not target.IsFloating() and safeRect.Contains(pt) and \
+               target.dock_direction != drop.dock_direction:
+                return False, target
+        
+            return self.ProcessDockResult(target, drop)
+    
+        # If the windows is floating and out of the client area, do nothing
+        if drop.IsFloating() and not self._frame.GetClientRect().Contains(pt):
+            return False, target
+    
+        # Ok, can't drop on edge - check internals ...
+
+        clientSize = self._frame.GetClientSize()
+        x = Clip(pt.x, 0, clientSize.x - 1)
+        y = Clip(pt.y, 0, clientSize.y - 1)
+        part = self.HitTest(x, y)
+
+        if not part or not part.dock:
+            return False, target
+        
+        dock = part.dock
+        
+        # toolbars may only be moved in and to fixed-pane docks,
+        # otherwise we will try to float the pane.  Also, the pane
+        # should float if being dragged over center pane windows
+        if not dock.fixed or dock.dock_direction == AUI_DOCK_CENTER:
+        
+            if (self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable()) or \
+               dock.dock_direction not in [AUI_DOCK_CENTER, AUI_DOCK_NONE]:
+                if drop.IsFloatable():
+                    drop.Float()
+            
+            return self.ProcessDockResult(target, drop)
+        
+        # calculate the offset from where the dock begins
+        # to the point where the user dropped the pane
+        dockDropOffset = 0
+        if dock.IsHorizontal():
+            dockDropOffset = pt.x - dock.rect.x - offset.x
+        else:
+            dockDropOffset = pt.y - dock.rect.y - offset.y
+        
+        drop.Dock().Direction(dock.dock_direction).Layer(dock.dock_layer). \
+            Row(dock.dock_row).Position(dockDropOffset)
+
+        if (pt.y <= dock.rect.GetTop() + 2 and dock.IsHorizontal()) or \
+           (pt.x <= dock.rect.GetLeft() + 2 and dock.IsVertical()):
+        
+            if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
+                row = drop.dock_row
+                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
+                drop.dock_row = row
+            
+            else:
+                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
+                drop.dock_row = dock.dock_row + 1
+            
+        if (pt.y >= dock.rect.GetBottom() - 2 and dock.IsHorizontal()) or \
+           (pt.x >= dock.rect.GetRight() - 2 and dock.IsVertical()):
+        
+            if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
+                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
+                drop.dock_row = dock.dock_row+1
+            
+            else:
+                row = drop.dock_row
+                panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
+                drop.dock_row = row
+
+        if not target.IsFloating() and safeRect.Contains(pt) and \
+           target.dock_direction != drop.dock_direction:
+            return False, target
+    
+        return self.ProcessDockResult(target, drop)
+
+
+    def DoDropFloatingPane(self, docks, panes, target, pt):
+        """
+        Handles the situation in which the dropped pane contains a normal window.
+
+        :param `docks`: a list of L{AuiDockInfo} classes;
+        :param `panes`: a list of L{AuiPaneInfo} instances;
+        :param `target`: the target pane containing the window;
+        :param `pt`: a mouse position to check for a drop operation.
+        """
+        
+        screenPt = self._frame.ClientToScreen(pt)
+        paneInfo = self.PaneHitTest(panes, pt)
+
+        if paneInfo.IsMaximized():
+            return False, target
+
+        if paneInfo.window is None:
+            return False, target
+
+        # search the dock guides.
+        # reverse order to handle the center first.
+        for i in xrange(len(self._guides)-1, -1, -1):
+            guide = self._guides[i]
+
+            # do hit testing on the guide
+            dir = guide.host.HitTest(screenPt.x, screenPt.y)
+
+            if dir == -1:  # point was outside of the dock guide
+                continue
+
+            if dir == wx.ALL:   # target is a single dock guide
+                return self.DoDropLayer(docks, target, guide.dock_direction)
+            
+            elif dir == wx.CENTER:
+
+                if not target.IsNotebookDockable():
+                    continue
+                if not paneInfo.IsNotebookDockable() and not paneInfo.IsNotebookControl():
+                    continue
+
+                if not paneInfo.HasNotebook():
+                
+                    # Add a new notebook pane with the original as a tab...
+                    self.CreateNotebookBase(panes, paneInfo)
+                
+                # Add new item to notebook
+                target.NotebookPage(paneInfo.notebook_id)
+            
+            else:
+            
+                drop_pane = False
+                drop_row = False
+
+                insert_dir = paneInfo.dock_direction
+                insert_layer = paneInfo.dock_layer
+                insert_row = paneInfo.dock_row
+                insert_pos = paneInfo.dock_pos
+
+                if insert_dir == AUI_DOCK_CENTER:
+                
+                    insert_layer = 0
+                    if dir == wx.LEFT:
+                        insert_dir = AUI_DOCK_LEFT
+                    elif dir == wx.UP:
+                        insert_dir = AUI_DOCK_TOP
+                    elif dir == wx.RIGHT:
+                        insert_dir = AUI_DOCK_RIGHT
+                    elif dir == wx.DOWN:
+                        insert_dir = AUI_DOCK_BOTTOM
+                
+                if insert_dir == AUI_DOCK_LEFT:
+                
+                    drop_pane = (dir == wx.UP   or dir == wx.DOWN)
+                    drop_row  = (dir == wx.LEFT or dir == wx.RIGHT)
+                    if dir == wx.RIGHT:
+                        insert_row += 1
+                    elif dir == wx.DOWN:
+                        insert_pos += 1
+                
+                elif insert_dir == AUI_DOCK_RIGHT:
+                
+                    drop_pane = (dir == wx.UP   or dir == wx.DOWN)
+                    drop_row  = (dir == wx.LEFT or dir == wx.RIGHT)
+                    if dir == wx.LEFT:
+                        insert_row += 1
+                    elif dir == wx.DOWN:
+                        insert_pos += 1
+                
+                elif insert_dir == AUI_DOCK_TOP:
+                
+                    drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
+                    drop_row  = (dir == wx.UP   or dir == wx.DOWN)
+                    if dir == wx.DOWN:
+                        insert_row += 1
+                    elif dir == wx.RIGHT:
+                        insert_pos += 1
+                
+                elif insert_dir == AUI_DOCK_BOTTOM:
+                
+                    drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
+                    drop_row  = (dir == wx.UP   or dir == wx.DOWN)
+                    if dir == wx.UP:
+                        insert_row += 1
+                    elif dir == wx.RIGHT:
+                        insert_pos += 1
+                
+                if paneInfo.dock_direction == AUI_DOCK_CENTER:
+                    insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
+
+                if drop_pane:
+                    return self.DoDropPane(panes, target, insert_dir, insert_layer, insert_row, insert_pos)
+
+                if drop_row:
+                    return self.DoDropRow(panes, target, insert_dir, insert_layer, insert_row)
+            
+            return True, target
+        
+        return False, target
+
+
+    def DoDropNonFloatingPane(self, docks, panes, target, pt):
+        """
+        Handles the situation in which the dropped pane is not floating.
+
+        :param `docks`: a list of L{AuiDockInfo} classes;
+        :param `panes`: a list of L{AuiPaneInfo} instances;
+        :param `target`: the target pane containing the toolbar;
+        :param `pt`: a mouse position to check for a drop operation.
+        """
+        
+        screenPt = self._frame.ClientToScreen(pt)
+        clientSize = self._frame.GetClientSize()
+        frameRect = GetInternalFrameRect(self._frame, self._docks)
+
+        drop = self.CopyTarget(target)
+
+        # The result should always be shown
+        drop.Show()
+
+        part = self.HitTest(pt.x, pt.y)
+
+        if not part:
+            return False, target
+
+        if part.type == AuiDockUIPart.typeDockSizer:
+        
+            if len(part.dock.panes) != 1:
+                return False, target
+            
+            part = self.GetPanePart(part.dock.panes[0].window)
+            if not part:
+                return False, target
+        
+        if not part.pane:
+            return False, target
+
+        part = self.GetPanePart(part.pane.window)
+        if not part:
+            return False, target
+
+        insert_dock_row = False
+        insert_row = part.pane.dock_row
+        insert_dir = part.pane.dock_direction
+        insert_layer = part.pane.dock_layer
+
+        direction = part.pane.dock_direction
+        
+        if direction == AUI_DOCK_TOP:
+            if pt.y >= part.rect.y and pt.y < part.rect.y+auiInsertRowPixels:
+                insert_dock_row = True
+
+        elif direction == AUI_DOCK_BOTTOM:
+            if pt.y > part.rect.y+part.rect.height-auiInsertRowPixels and \
+               pt.y <= part.rect.y + part.rect.height:
+                insert_dock_row = True
+
+        elif direction == AUI_DOCK_LEFT:
+            if pt.x >= part.rect.x and pt.x < part.rect.x+auiInsertRowPixels:
+                insert_dock_row = True
+
+        elif direction == AUI_DOCK_RIGHT:
+            if pt.x > part.rect.x+part.rect.width-auiInsertRowPixels and \
+               pt.x <= part.rect.x+part.rect.width:
+                insert_dock_row = True
+
+        elif direction == AUI_DOCK_CENTER:
+            
+                # "new row pixels" will be set to the default, but
+                # must never exceed 20% of the window size
+                new_row_pixels_x = auiNewRowPixels
+                new_row_pixels_y = auiNewRowPixels
+
+                if new_row_pixels_x > (part.rect.width*20)/100:
+                    new_row_pixels_x = (part.rect.width*20)/100
+
+                if new_row_pixels_y > (part.rect.height*20)/100:
+                    new_row_pixels_y = (part.rect.height*20)/100
+
+                # determine if the mouse pointer is in a location that
+                # will cause a new row to be inserted.  The hot spot positions
+                # are along the borders of the center pane
+
+                insert_layer = 0
+                insert_dock_row = True
+                pr = part.rect
+                
+                if pt.x >= pr.x and pt.x < pr.x + new_row_pixels_x:
+                    insert_dir = AUI_DOCK_LEFT
+                elif pt.y >= pr.y and pt.y < pr.y + new_row_pixels_y:
+                    insert_dir = AUI_DOCK_TOP
+                elif pt.x >= pr.x + pr.width - new_row_pixels_x and pt.x < pr.x + pr.width:
+                    insert_dir = AUI_DOCK_RIGHT
+                elif pt.y >= pr.y+ pr.height - new_row_pixels_y and pt.y < pr.y + pr.height:
+                    insert_dir = AUI_DOCK_BOTTOM
+                else:
+                    return False, target
+
+                insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
+            
+        if insert_dock_row:
+        
+            panes = DoInsertDockRow(panes, insert_dir, insert_layer, insert_row)
+            drop.Dock().Direction(insert_dir).Layer(insert_layer). \
+                Row(insert_row).Position(0)
+                
+            return self.ProcessDockResult(target, drop)
+
+        # determine the mouse offset and the pane size, both in the
+        # direction of the dock itself, and perpendicular to the dock
+
+        if part.orientation == wx.VERTICAL:
+        
+            offset = pt.y - part.rect.y
+            size = part.rect.GetHeight()
+        
+        else:
+        
+            offset = pt.x - part.rect.x
+            size = part.rect.GetWidth()
+        
+        drop_position = part.pane.dock_pos
+
+        # if we are in the top/left part of the pane,
+        # insert the pane before the pane being hovered over
+        if offset <= size/2:
+        
+            drop_position = part.pane.dock_pos
+            panes = DoInsertPane(panes,
+                                 part.pane.dock_direction,
+                                 part.pane.dock_layer,
+                                 part.pane.dock_row,
+                                 part.pane.dock_pos)
+
+        # if we are in the bottom/right part of the pane,
+        # insert the pane before the pane being hovered over
+        if offset > size/2:
+        
+            drop_position = part.pane.dock_pos+1
+            panes = DoInsertPane(panes,
+                                 part.pane.dock_direction,
+                                 part.pane.dock_layer,
+                                 part.pane.dock_row,
+                                 part.pane.dock_pos+1)
+        
+
+        drop.Dock(). \
+                     Direction(part.dock.dock_direction). \
+                     Layer(part.dock.dock_layer).Row(part.dock.dock_row). \
+                     Position(drop_position)
+        
+        return self.ProcessDockResult(target, drop)
+
+
+    def DoDropLayer(self, docks, target, dock_direction):
+        """
+        Handles the situation in which `target` is a single dock guide.
+
+        :param `docks`: a list of L{AuiDockInfo} classes;
+        :param `target`: the target pane;
+        :param `dock_direction`: the docking direction.
+        """
+
+        drop = self.CopyTarget(target)
+        
+        if dock_direction == AUI_DOCK_LEFT:
+            drop.Dock().Left()
+            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_LEFT),
+                                     GetMaxLayer(docks, AUI_DOCK_BOTTOM)),
+                                 GetMaxLayer(docks, AUI_DOCK_TOP)) + 1
+
+        elif dock_direction == AUI_DOCK_TOP:
+            drop.Dock().Top()
+            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_TOP),
+                                     GetMaxLayer(docks, AUI_DOCK_LEFT)),
+                                 GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
+
+        elif dock_direction == AUI_DOCK_RIGHT:
+            drop.Dock().Right()
+            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_RIGHT),
+                                     GetMaxLayer(docks, AUI_DOCK_TOP)),
+                                 GetMaxLayer(docks, AUI_DOCK_BOTTOM)) + 1
+
+        elif dock_direction == AUI_DOCK_BOTTOM:
+            drop.Dock().Bottom()
+            drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_BOTTOM),
+                                     GetMaxLayer(docks, AUI_DOCK_LEFT)),
+                                 GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
+
+        else:
+            return False, target
+        
+
+        drop.Dock().Layer(drop_new_layer)
+        return self.ProcessDockResult(target, drop)
+
+
+    def DoDropPane(self, panes, target, dock_direction, dock_layer, dock_row, dock_pos):
+        """
+        Drop a pane in the interface.
+
+        :param `panes`: a list of L{AuiPaneInfo} classes;
+        :param `target`: the target pane;
+        :param `dock_direction`: the docking direction;
+        :param `dock_layer`: the docking layer;
+        :param `dock_row`: the docking row;
+        :param `dock_pos`: the docking position.
+        """
+        
+        drop = self.CopyTarget(target)
+        panes = DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos)
+
+        drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(dock_pos)
+        return self.ProcessDockResult(target, drop)
+
+
+    def DoDropRow(self, panes, target, dock_direction, dock_layer, dock_row):
+        """
+        Insert a row in the interface before dropping.
+
+        :param `panes`: a list of L{AuiPaneInfo} classes;
+        :param `target`: the target pane;
+        :param `dock_direction`: the docking direction;
+        :param `dock_layer`: the docking layer;
+        :param `dock_row`: the docking row.
+        """
+        
+        drop = self.CopyTarget(target)
+        panes = DoInsertDockRow(panes, dock_direction, dock_layer, dock_row)
+
+        drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(0)
+        return self.ProcessDockResult(target, drop)
+
+
+    def ShowHint(self, rect):
+        """
+        Shows the AUI hint window.
+
+        :param `rect`: the hint rect calculated in advance.
+        """
+
+        if rect == self._last_hint:
+            return
+
+        if self._agwFlags & AUI_MGR_RECTANGLE_HINT and wx.Platform != "__WXMAC__":
+
+            if self._last_hint != rect:
+                # remove the last hint rectangle
+                self._last_hint = wx.Rect(*rect)
+                self._frame.Refresh()
+                self._frame.Update()
+            
+            screendc = wx.ScreenDC()
+            clip = wx.Region(1, 1, 10000, 10000)
+
+            # clip all floating windows, so we don't draw over them
+            for pane in self._panes:            
+                if pane.IsFloating() and pane.frame.IsShown():
+                
+                    rect2 = wx.Rect(*pane.frame.GetRect())
+                    if wx.Platform == "__WXGTK__":
+                        # wxGTK returns the client size, not the whole frame size
+                        rect2.width += 15
+                        rect2.height += 35
+                        rect2.Inflate(5, 5)
+
+                    clip.SubtractRect(rect2)
+                
+            # As we can only hide the hint by redrawing the managed window, we
+            # need to clip the region to the managed window too or we get
+            # nasty redrawn problems.
+            clip.IntersectRect(self._frame.GetRect())
+            screendc.SetClippingRegionAsRegion(clip)
+
+            stipple = PaneCreateStippleBitmap()
+            brush = wx.BrushFromBitmap(stipple)
+            screendc.SetBrush(brush)
+            screendc.SetPen(wx.TRANSPARENT_PEN)
+            screendc.DrawRectangle(rect.x, rect.y, 5, rect.height)
+            screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5)
+            screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height)
+            screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5)
+            RefreshDockingGuides(self._guides)
+
+            return
+            
+        if not self._hint_window:
+            self.CreateHintWindow()
+
+        if self._hint_window:
+            self._hint_window.SetRect(rect)
+            self._hint_window.Show()
+
+        self._hint_fadeamt = self._hint_fademax
+
+        if self._agwFlags & AUI_MGR_HINT_FADE:
+            self._hint_fadeamt = 0
+            self._hint_window.SetTransparent(self._hint_fadeamt)
+
+        if self._action == actionDragFloatingPane and self._action_window:
+            self._action_window.SetFocus()
+
+        if self._hint_fadeamt != self._hint_fademax: #  Only fade if we need to
+            # start fade in timer
+            self._hint_fadetimer.Start(5)
+
+        self._last_hint = wx.Rect(*rect)
+        
+
+    def HideHint(self):
+        """ Hides a transparent window hint if there is one. """
+
+        # hides a transparent window hint if there is one
+        if self._hint_window:
+            self._hint_window.Hide()
+
+        self._hint_fadetimer.Stop()
+        self._last_hint = wx.Rect()
+        
+
+    def IsPaneButtonVisible(self, part):
+        """
+        Returns whether a pane button in the pane caption is visible.
+
+        :param `part`: the UI part to analyze.
+        """
+
+        captionRect = wx.Rect()
+
+        for temp_part in self._uiparts:
+            if temp_part.pane == part.pane and \
+               temp_part.type == AuiDockUIPart.typeCaption:
+                captionRect = temp_part.rect
+                break
+
+        return captionRect.ContainsRect(part.rect)
+
+
+    def DrawPaneButton(self, dc, part, pt):
+        """
+        Draws a pane button in the caption (convenience function).
+
+        :param `dc`: a `wx.DC` device context object;
+        :param `part`: the UI part to analyze;
+        :param `pt`: a `wx.Point` object, specifying the mouse location.
+        """
+
+        if not self.IsPaneButtonVisible(part):
+            return
+
+        state = AUI_BUTTON_STATE_NORMAL
+
+        if part.rect.Contains(pt):
+
+            if _VERSION_STRING < "2.9":
+                leftDown = wx.GetMouseState().LeftDown()
+            else:
+                leftDown = wx.GetMouseState().LeftIsDown()
+
+            if leftDown:
+                state = AUI_BUTTON_STATE_PRESSED
+            else:
+                state = AUI_BUTTON_STATE_HOVER
+
+        self._art.DrawPaneButton(dc, self._frame, part.button.button_id,
+                                 state, part.rect, part.pane)
+
+    
+    def RefreshButton(self, part):
+        """
+        Refreshes a pane button in the caption.
+
+        :param `part`: the UI part to analyze.
+        """
+        
+        rect = wx.Rect(*part.rect)
+        rect.Inflate(2, 2)
+        self._frame.Refresh(True, rect)
+        self._frame.Update()
+
+
+    def RefreshCaptions(self):
+        """ Refreshes all pane captions. """
+
+        for part in self._uiparts:
+            if part.type == AuiDockUIPart.typeCaption:
+                self._frame.Refresh(True, part.rect)
+                self._frame.Update()
+
+
+    def CalculateHintRect(self, pane_window, pt, offset):
+        """
+        Calculates the drop hint rectangle.
+
+        The method first calls L{DoDrop} to determine the exact position the pane would
+        be at were if dropped. If the pane would indeed become docked at the
+        specified drop point, the the rectangle hint will be returned in
+        screen coordinates. Otherwise, an empty rectangle is returned.
+
+        :param `pane_window`: it is the window pointer of the pane being dragged;
+        :param `pt`: is the mouse position, in client coordinates;
+        :param `offset`: describes the offset that the mouse is from the upper-left
+         corner of the item being dragged.
+        """
+        
+        # we need to paint a hint rectangle to find out the exact hint rectangle,
+        # we will create a new temporary layout and then measure the resulting
+        # rectangle we will create a copy of the docking structures (self._docks)
+        # so that we don't modify the real thing on screen
+
+        rect = wx.Rect()
+        pane = self.GetPane(pane_window)
+        
+        attrs = self.GetAttributes(pane)
+        hint = AuiPaneInfo()
+        hint = self.SetAttributes(hint, attrs)
+        
+        if hint.name != "__HINT__":
+            self._oldname = hint.name
+            
+        hint.name = "__HINT__"
+        hint.PaneBorder(True)
+        hint.Show()
+
+        if not hint.IsOk():
+            hint.name = self._oldname
+            return rect
+
+        docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
+
+        # remove any pane already there which bears the same window
+        # this happens when you are moving a pane around in a dock
+        for ii in xrange(len(panes)):
+            if panes[ii].window == pane_window:
+                docks = RemovePaneFromDocks(docks, panes[ii])
+                panes.pop(ii)
+                break
+
+        # find out where the new pane would be
+        allow, hint = self.DoDrop(docks, panes, hint, pt, offset)
+
+        if not allow:
+            return rect
+        
+        panes.append(hint)
+
+        sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
+        
+        client_size = self._frame.GetClientSize()
+        sizer.SetDimension(0, 0, client_size.x, client_size.y)
+        sizer.Layout()
+
+        sought = "__HINT__"
+        
+        # For a notebook page, actually look for the noteboot itself.
+        if hint.IsNotebookPage():
+            id = hint.notebook_id
+            for pane in panes:
+                if pane.IsNotebookControl() and pane.notebook_id==id:
+                    sought = pane.name
+                    break
+
+        for part in uiparts:
+            if part.pane and part.pane.name == sought:    
+                rect.Union(wx.RectPS(part.sizer_item.GetPosition(),
+                                     part.sizer_item.GetSize()))
+
+        sizer.Destroy()
+
+        # check for floating frame ...
+        if rect.IsEmpty():
+            for p in panes:
+                if p.name == sought and p.IsFloating():
+                    return wx.RectPS(p.floating_pos, p.floating_size)
+    
+        if rect.IsEmpty():
+            return rect
+
+        # actually show the hint rectangle on the screen
+        rect.x, rect.y = self._frame.ClientToScreen((rect.x, rect.y))
+        if self._frame.GetLayoutDirection() == wx.Layout_RightToLeft:
+            # Mirror rectangle in RTL mode
+            rect.x -= rect.GetWidth()
+
+        return rect
+
+
+    def DrawHintRect(self, pane_window, pt, offset):
+        """
+        Calculates the hint rectangle by calling
+        L{CalculateHintRect}. If there is a rectangle, it shows it
+        by calling L{ShowHint}, otherwise it hides any hint
+        rectangle currently shown.
+
+        :param `pane_window`: it is the window pointer of the pane being dragged;
+        :param `pt`: is the mouse position, in client coordinates;
+        :param `offset`: describes the offset that the mouse is from the upper-left
+         corner of the item being dragged.
+        """
+
+        rect = self.CalculateHintRect(pane_window, pt, offset)
+
+        if rect.IsEmpty():
+            self.HideHint()
+            self._hint_rect = wx.Rect()
+        else:
+            self.ShowHint(rect)
+            self._hint_rect = wx.Rect(*rect)
+
+
+    def GetPartSizerRect(self, uiparts):
+        """
+        Returns the rectangle surrounding the specified UI parts.
+
+        :param `uiparts`: UI parts.
+        """
+
+        rect = wx.Rect()
+
+        for part in self._uiparts:
+            if part.pane and part.pane.name == "__HINT__":
+                rect.Union(wx.RectPS(part.sizer_item.GetPosition(),
+                                     part.sizer_item.GetSize()))
+
+        return rect
+
+
+    def GetAttributes(self, pane):
+        """
+        Returns all the attributes of a L{AuiPaneInfo}.
+
+        :param `pane`: a L{AuiPaneInfo} instance.
+        """
+
+        attrs = []
+        attrs.extend([pane.window, pane.frame, pane.state, pane.dock_direction,
+                      pane.dock_layer, pane.dock_pos, pane.dock_row, pane.dock_proportion,
+                      pane.floating_pos, pane.floating_size, pane.best_size,
+                      pane.min_size, pane.max_size, pane.caption, pane.name,
+                      pane.buttons, pane.rect, pane.icon, pane.notebook_id,
+                      pane.transparent, pane.snapped, pane.minimize_mode])
+
+        return attrs
+    
+
+    def SetAttributes(self, pane, attrs):
+        """
+        Sets all the attributes contained in `attrs` to a L{AuiPaneInfo}.
+
+        :param `pane`: a L{AuiPaneInfo} instance;
+        :param `attrs`: a list of attributes.
+        """
+        
+        pane.window = attrs[0]
+        pane.frame = attrs[1]
+        pane.state = attrs[2]
+        pane.dock_direction = attrs[3]
+        pane.dock_layer = attrs[4]
+        pane.dock_pos = attrs[5]
+        pane.dock_row = attrs[6]
+        pane.dock_proportion = attrs[7]
+        pane.floating_pos = attrs[8]
+        pane.floating_size = attrs[9]
+        pane.best_size = attrs[10]
+        pane.min_size = attrs[11]
+        pane.max_size = attrs[12]
+        pane.caption = attrs[13]
+        pane.name = attrs[14]
+        pane.buttons = attrs[15]
+        pane.rect = attrs[16]
+        pane.icon = attrs[17]
+        pane.notebook_id = attrs[18]
+        pane.transparent = attrs[19]
+        pane.snapped = attrs[20]
+        pane.minimize_mode = attrs[21]
+
+        return pane
+
+     
+    def OnFloatingPaneResized(self, wnd, size):
+        """
+        Handles the resizing of a floating pane.
+
+        :param `wnd`: a `wx.Window` derived window, managed by the pane;
+        :param `size`: a `wx.Size` object, specifying the new pane floating size.
+        """
+
+        # try to find the pane
+        pane = self.GetPane(wnd)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        if pane.frame:
+            indx = self._panes.index(pane)
+            pane.floating_pos = pane.frame.GetPosition()
+            pane.floating_size = size
+            self._panes[indx] = pane
+            if pane.IsSnappable():
+                self.SnapPane(pane, pane.floating_pos, pane.floating_size, True)
+            
+
+    def OnFloatingPaneClosed(self, wnd, event):
+        """
+        Handles the close event of a floating pane.
+
+        :param `wnd`: a `wx.Window` derived window, managed by the pane;
+        :param `event`: a `wx.CloseEvent` to be processed.
+        """
+        
+        # try to find the pane
+        pane = self.GetPane(wnd)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        # fire pane close event
+        e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
+        e.SetPane(pane)
+        e.SetCanVeto(event.CanVeto())
+        self.ProcessMgrEvent(e)
+
+        if e.GetVeto():
+            event.Veto()
+            return
+        else:
+            # close the pane, but check that it
+            # still exists in our pane array first
+            # (the event handler above might have removed it)
+
+            check = self.GetPane(wnd)
+            if check.IsOk():
+                self.ClosePane(pane)
+        
+
+    def OnFloatingPaneActivated(self, wnd):
+        """
+        Handles the activation event of a floating pane.
+
+        :param `wnd`: a `wx.Window` derived window, managed by the pane.
+        """
+        
+        pane = self.GetPane(wnd)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
+            ret, self._panes = SetActivePane(self._panes, wnd)
+            self.RefreshCaptions()
+            self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, wnd, canVeto=False)
+
+
+    def OnFloatingPaneMoved(self, wnd, eventOrPt):
+        """
+        Handles the move event of a floating pane.
+
+        :param `wnd`: a `wx.Window` derived window, managed by the pane;
+        :param `eventOrPt`: a `wx.MoveEvent` to be processed or an instance of `wx.Point`.
+        """
+        
+        pane = self.GetPane(wnd)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        if not pane.IsSnappable():
+            return
+
+        if isinstance(eventOrPt, wx.Point):
+            pane_pos = wx.Point(*eventOrPt)
+        else:
+            pane_pos = eventOrPt.GetPosition()
+
+        pane_size = pane.floating_size
+
+        self.SnapPane(pane, pane_pos, pane_size, False)
+
+
+    def SnapPane(self, pane, pane_pos, pane_size, toSnap=False):
+        """
+        Snaps a floating pane to one of the main frame sides.
+
+        :param `pane`: a L{AuiPaneInfo} instance;
+        :param `pane_pos`: the new pane floating position;
+        :param `pane_size`: the new pane floating size;
+        :param `toSnap`: a bool variable to check if L{SnapPane} was called from
+         a move event.
+        """
+
+        if self._from_move:
+            return
+        
+        managed_window = self.GetManagedWindow()
+        wnd_pos = managed_window.GetPosition()
+        wnd_size = managed_window.GetSize()
+        snapX, snapY = self._snap_limits
+
+        if not toSnap:
+            pane.snapped = 0
+            if pane.IsLeftSnappable():
+                # Check if we can snap to the left
+                diff = wnd_pos.x - (pane_pos.x + pane_size.x)
+                if -snapX <= diff <= snapX:
+                    pane.snapped = wx.LEFT
+                    pane.floating_pos = wx.Point(wnd_pos.x-pane_size.x, pane_pos.y)
+            elif pane.IsTopSnappable():
+                # Check if we can snap to the top
+                diff = wnd_pos.y - (pane_pos.y + pane_size.y)
+                if -snapY <= diff <= snapY:
+                    pane.snapped = wx.TOP
+                    pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y-pane_size.y)
+            elif pane.IsRightSnappable():
+                # Check if we can snap to the right
+                diff = pane_pos.x - (wnd_pos.x + wnd_size.x)
+                if -snapX <= diff <= snapX:
+                    pane.snapped = wx.RIGHT
+                    pane.floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y)
+            elif pane.IsBottomSnappable():
+                # Check if we can snap to the bottom
+                diff = pane_pos.y - (wnd_pos.y + wnd_size.y)
+                if -snapY <= diff <= snapY:
+                    pane.snapped = wx.BOTTOM
+                    pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y)
+
+        self.RepositionPane(pane, wnd_pos, wnd_size)
+
+
+    def RepositionPane(self, pane, wnd_pos, wnd_size):
+        """
+        Repositions a pane after the main frame has been moved/resized.
+        
+        :param `pane`: a L{AuiPaneInfo} instance;
+        :param `wnd_pos`: the main frame position;
+        :param `wnd_size`: the main frame size.
+        """
+
+        pane_pos = pane.floating_pos
+        pane_size = pane.floating_size
+
+        snap = pane.snapped
+        if snap == wx.LEFT:
+            floating_pos = wx.Point(wnd_pos.x - pane_size.x, pane_pos.y)
+        elif snap == wx.TOP:
+            floating_pos = wx.Point(pane_pos.x, wnd_pos.y - pane_size.y)
+        elif snap == wx.RIGHT:
+            floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y)
+        elif snap == wx.BOTTOM:
+            floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y)
+
+        if snap:
+            if pane_pos != floating_pos:
+                pane.floating_pos = floating_pos
+                self._from_move = True
+                pane.frame.SetPosition(pane.floating_pos)
+                self._from_move = False
+
+            
+    def OnGripperClicked(self, pane_window, start, offset):
+        """
+        Handles the mouse click on the pane gripper.
+
+        :param `pane_window`: a `wx.Window` derived window, managed by the pane;
+        :param `start`: a `wx.Point` object, specifying the clicking position;
+        :param `offset`: an offset point from the `start` position.
+        """
+
+        # try to find the pane
+        paneInfo = self.GetPane(pane_window)
+
+        if not paneInfo.IsOk():
+            raise Exception("Pane window not found")
+
+        if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
+            # set the caption as active
+            ret, self._panes = SetActivePane(self._panes, pane_window)
+            self.RefreshCaptions()
+            self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, pane_window, canVeto=False)
+        
+        self._action_part = None
+        self._action_pane = paneInfo
+        self._action_window = pane_window
+        self._action_start = start
+        self._action_offset = offset
+        self._toolbar_action_offset = wx.Point(*self._action_offset)
+        
+        self._frame.CaptureMouse()
+
+        if paneInfo.IsDocked():
+            self._action = actionClickCaption
+        else:
+            if paneInfo.IsToolbar():
+                self._action = actionDragToolbarPane
+            else:
+                self._action = actionDragFloatingPane
+
+            if paneInfo.frame:
+            
+                windowPt = paneInfo.frame.GetRect().GetTopLeft()
+                originPt = paneInfo.frame.ClientToScreen(wx.Point())
+                self._action_offset += originPt - windowPt
+                self._toolbar_action_offset = wx.Point(*self._action_offset)
+
+                if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
+                    paneInfo.frame.SetTransparent(150)
+            
+            if paneInfo.IsToolbar():
+                self._frame.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
+        
+
+    def OnRender(self, event):        
+        """
+        Draws all of the pane captions, sashes,
+        backgrounds, captions, grippers, pane borders and buttons.
+        It renders the entire user interface. It binds the ``EVT_AUI_RENDER`` event.
+
+        :param `event`: an instance of L{AuiManagerEvent}.
+        """
+
+        # if the frame is about to be deleted, don't bother
+        if not self._frame or self._frame.IsBeingDeleted():
+            return
+        
+        if not self._frame.GetSizer():
+            return
+
+        mouse = wx.GetMouseState()
+        mousePos = wx.Point(mouse.GetX(), mouse.GetY())
+        point = self._frame.ScreenToClient(mousePos)
+        art = self._art
+
+        dc = event.GetDC()
+        
+        for part in self._uiparts:
+        
+            # don't draw hidden pane items or items that aren't windows
+            if part.sizer_item and ((not part.sizer_item.IsWindow() and \
+                                     not part.sizer_item.IsSpacer() and \
+                                     not part.sizer_item.IsSizer()) or \
+                                    not part.sizer_item.IsShown()):
+            
+                continue
+            
+            ptype = part.type
+                    
+            if ptype in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
+                art.DrawSash(dc, self._frame, part.orientation, part.rect)
+
+            elif ptype == AuiDockUIPart.typeBackground:
+                art.DrawBackground(dc, self._frame, part.orientation, part.rect)
+
+            elif ptype == AuiDockUIPart.typeCaption:
+                art.DrawCaption(dc, self._frame, part.pane.caption, part.rect, part.pane)
+
+            elif ptype == AuiDockUIPart.typeGripper:
+                art.DrawGripper(dc, self._frame, part.rect, part.pane)
+
+            elif ptype == AuiDockUIPart.typePaneBorder:
+                art.DrawBorder(dc, self._frame, part.rect, part.pane)
+
+            elif ptype == AuiDockUIPart.typePaneButton:                
+                self.DrawPaneButton(dc, part, point)
+
+
+    def Repaint(self, dc=None):
+        """
+        Repaints the entire frame decorations (sashes, borders, buttons and so on).
+        It renders the entire user interface.
+
+        :param `dc`: if not ``None``, an instance of `wx.PaintDC`.
+        """
+        
+        w, h = self._frame.GetClientSize()
+
+        # Figure out which dc to use; if one
+        # has been specified, use it, otherwise
+        # make a client dc
+        if dc is None:
+            client_dc = wx.ClientDC(self._frame)
+            dc = client_dc
+
+        # If the frame has a toolbar, the client area
+        # origin will not be (0, 0).
+        pt = self._frame.GetClientAreaOrigin()
+        if pt.x != 0 or pt.y != 0:
+            dc.SetDeviceOrigin(pt.x, pt.y)
+
+        # Render all the items
+        self.Render(dc)
+
+                
+    def Render(self, dc):
+        """
+        Fires a render event, which is normally handled by
+        L{OnRender}. This allows the render function to
+        be overridden via the render event.
+
+        This can be useful for painting custom graphics in the main window.
+        Default behavior can be invoked in the overridden function by calling
+        L{OnRender}.
+
+        :param `dc`: a `wx.DC` device context object.        
+        """
+
+        e = AuiManagerEvent(wxEVT_AUI_RENDER)
+        e.SetManager(self)
+        e.SetDC(dc)
+        self.ProcessMgrEvent(e)
+
+
+    def OnCaptionDoubleClicked(self, pane_window):
+        """
+        Handles the mouse double click on the pane caption.
+
+        :param `pane_window`: a `wx.Window` derived window, managed by the pane.
+        """
+
+        # try to find the pane
+        paneInfo = self.GetPane(pane_window)
+        if not paneInfo.IsOk():
+            raise Exception("Pane window not found")
+
+        if not paneInfo.IsFloatable() or not paneInfo.IsDockable() or \
+           self._agwFlags & AUI_MGR_ALLOW_FLOATING == 0:
+            return
+
+        indx = self._panes.index(paneInfo)
+        win_rect = None
+        
+        if paneInfo.IsFloating():
+            if paneInfo.name.startswith("__floating__"):
+                # It's a floating tab from a AuiNotebook
+                notebook = paneInfo.window.__aui_notebook__
+                notebook.ReDockPage(paneInfo)
+                self.Update()
+                return
+            else:
+
+                e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
+                if e.GetVeto():
+                    self.HideHint()
+                    ShowDockingGuides(self._guides, False)
+                    return
+                
+                win_rect = paneInfo.frame.GetRect()
+                paneInfo.Dock()
+                if paneInfo.IsToolbar():
+                    paneInfo = self.SwitchToolBarOrientation(paneInfo)
+
+                e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
+
+        else:
+
+            e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, paneInfo, canVeto=True)
+            if e.GetVeto():
+                return
+
+            # float the window
+            if paneInfo.IsMaximized():
+                self.RestorePane(paneInfo)
+            
+            if paneInfo.floating_pos == wx.Point(-1, -1):
+                captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
+                paneInfo.floating_pos = pane_window.GetScreenPosition()
+                paneInfo.floating_pos.y -= captionSize
+
+            paneInfo.Float()
+            e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, paneInfo, canVeto=False)
+
+        self._panes[indx] = paneInfo
+        self.Update()
+
+        if win_rect and self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
+            paneInfo = self.GetPane(pane_window)
+            pane_rect = paneInfo.window.GetScreenRect()
+            self.AnimateDocking(win_rect, pane_rect)
+
+
+    def OnPaint(self, event):
+        """
+        Handles the ``wx.EVT_PAINT`` event for L{AuiManager}.
+
+        :param `event`: an instance of `wx.PaintEvent` to be processed.
+        """
+        
+        dc = wx.PaintDC(self._frame)
+        self.Repaint(dc)
+                
+
+    def OnEraseBackground(self, event):
+        """
+        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiManager}.
+
+        :param `event`: `wx.EraseEvent` to be processed.
+
+        :note: This is intentionally empty (excluding wxMAC) to reduce
+         flickering while drawing.
+        """
+        
+        if wx.Platform == "__WXMAC__":
+            event.Skip()
+
+
+    def OnSize(self, event):
+        """
+        Handles the ``wx.EVT_SIZE`` event for L{AuiManager}.
+
+        :param `event`: a `wx.SizeEvent` to be processed.
+        """
+        
+        skipped = False
+        if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
+            skipped = True
+            event.Skip()
+
+        if self._frame:
+                
+            self.DoFrameLayout()
+            if wx.Platform == "__WXMAC__":
+                self._frame.Refresh()
+            else:
+                self.Repaint()
+            
+            if isinstance(self._frame, wx.MDIParentFrame) or isinstance(self._frame, tabmdi.AuiMDIClientWindow) \
+               or isinstance(self._frame, tabmdi.AuiMDIParentFrame):
+                # for MDI parent frames, this event must not
+                # be "skipped".  In other words, the parent frame
+                # must not be allowed to resize the client window
+                # after we are finished processing sizing changes
+                return
+
+        if not skipped:
+            event.Skip()
+
+        # For the snap to screen...
+        self.OnMove(None)
+        
+
+    def OnFindManager(self, event):
+        """
+        Handles the ``EVT_AUI_FIND_MANAGER`` event for L{AuiManager}.
+
+        :param `event`: a L{AuiManagerEvent} event to be processed.
+        """
+        
+        # Initialize to None
+        event.SetManager(None)
+        
+        if not self._frame:
+            return
+        
+        # See it this window wants to overwrite
+        self._frame.ProcessEvent(event)
+
+        # if no, it must be us
+        if not event.GetManager():
+           event.SetManager(self)
+       
+
+    def OnSetCursor(self, event):
+        """
+        Handles the ``wx.EVT_SET_CURSOR`` event for L{AuiManager}.
+
+        :param `event`: a `wx.SetCursorEvent` to be processed.
+        """
+        
+        # determine cursor
+        part = self.HitTest(event.GetX(), event.GetY())
+        cursor = wx.NullCursor
+
+        if part:
+            if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
+
+                if not self.CheckMovableSizer(part):
+                    return
+                
+                if part.orientation == wx.VERTICAL:
+                    cursor = wx.StockCursor(wx.CURSOR_SIZEWE)
+                else:
+                    cursor = wx.StockCursor(wx.CURSOR_SIZENS)
+            
+            elif part.type == AuiDockUIPart.typeGripper:
+                cursor = wx.StockCursor(wx.CURSOR_SIZING)
+
+        event.SetCursor(cursor)
+
+
+    def UpdateButtonOnScreen(self, button_ui_part, event):
+        """
+        Updates/redraws the UI part containing a pane button.
+
+        :param `button_ui_part`: the UI part the button belongs to;
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        hit_test = self.HitTest(*event.GetPosition())
+
+        if not hit_test or not button_ui_part:
+            return
+    
+        state = AUI_BUTTON_STATE_NORMAL
+        
+        if hit_test == button_ui_part:
+            if event.LeftDown():
+                state = AUI_BUTTON_STATE_PRESSED
+            else:
+                state = AUI_BUTTON_STATE_HOVER
+        else:
+            if event.LeftDown():
+                state = AUI_BUTTON_STATE_HOVER
+        
+        # now repaint the button with hover state
+        cdc = wx.ClientDC(self._frame)
+
+        # if the frame has a toolbar, the client area
+        # origin will not be (0,0).
+        pt = self._frame.GetClientAreaOrigin()
+        if pt.x != 0 or pt.y != 0:
+            cdc.SetDeviceOrigin(pt.x, pt.y)
+
+        if hit_test.pane:        
+            self._art.DrawPaneButton(cdc, self._frame,
+                      button_ui_part.button.button_id,
+                      state,
+                      button_ui_part.rect, hit_test.pane)
+
+
+    def OnLeftDown(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_DOWN`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        part = self.HitTest(*event.GetPosition())
+
+        if not part:
+            event.Skip()
+            return
+        
+        self._currentDragItem = -1
+        
+        if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
+        
+            if not self.CheckMovableSizer(part):
+                return
+
+            self._action = actionResize
+            self._action_part = part
+            self._action_pane = None
+            self._action_rect = wx.Rect()
+            self._action_start = wx.Point(event.GetX(), event.GetY())
+            self._action_offset = wx.Point(event.GetX() - part.rect.x,
+                                           event.GetY() - part.rect.y)
+
+            # draw the resize hint
+            rect = wx.RectPS(self._frame.ClientToScreen(part.rect.GetPosition()),
+                             part.rect.GetSize())
+
+            self._action_rect = wx.Rect(*rect)
+
+            if not AuiManager_HasLiveResize(self):
+                if wx.Platform == "__WXMAC__":
+                    dc = wx.ClientDC(self._frame)
+                else:
+                    dc = wx.ScreenDC()
+                    
+                DrawResizeHint(dc, rect)
+
+            self._frame.CaptureMouse()
+        
+        elif part.type == AuiDockUIPart.typePaneButton:
+            if self.IsPaneButtonVisible(part):
+                self._action = actionClickButton
+                self._action_part = part
+                self._action_pane = None
+                self._action_start = wx.Point(*event.GetPosition())
+                self._frame.CaptureMouse()
+
+                self.RefreshButton(part)
+        
+        elif part.type in [AuiDockUIPart.typeCaption, AuiDockUIPart.typeGripper]:
+
+            # if we are managing a AuiFloatingFrame window, then
+            # we are an embedded AuiManager inside the AuiFloatingFrame.
+            # We want to initiate a toolbar drag in our owner manager
+            if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
+                rootManager = GetManager(part.pane.window)
+            else:
+                rootManager = self
+
+            offset = wx.Point(event.GetX() - part.rect.x, event.GetY() - part.rect.y)
+            rootManager.OnGripperClicked(part.pane.window, event.GetPosition(), offset)
+        
+        if wx.Platform != "__WXMAC__":
+            event.Skip()
+
+
+    def OnLeftDClick(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_DCLICK`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        part = self.HitTest(event.GetX(), event.GetY())
+
+        if part and part.type == AuiDockUIPart.typeCaption:
+            if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
+                rootManager = GetManager(part.pane.window)
+            else:
+                rootManager = self
+                
+            rootManager.OnCaptionDoubleClicked(part.pane.window)
+            
+        elif part and part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
+            # Handles double click on AuiNotebook sashes to unsplit
+            sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+            for child in part.cont_sizer.GetChildren():
+                if child.IsSizer():
+                    win = child.GetSizer().GetContainingWindow()
+                    if isinstance(win, auibook.AuiNotebook):
+                        win.UnsplitDClick(part, sash_size, event.GetPosition())
+                        break
+                
+        event.Skip()
+
+
+    def DoEndResizeAction(self, event):
+        """
+        Ends a resize action, or for live update, resizes the sash.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        clientPt = event.GetPosition()
+        screenPt = self._frame.ClientToScreen(clientPt)
+
+        return self.RestrictResize(clientPt, screenPt, createDC=False)
+
+
+    def RestrictResize(self, clientPt, screenPt, createDC):
+        """ Common method between L{DoEndResizeAction} and L{OnLeftUp_Resize}. """
+
+        dock = self._action_part.dock
+        pane = self._action_part.pane
+
+        if createDC:
+            if wx.Platform == "__WXMAC__":
+                dc = wx.ClientDC(self._frame)
+            else:
+                dc = wx.ScreenDC()
+
+            DrawResizeHint(dc, self._action_rect)
+            self._action_rect = wx.Rect()
+        
+        newPos = clientPt - self._action_offset
+
+        if self._action_part.type == AuiDockUIPart.typeDockSizer:
+            minPix, maxPix = self.CalculateDockSizerLimits(dock)
+        else:
+            if not self._action_part.pane:
+                return
+            minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
+
+        if self._action_part.orientation == wx.HORIZONTAL:
+            newPos.y = Clip(newPos.y, minPix, maxPix)
+        else:
+            newPos.x = Clip(newPos.x, minPix, maxPix)
+
+        if self._action_part.type == AuiDockUIPart.typeDockSizer:
+        
+            partnerDock = self.GetPartnerDock(dock)
+            sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
+            new_dock_size = 0
+            direction = dock.dock_direction
+
+            if direction == AUI_DOCK_LEFT:
+                new_dock_size = newPos.x - dock.rect.x
+
+            elif direction == AUI_DOCK_TOP:
+                new_dock_size = newPos.y - dock.rect.y
+
+            elif direction == AUI_DOCK_RIGHT:
+                new_dock_size = dock.rect.x + dock.rect.width - newPos.x - sash_size
+
+            elif direction == AUI_DOCK_BOTTOM:
+                new_dock_size = dock.rect.y + dock.rect.height - newPos.y - sash_size
+
+            deltaDockSize = new_dock_size - dock.size
+
+            if partnerDock:
+                if deltaDockSize > partnerDock.size - sash_size:
+                    deltaDockSize = partnerDock.size - sash_size
+
+                partnerDock.size -= deltaDockSize
+            
+            dock.size += deltaDockSize
+            self.Update()
+        
+        else:
+        
+            # determine the new pixel size that the user wants
+            # this will help us recalculate the pane's proportion
+            if dock.IsHorizontal():
+                oldPixsize = pane.rect.width
+                newPixsize = oldPixsize + newPos.x - self._action_part.rect.x
+                    
+            else:            
+                oldPixsize = pane.rect.height
+                newPixsize = oldPixsize + newPos.y - self._action_part.rect.y
+                                
+            totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
+            partnerPane = self.GetPartnerPane(dock, pane)
+
+            # prevent division by zero
+            if totalPixsize <= 0 or totalProportion <= 0 or not partnerPane:
+                return
+
+            # adjust for the surplus
+            while (oldPixsize > 0 and totalPixsize > 10 and \
+                  oldPixsize*totalProportion/totalPixsize < pane.dock_proportion):
+            
+                totalPixsize -= 1
+
+            # calculate the new proportion of the pane
+            
+            newProportion = newPixsize*totalProportion/totalPixsize
+            newProportion = Clip(newProportion, 1, totalProportion)
+            deltaProp = newProportion - pane.dock_proportion
+
+            if partnerPane.dock_proportion - deltaProp < 1:
+                deltaProp = partnerPane.dock_proportion - 1
+                newProportion = pane.dock_proportion + deltaProp
+            
+            # borrow the space from our neighbor pane to the
+            # right or bottom (depending on orientation)
+            partnerPane.dock_proportion -= deltaProp
+            pane.dock_proportion = newProportion
+
+            self.Update()
+        
+        return True
+    
+
+    def OnLeftUp(self, event):
+        """
+        Handles the ``wx.EVT_LEFT_UP`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        if self._action == actionResize:
+##            self._frame.Freeze()
+            self.OnLeftUp_Resize(event)
+##            self._frame.Thaw()
+        
+        elif self._action == actionClickButton:
+            self.OnLeftUp_ClickButton(event)
+        
+        elif self._action == actionDragFloatingPane:
+            self.OnLeftUp_DragFloatingPane(event)
+        
+        elif self._action == actionDragToolbarPane:
+            self.OnLeftUp_DragToolbarPane(event)
+            
+        else:
+            event.Skip()        
+
+        if self._frame.HasCapture():
+            self._frame.ReleaseMouse()
+            
+        self._action = actionNone
+
+
+    def OnMotion(self, event):
+        """
+        Handles the ``wx.EVT_MOTION`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        if self._action == actionResize:
+            self.OnMotion_Resize(event)
+        
+        elif self._action == actionClickCaption:
+            self.OnMotion_ClickCaption(event)
+        
+        elif self._action == actionDragFloatingPane:
+            self.OnMotion_DragFloatingPane(event)
+        
+        elif self._action == actionDragToolbarPane:
+            self.OnMotion_DragToolbarPane(event)
+        
+        else:
+            self.OnMotion_Other(event)
+                        
+    
+    def OnLeaveWindow(self, event):
+        """
+        Handles the ``wx.EVT_LEAVE_WINDOW`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        if self._hover_button:
+            self.RefreshButton(self._hover_button)
+            self._hover_button = None
+
+
+    def OnCaptureLost(self, event):
+        """
+        Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MouseCaptureLostEvent` to be processed.
+        """
+        
+        # cancel the operation in progress, if any
+        if self._action != actionNone:
+            self._action = actionNone
+            self.HideHint()
+
+
+    def OnHintFadeTimer(self, event):
+        """
+        Handles the ``wx.EVT_TIMER`` event for L{AuiManager}.
+
+        :param `event`: a `wx.TimerEvent` to be processed.
+        """
+
+        if not self._hint_window or self._hint_fadeamt >= self._hint_fademax:
+            self._hint_fadetimer.Stop()
+            return
+
+        self._hint_fadeamt += 4
+        self._hint_window.SetTransparent(self._hint_fadeamt)
+
+
+    def OnMove(self, event):
+        """
+        Handles the ``wx.EVT_MOVE`` event for L{AuiManager}.
+
+        :param `event`: a `wx.MoveEvent` to be processed.
+        """
+
+        if event is not None:
+            event.Skip()
+
+        if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
+            return
+
+        docked, hAlign, vAlign, monitor = self._is_docked
+        if docked:
+            self.Snap()
+
+        for pane in self._panes:
+            if pane.IsSnappable():
+                if pane.IsFloating() and pane.IsShown():
+                    self.SnapPane(pane, pane.floating_pos, pane.floating_size, True)
+        
+
+    def OnSysColourChanged(self, event):
+        """
+        Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for L{AuiManager}.
+
+        :param `event`: a `wx.SysColourChangedEvent` to be processed.
+        """
+        
+        # This event is probably triggered by a theme change 
+        # so we have to re-init the art provider.
+        if self._art:
+            self._art.Init()
+
+        if self._frame:
+            self.Update()
+            self._frame.Refresh()
+            
+
+    def OnChildFocus(self, event):
+        """
+        Handles the ``wx.EVT_CHILD_FOCUS`` event for L{AuiManager}.
+
+        :param `event`: a `wx.ChildFocusEvent` to be processed.
+        """
+
+        # when a child pane has it's focus set, we should change the 
+        # pane's active state to reflect this. (this is only true if 
+        # active panes are allowed by the owner)
+
+        window = event.GetWindow()
+        if isinstance(window, wx.Dialog):
+            # Ignore EVT_CHILD_FOCUS events originating from dialogs not
+            # managed by AUI
+            rootManager = None
+        elif isinstance(window.GetParent(), AuiFloatingFrame):
+            rootManager = GetManager(window)
+        else:
+            rootManager = self
+                
+        if rootManager:
+            rootManager.ActivatePane(window)
+            
+        event.Skip()
+
+
+    def OnMotion_ClickCaption(self, event):
+        """
+        Sub-handler for the L{OnMotion} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        clientPt = event.GetPosition()
+        screenPt = self._frame.ClientToScreen(clientPt)
+
+        drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X)
+        drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y)
+
+        if not self._action_pane:
+            return
+
+        # we need to check if the mouse is now being dragged
+        if not (abs(clientPt.x - self._action_start.x) > drag_x_threshold or \
+                abs(clientPt.y - self._action_start.y) > drag_y_threshold):
+        
+            return
+        
+        # dragged -- we need to change the mouse action to 'drag'
+        if self._action_pane.IsToolbar():
+            self._action = actionDragToolbarPane
+            self._action_window = self._action_pane.window
+        
+        elif self._action_pane.IsFloatable() and self._agwFlags & AUI_MGR_ALLOW_FLOATING:
+
+            e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, self._action_pane, canVeto=True)
+            if e.GetVeto():
+                return
+            
+            self._action = actionDragFloatingPane
+
+            # set initial float position
+            self._action_pane.floating_pos = screenPt - self._action_offset
+
+            # float the window
+            if self._action_pane.IsMaximized():
+                self.RestorePane(self._action_pane)
+                
+            self._action_pane.Hide()
+            self._action_pane.Float()
+            if wx.Platform == "__WXGTK__":
+                self._action_pane.Show()
+
+            e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, self._action_pane, canVeto=False)
+
+            if not self._action_pane.frame:
+                self.Update()
+
+            self._action_window = self._action_pane.window
+
+            # adjust action offset for window frame
+            windowPt = self._action_pane.frame.GetRect().GetTopLeft()
+            originPt = self._action_pane.frame.ClientToScreen(wx.Point())
+            self._toolbar_action_offset = originPt - windowPt
+            
+            if self._agwFlags & AUI_MGR_USE_NATIVE_MINIFRAMES:
+                originPt = windowPt + wx.Point(3, 3)
+                
+            self._action_offset += originPt - windowPt
+
+            # action offset is used here to make it feel "natural" to the user
+            # to drag a docked pane and suddenly have it become a floating frame.
+            # Sometimes, however, the offset where the user clicked on the docked
+            # caption is bigger than the width of the floating frame itself, so
+            # in that case we need to set the action offset to a sensible value
+            frame_size = self._action_pane.frame.GetSize()
+            if self._action_offset.x > frame_size.x * 2 / 3:
+                self._action_offset.x = frame_size.x / 2
+            if self._action_offset.y > frame_size.y * 2 / 3:
+                self._action_offset.y = frame_size.y / 2
+
+            self.OnMotion_DragFloatingPane(event)
+            if wx.Platform != "__WXGTK__":
+                self._action_pane.Show()
+                
+            self.Update()
+
+
+    def OnMotion_Resize(self, event):
+        """
+        Sub-handler for the L{OnMotion} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        if AuiManager_HasLiveResize(self):
+            if self._currentDragItem != -1:
+                self._action_part = self._uiparts[self._currentDragItem]
+            else:
+                self._currentDragItem = self._uiparts.index(self._action_part)
+
+            if self._frame.HasCapture():
+                self._frame.ReleaseMouse()
+                
+            self.DoEndResizeAction(event)
+            self._frame.CaptureMouse()
+            return
+
+        if not self._action_part or not self._action_part.dock or not self._action_part.orientation:
+            return
+
+        clientPt = event.GetPosition()
+        screenPt = self._frame.ClientToScreen(clientPt)
+                    
+        dock = self._action_part.dock
+        pos = self._action_part.rect.GetPosition()
+
+        if self._action_part.type == AuiDockUIPart.typeDockSizer:
+            minPix, maxPix = self.CalculateDockSizerLimits(dock)
+        else:
+            if not self._action_part.pane:
+                return
+            
+            pane = self._action_part.pane
+            minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
+
+        if self._action_part.orientation == wx.HORIZONTAL:
+            pos.y = Clip(clientPt.y - self._action_offset.y, minPix, maxPix)
+        else:
+            pos.x = Clip(clientPt.x - self._action_offset.x, minPix, maxPix)
+
+        hintrect = wx.RectPS(self._frame.ClientToScreen(pos), self._action_part.rect.GetSize())
+
+        if hintrect != self._action_rect:
+        
+            if wx.Platform == "__WXMAC__":
+                dc = wx.ClientDC(self._frame)
+            else:
+                dc = wx.ScreenDC()
+
+            DrawResizeHint(dc, self._action_rect)
+            DrawResizeHint(dc, hintrect)
+            self._action_rect = wx.Rect(*hintrect)
+                
+
+    def OnLeftUp_Resize(self, event):
+        """
+        Sub-handler for the L{OnLeftUp} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        if self._currentDragItem != -1 and AuiManager_HasLiveResize(self):
+            self._action_part = self._uiparts[self._currentDragItem]
+
+            if self._frame.HasCapture():
+                self._frame.ReleaseMouse()
+                
+            self.DoEndResizeAction(event)
+            self._currentDragItem = -1
+            return
+            
+        if not self._action_part or not self._action_part.dock:
+            return
+
+        clientPt = event.GetPosition()
+        screenPt = self._frame.ClientToScreen(clientPt)
+
+        return self.RestrictResize(clientPt, screenPt, createDC=True)
+        
+
+    def OnLeftUp_ClickButton(self, event):
+        """
+        Sub-handler for the L{OnLeftUp} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        self._hover_button = None
+
+        if self._action_part:
+            self.RefreshButton(self._action_part)
+
+            # make sure we're still over the item that was originally clicked
+            if self._action_part == self.HitTest(*event.GetPosition()):
+            
+                # fire button-click event
+                e = AuiManagerEvent(wxEVT_AUI_PANE_BUTTON)
+                e.SetManager(self)
+                e.SetPane(self._action_part.pane)
+                e.SetButton(self._action_part.button.button_id)
+                self.ProcessMgrEvent(e)
+        
+
+    def CheckPaneMove(self, pane):
+        """
+        Checks if a pane has moved by a visible amount.
+
+        :param `pane`: an instance of L{AuiPaneInfo}.
+        """
+
+        win_rect = pane.frame.GetRect()
+        win_rect.x, win_rect.y = pane.floating_pos
+        
+        if win_rect == self._last_rect:
+            return False
+
+        # skip the first move event
+        if self._last_rect.IsEmpty():
+            self._last_rect = wx.Rect(*win_rect)
+            return False
+
+        # skip if moving too fast to avoid massive redraws and
+        # jumping hint windows
+        if abs(win_rect.x - self._last_rect.x) > 10 or \
+           abs(win_rect.y - self._last_rect.y) > 10:
+            self._last_rect = wx.Rect(*win_rect)
+            return False
+
+        return True        
+        
+
+    def OnMotion_DragFloatingPane(self, eventOrPt):
+        """
+        Sub-handler for the L{OnMotion} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        isPoint = False
+        if isinstance(eventOrPt, wx.Point):
+            clientPt = self._frame.ScreenToClient(eventOrPt)
+            screenPt = wx.Point(*eventOrPt)
+            isPoint = True
+        else:
+            clientPt = eventOrPt.GetPosition()
+            screenPt = self._frame.ClientToScreen(clientPt)
+        
+        framePos = wx.Point()
+        
+        # try to find the pane
+        pane = self.GetPane(self._action_window)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        # update floating position
+        if pane.IsFloating():
+            diff = pane.floating_pos - (screenPt - self._action_offset)
+            pane.floating_pos = screenPt - self._action_offset
+
+        framePos = pane.floating_pos
+
+        # Move the pane window
+        if pane.frame:
+
+            if diff.x != 0 or diff.y != 0:
+                if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
+                    # return
+                    # HACK: Terrible hack on wxMSW (!)
+                    pane.frame.SetTransparent(254)
+                            
+                self._from_move = True
+                pane.frame.Move(pane.floating_pos)
+                self._from_move = False
+
+            if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
+                pane.frame.SetTransparent(150)
+
+        # calculate the offset from the upper left-hand corner
+        # of the frame to the mouse pointer
+        action_offset = screenPt - framePos
+
+        # is the pane dockable?
+        if not self.CanDockPanel(pane):
+            self.HideHint()
+            ShowDockingGuides(self._guides, False)
+            return
+        
+        for paneInfo in self._panes:
+        
+            if not paneInfo.IsDocked() or not paneInfo.IsShown():
+                continue
+            if paneInfo.IsToolbar() or paneInfo.IsNotebookControl():
+                continue
+            if paneInfo.IsMaximized():
+                continue
+
+            if paneInfo.IsNotebookPage():
+            
+                notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
+
+                if not notebookRoot or not notebookRoot.IsDocked():
+                    continue
+            
+            rc = paneInfo.window.GetScreenRect()
+            if rc.Contains(screenPt):
+                if rc.height < 20 or rc.width < 20:
+                    return
+                
+                self.UpdateDockingGuides(paneInfo)
+                ShowDockingGuides(self._guides, True)
+                break
+
+        self.DrawHintRect(pane.window, clientPt, action_offset)
+
+
+    def OnLeftUp_DragFloatingPane(self, eventOrPt):
+        """
+        Sub-handler for the L{OnLeftUp} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+
+        if isinstance(eventOrPt, wx.Point):
+            clientPt = self._frame.ScreenToClient(eventOrPt)
+            screenPt = wx.Point(*eventOrPt)
+        else:
+            clientPt = eventOrPt.GetPosition()
+            screenPt = self._frame.ClientToScreen(clientPt)
+
+        # try to find the pane
+        paneInfo = self.GetPane(self._action_window)
+        if not paneInfo.IsOk():
+            raise Exception("Pane window not found")
+
+        ret = False
+        
+        if paneInfo.frame:
+        
+            # calculate the offset from the upper left-hand corner
+            # of the frame to the mouse pointer
+            framePos = paneInfo.frame.GetPosition()
+            action_offset = screenPt - framePos
+
+            # is the pane dockable?
+            if self.CanDockPanel(paneInfo):
+                # do the drop calculation
+                indx = self._panes.index(paneInfo)
+                ret, paneInfo = self.DoDrop(self._docks, self._panes, paneInfo, clientPt, action_offset)
+
+                if ret:
+                    e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
+                    if e.GetVeto():
+                        self.HideHint()
+                        ShowDockingGuides(self._guides, False)
+                        return
+
+                    e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
+
+                    if self._agwFlags & AUI_MGR_SMOOTH_DOCKING:
+                        self.SmoothDock(paneInfo)
+
+                self._panes[indx] = paneInfo
+            
+        # if the pane is still floating, update it's floating
+        # position (that we store)
+        if paneInfo.IsFloating():
+            paneInfo.floating_pos = paneInfo.frame.GetPosition()
+            if paneInfo.frame._transparent != paneInfo.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
+                paneInfo.frame.SetTransparent(paneInfo.transparent)
+                paneInfo.frame._transparent = paneInfo.transparent
+        
+        elif self._has_maximized:
+            self.RestoreMaximizedPane()
+        
+        # reorder for dropping to a new notebook
+        # (caution: this code breaks the reference!)
+        tempPaneInfo = self.CopyTarget(paneInfo)
+        self._panes.remove(paneInfo)
+        self._panes.append(tempPaneInfo)
+
+        if ret:
+            self.Update()
+
+        self.HideHint()
+        ShowDockingGuides(self._guides, False)
+
+
+    def OnMotion_DragToolbarPane(self, eventOrPt):
+        """
+        Sub-handler for the L{OnMotion} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        isPoint = False
+        if isinstance(eventOrPt, wx.Point):
+            clientPt = self._frame.ScreenToClient(eventOrPt)
+            screenPt = wx.Point(*eventOrPt)
+            isPoint = True
+        else:
+            clientPt = eventOrPt.GetPosition()
+            screenPt = self._frame.ClientToScreen(clientPt)
+
+        pane = self.GetPane(self._action_window)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        pane.state |= AuiPaneInfo.actionPane
+        indx = self._panes.index(pane)
+
+        ret = False
+        wasFloating = pane.IsFloating()
+        # is the pane dockable?
+        if self.CanDockPanel(pane):
+            # do the drop calculation
+            ret, pane = self.DoDrop(self._docks, self._panes, pane, clientPt, self._action_offset)
+        
+        # update floating position
+        if pane.IsFloating():
+            pane.floating_pos = screenPt - self._toolbar_action_offset
+
+        # move the pane window
+        if pane.frame:
+            if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
+                # return
+                # HACK: Terrible hack on wxMSW (!)
+                pane.frame.SetTransparent(254)
+
+            self._from_move = True
+            pane.frame.Move(pane.floating_pos)
+            self._from_move = False
+                
+            if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
+                pane.frame.SetTransparent(150)
+
+        self._panes[indx] = pane
+        if ret and wasFloating != pane.IsFloating() or (ret and not wasFloating):
+            wx.CallAfter(self.Update)
+
+        # when release the button out of the window.
+        # TODO: a better fix is needed.
+
+        if _VERSION_STRING < "2.9":
+            leftDown = wx.GetMouseState().LeftDown()
+        else:
+            leftDown = wx.GetMouseState().LeftIsDown()
+        
+        if not leftDown:
+            self._action = actionNone
+            self.OnLeftUp_DragToolbarPane(eventOrPt)
+
+
+    def OnMotion_Other(self, event):
+        """
+        Sub-handler for the L{OnMotion} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        part = self.HitTest(*event.GetPosition())
+
+        if part and part.type == AuiDockUIPart.typePaneButton \
+           and self.IsPaneButtonVisible(part):
+            if part != self._hover_button:
+            
+                if self._hover_button:
+                    self.RefreshButton(self._hover_button)
+
+                self._hover_button = part
+                self.RefreshButton(part)
+            
+        else:
+        
+            if self._hover_button:
+                self.RefreshButton(self._hover_button)
+            else:
+                event.Skip()
+
+            self._hover_button = None
+        
+        
+    def OnLeftUp_DragToolbarPane(self, eventOrPt):
+        """
+        Sub-handler for the L{OnLeftUp} event.
+
+        :param `event`: a `wx.MouseEvent` to be processed.
+        """
+        
+        isPoint = False
+        if isinstance(eventOrPt, wx.Point):
+            clientPt = self._frame.ScreenToClient(eventOrPt)
+            screenPt = wx.Point(*eventOrPt)
+            isPoint = True
+        else:
+            clientPt = eventOrPt.GetPosition()
+            screenPt = self._frame.ClientToScreen(clientPt)
+
+        # try to find the pane
+        pane = self.GetPane(self._action_window)
+        if not pane.IsOk():
+            raise Exception("Pane window not found")
+
+        if pane.IsFloating():
+            pane.floating_pos = pane.frame.GetPosition()
+            if pane.frame._transparent != pane.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
+                pane.frame.SetTransparent(pane.transparent)
+                pane.frame._transparent = pane.transparent
+        
+        # save the new positions
+        docks = FindDocks(self._docks, pane.dock_direction, pane.dock_layer, pane.dock_row)
+        if len(docks) == 1:
+            dock = docks[0]
+            pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
+
+            for i in xrange(len(dock.panes)):
+                dock.panes[i].dock_pos = pane_positions[i]
+        
+        pane.state &= ~AuiPaneInfo.actionPane
+        self.Update()
+
+
+    def OnPaneButton(self, event):
+        """
+        Handles the ``EVT_AUI_PANE_BUTTON`` event for L{AuiManager}.
+
+        :param `event`: a L{AuiManagerEvent} event to be processed.
+        """
+
+        if not event.pane:
+            raise Exception("Pane Info passed to AuiManager.OnPaneButton must be non-null")
+
+        pane = event.pane
+
+        if event.button == AUI_BUTTON_CLOSE:
+
+            if isinstance(pane.window.GetParent(), AuiFloatingFrame):
+                rootManager = GetManager(pane.window)
+            else:
+                rootManager = self
+            
+            if rootManager != self:
+                self._frame.Close()
+                return
+
+            # fire pane close event
+            e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
+            e.SetManager(self)
+            e.SetPane(event.pane)
+            self.ProcessMgrEvent(e)
+
+            if not e.GetVeto():
+            
+                # close the pane, but check that it
+                # still exists in our pane array first
+                # (the event handler above might have removed it)
+
+                check = self.GetPane(pane.window)
+                if check.IsOk():                
+                    self.ClosePane(pane)
+                
+                self.Update()
+
+        # mn this performs the minimizing of a pane
+        elif event.button == AUI_BUTTON_MINIMIZE:
+            e = AuiManagerEvent(wxEVT_AUI_PANE_MINIMIZE)
+            e.SetManager(self)
+            e.SetPane(event.pane)
+            self.ProcessMgrEvent(e)
+
+            if not e.GetVeto():
+                self.MinimizePane(pane)
+    
+        elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and not pane.IsMaximized():
+        
+            # fire pane close event
+            e = AuiManagerEvent(wxEVT_AUI_PANE_MAXIMIZE)
+            e.SetManager(self)
+            e.SetPane(event.pane)
+            self.ProcessMgrEvent(e)
+
+            if not e.GetVeto():
+            
+                self.MaximizePane(pane)
+                self.Update()
+            
+        elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and pane.IsMaximized():
+        
+            # fire pane close event
+            e = AuiManagerEvent(wxEVT_AUI_PANE_RESTORE)
+            e.SetManager(self)
+            e.SetPane(event.pane)
+            self.ProcessMgrEvent(e)
+
+            if not e.GetVeto():
+            
+                self.RestorePane(pane)
+                self.Update()
+            
+        elif event.button == AUI_BUTTON_PIN:
+        
+            if self._agwFlags & AUI_MGR_ALLOW_FLOATING and pane.IsFloatable():
+                e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, pane, canVeto=True)
+                if e.GetVeto():
+                    return
+
+                pane.Float()
+                e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, pane, canVeto=False)
+
+            self.Update()
+
+
+    def MinimizePane(self, paneInfo):
+        """
+        Minimizes a pane in a newly and automatically created L{AuiToolBar}.
+
+        Clicking on the minimize button causes a new L{AuiToolBar} to be created
+        and added to the frame manager (currently the implementation is such that
+        panes at West will have a toolbar at the right, panes at South will have
+        toolbars at the bottom etc...) and the pane is hidden in the manager.
+        
+        Clicking on the restore button on the newly created toolbar will result in the
+        toolbar being removed and the original pane being restored.
+
+        :param `paneInfo`: a L{AuiPaneInfo} instance for the pane to be minimized.
+        """
+        
+        if not paneInfo.IsToolbar():
+
+            if paneInfo.IsMinimized():
+                # We are already minimized
+                return
+            
+            # Basically the idea is this.
+            #
+            # 1) create a toolbar, with a restore button 
+            #
+            # 2) place the new toolbar in the toolbar area representative of the location of the pane 
+            #  (NORTH/SOUTH/EAST/WEST, central area always to the right)
+            #
+            # 3) Hide the minimizing pane 
+
+
+            # personalize the toolbar style
+            tbStyle = AUI_TB_DEFAULT_STYLE
+            posMask = paneInfo.minimize_mode & AUI_MINIMIZE_POS_MASK
+            captMask = paneInfo.minimize_mode & AUI_MINIMIZE_CAPT_MASK
+            dockDirection = paneInfo.dock_direction
+            if captMask != 0:
+                tbStyle |= AUI_TB_TEXT
+            if posMask == AUI_MINIMIZE_POS_SMART:
+                if paneInfo.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
+                    tbStyle |= AUI_TB_HORZ_LAYOUT
+
+                elif paneInfo.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
+                    tbStyle |= AUI_TB_VERTICAL
+                    if captMask == AUI_MINIMIZE_CAPT_SMART:
+                        tbStyle |= AUI_TB_CLOCKWISE
+                    
+            elif posMask in [AUI_MINIMIZE_POS_TOP, AUI_MINIMIZE_POS_BOTTOM]:
+                tbStyle |= AUI_TB_HORZ_LAYOUT
+                if posMask == AUI_MINIMIZE_POS_TOP:
+                    dockDirection = AUI_DOCK_TOP
+                else:
+                    dockDirection = AUI_DOCK_BOTTOM
+
+            else:
+                tbStyle |= AUI_TB_VERTICAL
+                if captMask == AUI_MINIMIZE_CAPT_SMART:
+                    tbStyle |= AUI_TB_CLOCKWISE
+                if posMask == AUI_MINIMIZE_POS_LEFT:
+                    dockDirection = AUI_DOCK_LEFT
+                elif posMask == AUI_MINIMIZE_POS_RIGHT:
+                    dockDirection = AUI_DOCK_RIGHT
+                elif posMask == AUI_MINIMIZE_POS_BOTTOM:
+                    dockDirection = AUI_DOCK_BOTTOM
+
+            # Create a new toolbar
+            # give it the same name as the minimized pane with _min appended
+
+            win_rect = paneInfo.window.GetScreenRect()
+            
+            minimize_toolbar = auibar.AuiToolBar(self.GetManagedWindow(), agwStyle=tbStyle)
+            minimize_toolbar.Hide()
+            minimize_toolbar.SetToolBitmapSize(wx.Size(16, 16))
+
+            if paneInfo.icon and paneInfo.icon.IsOk():
+                restore_bitmap = paneInfo.icon
+            else:
+                restore_bitmap = self._art._restore_bitmap
+                
+            minimize_toolbar.AddSimpleTool(ID_RESTORE_FRAME, paneInfo.caption, restore_bitmap, "Restore " + paneInfo.caption)
+            minimize_toolbar.SetAuiManager(self)
+            minimize_toolbar.Realize()
+            toolpanelname = paneInfo.name + "_min"
+
+            if paneInfo.IsMaximized():
+                paneInfo.SetFlag(paneInfo.wasMaximized, True)
+
+            if dockDirection == AUI_DOCK_TOP:
+                self.AddPane(minimize_toolbar, AuiPaneInfo(). \
+                    Name(toolpanelname).Caption(paneInfo.caption). \
+                    ToolbarPane().Top().BottomDockable(False). \
+                    LeftDockable(False).RightDockable(False).DestroyOnClose())
+                
+            elif dockDirection == AUI_DOCK_BOTTOM:
+                self.AddPane(minimize_toolbar, AuiPaneInfo(). \
+                    Name(toolpanelname).Caption(paneInfo.caption). \
+                    ToolbarPane().Bottom().TopDockable(False). \
+                    LeftDockable(False).RightDockable(False).DestroyOnClose())
+                
+            elif dockDirection == AUI_DOCK_LEFT:
+                self.AddPane(minimize_toolbar, AuiPaneInfo(). \
+                    Name(toolpanelname).Caption(paneInfo.caption). \
+                    ToolbarPane().Left().TopDockable(False). \
+                    BottomDockable(False).RightDockable(False).DestroyOnClose())
+
+            elif dockDirection in [AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
+                self.AddPane(minimize_toolbar, AuiPaneInfo(). \
+                    Name(toolpanelname).Caption(paneInfo.caption). \
+                    ToolbarPane().Right().TopDockable(False). \
+                    LeftDockable(False).BottomDockable(False).DestroyOnClose())
+
+            arr = FindDocks(self._docks, paneInfo.dock_direction, paneInfo.dock_layer, paneInfo.dock_row)
+
+            if arr:
+                dock = arr[0]
+                paneInfo.previousDockSize = dock.size
+
+            paneInfo.previousDockPos = paneInfo.dock_pos
+            
+            # mark ourselves minimized
+            paneInfo.Minimize()
+            paneInfo.Show(False)
+            self._has_minimized = True
+            # last, hide the window
+            if paneInfo.window and paneInfo.window.IsShown():
+                paneInfo.window.Show(False)
+
+            minimize_toolbar.Show()
+            self.Update()
+            if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
+                self.AnimateDocking(win_rect, minimize_toolbar.GetScreenRect())
+
+
+    def OnRestoreMinimizedPane(self, event):
+        """
+        Handles the ``EVT_AUI_PANE_MIN_RESTORE`` event for L{AuiManager}.
+
+        :param `event`: an instance of L{AuiManagerEvent} to be processed.
+        """
+
+        self.RestoreMinimizedPane(event.pane)
+
+
+    def OnPaneDocked(self, event):
+        """
+        Handles the ``EVT_AUI_PANE_DOCKED`` event for L{AuiManager}.
+
+        :param `event`: an instance of L{AuiManagerEvent} to be processed.
+        """
+
+        event.Skip()
+        self.RemoveAutoNBCaption(event.GetPane())        
+    
+
+    def CreateNotebookBase(self, panes, paneInfo):
+        """
+        Creates an auto-notebook base from a pane, and then add that pane as a page.
+
+        :param `panes`: Set of panes to append new notebook base pane to
+        :param `paneInfo`: L{AuiPaneInfo} instance to convert to new notebook.
+        """
+
+        # Create base notebook pane ...
+        nbid = len(self._notebooks)
+
+        baseInfo = AuiPaneInfo()
+        baseInfo.SetDockPos(paneInfo).NotebookControl(nbid). \
+            CloseButton(False).SetNameFromNotebookId(). \
+            NotebookDockable(False).Floatable(paneInfo.IsFloatable())
+        baseInfo.best_size = paneInfo.best_size
+        panes.append(baseInfo)
+
+        # add original pane as tab ...
+        paneInfo.NotebookPage(nbid)
+
+    def RemoveAutoNBCaption(self, pane):
+        """
+        Removes the caption on newly created automatic notebooks.
+
+        :param `pane`: an instance of L{AuiPaneInfo} (the target notebook).
+        """
+
+        if self._agwFlags & AUI_MGR_AUTONB_NO_CAPTION == 0:
+            return False
+
+        def RemoveCaption():
+            """ Sub-function used to remove the pane caption on automatic notebooks. """
+            
+            if pane.HasNotebook(): 
+                notebook = self._notebooks[pane.notebook_id] 
+                self.GetPane(notebook).CaptionVisible(False).PaneBorder(False)                
+                self.Update() 
+
+        # it seems the notebook isnt created by this stage, so remove 
+        # the caption a moment later 
+        wx.CallAfter(RemoveCaption)
+        return True
+        
+        
+    def RestoreMinimizedPane(self, paneInfo):
+        """
+        Restores a previously minimized pane.
+
+        :param `paneInfo`: a L{AuiPaneInfo} instance for the pane to be restored.
+        """
+
+        panename = paneInfo.name
+        panename = panename[0:-4]
+        pane = self.GetPane(panename)
+
+        pane.SetFlag(pane.needsRestore, True)
+
+        if not pane.IsOk():
+            panename = paneInfo.name
+            pane = self.GetPane(panename)
+            paneInfo = self.GetPane(panename + "_min")
+            if not paneInfo.IsOk():
+                # Already minimized
+                return
+        
+        if pane.IsOk():
+            if not pane.IsMinimized():
+                return
+            
+
+            if pane.HasFlag(pane.wasMaximized):
+
+                self.SavePreviousDockSizes(pane)
+                
+
+            self.ShowPane(pane.window, True)
+            pane.Show(True)
+            self._has_minimized = False
+            pane.SetFlag(pane.optionMinimized, False)
+            paneInfo.window.Show(False)
+            self.DetachPane(paneInfo.window)
+            paneInfo.Show(False)
+            paneInfo.Hide()
+
+            self.Update()
+
+
+    def AnimateDocking(self, win_rect, pane_rect):
+        """
+        Animates the minimization/docking of a pane a la Eclipse, using a `wx.ScreenDC`
+        to draw a "moving docking rectangle" on the screen.
+
+        :param `win_rect`: the original pane screen rectangle;
+        :param `pane_rect`: the newly created toolbar/pane screen rectangle.
+
+        :note: This functionality is not available on wxMAC as this platform doesn't have
+         the ability to use `wx.ScreenDC` to draw on-screen and on Windows > Vista.
+        """
+
+        if wx.Platform == "__WXMAC__":
+            # No wx.ScreenDC on the Mac...
+            return
+        if wx.Platform == "__WXMSW__" and wx.GetOsVersion()[1] > 5:
+            # No easy way to handle this on Vista...
+            return
+
+        xstart, ystart = win_rect.x, win_rect.y
+        xend, yend = pane_rect.x, pane_rect.y
+
+        step = self.GetAnimationStep()
+        
+        wstep = int(abs(win_rect.width - pane_rect.width)/step)
+        hstep = int(abs(win_rect.height - pane_rect.height)/step)
+        xstep = int(win_rect.x - pane_rect.x)/step
+        ystep = int(win_rect.y - pane_rect.y)/step
+        
+        dc = wx.ScreenDC()
+        dc.SetLogicalFunction(wx.INVERT)
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.SetPen(wx.LIGHT_GREY_PEN)
+        
+        for i in xrange(int(step)):
+            width, height = win_rect.width - i*wstep, win_rect.height - i*hstep
+            x, y = xstart - i*xstep, ystart - i*ystep
+            new_rect = wx.Rect(x, y, width, height)
+            dc.DrawRoundedRectangleRect(new_rect, 3)
+            wx.SafeYield()
+            wx.MilliSleep(10)
+            dc.DrawRoundedRectangleRect(new_rect, 3)
+            
+
+    def SmoothDock(self, paneInfo):
+        """
+        This method implements a smooth docking effect for floating panes, similar to
+        what the PyQT library does with its floating windows.
+
+        :param `paneInfo`: an instance of L{AuiPaneInfo}.
+
+        :note: The smooth docking effect can only be used if you set the ``AUI_MGR_SMOOTH_DOCKING``
+         style to L{AuiManager}.
+        """
+
+        if paneInfo.IsToolbar():
+            return
+
+        if not paneInfo.frame or self._hint_rect.IsEmpty():
+            return
+
+        hint_rect = self._hint_rect
+        win_rect = paneInfo.frame.GetScreenRect()
+
+        xstart, ystart = win_rect.x, win_rect.y
+        xend, yend = hint_rect.x, hint_rect.y
+
+        step = self.GetAnimationStep()/3
+
+        wstep = int((win_rect.width - hint_rect.width)/step)
+        hstep = int((win_rect.height - hint_rect.height)/step)
+        xstep = int((win_rect.x - hint_rect.x))/step
+        ystep = int((win_rect.y - hint_rect.y))/step
+
+        for i in xrange(int(step)):
+            width, height = win_rect.width - i*wstep, win_rect.height - i*hstep
+            x, y = xstart - i*xstep, ystart - i*ystep
+            new_rect = wx.Rect(x, y, width, height)
+            paneInfo.frame.SetRect(new_rect)
+            wx.MilliSleep(10)            
+        
+            
+    def SetSnapLimits(self, x, y):
+        """
+        Modifies the snap limits used when snapping the `managed_window` to the screen
+        (using L{SnapToScreen}) or when snapping the floating panes to one side of the
+        `managed_window` (using L{SnapPane}).
+
+        To change the limit after which the `managed_window` or the floating panes are
+        automatically stickled to the screen border (or to the `managed_window` side),
+        set these two variables. Default values are 15 pixels.
+    
+        :param `x`: the minimum horizontal distance below which the snap occurs;
+        :param `y`: the minimum vertical distance below which the snap occurs.
+        """
+
+        self._snap_limits = (x, y)
+        self.Snap()
+
+
+    def Snap(self):
+        """
+        Snaps the main frame to specified position on the screen.
+
+        :see: L{SnapToScreen}
+        """
+        
+        snap, hAlign, vAlign, monitor = self._is_docked
+        if not snap:
+            return
+
+        managed_window = self.GetManagedWindow()
+        snap_pos = self.GetSnapPosition()
+        wnd_pos = managed_window.GetPosition()
+        snapX, snapY = self._snap_limits
+        
+        if abs(snap_pos.x - wnd_pos.x) < snapX and abs(snap_pos.y - wnd_pos.y) < snapY:
+            managed_window.SetPosition(snap_pos)
+        
+
+    def SnapToScreen(self, snap=True, monitor=0, hAlign=wx.RIGHT, vAlign=wx.TOP):
+        """
+        Snaps the main frame to specified position on the screen.
+
+        :param `snap`: whether to snap the main frame or not;
+        :param `monitor`: the monitor display in which snapping the window;
+        :param `hAlign`: the horizontal alignment of the snapping position;
+        :param `vAlign`: the vertical alignment of the snapping position.
+        """
+        
+        if not snap:
+            self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
+            return
+
+        displayCount = wx.Display.GetCount()
+        if monitor > displayCount:
+            raise Exception("Invalid monitor selected: you only have %d monitors"%displayCount)
+
+        self._is_docked = (True, hAlign, vAlign, monitor)
+        self.GetManagedWindow().SetPosition(self.GetSnapPosition())
+        
+
+    def GetSnapPosition(self):
+        """ Returns the main frame snapping position. """
+
+        snap, hAlign, vAlign, monitor = self._is_docked
+        
+        display = wx.Display(monitor)
+        area = display.GetClientArea()
+        size = self.GetManagedWindow().GetSize()
+        
+        pos = wx.Point()
+        if hAlign == wx.LEFT:
+            pos.x = area.x
+        elif hAlign == wx.CENTER:
+            pos.x = area.x + (area.width - size.x)/2
+        else:
+            pos.x = area.x + area.width - size.x
+
+        if vAlign == wx.TOP:
+            pos.y = area.y
+        elif vAlign == wx.CENTER:
+            pos.y = area.y + (area.height - size.y)/2
+        else:
+            pos.y = area.y + area.height - size.y
+
+        return pos            
+
+
+    def GetAnimationStep(self):
+        """ Returns the animation step speed (a float) to use in L{AnimateDocking}. """
+
+        return self._animation_step
+
+
+    def SetAnimationStep(self, step):
+        """
+        Sets the animation step speed (a float) to use in L{AnimateDocking}.
+
+        :param `step`: a floating point value for the animation speed.
+        """
+
+        self._animation_step = float(step)        
+
+        
+    def RequestUserAttention(self, pane_window):
+        """
+        Requests the user attention by intermittently highlighting the pane caption.
+
+        :param `pane_window`: a `wx.Window` derived window, managed by the pane.
+        """
+                
+        # try to find the pane
+        paneInfo = self.GetPane(pane_window)
+        if not paneInfo.IsOk():
+            raise Exception("Pane window not found")
+
+        dc = wx.ClientDC(self._frame)
+
+        # if the frame is about to be deleted, don't bother
+        if not self._frame or self._frame.IsBeingDeleted():
+            return
+        
+        if not self._frame.GetSizer():
+            return
+
+        for part in self._uiparts:
+            if part.pane == paneInfo:
+                self._art.RequestUserAttention(dc, self._frame, part.pane.caption, part.rect, part.pane)
+                self._frame.RefreshRect(part.rect, True)
+                break
+
+
+    def StartPreviewTimer(self, toolbar):
+        """
+        Starts a timer for sliding in and out a minimized pane.
+
+        :param `toolbar`: the L{AuiToolBar} containing the minimized pane tool.
+        """
+
+        toolbar_pane = self.GetPane(toolbar)
+        toolbar_name = toolbar_pane.name
+        
+        pane_name = toolbar_name[0:-4]
+        
+        self._sliding_pane = self.GetPane(pane_name)
+        self._sliding_rect = toolbar.GetScreenRect()
+        self._sliding_direction = toolbar_pane.dock_direction
+        self._sliding_frame = None
+        
+        self._preview_timer.Start(1000, wx.TIMER_ONE_SHOT)
+
+
+    def StopPreviewTimer(self):
+        """ Stops a timer for sliding in and out a minimized pane. """
+
+        if self._preview_timer.IsRunning():
+            self._preview_timer.Stop()
+
+        self.SlideOut()
+        self._sliding_pane = None
+
+
+    def SlideIn(self, event):
+        """
+        Handles the ``wx.EVT_TIMER`` event for L{AuiManager}.
+
+        :param `event`: a `wx.TimerEvent` to be processed.
+
+        :note: This is used solely for sliding in and out minimized panes.
+        """
+
+        window = self._sliding_pane.window
+        self._sliding_frame = wx.MiniFrame(None, -1, title=_("Pane Preview"),
+                                           style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
+                                           wx.FRAME_NO_TASKBAR | wx.CAPTION)
+        window.Reparent(self._sliding_frame)
+        self._sliding_frame.SetSize((0, 0))
+        window.Show()
+        self._sliding_frame.Show()
+        
+        size = window.GetBestSize()
+
+        startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
+        
+        step = stopX/10
+        window_size = 0
+        
+        for i in xrange(0, stopX, step):
+            window_size = i
+            self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
+            self._sliding_frame.Refresh()
+            self._sliding_frame.Update()
+            wx.MilliSleep(10)
+
+        self._sliding_frame.SetDimensions(startX, startY, stopX, stopY)
+        self._sliding_frame.Refresh()
+        self._sliding_frame.Update()
+        
+
+    def SlideOut(self):
+        """
+        Slides out a preview of a minimized pane.
+
+        :note: This is used solely for sliding in and out minimized panes.
+        """
+
+        if not self._sliding_frame:
+            return
+
+        window = self._sliding_frame.GetChildren()[0]
+        size = window.GetBestSize()
+        
+        startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
+
+        step = stopX/10
+        window_size = 0
+        
+        for i in xrange(stopX, 0, -step):
+            window_size = i
+            self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
+            self._sliding_frame.Refresh()
+            self._sliding_frame.Update()
+            self._frame.RefreshRect(wx.Rect(startX+window_size, startY, step, stopY))
+            self._frame.Update()
+            wx.MilliSleep(10)
+
+        self._sliding_frame.SetDimensions(startX, startY, 0, stopY)
+
+        window.Hide()
+        window.Reparent(self._frame)
+
+        self._sliding_frame.Hide()
+        self._sliding_frame.Destroy()
+        self._sliding_frame = None
+        self._sliding_pane = None
+        
+
+class AuiManager_DCP(AuiManager):
+    """
+    A class similar to L{AuiManager} but with a Dummy Center Pane (**DCP**).
+    The code for this class is still flickery due to the call to `wx.CallAfter`
+    and the double-update call.
+    """
+    
+    def __init__(self, *args, **keys):
+
+        AuiManager.__init__(self, *args, **keys)
+        self.hasDummyPane = False
+        
+
+    def _createDummyPane(self):
+        """ Creates a Dummy Center Pane (**DCP**). """
+
+        if self.hasDummyPane:
+            return
+
+        self.hasDummyPane = True
+        dummy = wx.Panel(self.GetManagedWindow())
+        info = AuiPaneInfo().CenterPane().NotebookDockable(True).Name('dummyCenterPane').DestroyOnClose(True)
+        self.AddPane(dummy, info)
+
+
+    def _destroyDummyPane(self):
+        """ Destroys the Dummy Center Pane (**DCP**). """
+
+        if not self.hasDummyPane:
+            return
+        
+        self.hasDummyPane = False
+        self.ClosePane(self.GetPane('dummyCenterPane'))
+
+        
+    def Update(self):
+        """
+        This method is called after any number of changes are made to any of the
+        managed panes. L{Update} must be invoked after L{AuiManager.AddPane} or L{AuiManager.InsertPane} are
+        called in order to "realize" or "commit" the changes.
+
+        In addition, any number of changes may be made to L{AuiPaneInfo} structures
+        (retrieved with L{AuiManager.GetPane}), but to realize the changes, L{Update}
+        must be called. This construction allows pane flicker to be avoided by updating
+        the whole layout at one time.
+        """
+        
+        AuiManager.Update(self)
+
+        # check if there's already a center pane (except our dummy pane)
+        dummyCenterPane = self.GetPane('dummyCenterPane')
+        haveCenterPane = any((pane != dummyCenterPane) and (pane.dock_direction == AUI_DOCK_CENTER) and
+                             not pane.IsFloating() and pane.IsShown() for pane in self.GetAllPanes())
+        if haveCenterPane:
+            if self.hasDummyPane:
+                # there's our dummy pane and also another center pane, therefor let's remove our dummy
+                def do():
+                    self._destroyDummyPane()
+                    self.Update()
+                wx.CallAfter(do)
+        else:
+            # if we get here, there's no center pane, create our dummy
+            if not self.hasDummyPane:
+                self._createDummyPane()
+
+                
diff --git a/aui/tabart.py b/aui/tabart.py
new file mode 100644 (file)
index 0000000..60b8e01
--- /dev/null
@@ -0,0 +1,2777 @@
+"""
+Tab art provider code - a tab provider provides all drawing functionality to
+the L{AuiNotebook}. This allows the L{AuiNotebook} to have a plugable look-and-feel.
+
+By default, a L{AuiNotebook} uses an instance of this class called L{AuiDefaultTabArt}
+which provides bitmap art and a colour scheme that is adapted to the major platforms'
+look. You can either derive from that class to alter its behaviour or write a
+completely new tab art class. Call L{AuiNotebook.SetArtProvider} to make use this
+new tab art.
+"""
+
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+
+if wx.Platform == '__WXMAC__':
+    import Carbon.Appearance
+
+from aui_utilities import BitmapFromBits, StepColour, IndentPressedBitmap, ChopText
+from aui_utilities import GetBaseColour, DrawMACCloseButton, LightColour, TakeScreenShot
+from aui_utilities import CopyAttributes
+
+from aui_constants import *
+
+
+# -- GUI helper classes and functions --
+class AuiCommandCapture(wx.PyEvtHandler):
+    """ A class to handle the dropdown window menu. """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        wx.PyEvtHandler.__init__(self)        
+        self._last_id = 0
+
+
+    def GetCommandId(self):
+        """ Returns the event command identifier. """
+
+        return self._last_id 
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more suitable
+        event handler function(s).
+
+        :param `event`: the event to process.
+
+        :note: Normally, your application would not call this function: it is called
+         in the wxPython implementation to dispatch incoming user interface events
+         to the framework (and application).
+         However, you might need to call it if implementing new functionality (such as
+         a new control) where you define new event types, as opposed to allowing the
+         user to override functions.
+
+         An instance where you might actually override the L{ProcessEvent} function is where
+         you want to direct event processing to event handlers not normally noticed by
+         wxPython. For example, in the document/view architecture, documents and views
+         are potential event handlers. When an event reaches a frame, L{ProcessEvent} will
+         need to be called on the associated document and view in case event handler
+         functions are associated with these objects. 
+
+         The normal order of event table searching is as follows:
+
+         1. If the object is disabled (via a call to `SetEvtHandlerEnabled`) the function
+            skips to step (6).
+         2. If the object is a `wx.Window`, L{ProcessEvent} is recursively called on the window's 
+            `wx.Validator`. If this returns ``True``, the function exits.
+         3. wxWidgets `SearchEventTable` is called for this event handler. If this fails, the
+            base class table is tried, and so on until no more tables exist or an appropriate
+            function was found, in which case the function exits.
+         4. The search is applied down the entire chain of event handlers (usually the chain
+            has a length of one). If this succeeds, the function exits.
+         5. If the object is a `wx.Window` and the event is a `wx.CommandEvent`, L{ProcessEvent} is
+            recursively applied to the parent window's event handler. If this returns ``True``,
+            the function exits.
+         6. Finally, L{ProcessEvent} is called on the `wx.App` object.
+        """
+        
+        if event.GetEventType() == wx.wxEVT_COMMAND_MENU_SELECTED:
+            self._last_id = event.GetId()
+            return True
+        
+        if self.GetNextHandler():
+            return self.GetNextHandler().ProcessEvent(event)
+
+        return False
+    
+
+class AuiDefaultTabArt(object):
+    """
+    Tab art provider code - a tab provider provides all drawing functionality to
+    the L{AuiNotebook}. This allows the L{AuiNotebook} to have a plugable look-and-feel.
+
+    By default, a L{AuiNotebook} uses an instance of this class called L{AuiDefaultTabArt}
+    which provides bitmap art and a colour scheme that is adapted to the major platforms'
+    look. You can either derive from that class to alter its behaviour or write a
+    completely new tab art class. Call L{AuiNotebook.SetArtProvider} to make use this
+    new tab art.
+    """
+    
+    def __init__(self):
+        """ Default class constructor. """
+
+        self._normal_font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._selected_font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._selected_font.SetWeight(wx.BOLD)
+        self._measuring_font = self._selected_font
+
+        self._fixed_tab_width = 100
+        self._tab_ctrl_height = 0
+        self._buttonRect = wx.Rect()
+
+        self.SetDefaultColours()
+
+        if wx.Platform == "__WXMAC__":
+            bmp_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW)
+            self._active_close_bmp = DrawMACCloseButton(bmp_colour)
+            self._disabled_close_bmp = DrawMACCloseButton(wx.Colour(128, 128, 128))
+        else:
+            self._active_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.BLACK)
+            self._disabled_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        self._hover_close_bmp = self._active_close_bmp
+        self._pressed_close_bmp = self._active_close_bmp
+
+        self._active_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.BLACK)
+        self._disabled_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        self._active_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.BLACK)
+        self._disabled_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        self._active_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.BLACK)
+        self._disabled_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        if wx.Platform == "__WXMAC__":
+            # Get proper highlight colour for focus rectangle from the
+            # current Mac theme.  kThemeBrushFocusHighlight is
+            # available on Mac OS 8.5 and higher
+            if hasattr(wx, 'MacThemeColour'):
+                c = wx.MacThemeColour(Carbon.Appearance.kThemeBrushFocusHighlight)
+            else:
+                brush = wx.Brush(wx.BLACK)
+                brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight)
+                c = brush.GetColour()
+            self._focusPen = wx.Pen(c, 2, wx.SOLID)
+        else:
+            self._focusPen = wx.Pen(wx.BLACK, 1, wx.USER_DASH)
+            self._focusPen.SetDashes([1, 1])
+            self._focusPen.SetCap(wx.CAP_BUTT)
+            
+            
+    def SetBaseColour(self, base_colour):
+        """
+        Sets a new base colour.
+
+        :param `base_colour`: an instance of `wx.Colour`.
+        """
+        
+        self._base_colour = base_colour
+        self._base_colour_pen = wx.Pen(self._base_colour)
+        self._base_colour_brush = wx.Brush(self._base_colour)
+
+
+    def SetDefaultColours(self, base_colour=None):
+        """
+        Sets the default colours, which are calculated from the given base colour.
+
+        :param `base_colour`: an instance of `wx.Colour`. If defaulted to ``None``, a colour
+         is generated accordingly to the platform and theme.
+        """
+
+        if base_colour is None:
+            base_colour = GetBaseColour()
+
+        self.SetBaseColour( base_colour )
+        self._border_colour = StepColour(base_colour, 75)
+        self._border_pen = wx.Pen(self._border_colour)
+
+        self._background_top_colour = StepColour(self._base_colour, 90)
+        self._background_bottom_colour = StepColour(self._base_colour, 170)
+        
+        self._tab_top_colour = self._base_colour
+        self._tab_bottom_colour = wx.WHITE
+        self._tab_gradient_highlight_colour = wx.WHITE
+
+        self._tab_inactive_top_colour = self._base_colour
+        self._tab_inactive_bottom_colour = StepColour(self._tab_inactive_top_colour, 160)
+        
+        self._tab_text_colour = lambda page: page.text_colour
+        self._tab_disabled_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)
+
+
+    def Clone(self):
+        """ Clones the art object. """
+
+        art = type(self)()
+        art.SetNormalFont(self.GetNormalFont())
+        art.SetSelectedFont(self.GetSelectedFont())
+        art.SetMeasuringFont(self.GetMeasuringFont())
+
+        art = CopyAttributes(art, self)
+        return art
+
+
+    def SetAGWFlags(self, agwFlags):
+        """
+        Sets the tab art flags.
+
+        :param `agwFlags`: a combination of the following values:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by L{AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
+         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
+         ==================================== ==================================
+        
+        """
+
+        self._agwFlags = agwFlags
+
+
+    def GetAGWFlags(self):
+        """
+        Returns the tab art flags.
+
+        :see: L{SetAGWFlags} for a list of possible return values.
+        """
+
+        return self._agwFlags
+    
+            
+    def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
+        """
+        Sets the tab sizing information.
+        
+        :param `tab_ctrl_size`: the size of the tab control area;
+        :param `tab_count`: the number of tabs;
+        :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
+         to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
+        """
+        
+        self._fixed_tab_width = 100
+        minTabWidth, maxTabWidth = minMaxTabWidth
+
+        tot_width = tab_ctrl_size.x - self.GetIndentSize() - 4
+        agwFlags = self.GetAGWFlags()
+        
+        if agwFlags & AUI_NB_CLOSE_BUTTON:
+            tot_width -= self._active_close_bmp.GetWidth()
+        if agwFlags & AUI_NB_WINDOWLIST_BUTTON:
+            tot_width -= self._active_windowlist_bmp.GetWidth()
+
+        if tab_count > 0:
+            self._fixed_tab_width = tot_width/tab_count
+
+        if self._fixed_tab_width < 100:
+            self._fixed_tab_width = 100
+
+        if self._fixed_tab_width > tot_width/2:
+            self._fixed_tab_width = tot_width/2
+
+        if self._fixed_tab_width > 220:
+            self._fixed_tab_width = 220
+
+        if minTabWidth > -1:
+            self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
+        if maxTabWidth > -1:
+            self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
+
+        self._tab_ctrl_height = tab_ctrl_size.y
+    
+
+    def DrawBackground(self, dc, wnd, rect):
+        """
+        Draws the tab area background.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `rect`: the tab control rectangle.
+        """
+
+        self._buttonRect = wx.Rect()
+
+        # draw background
+        agwFlags = self.GetAGWFlags()
+        if agwFlags & AUI_NB_BOTTOM:
+            r = wx.Rect(rect.x, rect.y, rect.width+2, rect.height)
+
+        # TODO: else if (agwFlags & AUI_NB_LEFT) 
+        # TODO: else if (agwFlags & AUI_NB_RIGHT) 
+        else: #for AUI_NB_TOP
+            r = wx.Rect(rect.x, rect.y, rect.width+2, rect.height-3)
+
+        dc.GradientFillLinear(r, self._background_top_colour, self._background_bottom_colour, wx.SOUTH)
+
+        # draw base lines
+
+        dc.SetPen(self._border_pen)
+        y = rect.GetHeight()
+        w = rect.GetWidth()
+
+        if agwFlags & AUI_NB_BOTTOM:
+            dc.SetBrush(wx.Brush(self._background_bottom_colour))
+            dc.DrawRectangle(-1, 0, w+2, 4)
+
+        # TODO: else if (agwFlags & AUI_NB_LEFT) 
+        # TODO: else if (agwFlags & AUI_NB_RIGHT)
+        
+        else: # for AUI_NB_TOP
+            dc.SetBrush(self._base_colour_brush)
+            dc.DrawRectangle(-1, y-4, w+2, 4)
+
+
+    def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
+        """
+        Draws a single tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `page`: the tab control page associated with the tab;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
+        """
+
+        # if the caption is empty, measure some temporary text
+        caption = page.caption
+        if not caption:
+            caption = "Xj"
+
+        dc.SetFont(self._selected_font)
+        selected_textx, selected_texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        dc.SetFont(self._normal_font)
+        normal_textx, normal_texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        control = page.control
+
+        # figure out the size of the tab
+        tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
+                                             page.active, close_button_state, control)
+
+        tab_height = self._tab_ctrl_height - 3
+        tab_width = tab_size[0]
+        tab_x = in_rect.x
+        tab_y = in_rect.y + in_rect.height - tab_height
+
+        caption = page.caption
+
+        # select pen, brush and font for the tab to be drawn
+
+        if page.active:
+        
+            dc.SetFont(self._selected_font)
+            textx, texty = selected_textx, selected_texty
+        
+        else:
+        
+            dc.SetFont(self._normal_font)
+            textx, texty = normal_textx, normal_texty
+
+        if not page.enabled:
+            dc.SetTextForeground(self._tab_disabled_text_colour)
+            pagebitmap = page.dis_bitmap
+        else:
+            dc.SetTextForeground(self._tab_text_colour(page))
+            pagebitmap = page.bitmap
+            
+        # create points that will make the tab outline
+
+        clip_width = tab_width
+        if tab_x + clip_width > in_rect.x + in_rect.width:
+            clip_width = in_rect.x + in_rect.width - tab_x
+
+        # since the above code above doesn't play well with WXDFB or WXCOCOA,
+        # we'll just use a rectangle for the clipping region for now --
+        dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3)
+
+        border_points = [wx.Point() for i in xrange(6)]
+        agwFlags = self.GetAGWFlags()
+        
+        if agwFlags & AUI_NB_BOTTOM:
+        
+            border_points[0] = wx.Point(tab_x,             tab_y)
+            border_points[1] = wx.Point(tab_x,             tab_y+tab_height-6)
+            border_points[2] = wx.Point(tab_x+2,           tab_y+tab_height-4)
+            border_points[3] = wx.Point(tab_x+tab_width-2, tab_y+tab_height-4)
+            border_points[4] = wx.Point(tab_x+tab_width,   tab_y+tab_height-6)
+            border_points[5] = wx.Point(tab_x+tab_width,   tab_y)
+        
+        else: #if (agwFlags & AUI_NB_TOP) 
+        
+            border_points[0] = wx.Point(tab_x,             tab_y+tab_height-4)
+            border_points[1] = wx.Point(tab_x,             tab_y+2)
+            border_points[2] = wx.Point(tab_x+2,           tab_y)
+            border_points[3] = wx.Point(tab_x+tab_width-2, tab_y)
+            border_points[4] = wx.Point(tab_x+tab_width,   tab_y+2)
+            border_points[5] = wx.Point(tab_x+tab_width,   tab_y+tab_height-4)
+        
+        # TODO: else if (agwFlags & AUI_NB_LEFT) 
+        # TODO: else if (agwFlags & AUI_NB_RIGHT) 
+
+        drawn_tab_yoff = border_points[1].y
+        drawn_tab_height = border_points[0].y - border_points[1].y
+
+        if page.active:
+        
+            # draw active tab
+
+            # draw base background colour
+            r = wx.Rect(tab_x, tab_y, tab_width, tab_height)
+            dc.SetPen(self._base_colour_pen)
+            dc.SetBrush(self._base_colour_brush)
+            dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4)
+
+            # this white helps fill out the gradient at the top of the tab
+            dc.SetPen( wx.Pen(self._tab_gradient_highlight_colour) )
+            dc.SetBrush( wx.Brush(self._tab_gradient_highlight_colour) )
+            dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4)
+
+            # these two points help the rounded corners appear more antialiased
+            dc.SetPen(self._base_colour_pen)
+            dc.DrawPoint(r.x+2, r.y+1)
+            dc.DrawPoint(r.x+r.width-2, r.y+1)
+
+            # set rectangle down a bit for gradient drawing
+            r.SetHeight(r.GetHeight()/2)
+            r.x += 2
+            r.width -= 2
+            r.y += r.height
+            r.y -= 2
+
+            # draw gradient background
+            top_colour = self._tab_bottom_colour
+            bottom_colour = self._tab_top_colour
+            dc.GradientFillLinear(r, bottom_colour, top_colour, wx.NORTH)
+        
+        else:
+        
+            # draw inactive tab
+
+            r = wx.Rect(tab_x, tab_y+1, tab_width, tab_height-3)
+
+            # start the gradent up a bit and leave the inside border inset
+            # by a pixel for a 3D look.  Only the top half of the inactive
+            # tab will have a slight gradient
+            r.x += 3
+            r.y += 1
+            r.width -= 4
+            r.height /= 2
+            r.height -= 1
+
+            # -- draw top gradient fill for glossy look
+            top_colour = self._tab_inactive_top_colour
+            bottom_colour = self._tab_inactive_bottom_colour
+            dc.GradientFillLinear(r, bottom_colour, top_colour, wx.NORTH)
+
+            r.y += r.height
+            r.y -= 1
+
+            # -- draw bottom fill for glossy look
+            top_colour = self._tab_inactive_bottom_colour
+            bottom_colour = self._tab_inactive_bottom_colour
+            dc.GradientFillLinear(r, top_colour, bottom_colour, wx.SOUTH)
+        
+        # draw tab outline
+        dc.SetPen(self._border_pen)
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.DrawPolygon(border_points)
+
+        # there are two horizontal grey lines at the bottom of the tab control,
+        # this gets rid of the top one of those lines in the tab control
+        if page.active:
+        
+            if agwFlags & AUI_NB_BOTTOM:
+                dc.SetPen(wx.Pen(self._background_bottom_colour))
+                
+            # TODO: else if (agwFlags & AUI_NB_LEFT) 
+            # TODO: else if (agwFlags & AUI_NB_RIGHT) 
+            else: # for AUI_NB_TOP
+                dc.SetPen(self._base_colour_pen)
+                
+            dc.DrawLine(border_points[0].x+1,
+                        border_points[0].y,
+                        border_points[5].x,
+                        border_points[5].y)
+        
+        text_offset = tab_x + 8
+        close_button_width = 0
+
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            close_button_width = self._active_close_bmp.GetWidth()
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                text_offset += close_button_width - 5
+                
+        bitmap_offset = 0
+        
+        if pagebitmap.IsOk():
+        
+            bitmap_offset = tab_x + 8
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
+                bitmap_offset += close_button_width - 5
+
+            # draw bitmap
+            dc.DrawBitmap(pagebitmap,
+                          bitmap_offset,
+                          drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2),
+                          True)
+
+            text_offset = bitmap_offset + pagebitmap.GetWidth()
+            text_offset += 3 # bitmap padding
+
+        else:
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
+                text_offset = tab_x + 8
+        
+        draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
+
+        ypos = drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1
+
+        offset_focus = text_offset     
+        if control is not None:
+            if control.GetPosition() != wx.Point(text_offset+1, ypos):
+                control.SetPosition(wx.Point(text_offset+1, ypos))
+
+            if not control.IsShown():
+                control.Show()
+
+            if paint_control:
+                bmp = TakeScreenShot(control.GetScreenRect())
+                dc.DrawBitmap(bmp, text_offset+1, ypos, True)
+                
+            controlW, controlH = control.GetSize()
+            text_offset += controlW + 4
+            textx += controlW + 4
+            
+        # draw tab text
+        rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
+        dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
+
+        # draw focus rectangle
+        if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
+            self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff, drawn_tab_height, rectx, recty)
+        
+        out_button_rect = wx.Rect()
+        
+        # draw close button if necessary
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+        
+            bmp = self._disabled_close_bmp
+
+            if close_button_state == AUI_BUTTON_STATE_HOVER:
+                bmp = self._hover_close_bmp
+            elif close_button_state == AUI_BUTTON_STATE_PRESSED:
+                bmp = self._pressed_close_bmp
+
+            shift = (agwFlags & AUI_NB_BOTTOM and [1] or [0])[0]
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                rect = wx.Rect(tab_x + 4, tab_y + (tab_height - bmp.GetHeight())/2 - shift,
+                               close_button_width, tab_height)
+            else:
+                rect = wx.Rect(tab_x + tab_width - close_button_width - 1,
+                               tab_y + (tab_height - bmp.GetHeight())/2 - shift,
+                               close_button_width, tab_height)
+
+            rect = IndentPressedBitmap(rect, close_button_state)
+            dc.DrawBitmap(bmp, rect.x, rect.y, True)
+
+            out_button_rect = rect
+        
+        out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
+
+        dc.DestroyClippingRegion()
+
+        return out_tab_rect, out_button_rect, x_extent
+    
+
+    def SetCustomButton(self, bitmap_id, button_state, bmp):
+        """
+        Sets a custom bitmap for the close, left, right and window list
+        buttons.
+        
+        :param `bitmap_id`: the button identifier;
+        :param `button_state`: the button state;
+        :param `bmp`: the custom bitmap to use for the button.
+        """
+
+        if bitmap_id == AUI_BUTTON_CLOSE:
+            if button_state == AUI_BUTTON_STATE_NORMAL:
+                self._active_close_bmp = bmp
+                self._hover_close_bmp = self._active_close_bmp
+                self._pressed_close_bmp = self._active_close_bmp
+                self._disabled_close_bmp = self._active_close_bmp
+                    
+            elif button_state == AUI_BUTTON_STATE_HOVER:
+                self._hover_close_bmp = bmp
+            elif button_state == AUI_BUTTON_STATE_PRESSED:
+                self._pressed_close_bmp = bmp
+            else:
+                self._disabled_close_bmp = bmp
+
+        elif bitmap_id == AUI_BUTTON_LEFT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                self._disabled_left_bmp = bmp
+            else:
+                self._active_left_bmp = bmp
+
+        elif bitmap_id == AUI_BUTTON_RIGHT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                self._disabled_right_bmp = bmp
+            else:
+                self._active_right_bmp = bmp
+
+        elif bitmap_id == AUI_BUTTON_WINDOWLIST:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                self._disabled_windowlist_bmp = bmp
+            else:
+                self._active_windowlist_bmp = bmp
+        
+
+    def GetIndentSize(self):
+        """ Returns the tabs indent size. """
+
+        return 5
+
+
+    def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
+        """
+        Returns the tab size for the given caption, bitmap and button state.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `caption`: the tab text caption;
+        :param `bitmap`: the bitmap displayed on the tab;
+        :param `active`: whether the tab is selected or not;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+
+        dc.SetFont(self._measuring_font)
+        measured_textx, measured_texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        # add padding around the text
+        tab_width = measured_textx
+        tab_height = measured_texty
+
+        # if the close button is showing, add space for it
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            tab_width += self._active_close_bmp.GetWidth() + 3
+
+        # if there's a bitmap, add space for it
+        if bitmap.IsOk():
+            tab_width += bitmap.GetWidth()
+            tab_width += 3 # right side bitmap padding
+            tab_height = max(tab_height, bitmap.GetHeight())
+        
+        # add padding
+        tab_width += 16
+        tab_height += 10
+
+        agwFlags = self.GetAGWFlags()
+        if agwFlags & AUI_NB_TAB_FIXED_WIDTH:
+            tab_width = self._fixed_tab_width
+
+        if control is not None:
+            tab_width += control.GetSize().GetWidth() + 4
+            
+        x_extent = tab_width
+
+        return (tab_width, tab_height), x_extent
+
+
+    def DrawButton(self, dc, wnd, in_rect, button, orientation):
+        """
+        Draws a button on the tab or on the tab area, depending on the button identifier. 
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `button`: an instance of the button class;
+        :param `orientation`: the tab orientation.
+        """
+
+        bitmap_id, button_state = button.id, button.cur_state
+        
+        if bitmap_id == AUI_BUTTON_CLOSE:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_close_bmp
+            elif button_state & AUI_BUTTON_STATE_HOVER:
+                bmp = self._hover_close_bmp
+            elif button_state & AUI_BUTTON_STATE_PRESSED:
+                bmp = self._pressed_close_bmp
+            else:
+                bmp = self._active_close_bmp
+
+        elif bitmap_id == AUI_BUTTON_LEFT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_left_bmp
+            else:
+                bmp = self._active_left_bmp
+
+        elif bitmap_id == AUI_BUTTON_RIGHT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_right_bmp
+            else:
+                bmp = self._active_right_bmp
+
+        elif bitmap_id == AUI_BUTTON_WINDOWLIST:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_windowlist_bmp
+            else:
+                bmp = self._active_windowlist_bmp
+
+        else:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = button.dis_bitmap
+            else:
+                bmp = button.bitmap
+                
+        if not bmp.IsOk():
+            return
+
+        rect = wx.Rect(*in_rect)
+
+        if orientation == wx.LEFT:
+        
+            rect.SetX(in_rect.x)
+            rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2))
+            rect.SetWidth(bmp.GetWidth())
+            rect.SetHeight(bmp.GetHeight())
+        
+        else:
+        
+            rect = wx.Rect(in_rect.x + in_rect.width - bmp.GetWidth(),
+                           ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
+                           bmp.GetWidth(), bmp.GetHeight())
+        
+        rect = IndentPressedBitmap(rect, button_state)
+        dc.DrawBitmap(bmp, rect.x, rect.y, True)
+
+        out_rect = rect
+
+        if bitmap_id == AUI_BUTTON_RIGHT:
+            self._buttonRect = wx.Rect(rect.x, rect.y, 30, rect.height)
+        
+        return out_rect
+
+
+    def DrawFocusRectangle(self, dc, page, wnd, draw_text, text_offset, bitmap_offset, drawn_tab_yoff, drawn_tab_height, textx, texty):
+        """
+        Draws the focus rectangle on a tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `page`: the page associated with the tab;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `draw_text`: the text that has been drawn on the tab;
+        :param `text_offset`: the text offset on the tab;
+        :param `bitmap_offset`: the bitmap offset on the tab;
+        :param `drawn_tab_yoff`: the y offset of the tab text;
+        :param `drawn_tab_height`: the height of the tab;
+        :param `textx`: the x text extent;
+        :param `texty`: the y text extent.
+        """
+
+        if self.GetAGWFlags() & AUI_NB_NO_TAB_FOCUS:
+            return
+        
+        if page.active and wx.Window.FindFocus() == wnd:
+        
+            focusRectText = wx.Rect(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2)),
+                                    textx, texty)
+
+            if page.bitmap.IsOk():
+                focusRectBitmap = wx.Rect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
+                                          page.bitmap.GetWidth(), page.bitmap.GetHeight())
+
+            if page.bitmap.IsOk() and draw_text == "":
+                focusRect = wx.Rect(*focusRectBitmap)
+            elif not page.bitmap.IsOk() and draw_text != "":
+                focusRect = wx.Rect(*focusRectText)
+            elif page.bitmap.IsOk() and draw_text != "":
+                focusRect = focusRectText.Union(focusRectBitmap)
+
+            focusRect.Inflate(2, 2)
+
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+            dc.SetPen(self._focusPen)
+            dc.DrawRoundedRectangleRect(focusRect, 2)
+        
+
+    def GetBestTabCtrlSize(self, wnd, pages, required_bmp_size):
+        """
+        Returns the best tab control size.
+
+        :param `wnd`: a `wx.Window` instance object;
+        :param `pages`: the pages associated with the tabs;
+        :param `required_bmp_size`: the size of the bitmap on the tabs.
+        """
+
+        dc = wx.ClientDC(wnd)
+        dc.SetFont(self._measuring_font)
+
+        # sometimes a standard bitmap size needs to be enforced, especially
+        # if some tabs have bitmaps and others don't.  This is important because
+        # it prevents the tab control from resizing when tabs are added.
+
+        measure_bmp = wx.NullBitmap
+        
+        if required_bmp_size.IsFullySpecified():
+            measure_bmp = wx.EmptyBitmap(required_bmp_size.x,
+                                         required_bmp_size.y)
+        
+        max_y = 0
+        
+        for page in pages:
+        
+            if measure_bmp.IsOk():
+                bmp = measure_bmp
+            else:
+                bmp = page.bitmap
+
+            # we don't use the caption text because we don't
+            # want tab heights to be different in the case
+            # of a very short piece of text on one tab and a very
+            # tall piece of text on another tab
+            s, x_ext = self.GetTabSize(dc, wnd, page.caption, bmp, True, AUI_BUTTON_STATE_HIDDEN, None)
+            max_y = max(max_y, s[1])
+
+            if page.control:
+                controlW, controlH = page.control.GetSize()
+                max_y = max(max_y, controlH+4)
+
+        return max_y + 2
+
+
+    def SetNormalFont(self, font):
+        """
+        Sets the normal font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._normal_font = font
+
+
+    def SetSelectedFont(self, font):
+        """
+        Sets the selected tab font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._selected_font = font
+
+
+    def SetMeasuringFont(self, font):
+        """
+        Sets the font for calculating text measurements.
+
+        :param `font`: a `wx.Font` object.
+        """
+
+        self._measuring_font = font
+
+
+    def GetNormalFont(self):
+        """ Returns the normal font for drawing tab labels. """
+
+        return self._normal_font
+
+
+    def GetSelectedFont(self):
+        """ Returns the selected tab font for drawing tab labels. """
+
+        return self._selected_font
+
+
+    def GetMeasuringFont(self):
+        """ Returns the font for calculating text measurements. """
+
+        return self._measuring_font
+    
+
+    def ShowDropDown(self, wnd, pages, active_idx):
+        """
+        Shows the drop-down window menu on the tab area.
+
+        :param `wnd`: a `wx.Window` derived window instance;
+        :param `pages`: the pages associated with the tabs;
+        :param `active_idx`: the active tab index.
+        """
+        
+        useImages = self.GetAGWFlags() & AUI_NB_USE_IMAGES_DROPDOWN
+        menuPopup = wx.Menu()
+
+        longest = 0
+        for i, page in enumerate(pages):
+        
+            caption = page.caption
+
+            # if there is no caption, make it a space.  This will prevent
+            # an assert in the menu code.
+            if caption == "":
+                caption = " "
+
+            # Save longest caption width for calculating menu width with
+            width = wnd.GetTextExtent(caption)[0]
+            if width > longest:
+                longest = width
+
+            if useImages:
+                menuItem = wx.MenuItem(menuPopup, 1000+i, caption)
+                if page.bitmap:
+                    menuItem.SetBitmap(page.bitmap)
+
+                menuPopup.AppendItem(menuItem)
+                
+            else:
+                
+                menuPopup.AppendCheckItem(1000+i, caption)
+                
+            menuPopup.Enable(1000+i, page.enabled)
+
+        if active_idx != -1 and not useImages:
+        
+            menuPopup.Check(1000+active_idx, True)
+        
+        # find out the screen coordinate at the bottom of the tab ctrl
+        cli_rect = wnd.GetClientRect()
+
+        # Calculate the approximate size of the popupmenu for setting the
+        # position of the menu when its shown.
+        # Account for extra padding on left/right of text on mac menus
+        if wx.Platform in ['__WXMAC__', '__WXMSW__']:
+            longest += 32
+
+        # Bitmap/Checkmark width + padding
+        longest += 20
+
+        if self.GetAGWFlags() & AUI_NB_CLOSE_BUTTON:
+            longest += 16
+
+        pt = wx.Point(cli_rect.x + cli_rect.GetWidth() - longest,
+                     cli_rect.y + cli_rect.height)
+
+        cc = AuiCommandCapture()
+        wnd.PushEventHandler(cc)
+        wnd.PopupMenu(menuPopup, pt)
+        command = cc.GetCommandId()
+        wnd.PopEventHandler(True)
+
+        if command >= 1000:
+            return command - 1000
+
+        return -1
+
+
+class AuiSimpleTabArt(object):
+    """ A simple-looking implementation of a tab art. """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        self._normal_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._selected_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        self._selected_font.SetWeight(wx.BOLD)
+        self._measuring_font = self._selected_font
+
+        self._agwFlags = 0
+        self._fixed_tab_width = 100
+
+        base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)
+
+        background_colour = base_colour
+        normaltab_colour = base_colour
+        selectedtab_colour = wx.WHITE
+
+        self._bkbrush = wx.Brush(background_colour)
+        self._normal_bkbrush = wx.Brush(normaltab_colour)
+        self._normal_bkpen = wx.Pen(normaltab_colour)
+        self._selected_bkbrush = wx.Brush(selectedtab_colour)
+        self._selected_bkpen = wx.Pen(selectedtab_colour)
+
+        self._active_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.BLACK)
+        self._disabled_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        self._active_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.BLACK)
+        self._disabled_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        self._active_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.BLACK)
+        self._disabled_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.Colour(128, 128, 128))
+
+        self._active_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.BLACK)
+        self._disabled_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.Colour(128, 128, 128))
+
+
+    def Clone(self):
+        """ Clones the art object. """
+
+        art = type(self)()
+        art.SetNormalFont(self.GetNormalFont())
+        art.SetSelectedFont(self.GetSelectedFont())
+        art.SetMeasuringFont(self.GetMeasuringFont())
+
+        art = CopyAttributes(art, self)
+        return art
+
+
+    def SetAGWFlags(self, agwFlags):
+        """
+        Sets the tab art flags.
+
+        :param `agwFlags`: a combination of the following values:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by L{AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
+         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
+         ==================================== ==================================
+        
+        """
+
+        self._agwFlags = agwFlags
+
+
+    def GetAGWFlags(self):
+        """
+        Returns the tab art flags.
+
+        :see: L{SetAGWFlags} for a list of possible return values.
+        """
+
+        return self._agwFlags
+    
+
+    def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
+        """
+        Sets the tab sizing information.
+        
+        :param `tab_ctrl_size`: the size of the tab control area;
+        :param `tab_count`: the number of tabs;
+        :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
+         to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
+        """
+        
+        self._fixed_tab_width = 100
+        minTabWidth, maxTabWidth = minMaxTabWidth
+
+        tot_width = tab_ctrl_size.x - self.GetIndentSize() - 4
+
+        if self._agwFlags & AUI_NB_CLOSE_BUTTON:
+            tot_width -= self._active_close_bmp.GetWidth()
+        if self._agwFlags & AUI_NB_WINDOWLIST_BUTTON:
+            tot_width -= self._active_windowlist_bmp.GetWidth()
+
+        if tab_count > 0:
+            self._fixed_tab_width = tot_width/tab_count
+        
+        if self._fixed_tab_width < 100:
+            self._fixed_tab_width = 100
+
+        if self._fixed_tab_width > tot_width/2:
+            self._fixed_tab_width = tot_width/2
+
+        if self._fixed_tab_width > 220:
+            self._fixed_tab_width = 220
+
+        if minTabWidth > -1:
+            self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
+        if maxTabWidth > -1:
+            self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
+
+        self._tab_ctrl_height = tab_ctrl_size.y
+        
+
+    def DrawBackground(self, dc, wnd, rect):
+        """
+        Draws the tab area background.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `rect`: the tab control rectangle.
+        """
+        
+        # draw background
+        dc.SetBrush(self._bkbrush)
+        dc.SetPen(wx.TRANSPARENT_PEN)
+        dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2)
+
+        # draw base line
+        dc.SetPen(wx.GREY_PEN)
+        dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1)
+
+
+    def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
+        """
+        Draws a single tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `page`: the tab control page associated with the tab;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
+        """
+        
+        # if the caption is empty, measure some temporary text
+        caption = page.caption
+        if caption == "":
+            caption = "Xj"
+
+        agwFlags = self.GetAGWFlags()
+        
+        dc.SetFont(self._selected_font)
+        selected_textx, selected_texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        dc.SetFont(self._normal_font)
+        normal_textx, normal_texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        control = page.control
+
+        # figure out the size of the tab
+        tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
+                                             page.active, close_button_state, control)
+
+        tab_height = tab_size[1]
+        tab_width = tab_size[0]
+        tab_x = in_rect.x
+        tab_y = in_rect.y + in_rect.height - tab_height
+
+        caption = page.caption
+        # select pen, brush and font for the tab to be drawn
+
+        if page.active:
+        
+            dc.SetPen(self._selected_bkpen)
+            dc.SetBrush(self._selected_bkbrush)
+            dc.SetFont(self._selected_font)
+            textx = selected_textx
+            texty = selected_texty
+        
+        else:
+        
+            dc.SetPen(self._normal_bkpen)
+            dc.SetBrush(self._normal_bkbrush)
+            dc.SetFont(self._normal_font)
+            textx = normal_textx
+            texty = normal_texty
+
+        if not page.enabled:
+            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+        else:
+            dc.SetTextForeground(page.text_colour)
+        
+        # -- draw line --
+
+        points = [wx.Point() for i in xrange(7)]
+        points[0].x = tab_x
+        points[0].y = tab_y + tab_height - 1
+        points[1].x = tab_x + tab_height - 3
+        points[1].y = tab_y + 2
+        points[2].x = tab_x + tab_height + 3
+        points[2].y = tab_y
+        points[3].x = tab_x + tab_width - 2
+        points[3].y = tab_y
+        points[4].x = tab_x + tab_width
+        points[4].y = tab_y + 2
+        points[5].x = tab_x + tab_width
+        points[5].y = tab_y + tab_height - 1
+        points[6] = points[0]
+
+        dc.SetClippingRect(in_rect)
+        dc.DrawPolygon(points)
+
+        dc.SetPen(wx.GREY_PEN)
+        dc.DrawLines(points)
+
+        close_button_width = 0
+        
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+        
+            close_button_width = self._active_close_bmp.GetWidth()
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                if control:
+                    text_offset = tab_x + (tab_height/2) + close_button_width - (textx/2) - 2
+                else:
+                    text_offset = tab_x + (tab_height/2) + ((tab_width+close_button_width)/2) - (textx/2) - 2
+            else:
+                if control:
+                    text_offset = tab_x + (tab_height/2) + close_button_width - (textx/2)
+                else:
+                    text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2)
+        
+        else:
+        
+            text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2)
+            if control:
+                if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                    text_offset = tab_x + (tab_height/3) - (textx/2) + close_button_width + 2
+                else:
+                    text_offset = tab_x + (tab_height/3) - (textx/2)
+        
+        # set minimum text offset
+        if text_offset < tab_x + tab_height:
+            text_offset = tab_x + tab_height
+
+        # chop text if necessary
+        if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x))
+        else:
+            draw_text = ChopText(dc, caption,
+                                 tab_width - (text_offset-tab_x) - close_button_width)
+
+        ypos = (tab_y + tab_height)/2 - (texty/2) + 1
+
+        if control is not None:
+            if control.GetPosition() != wx.Point(text_offset+1, ypos):
+                control.SetPosition(wx.Point(text_offset+1, ypos))
+
+            if not control.IsShown():
+                control.Show()
+
+            if paint_control:
+                bmp = TakeScreenShot(control.GetScreenRect())
+                dc.DrawBitmap(bmp, text_offset+1, ypos, True)
+                
+            controlW, controlH = control.GetSize()
+            text_offset += controlW + 4
+
+        # draw tab text
+        rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
+        dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
+
+        # draw focus rectangle
+        if page.active and wx.Window.FindFocus() == wnd and (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
+        
+            focusRect = wx.Rect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1),
+                                selected_textx, selected_texty)
+
+            focusRect.Inflate(2, 2)
+            # TODO:
+            # This should be uncommented when DrawFocusRect will become
+            # available in wxPython
+            # wx.RendererNative.Get().DrawFocusRect(wnd, dc, focusRect, 0)
+
+        out_button_rect = wx.Rect()        
+        # draw close button if necessary
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+        
+            if page.active:
+                bmp = self._active_close_bmp
+            else:
+                bmp = self._disabled_close_bmp
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                rect = wx.Rect(tab_x + tab_height - 2,
+                               tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
+                               close_button_width, tab_height - 1)
+            else:                
+                rect = wx.Rect(tab_x + tab_width - close_button_width - 1,
+                               tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
+                               close_button_width, tab_height - 1)
+            
+            self.DrawButtons(dc, rect, bmp, wx.WHITE, close_button_state)
+            out_button_rect = wx.Rect(*rect)
+        
+        out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
+        dc.DestroyClippingRegion()
+
+        return out_tab_rect, out_button_rect, x_extent  
+
+
+    def DrawButtons(self, dc, _rect, bmp, bkcolour, button_state):
+        """
+        Convenience method to draw tab buttons.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `_rect`: the tab rectangle;
+        :param `bmp`: the tab bitmap;
+        :param `bkcolour`: the tab background colour;
+        :param `button_state`: the state of the tab button.
+        """
+
+        rect = wx.Rect(*_rect)
+
+        if button_state == AUI_BUTTON_STATE_PRESSED:
+            rect.x += 1
+            rect.y += 1
+
+        if button_state in [AUI_BUTTON_STATE_HOVER, AUI_BUTTON_STATE_PRESSED]:
+            dc.SetBrush(wx.Brush(StepColour(bkcolour, 120)))
+            dc.SetPen(wx.Pen(StepColour(bkcolour, 75)))
+
+            # draw the background behind the button
+            dc.DrawRectangle(rect.x, rect.y, 15, 15)
+
+        # draw the button itself
+        dc.DrawBitmap(bmp, rect.x, rect.y, True)
+
+    
+    def GetIndentSize(self):
+        """ Returns the tabs indent size. """
+        
+        return 0
+
+
+    def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
+        """
+        Returns the tab size for the given caption, bitmap and button state.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `caption`: the tab text caption;
+        :param `bitmap`: the bitmap displayed on the tab;
+        :param `active`: whether the tab is selected or not;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+        
+        dc.SetFont(self._measuring_font)
+        measured_textx, measured_texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        tab_height = measured_texty + 4
+        tab_width = measured_textx + tab_height + 5
+
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            tab_width += self._active_close_bmp.GetWidth()
+
+        if self._agwFlags & AUI_NB_TAB_FIXED_WIDTH:
+            tab_width = self._fixed_tab_width
+
+        if control is not None:
+            controlW, controlH = control.GetSize()
+            tab_width += controlW + 4
+
+        x_extent = tab_width - (tab_height/2) - 1
+
+        return (tab_width, tab_height), x_extent
+
+
+    def DrawButton(self, dc, wnd, in_rect, button, orientation):
+        """
+        Draws a button on the tab or on the tab area, depending on the button identifier. 
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `button`: an instance of the button class;
+        :param `orientation`: the tab orientation.
+        """
+
+        bitmap_id, button_state = button.id, button.cur_state
+        
+        if bitmap_id == AUI_BUTTON_CLOSE:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_close_bmp
+            else:
+                bmp = self._active_close_bmp
+
+        elif bitmap_id == AUI_BUTTON_LEFT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_left_bmp
+            else:
+                bmp = self._active_left_bmp
+
+        elif bitmap_id == AUI_BUTTON_RIGHT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_right_bmp
+            else:
+                bmp = self._active_right_bmp
+
+        elif bitmap_id == AUI_BUTTON_WINDOWLIST:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = self._disabled_windowlist_bmp
+            else:
+                bmp = self._active_windowlist_bmp
+
+        else:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                bmp = button.dis_bitmap
+            else:
+                bmp = button.bitmap
+            
+        if not bmp.IsOk():
+            return
+
+        rect = wx.Rect(*in_rect)
+
+        if orientation == wx.LEFT:
+        
+            rect.SetX(in_rect.x)
+            rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2))
+            rect.SetWidth(bmp.GetWidth())
+            rect.SetHeight(bmp.GetHeight())
+        
+        else:
+        
+            rect = wx.Rect(in_rect.x + in_rect.width - bmp.GetWidth(),
+                           ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
+                           bmp.GetWidth(), bmp.GetHeight())
+
+        self.DrawButtons(dc, rect, bmp, wx.WHITE, button_state)
+
+        out_rect = wx.Rect(*rect)
+        return out_rect
+
+
+    def ShowDropDown(self, wnd, pages, active_idx):
+        """
+        Shows the drop-down window menu on the tab area.
+
+        :param `wnd`: a `wx.Window` derived window instance;
+        :param `pages`: the pages associated with the tabs;
+        :param `active_idx`: the active tab index.
+        """
+        
+        menuPopup = wx.Menu()
+        useImages = self.GetAGWFlags() & AUI_NB_USE_IMAGES_DROPDOWN
+        
+        for i, page in enumerate(pages):
+
+            if useImages:
+                menuItem = wx.MenuItem(menuPopup, 1000+i, page.caption)
+                if page.bitmap:
+                    menuItem.SetBitmap(page.bitmap)
+
+                menuPopup.AppendItem(menuItem)
+                
+            else:
+                
+                menuPopup.AppendCheckItem(1000+i, page.caption)
+                
+            menuPopup.Enable(1000+i, page.enabled)
+        
+        if active_idx != -1 and not useImages:
+            menuPopup.Check(1000+active_idx, True)
+        
+        # find out where to put the popup menu of window
+        # items.  Subtract 100 for now to center the menu
+        # a bit, until a better mechanism can be implemented
+        pt = wx.GetMousePosition()
+        pt = wnd.ScreenToClient(pt)
+        
+        if pt.x < 100:
+            pt.x = 0
+        else:
+            pt.x -= 100
+
+        # find out the screen coordinate at the bottom of the tab ctrl
+        cli_rect = wnd.GetClientRect()
+        pt.y = cli_rect.y + cli_rect.height
+
+        cc = AuiCommandCapture()
+        wnd.PushEventHandler(cc)
+        wnd.PopupMenu(menuPopup, pt)
+        command = cc.GetCommandId()
+        wnd.PopEventHandler(True)
+
+        if command >= 1000:
+            return command-1000
+
+        return -1
+
+
+    def GetBestTabCtrlSize(self, wnd, pages, required_bmp_size):
+        """
+        Returns the best tab control size.
+
+        :param `wnd`: a `wx.Window` instance object;
+        :param `pages`: the pages associated with the tabs;
+        :param `required_bmp_size`: the size of the bitmap on the tabs.
+        """
+        
+        dc = wx.ClientDC(wnd)
+        dc.SetFont(self._measuring_font)
+        s, x_extent = self.GetTabSize(dc, wnd, "ABCDEFGHIj", wx.NullBitmap, True,
+                                      AUI_BUTTON_STATE_HIDDEN, None)
+
+        max_y = s[1]
+
+        for page in pages:
+            if page.control:
+                controlW, controlH = page.control.GetSize()
+                max_y = max(max_y, controlH+4)
+                
+            textx, texty, dummy = dc.GetMultiLineTextExtent(page.caption)
+            max_y = max(max_y, texty)
+        
+        return max_y + 3
+
+
+    def SetNormalFont(self, font):
+        """
+        Sets the normal font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+        
+        self._normal_font = font
+
+
+    def SetSelectedFont(self, font):
+        """
+        Sets the selected tab font for drawing tab labels.
+
+        :param `font`: a `wx.Font` object.
+        """
+        
+        self._selected_font = font
+
+
+    def SetMeasuringFont(self, font):
+        """
+        Sets the font for calculating text measurements.
+
+        :param `font`: a `wx.Font` object.
+        """
+        
+        self._measuring_font = font
+
+
+    def GetNormalFont(self):
+        """ Returns the normal font for drawing tab labels. """
+
+        return self._normal_font
+
+
+    def GetSelectedFont(self):
+        """ Returns the selected tab font for drawing tab labels. """
+
+        return self._selected_font
+
+
+    def GetMeasuringFont(self):
+        """ Returns the font for calculating text measurements. """
+
+        return self._measuring_font
+
+
+    def SetCustomButton(self, bitmap_id, button_state, bmp):
+        """
+        Sets a custom bitmap for the close, left, right and window list
+        buttons.
+        
+        :param `bitmap_id`: the button identifier;
+        :param `button_state`: the button state;
+        :param `bmp`: the custom bitmap to use for the button.
+        """
+        
+        if bitmap_id == AUI_BUTTON_CLOSE:
+            if button_state == AUI_BUTTON_STATE_NORMAL:
+                self._active_close_bmp = bmp
+                self._hover_close_bmp = self._active_close_bmp
+                self._pressed_close_bmp = self._active_close_bmp
+                self._disabled_close_bmp = self._active_close_bmp
+                    
+            elif button_state == AUI_BUTTON_STATE_HOVER:
+                self._hover_close_bmp = bmp
+            elif button_state == AUI_BUTTON_STATE_PRESSED:
+                self._pressed_close_bmp = bmp
+            else:
+                self._disabled_close_bmp = bmp
+
+        elif bitmap_id == AUI_BUTTON_LEFT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                self._disabled_left_bmp = bmp
+            else:
+                self._active_left_bmp = bmp
+
+        elif bitmap_id == AUI_BUTTON_RIGHT:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                self._disabled_right_bmp = bmp
+            else:
+                self._active_right_bmp = bmp
+
+        elif bitmap_id == AUI_BUTTON_WINDOWLIST:
+            if button_state & AUI_BUTTON_STATE_DISABLED:
+                self._disabled_windowlist_bmp = bmp
+            else:
+                self._active_windowlist_bmp = bmp
+    
+
+class VC71TabArt(AuiDefaultTabArt):
+    """ A class to draw tabs using the Visual Studio 2003 (VC71) style. """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        AuiDefaultTabArt.__init__(self)
+
+
+    def Clone(self):
+        """ Clones the art object. """
+
+        art = type(self)()
+        art.SetNormalFont(self.GetNormalFont())
+        art.SetSelectedFont(self.GetSelectedFont())
+        art.SetMeasuringFont(self.GetMeasuringFont())
+
+        art = CopyAttributes(art, self)
+        return art
+
+
+    def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
+        """
+        Draws a single tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `page`: the tab control page associated with the tab;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
+        """
+        
+        # Visual studio 7.1 style
+        # This code is based on the renderer included in FlatNotebook
+
+        # figure out the size of the tab
+
+        control = page.control
+        tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active,
+                                             close_button_state, control)
+
+        tab_height = self._tab_ctrl_height - 3
+        tab_width = tab_size[0]
+        tab_x = in_rect.x
+        tab_y = in_rect.y + in_rect.height - tab_height
+        clip_width = tab_width
+
+        if tab_x + clip_width > in_rect.x + in_rect.width - 4:
+            clip_width = (in_rect.x + in_rect.width) - tab_x - 4
+            
+        dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3)
+        agwFlags = self.GetAGWFlags()
+
+        if agwFlags & AUI_NB_BOTTOM:
+            tab_y -= 1
+
+        dc.SetPen((page.active and [wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DHIGHLIGHT))] or \
+                   [wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW))])[0])
+        dc.SetBrush((page.active and [wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE))] or \
+                     [wx.TRANSPARENT_BRUSH])[0])
+
+        if page.active:
+
+            tabH = tab_height - 2
+            dc.DrawRectangle(tab_x, tab_y, tab_width, tabH)
+
+            rightLineY1 = (agwFlags & AUI_NB_BOTTOM and [vertical_border_padding - 2] or \
+                           [vertical_border_padding - 1])[0]
+            rightLineY2 = tabH + 3
+            dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW)))
+            dc.DrawLine(tab_x + tab_width - 1, rightLineY1 + 1, tab_x + tab_width - 1, rightLineY2)
+            
+            if agwFlags & AUI_NB_BOTTOM:
+                dc.DrawLine(tab_x + 1, rightLineY2 - 3 , tab_x + tab_width - 1, rightLineY2 - 3)
+                
+            dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW)))
+            dc.DrawLine(tab_x + tab_width, rightLineY1, tab_x + tab_width, rightLineY2)
+            
+            if agwFlags & AUI_NB_BOTTOM:
+                dc.DrawLine(tab_x, rightLineY2 - 2, tab_x + tab_width, rightLineY2 - 2)
+
+        else:
+        
+            # We dont draw a rectangle for non selected tabs, but only
+            # vertical line on the right
+            blackLineY1 = (agwFlags & AUI_NB_BOTTOM and [vertical_border_padding + 2] or \
+                           [vertical_border_padding + 1])[0]
+            blackLineY2 = tab_height - 5
+            dc.DrawLine(tab_x + tab_width, blackLineY1, tab_x + tab_width, blackLineY2)
+        
+        border_points = [0, 0]
+        
+        if agwFlags & AUI_NB_BOTTOM:
+        
+            border_points[0] = wx.Point(tab_x, tab_y)
+            border_points[1] = wx.Point(tab_x, tab_y + tab_height - 6)
+        
+        else: # if (agwFlags & AUI_NB_TOP)
+        
+            border_points[0] = wx.Point(tab_x, tab_y + tab_height - 4)
+            border_points[1] = wx.Point(tab_x, tab_y + 2)
+
+        drawn_tab_yoff = border_points[1].y
+        drawn_tab_height = border_points[0].y - border_points[1].y
+
+        text_offset = tab_x + 8
+        close_button_width = 0
+
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            close_button_width = self._active_close_bmp.GetWidth()
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                text_offset += close_button_width - 5
+
+        if not page.enabled:
+            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+            pagebitmap = page.dis_bitmap
+        else:
+            dc.SetTextForeground(page.text_colour)
+            pagebitmap = page.bitmap
+
+        shift = 0
+        if agwFlags & AUI_NB_BOTTOM:
+            shift = (page.active and [1] or [2])[0]
+            
+        bitmap_offset = 0
+        if pagebitmap.IsOk():
+            bitmap_offset = tab_x + 8
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
+                bitmap_offset += close_button_width - 5
+
+            # draw bitmap
+            dc.DrawBitmap(pagebitmap, bitmap_offset,
+                          drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift,
+                          True)
+
+            text_offset = bitmap_offset + pagebitmap.GetWidth()
+            text_offset += 3 # bitmap padding
+        
+        else:
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
+                text_offset = tab_x + 8
+        
+        # if the caption is empty, measure some temporary text
+        caption = page.caption
+
+        if caption == "":
+            caption = "Xj"
+
+        if page.active:
+            dc.SetFont(self._selected_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+        else:
+            dc.SetFont(self._normal_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
+
+        ypos = drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1 + shift
+
+        offset_focus = text_offset
+        
+        if control is not None:
+            if control.GetPosition() != wx.Point(text_offset+1, ypos):
+                control.SetPosition(wx.Point(text_offset+1, ypos))
+
+            if not control.IsShown():
+                control.Show()
+
+            if paint_control:
+                bmp = TakeScreenShot(control.GetScreenRect())
+                dc.DrawBitmap(bmp, text_offset+1, ypos, True)
+                
+            controlW, controlH = control.GetSize()
+            text_offset += controlW + 4
+            textx += controlW + 4
+
+        # draw tab text
+        rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
+        dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
+
+        out_button_rect = wx.Rect()
+
+        # draw focus rectangle
+        if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
+            self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift,
+                                    drawn_tab_height+shift, rectx, recty)
+                
+        # draw 'x' on tab (if enabled)
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            close_button_width = self._active_close_bmp.GetWidth()
+
+            bmp = self._disabled_close_bmp
+
+            if close_button_state == AUI_BUTTON_STATE_HOVER:
+                bmp = self._hover_close_bmp
+            elif close_button_state == AUI_BUTTON_STATE_PRESSED:
+                bmp = self._pressed_close_bmp
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                rect = wx.Rect(tab_x + 4,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
+                               close_button_width, tab_height)
+            else:
+                rect = wx.Rect(tab_x + tab_width - close_button_width - 3,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
+                               close_button_width, tab_height)
+
+            # Indent the button if it is pressed down:
+            rect = IndentPressedBitmap(rect, close_button_state)
+            dc.DrawBitmap(bmp, rect.x, rect.y, True)
+
+            out_button_rect = rect        
+
+        out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
+        dc.DestroyClippingRegion()
+
+        return out_tab_rect, out_button_rect, x_extent
+
+
+class FF2TabArt(AuiDefaultTabArt):
+    """ A class to draw tabs using the Firefox 2 (FF2) style. """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        AuiDefaultTabArt.__init__(self)
+
+
+    def Clone(self):
+        """ Clones the art object. """
+
+        art = type(self)()
+        art.SetNormalFont(self.GetNormalFont())
+        art.SetSelectedFont(self.GetSelectedFont())
+        art.SetMeasuringFont(self.GetMeasuringFont())
+
+        art = CopyAttributes(art, self)
+        return art
+
+
+    def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control):
+        """
+        Returns the tab size for the given caption, bitmap and button state.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `caption`: the tab text caption;
+        :param `bitmap`: the bitmap displayed on the tab;
+        :param `active`: whether the tab is selected or not;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+        
+        tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap,
+                                                         active, close_button_state, control)
+
+        tab_width, tab_height = tab_size        
+
+        # add some vertical padding
+        tab_height += 2
+        
+        return (tab_width, tab_height), x_extent
+
+
+    def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
+        """
+        Draws a single tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `page`: the tab control page associated with the tab;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
+        """
+        
+        # Firefox 2 style
+
+        control = page.control
+
+        # figure out the size of the tab
+        tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
+                                             page.active, close_button_state, control)
+
+        tab_height = self._tab_ctrl_height - 2
+        tab_width = tab_size[0]
+        tab_x = in_rect.x
+        tab_y = in_rect.y + in_rect.height - tab_height
+
+        clip_width = tab_width
+        if tab_x + clip_width > in_rect.x + in_rect.width - 4:
+            clip_width = (in_rect.x + in_rect.width) - tab_x - 4
+            
+        dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3)
+
+        tabPoints = [wx.Point() for i in xrange(7)]
+        
+        adjust = 0
+        if not page.active:
+            adjust = 1
+
+        agwFlags = self.GetAGWFlags()
+        
+        tabPoints[0].x = tab_x + 3
+        tabPoints[0].y = (agwFlags & AUI_NB_BOTTOM and [3] or [tab_height - 2])[0]
+
+        tabPoints[1].x = tabPoints[0].x
+        tabPoints[1].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - (vertical_border_padding + 2) - adjust] or \
+                          [(vertical_border_padding + 2) + adjust])[0]
+
+        tabPoints[2].x = tabPoints[1].x+2
+        tabPoints[2].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding - adjust] or \
+                          [vertical_border_padding + adjust])[0]
+
+        tabPoints[3].x = tab_x + tab_width - 2
+        tabPoints[3].y = tabPoints[2].y
+
+        tabPoints[4].x = tabPoints[3].x + 2
+        tabPoints[4].y = tabPoints[1].y
+
+        tabPoints[5].x = tabPoints[4].x
+        tabPoints[5].y = tabPoints[0].y
+
+        tabPoints[6].x = tabPoints[0].x
+        tabPoints[6].y = tabPoints[0].y
+
+        rr = wx.RectPP(tabPoints[2], tabPoints[5])
+        self.DrawTabBackground(dc, rr, page.active, (agwFlags & AUI_NB_BOTTOM) == 0)
+
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
+
+        # Draw the tab as rounded rectangle
+        dc.DrawPolygon(tabPoints)
+
+        if page.active:
+            dc.DrawLine(tabPoints[0].x + 1, tabPoints[0].y, tabPoints[5].x , tabPoints[0].y)
+        
+        drawn_tab_yoff = tabPoints[1].y
+        drawn_tab_height = tabPoints[0].y - tabPoints[2].y
+
+        text_offset = tab_x + 8
+        close_button_width = 0
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            close_button_width = self._active_close_bmp.GetWidth()
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                text_offset += close_button_width - 4
+
+        if not page.enabled:
+            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+            pagebitmap = page.dis_bitmap
+        else:
+            dc.SetTextForeground(page.text_colour)
+            pagebitmap = page.bitmap
+
+        shift = -1
+        if agwFlags & AUI_NB_BOTTOM:
+            shift = 2
+        
+        bitmap_offset = 0
+        if pagebitmap.IsOk():
+            bitmap_offset = tab_x + 8
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
+                bitmap_offset += close_button_width - 4
+
+            # draw bitmap
+            dc.DrawBitmap(pagebitmap, bitmap_offset,
+                          drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift,
+                          True)
+
+            text_offset = bitmap_offset + pagebitmap.GetWidth()
+            text_offset += 3 # bitmap padding
+        
+        else:
+        
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
+                text_offset = tab_x + 8
+        
+        # if the caption is empty, measure some temporary text
+        caption = page.caption
+        if caption == "":
+            caption = "Xj"
+
+        if page.active:
+            dc.SetFont(self._selected_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+        else:
+            dc.SetFont(self._normal_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width + 1)
+        else:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
+
+        ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 + shift
+
+        offset_focus = text_offset
+        
+        if control is not None:
+            if control.GetPosition() != wx.Point(text_offset+1, ypos):
+                control.SetPosition(wx.Point(text_offset+1, ypos))
+
+            if not control.IsShown():
+                control.Show()
+
+            if paint_control:
+                bmp = TakeScreenShot(control.GetScreenRect())
+                dc.DrawBitmap(bmp, text_offset+1, ypos, True)
+                
+            controlW, controlH = control.GetSize()
+            text_offset += controlW + 4
+            textx += controlW + 4
+        
+        # draw tab text
+        rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
+        dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
+
+        # draw focus rectangle
+        if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
+            self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift,
+                                    drawn_tab_height, rectx, recty)
+        
+        out_button_rect = wx.Rect()
+        # draw 'x' on tab (if enabled)
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+        
+            close_button_width = self._active_close_bmp.GetWidth()
+            bmp = self._disabled_close_bmp
+
+            if close_button_state == AUI_BUTTON_STATE_HOVER:
+                bmp = self._hover_close_bmp
+            elif close_button_state == AUI_BUTTON_STATE_PRESSED:
+                bmp = self._pressed_close_bmp
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                rect = wx.Rect(tab_x + 5,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
+                               close_button_width, tab_height)
+            else:
+                rect = wx.Rect(tab_x + tab_width - close_button_width - 3,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
+                               close_button_width, tab_height)
+
+            # Indent the button if it is pressed down:
+            rect = IndentPressedBitmap(rect, close_button_state)
+            dc.DrawBitmap(bmp, rect.x, rect.y, True)
+            out_button_rect = rect
+        
+        out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
+        dc.DestroyClippingRegion()
+    
+        return out_tab_rect, out_button_rect, x_extent
+
+
+    def DrawTabBackground(self, dc, rect, focus, upperTabs):
+        """
+        Draws the tab background for the Firefox 2 style.
+        This is more consistent with L{FlatNotebook} than before.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `rect`: rectangle the tab should be confined to;
+        :param `focus`: whether the tab has focus or not;
+        :param `upperTabs`: whether the style is ``AUI_NB_TOP`` or ``AUI_NB_BOTTOM``.
+        """
+
+        # Define the rounded rectangle base on the given rect
+        # we need an array of 9 points for it
+        regPts = [wx.Point() for indx in xrange(9)]
+
+        if focus:
+            if upperTabs:
+                leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*8)
+                rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*8)
+            else:
+                leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*5)
+                rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*5)
+        else:
+            leftPt = wx.Point(rect.x, rect.y + (rect.height / 2))
+            rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 2))
+
+        # Define the top region
+        top = wx.RectPP(rect.GetTopLeft(), rightPt)
+        bottom = wx.RectPP(leftPt, rect.GetBottomRight())
+
+        topStartColour = wx.WHITE
+
+        if not focus:
+            topStartColour = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 50)
+
+        topEndColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
+        bottomStartColour = topEndColour
+        bottomEndColour = topEndColour
+
+        # Incase we use bottom tabs, switch the colours
+        if upperTabs:
+            if focus:
+                dc.GradientFillLinear(top, topStartColour, topEndColour, wx.SOUTH)
+                dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH)
+            else:
+                dc.GradientFillLinear(top, topEndColour , topStartColour, wx.SOUTH)
+                dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH)
+
+        else:
+            if focus:
+                dc.GradientFillLinear(bottom, topEndColour, bottomEndColour, wx.SOUTH)
+                dc.GradientFillLinear(top, topStartColour, topStartColour, wx.SOUTH)
+            else:
+                dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH)
+                dc.GradientFillLinear(top, topEndColour, topStartColour, wx.SOUTH)
+        
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+
+class VC8TabArt(AuiDefaultTabArt):
+    """ A class to draw tabs using the Visual Studio 2005 (VC8) style. """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        AuiDefaultTabArt.__init__(self)
+
+
+    def Clone(self):
+        """ Clones the art object. """
+
+        art = type(self)()
+        art.SetNormalFont(self.GetNormalFont())
+        art.SetSelectedFont(self.GetSelectedFont())
+        art.SetMeasuringFont(self.GetMeasuringFont())
+
+        art = CopyAttributes(art, self)
+        return art
+
+
+    def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
+        """
+        Sets the tab sizing information.
+        
+        :param `tab_ctrl_size`: the size of the tab control area;
+        :param `tab_count`: the number of tabs;
+        :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
+         to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
+        """
+        
+        AuiDefaultTabArt.SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth)
+
+        minTabWidth, maxTabWidth = minMaxTabWidth
+        if minTabWidth > -1:
+            self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
+        if maxTabWidth > -1:
+            self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
+        
+        self._fixed_tab_width -= 5
+
+
+    def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
+        """
+        Returns the tab size for the given caption, bitmap and button state.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `caption`: the tab text caption;
+        :param `bitmap`: the bitmap displayed on the tab;
+        :param `active`: whether the tab is selected or not;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+        
+        tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap,
+                                                         active, close_button_state, control)
+
+        tab_width, tab_height = tab_size        
+
+        # add some padding
+        tab_width += 10
+        tab_height += 2
+
+        return (tab_width, tab_height), x_extent
+
+
+    def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
+        """
+        Draws a single tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `page`: the tab control page associated with the tab;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
+        """
+        
+        # Visual Studio 8 style
+
+        control = page.control
+
+        # figure out the size of the tab
+        tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
+                                             page.active, close_button_state, control)
+
+        tab_height = self._tab_ctrl_height - 1
+        tab_width = tab_size[0]
+        tab_x = in_rect.x
+        tab_y = in_rect.y + in_rect.height - tab_height
+
+        clip_width = tab_width + 3
+        if tab_x + clip_width > in_rect.x + in_rect.width - 4:
+            clip_width = (in_rect.x + in_rect.width) - tab_x - 4
+        
+        tabPoints = [wx.Point() for i in xrange(8)]
+
+        # If we draw the first tab or the active tab, 
+        # we draw a full tab, else we draw a truncated tab
+        #
+        #             X(2)                  X(3)
+        #        X(1)                            X(4)
+        #                                          
+        #                                           X(5)
+        #                                           
+        # X(0),(7)                                  X(6)
+        #
+        #
+
+        adjust = 0
+        if not page.active:
+            adjust = 1
+
+        agwFlags = self.GetAGWFlags()
+        tabPoints[0].x = (agwFlags & AUI_NB_BOTTOM and [tab_x] or [tab_x + adjust])[0]
+        tabPoints[0].y = (agwFlags & AUI_NB_BOTTOM and [2] or [tab_height - 3])[0]
+
+        tabPoints[1].x = tabPoints[0].x + tab_height - vertical_border_padding - 3 - adjust
+        tabPoints[1].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - (vertical_border_padding+2)] or \
+                          [(vertical_border_padding+2)])[0]
+
+        tabPoints[2].x = tabPoints[1].x + 4
+        tabPoints[2].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding] or \
+                          [vertical_border_padding])[0]
+
+        tabPoints[3].x = tabPoints[2].x + tab_width - tab_height + vertical_border_padding
+        tabPoints[3].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding] or \
+                          [vertical_border_padding])[0]
+
+        tabPoints[4].x = tabPoints[3].x + 1
+        tabPoints[4].y = (agwFlags & AUI_NB_BOTTOM and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
+
+        tabPoints[5].x = tabPoints[4].x + 1
+        tabPoints[5].y = (agwFlags & AUI_NB_BOTTOM and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
+
+        tabPoints[6].x = tabPoints[2].x + tab_width - tab_height + 2 + vertical_border_padding
+        tabPoints[6].y = tabPoints[0].y
+
+        tabPoints[7].x = tabPoints[0].x
+        tabPoints[7].y = tabPoints[0].y
+
+        self.FillVC8GradientColour(dc, tabPoints, page.active)        
+
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+        dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)))
+        dc.DrawPolygon(tabPoints)
+
+        if page.active:
+            # Delete the bottom line (or the upper one, incase we use wxBOTTOM) 
+            dc.SetPen(wx.WHITE_PEN)
+            dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y)
+
+        dc.SetClippingRegion(tab_x, tab_y, clip_width + 2, tab_height - 3)            
+
+        drawn_tab_yoff = tabPoints[1].y
+        drawn_tab_height = tabPoints[0].y - tabPoints[2].y
+
+        text_offset = tab_x + 20
+        close_button_width = 0
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            close_button_width = self._active_close_bmp.GetWidth()
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                text_offset += close_button_width
+
+        if not page.enabled:
+            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+            pagebitmap = page.dis_bitmap
+        else:
+            dc.SetTextForeground(page.text_colour)
+            pagebitmap = page.bitmap
+
+        shift = 0
+        if agwFlags & AUI_NB_BOTTOM:
+            shift = (page.active and [1] or [2])[0]
+        
+        bitmap_offset = 0
+        if pagebitmap.IsOk():
+            bitmap_offset = tab_x + 20
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
+                bitmap_offset += close_button_width
+
+            # draw bitmap
+            dc.DrawBitmap(pagebitmap, bitmap_offset,
+                          drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift,
+                          True)
+
+            text_offset = bitmap_offset + pagebitmap.GetWidth()
+            text_offset += 3 # bitmap padding
+        
+        else:
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
+                text_offset = tab_x + tab_height
+        
+        # if the caption is empty, measure some temporary text
+        caption = page.caption
+        if caption == "":
+            caption = "Xj"
+
+        if page.active:
+            dc.SetFont(self._selected_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+        else:
+            dc.SetFont(self._normal_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x))
+        else:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
+
+        ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 + shift
+
+        offset_focus = text_offset
+        
+        if control is not None:
+            if control.GetPosition() != wx.Point(text_offset+1, ypos):
+                control.SetPosition(wx.Point(text_offset+1, ypos))
+
+            if not control.IsShown():
+                control.Show()
+
+            if paint_control:
+                bmp = TakeScreenShot(control.GetScreenRect())
+                dc.DrawBitmap(bmp, text_offset+1, ypos, True)
+                
+            controlW, controlH = control.GetSize()
+            text_offset += controlW + 4
+            textx += controlW + 4
+
+        # draw tab text
+        rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
+        dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
+        
+        # draw focus rectangle
+        if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
+            self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift,
+                                    drawn_tab_height+shift, rectx, recty)
+        
+        out_button_rect = wx.Rect()
+        # draw 'x' on tab (if enabled)
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+        
+            close_button_width = self._active_close_bmp.GetWidth()
+            bmp = self._disabled_close_bmp
+
+            if close_button_state == AUI_BUTTON_STATE_HOVER:
+                bmp = self._hover_close_bmp
+            elif close_button_state == AUI_BUTTON_STATE_PRESSED:
+                bmp = self._pressed_close_bmp
+                
+            if page.active:
+                xpos = tab_x + tab_width - close_button_width + 3
+            else:
+                xpos = tab_x + tab_width - close_button_width - 5
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                rect = wx.Rect(tab_x + 20,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
+                               close_button_width, tab_height)
+            else:
+                rect = wx.Rect(xpos,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
+                               close_button_width, tab_height)
+
+            # Indent the button if it is pressed down:
+            rect = IndentPressedBitmap(rect, close_button_state)
+            dc.DrawBitmap(bmp, rect.x, rect.y, True)
+            out_button_rect = rect
+        
+        out_tab_rect = wx.Rect(tab_x, tab_y, x_extent, tab_height)
+        dc.DestroyClippingRegion()
+
+        return out_tab_rect, out_button_rect, x_extent
+        
+
+    def FillVC8GradientColour(self, dc, tabPoints, active):
+        """
+        Fills the tab with the Visual Studio 2005 gradient background.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `tabPoints`: a list of `wx.Point` objects describing the tab shape;
+        :param `active`: whether the tab is selected or not.
+        """
+
+        xList = [pt.x for pt in tabPoints]
+        yList = [pt.y for pt in tabPoints]
+        
+        minx, maxx = min(xList), max(xList)
+        miny, maxy = min(yList), max(yList)
+
+        rect = wx.Rect(minx, maxy, maxx-minx, miny-maxy+1)        
+        region = wx.RegionFromPoints(tabPoints)
+
+        if self._buttonRect.width > 0:
+            buttonRegion = wx.Region(*self._buttonRect)
+            region.XorRegion(buttonRegion)
+        
+        dc.SetClippingRegionAsRegion(region)
+
+        if active:
+            bottom_colour = top_colour = wx.WHITE
+        else:
+            bottom_colour = StepColour(self._base_colour, 90)
+            top_colour = StepColour(self._base_colour, 170)
+
+        dc.GradientFillLinear(rect, top_colour, bottom_colour, wx.SOUTH)
+        dc.DestroyClippingRegion()
+        
+
+class ChromeTabArt(AuiDefaultTabArt):
+    """
+    A class to draw tabs using the Google Chrome browser style.
+    It uses custom bitmap to render the tabs, so that the look and feel is as close
+    as possible to the Chrome style.
+    """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        AuiDefaultTabArt.__init__(self)
+
+        self.SetBitmaps(mirror=False)
+        
+        closeBmp = tab_close.GetBitmap()
+        closeHBmp = tab_close_h.GetBitmap()
+        closePBmp = tab_close_p.GetBitmap()
+
+        self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_NORMAL, closeBmp)
+        self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_HOVER, closeHBmp)
+        self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_PRESSED, closePBmp)
+        
+
+    def SetAGWFlags(self, agwFlags):
+        """
+        Sets the tab art flags.
+
+        :param `agwFlags`: a combination of the following values:
+
+         ==================================== ==================================
+         Flag name                            Description
+         ==================================== ==================================
+         ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
+         ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
+         ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
+         ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
+         ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
+         ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
+         ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
+         ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
+         ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
+         ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
+         ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
+         ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
+         ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
+         ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
+         ``AUI_NB_SUB_NOTEBOOK``              This style is used by L{AuiManager} to create automatic AuiNotebooks
+         ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
+         ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
+         ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
+         ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
+         ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
+         ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
+         ``AUI_NB_ORDER_BY_ACCESS``           Tab navigation order by last access time for the tabs
+         ``AUI_NB_NO_TAB_FOCUS``              Don't draw tab focus rectangle
+         ==================================== ==================================
+
+        :note: Overridden from L{AuiDefaultTabArt}.
+        """
+
+        if agwFlags & AUI_NB_TOP:
+            self.SetBitmaps(mirror=False)
+        elif agwFlags & AUI_NB_BOTTOM:
+            self.SetBitmaps(mirror=True)
+
+        AuiDefaultTabArt.SetAGWFlags(self, agwFlags)            
+
+
+    def SetBitmaps(self, mirror):
+        """
+        Assigns the tab custom bitmaps
+
+        :param `mirror`: whether to vertically mirror the bitmap or not.
+        """
+
+        bmps = [tab_active_left.GetBitmap(), tab_active_center.GetBitmap(),
+                tab_active_right.GetBitmap(), tab_inactive_left.GetBitmap(),
+                tab_inactive_center.GetBitmap(), tab_inactive_right.GetBitmap()]
+
+        if mirror:
+            for indx, bmp in enumerate(bmps):
+                img = bmp.ConvertToImage()
+                img = img.Mirror(horizontally=False)
+                bmps[indx] = img.ConvertToBitmap()
+                
+        self._leftActiveBmp = bmps[0]
+        self._centerActiveBmp = bmps[1]
+        self._rightActiveBmp = bmps[2]
+        self._leftInactiveBmp = bmps[3]
+        self._centerInactiveBmp = bmps[4]
+        self._rightInactiveBmp = bmps[5]
+            
+
+    def Clone(self):
+        """ Clones the art object. """
+
+        art = type(self)()
+        art.SetNormalFont(self.GetNormalFont())
+        art.SetSelectedFont(self.GetSelectedFont())
+        art.SetMeasuringFont(self.GetMeasuringFont())
+
+        art = CopyAttributes(art, self)
+        return art
+
+
+    def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
+        """
+        Sets the tab sizing information.
+        
+        :param `tab_ctrl_size`: the size of the tab control area;
+        :param `tab_count`: the number of tabs;
+        :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
+         to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
+        """
+        
+        AuiDefaultTabArt.SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth)
+
+        minTabWidth, maxTabWidth = minMaxTabWidth
+        if minTabWidth > -1:
+            self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
+        if maxTabWidth > -1:
+            self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
+
+        self._fixed_tab_width -= 5
+
+
+    def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
+        """
+        Returns the tab size for the given caption, bitmap and button state.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `caption`: the tab text caption;
+        :param `bitmap`: the bitmap displayed on the tab;
+        :param `active`: whether the tab is selected or not;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `control`: a `wx.Window` instance inside a tab (or ``None``).
+        """
+        
+        tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap,
+                                                         active, close_button_state, control)
+
+        tab_width, tab_height = tab_size        
+
+        # add some padding
+        tab_width += self._leftActiveBmp.GetWidth()
+        tab_height += 2
+
+        tab_height = max(tab_height, self._centerActiveBmp.GetHeight())        
+
+        return (tab_width, tab_height), x_extent
+
+
+    def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
+        """
+        Draws a single tab.
+
+        :param `dc`: a `wx.DC` device context;
+        :param `wnd`: a `wx.Window` instance object;
+        :param `page`: the tab control page associated with the tab;
+        :param `in_rect`: rectangle the tab should be confined to;
+        :param `close_button_state`: the state of the close button on the tab;
+        :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
+        """
+        
+        # Chrome tab style
+
+        control = page.control
+        # figure out the size of the tab
+        tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active,
+                                             close_button_state, control)
+
+        agwFlags = self.GetAGWFlags()
+        
+        tab_height = self._tab_ctrl_height - 1
+        tab_width = tab_size[0]
+        tab_x = in_rect.x
+        tab_y = in_rect.y + in_rect.height - tab_height
+        clip_width = tab_width
+
+        if tab_x + clip_width > in_rect.x + in_rect.width - 4:
+            clip_width = (in_rect.x + in_rect.width) - tab_x - 4
+            
+        dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3)
+        drawn_tab_yoff = 1
+
+        if page.active:
+            left = self._leftActiveBmp
+            center = self._centerActiveBmp
+            right = self._rightActiveBmp
+        else:
+            left = self._leftInactiveBmp
+            center = self._centerInactiveBmp
+            right = self._rightInactiveBmp
+
+        dc.DrawBitmap(left, tab_x, tab_y)
+        leftw = left.GetWidth()
+        centerw = center.GetWidth()
+        rightw = right.GetWidth()
+
+        available = tab_x + tab_width - rightw
+        posx = tab_x + leftw
+        
+        while 1:
+            if posx >= available:
+                break
+            dc.DrawBitmap(center, posx, tab_y)
+            posx += centerw
+
+        dc.DrawBitmap(right, posx, tab_y)
+
+        drawn_tab_height = center.GetHeight()
+        text_offset = tab_x + leftw
+        
+        close_button_width = 0
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+            close_button_width = self._active_close_bmp.GetWidth()
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                text_offset += close_button_width
+
+        if not page.enabled:
+            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+            pagebitmap = page.dis_bitmap
+        else:
+            dc.SetTextForeground(page.text_colour)
+            pagebitmap = page.bitmap
+        
+        bitmap_offset = 0
+        if pagebitmap.IsOk():
+            bitmap_offset = tab_x + leftw
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
+                bitmap_offset += close_button_width
+
+            # draw bitmap
+            dc.DrawBitmap(pagebitmap, bitmap_offset,
+                          drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2),
+                          True)
+
+            text_offset = bitmap_offset + pagebitmap.GetWidth()
+            text_offset += 3 # bitmap padding
+        
+        else:
+        
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
+                text_offset = tab_x + leftw
+        
+        # if the caption is empty, measure some temporary text
+        caption = page.caption
+        if caption == "":
+            caption = "Xj"
+
+        if page.active:
+            dc.SetFont(self._selected_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+        else:
+            dc.SetFont(self._normal_font)
+            textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
+
+        if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - leftw)
+        else:
+            draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width - leftw)
+
+        ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1
+
+        if control is not None:
+            if control.GetPosition() != wx.Point(text_offset+1, ypos):
+                control.SetPosition(wx.Point(text_offset+1, ypos))
+
+            if not control.IsShown():
+                control.Show()
+
+            if paint_control:
+                bmp = TakeScreenShot(control.GetScreenRect())
+                dc.DrawBitmap(bmp, text_offset+1, ypos, True)
+                
+            controlW, controlH = control.GetSize()
+            text_offset += controlW + 4
+
+        # draw tab text
+        rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
+        dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
+                
+        out_button_rect = wx.Rect()
+        # draw 'x' on tab (if enabled)
+        if close_button_state != AUI_BUTTON_STATE_HIDDEN:
+        
+            close_button_width = self._active_close_bmp.GetWidth()
+            bmp = self._disabled_close_bmp
+
+            if close_button_state == AUI_BUTTON_STATE_HOVER:
+                bmp = self._hover_close_bmp
+            elif close_button_state == AUI_BUTTON_STATE_PRESSED:
+                bmp = self._pressed_close_bmp
+
+            if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
+                rect = wx.Rect(tab_x + leftw - 2,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + 1,
+                               close_button_width, tab_height)
+            else:
+                rect = wx.Rect(tab_x + tab_width - close_button_width - rightw + 2,
+                               drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + 1,
+                               close_button_width, tab_height)
+
+            if agwFlags & AUI_NB_BOTTOM:
+                rect.y -= 1
+                
+            # Indent the button if it is pressed down:
+            rect = IndentPressedBitmap(rect, close_button_state)
+            dc.DrawBitmap(bmp, rect.x, rect.y, True)
+            out_button_rect = rect
+            
+        out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
+        dc.DestroyClippingRegion()
+
+        return out_tab_rect, out_button_rect, x_extent        
+
+
diff --git a/aui/tabmdi.py b/aui/tabmdi.py
new file mode 100644 (file)
index 0000000..ef09e9f
--- /dev/null
@@ -0,0 +1,666 @@
+__author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
+__date__ = "31 March 2009"
+
+
+import wx
+
+import auibook
+from aui_constants import *
+
+_ = wx.GetTranslation
+
+#-----------------------------------------------------------------------------
+# AuiMDIParentFrame
+#-----------------------------------------------------------------------------
+
+class AuiMDIParentFrame(wx.Frame):
+
+    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.VSCROLL|wx.HSCROLL,
+                 name="AuiMDIParentFrame"):
+
+        wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
+        self.Init()
+
+        self.Bind(wx.EVT_MENU, self.DoHandleMenu, id=wx.ID_ANY)
+
+        # this style can be used to prevent a window from having the standard MDI
+        # "Window" menu
+        if not style & wx.FRAME_NO_WINDOW_MENU:
+        
+            self._pWindowMenu = wx.Menu()
+            self._pWindowMenu.Append(wxWINDOWCLOSE,    _("Cl&ose"))
+            self._pWindowMenu.Append(wxWINDOWCLOSEALL, _("Close All"))
+            self._pWindowMenu.AppendSeparator()
+            self._pWindowMenu.Append(wxWINDOWNEXT,     _("&Next"))
+            self._pWindowMenu.Append(wxWINDOWPREV,     _("&Previous"))
+    
+        self._pClientWindow = self.OnCreateClient()
+
+
+    def SetArtProvider(self, provider):
+
+        if self._pClientWindow:
+            self._pClientWindow.SetArtProvider(provider)
+    
+
+    def GetArtProvider(self):
+
+        if not self._pClientWindow:
+            return None
+
+        return self._pClientWindow.GetArtProvider()
+
+
+    def GetNotebook(self):
+
+        return self._pClientWindow
+
+
+    def SetWindowMenu(self, pMenu):
+
+        # Replace the window menu from the currently loaded menu bar.
+        pMenuBar = self.GetMenuBar()
+
+        if self._pWindowMenu:
+            self.RemoveWindowMenu(pMenuBar)
+            del self._pWindowMenu
+            self._pWindowMenu = None
+
+        if pMenu:
+            self._pWindowMenu = pMenu
+            self.AddWindowMenu(pMenuBar)
+        
+
+    def GetWindowMenu(self):
+
+        return self._pWindowMenu
+    
+
+    def SetMenuBar(self, pMenuBar):
+
+        # Remove the Window menu from the old menu bar
+        self.RemoveWindowMenu(self.GetMenuBar())
+
+        # Add the Window menu to the new menu bar.
+        self.AddWindowMenu(pMenuBar)
+
+        wx.Frame.SetMenuBar(self, pMenuBar)
+
+
+    def SetChildMenuBar(self, pChild):
+
+        if not pChild:
+        
+            # No Child, set Our menu bar back.
+            if self._pMyMenuBar:
+                self.SetMenuBar(self._pMyMenuBar)
+            else:
+                self.SetMenuBar(self.GetMenuBar())
+
+            # Make sure we know our menu bar is in use
+            self._pMyMenuBar = None
+        
+        else:
+        
+            if pChild.GetMenuBar() == None:
+                return
+
+            # Do we need to save the current bar?
+            if self._pMyMenuBar == None:
+                self._pMyMenuBar = self.GetMenuBar()
+
+            self.SetMenuBar(pChild.GetMenuBar())
+    
+
+    def ProcessEvent(self, event):
+
+        # stops the same event being processed repeatedly
+        if self._pLastEvt == event:
+            return False
+        
+        self._pLastEvt = event
+
+        # let the active child (if any) process the event first.
+        res = False
+        if self._pActiveChild and event.IsCommandEvent() and \
+           event.GetEventObject() != self._pClientWindow and \
+           event.GetEventType() not in [wx.wxEVT_ACTIVATE, wx.wxEVT_SET_FOCUS,
+                                        wx.wxEVT_KILL_FOCUS, wx.wxEVT_CHILD_FOCUS,
+                                        wx.wxEVT_COMMAND_SET_FOCUS, wx.wxEVT_COMMAND_KILL_FOCUS]:
+        
+            res = self._pActiveChild.GetEventHandler().ProcessEvent(event)
+        
+        if not res:
+        
+            # if the event was not handled this frame will handle it,
+            # which is why we need the protection code at the beginning
+            # of this method
+            res = self.GetEventHandler().ProcessEvent(event)
+        
+        self._pLastEvt = None
+
+        return res
+
+
+    def GetActiveChild(self):
+
+        return self._pActiveChild
+
+
+    def SetActiveChild(self, pChildFrame):
+
+        self._pActiveChild = pChildFrame
+
+
+    def GetClientWindow(self):
+
+        return self._pClientWindow
+
+
+    def OnCreateClient(self):
+
+        return AuiMDIClientWindow(self)
+
+
+    def ActivateNext(self):
+
+        if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND:
+        
+            active = self._pClientWindow.GetSelection() + 1
+            if active >= self._pClientWindow.GetPageCount():
+                active = 0
+
+            self._pClientWindow.SetSelection(active)
+        
+
+    def ActivatePrevious(self):
+
+        if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND:
+        
+            active = self._pClientWindow.GetSelection() - 1
+            if active < 0:
+                active = self._pClientWindow.GetPageCount() - 1
+
+            self._pClientWindow.SetSelection(active)
+    
+
+    def Init(self):
+
+        self._pLastEvt = None
+
+        self._pClientWindow = None
+        self._pActiveChild = None
+        self._pWindowMenu = None
+        self._pMyMenuBar = None
+
+
+    def RemoveWindowMenu(self, pMenuBar):
+
+        if pMenuBar and self._pWindowMenu:
+        
+            # Remove old window menu
+            pos = pMenuBar.FindMenu(_("&Window"))
+            if pos != wx.NOT_FOUND:            
+                pMenuBar.Remove(pos)
+            
+
+    def AddWindowMenu(self, pMenuBar):
+
+        if pMenuBar and self._pWindowMenu:
+        
+            pos = pMenuBar.FindMenu(wx.GetStockLabel(wx.ID_HELP, wx.STOCK_NOFLAGS))
+            if pos == wx.NOT_FOUND:
+                pMenuBar.Append(self._pWindowMenu, _("&Window"))
+            else:
+                pMenuBar.Insert(pos, self._pWindowMenu, _("&Window"))
+    
+
+    def DoHandleMenu(self, event):
+
+        evId = event.GetId()
+        
+        if evId == wxWINDOWCLOSE:
+            if self._pActiveChild:
+                self._pActiveChild.Close()
+
+        elif evId == wxWINDOWCLOSEALL:
+            
+            while self._pActiveChild:            
+                if not self._pActiveChild.Close():
+                    return # failure
+                
+        elif evId == wxWINDOWNEXT:
+            self.ActivateNext()
+
+        elif evId == wxWINDOWPREV:
+            self.ActivatePrevious()
+
+        else:
+            event.Skip()
+
+    
+    def Tile(self, orient=wx.HORIZONTAL):
+
+        client_window = self.GetClientWindow()
+        if not client_window:
+            raise Exception("Missing MDI Client Window")
+
+        cur_idx = client_window.GetSelection()
+        if cur_idx == -1:
+            return
+
+        if orient == wx.VERTICAL:
+        
+            client_window.Split(cur_idx, wx.LEFT)
+        
+        elif orient == wx.HORIZONTAL:
+        
+            client_window.Split(cur_idx, wx.TOP)
+    
+
+#-----------------------------------------------------------------------------
+# AuiMDIChildFrame
+#-----------------------------------------------------------------------------
+
+class AuiMDIChildFrame(wx.PyPanel):
+
+    def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="AuiMDIChildFrame"):
+
+        pClientWindow = parent.GetClientWindow()
+        if pClientWindow is None:
+            raise Exception("Missing MDI client window.")
+
+        self.Init()
+        
+        # see comment in constructor
+        if style & wx.MINIMIZE:
+            self._activate_on_create = False
+
+        cli_size = pClientWindow.GetClientSize()
+
+        # create the window off-screen to prevent flicker
+        wx.PyPanel.__init__(self, pClientWindow, id, wx.Point(cli_size.x+1, cli_size.y+1),
+                            size, wx.NO_BORDER, name=name)
+
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        self.Show(False)
+        self.SetMDIParentFrame(parent)
+
+        # this is the currently active child
+        parent.SetActiveChild(self)
+        self._title = title
+
+        pClientWindow.AddPage(self, title, self._activate_on_create)
+        pClientWindow.Refresh()
+
+        self.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight)
+        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+
+    def Init(self):
+
+        # There are two ways to create an tabbed mdi child fram without
+        # making it the active document.  Either Show(False) can be called
+        # before Create() (as is customary on some ports with wxFrame-type
+        # windows), or wx.MINIMIZE can be passed in the style flags.  Note that
+        # AuiMDIChildFrame is not really derived from wxFrame, as MDIChildFrame
+        # is, but those are the expected symantics.  No style flag is passed
+        # onto the panel underneath.
+
+        self._activate_on_create = True
+
+        self._pMDIParentFrame = None
+        self._pMenuBar = None
+        
+        self._mdi_currect = None
+        self._mdi_newrect = wx.Rect()
+        self._icon = None
+        self._icon_bundle = None
+
+
+    def Destroy(self):
+
+        pParentFrame = self.GetMDIParentFrame()
+        if not pParentFrame:
+            raise Exception("Missing MDI Parent Frame")
+
+        pClientWindow = pParentFrame.GetClientWindow()
+        if not pClientWindow:
+            raise Exception("Missing MDI Client Window")
+
+        if pParentFrame.GetActiveChild() == self:
+        
+            # deactivate ourself
+            event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, self.GetId())
+            event.SetEventObject(self)
+            self.GetEventHandler().ProcessEvent(event)
+
+            pParentFrame.SetActiveChild(None)
+            pParentFrame.SetChildMenuBar(None)
+        
+        for pos in xrange(pClientWindow.GetPageCount()):
+            if pClientWindow.GetPage(pos) == self:
+                return pClientWindow.DeletePage(pos)
+
+        return False
+
+
+    def SetMenuBar(self, menu_bar):
+
+        pOldMenuBar = self._pMenuBar
+        self._pMenuBar = menu_bar
+
+        if self._pMenuBar:
+        
+            pParentFrame = self.GetMDIParentFrame()
+            if not pParentFrame:
+                raise Exception("Missing MDI Parent Frame")
+
+            self._pMenuBar.Reparent(pParentFrame)
+            if pParentFrame.GetActiveChild() == self:
+            
+                # replace current menu bars
+                if pOldMenuBar:
+                    pParentFrame.SetChildMenuBar(None)
+                    
+                pParentFrame.SetChildMenuBar(self)
+            
+
+    def GetMenuBar(self):
+
+        return self._pMenuBar
+
+
+    def SetTitle(self, title):
+
+        self._title = title
+
+        pParentFrame = self.GetMDIParentFrame()
+        if not pParentFrame:
+            raise Exception("Missing MDI Parent Frame")
+        
+        pClientWindow = pParentFrame.GetClientWindow()
+        if pClientWindow is not None:
+        
+            for pos in xrange(pClientWindow.GetPageCount()):
+                if pClientWindow.GetPage(pos) == self:
+                    pClientWindow.SetPageText(pos, self._title)
+                    break
+
+
+    def GetTitle(self):
+
+        return self._title
+
+
+    def SetIcons(self, icons):
+
+        # get icon with the system icon size
+        self.SetIcon(icons.GetIcon(-1))
+        self._icon_bundle = icons
+
+
+    def GetIcons(self):
+
+        return self._icon_bundle
+
+
+    def SetIcon(self, icon):
+
+        pParentFrame = self.GetMDIParentFrame()
+        if not pParentFrame:
+            raise Exception("Missing MDI Parent Frame")
+
+        self._icon = icon
+
+        bmp = wx.BitmapFromIcon(self._icon)
+
+        pClientWindow = pParentFrame.GetClientWindow()
+        if pClientWindow is not None:
+            idx = pClientWindow.GetPageIndex(self)
+            if idx != -1:
+                pClientWindow.SetPageBitmap(idx, bmp)
+        
+
+    def GetIcon(self):
+
+        return self._icon
+
+
+    def Activate(self):
+
+        pParentFrame = self.GetMDIParentFrame()
+        if not pParentFrame:
+            raise Exception("Missing MDI Parent Frame")
+        
+        pClientWindow = pParentFrame.GetClientWindow()
+        if pClientWindow is not None:
+        
+            for pos in xrange(pClientWindow.GetPageCount()):
+                if pClientWindow.GetPage(pos) == self:
+                    pClientWindow.SetSelection(pos)
+                    break
+            
+
+    def OnMenuHighlight(self, event):
+
+        if self._pMDIParentFrame:
+    
+            # we don't have any help text for this item,
+            # but may be the MDI frame does?
+            self._pMDIParentFrame.OnMenuHighlight(event)
+
+
+    def OnActivate(self, event):
+
+        # do nothing
+        pass
+
+
+    def OnCloseWindow(self, event):
+
+        pParentFrame = self.GetMDIParentFrame()
+        if pParentFrame:
+            if pParentFrame.GetActiveChild() == self:
+            
+                pParentFrame.SetActiveChild(None)
+                pParentFrame.SetChildMenuBar(None)
+            
+            pClientWindow = pParentFrame.GetClientWindow()
+            idx = pClientWindow.GetPageIndex(self)
+            
+            if idx != wx.NOT_FOUND:
+                pClientWindow.RemovePage(idx)
+
+        self.Destroy()
+
+
+    def SetMDIParentFrame(self, parentFrame):
+
+        self._pMDIParentFrame = parentFrame
+
+
+    def GetMDIParentFrame(self):
+
+        return self._pMDIParentFrame
+
+
+    def CreateStatusBar(self, number=1, style=1, winid=1, name=""):
+        
+        return None
+
+
+    def GetStatusBar(self):
+
+        return None
+    
+
+    def SetStatusText(self, text, number=0):
+
+        pass
+
+    
+    def SetStatusWidths(self, widths_field):
+
+        pass
+    
+
+    # no toolbar bars
+    def CreateToolBar(self, style=1, winid=-1, name=""):
+        
+        return None
+
+    
+    def GetToolBar(self):
+
+        return None
+    
+
+    # no maximize etc
+    def Maximize(self, maximize=True):
+
+        pass
+
+
+    def Restore(self):
+    
+        pass
+
+    
+    def Iconize(self, iconize=True):
+
+        pass
+
+    
+    def IsMaximized(self):
+
+        return True
+
+    
+    def IsIconized(self):
+
+        return False
+
+    
+    def ShowFullScreen(self, show=True, style=0):
+
+        return False
+
+    
+    def IsFullScreen(self):
+
+        return False        
+
+
+    def IsTopLevel(self):
+
+        return False
+
+
+    # renamed from Show().
+    def ActivateOnCreate(self, activate_on_create):
+
+        self._activate_on_create = activate_on_create
+        return True
+
+    
+    def Show(self, show=True):
+
+        wx.PyPanel.Show(self, show)
+
+
+    def ApplyMDIChildFrameRect(self):
+
+        if self._mdi_currect != self._mdi_newrect:
+            self.SetDimensions(*self._mdi_newrect)
+            self._mdi_currect = wx.Rect(*self._mdi_newrect)
+
+
+#-----------------------------------------------------------------------------
+# AuiMDIClientWindow
+#-----------------------------------------------------------------------------
+
+class AuiMDIClientWindow(auibook.AuiNotebook):
+
+    def __init__(self, parent, agwStyle=0):
+
+        auibook.AuiNotebook.__init__(self, parent, wx.ID_ANY, wx.Point(0, 0), wx.Size(100, 100),
+                                     agwStyle=AUI_NB_DEFAULT_STYLE|wx.NO_BORDER)
+
+        caption_icon_size = wx.Size(wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_X),
+                                    wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_Y))
+        self.SetUniformBitmapSize(caption_icon_size)
+
+        bkcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_APPWORKSPACE)
+        self.SetOwnBackgroundColour(bkcolour)
+
+        self._mgr.GetArtProvider().SetColour(AUI_DOCKART_BACKGROUND_COLOUR, bkcolour)
+
+        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+
+
+    def SetSelection(self, nPage):
+
+        return auibook.AuiNotebook.SetSelection(self, nPage)
+
+
+    def PageChanged(self, old_selection, new_selection):
+
+        # don't do anything if the page doesn't actually change
+        if old_selection == new_selection:
+            return
+
+        # notify old active child that it has been deactivated
+        if old_selection != -1 and old_selection < self.GetPageCount():
+        
+            old_child = self.GetPage(old_selection)
+            if not old_child:
+                raise Exception("AuiMDIClientWindow.PageChanged - null page pointer")
+
+            event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, old_child.GetId())
+            event.SetEventObject(old_child)
+            old_child.GetEventHandler().ProcessEvent(event)
+        
+        # notify new active child that it has been activated
+        if new_selection != -1:
+        
+            active_child = self.GetPage(new_selection)
+            if not active_child:
+                raise Exception("AuiMDIClientWindow.PageChanged - null page pointer")
+
+            event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, True, active_child.GetId())
+            event.SetEventObject(active_child)
+            active_child.GetEventHandler().ProcessEvent(event)
+
+            if active_child.GetMDIParentFrame():
+                active_child.GetMDIParentFrame().SetActiveChild(active_child)
+                active_child.GetMDIParentFrame().SetChildMenuBar(active_child)
+
+
+    def OnPageClose(self, event):
+
+        wnd = self.GetPage(event.GetSelection())
+        wnd.Close()
+
+        # regardless of the result of wnd.Close(), we've
+        # already taken care of the close operations, so
+        # suppress further processing
+        event.Veto()
+
+
+    def OnPageChanged(self, event):
+
+        self.PageChanged(event.GetOldSelection(), event.GetSelection())
+
+
+    def OnSize(self, event):
+
+        auibook.AuiNotebook.OnSize(self, event)
+
+        for pos in xrange(self.GetPageCount()):
+            self.GetPage(pos).ApplyMDIChildFrameRect()
index 3b3ee17..b441a32 100644 (file)
@@ -221,7 +221,6 @@ ChdTxtPathOut = {'TableUc1': 'TableUc1.csv',
         'R3DCoul': ffr(tempfile.mkstemp(prefix='iramuteq')[1]),
         'RESULT_CHD':  'resultats-chd.html',
         'RESULT_AFC':  'resultats-afc.html',
-        'Act01':  'Act01.csv',
         'Et01':  'Et01.csv',
         'Rchdquest':ffr(tempfile.mkstemp(prefix='iramuteq')[1]),
         'RTxtProfGraph':ffr(tempfile.mkstemp(prefix='iramuteq')[1]),
index e043707..7cc9306 100644 (file)
--- a/corpus.py
+++ b/corpus.py
@@ -11,7 +11,6 @@ from time import time
 from functions import decoupercharact, ReadDicoAsDico, DoConf
 import re
 import sqlite3
-import numpy
 import itertools
 import logging
 from operator import itemgetter
index 8a10f67..e72ebd9 100644 (file)
@@ -45,14 +45,17 @@ class History :
     def read(self) :
         d = shelve.open(self.filein)
         self.history = d.get('history', [])
+        self.matrix = d.get('matrix', [])
         self.ordercorpus = dict([[corpus['uuid'], i] for i, corpus in enumerate(self.history)])
-        self.corpus = dict([[corpus['uuid'], corpus] for i, corpus in enumerate(self.history)])
+        self.corpus = dict([[corpus['uuid'], corpus] for corpus in self.history])
         self.analyses = dict([[analyse['uuid'], analyse] for corpus in self.history for analyse in corpus.get('analyses', [])])
+        self.matrixanalyse = dict([[mat['uuid'], mat] for mat in self.matrix])
         d.close()
 
     def write(self) :
         d = shelve.open(self.filein)
         d['history'] = self.history
+        d['matrix'] = self.matrix
         d.close()
     
     def add(self, analyse) :
@@ -77,6 +80,13 @@ class History :
         self.write()
         self.read()
 
+    def addMatrix(self, analyse) :
+        tosave = {'uuid' : analyse['uuid'], 'ira': analyse['ira'], 'type' : analyse['type']}
+        tosave['name'] = analyse['name']
+        self.matrix.append(tosave)
+        self.write()
+        self.read()
+
     def addmultiple(self, analyses) :
         for analyse in analyses :
             tosave = {'uuid' : analyse['uuid'], 'ira': analyse['ira'], 'type' : analyse['type']}
@@ -96,9 +106,11 @@ class History :
             self.history.pop(self.ordercorpus[analyse['uuid']])
             if analyse['uuid'] in self.openedcorpus :
                 del self.openedcorpus[analyse['uuid']]
-        else :
+        elif analyse['uuid'] in self.analyses :
             todel = [i for i, ana in enumerate(self.corpus[analyse['corpus']]['analyses']) if ana['uuid'] == analyse['uuid']][0]
             self.history[self.ordercorpus[analyse['corpus']]]['analyses'].pop(todel)
+        elif analyse['uuid'] in self.matrixanalyse :
+            self.matrix = [mat for mat in self.matrix if mat['uuid'] != analyse['uuid']]
         self.write()
         self.read()
 
index aad2ebd..c59894b 100644 (file)
@@ -28,8 +28,10 @@ import logging
 #------------------------------------
 import wx
 #import wx.aui
-import wx.lib.agw.aui as aui
-#import agw.aui as aui
+if wx.__version__ >= '2.11' :
+    import wx.lib.agw.aui as aui
+else :
+    import aui
 import wx.html
 import wx.grid
 import wx.lib.hyperlink as hl
index 0e2d5a9..2a30f5c 100644 (file)
--- a/layout.py
+++ b/layout.py
@@ -7,8 +7,10 @@
 import os
 import wx
 import wx.lib.hyperlink as hl
-#import agw.aui as aui
-import wx.lib.agw.aui as aui
+if wx.__version__ >= '2.11' :
+    import wx.lib.agw.aui as aui
+else :
+    import aui
 from chemins import ConstructPathOut, ChdTxtPathOut, FFF, ffr, PathOut, StatTxtPathOut, simipath
 from ConfigParser import ConfigParser
 from functions import ReadProfileAsDico, GetTxtProfile, read_list_file, ReadList, exec_rcode, print_liste, BugReport, DoConf, indices_simi, check_Rresult, progressbar
@@ -303,16 +305,16 @@ class OpenCHDS():
 
        Profile = DictPathOut['PROFILE_OUT']
        AntiProfile = DictPathOut['ANTIPRO_OUT']
+       self.encoding = self.corpus.parametres['syscoding']
        if isinstance(self.corpus, Corpus) :
-            self.encoding = self.corpus.parametres['syscoding']
             self.corpus.make_ucecl_from_R(self.pathout['uce'])
-       elif 'tableau' in dir(gparent) :
-            self.encoding = gparent.tableau.parametres['syscoding']
+            corpname = self.corpus.parametres['corpus_name']
+       else :
+           corpname = self.corpus.parametres['name']
 
        clnb = parametres['clnb']
        dlg = progressbar(self, maxi = 4 + clnb) 
        self.clnb = clnb 
-       corpname = self.corpus.parametres['corpus_name']
        print 'lecture des profils'
        dlg.Update(2, u'lecture des profils')
  
@@ -336,12 +338,14 @@ class OpenCHDS():
 
        if isinstance(self.corpus, Corpus) :
            panel.corpus = self.corpus
-           panel.dictpathout = self.DictPathOut
-           panel.pathout = self.DictPathOut
-           panel.parent = self.parent
-           panel.DictProfile = self.DictProfile
-           panel.cluster_size = self.cluster_size
-           panel.debtext = self.debtext
+       else :
+           panel.tableau = self.corpus
+       panel.dictpathout = self.DictPathOut
+       panel.pathout = self.DictPathOut
+       panel.parent = self.parent
+       panel.DictProfile = self.DictProfile
+       panel.cluster_size = self.cluster_size
+       panel.debtext = self.debtext
 
 #       self.ID_rapport = wx.NewId()
 #       #rap_img = wx.Image(os.path.join(self.parent.images_path,'icone_rap_16.png'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
@@ -365,8 +369,11 @@ class OpenCHDS():
        if isinstance(self.corpus, Corpus) :
            panel.TabChdSim.corpus = corpus
            panel.TabChdSim.corpus.dictpathout = self.DictPathOut
-           panel.parametres = self.parametres
-           self.panel = panel
+       else :
+           panel.TabChdSim.tableau = corpus
+           panel.TabChdSim.tableau.dictpathout = self.DictPathOut
+       panel.parametres = self.parametres
+       self.panel = panel
 
        self.notenb = self.parent.nb.GetPageCount()
 
@@ -542,7 +549,7 @@ class OpenCHDS():
     
         
 
-def PrintRapport(self, corpus, parametres, txt = True):
+def PrintRapport(self, corpus, parametres, istxt = True):
     #if sys.platform == 'win32':
     #    sep = '\r\n'
     #else:
@@ -554,8 +561,9 @@ def PrintRapport(self, corpus, parametres, txt = True):
 
 
 """ % datetime.datetime.now().ctime()
-    totocc = corpus.gettotocc()
-    if txt :
+    print istxt
+    if istxt :
+        totocc = corpus.gettotocc()
         txt += u'nombre d\'uci: %i%s' % (corpus.getucinb(), sep)
         txt += u'nombre d\'uce: %i%s' % (corpus.getucenb(), sep)
         txt += u'nombre de formes: %i%s' % (len(corpus.formes), sep)
@@ -571,24 +579,24 @@ def PrintRapport(self, corpus, parametres, txt = True):
                 txt += u'taille uc1 : %i\n' % parametres['tailleuc1']
             else:
                 txt += u'taille uc1 / uc2: %i / %i - %i / %i%s' % (parametres['tailleuc1'], parametres['tailleuc2'], parametres['lenuc1'], parametres['lenuc2'], sep)
-    elif not txt :
+    else :
         self.Ucenb = self.nbind
         txt += u'nombre d\'individus : %i%s' % (self.nbind, sep)
         txt += u'nombre de classes : %i%s' % (self.clnb, sep)
-    if txt :
+    if istxt :
         txt += u'nombre de classes : %i%s' % (parametres['clnb'], sep)
         if parametres['classif_mode'] == 0 or parametres['classif_mode'] == 1 :
             txt += u'%i uce classées sur %i (%.2f%%)%s' % (sum([len(cl) for cl in corpus.lc]), corpus.getucenb(), (float(sum([len(cl) for cl in corpus.lc])) / float(corpus.getucenb())) * 100, sep)
         elif self.parametres['classif_mode'] == 2 :
             txt += u'%i uci classées sur %i (%.2f%%)%s' % (sum([len(cl) for cl in corpus.lc]), corpus.getucinb(), (float(sum([len(cl) for cl in corpus.lc]))) / float(corpus.getucinb()) * 100, sep)
-    elif analyse == 'quest' :
+    else :
         txt += u'%i uce classées sur %i (%.2f%%)%s' % (self.ucecla, self.Ucenb, (float(self.ucecla) / float(self.Ucenb)) * 100, sep)
  
     txt += """
 ###########################
 temps d'analyse : %s
 ###########################
-""" % parametres['time']
+""" % parametres.get('time', '')
     with open(self.pathout['pre_rapport'], 'w') as f :
         f.write(txt)
 
index 2237fcc..75607f3 100644 (file)
@@ -67,7 +67,7 @@ class ListForSpec(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ColumnSor
         self.SetColumnWidth(0, 180)
 
         for i in range(1,len(first)-1):
-            self.SetColumnWidth(i, len(first[i]) * 10)
+            self.SetColumnWidth(i, self.checkcolumnwidth(len(first[i]) * 10))
         
         self.itemDataMap = dlist
         self.itemIndexMap = dlist.keys()
@@ -88,6 +88,12 @@ class ListForSpec(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ColumnSor
 
 #-----------------------------------------------------------------------------------------    
         
+    def checkcolumnwidth(self, width) :
+        if width < 80 :
+            return 80
+        else :
+            return width
+
     def OnGetItemText(self, item, col):
         index=self.itemIndexMap[item]
         s = self.itemDataMap[index][col]
index 29a0d63..2cf40c8 100644 (file)
@@ -4,7 +4,7 @@
 #Copyright (c) 2008-2012, Pierre Ratinaud
 #Lisense: GNU/GPL
 
-from chemins import ChdTxtPathOut, StatTxtPathOut, construct_simipath
+from chemins import ChdTxtPathOut, StatTxtPathOut, construct_simipath, PathOut
 from layout import OpenCHDS, dolexlayout, StatLayout, WordCloudLayout, OpenCorpus, SimiLayout
 from corpus import Corpus, copycorpus
 from tableau import Tableau
@@ -12,6 +12,7 @@ import os
 import shelve
 from tabsimi import DoSimi
 from functions import BugReport, DoConf
+from tableau import Tableau
 import logging
 
 log = logging.getLogger('iramuteq.openanalyse')
@@ -30,7 +31,7 @@ class OpenAnalyse():
         
         if self.conf['type'] == 'corpus' :
             corpus = self.opencorpus()
-        elif self.conf['corpus'] in self.parent.history.corpus :
+        elif self.conf.get('corpus', False) in self.parent.history.corpus :
             if self.conf['uuid'] in self.parent.history.analyses :
                 intree  = True
             else :
@@ -47,6 +48,19 @@ class OpenAnalyse():
             self.doopen(corpus)
         else :
             corpus = None
+            if isinstance(parametres, dict) :
+                tableau = Tableau(parent, parametres['ira'])
+            else :
+                tableau = Tableau(parent, parametres)
+            tableau.parametres = self.conf 
+            tableau.dictpathout = PathOut(filename = tableau.parametres['filename'], dirout = self.conf['pathout'], analyse_type = self.conf['type'])
+            tableau.dictpathout.basefiles(ChdTxtPathOut)
+            tableau.read_tableau(tableau.dictpathout['db'])
+            if self.parent.tree.IsInTree(uuid = self.conf['uuid']) :
+                self.parent.tree.GiveFocus(uuid = self.conf['uuid'], bold = True)
+            else :
+                self.parent.tree.AddAnalyse(self.conf, bold = True)
+            self.doopen(tableau)
         self.parent.history.addtab(self.conf)
     
     def redopath(self, conf, path) :
@@ -116,4 +130,7 @@ class OpenAnalyse():
         elif self.conf['type'] == 'wordcloud' :
             self.parent.ShowMenu(_("Text analysis"))
             WordCloudLayout(self.parent, corpus, self.conf)
+        elif self.conf['type'] == 'gnepamatrix' :
+            self.parent.ShowMenu(_("Spreadsheet analysis"))
+            OpenCHDS(self.parent,  corpus, self.conf, Alceste = False)
         
index 9a89195..1eeee9c 100644 (file)
@@ -6,8 +6,12 @@
 
 import tempfile
 from ProfList import *
+import wx
+if wx.__version__ >= '2.11' :
 #import agw.aui as aui
-import wx.lib.agw.aui as aui
+    import wx.lib.agw.aui as aui
+else :
+    import aui
 from functions import exec_rcode, check_Rresult, ReadProfileAsDico, ReadList
 from listlex import *
 from dialog import PrefSegProf, PrefProfTypes
index 39fd377..03d7a66 100644 (file)
@@ -4,15 +4,15 @@
 #Copyright (c) 2008-2009 Pierre Ratinaud
 #Lisense: GNU/GPL
 
-from chemins import ConstructPathOut, ChdTxtPathOut, ConstructAfcUciPath, ffr
+from chemins import ConstructPathOut, ChdTxtPathOut, ConstructAfcUciPath, ffr, PathOut
 from functions import sortedby, CreateIraFile, print_liste, exec_rcode, check_Rresult
 from PrintRScript import RchdQuest
 from layout import OpenCHDS, PrintRapport
 from dialog import PrefQuestAlc
+from analysematrix import AnalyseMatrix
 import os
 import sys
 import wx
-from numpy import *
 import tempfile
 import time
 
@@ -22,52 +22,63 @@ class AnalyseQuest():
         dlg = PrefQuestAlc(parent)
         dlg.CenterOnParent()
         self.val = dlg.ShowModal()
+        parametres = parent.tableau.parametre
         if self.val == wx.ID_OK :
+            parametres['nbcl_p1'] = dlg.spin_nbcl.GetValue()
+            parametres['mincl'] = dlg.spin_mincl.GetValue()
             if dlg.m_radioBox1.GetSelection() == 1 :
-                ListAct = dlg.nactives
-                ListSup = dlg.varsup
-                nbcl_p1 = dlg.spin_nbcl.GetValue()
-                mincl = dlg.spin_mincl.GetValue()
-                DoQuestAlceste(parent, ListAct, ListSup, nbcl = nbcl_p1, mincl = mincl)
-            else:
-                nbcl_p1 = dlg.spin_nbcl.GetValue()
-                mincl = dlg.spin_mincl.GetValue()
-                DoQuestAlceste(parent, nbcl = nbcl_p1, mincl = mincl) 
+                parametres['listact'] = dlg.nactives
+                parametres['listsup'] = dlg.varsup
+            else :
+                parametres['formatted'] = 1
+            DoQuestAlceste(parent, parametres)
 
-class DoQuestAlceste:
-    def __init__(self, parent, ListAct=False, ListSup=False, nbcl = 10, mincl = 10):
-        self.t1 = time.time()
-#-------------------------------------------------------------------               
-        dlg = wx.ProgressDialog("Traitements",
-                               "Veuillez patienter...",
-                               maximum=5,
-                               parent=parent,
-                               style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_ELAPSED_TIME
-                                )
-        dlg.Center()
-        count = 1
-        keepGoing = dlg.Update(count)
-#-------------------------------------------------------------------
-        self.pathout = ConstructPathOut(parent.tableau.parametre['filename'], 'AlcesteQuest')
+class DoQuestAlceste(AnalyseMatrix):
+    def __init__(self, parent, parametres):
+        parametres['pathout'] = ConstructPathOut(parent.tableau.parametre['filename'], 'gnepaMatrix')
+        self.parametres = parametres
+        self.parametres['type'] = 'gnepamatrix'
         self.DictForme = {}
         self.DictFormeSup = {}
         self.Min = 10
         self.Linecontent = []
         self.parent = parent
         self.RPath = self.parent.PathPath.get('PATHS', 'rpath')
-        self.dictpathout = ChdTxtPathOut(self.pathout)
-        self.parent.tableau.dictpathout = self.dictpathout
+        #self.dictpathout = PathOut(dirout = self.pathout)
+        #self.dictpathout = self.pathout
+        #self.dictpathout.basefiles(ChdTxtPathOut)
+        #self.pathout = self.dictpathout
         self.clnb = ''
-        self.ListAct = ListAct
+        self.ListAct = parametres.get('listact', False)
         self.ucecla = ''
-        self.parent = parent
+        dlg = wx.ProgressDialog("Traitements",
+                               "Veuillez patienter...",
+                               maximum=5,
+                               parent=self.parent,
+                               style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_ELAPSED_TIME
+                                )
+
+        AnalyseMatrix.__init__(self, parent, parent.tableau, self.parametres, dlg = dlg)
+
+
 #-----------------------------------------------------------
+    def doanalyse(self) :
+#-------------------------------------------------------------------               
+        self.dictpathout = self.pathout
+        self.dictpathout.basefiles(ChdTxtPathOut)
+        self.parent.tableau.dictpathout = self.dictpathout
+
+        self.dlg.Center()
+        count = 1
+        keepGoing = self.dlg.Update(count)
+#-------------------------------------------------------------------
         count += 1
-        dlg.Update(count, u"passage en O/1")
-        if not ListAct:
-            self.parent.tableau.make_01_alc_format(self.dictpathout['Act01'])
+        self.dlg.Update(count, u"passage en O/1")
+        if 'formatted' in self.parametres:
+            self.parent.tableau.make_01_alc_format(self.dictpathout['mat01'])
         else:
-            self.parent.tableau.make_01_from_selection(ListAct, ListSup)
+            self.parent.tableau.make_01_from_selection(self.parametres['listact'], self.parametres['listsup'])
         file = open(self.dictpathout['listeuce1'], 'w')
         file.write('num uce;num uc\n')
         for i in range(0, len(self.parent.tableau.linecontent)):
@@ -75,27 +86,28 @@ class DoQuestAlceste:
         file.close()
         self.nbind = len(self.parent.tableau.linecontent)
 #------------------------------------------------------------
-        RchdQuest(self.dictpathout, parent.RscriptsPath, nbcl, mincl)
+        RchdQuest(self.dictpathout, self.parent.RscriptsPath, self.parametres['nbcl_p1'], self.parametres['mincl'])
 #------------------------------------------------------------
         count += 1
-        dlg.Update(count, u"Analyse (patientez...)")
+        self.dlg.Update(count, u"Analyse (patientez...)")
         
         pid = exec_rcode(self.RPath, self.dictpathout['Rchdquest'], wait = False)
         while pid.poll() == None :
-            dlg.Pulse(u"Analyse (patientez...)")
+            self.dlg.Pulse(u"Analyse (patientez...)")
             time.sleep(0.2)
         check_Rresult(self.parent, pid)
 #------------------------------------------------------------
         count += 1
-        dlg.Update(count, u"Ecriture des résultats")
+        self.dlg.Update(count, u"Ecriture des résultats")
         self.parent.tableau.buildprofil()
         self.clnb = self.parent.tableau.clnb
+        self.parametres['clnb'] = self.clnb
         self.ucecla = self.parent.tableau.ucecla
         self.BuildProfile()
         temps = time.time() - self.t1
-        PrintRapport(self, 'quest')
+        PrintRapport(self, self, {}, istxt = False)
         self.parent.tableau.save_tableau(self.dictpathout['db'])
-        CreateIraFile(self.dictpathout, self.clnb, corpname = os.path.basename(parent.filename), section = 'questionnaire')
+        #CreateIraFile(self.dictpathout, self.clnb, corpname = os.path.basename(self.parent.filename), section = 'questionnaire')
         afc_graph_list = [[os.path.basename(self.dictpathout['AFC2DL_OUT']), u'Variables actives - coordonnées - facteurs 1 / 2'],
                          [os.path.basename(self.dictpathout['AFC2DSL_OUT']), u'variables illustratives - coordonnées - facteurs 1 / 2'],
                          [os.path.basename(self.dictpathout['AFC2DCL_OUT']), u'Classes - Coordonnées - facteur 1 / 2'],
@@ -108,11 +120,11 @@ class DoQuestAlceste:
         print_liste(self.dictpathout['liste_graph_chd'], chd_graph_list)
 
         self.tableau = self.parent.tableau
-        OpenCHDS(self.parent, self, self.dictpathout['ira'], False)
+        #OpenCHDS(self.parent, self, self.dictpathout['ira'], False)
 #------------------------------------------------------------
         print 'fini', time.time() - self.t1
         count += 1
-        dlg.Update(count, "Fini")
+        self.dlg.Update(count, "Fini")
     
     def BuildProfile(self):
         print 'build profile'
index 2508bb4..6010eaa 100644 (file)
@@ -13,7 +13,6 @@ from ConfigParser import ConfigParser
 from functions import CreateIraFile, print_liste, exec_rcode, check_Rresult
 from dialog import CHDDialog, PrefQuestAlc, ClusterNbDialog
 import tempfile
-from numpy import *
 import time
 
 
index a8f7428..06f58e8 100644 (file)
@@ -7,12 +7,15 @@ import codecs
 import sys
 import xlrd
 import ooolib
+import os
 import tempfile
 import re
 import htmlentitydefs
-from numpy import *
 import shelve
+from uuid import uuid4
+import logging
 
+log = logging.getLogger('iramuteq.tableau')
 
 ##
 # Removes HTML or XML character references and entities from a text string.
@@ -55,8 +58,11 @@ class Tableau() :
         self.parametre = {'filename' : filename}
         self.parametre['filetype'] = filetype
         self.parametre['encodage'] = encodage
+        self.parametre['pathout'] = os.path.dirname(os.path.abspath(filename))
         self.parametre['mineff'] = 3
         self.parametre['syscoding'] = sys.getdefaultencoding()
+        self.parametre['type'] = 'matrix'
+        self.parametre['name'] = 'unNOm'
         self.sups = {}
         self.actives = {}
         self.listactives = None
@@ -71,6 +77,7 @@ class Tableau() :
         self.colnb = 0
         self.rownb = 0
         self.classes = []
+        self.parametres = self.parametre
 
     def read_tableau(self, fileout) :
         d=shelve.open(fileout)
@@ -200,9 +207,8 @@ class Tableau() :
         return dico
     
     def select_col(self, listcol) :
-        ArTable = array(self.linecontent)
-        selcol = ArTable[:, listcol]
-        selcol = selcol.tolist()
+        dc = dict(zip(listcol, listcol))
+        selcol = [[val for i, val in enumerate(row) if i in dc] for row in self.linecontent]
         return selcol
     
     def write01(self, fileout, dico, linecontent) :
@@ -220,10 +226,7 @@ class Tableau() :
     def make_01_from_selection(self, listact, listsup = None, dowrite = True) :
         selcol = self.select_col(listact)
         self.actives = self.make_dico(selcol)
-        if 'Act01' in self.dictpathout and dowrite:
-            self.write01(self.dictpathout['Act01'], self.actives, selcol)
-        elif 'mat01' in self.dictpathout and dowrite:
-            self.write01(self.dictpathout['mat01'], self.actives, selcol)
+        self.write01(self.dictpathout['mat01'], self.actives, selcol)
         if listsup is not None :
             selcol = self.select_col(listsup)
             self.sups = self.make_dico(selcol)
index 2af9792..8a5ca35 100644 (file)
@@ -10,8 +10,10 @@ from dialog import SelectColDial, OptLexi
 from guifunct import PrefSimi
 from listlex import *
 import wx
-import wx.lib.agw.aui as aui
-from numpy import *
+if wx.__version__ >= '2.11' :
+    import wx.lib.agw.aui as aui
+else :
+    import aui
 import os
 import tempfile
 import datetime
index 031e4e7..fd34232 100644 (file)
@@ -12,7 +12,6 @@ import wx
 import os
 import sys
 import tempfile
-from numpy import *
 from functions import exec_rcode, check_Rresult
 from time import sleep
 
index a866276..5ff4c37 100644 (file)
@@ -208,10 +208,11 @@ class Lexico(AnalyseText) :
         tmpscript = open(tmpfile, 'w')
         tmpscript.write(txt)
         tmpscript.close()
-        pid = exec_rcode(self.parent.RPath, tmpfile, wait = False)
-        while pid.poll() == None :
-            sleep(0.2)
-        check_Rresult(self.parent, pid)
+        self.doR(tmpfile, dlg = self.dlg, message = 'R...')
+        #pid = exec_rcode(self.parent.RPath, tmpfile, wait = False)
+        #while pid.poll() == None :
+        #    sleep(0.2)
+        #check_Rresult(self.parent, pid)
 
     def preferences(self) :
         listet = self.corpus.make_etoiles()
@@ -294,9 +295,11 @@ class Lexico(AnalyseText) :
 
         tabout = self.corpus.make_efftype_from_etoiles(self.listet)
         write_tab(tabout, self.dictpathout['tabletypem'])
-        #dlg.Update(2, u'R...')
+        if self.dlg :
+            self.dlg.Update(2, u'R...')
         self.DoR()
-        #dlg.Update(3, u'Chargement...')
+        if self.dlg :
+            self.dlg.Update(3, u'Chargement...')
         afcf_graph_list = [[os.path.basename(self.dictpathout['afcf_row']), u'lignes'],\
                             [os.path.basename(self.dictpathout['afcf_col']), u'colonnes']]
         afct_graph_list = [[os.path.basename(self.dictpathout['afct_row']), u'lignes'],\
index 918ee44..8650be1 100644 (file)
@@ -61,21 +61,21 @@ class SimiTxt(AnalyseText):
         else : 
             return False
 
-    def preferences(self) :
-        dial = StatDialog(self, self.parent)
-        dial.CenterOnParent()
-        val = dial.ShowModal()
-        if val == 5100 :
-            if dial.radio_lem.GetSelection() == 0 :
-                lem = 1
-            else :
-                lem = 0            
-            self.parametres['lem'] = lem
-            dial.Destroy()
-            return self.parametres
-        else :
-            dial.Destroy()
-            return None
+#    def preferences(self) :
+#        dial = StatDialog(self, self.parent)
+#        dial.CenterOnParent()
+#        val = dial.ShowModal()
+#        if val == 5100 :
+#            if dial.radio_lem.GetSelection() == 0 :
+#                lem = 1
+#            else :
+#                lem = 0            
+#            self.parametres['lem'] = lem
+#            dial.Destroy()
+#            return self.parametres
+#        else :
+#            dial.Destroy()
+#            return None
 
     def makesimiparam(self) :
         self.paramsimi = {'coeff' : 0,
index d14522f..afc9ff1 100644 (file)
@@ -31,20 +31,7 @@ class Stat(AnalyseText) :
         self.make_stats()
 
     def preferences(self) :
-        dial = StatDialog(self, self.parent)
-        dial.CenterOnParent()
-        val = dial.ShowModal()
-        if val == 5100 :
-            if dial.radio_lem.GetSelection() == 0 :
-                lem = 1
-            else :
-                lem = 0            
-            self.parametres['lem'] = lem
-            dial.Destroy()
-            return self.parametres
-        else :
-            dial.Destroy()
-            return None
+        return self.parametres
 
     def make_stats(self):
         if self.dlg :
diff --git a/tools.py b/tools.py
new file mode 100644 (file)
index 0000000..3b1b0d9
--- /dev/null
+++ b/tools.py
@@ -0,0 +1,156 @@
+#!/bin/env python
+# -*- coding: utf-8 -*-
+#Author: Pierre Ratinaud
+#Copyright (c) 2008-2013, Pierre Ratinaud
+#Lisense: GNU GPL
+
+import codecs
+import os
+from dialog import ExtractDialog
+from corpus import Corpus, copycorpus
+import wx
+
+
+parametres = {'filein' : 'corpus/lru2.txt',
+              'encodein' : 'utf8',
+              'encodeout' : 'utf8',
+              'mods' : [u'*annee_2010', u'*annee_2011']}
+
+def istext(line) :
+    if line.startswith(u'**** ') :
+        return True
+    else :
+        return False
+
+def testvar(line, variable) :
+    line = line.split()
+    varmod = [val.split('_') for val in line[1:]]
+    vars = [var[0] for var in varmod]
+    if variable in vars :
+        return '_'.join([variable, varmod[vars.index(variable)][1]]).replace(u'*','')
+    else :
+        return False
+
+def testmod(line, mods) :
+    line = line.split()
+    for mod in mods :
+        if mod in line[1:] :
+            return mod.replace(u'*','')
+    return False
+
+
+class Extract :
+    def __init__(self, parent, option) :
+        dial = ExtractDialog(parent, option)
+        dial.CenterOnParent()
+        res = dial.ShowModal()
+        if res == wx.ID_OK :
+            parametres = dial.make_param()
+            if option == 'splitvar' :
+                SplitFromVar(parametres)
+            else :
+                ExtractMods(parametres)
+
+class SplitFromVar :
+    def __init__(self, parametres) :
+        self.filein = parametres['filein']
+        self.var = parametres['var']
+        self.encodein = parametres['encodein']
+        self.encodeout = parametres['encodeout']
+        self.basepath = os.path.dirname(self.filein)
+        self.doparse()
+
+    def doparse(self) :
+        keepline = False
+        filedict = {}
+        with codecs.open(self.filein, 'r', self.encodein) as fin :
+             for line in fin :
+                 if istext(line) :
+                     varmod = testvar(line, self.var)
+                     if varmod :
+                         keepline = True
+                         if varmod not in filedict :
+                             filename = os.path.join(self.basepath, varmod + '.txt')
+                             filedict[varmod] = open(filename, 'w')
+                         fileout = filedict[varmod]
+                     else : 
+                         keepline = False
+                 if keepline :
+                     fileout.write(line.encode(self.encodeout))
+        for f in filedict :
+            filedict[f].close()
+
+class ExtractMods :
+    def __init__(self, parametres) :
+        self.onefile = parametres.get('onefile', False)
+        self.filein = parametres['filein']
+        self.mods = parametres['mods']
+        self.encodein = parametres['encodein']
+        self.encodeout = parametres['encodeout']
+        self.basepath = os.path.dirname(self.filein)
+        if self.onefile :
+            filename = os.path.join(self.basepath, '_'.join([mod.replace(u'*','') for mod in self.mods])+'.txt')
+            self.fileout = open(filename, 'w')
+        self.doparse()
+
+    def doparse(self) :
+        keepline = False
+        filedict = {}
+        with codecs.open(self.filein, 'r', self.encodein) as fin :
+             for line in fin :
+                 if istext(line) :
+                     modinline = testmod(line, self.mods)
+                     if modinline :
+                         keepline = True
+                         if not self.onefile :
+                            if modinline not in filedict :
+                                filename = os.path.join(self.basepath, modinline + '.txt')
+                                filedict[modinline] = open(filename, 'w')
+                            fileout = filedict[modinline]
+                         else :
+                             fileout = self.fileout
+                     else : 
+                         keepline = False
+                 if keepline :
+                     fileout.write(line.encode(self.encodeout))
+        if not self.onefile :
+            for f in filedict :
+                filedict[f].close()
+        else :
+            self.fileout.close()
+
+
+class SubCorpus(Corpus) :
+    def __init__(self, parent, corpus, sgts) :
+        Corpus.__init__(self, parent, corpus.parametres)
+        self.sgts = sgts
+        self.corpus = copycorpus(corpus)
+        self.corpus.make_lems(self.parametres['lem'])
+        textes = list(set([corpus.getucefromid(sgt).uci for sgt in sgts]))
+        self.ucis = [corpus.ucis[i] for i in textes]
+        for texte in self.ucis :
+            texte.uces = [uce for uce in texte.uces if uce.ident in self.sgts] 
+        self.make_formes(corpus)
+        self.pathout = corpus.pathout 
+        self.parametres['sub'] = self.sgts
+
+    def make_formes(self, corpus) :
+        self.formes = {}
+        for forme in self.corpus.formes :
+            sgtseff = self.corpus.getformeuceseff(forme)
+            sgts = set(self.sgts).intersection(sgtseff.keys())
+            if len(sgts) :
+                self.formes[forme] = self.corpus.formes[forme]
+                self.formes[forme].freq = sum([sgtseff[sgt] for sgt in sgts])
+
+    def getlemuces(self, lem) :
+        return list(set(self.sgts).intersection(self.corpus.getlemuces(lem)))
+
+
+
+
+
+
+if __name__ == '__main__' :
+    #SplitFromVar(parametres)
+    ExtractMods(parametres, True)
diff --git a/tree.py b/tree.py
index ea3d153..e9ab091 100644 (file)
--- a/tree.py
+++ b/tree.py
@@ -114,7 +114,7 @@ class LeftTree(CT.CustomTreeCtrl):
         self.history = parent.history
         self.h = self.history.history
         self.root = self.AddRoot("Iramuteq")
-
+        
         if not(self.GetAGWWindowStyleFlag() & CT.TR_HIDE_ROOT):
             self.SetPyData(self.root, None)
             self.SetItemImage(self.root, 24, CT.TreeItemIcon_Normal)
@@ -129,11 +129,17 @@ class LeftTree(CT.CustomTreeCtrl):
             if 'analyses' in corpus :
                 for y in corpus['analyses'] :
                     last = self.AppendItem(child, y['name'], ct_type=0)
-                        
                     self.SetPyData(last, y)
                     self.SetItemImage(last, 24, CT.TreeItemIcon_Normal)
                     self.SetItemImage(last, 13, CT.TreeItemIcon_Expanded)
-    
+
+        for matrix in self.history.matrix :
+            last = self.AppendItem(self.root, matrix['name'])
+            self.SetPyData(last, matrix)
+            self.SetItemImage(last, 24, CT.TreeItemIcon_Normal)
+            self.SetItemImage(last, 13, CT.TreeItemIcon_Expanded)
+
+
         self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
         #self.Bind(wx.EVT_IDLE, self.OnIdle)
 
@@ -258,6 +264,19 @@ class LeftTree(CT.CustomTreeCtrl):
             self.GiveFocus(child, uuid, bold)
             child, cookie = self.GetNextChild(itemParent, cookie)
 
+    def IsInTree(self, itemParent = None, uuid = None) :
+        if itemParent is None :
+            itemParent = self.root
+        child, cookie = self.GetFirstChild(itemParent)
+        while child :
+            pydata = self.GetPyData(child)
+            if pydata['uuid'] == uuid :
+                return True
+            self.GiveFocus(child, uuid)
+            child, cookie = self.GetNextChild(itemParent, cookie)
+        return False
+
+
     def OnRightDown(self, event):
         
         pt = event.GetPosition()
@@ -656,21 +675,24 @@ class LeftTree(CT.CustomTreeCtrl):
         dlg.Destroy()
 
     def AddAnalyse(self, parametres, itemParent = None, bold = True) :
-        uuid = parametres['corpus']
-        if itemParent is None :
-            itemParent = self.root
-        child, cookie = self.GetFirstChild(itemParent)
-        corpus = None
-        while child :
-            pydata = self.GetPyData(child)
-            if pydata['uuid'] == uuid :
-                corpus = child
-                break
-            self.GiveFocus(child, uuid)
-            child, cookie = self.GetNextChild(itemParent, cookie)
-        #item = self.AppendItem(child, parametres['name'])
-        if corpus is not None : 
-            item = self.AppendItem(corpus, parametres['name'])
+        uuid = parametres.get('corpus', None)
+        if uuid is not None :
+            if itemParent is None :
+                itemParent = self.root
+            child, cookie = self.GetFirstChild(itemParent)
+            corpus = None
+            while child :
+                pydata = self.GetPyData(child)
+                if pydata['uuid'] == uuid :
+                    corpus = child
+                    break
+                self.GiveFocus(child, uuid)
+                child, cookie = self.GetNextChild(itemParent, cookie)
+            #item = self.AppendItem(child, parametres['name'])
+            if corpus is not None : 
+                item = self.AppendItem(corpus, parametres['name'])
+            else :
+                item = self.AppendItem(self.root, parametres['name'])
         else :
             item = self.AppendItem(self.root, parametres['name'])
         self.SetPyData(item, parametres)
index 33a3766..d300d3a 100644 (file)
@@ -4,7 +4,6 @@
 
 #a simple treetagger parser
 import codecs
-import numpy
 import time
 import re
 from functions import ReadDicoAsDico