]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/flatnotebook.py
Added Changer classes
[wxWidgets.git] / wxPython / wx / lib / flatnotebook.py
index b43def683adcc51548748bfef259173e54083930..a177d5e265aa92dd22aeaabaf2f3f632dca3cb22 100644 (file)
@@ -11,7 +11,7 @@
 # Python Code By:
 #
 # Andrea Gavana, @ 02 Oct 2006
-# Latest Revision: 04 Oct 2006, 20.00 GMT
+# Latest Revision: 12 Oct 2006, 20.00 GMT
 #
 #
 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
@@ -31,160 +31,158 @@ The FlatNotebook is a full implementation of the wx.Notebook, and designed to be
 a drop-in replacement for wx.Notebook. The API functions are similar so one can
 expect the function to behave in the same way. 
 
-Some features: 
-- The buttons are highlighted a la Firefox style  
-- The scrolling is done for bulks of tabs (so, the scrolling is faster and better) 
-- The buttons area is never overdrawn by tabs (unlike many other implementations I saw) 
-- It is a generic control 
-- Currently there are 4 differnt styles - VC8, VC 71, Standard and Fancy. 
-- Mouse middle click can be used to close tabs 
-- A function to add right click menu for tabs (simple as SetRightClickMenu) 
-- All styles has bottom style as well (they can be drawn in the bottom of screen) 
-- An option to hide 'X' button or navigation buttons (separately)
-- Gradient coloring of the selected tabs and border
-- Support for drag 'n' drop of tabs, both in the same notebook or to another notebook
-- Possibility to have closing button on the active tab directly
-- Support for disabled tabs
-- Colours for active/inactive tabs, and captions
-- Background of tab area can be painted in gradient (VC8 style only)
-- Colourful tabs - a random gentle colour is generated for each new tab (very cool,
-  VC8 style only)
+Some features:
+
+  - The buttons are highlighted a la Firefox style
+  - The scrolling is done for bulks of tabs (so, the scrolling is faster and better)
+  - The buttons area is never overdrawn by tabs (unlike many other implementations I saw)
+  - It is a generic control
+  - Currently there are 4 differnt styles - VC8, VC 71, Standard and Fancy
+  - Mouse middle click can be used to close tabs
+  - A function to add right click menu for tabs (simple as SetRightClickMenu)
+  - All styles has bottom style as well (they can be drawn in the bottom of screen)
+  - An option to hide 'X' button or navigation buttons (separately)
+  - Gradient coloring of the selected tabs and border
+  - Support for drag 'n' drop of tabs, both in the same notebook or to another notebook
+  - Possibility to have closing button on the active tab directly
+  - Support for disabled tabs
+  - Colours for active/inactive tabs, and captions
+  - Background of tab area can be painted in gradient (VC8 style only)
+  - Colourful tabs - a random gentle colour is generated for each new tab (very cool, VC8 style only)
+
 
 And much more.
 
 
-Usage:
-
-The following example shows a simple implementation that uses FlatNotebook inside
-a very simple frame::
-
-  import wx
-  import wx.lib.flatnotebook as FNB
-  
-  class MyFrame(wx.Frame):
-  
-      def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, size=(800, 600),
-                   style=wx.DEFAULT_FRAME_STYLE | wx.MAXIMIZE |wx.NO_FULL_REPAINT_ON_RESIZE):
-  
-          wx.Frame.__init__(self, parent, id, title, pos, size, style)
-  
-          mainSizer = wx.BoxSizer(wx.VERTICAL)
-          self.SetSizer(mainSizer)
-  
-          bookStyle = FNB.FNB_TABS_BORDER_SIMPLE
-  
-          self.book = FNB.StyledNotebook(self, wx.ID_ANY, style=bookStyle)
-          mainSizer.Add(self.book, 1, wx.EXPAND)
-  
-          # Add some pages to the notebook
-          self.Freeze()
-  
-          text = wx.TextCtrl(self.book, -1, "Book Page 1", style=wx.TE_MULTILINE)  
-          self.book.AddPage(text, "Book Page 1")
-  
-          text = wx.TextCtrl(self.book, -1, "Book Page 2", style=wx.TE_MULTILINE)
-          self.book.AddPage(text,  "Book Page 2")
-  
-          self.Thaw()  
-  
-          mainSizer.Layout()
-          self.SendSizeEvent()
-  
-  # our normal wxApp-derived class, as usual
-  
-  app = wx.PySimpleApp()
-
-  frame = MyFrame(None)
-  app.SetTopWindow(frame)
-  frame.Show()
-  
-  app.MainLoop()
-  
-  
 License And Version:
 
 FlatNotebook Is Freeware And Distributed Under The wxPython License. 
 
-Latest Revision: Andrea Gavana @ 04 Oct 2006, 20.00 GMT
-Version 0.3.
+Latest Revision: Andrea Gavana @ 12 Oct 2006, 20.00 GMT
+
+Version 2.0.
 
+@undocumented: FNB_HEIGHT_SPACER, VERTICAL_BORDER_PADDING, VC8_SHAPE_LEN,
+    wxEVT*, left_arrow_*, right_arrow*, x_button*, down_arrow*,
+    FNBDragInfo, FNBDropTarget, GetMondrian*
 """
 
+__docformat__ = "epytext"
+
+
+#----------------------------------------------------------------------
+# Beginning Of FLATNOTEBOOK wxPython Code
+#----------------------------------------------------------------------
+
 import wx
 import random
 import math
 import weakref
 import cPickle
-
+    
 # Check for the new method in 2.7 (not present in 2.6.3.3)
 if wx.VERSION_STRING < "2.7":
     wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point)
 
 FNB_HEIGHT_SPACER = 10
 
-# Use Visual Studio 2003 (VC7.1) Style for tabs
+# Use Visual Studio 2003 (VC7.1) style for tabs
 FNB_VC71 = 1
+"""Use Visual Studio 2003 (VC7.1) style for tabs"""
 
 # Use fancy style - square tabs filled with gradient coloring
 FNB_FANCY_TABS = 2
+"""Use fancy style - square tabs filled with gradient coloring"""
 
 # Draw thin border around the page
 FNB_TABS_BORDER_SIMPLE = 4
+"""Draw thin border around the page"""
 
 # Do not display the 'X' button
 FNB_NO_X_BUTTON = 8
+"""Do not display the 'X' button"""
 
 # Do not display the Right / Left arrows
 FNB_NO_NAV_BUTTONS = 16
+"""Do not display the right/left arrows"""
 
 # Use the mouse middle button for cloing tabs
 FNB_MOUSE_MIDDLE_CLOSES_TABS = 32
+"""Use the mouse middle button for cloing tabs"""
 
 # Place tabs at bottom - the default is to place them
 # at top
 FNB_BOTTOM = 64
+"""Place tabs at bottom - the default is to place them at top"""
 
 # Disable dragging of tabs
 FNB_NODRAG = 128
+"""Disable dragging of tabs"""
 
-# Use Visual Studio 2005 (VC8) Style for tabs
+# Use Visual Studio 2005 (VC8) style for tabs
 FNB_VC8 = 256
+"""Use Visual Studio 2005 (VC8) style for tabs"""
 
 # Place 'X' on a tab
-# Note: This style is not supported on VC8 style
 FNB_X_ON_TAB = 512
+"""Place 'X' close button on the active tab"""
 
 FNB_BACKGROUND_GRADIENT = 1024
+"""Use gradients to paint the tabs background"""
 
 FNB_COLORFUL_TABS = 2048
+"""Use colourful tabs (VC8 style only)"""
 
 # Style to close tab using double click - styles 1024, 2048 are reserved
 FNB_DCLICK_CLOSES_TABS = 4096
+"""Style to close tab using double click"""
+
+FNB_SMART_TABS = 8192
+"""Use Smart Tabbing, like Alt+Tab on Windows"""
+
+FNB_DROPDOWN_TABS_LIST = 16384
+"""Use a dropdown menu on the left in place of the arrows"""
+
+FNB_ALLOW_FOREIGN_DND = 32768
+"""Allows drag 'n' drop operations between different L{FlatNotebook}s"""
 
 VERTICAL_BORDER_PADDING = 4
 
 # Button size is a 16x16 xpm bitmap
 BUTTON_SPACE = 16
+"""Button size is a 16x16 xpm bitmap"""
 
 VC8_SHAPE_LEN = 16
 
-MASK_COLOR  = wx.Color(0, 128, 128)
+MASK_COLOR  = wx.Colour(0, 128, 128)
+"""Mask colour for the arrow bitmaps"""
 
 # Button status
 FNB_BTN_PRESSED = 2
+"""Navigation button is pressed"""
 FNB_BTN_HOVER = 1
+"""Navigation button is hovered"""
 FNB_BTN_NONE = 0
-
+"""No navigation"""
 
 # Hit Test results
 FNB_TAB = 1             # On a tab
+"""Indicates mouse coordinates inside a tab"""
 FNB_X = 2               # On the X button
+"""Indicates mouse coordinates inside the I{X} region"""
 FNB_TAB_X = 3           # On the 'X' button (tab's X button)
+"""Indicates mouse coordinates inside the I{X} region in a tab"""
 FNB_LEFT_ARROW = 4      # On the rotate left arrow button
+"""Indicates mouse coordinates inside the left arrow region"""
 FNB_RIGHT_ARROW = 5     # On the rotate right arrow button
+"""Indicates mouse coordinates inside the right arrow region"""
+FNB_DROP_DOWN_ARROW = 6 # On the drop down arrow button
+"""Indicates mouse coordinates inside the drop down arrow region"""
 FNB_NOWHERE = 0         # Anywhere else
+"""Indicates mouse coordinates not on any tab of the notebook"""
 
 FNB_DEFAULT_STYLE = FNB_MOUSE_MIDDLE_CLOSES_TABS
+"""L{FlatNotebook} default style"""
 
 # FlatNotebook Events:
 # wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page;
@@ -208,10 +206,18 @@ wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.NewEventType()
 #-----------------------------------#
 
 EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGED, 1)
+"""Notify client objects when the active page in L{FlatNotebook} 
+has changed."""
 EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, 1)
+"""Notify client objects when the active page in L{FlatNotebook} 
+is about to change."""
 EVT_FLATNOTEBOOK_PAGE_CLOSING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, 1)
+"""Notify client objects when a page in L{FlatNotebook} is closing."""
 EVT_FLATNOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, 1)
+"""Notify client objects when a page in L{FlatNotebook} has been closed."""
 EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, 1)
+"""Notify client objects when a pop-up menu should appear next to a tab."""
+
 
 # Some icons in XPM format
 
@@ -525,6 +531,119 @@ right_arrow_xpm = [
     "````````````````"
     ]
 
+down_arrow_hilite_xpm = [
+    "    16    16        8            1",
+    "` c #008080",
+    ". c #4766e0",
+    "# c #c9dafb",
+    "a c #000000",
+    "b c #000000",
+    "c c #000000",
+    "d c #000000",
+    "e c #000000",
+    "````````````````",
+    "``.............`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.#aaaaaaaaa#.`",
+    "``.##aaaaaaa##.`",
+    "``.###aaaaa###.`",
+    "``.####aaa####.`",
+    "``.#####a#####.`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.............`",
+    "````````````````",
+    "````````````````"
+    ]
+
+down_arrow_pressed_xpm = [
+    "    16    16        8            1",
+    "` c #008080",
+    ". c #4766e0",
+    "# c #9e9ede",
+    "a c #000000",
+    "b c #000000",
+    "c c #000000",
+    "d c #000000",
+    "e c #000000",
+    "````````````````",
+    "``.............`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.###########.`",
+    "``.#aaaaaaaaa#.`",
+    "``.##aaaaaaa##.`",
+    "``.###aaaaa###.`",
+    "``.####aaa####.`",
+    "``.#####a#####.`",
+    "``.###########.`",
+    "``.............`",
+    "````````````````",
+    "````````````````"
+    ]
+
+
+down_arrow_xpm = [
+    "    16    16        8            1",
+    "` c #008080",
+    ". c #000000",
+    "# c #000000",
+    "a c #000000",
+    "b c #000000",
+    "c c #000000",
+    "d c #000000",
+    "e c #000000",
+    "````````````````",
+    "````````````````",
+    "````````````````",
+    "````````````````",
+    "````````````````",
+    "````````````````",
+    "````.........```",
+    "`````.......````",
+    "``````.....`````",
+    "```````...``````",
+    "````````.```````",
+    "````````````````",
+    "````````````````",
+    "````````````````",
+    "````````````````",
+    "````````````````"
+    ]
+
+
+#----------------------------------------------------------------------
+def GetMondrianData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
+\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\
+ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\
+o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\
+\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\
+\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\
+\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82' 
+
+
+def GetMondrianBitmap():
+    return wx.BitmapFromImage(GetMondrianImage().Scale(16, 16))
+
+
+def GetMondrianImage():
+    import cStringIO
+    stream = cStringIO.StringIO(GetMondrianData())
+    return wx.ImageFromStream(stream)
+
+
+def GetMondrianIcon():
+    icon = wx.EmptyIcon()
+    icon.CopyFromBitmap(GetMondrianBitmap())
+    return icon
+#----------------------------------------------------------------------
 
 
 def LightColour(color, percent):
@@ -543,7 +662,17 @@ def LightColour(color, percent):
     r = color.Red() + ((i*rd*100)/high)/100
     g = color.Green() + ((i*gd*100)/high)/100
     b = color.Blue() + ((i*bd*100)/high)/100
-    return wx.Color(r, g, b)
+    return wx.Colour(r, g, b)
+
+
+def RandomColour(): 
+    """ Creates a random colour. """
+    
+    r = random.randint(0, 255) # Random value betweem 0-255
+    g = random.randint(0, 255) # Random value betweem 0-255
+    b = random.randint(0, 255) # Random value betweem 0-255
+
+    return wx.Colour(r, g, b)
 
 
 def PaintStraightGradientBox(dc, rect, startColor, endColor, vertical=True):
@@ -571,7 +700,7 @@ def PaintStraightGradientBox(dc, rect, startColor, endColor, vertical=True):
         g = startColor.Green() + ((i*gd*100)/high)/100
         b = startColor.Blue() + ((i*bd*100)/high)/100
 
-        p = wx.Pen(wx.Color(r, g, b))
+        p = wx.Pen(wx.Colour(r, g, b))
         dc.SetPen(p)
 
         if vertical:
@@ -584,14 +713,30 @@ def PaintStraightGradientBox(dc, rect, startColor, endColor, vertical=True):
     dc.SetBrush(savedBrush)
 
 
-def RandomColor(): 
-    """ Creates a random colour. """
+# ---------------------------------------------------------------------------- #
+# Class FNBDropSource
+# Gives Some Custom UI Feedback during the DnD Operations
+# ---------------------------------------------------------------------------- #
+
+class FNBDropSource(wx.DropSource):
+    """
+    Give some custom UI feedback during the drag and drop operation in this
+    function. It is called on each mouse move, so your implementation must
+    not be too slow.
+    """
     
-    r = random.randint(0, 255) # Random value betweem 0-255
-    g = random.randint(0, 255) # Random value betweem 0-255
-    b = random.randint(0, 255) # Random value betweem 0-255
+    def __init__(self, win):
+        """ Default class constructor. Used internally. """
+        
+        wx.DropSource.__init__(self, win)
+        self._win = win
+
 
-    return wx.Color(r, g, b)
+    def GiveFeedback(self, effect):
+        """ Provides user with a nice feedback when tab is being dragged. """
+
+        self._win.DrawDragHint()
+        return False
 
 
 # ---------------------------------------------------------------------------- #
@@ -613,7 +758,7 @@ class FNBDragInfo:
 
 
     def GetContainer(self):
-        """ Returns the FlatNotebook page (usually a panel). """
+        """ Returns the L{FlatNotebook} page (usually a panel). """
         
         return FNBDragInfo._map.get(self._id, None)
 
@@ -660,16 +805,20 @@ class FNBDropTarget(wx.DropTarget):
 # ---------------------------------------------------------------------------- #
 
 class PageInfo:
-
+    """
+    This class holds all the information (caption, image, etc...) belonging to a
+    single tab in L{FlatNotebook}.
+    """
+    
     def __init__(self, caption="", imageindex=-1, tabangle=0, enabled=True):
         """
         Default Class Constructor.
 
         Parameters:
-        - caption: the tab caption;
-        - imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
-        - tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
-        - enabled: sets enabled or disabled the tab.
+        @param caption: the tab caption;
+        @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
+        @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
+        @param enabled: sets enabled or disabled the tab.
         """
 
         self._strCaption = caption
@@ -779,13 +928,13 @@ class PageInfo:
         return self._xRect 
 
 
-    def GetColor(self):
+    def GetColour(self):
         """ Returns the tab colour. """
 
         return self._color 
 
 
-    def SetColor(self, color):
+    def SetColour(self, color):
         """ Sets the tab colour. """
 
         self._color = color 
@@ -798,8 +947,9 @@ class PageInfo:
 class FlatNotebookEvent(wx.PyCommandEvent):
     """
     This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
-    EVT_FLATNOTEBOOK_PAGE_CHANGING And EVT_FLATNOTEBOOK_PAGE_CLOSING is mapped in
-    the parent.
+    EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING,
+    EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is
+    mapped in the parent.
     """
         
     def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1):
@@ -860,2483 +1010,3155 @@ class FlatNotebookEvent(wx.PyCommandEvent):
 
 
 # ---------------------------------------------------------------------------- #
-# Class FlatNotebookBase
+# Class TabNavigatorWindow
 # ---------------------------------------------------------------------------- #
 
-class FlatNotebookBase(wx.Panel):
-
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=0, name="FlatNotebook"):
-        """
-        Default class constructor.
+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.
+    """
 
-        All the parameters are as in wxPython class construction, except the
-        'style': this can be assigned to whatever combination of FNB_* styles.
-        """
+    def __init__(self, parent=None):
+        """ Default class constructor. Used internally."""
 
-        self._bForceSelection = False
-        self._nPadding = 6
-        self._nFrom = 0
-        style |= wx.TAB_TRAVERSAL
-        self._pages = None
-        self._windows = []
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, "", style=0)
 
-        wx.Panel.__init__(self, parent, id, pos, size, style)
+        self._selectedItem = -1
+        self._indexMap = []
         
-        self._pages = StyledTabsContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style)
+        self._bmp = GetMondrianBitmap()
 
-        self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
+        sz = wx.BoxSizer(wx.VERTICAL)
         
-        self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
+        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)
 
-        self._mainSizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self._mainSizer)
+        panelHeight = mem_dc.GetCharHeight()
+        panelHeight += 4 # Place a spacer of 2 pixels
 
-        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
+        # 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))
 
-        # Add the tab container to the sizer
-        self._mainSizer.Insert(0, self._pages, 0, wx.EXPAND)
+        sz.Add(self._panel)
+        sz.Add(self._listBox, 1, wx.EXPAND)
+        
+        self.SetSizer(sz)
 
-        # Set default page height
-        dc = wx.ClientDC(self)
+        # 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)
 
-        if "__WXGTK__" in wx.PlatformInfo:
-            # For GTK it seems that we must do this steps in order
-            # for the tabs will get the proper height on initialization
-            # on MSW, preforming these steps yields wierd results
-            normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-            dc.SetFont(boldFont)
+        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()
 
-        width, height = dc.GetTextExtent("Tp")
 
-        tabHeight = height + FNB_HEIGHT_SPACER         # We use 8 pixels as padding
-        self._pages.SetSizeHints(-1, tabHeight)
+    def OnKeyUp(self, event):
+        """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}."""
+        
+        if event.GetKeyCode() == wx.WXK_CONTROL:
+            self.CloseDialog()
 
-        self._mainSizer.Layout()
 
-        self._pages._nFrom = self._nFrom
-        self._pDropTarget = FNBDropTarget(self)
-        self.SetDropTarget(self._pDropTarget)
+    def OnNavigationKey(self, event):
+        """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """
 
+        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 CreatePageContainer(self):
-        """ Creates the page container for the tabs. """
 
-        return PageContainerBase(self, wx.ID_ANY)
+    def PopulateListControl(self, book):
+        """Populates the L{TabNavigatorWindow} listbox with a list of tabs."""
 
+        selection = book.GetSelection()
+        count = book.GetPageCount()
+        
+        self._listBox.Append(book.GetPageText(selection))
+        self._indexMap.append(selection)
+        
+        prevSel = book.GetPreviousSelection()
+        
+        if prevSel != wx.NOT_FOUND:
+        
+            # Insert the previous selection as second entry 
+            self._listBox.Append(book.GetPageText(prevSel))
+            self._indexMap.append(prevSel)
+        
+        for c in xrange(count):
+        
+            # Skip selected page
+            if c == selection:
+                continue
 
-    def SetActiveTabTextColour(self, textColour):
-        """ Sets the text colour for the active tab. """
+            # Skip previous selected page as well
+            if c == prevSel:
+                continue
 
-        self._pages._activeTextColor = textColour
+            self._listBox.Append(book.GetPageText(c))
+            self._indexMap.append(c)
 
+        # Select the next entry after the current selection
+        self._listBox.SetSelection(0)
+        dummy = wx.NavigationKeyEvent()
+        dummy.SetDirection(True)
+        self.OnNavigationKey(dummy)
 
-    def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
-        """ Handles the drop action from a DND operation. """
 
-        return self._pages.OnDropTarget(x, y, nTabPage, wnd_oldContainer)
+    def OnItemSelected(self, event):
+        """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """
 
+       self.CloseDialog()
 
-    def AddPage(self, window, caption, selected=True, imgindex=-1):
-        """
-        Add a page to the FlatNotebook.
 
-        Parameters:
-        - window: Specifies the new page.
-        - caption: Specifies the text for the new page.
-        - selected: Specifies whether the page should be selected.
-        - imgindex: Specifies the optional image index for the new page.
+    def CloseDialog(self):
+        """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}."""
+
+        bk = self.GetParent()
+        self._selectedItem = self._listBox.GetSelection()
+        iter = self._indexMap[self._selectedItem]
+        bk._pages.FireEvent(iter)
+        self.EndModal(wx.ID_OK)
         
-        Return value:
-        True if successful, False otherwise.
-        """
 
-        # sanity check
-        if not window:
-            return False
+    def OnPanelPaint(self, event):
+        """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """
 
-        # reparent the window to us
-        window.Reparent(self)
+        dc = wx.PaintDC(self._panel)
+        rect = self._panel.GetClientRect()
 
-        # Add tab
-        bSelected = selected or not self._windows
-        curSel = self._pages.GetSelection()
+        bmp = wx.EmptyBitmap(rect.width, rect.height)
 
-        if not self._pages.IsShown():
-            self._pages.Show()
+        mem_dc = wx.MemoryDC()
+        mem_dc.SelectObject(bmp)
 
-        self._pages.AddPage(caption, bSelected, imgindex)
-        self._windows.append(window)
+        endColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
+        startColour = LightColour(endColour, 50)
+        PaintStraightGradientBox(mem_dc, rect, startColour, endColour)
 
-        self.Freeze()
+        # 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)
 
-        # Check if a new selection was made
-        if bSelected:
-        
-            if curSel >= 0:
-            
-                # Remove the window from the main sizer
-                self._mainSizer.Detach(self._windows[curSel])
-                self._windows[curSel].Hide()
-            
-            if self.GetWindowStyleFlag() & FNB_BOTTOM:
-            
-                self._mainSizer.Insert(0, window, 1, wx.EXPAND)
-            
-            else:
-            
-                # We leave a space of 1 pixel around the window
-                self._mainSizer.Add(window, 1, wx.EXPAND)
-            
-        else:
-        
-            # Hide the page
-            window.Hide()
+        # 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)
         
-        self._mainSizer.Layout()
-        self.Thaw()
-        self.Refresh()
+        dc.DrawBitmap(bmp, 0, 0)
 
-        return True        
 
+    def OnPanelEraseBg(self, event):
+        """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """
 
-    def SetImageList(self, imglist):
-        """
-        Sets the image list for the page control. It does not take ownership
-        of the image list, you must delete it yourself.
-        """
+        pass
 
-        self._pages.SetImageList(imglist)
 
+# ---------------------------------------------------------------------------- #
+# Class FNBRenderer
+# ---------------------------------------------------------------------------- #
 
-    def GetImageList(self):
-        """ Returns the associated image list. """
+class FNBRenderer:
+    """
+    Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy}
+    and I{VC8}. This class implements the common methods of all 4 renderers.
+    @undocumented: _GetBitmap*
+    """
+
+    def __init__(self):
+        """Default class constructor. """
         
-        return self._pages.GetImageList()
+        self._tabXBgBmp = wx.EmptyBitmap(16, 16)
+        self._xBgBmp = wx.EmptyBitmap(16, 14)
+        self._leftBgBmp = wx.EmptyBitmap(16, 14)
+        self._rightBgBmp = wx.EmptyBitmap(16, 14)
+        self._tabHeight = None
 
 
-    def InsertPage(self, indx, page, text, select=True, imgindex=-1):
-        """
-        Inserts a new page at the specified position.
+    def GetLeftButtonPos(self, pageContainer):
+        """ Returns the left button position in the navigation area. """
 
-        Parameters:
-        - indx: Specifies the position of the new page.
-        - page: Specifies the new page.
-        - text: Specifies the text for the new page.
-        - select: Specifies whether the page should be selected.
-        - imgindex: Specifies the optional image index for the new page.
+        pc = pageContainer
+        style = pc.GetParent().GetWindowStyleFlag()
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
         
-        Return value:
-        True if successful, False otherwise.
-        """     
-
-        # sanity check
-        if not page:
-            return False
+        if style & FNB_NO_X_BUTTON:
+            return clientWidth - 38
+        else:
+            return clientWidth - 54
 
-        # reparent the window to us
-        page.Reparent(self)
 
-        if not self._windows:
-        
-            self.AddPage(page, text, select, imgindex)
-            return True
 
-        # Insert tab
-        bSelected = select or not self._windows
-        curSel = self._pages.GetSelection()
-        
-        indx = max(0, min(indx, len(self._windows)))
+    def GetRightButtonPos(self, pageContainer):
+        """ Returns the right button position in the navigation area. """
 
-        if indx <= len(self._windows):
-        
-            self._windows.insert(indx, page)
+        pc = pageContainer
+        style = pc.GetParent().GetWindowStyleFlag()
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
         
+        if style & FNB_NO_X_BUTTON:
+            return clientWidth - 22
         else:
-        
-            self._windows.append(page)
-        
-        self._pages.InsertPage(indx, text, bSelected, imgindex)
-        
-        if indx <= curSel:
-            curSel = curSel + 1
+            return clientWidth - 38
 
-        self.Freeze()
 
-        # Check if a new selection was made
-        if bSelected:
-        
-            if curSel >= 0:
-            
-                # Remove the window from the main sizer
-                self._mainSizer.Detach(self._windows[curSel])
-                self._windows[curSel].Hide()
-            
-            self._pages.SetSelection(indx)
-        
-        else:
-        
-            # Hide the page
-            page.Hide()
-        
-        self.Thaw()
-        self._mainSizer.Layout()
-        self.Refresh()
+    def GetDropArrowButtonPos(self, pageContainer):
+        """ Returns the drop down button position in the navigation area. """
 
-        return True
+        return self.GetRightButtonPos(pageContainer)
 
 
-    def SetSelection(self, page):
-        """
-        Sets the selection for the given page.
-        The call to this function generates the page changing events
-        """
+    def GetXPos(self, pageContainer):
+        """ Returns the 'X' button position in the navigation area. """
 
-        if page >= len(self._windows) or not self._windows:
-            return
+        pc = pageContainer
+        style = pc.GetParent().GetWindowStyleFlag()
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
+        
+        if style & FNB_NO_X_BUTTON:
+            return clientWidth
+        else:
+            return clientWidth - 22
 
-        # Support for disabed tabs
-        if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection:
-            return
 
-        curSel = self._pages.GetSelection()
+    def GetButtonsAreaLength(self, pageContainer):
+        """ Returns the navigation area width. """
 
-        # program allows the page change
-        self.Freeze()
-        if curSel >= 0:
-        
-            # Remove the window from the main sizer
-            self._mainSizer.Detach(self._windows[curSel])
-            self._windows[curSel].Hide()
-        
-        if self.GetWindowStyleFlag() & FNB_BOTTOM:
-        
-            self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND)
-        
-        else:
-        
-            # We leave a space of 1 pixel around the window
-            self._mainSizer.Add(self._windows[page], 1, wx.EXPAND)
-        
-        self._windows[page].Show()
-        
-        self._mainSizer.Layout()
-        self._pages._iActivePage = page
+        pc = pageContainer
+        style = pc.GetParent().GetWindowStyleFlag()
 
-        self.Thaw()
+        # ''
+        if style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
+            return 0
+
+        # 'x'        
+        elif style & FNB_NO_NAV_BUTTONS and not style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
+            return 22
         
-        self._pages.DoSetSelection(page)
+        # '<>'
+        if not style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
+            return 53 - 16
+        
+        # 'vx'
+        if style & FNB_DROPDOWN_TABS_LIST and not style & FNB_NO_X_BUTTON:
+            return 22 + 16
 
+        # 'v'
+        if style & FNB_DROPDOWN_TABS_LIST and style & FNB_NO_X_BUTTON:
+            return 22
 
-    def DeletePage(self, page):
-        """
-        Deletes the specified page, and the associated window.
-        The call to this function generates the page changing events.
-        """
+        # '<>x'
+        return 53
 
-        if page >= len(self._windows):
-            return
 
-        # Fire a closing event
-        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
-        event.SetSelection(page)
-        event.SetEventObject(self)
-        self.GetEventHandler().ProcessEvent(event)
+    def DrawLeftArrow(self, pageContainer, dc):
+        """ Draw the left navigation arrow. """
 
-        # The event handler allows it?
-        if not event.IsAllowed():
+        pc = pageContainer
+        
+        style = pc.GetParent().GetWindowStyleFlag()
+        if style & FNB_NO_NAV_BUTTONS:
             return
 
-        self.Freeze()
+        # Make sure that there are pages in the container
+        if not pc._pagesInfoVec:
+            return
 
-        # Delete the requested page
-        pageRemoved = self._windows[page]
+        # Set the bitmap according to the button status
+        if pc._nLeftButtonStatus == FNB_BTN_HOVER:
+            arrowBmp = wx.BitmapFromXPMData(left_arrow_hilite_xpm)
+        elif pc._nLeftButtonStatus == FNB_BTN_PRESSED:
+            arrowBmp = wx.BitmapFromXPMData(left_arrow_pressed_xpm)
+        else:
+            arrowBmp = wx.BitmapFromXPMData(left_arrow_xpm)
 
-        # If the page is the current window, remove it from the sizer
-        # as well
-        if page == self._pages.GetSelection():
-            self._mainSizer.Detach(pageRemoved)
+        if pc._nFrom == 0:
+            # Handle disabled arrow
+            arrowBmp = wx.BitmapFromXPMData(left_arrow_disabled_xpm)
         
-        # Remove it from the array as well
-        self._windows.pop(page)
+        arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
 
-        # Now we can destroy it in wxWidgets use Destroy instead of delete
-        pageRemoved.Destroy()
+        # Erase old bitmap
+        posx = self.GetLeftButtonPos(pc)
+        dc.DrawBitmap(self._leftBgBmp, posx, 6)
 
-        self.Thaw()
+        # Draw the new bitmap
+        dc.DrawBitmap(arrowBmp, posx, 6, True)
 
-        self._pages.DoDeletePage(page)
-        self.Refresh()
 
-        # Fire a closed event
-        closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
-        closedEvent.SetSelection(page)
-        closedEvent.SetEventObject(self)
-        self.GetEventHandler().ProcessEvent(closedEvent)
+    def DrawRightArrow(self, pageContainer, dc):
+        """ Draw the right navigation arrow. """
 
+        pc = pageContainer
+        
+        style = pc.GetParent().GetWindowStyleFlag()
+        if style & FNB_NO_NAV_BUTTONS:
+            return
 
-    def DeleteAllPages(self):
-        """ Deletes all the pages. """
+        # Make sure that there are pages in the container
+        if not pc._pagesInfoVec:
+            return
 
-        if not self._windows:
-            return False
+        # Set the bitmap according to the button status
+        if pc._nRightButtonStatus == FNB_BTN_HOVER:        
+            arrowBmp = wx.BitmapFromXPMData(right_arrow_hilite_xpm)
+        elif pc._nRightButtonStatus == FNB_BTN_PRESSED:
+            arrowBmp = wx.BitmapFromXPMData(right_arrow_pressed_xpm)
+        else:
+            arrowBmp = wx.BitmapFromXPMData(right_arrow_xpm)
 
-        self.Freeze()
-        
-        for page in self._windows:
-            page.Destroy()
+        # Check if the right most tab is visible, if it is
+        # don't rotate right anymore
+        if pc._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
+            arrowBmp = wx.BitmapFromXPMData(right_arrow_disabled_xpm)
         
-        self._windows = []
-        self.Thaw()
+        arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
 
-        # Clear the container of the tabs as well
-        self._pages.DeleteAllPages()
-        return True
+        # erase old bitmap
+        posx = self.GetRightButtonPos(pc)
+        dc.DrawBitmap(self._rightBgBmp, posx, 6)
 
+        # Draw the new bitmap
+        dc.DrawBitmap(arrowBmp, posx, 6, True)
 
-    def GetCurrentPage(self):
-        """ Returns the currently selected notebook page or None. """
-        
-        sel = self._pages.GetSelection()
-        if sel < 0:
-            return None
 
-        return self._windows[sel]
+    def DrawDropDownArrow(self, pageContainer, dc):
+        """ Draws the drop-down arrow in the navigation area. """
 
+        pc = pageContainer
+        
+        # Check if this style is enabled
+        style = pc.GetParent().GetWindowStyleFlag()
+        if not style & FNB_DROPDOWN_TABS_LIST:
+            return
 
-    def GetPage(self, page):
-        """ Returns the window at the given page position, or None. """
+        # Make sure that there are pages in the container
+        if not pc._pagesInfoVec:
+            return
 
-        if page >= len(self._windows):
-            return None
+        if pc._nArrowDownButtonStatus == FNB_BTN_HOVER:
+            downBmp = wx.BitmapFromXPMData(down_arrow_hilite_xpm)
+        elif pc._nArrowDownButtonStatus == FNB_BTN_PRESSED:
+            downBmp = wx.BitmapFromXPMData(down_arrow_pressed_xpm)
+        else:
+            downBmp = wx.BitmapFromXPMData(down_arrow_xpm)
 
-        return self._windows[page]
+        downBmp.SetMask(wx.Mask(downBmp, MASK_COLOR))
 
+        # erase old bitmap
+        posx = self.GetDropArrowButtonPos(pc)
+        dc.DrawBitmap(self._xBgBmp, posx, 6)
 
-    def GetPageIndex(self, win):
-        """ Returns the index at which the window is found. """
+        # Draw the new bitmap
+        dc.DrawBitmap(downBmp, posx, 6, True)
 
-        try:
-            return self._windows.index(win)
-        except:
-            return -1
 
+    def DrawX(self, pageContainer, dc):
+        """ Draw the 'X' navigation button in the navigation area. """
 
-    def GetSelection(self):
-        """ Returns the currently selected page, or -1 if none was selected. """
+        pc = pageContainer
         
-        return self._pages.GetSelection()
-
+        # Check if this style is enabled
+        style = pc.GetParent().GetWindowStyleFlag()
+        if style & FNB_NO_X_BUTTON:
+            return
 
-    def AdvanceSelection(self, bForward=True):
-        """
-        Cycles through the tabs.
-        The call to this function generates the page changing events.
-        """
+        # Make sure that there are pages in the container
+        if not pc._pagesInfoVec:
+            return
 
-        self._pages.AdvanceSelection(bForward)
+        # Set the bitmap according to the button status
+        if pc._nXButtonStatus == FNB_BTN_HOVER:
+            xbmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
+        elif pc._nXButtonStatus == FNB_BTN_PRESSED:
+            xbmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
+        else:
+            xbmp = wx.BitmapFromXPMData(x_button_xpm)
 
+        xbmp.SetMask(wx.Mask(xbmp, MASK_COLOR))
+        
+        # erase old bitmap
+        posx = self.GetXPos(pc) 
+        dc.DrawBitmap(self._xBgBmp, posx, 6)
 
-    def GetPageCount(self):
-        """ Returns the number of pages in the FlatNotebook control. """
-        return self._pages.GetPageCount()
+        # Draw the new bitmap
+        dc.DrawBitmap(xbmp, posx, 6, True)
 
 
-    def OnNavigationKey(self, event):
-        """ Handles the wx.EVT_NAVIGATION_KEY event for FlatNotebook. """
+    def DrawTabX(self, pageContainer, dc, rect, tabIdx, btnStatus):
+        """ Draws the 'X' in the selected tab. """
 
-        if event.IsWindowChange():
-            # change pages
-            self.AdvanceSelection(event.GetDirection())
-        else:
-            # pass to the parent
-            if self.GetParent():
-                event.SetCurrentFocus(self)
-                self.GetParent().ProcessEvent(event)
-            
+        pc = pageContainer
+        if not pc.HasFlag(FNB_X_ON_TAB):
+            return
 
-    def GetPageShapeAngle(self, page_index):
-        """ Returns the angle associated to a tab. """
+        # We draw the 'x' on the active tab only
+        if tabIdx != pc.GetSelection() or tabIdx < 0:
+            return
 
-        if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
-            return None, False
+        # Set the bitmap according to the button status
         
-        result = self._pages._pagesInfoVec[page_index].GetTabAngle()
-        return result, True
+        if btnStatus == FNB_BTN_HOVER:
+            xBmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
+        elif btnStatus == FNB_BTN_PRESSED:
+            xBmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
+        else:
+            xBmp = wx.BitmapFromXPMData(x_button_xpm)
 
+        # Set the masking
+        xBmp.SetMask(wx.Mask(xBmp, MASK_COLOR))
 
-    def SetPageShapeAngle(self, page_index, angle):
-        """ Sets the angle associated to a tab. """
+        # erase old button
+        dc.DrawBitmap(self._tabXBgBmp, rect.x, rect.y)
 
-        if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
-            return
+        # Draw the new bitmap
+        dc.DrawBitmap(xBmp, rect.x, rect.y, True)
 
-        if angle > 15:
-            return
+        # Update the vector
+        rr = wx.Rect(rect.x, rect.y, 14, 13)
+        pc._pagesInfoVec[tabIdx].SetXRect(rr)
 
-        self._pages._pagesInfoVec[page_index].SetTabAngle(angle)
 
+    def _GetBitmap(self, dc, rect, bmp):
 
-    def SetAllPagesShapeAngle(self, angle):
-        """ Sets the angle associated to all the tab. """
+        mem_dc = wx.MemoryDC()
+        mem_dc.SelectObject(bmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
+        return bmp
 
-        if angle > 15:
-            return
-
-        for ii in xrange(len(self._pages._pagesInfoVec)):
-            self._pages._pagesInfoVec[ii].SetTabAngle(angle)
-        
-        self.Refresh()
 
+    def DrawTabsLine(self, pageContainer, dc):
+        """ Draws a line over the tabs. """
 
-    def GetPageBestSize(self):
-        """ Return the page best size. """
+        pc = pageContainer
+        
+        clntRect = pc.GetClientRect()
+        clientRect3 = wx.Rect(0, 0, clntRect.width, clntRect.height)
 
-        return self._pages.GetClientSize()
+        if pc.HasFlag(FNB_BOTTOM):
+        
+            clientRect = wx.Rect(0, 2, clntRect.width, clntRect.height - 2)
+            clientRect2 = wx.Rect(0, 1, clntRect.width, clntRect.height - 1)
+        
+        else:
+        
+            clientRect = wx.Rect(0, 0, clntRect.width, clntRect.height - 2)
+            clientRect2 = wx.Rect(0, 0, clntRect.width, clntRect.height - 1)
+        
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.SetPen(wx.Pen(pc.GetSingleLineBorderColour()))
+        dc.DrawRectangleRect(clientRect2)
+        dc.DrawRectangleRect(clientRect3)
 
+        dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
+        dc.DrawRectangleRect(clientRect)
 
-    def SetPageText(self, page, text):
-        """ Sets the text for the given page. """
+        if not pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
+        
+            dc.SetPen(wx.Pen((pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc._tabAreaColor])[0]))
+            dc.DrawLine(0, 0, 0, clientRect.height+1)
+            
+            if pc.HasFlag(FNB_BOTTOM):
+            
+                dc.DrawLine(0, clientRect.height+1, clientRect.width, clientRect.height+1)
+            
+            else:
+                
+                dc.DrawLine(0, 0, clientRect.width, 0)
+                
+            dc.DrawLine(clientRect.width - 1, 0, clientRect.width - 1, clientRect.height+1)
 
-        bVal = self._pages.SetPageText(page, text)
-        self._pages.Refresh()
 
-        return bVal
+    def CalcTabWidth(self, pageContainer, tabIdx, tabHeight):
+        """ Calculates the width of the input tab. """
 
+        pc = pageContainer
+        dc = wx.MemoryDC()
+        dc.SelectObject(wx.EmptyBitmap(1,1))
 
-    def SetPadding(self, padding):
-        """
-        Sets the amount of space around each page's icon and label, in pixels.
-        NB: only the horizontal padding is considered.
-        """
+        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
 
-        self._nPadding = padding.GetWidth()
+        if pc.IsDefaultTabs():
+            shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
 
+        # Calculate the text length using the bold font, so when selecting a tab
+        # its width will not change
+        dc.SetFont(boldFont)
+        width, pom = dc.GetTextExtent(pc.GetPageText(tabIdx))
 
-    def GetTabArea(self):
-        """ Returns the associated page. """
+        # Set a minimum size to a tab
+        if width < 20:
+            width = 20
 
-        return self._pages
+        tabWidth = 2*pc._pParent.GetPadding() + width
 
+        # Style to add a small 'x' button on the top right
+        # of the tab
+        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
+            # The xpm image that contains the 'x' button is 9 pixels
+            spacer = 9
+            if pc.HasFlag(FNB_VC8):
+                spacer = 4
 
-    def GetPadding(self):
-        """ Returns the amount of space around each page's icon and label, in pixels. """
+            tabWidth += pc._pParent.GetPadding() + spacer
         
-        return self._nPadding 
-
-
-    def SetWindowStyleFlag(self, style):
-        """ Sets the FlatNotebook window style flags. """
+        if pc.IsDefaultTabs():
+            # Default style
+            tabWidth += 2*shapePoints
 
-        wx.Panel.SetWindowStyleFlag(self, style)
+        hasImage = pc._ImageList != None and pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
 
-        if self._pages:
+        # For VC71 style, we only add the icon size (16 pixels)
+        if hasImage:
         
-            # For changing the tab position (i.e. placing them top/bottom)
-            # refreshing the tab container is not enough
-            self.SetSelection(self._pages._iActivePage)
+            if not pc.IsDefaultTabs():
+                tabWidth += 16 + pc._pParent.GetPadding()
+            else:
+                # Default style
+                tabWidth += 16 + pc._pParent.GetPadding() + shapePoints/2
+        
+        return tabWidth
 
 
-    def RemovePage(self, page):
-        """ Deletes the specified page, without deleting the associated window. """
+    def CalcTabHeight(self, pageContainer):
+        """ Calculates the height of the input tab. """
 
-        if page >= len(self._windows):
-            return False
+        if self._tabHeight:
+            return self._tabHeight
 
-        # Fire a closing event
-        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
-        event.SetSelection(page)
-        event.SetEventObject(self)
-        self.GetEventHandler().ProcessEvent(event)
+        pc = pageContainer
+        dc = wx.MemoryDC()
+        dc.SelectObject(wx.EmptyBitmap(1,1))
 
-        # The event handler allows it?
-        if not event.IsAllowed():
-            return False
+        # For GTK it seems that we must do this steps in order
+        # for the tabs will get the proper height on initialization
+        # on MSW, preforming these steps yields wierd results
+        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        boldFont = normalFont
 
-        self.Freeze()
+        if "__WXGTK__" in wx.PlatformInfo:
+            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
+            dc.SetFont(boldFont)
 
-        # Remove the requested page
-        pageRemoved = self._windows[page]
+        height = dc.GetCharHeight()
+        
+        tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding
+        if "__WXGTK__" in wx.PlatformInfo:
+            # On GTK the tabs are should be larger
+            tabHeight += 6
 
-        # If the page is the current window, remove it from the sizer
-        # as well
-        if page == self._pages.GetSelection():
-            self._mainSizer.Detach(pageRemoved)
+        self._tabHeight = tabHeight
         
-        # Remove it from the array as well
-        self._windows.pop(page)
-        self.Thaw()
+        return tabHeight
 
-        self._pages.DoDeletePage(page)
 
-        return True
+    def DrawTabs(self, pageContainer, dc):
+        """ Actually draws the tabs in L{FlatNotebook}."""
 
+        pc = pageContainer
+        if "__WXMAC__" in wx.PlatformInfo:
+            # Works well on MSW & GTK, however this lines should be skipped on MAC
+            if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
+                pc.Hide()
+                return
+            
+        # Get the text hight
+        tabHeight = self.CalcTabHeight(pageContainer)
+        style = pc.GetParent().GetWindowStyleFlag()
 
-    def SetRightClickMenu(self, menu):
-        """ Sets the popup menu associated to a right click on a tab. """
+        # Calculate the number of rows required for drawing the tabs
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
 
-        self._pages._pRightClickMenu = menu
+        # Set the maximum client size
+        pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
+        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
 
+        if style & FNB_VC71:
+            backBrush = wx.Brush(wx.Colour(247, 243, 233))
+        else:
+            backBrush = wx.Brush(pc._tabAreaColor)
 
-    def GetPageText(self, page):
-        """ Returns the tab caption. """
+        noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
+        selBrush = wx.Brush(pc._activeTabColor)
 
-        return self._pages.GetPageText(page)
+        size = pc.GetSize()
 
+        # Background
+        dc.SetTextBackground((style & FNB_VC71 and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0])
+        dc.SetTextForeground(pc._activeTextColor)
+        dc.SetBrush(backBrush)
 
-    def SetGradientColors(self, fr, to, border):
-        """ Sets the gradient colours for the tab. """
+        # If border style is set, set the pen to be border pen
+        if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
+            dc.SetPen(borderPen)
+        else:
+            colr = (pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0]
+            dc.SetPen(wx.Pen(colr))
+        
+        dc.DrawRectangle(0, 0, size.x, size.y)
 
-        self._pages._colorFrom = fr
-        self._pages._colorTo   = to
-        self._pages._colorBorder = border
+        # Take 3 bitmaps for the background for the buttons
+        
+        mem_dc = wx.MemoryDC()
+        #---------------------------------------
+        # X button
+        #---------------------------------------
+        rect = wx.Rect(self.GetXPos(pc), 6, 16, 14)
+        mem_dc.SelectObject(self._xBgBmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
 
+        #---------------------------------------
+        # Right button
+        #---------------------------------------
+        rect = wx.Rect(self.GetRightButtonPos(pc), 6, 16, 14)
+        mem_dc.SelectObject(self._rightBgBmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
 
-    def SetGradientColorFrom(self, fr):
-        """ Sets the starting colour for the gradient. """
+        #---------------------------------------
+        # Left button
+        #---------------------------------------
+        rect = wx.Rect(self.GetLeftButtonPos(pc), 6, 16, 14)
+        mem_dc.SelectObject(self._leftBgBmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
 
-        self._pages._colorFrom = fr
+        # We always draw the bottom/upper line of the tabs
+        # regradless the style
+        dc.SetPen(borderPen)
+        self.DrawTabsLine(pc, dc)
 
+        # Restore the pen
+        dc.SetPen(borderPen)
 
-    def SetGradientColorTo(self, to):
-        """ Sets the ending colour for the gradient. """
+        if pc.HasFlag(FNB_VC71):
+        
+            greyLineYVal  = (pc.HasFlag(FNB_BOTTOM) and [0] or [size.y - 2])[0]
+            whiteLineYVal = (pc.HasFlag(FNB_BOTTOM) and [3] or [size.y - 3])[0]
 
-        self._pages._colorTo = to
+            pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
+            dc.SetPen(pen)
 
+            # Draw thik grey line between the windows area and
+            # the tab area
+            for num in xrange(3):
+                dc.DrawLine(0, greyLineYVal + num, size.x, greyLineYVal + num)
 
-    def SetGradientColorBorder(self, border):
-        """ Sets the tab border colour. """
+            wbPen = (pc.HasFlag(FNB_BOTTOM) and [wx.BLACK_PEN] or [wx.WHITE_PEN])[0]
+            dc.SetPen(wbPen)
+            dc.DrawLine(1, whiteLineYVal, size.x - 1, whiteLineYVal)
 
-        self._pages._colorBorder = border
+            # Restore the pen
+            dc.SetPen(borderPen)
+        
+        # Draw labels
+        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
+        dc.SetFont(boldFont)
 
+        posx = pc._pParent.GetPadding()
 
-    def GetGradientColorFrom(self):
-        """ Gets first gradient colour. """
+        # Update all the tabs from 0 to 'pc._nFrom' to be non visible
+        for i in xrange(pc._nFrom):
+        
+            pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
+            pc._pagesInfoVec[i].GetRegion().Clear()
 
-        return self._pages._colorFrom
+        count = pc._nFrom
+        
+        #----------------------------------------------------------
+        # Go over and draw the visible tabs
+        #----------------------------------------------------------
+        for i in xrange(pc._nFrom, len(pc._pagesInfoVec)):
+        
+            dc.SetPen(borderPen)
+            dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
 
+            # Now set the font to the correct font
+            dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
 
-    def GetGradientColorTo(self):
-        """ Gets second gradient colour. """
+            # Add the padding to the tab width
+            # Tab width:
+            # +-----------------------------------------------------------+
+            # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
+            # +-----------------------------------------------------------+
+            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
 
-        return self._pages._colorTo
+            # Check if we can draw more
+            if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth:
+                break
 
+            count = count + 1
+            
+            # By default we clean the tab region
+            pc._pagesInfoVec[i].GetRegion().Clear()
 
-    def GetGradientColorBorder(self):
-        """ Gets the tab border colour. """
+            # Clean the 'x' buttn on the tab.
+            # A 'Clean' rectangle, is a rectangle with width or height
+            # with values lower than or equal to 0
+            pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
 
-        return self._pages._colorBorder
+            # Draw the tab (border, text, image & 'x' on tab)
+            self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
 
+            # Restore the text forground
+            dc.SetTextForeground(pc._activeTextColor)
 
-    def GetActiveTabTextColour(self):
-        """ Get the active tab text colour. """
+            # Update the tab position & size
+            posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
 
-        return self._pages._activeTextColor
+            pc._pagesInfoVec[i].SetPosition(wx.Point(posx, posy))
+            pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
+            posx += tabWidth
+        
+        # Update all tabs that can not fit into the screen as non-visible
+        for i in xrange(count, len(pc._pagesInfoVec)):
+            pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
+            pc._pagesInfoVec[i].GetRegion().Clear()
+        
+        # Draw the left/right/close buttons
+        # Left arrow
+        self.DrawLeftArrow(pc, dc)
+        self.DrawRightArrow(pc, dc)
+        self.DrawX(pc, dc)
+        self.DrawDropDownArrow(pc, dc)
 
 
-    def SetPageImageIndex(self, page, imgindex):
+    def DrawDragHint(self, pc, tabIdx):
         """
-        Sets the image index for the given page. Image is an index into the
-        image list which was set with SetImageList.
+        Draws tab drag hint, the default implementation is to do nothing.
+        You can override this function to provide a nice feedback to user.
         """
+        
+        pass
 
-        self._pages.SetPageImageIndex(page, imgindex)
 
+    def NumberTabsCanFit(self, pageContainer, fr=-1):
 
-    def GetPageImageIndex(self, page):
-        """
-        Returns the image index for the given page. Image is an index into the
-        image list which was set with SetImageList.
-        """
+        pc = pageContainer
+        
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
 
-        return self._pages.GetPageImageIndex(page)
+        vTabInfo = []
 
+        tabHeight = self.CalcTabHeight(pageContainer)
 
-    def GetEnabled(self, page):
-        """ Returns whether a tab is enabled or not. """
+        # The drawing starts from posx 
+        posx = pc._pParent.GetPadding()
 
-        return self._pages.GetEnabled(page)
+        if fr < 0:
+            fr = pc._nFrom
 
+        for i in xrange(fr, len(pc._pagesInfoVec)):
 
-    def Enable(self, page, enabled=True):
-        """ Enables or disables a tab. """
+            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight) 
+            if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth:
+                break; 
 
-        if page >= len(self._windows):
-            return
+            # Add a result to the returned vector 
+            tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth , tabHeight)
+            vTabInfo.append(tabRect)
 
-        self._windows[page].Enable(enabled)
-        self._pages.Enable(page, enabled)
+            # Advance posx 
+            posx += tabWidth + FNB_HEIGHT_SPACER
 
+        return vTabInfo
 
-    def GetNonActiveTabTextColour(self):
-        """ Returns the non active tabs text colour. """
+    
+# ---------------------------------------------------------------------------- #
+# Class FNBRendererMgr
+# A manager that handles all the renderers defined below and calls the
+# appropriate one when drawing is needed
+# ---------------------------------------------------------------------------- #
 
-        return self._pages._nonActiveTextColor
+class FNBRendererMgr:
+    """
+    This class represents a manager that handles all the 4 renderers defined
+    and calls the appropriate one when drawing is needed.
+    """
 
+    def __init__(self):
+        """ Default class constructor. """
+        
+        # register renderers
 
-    def SetNonActiveTabTextColour(self, color):
-        """ Sets the non active tabs text colour. """
+        self._renderers = {}        
+        self._renderers.update({-1: FNBRendererDefault()})
+        self._renderers.update({FNB_VC71: FNBRendererVC71()})
+        self._renderers.update({FNB_FANCY_TABS: FNBRendererFancy()})
+        self._renderers.update({FNB_VC8: FNBRendererVC8()})
 
-        self._pages._nonActiveTextColor = color
 
+    def GetRenderer(self, style):
+        """ Returns the current renderer based on the style selected. """
 
-    def SetTabAreaColour(self, color):
-        """ Sets the area behind the tabs colour. """
-
-        self._pages._tabAreaColor = color
+        # since we dont have a style for default tabs, we 
+        # test for all others - FIXME: add style for default tabs
+        if not style & FNB_VC71 and not style & FNB_VC8 and not style & FNB_FANCY_TABS:
+            return self._renderers[-1]
 
+        if style & FNB_VC71:
+            return self._renderers[FNB_VC71]
 
-    def GetTabAreaColour(self):
-        """ Returns the area behind the tabs colour. """
+        if style & FNB_FANCY_TABS:
+            return self._renderers[FNB_FANCY_TABS]
 
-        return self._pages._tabAreaColor
+        if style & FNB_VC8:
+            return self._renderers[FNB_VC8]
 
+        # the default is to return the default renderer
+        return self._renderers[-1]
 
-    def SetActiveTabColour(self, color):
-        """ Sets the active tab colour. """
 
-        self._pages._activeTabColor = color
+#------------------------------------------
+# Default renderer 
+#------------------------------------------
 
+class FNBRendererDefault(FNBRenderer):
+    """
+    This class handles the drawing of tabs using the I{Standard} renderer.
+    """
+    
+    def __init__(self):
+        """ Default class constructor. """
 
-    def GetActiveTabColour(self):
-        """ Returns the active tab colour. """
+        FNBRenderer.__init__(self)
+        
 
-        return self._pages._activeTabColor
+    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
+        """ Draws a tab using the I{Standard} style. """
 
+        # Default style
+        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+        pc = pageContainer 
 
-# ---------------------------------------------------------------------------- #
-# Class PageContainerBase
-# Acts as a container for the pages you add to FlatNotebook
-# ---------------------------------------------------------------------------- #
+        tabPoints = [wx.Point() for ii in xrange(7)]
+        tabPoints[0].x = posx
+        tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
 
-class PageContainerBase(wx.Panel):
+        tabPoints[1].x = int(posx+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
+        tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
 
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
-                 size=wx.DefaultSize, style=0):
-        """ Default class constructor. """
-        
-        self._ImageList = None
-        self._iActivePage = -1
-        self._pDropTarget = None
-        self._nLeftClickZone = FNB_NOWHERE
-        self._tabXBgBmp = wx.EmptyBitmap(16, 16)
-        self._xBgBmp = wx.EmptyBitmap(16, 14)
-        self._leftBgBmp = wx.EmptyBitmap(16, 14)
-        self._rightBgBmp = wx.EmptyBitmap(16, 14)
+        tabPoints[2].x = tabPoints[1].x+2
+        tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
 
-        self._pRightClickMenu = None
-        self._nXButtonStatus = FNB_BTN_NONE
-        self._pParent = parent
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nLeftButtonStatus = FNB_BTN_NONE
-        self._nTabXButtonStatus = FNB_BTN_NONE
+        tabPoints[3].x = int(posx+tabWidth-(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))-2
+        tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
 
-        self._pagesInfoVec = []        
+        tabPoints[4].x = tabPoints[3].x+2
+        tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
 
-        self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
-        self._colorFrom = wx.WHITE
-        self._activeTabColor = wx.WHITE
-        self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
-        self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
-        self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
+        tabPoints[5].x = int(tabPoints[4].x+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
+        tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
 
-        self._nFrom = 0
-        self._isdragging = False
+        tabPoints[6].x = tabPoints[0].x
+        tabPoints[6].y = tabPoints[0].y
         
-        wx.Panel.__init__(self, parent, id, pos, size, style)
+        if tabIdx == pc.GetSelection():
+        
+            # Draw the tab as rounded rectangle
+            dc.DrawPolygon(tabPoints)
+        
+        else:
+        
+            if tabIdx != pc.GetSelection() - 1:
+            
+                # Draw a vertical line to the right of the text
+                pt1x = tabPoints[5].x
+                pt1y = (pc.HasFlag(FNB_BOTTOM) and [4] or [tabHeight - 6])[0]
+                pt2x = tabPoints[5].x
+                pt2y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 4] or [4])[0]
+                dc.DrawLine(pt1x, pt1y, pt2x, pt2y)
 
-        self._pDropTarget = FNBDropTarget(self)
-        self.SetDropTarget(self._pDropTarget)
+        if tabIdx == pc.GetSelection():
+        
+            savePen = dc.GetPen()
+            whitePen = wx.Pen(wx.WHITE)
+            whitePen.SetWidth(1)
+            dc.SetPen(whitePen)
 
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
-        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
-        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
-        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
-        self.Bind(wx.EVT_MOTION, self.OnMouseMove)
-        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
-        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
-        self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
-        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
+            secPt = wx.Point(tabPoints[5].x + 1, tabPoints[5].y)
+            dc.DrawLine(tabPoints[0].x, tabPoints[0].y, secPt.x, secPt.y)
 
+            # Restore the pen
+            dc.SetPen(savePen)
+        
+        # -----------------------------------
+        # Text and image drawing
+        # -----------------------------------
 
-    def GetButtonAreaWidth(self):
-        """ Returns the width of the navigation button area. """
+        # Text drawing offset from the left border of the
+        # rectangle
+        
+        # The width of the images are 16 pixels
+        padding = pc.GetParent().GetPadding()
+        shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
+        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
+        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
 
-        style = self.GetParent().GetWindowStyleFlag()
-        btnareawidth = 2*self._pParent._nPadding
+        if hasImage:
+            textOffset = 2*pc._pParent._nPadding + 16 + shapePoints/2 
+        else:
+            textOffset = pc._pParent._nPadding + shapePoints/2 
 
-        if style & FNB_NO_X_BUTTON == 0:
-            btnareawidth += BUTTON_SPACE
+        textOffset += 2
 
-        if style & FNB_NO_NAV_BUTTONS == 0:
-            btnareawidth += 2*BUTTON_SPACE
+        if tabIdx != pc.GetSelection():
+        
+            # Set the text background to be like the vertical lines
+            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
+        
+        if hasImage:
+        
+            imageXOffset = textOffset - 16 - padding
+            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
+                                     posx + imageXOffset, imageYCoord,
+                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
+        
+        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
 
-        return btnareawidth
+        # draw 'x' on tab (if enabled)
+        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
+        
+            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
+            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
 
+            # take a bitmap from the position of the 'x' button (the x on tab button)
+            # this bitmap will be used later to delete old buttons
+            tabCloseButtonYCoord = imageYCoord
+            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
+            self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
 
-    def OnEraseBackground(self, event):
-        """ Handles the wx.EVT_ERASE_BACKGROUND event for PageContainerBase (does nothing)."""
+            # Draw the tab
+            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)            
+        
 
-        pass
+#------------------------------------------------------------------
+# Visual studio 7.1 
+#------------------------------------------------------------------
 
-    
-    def OnPaint(self, event):
-        """ Handles the wx.EVT_PAINT event for PageContainerBase."""
+class FNBRendererVC71(FNBRenderer):
+    """
+    This class handles the drawing of tabs using the I{VC71} renderer.
+    """
 
-        dc = wx.BufferedPaintDC(self)
+    def __init__(self):
+        """ Default class constructor. """
 
-        if "__WXMAC__" in wx.PlatformInfo:
-            # Works well on MSW & GTK, however this lines should be skipped on MAC
-            if len(self._pagesInfoVec) == 0 or self._nFrom >= len(self._pagesInfoVec):
-                self.Hide()
-                event.Skip()
-                return
-        
-        # Get the text hight
-        style = self.GetParent().GetWindowStyleFlag()
+        FNBRenderer.__init__(self)
 
-        # For GTK it seems that we must do this steps in order
-        # for the tabs will get the proper height on initialization
-        # on MSW, preforming these steps yields wierd results
-        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-        if "__WXGTK__" in wx.PlatformInfo:
-            dc.SetFont(boldFont)
 
-        width, height = dc.GetTextExtent("Tp")
+    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
+        """ Draws a tab using the I{VC71} style. """
 
-        tabHeight = height + FNB_HEIGHT_SPACER   # We use 8 pixels as padding
+        # Visual studio 7.1 style
+        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+        pc = pageContainer
 
-        # Calculate the number of rows required for drawing the tabs
-        rect = self.GetClientRect()
-        clientWidth = rect.width
+        dc.SetPen((tabIdx == pc.GetSelection() and [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [borderPen])[0])
+        dc.SetBrush((tabIdx == pc.GetSelection() and [wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [wx.Brush(wx.Colour(247, 243, 233))])[0])
 
-        # Set the maximum client size
-        self.SetSizeHints(self.GetButtonsAreaLength(), tabHeight)
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+        if tabIdx == pc.GetSelection():
+        
+            posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
+            tabH = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 5] or [tabHeight - 3])[0]
+            dc.DrawRectangle(posx, posy, tabWidth, tabH) 
 
-        if style & FNB_VC71:
-            backBrush = wx.Brush(wx.Colour(247, 243, 233))
-        else:
-            backBrush = wx.Brush(self._tabAreaColor)
+            # Draw a black line on the left side of the
+            # rectangle
+            dc.SetPen(wx.BLACK_PEN)
 
-        noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
-        selBrush = wx.Brush(self._activeTabColor)
+            blackLineY1 = VERTICAL_BORDER_PADDING
+            blackLineY2 = tabH
+            dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
 
-        size = self.GetSize()
+            # To give the tab more 3D look we do the following
+            # Incase the tab is on top,
+            # Draw a thik white line on topof the rectangle
+            # Otherwise, draw a thin (1 pixel) black line at the bottom
 
-        # Background
-        dc.SetTextBackground((style & FNB_VC71 and [wx.Colour(247, 243, 233)] or [self.GetBackgroundColour()])[0])
-        dc.SetTextForeground(self._activeTextColor)
-        dc.SetBrush(backBrush)
+            pen = wx.Pen((pc.HasFlag(FNB_BOTTOM) and [wx.BLACK] or [wx.WHITE])[0])
+            dc.SetPen(pen)
+            whiteLinePosY = (pc.HasFlag(FNB_BOTTOM) and [blackLineY2] or [VERTICAL_BORDER_PADDING ])[0]
+            dc.DrawLine(posx , whiteLinePosY, posx + tabWidth + 1, whiteLinePosY)
 
-        # If border style is set, set the pen to be border pen
-        if style & FNB_TABS_BORDER_SIMPLE:
-            dc.SetPen(borderPen)
+            # Draw a white vertical line to the left of the tab
+            dc.SetPen(wx.WHITE_PEN)
+            if not pc.HasFlag(FNB_BOTTOM):
+                blackLineY2 += 1
+                
+            dc.DrawLine(posx, blackLineY1, posx, blackLineY2)
+        
         else:
-            pc = (self.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [self.GetBackgroundColour()])[0]
-            dc.SetPen(wx.Pen(pc))
         
-        dc.DrawRectangle(0, 0, size.x, size.y)
+            # We dont draw a rectangle for non selected tabs, but only
+            # vertical line on the left
 
-        # Take 3 bitmaps for the background for the buttons
+            blackLineY1 = (pc.HasFlag(FNB_BOTTOM) and [VERTICAL_BORDER_PADDING + 2] or [VERTICAL_BORDER_PADDING + 1])[0]
+            blackLineY2 = pc.GetSize().y - 5 
+            dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
         
-        mem_dc = wx.MemoryDC()
+        # -----------------------------------
+        # Text and image drawing
+        # -----------------------------------
 
-        #---------------------------------------
-        # X button
-        #---------------------------------------
-        rect = wx.Rect(self.GetXPos(), 6, 16, 14)
-        mem_dc.SelectObject(self._xBgBmp)
-        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
-        mem_dc.SelectObject(wx.NullBitmap)
+        # Text drawing offset from the left border of the
+        # rectangle
+        
+        # The width of the images are 16 pixels
+        padding = pc.GetParent().GetPadding()
+        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
+        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [5] or [8])[0]
 
-        #---------------------------------------
-        # Right button
-        #---------------------------------------
-        rect = wx.Rect(self.GetRightButtonPos(), 6, 16, 14)
-        mem_dc.SelectObject(self._rightBgBmp)
-        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
-        mem_dc.SelectObject(wx.NullBitmap)
+        if hasImage:
+            textOffset = 2*pc._pParent._nPadding + 16
+        else:
+            textOffset = pc._pParent._nPadding
 
-        #---------------------------------------
-        # Left button
-        #---------------------------------------
-        rect = wx.Rect(self.GetLeftButtonPos(), 6, 16, 14)
-        mem_dc.SelectObject(self._leftBgBmp)
-        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
-        mem_dc.SelectObject(wx.NullBitmap)
+        if tabIdx != pc.GetSelection():
         
-        # We always draw the bottom/upper line of the tabs
-        # regradless the style
-        dc.SetPen(borderPen)
-        self.DrawTabsLine(dc)
+            # Set the text background to be like the vertical lines
+            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
+        
+        if hasImage:
+        
+            imageXOffset = textOffset - 16 - padding
+            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
+                                     posx + imageXOffset, imageYCoord,
+                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
+        
+        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
+        
+        # draw 'x' on tab (if enabled)
+        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
+        
+            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
+            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
 
-        # Restore the pen
-        dc.SetPen(borderPen)
+            # take a bitmap from the position of the 'x' button (the x on tab button)
+            # this bitmap will be used later to delete old buttons
+            tabCloseButtonYCoord = imageYCoord
+            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
+            self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
 
-        if self.HasFlag(FNB_VC71):
-        
-            greyLineYVal = self.HasFlag((FNB_BOTTOM and [0] or [size.y - 2])[0])
-            whiteLineYVal = self.HasFlag((FNB_BOTTOM and [3] or [size.y - 3])[0])
+            # Draw the tab
+            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)                    
 
-            pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
-            dc.SetPen(pen)
 
-            # Draw thik grey line between the windows area and
-            # the tab area
+#------------------------------------------------------------------
+# Fancy style
+#------------------------------------------------------------------
 
-            for num in xrange(3):
-                dc.DrawLine(0, greyLineYVal + num, size.x, greyLineYVal + num)
+class FNBRendererFancy(FNBRenderer):
+    """
+    This class handles the drawing of tabs using the I{Fancy} renderer.
+    """
 
-            wbPen = wx.Pen((self.HasFlag(FNB_BOTTOM) and [wx.BLACK] or [wx.WHITE])[0])
-            dc.SetPen(wbPen)
-            dc.DrawLine(1, whiteLineYVal, size.x - 1, whiteLineYVal)
+    def __init__(self):
+        """ Default class constructor. """
 
-            # Restore the pen
-            dc.SetPen(borderPen)
+        FNBRenderer.__init__(self)
+
+
+    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
+        """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
+
+        # Fancy tabs - like with VC71 but with the following differences:
+        # - The Selected tab is colored with gradient color
+        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+        pc = pageContainer
+
+        pen = (tabIdx == pc.GetSelection() and [wx.Pen(pc._pParent.GetBorderColour())] or [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))])[0]
+
+        if tabIdx == pc.GetSelection():
         
-        if "__WXMAC__" in wx.PlatformInfo:
-            # On MAC, Add these lines so the tab background gets painted
-            if len(self._pagesInfoVec) == 0 or self._nFrom >= len(self._pagesInfoVec):
-                self.Hide()
-                return
-            
-        # Draw labels
-        dc.SetFont(boldFont)
-        posx = self._pParent.GetPadding()
+            posy = (pc.HasFlag(FNB_BOTTOM) and [2] or [VERTICAL_BORDER_PADDING])[0]
+            th = tabHeight - 5
 
-        # Update all the tabs from 0 to '_nFrom' to be non visible
-        for ii in xrange(self._nFrom):
-            self._pagesInfoVec[ii].SetPosition(wx.Point(-1, -1))
-            self._pagesInfoVec[ii].GetRegion().Clear()
+            rect = wx.Rect(posx, posy, tabWidth, th)
 
-        if style & FNB_VC71:
-            tabHeight = ((style & FNB_BOTTOM) and [tabHeight - 4] or [tabHeight])[0]
-        elif style & FNB_FANCY_TABS:
-            tabHeight = ((style & FNB_BOTTOM) and [tabHeight - 2] or [tabHeight])[0]
+            col2 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourTo()] or [pc._pParent.GetGradientColourFrom()])[0]
+            col1 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourFrom()] or [pc._pParent.GetGradientColourTo()])[0]
 
-        #----------------------------------------------------------
-        # Go over and draw the visible tabs
-        #----------------------------------------------------------
+            PaintStraightGradientBox(dc, rect, col1, col2)
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+            dc.SetPen(pen)
+            dc.DrawRectangleRect(rect)
 
-        count = self._nFrom
+            # erase the bottom/top line of the rectangle
+            dc.SetPen(wx.Pen(pc._pParent.GetGradientColourFrom()))
+            if pc.HasFlag(FNB_BOTTOM):
+                dc.DrawLine(rect.x, 2, rect.x + rect.width, 2)
+            else:
+                dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
         
-        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
+        else:
         
-            if style != FNB_VC71:
-                shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[ii].GetTabAngle())/180.0*math.pi))
-            else:
-                shapePoints = 0
-
+            # We dont draw a rectangle for non selected tabs, but only
+            # vertical line on the left
             dc.SetPen(borderPen)
-            dc.SetBrush((ii==self.GetSelection() and [selBrush] or [noselBrush])[0])
+            dc.DrawLine(posx + tabWidth, VERTICAL_BORDER_PADDING + 3, posx + tabWidth, tabHeight - 4)
+        
 
-            # Calculate the text length using the bold font, so when selecting a tab
-            # its width will not change
-            dc.SetFont(boldFont)
-            width, pom = dc.GetTextExtent(self.GetPageText(ii))
+        # -----------------------------------
+        # Text and image drawing
+        # -----------------------------------
 
-            # Now set the font to the correct font
-            dc.SetFont((ii==self.GetSelection() and [boldFont] or [normalFont])[0])
+        # Text drawing offset from the left border of the
+        # rectangle
+        
+        # The width of the images are 16 pixels
+        padding = pc.GetParent().GetPadding()
+        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
+        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
 
-            # Set a minimum size to a tab
-            if width < 20:
-                width = 20
+        if hasImage:
+            textOffset = 2*pc._pParent._nPadding + 16
+        else:
+            textOffset = pc._pParent._nPadding 
 
-            # Add the padding to the tab width
+        textOffset += 2
+
+        if tabIdx != pc.GetSelection():
+        
+            # Set the text background to be like the vertical lines
+            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
+        
+        if hasImage:
+        
+            imageXOffset = textOffset - 16 - padding
+            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
+                                     posx + imageXOffset, imageYCoord,
+                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
+        
+        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
+        
+        # draw 'x' on tab (if enabled)
+        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
+        
+            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
+            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
+
+            # take a bitmap from the position of the 'x' button (the x on tab button)
+            # this bitmap will be used later to delete old buttons
+            tabCloseButtonYCoord = imageYCoord
+            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
+            self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
+
+            # Draw the tab
+            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)            
+        
+
+#------------------------------------------------------------------
+# Visual studio 2005 (VS8)
+#------------------------------------------------------------------
+class FNBRendererVC8(FNBRenderer):    
+    """
+    This class handles the drawing of tabs using the I{VC8} renderer.
+    """
+
+    def __init__(self):
+        """ Default class constructor. """
+
+        FNBRenderer.__init__(self)
+        self._first = True
+        self._factor = 1
+
+        
+    def DrawTabs(self, pageContainer, dc):
+        """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
+
+        pc = pageContainer
+
+        if "__WXMAC__" in wx.PlatformInfo:
+            # Works well on MSW & GTK, however this lines should be skipped on MAC
+            if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
+                pc.Hide()
+                return
+            
+        # Get the text hight
+        tabHeight = self.CalcTabHeight(pageContainer)
+
+        # Set the font for measuring the tab height
+        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
+
+        # Calculate the number of rows required for drawing the tabs
+        rect = pc.GetClientRect()
+
+        # Set the maximum client size
+        pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
+        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+
+        # Create brushes
+        backBrush = wx.Brush(pc._tabAreaColor)
+        noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
+        selBrush = wx.Brush(pc._activeTabColor)
+        size = pc.GetSize()
+
+        # Background
+        dc.SetTextBackground(pc.GetBackgroundColour())
+        dc.SetTextForeground(pc._activeTextColor)
+        
+        # If border style is set, set the pen to be border pen
+        if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
+            dc.SetPen(borderPen)
+        else:
+            dc.SetPen(wx.TRANSPARENT_PEN)
+
+        lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
+        
+        # For VC8 style, we color the tab area in gradient coloring
+        lightcolour = LightColour(pc._tabAreaColor, lightFactor)
+        PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, lightcolour)
+
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.DrawRectangle(0, 0, size.x, size.y)
+
+        # Take 3 bitmaps for the background for the buttons
+        
+        mem_dc = wx.MemoryDC()
+        #---------------------------------------
+        # X button
+        #---------------------------------------
+        rect = wx.Rect(self.GetXPos(pc), 6, 16, 14)
+        mem_dc.SelectObject(self._xBgBmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
+
+        #---------------------------------------
+        # Right button
+        #---------------------------------------
+        rect = wx.Rect(self.GetRightButtonPos(pc), 6, 16, 14)
+        mem_dc.SelectObject(self._rightBgBmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
+
+        #---------------------------------------
+        # Left button
+        #---------------------------------------
+        rect = wx.Rect(self.GetLeftButtonPos(pc), 6, 16, 14)
+        mem_dc.SelectObject(self._leftBgBmp)
+        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
+        mem_dc.SelectObject(wx.NullBitmap)
+    
+        # We always draw the bottom/upper line of the tabs
+        # regradless the style
+        dc.SetPen(borderPen)
+        self.DrawTabsLine(pc, dc)
+
+        # Restore the pen
+        dc.SetPen(borderPen)
+
+        # Draw labels
+        dc.SetFont(boldFont)
+
+        # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
+        for i in xrange(pc._nFrom):
+        
+            pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
+            pc._pagesInfoVec[i].GetRegion().Clear()
+        
+        # Draw the visible tabs, in VC8 style, we draw them from right to left
+        vTabsInfo = self.NumberTabsCanFit(pc)
+
+        activeTabPosx = 0
+        activeTabWidth = 0
+        activeTabHeight = 0
+
+        for cur in xrange(len(vTabsInfo)-1, -1, -1):
+        
+            # 'i' points to the index of the currently drawn tab
+            # in pc.GetPageInfoVector() vector
+            i = pc._nFrom + cur
+            dc.SetPen(borderPen)
+            dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
+
+            # Now set the font to the correct font
+            dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
+
+            # Add the padding to the tab width
             # Tab width:
             # +-----------------------------------------------------------+
             # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
             # +-----------------------------------------------------------+
 
-            tabWidth = 2*self._pParent._nPadding + width
-            imageYCoord = (self.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
+            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
+            posx = vTabsInfo[cur].x
+
+            # By default we clean the tab region
+            # incase we use the VC8 style which requires
+            # the region, it will be filled by the function
+            # drawVc8Tab
+            pc._pagesInfoVec[i].GetRegion().Clear()
+            
+            # Clean the 'x' buttn on the tab 
+            # 'Clean' rectanlge is a rectangle with width or height
+            # with values lower than or equal to 0
+            pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
+
+            # Draw the tab
+            # Incase we are drawing the active tab
+            # we need to redraw so it will appear on top
+            # of all other tabs
+
+            # when using the vc8 style, we keep the position of the active tab so we will draw it again later
+            if i == pc.GetSelection() and pc.HasFlag(FNB_VC8):
+            
+                activeTabPosx = posx
+                activeTabWidth = tabWidth
+                activeTabHeight = tabHeight
+            
+            else:
+            
+                self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
+            
+            # Restore the text forground
+            dc.SetTextForeground(pc._activeTextColor)
+
+            # Update the tab position & size
+            pc._pagesInfoVec[i].SetPosition(wx.Point(posx, VERTICAL_BORDER_PADDING))
+            pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
+        
+        # Incase we are in VC8 style, redraw the active tab (incase it is visible)
+        if pc.GetSelection() >= pc._nFrom and pc.GetSelection() < pc._nFrom + len(vTabsInfo):
+        
+            self.DrawTab(pc, dc, activeTabPosx, pc.GetSelection(), activeTabWidth, activeTabHeight, pc._nTabXButtonStatus)
+        
+        # Update all tabs that can not fit into the screen as non-visible
+        for xx in xrange(pc._nFrom + len(vTabsInfo), len(pc._pagesInfoVec)):
+        
+            pc._pagesInfoVec[xx].SetPosition(wx.Point(-1, -1))
+            pc._pagesInfoVec[xx].GetRegion().Clear()
+        
+        # Draw the left/right/close buttons 
+        # Left arrow
+        self.DrawLeftArrow(pc, dc)
+        self.DrawRightArrow(pc, dc)
+        self.DrawX(pc, dc)
+        self.DrawDropDownArrow(pc, dc)
+
+
+    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
+        """ Draws a tab using VC8 style. """
+
+        pc = pageContainer
+        borderPen = wx.Pen(pc._pParent.GetBorderColour())
+        tabPoints = [wx.Point() for ii 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)
+        #
+        #
+
+        tabPoints[0].x = (pc.HasFlag(FNB_BOTTOM) and [posx] or [posx+self._factor])[0]
+        tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 3])[0]
+
+        tabPoints[1].x = tabPoints[0].x + tabHeight - VERTICAL_BORDER_PADDING - 3 - self._factor
+        tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
+
+        tabPoints[2].x = tabPoints[1].x + 4
+        tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
+
+        tabPoints[3].x = tabPoints[2].x + tabWidth - 2
+        tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
+
+        tabPoints[4].x = tabPoints[3].x + 1
+        tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
+
+        tabPoints[5].x = tabPoints[4].x + 1
+        tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
+
+        tabPoints[6].x = tabPoints[2].x + tabWidth
+        tabPoints[6].y = tabPoints[0].y
+
+        tabPoints[7].x = tabPoints[0].x
+        tabPoints[7].y = tabPoints[0].y
+
+        pc._pagesInfoVec[tabIdx].SetRegion(tabPoints)
+
+        # Draw the polygon
+        br = dc.GetBrush()
+        dc.SetBrush(wx.Brush((tabIdx == pc.GetSelection() and [pc._activeTabColor] or [pc._colorTo])[0]))
+        dc.SetPen(wx.Pen((tabIdx == pc.GetSelection() and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
+        dc.DrawPolygon(tabPoints)
+
+        # Restore the brush
+        dc.SetBrush(br)
+        rect = pc.GetClientRect()
+
+        if tabIdx != pc.GetSelection() and not pc.HasFlag(FNB_BOTTOM):
+        
+            # Top default tabs
+            dc.SetPen(wx.Pen(pc._pParent.GetBorderColour()))
+            lineY = rect.height
+            curPen = dc.GetPen()
+            curPen.SetWidth(1)
+            dc.SetPen(curPen)
+            dc.DrawLine(posx, lineY, posx+rect.width, lineY)
+        
+        # Incase we are drawing the selected tab, we draw the border of it as well
+        # but without the bottom (upper line incase of wxBOTTOM)
+        if tabIdx == pc.GetSelection():
+        
+            borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+            dc.SetPen(borderPen)
+            dc.SetBrush(wx.TRANSPARENT_BRUSH)
+            dc.DrawPolygon(tabPoints)
+
+            # 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)
+
+        self.FillVC8GradientColour(pc, dc, tabPoints, tabIdx == pc.GetSelection(), tabIdx)
+
+        # Draw a thin line to the right of the non-selected tab
+        if tabIdx != pc.GetSelection():
+        
+            dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
+            dc.DrawLine(tabPoints[4].x-1, tabPoints[4].y, tabPoints[5].x-1, tabPoints[5].y)
+            dc.DrawLine(tabPoints[5].x-1, tabPoints[5].y, tabPoints[6].x-1, tabPoints[6].y)
+        
+        # Text drawing offset from the left border of the 
+        # rectangle
+        
+        # The width of the images are 16 pixels
+        vc8ShapeLen = tabHeight - VERTICAL_BORDER_PADDING - 2
+        if pc.TabHasImage(tabIdx):
+            textOffset = 2*pc._pParent.GetPadding() + 16 + vc8ShapeLen 
+        else:
+            textOffset = pc._pParent.GetPadding() + vc8ShapeLen
+
+        # Draw the image for the tab if any
+        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
+
+        if pc.TabHasImage(tabIdx):
+        
+            imageXOffset = textOffset - 16 - pc._pParent.GetPadding()
+            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
+                                     posx + imageXOffset, imageYCoord,
+                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)        
+
+        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+            
+        # if selected tab, draw text in bold
+        if tabIdx == pc.GetSelection():
+            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
+        
+        dc.SetFont(boldFont)
+        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
+
+        # draw 'x' on tab (if enabled)
+        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
+
+            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
+            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
+
+            # take a bitmap from the position of the 'x' button (the x on tab button)
+            # this bitmap will be used later to delete old buttons
+            tabCloseButtonYCoord = imageYCoord
+            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
+            self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
+            # Draw the tab
+            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
+
+
+    def FillVC8GradientColour(self, pageContainer, dc, tabPoints, bSelectedTab, tabIdx):
+        """ Fills a tab with a gradient shading. """
+
+        # calculate gradient coefficients
+        pc = pageContainer
+
+        if self._first:
+            self._first = False
+            pc._colorTo   = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 0) 
+            pc._colorFrom = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 60)
+        
+        col2 = pc._pParent.GetGradientColourTo()
+        col1 = pc._pParent.GetGradientColourFrom()
+
+        # If colorful tabs style is set, override the tab color
+        if pc.HasFlag(FNB_COLORFUL_TABS):
+        
+            if not pc._pagesInfoVec[tabIdx].GetColour():
+            
+                # First time, generate color, and keep it in the vector
+                tabColor = RandomColour()
+                pc._pagesInfoVec[tabIdx].SetColour(tabColor)
+            
+            if pc.HasFlag(FNB_BOTTOM):
+            
+                col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
+                col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
+            
+            else:
+            
+                col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
+                col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
+            
+        size = abs(tabPoints[2].y - tabPoints[0].y) - 1
+
+        rf, gf, bf = 0, 0, 0
+        rstep = float(col2.Red() - col1.Red())/float(size)
+        gstep = float(col2.Green() - col1.Green())/float(size)
+        bstep = float(col2.Blue() - col1.Blue())/float(size)
+        
+        y = tabPoints[0].y 
+
+        # If we are drawing the selected tab, we need also to draw a line 
+        # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
+        # by drawing the rectangle with transparent brush
+        # the line under the selected tab will be deleted by the drwaing loop
+        if bSelectedTab:
+            self.DrawTabsLine(pc, dc)
+
+        while 1:
+        
+            if pc.HasFlag(FNB_BOTTOM):
+            
+                if y > tabPoints[0].y + size:
+                    break
+            
+            else:
+            
+                if y < tabPoints[0].y - size:
+                    break
+            
+            currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
+
+            dc.SetPen((bSelectedTab and [wx.Pen(pc._activeTabColor)] or [wx.Pen(currCol)])[0])
+            startX = self.GetStartX(tabPoints, y, pc.GetParent().GetWindowStyleFlag()) 
+            endX = self.GetEndX(tabPoints, y, pc.GetParent().GetWindowStyleFlag())
+            dc.DrawLine(startX, y, endX, y)
+
+            # Draw the border using the 'edge' point
+            dc.SetPen(wx.Pen((bSelectedTab and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
+            
+            dc.DrawPoint(startX, y)
+            dc.DrawPoint(endX, y)
+            
+            # Progress the color 
+            rf += rstep
+            gf += gstep
+            bf += bstep
+
+            if pc.HasFlag(FNB_BOTTOM):
+                y = y + 1
+            else:
+                y = y - 1
+
+
+    def GetStartX(self, tabPoints, y, style):
+        """ Returns the x start position of a tab. """
+
+        x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
+
+        # We check the 3 points to the left
+
+        bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
+        match = False
+
+        if bBottomStyle:
+        
+            for i in xrange(3):
+                
+                if y >= tabPoints[i].y and y < tabPoints[i+1].y:
+                
+                    x1 = tabPoints[i].x
+                    x2 = tabPoints[i+1].x
+                    y1 = tabPoints[i].y
+                    y2 = tabPoints[i+1].y
+                    match = True
+                    break
+                
+        else:
+        
+            for i in xrange(3):
+                
+                if y <= tabPoints[i].y and y > tabPoints[i+1].y:
+                
+                    x1 = tabPoints[i].x
+                    x2 = tabPoints[i+1].x
+                    y1 = tabPoints[i].y
+                    y2 = tabPoints[i+1].y
+                    match = True
+                    break
+                
+        if not match:
+            return tabPoints[2].x
+
+        # According to the equation y = ax + b => x = (y-b)/a
+        # We know the first 2 points
+
+        if x2 == x1:
+            return x2
+        else:
+            a = (y2 - y1)/(x2 - x1)
+
+        b = y1 - ((y2 - y1)/(x2 - x1))*x1
+
+        if a == 0:
+            return int(x1)
+
+        x = (y - b)/a
+        
+        return int(x)
+
+
+    def GetEndX(self, tabPoints, y, style):
+        """ Returns the x end position of a tab. """
+
+        x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
+
+        # We check the 3 points to the left
+        bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
+        match = False
+
+        if bBottomStyle:
+
+            for i in xrange(7, 3, -1):
+                
+                if y >= tabPoints[i].y and y < tabPoints[i-1].y:
+                
+                    x1 = tabPoints[i].x
+                    x2 = tabPoints[i-1].x
+                    y1 = tabPoints[i].y
+                    y2 = tabPoints[i-1].y
+                    match = True
+                    break
+        
+        else:
+        
+            for i in xrange(7, 3, -1):
+                
+                if y <= tabPoints[i].y and y > tabPoints[i-1].y:
+                
+                    x1 = tabPoints[i].x
+                    x2 = tabPoints[i-1].x
+                    y1 = tabPoints[i].y
+                    y2 = tabPoints[i-1].y
+                    match = True
+                    break
+
+        if not match:
+            return tabPoints[3].x
 
-            # Style to add a small 'x' button on the top right
-            # of the tab
-            if style & FNB_X_ON_TAB and ii == self.GetSelection():
-            
-                # The xpm image that contains the 'x' button is 9 pixles
-                tabWidth += self._pParent._nPadding + 9
-            
-            if not (style & FNB_VC71) and not (style & FNB_FANCY_TABS):
-                # Default style
-                tabWidth += 2*shapePoints
+        # According to the equation y = ax + b => x = (y-b)/a
+        # We know the first 2 points
 
-            hasImage = self._ImageList != None and self._pagesInfoVec[ii].GetImageIndex() != -1
+        # Vertical line
+        if x1 == x2:
+            return int(x1)
+        
+        a = (y2 - y1)/(x2 - x1)
+        b = y1 - ((y2 - y1)/(x2 - x1))*x1
 
-            # For VC71 style, we only add the icon size (16 pixels)
-            if hasImage:
-            
-                if style & FNB_VC71 or style & FNB_FANCY_TABS:
-                    tabWidth += 16 + self._pParent._nPadding
-                else:
-                    # Default style
-                    tabWidth += 16 + self._pParent._nPadding + shapePoints/2
-            
-            # Check if we can draw more
-            if posx + tabWidth + self.GetButtonsAreaLength() >= clientWidth:
-                break
-            
-            count = count + 1            
+        if a == 0:
+            return int(x1)
 
-            # By default we clean the tab region
-            self._pagesInfoVec[ii].GetRegion().Clear()
+        x = (y - b)/a
 
-            # Clean the 'x' buttn on the tab
-            # 'Clean' rectanlge is a rectangle with width or height
-            # with values lower than or equal to 0
-            self._pagesInfoVec[ii].GetXRect().SetSize(wx.Size(-1, -1))
+        return int(x)
 
-            # Draw the tab
-            if style & FNB_FANCY_TABS:
-                self.DrawFancyTab(dc, posx, ii, tabWidth, tabHeight)
-            elif style & FNB_VC71:
-                self.DrawVC71Tab(dc, posx, ii, tabWidth, tabHeight)
-            else:
-                self.DrawStandardTab(dc, posx, ii, tabWidth, tabHeight)
 
-            # The width of the images are 16 pixels
-            if hasImage:
-                textOffset = 2*self._pParent._nPadding + 16 + shapePoints/2 
-            else:
-                textOffset = self._pParent._nPadding + shapePoints/2 
+    def NumberTabsCanFit(self, pageContainer, fr=-1):
+        """ Returns the number of tabs that can fit in the visible area. """
 
-            # After several testing, it seems that we can draw
-            # the text 2 pixles to the right - this is done only
-            # for the standard tabs
-                
-            if not self.HasFlag(FNB_FANCY_TABS):
-                textOffset += 2
+        pc = pageContainer
+        
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
 
-            if ii != self.GetSelection():
-                # Set the text background to be like the vertical lines
-                dc.SetTextForeground(self._nonActiveTextColor)
-            
-            if hasImage:
-            
-                imageXOffset = textOffset - 16 - self._pParent._nPadding
-                self._ImageList.Draw(self._pagesInfoVec[ii].GetImageIndex(), dc,
-                                     posx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
+        # Empty results
+        vTabInfo = []
+        tabHeight = self.CalcTabHeight(pageContainer)
 
-            dc.DrawText(self.GetPageText(ii), posx + textOffset, imageYCoord)
+        # The drawing starts from posx
+        posx = pc._pParent.GetPadding()
+        
+        if fr < 0:
+            fr = pc._nFrom
 
-            # From version 1.2 - a style to add 'x' button
-            # on a tab
-            
-            if self.HasFlag(FNB_X_ON_TAB) and ii == self.GetSelection():
-            
-                textWidth, textHeight = dc.GetTextExtent(self.GetPageText(ii))
-                tabCloseButtonXCoord = posx + textOffset + textWidth + 1
+        for i in xrange(fr, len(pc._pagesInfoVec)):
+        
+            vc8glitch = tabHeight + FNB_HEIGHT_SPACER
+            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
 
-                # take a bitmap from the position of the 'x' button (the x on tab button)
-                # this bitmap will be used later to delete old buttons
-                tabCloseButtonYCoord = imageYCoord
-                x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-                mem_dc = wx.MemoryDC()
-                mem_dc.SelectObject(self._tabXBgBmp)
-                mem_dc.Blit(0, 0, x_rect.width, x_rect.height, dc, x_rect.x, x_rect.y)
-                mem_dc.SelectObject(wx.NullBitmap)
+            if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength(pc) >= clientWidth:
+                break
 
-                # Draw the tab
-                self.DrawTabX(dc, x_rect, ii)
-            
-            # Restore the text forground
-            dc.SetTextForeground(self._activeTextColor)
+            # Add a result to the returned vector
+            tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth, tabHeight)
+            vTabInfo.append(tabRect)
 
-            # Update the tab position & size
-            posy = (style & FNB_BOTTOM and [0] or [VERTICAL_BORDER_PADDING])[0]
-            
-            self._pagesInfoVec[ii].SetPosition(wx.Point(posx, posy))
-            self._pagesInfoVec[ii].SetSize(wx.Size(tabWidth, tabHeight))
-            posx += tabWidth
-            
-        # Update all tabs that can not fit into the screen as non-visible
-        for ii in xrange(count, len(self._pagesInfoVec)):
-        
-            self._pagesInfoVec[ii].SetPosition(wx.Point(-1, -1))
-            self._pagesInfoVec[ii].GetRegion().Clear()
+            # Advance posx
+            posx += tabWidth + FNB_HEIGHT_SPACER
         
-        # Draw the left/right/close buttons
-        # Left arrow
-        self.DrawLeftArrow(dc)
-        self.DrawRightArrow(dc)
-        self.DrawX(dc)
+        return vTabInfo
+    
 
+# ---------------------------------------------------------------------------- #
+# Class FlatNotebook
+# ---------------------------------------------------------------------------- #
 
-    def DrawFancyTab(self, dc, posx, tabIdx, tabWidth, tabHeight):
+class FlatNotebook(wx.Panel):
+    """
+    Display one or more windows in a notebook.
+    
+    B{Events}:
+        - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active 
+            page in the notebook is changing
+        - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active 
+            page in the notebook has changed
+        - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the 
+            notebook is closing
+        - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the 
+            notebook has been closed
+        - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
+            clicks a tab in the notebook with the right mouse
+            button
+    """
+    
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=0, name="FlatNotebook"):
         """
-        Fancy tabs - like with VC71 but with the following differences:
-        - The Selected tab is colored with gradient color
+        Default class constructor.
+
+        All the parameters are as in wxPython class construction, except the
+        'style': this can be assigned to whatever combination of FNB_* styles.
+        
         """
+
+        self._bForceSelection = False
+        self._nPadding = 6
+        self._nFrom = 0
+        style |= wx.TAB_TRAVERSAL
+        self._pages = None
+        self._windows = []
+        self._popupWin = None
+
+        wx.Panel.__init__(self, parent, id, pos, size, style)
         
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-        pen = (tabIdx==self.GetSelection() and [wx.Pen(self._colorBorder)] \
-               or [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))])[0]
+        self._pages = PageContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style)
+
+        self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
+
+        self.Init()
 
-        fnb_bottom = self.HasFlag(FNB_BOTTOM)
 
-        if tabIdx == self.GetSelection():
+    def Init(self):
+        """ Initializes all the class attributes. """
         
-            posy = (fnb_bottom and [2] or [VERTICAL_BORDER_PADDING])[0]
-            th = (fnb_bottom and [tabHeight - 2] or [tabHeight - 5])[0]
+        self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
 
-            rect = wx.Rect(posx, posy, tabWidth, th)
-            self.FillGradientColor(dc, rect)
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-            dc.SetPen(pen)
-            dc.DrawRectangleRect(rect)
+        self._mainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.SetSizer(self._mainSizer)
 
-            # erase the bottom/top line of the rectangle
-            dc.SetPen(wx.Pen(self._colorFrom))
-            if fnb_bottom:
-                dc.DrawLine(rect.x, 2, rect.x + rect.width, 2)
-            else:
-                dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
+        # The child panels will inherit this bg color, so leave it at the default value
+        #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
+
+        # Set default page height
+        dc = wx.ClientDC(self)
         
-        else:
+        if "__WXGTK__" in wx.PlatformInfo:
+            # For GTK it seems that we must do this steps in order
+            # for the tabs will get the proper height on initialization
+            # on MSW, preforming these steps yields wierd results
+            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
+            dc.SetFont(boldFont)
         
-            # We dont draw a rectangle for non selected tabs, but only
-            # vertical line on the left
-            dc.SetPen(borderPen)
-            dc.DrawLine(posx + tabWidth, VERTICAL_BORDER_PADDING + 3, posx + tabWidth, tabHeight - 4)
+        height = dc.GetCharHeight()
+
+        tabHeight = height + FNB_HEIGHT_SPACER         # We use 8 pixels as padding
         
+        if "__WXGTK__" in wx.PlatformInfo:
+            tabHeight += 6
+            
+        self._pages.SetSizeHints(-1, tabHeight)
+        # Add the tab container to the sizer
+        self._mainSizer.Insert(0, self._pages, 0, wx.EXPAND)
+        self._mainSizer.Layout()
 
-    def DrawVC71Tab(self, dc, posx, tabIdx, tabWidth, tabHeight):
-        """ Draws tabs with VC71 style. """
+        self._pages._nFrom = self._nFrom
+        self._pDropTarget = FNBDropTarget(self)
+        self.SetDropTarget(self._pDropTarget)
 
-        fnb_bottom = self.HasFlag(FNB_BOTTOM)
-        
-        # Visual studio 7.1 style
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-        dc.SetPen((tabIdx==self.GetSelection() and [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [borderPen])[0])
-        dc.SetBrush((tabIdx==self.GetSelection() and [wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or \
-                     [wx.Brush(wx.Colour(247, 243, 233))])[0])
 
-        if tabIdx == self.GetSelection():
-        
-            posy = (fnb_bottom and [0] or [VERTICAL_BORDER_PADDING])[0]
-            dc.DrawRectangle(posx, posy, tabWidth, tabHeight - 1)
+    def SetActiveTabTextColour(self, textColour):
+        """ Sets the text colour for the active tab. """
 
-            # Draw a black line on the left side of the
-            # rectangle
-            dc.SetPen(wx.BLACK_PEN)
+        self._pages._activeTextColor = textColour
 
-            blackLineY1 = VERTICAL_BORDER_PADDING
-            blackLineY2 = (fnb_bottom and [self.GetSize().y - 5] or [self.GetSize().y - 3])[0]
-            dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
 
-            # To give the tab more 3D look we do the following
-            # Incase the tab is on top,
-            # Draw a thick white line on top of the rectangle
-            # Otherwise, draw a thin (1 pixel) black line at the bottom
+    def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
+        """ Handles the drop action from a DND operation. """
 
-            pen = wx.Pen((fnb_bottom and [wx.BLACK] or [wx.WHITE])[0])
-            dc.SetPen(pen)
-            whiteLinePosY = (fnb_bottom and [blackLineY2] or [VERTICAL_BORDER_PADDING])[0]
-            dc.DrawLine(posx , whiteLinePosY, posx + tabWidth + 1, whiteLinePosY)
+        return self._pages.OnDropTarget(x, y, nTabPage, wnd_oldContainer)
 
-            # Draw a white vertical line to the left of the tab
-            dc.SetPen(wx.WHITE_PEN)
-            if not fnb_bottom:
-                blackLineY2 += 1
-                
-            dc.DrawLine(posx, blackLineY1, posx, blackLineY2)
-        
-        else:
-        
-            # We dont draw a rectangle for non selected tabs, but only
-            # vertical line on the left
 
-            blackLineY1 = (fnb_bottom and [VERTICAL_BORDER_PADDING + 2] or [VERTICAL_BORDER_PADDING + 1])[0]
-            blackLineY2 = self.GetSize().y - 5 
-            dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
-        
+    def GetPreviousSelection(self):
+        """ Returns the previous selection. """
+
+        return self._pages._iPreviousActivePage
 
-    def DrawStandardTab(self, dc, posx, tabIdx, tabWidth, tabHeight):
-        """ Draws tabs with standard style. """
 
-        fnb_bottom = self.HasFlag(FNB_BOTTOM)
+    def AddPage(self, page, text, select=True, imageId=-1):
+        """
+        Add a page to the L{FlatNotebook}.
+
+        @param page: Specifies the new page.
+        @param text: Specifies the text for the new page.
+        @param select: Specifies whether the page should be selected.
+        @param imageId: Specifies the optional image index for the new page.
         
-        # Default style
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+        Return value:
+        True if successful, False otherwise.
+        """
 
-        tabPoints = [wx.Point() for ii in xrange(7)]
-        tabPoints[0].x = posx
-        tabPoints[0].y = (fnb_bottom and [2] or [tabHeight - 2])[0]
+        # sanity check
+        if not page:
+            return False
 
-        tabPoints[1].x = int(posx+(tabHeight-2)*math.tan(float(self._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-        tabPoints[1].y = (fnb_bottom and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
+        # reparent the window to us
+        page.Reparent(self)
 
-        tabPoints[2].x = tabPoints[1].x+2
-        tabPoints[2].y = (fnb_bottom and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
+        # Add tab
+        bSelected = select or len(self._windows) == 0
 
-        tabPoints[3].x = int(posx+tabWidth-(tabHeight-2)*math.tan(float(self._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))-2
-        tabPoints[3].y = (fnb_bottom and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
+        if bSelected:
+            
+            bSelected = False
+            
+            # Check for selection and send events
+            oldSelection = self._pages._iActivePage
+            tabIdx = len(self._windows)
+            
+            event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
+            event.SetSelection(tabIdx)
+            event.SetOldSelection(oldSelection)
+            event.SetEventObject(self)
+            
+            if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
+                bSelected = True            
+        
+        curSel = self._pages.GetSelection()
 
-        tabPoints[4].x = tabPoints[3].x+2
-        tabPoints[4].y = (fnb_bottom and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
+        if not self._pages.IsShown():
+            self._pages.Show()
 
-        tabPoints[5].x = int(tabPoints[4].x+(tabHeight-2)*math.tan(float(self._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-        tabPoints[5].y = (fnb_bottom and [2] or [tabHeight - 2])[0]
+        self._pages.AddPage(text, bSelected, imageId)
+        self._windows.append(page)
 
-        tabPoints[6].x = tabPoints[0].x
-        tabPoints[6].y = tabPoints[0].y
+        self.Freeze()
 
-        if tabIdx == self.GetSelection():
-        
-            # Draw the tab as rounded rectangle
-            dc.DrawPolygon(tabPoints)
-        
-        else:
+        # Check if a new selection was made
+        if bSelected:
         
-            if tabIdx != self.GetSelection() - 1:
+            if curSel >= 0:
             
-                # Draw a vertical line to the right of the text
-                pt1x = tabPoints[5].x
-                pt1y = (fnb_bottom and [4] or [tabHeight - 6])[0]
-                pt2x = tabPoints[5].x
-                pt2y = (fnb_bottom and [tabHeight - 4] or [4])[0]
-                dc.DrawLine(pt1x, pt1y, pt2x, pt2y)
+                # Remove the window from the main sizer
+                self._mainSizer.Detach(self._windows[curSel])
+                self._windows[curSel].Hide()
             
-        if tabIdx == self.GetSelection():
-        
-            savePen = dc.GetPen()
-            whitePen = wx.Pen(wx.WHITE)
-            whitePen.SetWidth(1)
-            dc.SetPen(whitePen)
+            if self.GetWindowStyleFlag() & FNB_BOTTOM:
+            
+                self._mainSizer.Insert(0, page, 1, wx.EXPAND)
+            
+            else:
+            
+                # We leave a space of 1 pixel around the window
+                self._mainSizer.Add(page, 1, wx.EXPAND)
 
-            secPt = wx.Point(tabPoints[5].x + 1, tabPoints[5].y)
-            dc.DrawLine(tabPoints[0].x, tabPoints[0].y, secPt.x, secPt.y)
+            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
+            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
+            event.SetOldSelection(oldSelection)
+            self.GetEventHandler().ProcessEvent(event)
+            
+        else:
 
-            # Restore the pen
-            dc.SetPen(savePen)
-        
+            # Hide the page
+            page.Hide()
 
-    def AddPage(self, caption, selected=True, imgindex=-1):
+        self.Thaw()        
+        self._mainSizer.Layout()
+        self.Refresh()
+
+        return True        
+
+
+    def SetImageList(self, imageList):
+        """
+        Sets the image list for the page control. It does not take ownership
+        of the image list, you must delete it yourself.
         """
-        Add a page to the FlatNotebook.
 
-        Parameters:
-        - window: Specifies the new page.
-        - caption: Specifies the text for the new page.
-        - selected: Specifies whether the page should be selected.
-        - imgindex: Specifies the optional image index for the new page.
-        
-        Return value:
-        True if successful, False otherwise.
-        """
+        self._pages.SetImageList(imageList)
 
-        if selected:
-        
-            self._iActivePage = len(self._pagesInfoVec)
+
+    def GetImageList(self):
+        """ Returns the associated image list. """
         
-        # Create page info and add it to the vector
-        pageInfo = PageInfo(caption, imgindex)
-        self._pagesInfoVec.append(pageInfo)
-        self.Refresh()
+        return self._pages.GetImageList()
 
 
-    def InsertPage(self, indx, text, selected=True, imgindex=-1):
+    def InsertPage(self, indx, page, text, select=True, imageId=-1):
         """
         Inserts a new page at the specified position.
 
-        Parameters:
-        - indx: Specifies the position of the new page.
-        - page: Specifies the new page.
-        - text: Specifies the text for the new page.
-        - select: Specifies whether the page should be selected.
-        - imgindex: Specifies the optional image index for the new page.
+        @param indx: Specifies the position of the new page.
+        @param page: Specifies the new page.
+        @param text: Specifies the text for the new page.
+        @param select: Specifies whether the page should be selected.
+        @param imageId: Specifies the optional image index for the new page.
         
         Return value:
         True if successful, False otherwise.
         """     
 
-        if selected:
-        
-            self._iActivePage = len(self._pagesInfoVec)
-        
-        self._pagesInfoVec.insert(indx, PageInfo(text, imgindex))
-        
-        self.Refresh()
-        return True
-
-
-    def OnSize(self, event):
-        """ Handles the wx.EVT_SIZE events for PageContainerBase. """
+        # sanity check
+        if not page:
+            return False
 
-        self.Refresh() # Call on paint
-        event.Skip()
+        # reparent the window to us
+        page.Reparent(self)
 
+        if not self._windows:
+        
+            self.AddPage(page, text, select, imageId)
+            return True
 
-    def OnMiddleDown(self, event):
-        """ Handles the wx.EVT_MIDDLE_DOWN events for PageContainerBase. """
+        # Insert tab
+        bSelected = select or not self._windows
+        curSel = self._pages.GetSelection()
+        
+        indx = max(0, min(indx, len(self._windows)))
 
-        # Test if this style is enabled
-        style = self.GetParent().GetWindowStyleFlag()
+        if indx <= len(self._windows):
         
-        if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS:
-            return
+            self._windows.insert(indx, page)
+        
+        else:
+        
+            self._windows.append(page)
 
-        where, tabIdx = self.HitTest(event.GetPosition())
+        if bSelected:
         
-        if where == FNB_TAB:
-            self.DeletePage(tabIdx)
+            bSelected = False
+            
+            # Check for selection and send events
+            oldSelection = self._pages._iActivePage
+            
+            event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
+            event.SetSelection(indx)
+            event.SetOldSelection(oldSelection)
+            event.SetEventObject(self)
+            
+            if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
+                bSelected = True            
         
-        event.Skip()
+        self._pages.InsertPage(indx, text, bSelected, imageId)
+        
+        if indx <= curSel:
+            curSel = curSel + 1
 
+        self.Freeze()
 
-    def OnRightDown(self, event):
-        """ Handles the wx.EVT_RIGHT_DOWN events for PageContainerBase. """
+        # Check if a new selection was made
+        if bSelected:
+        
+            if curSel >= 0:
+            
+                # Remove the window from the main sizer
+                self._mainSizer.Detach(self._windows[curSel])
+                self._windows[curSel].Hide()
+            
+            self._pages.SetSelection(indx)
 
-        if self._pRightClickMenu:
+            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
+            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
+            event.SetOldSelection(oldSelection)
+            self.GetEventHandler().ProcessEvent(event)
         
-            where, tabIdx = self.HitTest(event.GetPosition())
+        else:
+        
+            # Hide the page
+            page.Hide()
 
-            if where in [FNB_TAB, FNB_TAB_X]:
+        self.Thaw()
+        self._mainSizer.Layout()        
+        self.Refresh()
 
-                if self._pagesInfoVec[tabIdx].GetEnabled():
-                    # Set the current tab to be active
-                    self.SetSelection(tabIdx)
-
-                    # If the owner has defined a context menu for the tabs,
-                    # popup the right click menu
-                    if self._pRightClickMenu:
-                        self.PopupMenu(self._pRightClickMenu)
-                    else:
-                        # send a message to popup a custom menu
-                        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId())
-                        event.SetSelection(tabIdx)
-                        event.SetOldSelection(self._iActivePage)
-                        event.SetEventObject(self.GetParent())
-                        self.GetParent().GetEventHandler().ProcessEvent(event)
-                
-            event.Skip()
+        return True
 
 
-    def OnLeftDown(self, event):
-        """ Handles the wx.EVT_LEFT_DOWN events for PageContainerBase. """
+    def SetSelection(self, page):
+        """
+        Sets the selection for the given page.
+        The call to this function generates the page changing events
+        """
 
-        # Reset buttons status
-        self._nXButtonStatus     = FNB_BTN_NONE
-        self._nLeftButtonStatus  = FNB_BTN_NONE
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nTabXButtonStatus  = FNB_BTN_NONE
+        if page >= len(self._windows) or not self._windows:
+            return
 
-        self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition())
+        # Support for disabed tabs
+        if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection:
+            return
 
-        if self._nLeftClickZone == FNB_LEFT_ARROW:
-            self._nLeftButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_RIGHT_ARROW:
-            self._nRightButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_X:
-            self._nXButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_TAB_X:
-            self._nTabXButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
+        curSel = self._pages.GetSelection()
 
-        elif self._nLeftClickZone == FNB_TAB:
-            
-            if self._iActivePage != tabIdx:
-            
-                # In case the tab is disabled, we dont allow to choose it
-                if self._pagesInfoVec[tabIdx].GetEnabled():
+        # program allows the page change
+        self.Freeze()
+        if curSel >= 0:
+        
+            # Remove the window from the main sizer
+            self._mainSizer.Detach(self._windows[curSel])
+            self._windows[curSel].Hide()
+        
+        if self.GetWindowStyleFlag() & FNB_BOTTOM:
+        
+            self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND)
+        
+        else:
+        
+            # We leave a space of 1 pixel around the window
+            self._mainSizer.Add(self._windows[page], 1, wx.EXPAND)
+        
+        self._windows[page].Show()
+        self.Thaw()
+        
+        self._mainSizer.Layout()
+        
+        if page != self._pages._iActivePage:
+            # there is a real page changing
+            self._pages._iPreviousActivePage = self._pages._iActivePage
 
-                    oldSelection = self._iActivePage
+        self._pages._iActivePage = page
+        self._pages.DoSetSelection(page)
 
-                    event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
-                    event.SetSelection(tabIdx)
-                    event.SetOldSelection(oldSelection)
-                    event.SetEventObject(self.GetParent())
-                    if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed():
-                    
-                        self.SetSelection(tabIdx)
 
-                        # Fire a wxEVT_TABBEDCTRL_PAGE_CHANGED event
-                        event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
-                        event.SetOldSelection(oldSelection)
-                        self.GetParent().GetEventHandler().ProcessEvent(event)        
+    def DeletePage(self, page):
+        """
+        Deletes the specified page, and the associated window.
+        The call to this function generates the page changing events.
+        """
 
+        if page >= len(self._windows) or page < 0:
+            return
 
-    def OnLeftUp(self, event):
-        """ Handles the wx.EVT_LEFT_UP events for PageContainerBase. """
+        # Fire a closing event
+        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
+        event.SetSelection(page)
+        event.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(event)
 
-        # forget the zone that was initially clicked
-        self._nLeftClickZone = FNB_NOWHERE
+        # The event handler allows it?
+        if not event.IsAllowed():
+            return
 
-        where, tabIdx = self.HitTest(event.GetPosition())
+        self.Freeze()
+
+        # Delete the requested page
+        pageRemoved = self._windows[page]
+
+        # If the page is the current window, remove it from the sizer
+        # as well
+        if page == self._pages.GetSelection():
+            self._mainSizer.Detach(pageRemoved)
         
-        if where == FNB_LEFT_ARROW:
-            
-            if self._nFrom == 0:
-                return
+        # Remove it from the array as well
+        self._windows.pop(page)
 
-            # Make sure that the button was pressed before
-            if self._nLeftButtonStatus != FNB_BTN_PRESSED:
-                return
+        # Now we can destroy it in wxWidgets use Destroy instead of delete
+        pageRemoved.Destroy()
 
-            self._nLeftButtonStatus = FNB_BTN_HOVER
+        self.Thaw()
 
-            # We scroll left with bulks of 5
-            scrollLeft = self.GetNumTabsCanScrollLeft()
+        self._pages.DoDeletePage(page)
+        self.Refresh()
 
-            self._nFrom -= scrollLeft
-            if self._nFrom < 0:
-                self._nFrom = 0
+        # Fire a closed event
+        closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
+        closedEvent.SetSelection(page)
+        closedEvent.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(closedEvent)
 
-            self.Refresh()
-            
-        elif where == FNB_RIGHT_ARROW:
-            
-            if self._nFrom >= len(self._pagesInfoVec) - 1:
-                return
 
-            # Make sure that the button was pressed before
-            if self._nRightButtonStatus != FNB_BTN_PRESSED:
-                return
+    def DeleteAllPages(self):
+        """ Deletes all the pages. """
 
-            self._nRightButtonStatus = FNB_BTN_HOVER
+        if not self._windows:
+            return False
 
-            # Check if the right most tab is visible, if it is
-            # don't rotate right anymore
-            if self._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
-                return
+        self.Freeze()
+        
+        for page in self._windows:
+            page.Destroy()
+        
+        self._windows = []
+        self.Thaw()
 
-            lastVisibleTab = self.GetLastVisibleTab()
-            if lastVisibleTab < 0:
-                # Probably the screen is too small for displaying even a single
-                # tab, in this case we do nothing
-                return
+        # Clear the container of the tabs as well
+        self._pages.DeleteAllPages()
+        return True
 
-            self._nFrom += self.GetNumOfVisibleTabs()
-            self.Refresh()
-            
-        elif where == FNB_X:
-            
-            # Make sure that the button was pressed before
-            if self._nXButtonStatus != FNB_BTN_PRESSED:
-                return
 
-            self._nXButtonStatus = FNB_BTN_HOVER
+    def GetCurrentPage(self):
+        """ Returns the currently selected notebook page or None. """
+        
+        sel = self._pages.GetSelection()
+        if sel < 0:
+            return None
 
-            self.DeletePage(self._iActivePage)
-            
-        elif where == FNB_TAB_X:
-            
-            # Make sure that the button was pressed before
-            if self._nTabXButtonStatus != FNB_BTN_PRESSED:
-                return 
+        return self._windows[sel]
 
-            self._nTabXButtonStatus = FNB_BTN_HOVER
 
-            self.DeletePage(self._iActivePage)
-            
+    def GetPage(self, page):
+        """ Returns the window at the given page position, or None. """
 
-    def HitTest(self, pt):
-        """
-        HitTest method for PageContainerBase.
-        Returns the flag (if any) and the hit page (if any).
-        """
+        if page >= len(self._windows):
+            return None
 
-        fullrect = self.GetClientRect()
-        btnLeftPos = self.GetLeftButtonPos()
-        btnRightPos = self.GetRightButtonPos()
-        btnXPos = self.GetXPos()
-        style = self.GetParent().GetWindowStyleFlag()
-        
-        tabIdx = -1
+        return self._windows[page]
 
-        if not self._pagesInfoVec:        
-            return FNB_NOWHERE, -1
-        
-        rect = wx.Rect(btnXPos, 6, 16, 16)
-        if rect.Contains(pt):
-            return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], -1
-        
-        rect = wx.Rect(btnRightPos, 6, 16, 16)
-        if rect.Contains(pt):
-            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], -1
-        
-        rect = wx.Rect(btnLeftPos, 6, 16, 16)
-        if rect.Contains(pt):
-            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], -1        
 
-        # Test whether a left click was made on a tab
-        for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
-        
-            pgInfo = self._pagesInfoVec[cur]
-        
-            if pgInfo.GetPosition() == wx.Point(-1, -1):
-                continue
-            
-            if style & FNB_X_ON_TAB and cur == self.GetSelection():
-                # 'x' button exists on a tab
-                if self._pagesInfoVec[cur].GetXRect().Contains(pt):                
-                    return FNB_TAB_X, cur
-                
-            tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y, pgInfo.GetSize().x, pgInfo.GetSize().y)
-            if tabRect.Contains(pt):
-                # We have a match
-                return FNB_TAB, cur
+    def GetPageIndex(self, win):
+        """ Returns the index at which the window is found. """
 
-        if self._isdragging:
-            # We are doing DND, so check also the region outside the tabs
-            
-            # try before the first tab
-            pgInfo = self._pagesInfoVec[0]
-            tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
-            if tabRect.Contains(pt):
-                return FNB_TAB, 0
+        try:
+            return self._windows.index(win)
+        except:
+            return -1
 
-            # try after the last tab
-            pgInfo = self._pagesInfoVec[-1]
-            startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
-            tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
-            
-            if tabRect.Contains(pt):
-                return FNB_TAB, len(self._pagesInfoVec)-1
 
-        # Default
-        return FNB_NOWHERE, -1
+    def GetSelection(self):
+        """ Returns the currently selected page, or -1 if none was selected. """
+        
+        return self._pages.GetSelection()
 
 
-    def SetSelection(self, page):
-        """ Sets the selected page. """
+    def AdvanceSelection(self, forward=True):
+        """
+        Cycles through the tabs.
+        The call to this function generates the page changing events.
+        """
 
-        book = self.GetParent()
-        book.SetSelection(page)
-        self.DoSetSelection(page)
+        self._pages.AdvanceSelection(forward)
 
 
-    def DoSetSelection(self, page):
-        """ Does the actual selection of a page. """
+    def GetPageCount(self):
+        """ Returns the number of pages in the L{FlatNotebook} control. """
 
-        # Make sure that the selection is visible
-        style = self.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_NAV_BUTTONS:        
-            # Incase that we dont have navigation buttons,
-            # there is no point of checking if the tab is visible
-            # Just do the refresh
-            self.Refresh()
-            return
-        
-        if page < len(self._pagesInfoVec):
-            #! fix for tabfocus
-            da_page = self._pParent.GetPage(page)
+        return self._pages.GetPageCount()
 
-            # THIS IS GIVING TROUBLES!!            
-            if da_page != None:
-                da_page.SetFocus()
-        
-        if not self.IsTabVisible(page):
-        
-            if page == len(self._pagesInfoVec) - 1:
-                # Incase the added tab is last,
-                # the function IsTabVisible() will always return False
-                # and thus will cause an evil behaviour that the new
-                # tab will hide all other tabs, we need to check if the
-                # new selected tab can fit to the current screen
-                if not self.CanFitToScreen(page):
-                    self._nFrom = page
-                            
-            else:
 
-                if not self.CanFitToScreen(page):
-                    # Redraw the tabs starting from page
-                    self._nFrom = page
-                    
-        self.Refresh()
+    def OnNavigationKey(self, event):
+        """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
 
+        if event.IsWindowChange():
+            if len(self._windows) == 0:
+                return
+            # change pages
+            if self.HasFlag(FNB_SMART_TABS):
+                if not self._popupWin:
+                    self._popupWin = TabNavigatorWindow(self)
+                    self._popupWin.SetReturnCode(wx.ID_OK)
+                    self._popupWin.ShowModal()
+                    self._popupWin.Destroy()
+                    self._popupWin = None
+                else:
+                    # a dialog is already opened
+                    self._popupWin.OnNavigationKey(event)
+                    return
+            else:
+                # change pages
+                self.AdvanceSelection(event.GetDirection())
+        else:
+            # pass to the parent
+            if self.GetParent():
+                event.SetCurrentFocus(self)
+                self.GetParent().ProcessEvent(event)
+            
 
-    def DeletePage(self, page):
-        """ Delete the specified page from FlatNotebook. """
+    def GetPageShapeAngle(self, page_index):
+        """ Returns the angle associated to a tab. """
 
-        book = self.GetParent()
-        book.DeletePage(page)
-        book.Refresh()
+        if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
+            return None, False
+        
+        result = self._pages._pagesInfoVec[page_index].GetTabAngle()
+        return result, True
 
 
-    def IsTabVisible(self, page):
-        """ Returns whether a tab is visible or not. """
+    def SetPageShapeAngle(self, page_index, angle):
+        """ Sets the angle associated to a tab. """
 
-        iLastVisiblePage = self.GetLastVisibleTab()
-        return page <= iLastVisiblePage and page >= self._nFrom
+        if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
+            return
 
+        if angle > 15:
+            return
 
-    def DoDeletePage(self, page):
-        """ Does the actual page deletion. """
+        self._pages._pagesInfoVec[page_index].SetTabAngle(angle)
 
-        # Remove the page from the vector
-        book = self.GetParent()
-        self._pagesInfoVec.pop(page)
 
-        # Thanks to Yiaanis AKA Mandrav
-        if self._iActivePage >= page:
-            self._iActivePage = self._iActivePage - 1
+    def SetAllPagesShapeAngle(self, angle):
+        """ Sets the angle associated to all the tab. """
 
-        # The delete page was the last first on the array,
-        # but the book still has more pages, so we set the
-        # active page to be the first one (0)
-        if self._iActivePage < 0 and self._pagesInfoVec:
-            self._iActivePage = 0
+        if angle > 15:
+            return
 
-        # Refresh the tabs
-        if self._iActivePage >= 0:
-        
-            book._bForceSelection = True
-            book.SetSelection(self._iActivePage)
-            book._bForceSelection = False
-        
-        if not self._pagesInfoVec:        
-            # Erase the page container drawings
-            dc = wx.ClientDC(self)
-            dc.Clear()
+        for ii in xrange(len(self._pages._pagesInfoVec)):
+            self._pages._pagesInfoVec[ii].SetTabAngle(angle)
         
+        self.Refresh()
 
-    def DeleteAllPages(self):
-        """ Deletes all the pages. """
 
-        self._iActivePage = -1
-        self._nFrom = 0
-        self._pagesInfoVec = []
+    def GetPageBestSize(self):
+        """ Return the page best size. """
 
-        # Erase the page container drawings
-        dc = wx.ClientDC(self)
-        dc.Clear()
+        return self._pages.GetClientSize()
 
 
-    def DrawTabX(self, dc, rect, tabIdx):
-        """ Draws the 'X' in the selected tab (VC8 style excluded). """
+    def SetPageText(self, page, text):
+        """ Sets the text for the given page. """
 
-        if not self.HasFlag(FNB_X_ON_TAB) or not self.CanDrawXOnTab():
-            return
+        bVal = self._pages.SetPageText(page, text)
+        self._pages.Refresh()
 
-        # We draw the 'x' on the active tab only
-        if tabIdx != self.GetSelection() or tabIdx < 0 or not self.CanFitToScreen(tabIdx):
-            return
+        return bVal
 
-        # Set the bitmap according to the button status
-        if self._nTabXButtonStatus == FNB_BTN_HOVER:        
-            xBmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
-        elif self._nTabXButtonStatus == FNB_BTN_PRESSED:
-            xBmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
-        else:
-            xBmp = wx.BitmapFromXPMData(x_button_xpm)
 
-        # Set the masking
-        xBmp.SetMask(wx.Mask(xBmp, MASK_COLOR))
+    def SetPadding(self, padding):
+        """
+        Sets the amount of space around each page's icon and label, in pixels.
+        NB: only the horizontal padding is considered.
+        """
 
-        # erase old button
-        dc.DrawBitmap(self._tabXBgBmp, rect.x, rect.y)
+        self._nPadding = padding.GetWidth()
 
-        # Draw the new bitmap
-        dc.DrawBitmap(xBmp, rect.x, rect.y, True)
 
-        # Update the vectpr
-        self._pagesInfoVec[tabIdx].SetXRect(rect)
+    def GetTabArea(self):
+        """ Returns the associated page. """
 
+        return self._pages
 
-    def DrawLeftArrow(self, dc):
-        """ Draw the left navigation arrow. """
 
-        style = self.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_NAV_BUTTONS:
-            return
+    def GetPadding(self):
+        """ Returns the amount of space around each page's icon and label, in pixels. """
+        
+        return self._nPadding 
 
-        # Make sure that there are pages in the container
-        if not self._pagesInfoVec:
-            return
 
-        # Set the bitmap according to the button status
-        if self._nLeftButtonStatus == FNB_BTN_HOVER:
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_hilite_xpm)
-        elif self._nLeftButtonStatus == FNB_BTN_PRESSED:
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_pressed_xpm)
-        else:
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_xpm)
+    def SetWindowStyleFlag(self, style):
+        """ Sets the L{FlatNotebook} window style flags. """
+            
+        wx.Panel.SetWindowStyleFlag(self, style)
+        renderer = self._pages._mgr.GetRenderer(self.GetWindowStyleFlag())
+        renderer._tabHeight = None
 
-        if self._nFrom == 0:
-            # Handle disabled arrow
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_disabled_xpm)
+        if self._pages:
         
-        arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
+            # For changing the tab position (i.e. placing them top/bottom)
+            # refreshing the tab container is not enough
+            self.SetSelection(self._pages._iActivePage)
 
-        # Erase old bitmap
-        posx = self.GetLeftButtonPos()
-        dc.DrawBitmap(self._leftBgBmp, posx, 6)
 
-        # Draw the new bitmap
-        dc.DrawBitmap(arrowBmp, posx, 6, True)
+    def RemovePage(self, page):
+        """ Deletes the specified page, without deleting the associated window. """
 
+        if page >= len(self._windows):
+            return False
 
-    def DrawRightArrow(self, dc):
-        """ Draw the right navigation arrow. """
+        # Fire a closing event
+        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
+        event.SetSelection(page)
+        event.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(event)
 
-        style = self.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_NAV_BUTTONS:
-            return
+        # The event handler allows it?
+        if not event.IsAllowed():
+            return False
 
-        # Make sure that there are pages in the container
-        if not self._pagesInfoVec:
-            return
+        self.Freeze()
 
-        # Set the bitmap according to the button status
-        if self._nRightButtonStatus == FNB_BTN_HOVER:        
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_hilite_xpm)
-        elif self._nRightButtonStatus == FNB_BTN_PRESSED:
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_pressed_xpm)
-        else:
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_xpm)
+        # Remove the requested page
+        pageRemoved = self._windows[page]
 
-        # Check if the right most tab is visible, if it is
-        # don't rotate right anymore
-        if self._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_disabled_xpm)
+        # If the page is the current window, remove it from the sizer
+        # as well
+        if page == self._pages.GetSelection():
+            self._mainSizer.Detach(pageRemoved)
         
-        arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
+        # Remove it from the array as well
+        self._windows.pop(page)
+        self.Thaw()
 
-        # erase old bitmap
-        posx = self.GetRightButtonPos()
-        dc.DrawBitmap(self._rightBgBmp, posx, 6)
+        self._pages.DoDeletePage(page)
 
-        # Draw the new bitmap
-        dc.DrawBitmap(arrowBmp, posx, 6, True)
+        return True
 
 
-    def DrawX(self, dc):
-        """ Draw the 'X' navigation button in the navigation area. """
+    def SetRightClickMenu(self, menu):
+        """ Sets the popup menu associated to a right click on a tab. """
 
-        # Check if this style is enabled
-        style = self.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_X_BUTTON:
-            return
+        self._pages._pRightClickMenu = menu
 
-        # Make sure that there are pages in the container
-        if not self._pagesInfoVec:
-            return
 
-        # Set the bitmap according to the button status
-        if self._nXButtonStatus == FNB_BTN_HOVER:
-            xbmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
-        elif self._nXButtonStatus == FNB_BTN_PRESSED:
-            xbmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
-        else:
-            xbmp = wx.BitmapFromXPMData(x_button_xpm)
+    def GetPageText(self, nPage):
+        """ Returns the tab caption. """
 
-        xbmp.SetMask(wx.Mask(xbmp, MASK_COLOR))
-        # erase old bitmap
+        return self._pages.GetPageText(nPage)
 
-        posx = self.GetXPos()        
-        dc.DrawBitmap(self._xBgBmp, posx, 6)
 
-        # Draw the new bitmap
-        dc.DrawBitmap(xbmp, posx, 6, True)
+    def SetGradientColours(self, fr, to, border):
+        """ Sets the gradient colours for the tab. """
 
+        self._pages._colorFrom = fr
+        self._pages._colorTo   = to
+        self._pages._colorBorder = border
 
-    def OnMouseMove(self, event):
-        """ Handles the wx.EVT_MOTION for PageContainerBase. """
 
-        if self._pagesInfoVec and self.IsShown():
-        
-            xButtonStatus = self._nXButtonStatus
-            xTabButtonStatus = self._nTabXButtonStatus
-            rightButtonStatus = self._nRightButtonStatus
-            leftButtonStatus = self._nLeftButtonStatus
-            style = self.GetParent().GetWindowStyleFlag()
+    def SetGradientColourFrom(self, fr):
+        """ Sets the starting colour for the gradient. """
 
-            self._nXButtonStatus = FNB_BTN_NONE
-            self._nRightButtonStatus = FNB_BTN_NONE
-            self._nLeftButtonStatus = FNB_BTN_NONE
-            self._nTabXButtonStatus = FNB_BTN_NONE
+        self._pages._colorFrom = fr
 
-            where, tabIdx = self.HitTest(event.GetPosition())
-            
-            if where == FNB_X:
-                if event.LeftIsDown():
-                
-                    self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-                
-                    self._nXButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_TAB_X:
-                if event.LeftIsDown():
-                
-                    self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
 
-                    self._nTabXButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_RIGHT_ARROW:
-                if event.LeftIsDown():
-                
-                    self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-                
-                    self._nRightButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_LEFT_ARROW:
-                if event.LeftIsDown():
-                
-                    self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-                
-                    self._nLeftButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_TAB:
-                # Call virtual method for showing tooltip
-                self.ShowTabTooltip(tabIdx)
-                
-                if not self.GetEnabled(tabIdx):                
-                    # Set the cursor to be 'No-entry'
-                    wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
-                
-                # Support for drag and drop
-                if event.LeftIsDown() and not (style & FNB_NODRAG):
+    def SetGradientColourTo(self, to):
+        """ Sets the ending colour for the gradient. """
 
-                    self._isdragging = True                
-                    draginfo = FNBDragInfo(self, tabIdx)
-                    drginfo = cPickle.dumps(draginfo)
-                    dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
-                    dataobject.SetData(drginfo)
-                    dragSource = wx.DropSource(self)
-                    dragSource.SetData(dataobject)
-                    dragSource.DoDragDrop(wx.Drag_DefaultMove)
-                    
-            bRedrawX = self._nXButtonStatus != xButtonStatus
-            bRedrawRight = self._nRightButtonStatus != rightButtonStatus
-            bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus
-            bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus
+        self._pages._colorTo = to
 
-            if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX):
-            
-                dc = wx.ClientDC(self)
-                if bRedrawX:
-                
-                    self.DrawX(dc)
-                
-                if bRedrawLeft:
-                
-                    self.DrawLeftArrow(dc)
-                
-                if bRedrawRight:
-                
-                    self.DrawRightArrow(dc)
-                
-                if bRedrawTabX:
-                
-                    self.DrawTabX(dc, self._pagesInfoVec[tabIdx].GetXRect(), tabIdx)
-                
-        event.Skip()
 
+    def SetGradientColourBorder(self, border):
+        """ Sets the tab border colour. """
 
-    def GetLastVisibleTab(self):
-        """ Returns the last visible tab. """
+        self._pages._colorBorder = border
 
-        ii = 0
-        
-        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
-        
-            if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
-                break
-        
-        return ii-1
 
+    def GetGradientColourFrom(self):
+        """ Gets first gradient colour. """
 
-    def GetNumTabsCanScrollLeft(self):
-        """ Returns the number of tabs than can be scrolled left. """
+        return self._pages._colorFrom
 
-        # Reserved area for the buttons (<>x)
-        rect = self.GetClientRect()
-        clientWidth = rect.width
-        posx = self._pParent._nPadding
-        numTabs = 0
-        pom = 0
-        
-        dc = wx.ClientDC(self)
 
-        # In case we have error prevent crash
-        if self._nFrom < 0:
-            return 0
+    def GetGradientColourTo(self):
+        """ Gets second gradient colour. """
 
-        style = self.GetParent().GetWindowStyleFlag()
-        
-        for ii in xrange(self._nFrom, -1, -1):
+        return self._pages._colorTo
 
-            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)        
-            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-            dc.SetFont(boldFont)
 
-            width, height = dc.GetTextExtent("Tp")
+    def GetGradientColourBorder(self):
+        """ Gets the tab border colour. """
 
-            tabHeight = height + FNB_HEIGHT_SPACER # We use 6 pixels as padding
-            if style & FNB_VC71:
-                tabHeight = (style & FNB_BOTTOM and [tabHeight - 4] or [tabHeight])[0]
-            elif style & FNB_FANCY_TABS:
-                tabHeight = (style & FNB_BOTTOM and [tabHeight - 3] or [tabHeight])[0]
+        return self._pages._colorBorder
 
-            width, pom = dc.GetTextExtent(self.GetPageText(ii))
-            if style != FNB_VC71:
-                shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[ii].GetTabAngle())/180.0*math.pi))
-            else:
-                shapePoints = 0
 
-            tabWidth = self._pParent._nPadding*2 + width
-            
-            if not (style & FNB_VC71):
-                # Default style
-                tabWidth += 2*shapePoints
+    def GetBorderColour(self):
+        """ Returns the border colour. """
 
-            hasImage = self._ImageList != None and self._pagesInfoVec[ii].GetImageIndex() != -1
+        return self._pages._colorBorder
+    
 
-            # For VC71 style, we only add the icon size (16 pixels)
-            if hasImage:
-            
-                if not self.IsDefaultTabs():
-                    tabWidth += 16 + self._pParent._nPadding
-                else:
-                    # Default style
-                    tabWidth += 16 + self._pParent._nPadding + shapePoints/2
-            
-            if posx + tabWidth + self.GetButtonsAreaLength() >= clientWidth:
-                break
+    def GetActiveTabTextColour(self):
+        """ Get the active tab text colour. """
 
-            numTabs = numTabs + 1
-            posx += tabWidth
-        
-        return numTabs
+        return self._pages._activeTextColor
 
 
-    def IsDefaultTabs(self):
-        """ Returns whether a tab has a default style. """
+    def SetPageImage(self, page, image):
+        """
+        Sets the image index for the given page. Image is an index into the
+        image list which was set with SetImageList.
+        """
 
-        style = self.GetParent().GetWindowStyleFlag()
-        res = (style & FNB_VC71) or (style & FNB_FANCY_TABS)
-        return not res
+        self._pages.SetPageImage(page, image)
 
 
-    def AdvanceSelection(self, bForward=True):
+    def GetPageImage(self, nPage):
         """
-        Cycles through the tabs.
-        The call to this function generates the page changing events.
+        Returns the image index for the given page. Image is an index into the
+        image list which was set with SetImageList.
         """
 
-        nSel = self.GetSelection()
+        return self._pages.GetPageImage(nPage)
 
-        if nSel < 0:
+
+    def GetEnabled(self, page):
+        """ Returns whether a tab is enabled or not. """
+
+        return self._pages.GetEnabled(page)
+
+
+    def Enable(self, page, enabled=True):
+        """ Enables or disables a tab. """
+
+        if page >= len(self._windows):
             return
 
-        nMax = self.GetPageCount() - 1
-        if bForward:
-            self.SetSelection((nSel == nMax and [0] or [nSel + 1])[0])
-        else:
-            self.SetSelection((nSel == 0 and [nMax] or [nSel - 1])[0])
+        self._windows[page].Enable(enabled)
+        self._pages.Enable(page, enabled)
 
 
-    def OnMouseLeave(self, event):
-        """ Handles the wx.EVT_LEAVE_WINDOW event for PageContainerBase. """
+    def GetNonActiveTabTextColour(self):
+        """ Returns the non active tabs text colour. """
 
-        self._nLeftButtonStatus = FNB_BTN_NONE
-        self._nXButtonStatus = FNB_BTN_NONE
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nTabXButtonStatus = FNB_BTN_NONE
+        return self._pages._nonActiveTextColor
 
-        dc = wx.ClientDC(self)
-        self.DrawX(dc)
-        self.DrawLeftArrow(dc)
-        self.DrawRightArrow(dc)
 
-        selection = self.GetSelection()
-        
-        if selection != -1:
-            self.DrawTabX(dc, self._pagesInfoVec[selection].GetXRect(), selection)
-            
-        event.Skip()
+    def SetNonActiveTabTextColour(self, color):
+        """ Sets the non active tabs text colour. """
 
+        self._pages._nonActiveTextColor = color
 
-    def OnMouseEnterWindow(self, event):
-        """ Handles the wx.EVT_ENTER_WINDOW event for PageContainerBase. """
 
-        self._nLeftButtonStatus = FNB_BTN_NONE
-        self._nXButtonStatus = FNB_BTN_NONE
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nLeftClickZone = FNB_BTN_NONE
+    def SetTabAreaColour(self, color):
+        """ Sets the area behind the tabs colour. """
 
-        event.Skip()
+        self._pages._tabAreaColor = color
+
+
+    def GetTabAreaColour(self):
+        """ Returns the area behind the tabs colour. """
 
+        return self._pages._tabAreaColor
 
-    def ShowTabTooltip(self, tabIdx):
-        """ Shows a tab tooltip. """
 
-        pWindow = self._pParent.GetPage(tabIdx)
-        
-        if pWindow:        
-            pToolTip = pWindow.GetToolTip()
-            if pToolTip and pToolTip.GetWindow() == pWindow:
-                self.SetToolTipString(pToolTip.GetTip())
-        
+    def SetActiveTabColour(self, color):
+        """ Sets the active tab colour. """
 
-    def FillGradientColor(self, dc, rect):
-        """ Gradient fill from colour 1 to colour 2 with top to bottom. """
+        self._pages._activeTabColor = color
 
-        if rect.height < 1 or rect.width < 1:
-            return
 
-        size = rect.height
+    def GetActiveTabColour(self):
+        """ Returns the active tab colour. """
 
-        # calculate gradient coefficients
-        style = self.GetParent().GetWindowStyleFlag()
-        col2 = ((style & FNB_BOTTOM) and [self._colorTo] or [self._colorFrom])[0]
-        col1 = ((style & FNB_BOTTOM) and [self._colorFrom] or [self._colorTo])[0]
+        return self._pages._activeTabColor
 
-        rf, gf, bf = 0, 0, 0
-        rstep = float(col2.Red() - col1.Red())/float(size)
-        gstep = float(col2.Green() - col1.Green())/float(size)
-        bstep = float(col2.Blue() - col1.Blue())/float(size)
 
-        for y in xrange(rect.y, rect.y + size):
-            currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)        
-            dc.SetBrush(wx.Brush(currCol))
-            dc.SetPen(wx.Pen(currCol))
-            dc.DrawLine(rect.x, y, rect.x + rect.width, y)
-            rf += rstep
-            gf += gstep
-            bf += bstep
-        
+# ---------------------------------------------------------------------------- #
+# Class PageContainer
+# Acts as a container for the pages you add to FlatNotebook
+# ---------------------------------------------------------------------------- #
 
-    def SetPageImageIndex(self, page, imgindex):
-        """ Sets the image index associated to a page. """
+class PageContainer(wx.Panel):
+    """
+    This class acts as a container for the pages you add to L{FlatNotebook}.
+    """
 
-        if page < len(self._pagesInfoVec):
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=0):
+        """ Default class constructor. """
         
-            self._pagesInfoVec[page].SetImageIndex(imgindex)
-            self.Refresh()
-
+        self._ImageList = None
+        self._iActivePage = -1
+        self._pDropTarget = None
+        self._nLeftClickZone = FNB_NOWHERE
+        self._iPreviousActivePage = -1
 
-    def GetPageImageIndex(self, page):
-        """ Returns the image index associated to a page. """
+        self._pRightClickMenu = None
+        self._nXButtonStatus = FNB_BTN_NONE
+        self._nArrowDownButtonStatus = FNB_BTN_NONE
+        self._pParent = parent
+        self._nRightButtonStatus = FNB_BTN_NONE
+        self._nLeftButtonStatus = FNB_BTN_NONE
+        self._nTabXButtonStatus = FNB_BTN_NONE
 
-        if page < len(self._pagesInfoVec):
-        
-            return self._pagesInfoVec[page].GetImageIndex()
-        
-        return -1
+        self._pagesInfoVec = []        
 
+        self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
+        self._colorFrom = wx.WHITE
+        self._activeTabColor = wx.WHITE
+        self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
+        self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
+        self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
 
-    def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
-        """ Handles the drop action from a DND operation. """
+        self._nFrom = 0
+        self._isdragging = False
 
-        # Disable drag'n'drop for disabled tab
-        if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled():
-            return wx.DragCancel
+        # Set default page height, this is done according to the system font
+        memDc = wx.MemoryDC()
+        memDc.SelectObject(wx.EmptyBitmap(1,1))
+    
+        if "__WXGTK__" in wx.PlatformInfo:
+            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+            boldFont.SetWeight(wx.BOLD)
+            memDc.SetFont(boldFont)
 
-        self._isdragging = True
-        oldContainer = wnd_oldContainer
-        nIndex = -1
+        height = memDc.GetCharHeight()
+        tabHeight = height + FNB_HEIGHT_SPACER # We use 10 pixels as padding
 
-        where, nIndex = self.HitTest(wx.Point(x, y))
+        wx.Panel.__init__(self, parent, id, pos, wx.Size(size.x, tabHeight),
+                          style|wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE)
 
-        oldNotebook = oldContainer.GetParent()
-        newNotebook = self.GetParent()
+        self._pDropTarget = FNBDropTarget(self)
+        self.SetDropTarget(self._pDropTarget)
+        self._mgr = FNBRendererMgr()
 
-        if oldNotebook == newNotebook:
-        
-            if nTabPage >= 0:
-            
-                if where == FNB_TAB:
-                    self.MoveTabPage(nTabPage, nIndex)
-        
-        else:
-        
-            if wx.Platform in ["__WXMSW__", "__WXGTK__"]:
-                if nTabPage >= 0:
-                
-                    window = oldNotebook.GetPage(nTabPage)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
+        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
+        self.Bind(wx.EVT_MOTION, self.OnMouseMove)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
+        self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
+        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
 
-                    if window:
-                        where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y))
-                        caption = oldContainer.GetPageText(nTabPage)
-                        imageindex = oldContainer.GetPageImageIndex(nTabPage)
-                        oldNotebook.RemovePage(nTabPage)
-                        window.Reparent(newNotebook)
 
-                        newNotebook.InsertPage(nIndex, window, caption, True, imageindex)
+    def OnEraseBackground(self, event):
+        """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
 
-        self._isdragging = False
-        
-        return wx.DragMove
+        pass
 
+    
+    def OnPaint(self, event):
+        """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
 
-    def MoveTabPage(self, nMove, nMoveTo):
-        """ Moves a tab inside the same FlatNotebook. """
+        dc = wx.BufferedPaintDC(self)
+        renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
+        renderer.DrawTabs(self, dc)
 
-        if nMove == nMoveTo:
-            return
 
-        elif nMoveTo < len(self._pParent._windows):
-            nMoveTo = nMoveTo + 1
+    def AddPage(self, caption, selected=True, imgindex=-1):
+        """
+        Add a page to the L{FlatNotebook}.
 
-        self._pParent.Freeze()
+        @param window: Specifies the new page.
+        @param caption: Specifies the text for the new page.
+        @param selected: Specifies whether the page should be selected.
+        @param imgindex: Specifies the optional image index for the new page.
         
-        # Remove the window from the main sizer
-        nCurSel = self._pParent._pages.GetSelection()
-        self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel])
-        self._pParent._windows[nCurSel].Hide()
+        Return value:
+        True if successful, False otherwise.
+        """
 
-        pWindow = self._pParent._windows[nMove]
-        self._pParent._windows.pop(nMove)
-        self._pParent._windows.insert(nMoveTo-1, pWindow)
+        if selected:
 
-        pgInfo = self._pagesInfoVec[nMove]
+            self._iPreviousActivePage = self._iActivePage        
+            self._iActivePage = len(self._pagesInfoVec)
+        
+        # Create page info and add it to the vector
+        pageInfo = PageInfo(caption, imgindex)
+        self._pagesInfoVec.append(pageInfo)
+        self.Refresh()
 
-        self._pagesInfoVec.pop(nMove)
-        self._pagesInfoVec.insert(nMoveTo - 1, pgInfo)
 
-        # Add the page according to the style
-        pSizer = self._pParent._mainSizer
-        style = self.GetParent().GetWindowStyleFlag()
+    def InsertPage(self, indx, text, selected=True, imgindex=-1):
+        """
+        Inserts a new page at the specified position.
 
-        if style & FNB_BOTTOM:
-        
-            pSizer.Insert(0, pWindow, 1, wx.EXPAND)
+        @param indx: Specifies the position of the new page.
+        @param page: Specifies the new page.
+        @param text: Specifies the text for the new page.
+        @param select: Specifies whether the page should be selected.
+        @param imgindex: Specifies the optional image index for the new page.
         
-        else:
+        Return value:
+        True if successful, False otherwise.
+        """     
+
+        if selected:
+
+            self._iPreviousActivePage = self._iActivePage        
+            self._iActivePage = len(self._pagesInfoVec)
         
-            # We leave a space of 1 pixel around the window
-            pSizer.Add(pWindow, 1, wx.EXPAND)
+        self._pagesInfoVec.insert(indx, PageInfo(text, imgindex))
         
-        pWindow.Show()
-
-        pSizer.Layout()
-        self._iActivePage = nMoveTo - 1
-        self.DoSetSelection(self._iActivePage)
         self.Refresh()
-        self._pParent.Thaw()
+        return True
 
 
-    def CanFitToScreen(self, page):
-        """ Returns whether all the tabs can fit in the available space. """
+    def OnSize(self, event):
+        """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
 
-        # Incase the from is greater than page,
-        # we need to reset the self._nFrom, so in order
-        # to force the caller to do so, we return False
-        if self._nFrom > page:
-            return False
+        # When resizing the control, try to fit to screen as many tabs as we can 
+        style = self.GetParent().GetWindowStyleFlag() 
+        renderer = self._mgr.GetRenderer(style)
+        
+        fr = 0
+        page = self.GetSelection()
+        
+        for fr in xrange(self._nFrom):
+            vTabInfo = renderer.NumberTabsCanFit(self, fr)
+            if page - fr >= len(vTabInfo):
+                continue
+            break
 
-        # Calculate the tab width including borders and image if any
-        dc = wx.ClientDC(self)
+        self._nFrom = fr
 
-        style = self.GetParent().GetWindowStyleFlag()
+        self.Refresh() # Call on paint
+        event.Skip()
 
-        width, height = dc.GetTextExtent("Tp")
-        width, pom = dc.GetTextExtent(self.GetPageText(page))
 
-        tabHeight = height + FNB_HEIGHT_SPACER # We use 6 pixels as padding
+    def OnMiddleDown(self, event):
+        """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
 
-        if style & FNB_VC71:
-            tabHeight = (style & FNB_BOTTOM and [tabHeight - 4] or [tabHeight])[0]
-        elif style & FNB_FANCY_TABS:
-            tabHeight = (style & FNB_BOTTOM and [tabHeight - 2] or [tabHeight])[0]
+        # Test if this style is enabled
+        style = self.GetParent().GetWindowStyleFlag()
+        
+        if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS:
+            return
 
-        tabWidth = self._pParent._nPadding * 2 + width
+        where, tabIdx = self.HitTest(event.GetPosition())
         
-        if not style & FNB_VC71:
-            shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[page].GetTabAngle())/180.0*math.pi))
-        else:
-            shapePoints = 0
+        if where == FNB_TAB:
+            self.DeletePage(tabIdx)
+        
+        event.Skip()
 
-        if not style & FNB_VC71:
-            # Default style
-            tabWidth += 2*shapePoints
 
-        hasImage = self._ImageList != None
+    def OnRightDown(self, event):
+        """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
         
-        if hasImage:
-            hasImage &= self._pagesInfoVec[page].GetImageIndex() != -1
+        where, tabIdx = self.HitTest(event.GetPosition())
 
-        # For VC71 style, we only add the icon size (16 pixels)
-        if hasImage and (style & FNB_VC71 or style & FNB_FANCY_TABS):
-            tabWidth += 16
-        else:
-            # Default style
-            tabWidth += 16 + shapePoints/2
+        if where in [FNB_TAB, FNB_TAB_X]:
 
-        # Check if we can draw more
-        posx = self._pParent._nPadding
+            if self._pagesInfoVec[tabIdx].GetEnabled():
+                # Fire events and eventually (if allowed) change selection
+                self.FireEvent(tabIdx)
 
-        if self._nFrom >= 0:
-            for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
-                if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
-                    break
-                posx += self._pagesInfoVec[ii].GetSize().x
+                # send a message to popup a custom menu
+                event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId())
+                event.SetSelection(tabIdx)
+                event.SetOldSelection(self._iActivePage)
+                event.SetEventObject(self.GetParent())
+                self.GetParent().GetEventHandler().ProcessEvent(event)
+
+                if self._pRightClickMenu:
+                    self.PopupMenu(self._pRightClickMenu)
             
-        rect = self.GetClientRect()
-        clientWidth = rect.width
+        event.Skip()
 
-        if posx + tabWidth + self.GetButtonsAreaLength() >= clientWidth:
-            return False
 
-        return True
+    def OnLeftDown(self, event):
+        """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
 
+        # Reset buttons status
+        self._nXButtonStatus     = FNB_BTN_NONE
+        self._nLeftButtonStatus  = FNB_BTN_NONE
+        self._nRightButtonStatus = FNB_BTN_NONE
+        self._nTabXButtonStatus  = FNB_BTN_NONE
+        self._nArrowDownButtonStatus = FNB_BTN_NONE
 
-    def GetNumOfVisibleTabs(self):
-        """ Returns the number of visible tabs. """
+        self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition())
 
-        count = 0
-        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
-            if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
-                break
-            count = count + 1
+        if self._nLeftClickZone == FNB_DROP_DOWN_ARROW:
+            self._nArrowDownButtonStatus = FNB_BTN_PRESSED
+            self.Refresh()
+        elif self._nLeftClickZone == FNB_LEFT_ARROW:
+            self._nLeftButtonStatus = FNB_BTN_PRESSED
+            self.Refresh()
+        elif self._nLeftClickZone == FNB_RIGHT_ARROW:
+            self._nRightButtonStatus = FNB_BTN_PRESSED
+            self.Refresh()
+        elif self._nLeftClickZone == FNB_X:
+            self._nXButtonStatus = FNB_BTN_PRESSED
+            self.Refresh()
+        elif self._nLeftClickZone == FNB_TAB_X:
+            self._nTabXButtonStatus = FNB_BTN_PRESSED
+            self.Refresh()
 
-        return count
+        elif self._nLeftClickZone == FNB_TAB:
+            
+            if self._iActivePage != tabIdx:
+                
+                # In case the tab is disabled, we dont allow to choose it
+                if self._pagesInfoVec[tabIdx].GetEnabled():
+                    self.FireEvent(tabIdx)
 
 
-    def GetEnabled(self, page):
-        """ Returns whether a tab is enabled or not. """
+    def OnLeftUp(self, event):
+        """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
+
+        # forget the zone that was initially clicked
+        self._nLeftClickZone = FNB_NOWHERE
 
-        if page >= len(self._pagesInfoVec):
-            return True # Seems strange, but this is the default
+        where, tabIdx = self.HitTest(event.GetPosition())
         
-        return self._pagesInfoVec[page].GetEnabled()
+        if where == FNB_LEFT_ARROW:
+            
+            if self._nFrom == 0:
+                return
 
+            # Make sure that the button was pressed before
+            if self._nLeftButtonStatus != FNB_BTN_PRESSED:
+                return
 
-    def Enable(self, page, enabled=True):
-        """ Enables or disables a tab. """
+            self._nLeftButtonStatus = FNB_BTN_HOVER
 
-        if page >= len(self._pagesInfoVec):
-            return
-        
-        self._pagesInfoVec[page].Enable(enabled)
-        
+            # We scroll left with bulks of 5
+            scrollLeft = self.GetNumTabsCanScrollLeft()
 
-    def GetLeftButtonPos(self):
-        """ Returns the left button position in the navigation area. """
+            self._nFrom -= scrollLeft
+            if self._nFrom < 0:
+                self._nFrom = 0
 
-        style = self.GetParent().GetWindowStyleFlag()
-        rect = self.GetClientRect()
-        clientWidth = rect.width
-        
-        if style & FNB_NO_X_BUTTON:
-            return clientWidth - 38
-        else:
-            return clientWidth - 54
+            self.Refresh()
+            
+        elif where == FNB_RIGHT_ARROW:
+            
+            if self._nFrom >= len(self._pagesInfoVec) - 1:
+                return
 
+            # Make sure that the button was pressed before
+            if self._nRightButtonStatus != FNB_BTN_PRESSED:
+                return
 
-    def GetRightButtonPos(self):
-        """ Returns the right button position in the navigation area. """
+            self._nRightButtonStatus = FNB_BTN_HOVER
 
-        style = self.GetParent().GetWindowStyleFlag()
-        rect = self.GetClientRect()
-        clientWidth = rect.width
-        
-        if style & FNB_NO_X_BUTTON:
-            return clientWidth - 22
-        else:
-            return clientWidth - 38
+            # Check if the right most tab is visible, if it is
+            # don't rotate right anymore
+            if self._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
+                return
 
+            lastVisibleTab = self.GetLastVisibleTab()
+            if lastVisibleTab < 0:
+                # Probably the screen is too small for displaying even a single
+                # tab, in this case we do nothing
+                return
 
-    def GetXPos(self):
-        """ Returns the 'X' button position in the navigation area. """
+            self._nFrom += self.GetNumOfVisibleTabs()
+            self.Refresh()
+            
+        elif where == FNB_X:
+            
+            # Make sure that the button was pressed before
+            if self._nXButtonStatus != FNB_BTN_PRESSED:
+                return
 
-        style = self.GetParent().GetWindowStyleFlag()
-        rect = self.GetClientRect()
-        clientWidth = rect.width
-        
-        if style & FNB_NO_X_BUTTON:
-            return clientWidth
-        else:
-            return clientWidth - 22
+            self._nXButtonStatus = FNB_BTN_HOVER
 
+            self.DeletePage(self._iActivePage)
+            
+        elif where == FNB_TAB_X:
+            
+            # Make sure that the button was pressed before
+            if self._nTabXButtonStatus != FNB_BTN_PRESSED:
+                return 
 
-    def GetButtonsAreaLength(self):
-        """ Returns the navigation area width. """
+            self._nTabXButtonStatus = FNB_BTN_HOVER
 
-        style = self.GetParent().GetWindowStyleFlag()
-        
-        if style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON:
-            return 0
-        elif style & FNB_NO_NAV_BUTTONS and not style & FNB_NO_X_BUTTON:
-            return 53 - 16
-        elif not style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON:
-            return 53 - 16
-        else:
-            # All buttons
-            return 53
+            self.DeletePage(self._iActivePage)
 
+        elif where == FNB_DROP_DOWN_ARROW:
 
-    def GetSingleLineBorderColor(self):
+            # Make sure that the button was pressed before
+            if self._nArrowDownButtonStatus != FNB_BTN_PRESSED:
+                return
 
-        if self.HasFlag(FNB_FANCY_TABS):
-            return self._colorFrom
-        
-        return wx.WHITE
+            self._nArrowDownButtonStatus = FNB_BTN_NONE
 
+            # Refresh the button status
+            renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
+            dc = wx.ClientDC(self)
+            renderer.DrawDropDownArrow(self, dc)
 
-    def DrawTabsLine(self, dc):
-        """ Draws a line over the tabs. """
+            self.PopupTabsMenu()
 
-        clntRect = self.GetClientRect()
-        clientRect3 = wx.Rect(0, 0, clntRect.width, clntRect.height)
 
-        if self.HasFlag(FNB_BOTTOM):
-        
-            clientRect = wx.Rect(0, 2, clntRect.width, clntRect.height - 2)
-            clientRect2 = wx.Rect(0, 1, clntRect.width, clntRect.height - 1)
-        
-        else:
-        
-            clientRect = wx.Rect(0, 0, clntRect.width, clntRect.height - 2)
-            clientRect2 = wx.Rect(0, 0, clntRect.width, clntRect.height - 1)
-        
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        dc.SetPen(wx.Pen(self.GetSingleLineBorderColor()))
-        dc.DrawRectangleRect(clientRect2)
-        dc.DrawRectangleRect(clientRect3)
+    def HitTest(self, pt):
+        """
+        HitTest method for L{PageContainer}.
+        Returns the flag (if any) and the hit page (if any).
+        """
 
-        dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
-        dc.DrawRectangleRect(clientRect)
+        style = self.GetParent().GetWindowStyleFlag()
+        render = self._mgr.GetRenderer(style)
 
-        if not self.HasFlag(FNB_TABS_BORDER_SIMPLE):
+        fullrect = self.GetClientRect()
+        btnLeftPos = render.GetLeftButtonPos(self)
+        btnRightPos = render.GetRightButtonPos(self)
+        btnXPos = render.GetXPos(self)
         
-            dc.SetPen(wx.Pen((self.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [self._tabAreaColor])[0]))
-            dc.DrawLine(0, 0, 0, clientRect.height+1)
-            
-            if self.HasFlag(FNB_BOTTOM):
-            
-                dc.DrawLine(0, clientRect.height+1, clientRect.width, clientRect.height+1)
-            
-            else:
-                dc.DrawLine(0, 0, clientRect.width, 0)
-                
-            dc.DrawLine(clientRect.width - 1, 0, clientRect.width - 1, clientRect.height+1)
+        tabIdx = -1
         
+        if len(self._pagesInfoVec) == 0:
+            return FNB_NOWHERE, tabIdx
 
-    def HasFlag(self, flag):
-        """ Returns whether a flag is present in the FlatNotebook style. """
+        rect = wx.Rect(btnXPos, 8, 16, 16)
+        if rect.Contains(pt):
+            return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], tabIdx
 
-        style = self.GetParent().GetWindowStyleFlag()
-        res = (style & flag and [True] or [False])[0]
-        return res
+        rect = wx.Rect(btnRightPos, 8, 16, 16)
+        if style & FNB_DROPDOWN_TABS_LIST:
+            rect = wx.Rect(render.GetDropArrowButtonPos(self), 8, 16, 16)
+            if rect.Contains(pt):
+                return FNB_DROP_DOWN_ARROW, tabIdx
 
+        if rect.Contains(pt):
+            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], tabIdx
 
-    def ClearFlag(self, flag):
-        """ Deletes a flag from the FlatNotebook style. """
+        rect = wx.Rect(btnLeftPos, 8, 16, 16)
+        if rect.Contains(pt):
+            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], tabIdx
 
-        style = self.GetParent().GetWindowStyleFlag()
-        style &= ~flag 
-        self.SetWindowStyleFlag(style)
+        # Test whether a left click was made on a tab
+        bFoundMatch = False
+        
+        for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
 
+            pgInfo = self._pagesInfoVec[cur]
 
-    def TabHasImage(self, tabIdx):
-        """ Returns whether a tab has an associated image index or not. """
+            if pgInfo.GetPosition() == wx.Point(-1, -1):
+                continue
 
-        if self._ImageList:
-            return self._pagesInfoVec[tabIdx].GetImageIndex() != -1
-        
-        return False
+            if style & FNB_X_ON_TAB and cur == self.GetSelection():
+                # 'x' button exists on a tab
+                if self._pagesInfoVec[cur].GetXRect().Contains(pt):
+                    return FNB_TAB_X, cur
+                    
+            if style & FNB_VC8:
 
+                if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y):
+                    if bFoundMatch or cur == self.GetSelection():    
+                        return FNB_TAB, cur
 
-    def OnLeftDClick(self, event):
-        """ Handles the wx.EVT_LEFT_DCLICK event for PageContainerBase. """
+                    tabIdx = cur
+                    bFoundMatch = True
+                    
+            else:
 
-        if self.HasFlag(FNB_DCLICK_CLOSES_TABS):
-        
-            where, tabIdx = self.HitTest(event.GetPosition())
-            
-            if where == FNB_TAB:
-                self.DeletePage(tabIdx)
-        
-        else:
-        
-            event.Skip()
-        
+                tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y,
+                                  pgInfo.GetSize().x, pgInfo.GetSize().y)
+                
+                if tabRect.Contains(pt):
+                    # We have a match
+                    return FNB_TAB, cur
 
-    def SetImageList(self, imglist):
-        """ Sets the image list for the page control. """
+        if bFoundMatch:
+            return FNB_TAB, tabIdx
 
-        self._ImageList = imglist
+        if self._isdragging:
+            # We are doing DND, so check also the region outside the tabs
+            # try before the first tab
+            pgInfo = self._pagesInfoVec[0]
+            tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
+            if tabRect.Contains(pt):
+                return FNB_TAB, 0
 
+            # try after the last tab
+            pgInfo = self._pagesInfoVec[-1]
+            startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
+            tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
 
-    def GetImageList(self):
-        """ Returns the image list for the page control. """
+            if tabRect.Contains(pt):
+                return FNB_TAB, len(self._pagesInfoVec)        
 
-        return self._ImageList
+        # Default
+        return FNB_NOWHERE, -1
 
 
-    def GetSelection(self):
-        """ Returns the current selected page. """
+    def SetSelection(self, page):
+        """ Sets the selected page. """
 
-        return self._iActivePage 
+        book = self.GetParent()
+        book.SetSelection(page)
+        self.DoSetSelection(page)
 
 
-    def GetPageCount(self):
-        """ Returns the number of tabs in the FlatNotebook control. """
+    def DoSetSelection(self, page):
+        """ Does the actual selection of a page. """
 
-        return len(self._pagesInfoVec)
+        if page < len(self._pagesInfoVec):
+            #! fix for tabfocus
+            da_page = self._pParent.GetPage(page)
+    
+            if da_page != None:
+                da_page.SetFocus()
+        
+        if not self.IsTabVisible(page):
+            # Try to remove one tab from start and try again
+            
+            if not self.CanFitToScreen(page):
 
+                if self._nFrom > page:
+                    self._nFrom = page
+                else:
+                    while self._nFrom < page:
+                        self._nFrom += 1
+                        if self.CanFitToScreen(page):
+                            break
+        self.Refresh()
 
-    def GetPageText(self, page):
-        """ Returns the tab caption of the page. """
 
-        return self._pagesInfoVec[page].GetCaption() 
+    def DeletePage(self, page):
+        """ Delete the specified page from L{FlatNotebook}. """
 
+        book = self.GetParent()
+        book.DeletePage(page)
+        book.Refresh()
 
-    def SetPageText(self, page, text):
-        """ Sets the tab caption of the page. """
 
-        self._pagesInfoVec[page].SetCaption(text)
-        return True 
+    def IsTabVisible(self, page):
+        """ Returns whether a tab is visible or not. """
 
+        iLastVisiblePage = self.GetLastVisibleTab()
+        return page <= iLastVisiblePage and page >= self._nFrom
 
-    def CanDrawXOnTab(self):
-        """ Returns whether an 'X' can be drawn on a tab (all styles except VC8. """
-        
-        return True
 
+    def DoDeletePage(self, page):
+        """ Does the actual page deletion. """
+
+        # Remove the page from the vector
+        book = self.GetParent()
+        self._pagesInfoVec.pop(page)
+
+        # Thanks to Yiaanis AKA Mandrav
+        if self._iActivePage >= page:
+            self._iActivePage = self._iActivePage - 1
+            self._iPreviousActivePage = -1
 
-# ---------------------------------------------------------------------------- #
-# Class FlatNotebook
-# Simple super class based on PageContainerBase
-# ---------------------------------------------------------------------------- #
+        # The delete page was the last first on the array,
+        # but the book still has more pages, so we set the
+        # active page to be the first one (0)
+        if self._iActivePage < 0 and len(self._pagesInfoVec) > 0:
+            self._iActivePage = 0
+            self._iPreviousActivePage = -1
 
-class FlatNotebook(FlatNotebookBase):
+        # Refresh the tabs
+        if self._iActivePage >= 0:
+        
+            book._bForceSelection = True
 
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=0, name="FlatNotebook"):
-        """
-        Default class constructor.
+            # Check for selection and send event
+            event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
+            event.SetSelection(self._iActivePage)
+            event.SetOldSelection(self._iPreviousActivePage)
+            event.SetEventObject(self.GetParent())
 
-        It is better to use directly the StyledNotebook class (see below) and then
-        assigning the style you wish instead of calling FlatNotebook.
-        """
+            book.SetSelection(self._iActivePage)
+            book._bForceSelection = False
 
-        style |= wx.TAB_TRAVERSAL
+            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
+            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
+            event.SetOldSelection(self._iPreviousActivePage)
+            self.GetParent().GetEventHandler().ProcessEvent(event)            
+        
+        if not self._pagesInfoVec:        
+            # Erase the page container drawings
+            dc = wx.ClientDC(self)
+            dc.Clear()
         
-        FlatNotebookBase.__init__(self, parent, id, pos, size, style, name)
-        self._pages = self.CreatePageContainer()
-
 
-    def CreatePageContainer(self):
-        """ Creates the page container. """
+    def DeleteAllPages(self):
+        """ Deletes all the pages. """
 
-        return FlatNotebookBase.CreatePageContainer(self)
+        self._iActivePage = -1
+        self._iPreviousActivePage = -1
+        self._nFrom = 0
+        self._pagesInfoVec = []
 
+        # Erase the page container drawings
+        dc = wx.ClientDC(self)
+        dc.Clear()
 
-#--------------------------------------------------------------------
-# StyledNotebook - a notebook with look n feel of Visual Studio 2005
-#--------------------------------------------------------------------
 
-class StyledNotebook(FlatNotebookBase):
+    def OnMouseMove(self, event):
+        """ Handles the wx.EVT_MOTION for L{PageContainer}. """
 
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=0, name="StyledNotebook"):
-        """ Default class constructor.
+        if self._pagesInfoVec and self.IsShown():
         
-        It is better to use directly the StyledNotebook class and then
-        assigning the style you wish instead of calling FlatNotebook.
-        """
+            xButtonStatus = self._nXButtonStatus
+            xTabButtonStatus = self._nTabXButtonStatus
+            rightButtonStatus = self._nRightButtonStatus
+            leftButtonStatus = self._nLeftButtonStatus
+            dropDownButtonStatus = self._nArrowDownButtonStatus
+            
+            style = self.GetParent().GetWindowStyleFlag()
 
-        style |= wx.TAB_TRAVERSAL
-        
-        FlatNotebookBase.__init__(self, parent, id, pos, size, style, name)
-        
-        # Custom initialization of the tab area
-        if style & FNB_VC8:
-            # Initialise the default style colors
-            self.SetNonActiveTabTextColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT))
+            self._nXButtonStatus = FNB_BTN_NONE
+            self._nRightButtonStatus = FNB_BTN_NONE
+            self._nLeftButtonStatus = FNB_BTN_NONE
+            self._nTabXButtonStatus = FNB_BTN_NONE
+            self._nArrowDownButtonStatus = FNB_BTN_NONE
 
+            where, tabIdx = self.HitTest(event.GetPosition())
+            
+            if where == FNB_X:
+                if event.LeftIsDown():
+                
+                    self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
+                
+                else:
+                
+                    self._nXButtonStatus = FNB_BTN_HOVER
 
-    def CreatePageContainer(self):
-        """ Creates the page container. """
+            elif where == FNB_DROP_DOWN_ARROW:
+                if event.LeftIsDown():
 
-        return StyledTabsContainer(self, wx.ID_ANY)
+                    self._nArrowDownButtonStatus = (self._nLeftClickZone==FNB_DROP_DOWN_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
 
+                else:
 
-# ---------------------------------------------------------------------------- #
-# Class StyledTabsContainer
-# Acts as a container for the pages you add to FlatNotebook
-# A more generic and more powerful implementation of PageContainerBase, can
-# handle also VC8 tabs style
-# ---------------------------------------------------------------------------- #
+                    self._nArrowDownButtonStatus = FNB_BTN_HOVER
 
-class StyledTabsContainer(PageContainerBase):
+            elif where == FNB_TAB_X:
+                if event.LeftIsDown():
+                
+                    self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
+                
+                else:
 
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=0):
-        """ Default class constructor. """        
+                    self._nTabXButtonStatus = FNB_BTN_HOVER
+                
+            elif where == FNB_RIGHT_ARROW:
+                if event.LeftIsDown():
+                
+                    self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
+                
+                else:
+                
+                    self._nRightButtonStatus = FNB_BTN_HOVER
+                
+            elif where == FNB_LEFT_ARROW:
+                if event.LeftIsDown():
+                
+                    self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
+                
+                else:
+                
+                    self._nLeftButtonStatus = FNB_BTN_HOVER
+                
+            elif where == FNB_TAB:
+                # Call virtual method for showing tooltip
+                self.ShowTabTooltip(tabIdx)
+                
+                if not self.GetEnabled(tabIdx):                
+                    # Set the cursor to be 'No-entry'
+                    wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
+                
+                # Support for drag and drop
+                if event.Dragging() and not (style & FNB_NODRAG):
 
-        self._factor = 1
+                    self._isdragging = True                
+                    draginfo = FNBDragInfo(self, tabIdx)
+                    drginfo = cPickle.dumps(draginfo)
+                    dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
+                    dataobject.SetData(drginfo)
+                    dragSource = FNBDropSource(self)
+                    dragSource.SetData(dataobject)
+                    dragSource.DoDragDrop(wx.Drag_DefaultMove)
+                    
+            bRedrawX = self._nXButtonStatus != xButtonStatus
+            bRedrawRight = self._nRightButtonStatus != rightButtonStatus
+            bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus
+            bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus
+            bRedrawDropArrow = self._nArrowDownButtonStatus != dropDownButtonStatus
 
-        self._colorTo = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 0) 
-        self._colorFrom = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 60)
+            render = self._mgr.GetRenderer(style)
         
-        PageContainerBase.__init__(self, parent, id, pos, size, style) 
+            if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX or bRedrawDropArrow):
 
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
+                dc = wx.ClientDC(self)
+                
+                if bRedrawX:
+                
+                    render.DrawX(self, dc)
+                
+                if bRedrawLeft:
+                
+                    render.DrawLeftArrow(self, dc)
+                
+                if bRedrawRight:
+                
+                    render.DrawRightArrow(self, dc)
+                
+                if bRedrawTabX:
+                
+                    render.DrawTabX(self, dc, self._pagesInfoVec[tabIdx].GetXRect(), tabIdx, self._nTabXButtonStatus)
 
-        
-    def NumberTabsCanFit(self, dc):
-        """ Returns the number of tabs that can fit inside the available space. """
+                if bRedrawDropArrow:
 
-        rect = self.GetClientRect()
-        clientWidth = rect.width
+                    render.DrawDropDownArrow(self, dc)
 
-        # Empty results
-        vTabInfo = []
+        event.Skip()
 
-        # We take the maxmimum font size, this is 
-        # achieved by setting the font to be bold
-        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        font.SetWeight(wx.FONTWEIGHT_BOLD)
-        dc.SetFont(font)
 
-        width, height = dc.GetTextExtent("Tp")
+    def GetLastVisibleTab(self):
+        """ Returns the last visible tab. """
 
-        tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels
-        # The drawing starts from posx
-        posx = self._pParent.GetPadding()
+        if self._nFrom < 0:
+            return -1
+
+        ii = 0
         
-        for i in xrange(self._nFrom, len(self._pagesInfoVec)):
+        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
         
-            width, pom = dc.GetTextExtent(self.GetPageText(i))
-            
-            # Set a minimum size to a tab
-            if width < 20:
-                width = 20
-
-            tabWidth = self._pParent.GetPadding() * 2 + width
-            
-            # Add the image width if it exist
-            if self.TabHasImage(i):
-                tabWidth += 16 + self._pParent.GetPadding()
-
-            vc8glitch = tabHeight + FNB_HEIGHT_SPACER
-            if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength() >= clientWidth:
+            if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
                 break
-
-            # Add a result to the returned vector
-            tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth , tabHeight)
-            vTabInfo.append(tabRect)
-
-            # Advance posx
-            posx += tabWidth + FNB_HEIGHT_SPACER
         
-        return vTabInfo
-    
+        return ii-1
+
 
     def GetNumTabsCanScrollLeft(self):
         """ Returns the number of tabs than can be scrolled left. """
@@ -3344,725 +4166,481 @@ class StyledTabsContainer(PageContainerBase):
         # Reserved area for the buttons (<>x)
         rect = self.GetClientRect()
         clientWidth = rect.width
-        posx = self._pParent.GetPadding()
+        posx = self._pParent._nPadding
         numTabs = 0
         pom = 0
-
-        dc = wx.ClientDC(self)
-
-        # Incase we have error prevent crash
+        
+        # In case we have error prevent crash
         if self._nFrom < 0:
             return 0
 
+        dc = wx.ClientDC(self)
+
         style = self.GetParent().GetWindowStyleFlag()
+        render = self._mgr.GetRenderer(style)
         
-        for i in xrange(self._nFrom, -1, -1):
-        
-            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        for ii in xrange(self._nFrom, -1, -1):
+
+            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)        
             boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
             dc.SetFont(boldFont)
 
-            width, height = dc.GetTextExtent("Tp")
+            height = dc.GetCharHeight()
 
             tabHeight = height + FNB_HEIGHT_SPACER # We use 6 pixels as padding
-            
             if style & FNB_VC71:
-                tabHeight = (self.HasFlag(FNB_BOTTOM) and [tabHeight - 4] or [tabHeight])[0]
+                tabHeight = (style & FNB_BOTTOM and [tabHeight - 4] or [tabHeight])[0]
             elif style & FNB_FANCY_TABS:
-                tabHeight = (self.HasFlag(FNB_BOTTOM) and [tabHeight - 3] or [tabHeight])[0]
+                tabHeight = (style & FNB_BOTTOM and [tabHeight - 3] or [tabHeight])[0]
 
-            width, pom = dc.GetTextExtent(self.GetPageText(i))
-            
+            width, pom = dc.GetTextExtent(self.GetPageText(ii))
             if style != FNB_VC71:
-                shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[i].GetTabAngle())/180.0*math.pi))
+                shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[ii].GetTabAngle())/180.0*math.pi))
             else:
                 shapePoints = 0
 
-            tabWidth = self._pParent.GetPadding() * 2 + width
-            if not style & FNB_VC71:
+            tabWidth = 2*self._pParent._nPadding + width
+            
+            if not (style & FNB_VC71):
                 # Default style
                 tabWidth += 2*shapePoints
 
+            hasImage = self._ImageList != None and self._pagesInfoVec[ii].GetImageIndex() != -1
+
             # For VC71 style, we only add the icon size (16 pixels)
-            if self.TabHasImage(i):
+            if hasImage:
             
                 if not self.IsDefaultTabs():
-                    tabWidth += 16 + self._pParent.GetPadding()
+                    tabWidth += 16 + self._pParent._nPadding
                 else:
                     # Default style
-                    tabWidth += 16 + self._pParent.GetPadding() + shapePoints/2
-            
-            vc8glitch = (style & FNB_VC8 and [tabHeight + FNB_HEIGHT_SPACER] or [0])[0]
+                    tabWidth += 16 + self._pParent._nPadding + shapePoints/2
             
-            if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength() >= clientWidth:
+            if posx + tabWidth + render.GetButtonsAreaLength(self) >= clientWidth:
                 break
 
             numTabs = numTabs + 1
-            posx += tabWidth
-
-        return numTabs
-
-
-    def CanDrawXOnTab(self):
-        """ Returns whether an 'X' button can be drawn on a tab (not VC8 style). """
-
-        style = self.GetParent().GetWindowStyleFlag()
-        isVC8 = (style & FNB_VC8 and [True] or [False])[0]
-        return not isVC8
-
-
-    def IsDefaultTabs(self):
-        """ Returns whether a tab has a default style or not. """
-
-        style = self.GetParent().GetWindowStyleFlag()
-        res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8)
-        return not res
-
-
-    def HitTest(self, pt):
-        """ HitTest specific method for VC8 style. """
-
-        fullrect = self.GetClientRect()
-        btnLeftPos = self.GetLeftButtonPos()
-        btnRightPos = self.GetRightButtonPos()
-        btnXPos = self.GetXPos()
-        style = self.GetParent().GetWindowStyleFlag()
-        tabIdx = -1
-
-        if not self._pagesInfoVec:        
-            return FNB_NOWHERE, -1
-        
-        rect = wx.Rect(btnXPos, 8, 16, 16)
-        
-        if rect.Contains(pt):
-            return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], -1
-
-        rect = wx.Rect(btnRightPos, 8, 16, 16)
-        
-        if rect.Contains(pt):        
-            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], -1
-        
-        rect = wx.Rect(btnLeftPos, 8, 16, 16)
-        
-        if rect.Contains(pt):
-            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], -1
-        
-        # Test whether a left click was made on a tab
-        bFoundMatch = False
-        
-        for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
-        
-            pgInfo = self._pagesInfoVec[cur]
-
-            if pgInfo.GetPosition() == wx.Point(-1, -1):
-                continue
-            
-            if style & FNB_VC8:
-            
-                if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y):
-                
-                    if bFoundMatch or cur == self.GetSelection():
-
-                        return FNB_TAB, cur
-                    
-                    tabIdx = cur
-                    bFoundMatch = True
-                
-            else:
-            
-                if style & FNB_X_ON_TAB and cur == self.GetSelection():
-                
-                    # 'x' button exists on a tab
-                    if self._pagesInfoVec[cur].GetXRect().Contains(pt):                    
-                        return FNB_TAB_X, cur
-                    
-                tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y, pgInfo.GetSize().x, pgInfo.GetSize().y)
-                
-                if tabRect.Contains(pt):                
-                    return FNB_TAB, cur
-
-        if bFoundMatch:
-            return FNB_TAB, tabIdx
+            posx += tabWidth
+        
+        return numTabs
 
-        if self._isdragging:
-            # We are doing DND, so check also the region outside the tabs
-            # try before the first tab
-            pgInfo = self._pagesInfoVec[0]
-            tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
-            if tabRect.Contains(pt):
-                return FNB_TAB, 0
 
-            # try after the last tab
-            pgInfo = self._pagesInfoVec[-1]
-            startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
-            tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
+    def IsDefaultTabs(self):
+        """ Returns whether a tab has a default style. """
 
-            if tabRect.Contains(pt):
-                return FNB_TAB, len(self._pagesInfoVec)
-        
-        # Default
-        return FNB_NOWHERE, -1
+        style = self.GetParent().GetWindowStyleFlag()
+        res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8)
+        return not res
 
 
-    def OnPaint(self, event):
+    def AdvanceSelection(self, bForward=True):
         """
-        Handles the wx.EVT_PAINT event for StyledTabsContainer.
-        Switches to PageContainerBase.OnPaint() method if the style is not VC8. 
+        Cycles through the tabs.
+        The call to this function generates the page changing events.
         """
 
-        if not self.HasFlag(FNB_VC8):
-        
-            PageContainerBase.OnPaint(self, event)
-            return
+        nSel = self.GetSelection()
 
-        # Visual studio 8 style
-        dc = wx.BufferedPaintDC(self)
+        if nSel < 0:
+            return
 
-        if "__WXMAC__" in wx.PlatformInfo:
-            # Works well on MSW & GTK, however this lines should be skipped on MAC
-            if not self._pagesInfoVec or self._nFrom >= len(self._pagesInfoVec):
-                self.Hide()
-                event.Skip()
-                return
+        nMax = self.GetPageCount() - 1
         
-        # Set the font for measuring the tab height
-        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-
-        if "__WXGTK__" in wx.PlatformInfo:
-            dc.SetFont(boldFont)
+        if bForward:
+            newSelection = (nSel == nMax and [0] or [nSel + 1])[0]
+        else:
+            newSelection = (nSel == 0 and [nMax] or [nSel - 1])[0]
 
-        width, height = dc.GetTextExtent("Tp")
+        if not self._pagesInfoVec[newSelection].GetEnabled():
+            return
 
-        tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding
+        self.FireEvent(newSelection)
 
-        # Calculate the number of rows required for drawing the tabs
-        rect = self.GetClientRect()
 
-        # Set the maximum client size
-        self.SetSizeHints(self.GetButtonsAreaLength(), tabHeight)
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
+    def OnMouseLeave(self, event):
+        """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
 
-        # Create brushes
-        backBrush = wx.Brush(self._tabAreaColor)
-        noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
-        selBrush = wx.Brush(self._activeTabColor)
-        size = self.GetSize()
+        self._nLeftButtonStatus = FNB_BTN_NONE
+        self._nXButtonStatus = FNB_BTN_NONE
+        self._nRightButtonStatus = FNB_BTN_NONE
+        self._nTabXButtonStatus = FNB_BTN_NONE
+        self._nArrowDownButtonStatus = FNB_BTN_NONE
 
-        # Background
-        dc.SetTextBackground(self.GetBackgroundColour())
-        dc.SetTextForeground(self._activeTextColor)
+        style = self.GetParent().GetWindowStyleFlag()        
+        render = self._mgr.GetRenderer(style)
         
-        # If border style is set, set the pen to be border pen
-        if self.HasFlag(FNB_TABS_BORDER_SIMPLE):
-            dc.SetPen(borderPen)
-        else:
-            dc.SetPen(wx.TRANSPARENT_PEN)
+        dc = wx.ClientDC(self)
 
-        lightFactor = (self.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
-        # For VC8 style, we color the tab area in gradient coloring
-        PaintStraightGradientBox(dc, self.GetClientRect(), self._tabAreaColor, LightColour(self._tabAreaColor, lightFactor))
+        render.DrawX(self, dc)
+        render.DrawLeftArrow(self, dc)
+        render.DrawRightArrow(self, dc)
 
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        dc.DrawRectangle(0, 0, size.x, size.y)
+        selection = self.GetSelection()
 
-        # Take 3 bitmaps for the background for the buttons
+        if selection == -1:
+            event.Skip()
+            return
         
-        mem_dc = wx.MemoryDC()
+        if not self.IsTabVisible(selection):
+            if selection == len(self._pagesInfoVec) - 1:
+                if not self.CanFitToScreen(selection):
+                    event.Skip()
+                    return
+            else:
+                event.Skip()
+                return
+                    
+        render.DrawTabX(self, dc, self._pagesInfoVec[selection].GetXRect(), selection, self._nTabXButtonStatus)
+            
+        event.Skip()
 
-        #---------------------------------------
-        # X button
-        #---------------------------------------
-        rect = wx.Rect(self.GetXPos(), 6, 16, 14)
-        mem_dc.SelectObject(self._xBgBmp)
-        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
-        mem_dc.SelectObject(wx.NullBitmap)
 
-        #---------------------------------------
-        # Right button
-        #---------------------------------------
-        rect = wx.Rect(self.GetRightButtonPos(), 6, 16, 14)
-        mem_dc.SelectObject(self._rightBgBmp)
-        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
-        mem_dc.SelectObject(wx.NullBitmap)
+    def OnMouseEnterWindow(self, event):
+        """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
 
-        #---------------------------------------
-        # Left button
-        #---------------------------------------
-        rect = wx.Rect(self.GetLeftButtonPos(), 6, 16, 14)
-        mem_dc.SelectObject(self._leftBgBmp)
-        mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
-        mem_dc.SelectObject(wx.NullBitmap)
-        
-        # We always draw the bottom/upper line of the tabs
-        # regradless the style
-        dc.SetPen(borderPen)
-        self.DrawTabsLine(dc)
+        self._nLeftButtonStatus = FNB_BTN_NONE
+        self._nXButtonStatus = FNB_BTN_NONE
+        self._nRightButtonStatus = FNB_BTN_NONE
+        self._nLeftClickZone = FNB_BTN_NONE
+        self._nArrowDownButtonStatus = FNB_BTN_NONE
 
-        # Restore the pen
-        dc.SetPen(borderPen)
+        event.Skip()
 
-        # Draw labels
-        dc.SetFont(boldFont)
-        activeTabPosx = 0
 
-        # Update all the tabs from 0 to 'self._nFrom' to be non visible
-        for i in xrange(self._nFrom):
-        
-            self._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
-            self._pagesInfoVec[i].GetRegion().Clear()
+    def ShowTabTooltip(self, tabIdx):
+        """ Shows a tab tooltip. """
 
-        # Draw the visible tabs, in VC8 style, we draw them from right to left
-        vTabsInfo = self.NumberTabsCanFit(dc)
+        pWindow = self._pParent.GetPage(tabIdx)
         
-        for cur in xrange(len(vTabsInfo) - 1, -1, -1):
+        if pWindow:        
+            pToolTip = pWindow.GetToolTip()
+            if pToolTip and pToolTip.GetWindow() == pWindow:
+                self.SetToolTipString(pToolTip.GetTip())
         
-            # 'i' points to the index of the currently drawn tab
-            # in self._pagesInfoVec vector
-            i = self._nFrom + cur
-            dc.SetPen(borderPen)
-            dc.SetBrush((i==self.GetSelection() and [selBrush] or [noselBrush])[0])
-
-            # Calculate the text length using the bold font, so when selecting a tab
-            # its width will not change
-            dc.SetFont(boldFont)
-            width, pom = dc.GetTextExtent(self.GetPageText(i))
-
-            # Now set the font to the correct font
-            dc.SetFont((i==self.GetSelection() and [boldFont] or [normalFont])[0])
 
-            # Set a minimum size to a tab
-            if width < 20:
-                width = 20
-
-            # Add the padding to the tab width
-            # Tab width:
-            # +-----------------------------------------------------------+
-            # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
-            # +-----------------------------------------------------------+
+    def SetPageImage(self, page, imgindex):
+        """ Sets the image index associated to a page. """
 
-            tabWidth = self._pParent.GetPadding() * 2 + width
-            imageYCoord = (self.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
+        if page < len(self._pagesInfoVec):
+        
+            self._pagesInfoVec[page].SetImageIndex(imgindex)
+            self.Refresh()
 
-            if self.TabHasImage(i):
-                tabWidth += 16 + self._pParent.GetPadding()
 
-            posx = vTabsInfo[cur].x
+    def GetPageImage(self, page):
+        """ Returns the image index associated to a page. """
 
-            # By default we clean the tab region
-            # incase we use the VC8 style which requires
-            # the region, it will be filled by the function
-            # drawVc8Tab
-            self._pagesInfoVec[i].GetRegion().Clear()
-            
-            # Clean the 'x' buttn on the tab 
-            # 'Clean' rectanlge is a rectangle with width or height
-            # with values lower than or equal to 0
-            self._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
+        if page < len(self._pagesInfoVec):
+        
+            return self._pagesInfoVec[page].GetImageIndex()
+        
+        return -1
 
-            # Draw the tab
-            # Incase we are drawing the active tab
-            # we need to redraw so it will appear on top
-            # of all other tabs
-            if i == self.GetSelection():
-            
-                activeTabPosx = posx
-            
-            else:
-            
-                self.DrawVC8Tab(dc, posx, i, tabWidth, tabHeight)
 
-            # Text drawing offset from the left border of the 
-            # rectangle
-            # The width of the images are 16 pixels
-            vc8ShapeLen = tabHeight
-            
-            if self.TabHasImage(i):
-                textOffset = self._pParent.GetPadding() * 2 + 16 + vc8ShapeLen 
-            else:
-                textOffset = self._pParent.GetPadding() + vc8ShapeLen
+    def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
+        """ Handles the drop action from a DND operation. """
 
-            # Set the non-active text color
-            if i != self.GetSelection():
-                dc.SetTextForeground(self._nonActiveTextColor)
+        # Disable drag'n'drop for disabled tab
+        if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled():
+            return wx.DragCancel
 
-            if self.TabHasImage(i):
-                imageXOffset = textOffset - 16 - self._pParent.GetPadding()
-                self._ImageList.Draw(self._pagesInfoVec[i].GetImageIndex(), dc,
-                                     posx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
+        self._isdragging = True
+        oldContainer = wnd_oldContainer
+        nIndex = -1
 
-            dc.DrawText(self.GetPageText(i), posx + textOffset, imageYCoord)
-            
-            textWidth, textHeight = dc.GetTextExtent(self.GetPageText(i))
+        where, nIndex = self.HitTest(wx.Point(x, y))
 
-            # Restore the text forground
-            dc.SetTextForeground(self._activeTextColor)
+        oldNotebook = oldContainer.GetParent()
+        newNotebook = self.GetParent()
 
-            # Update the tab position & size
-            self._pagesInfoVec[i].SetPosition(wx.Point(posx, VERTICAL_BORDER_PADDING))
-            self._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
+        if oldNotebook == newNotebook:
         
-        # Incase we are in VC8 style, redraw the active tab (incase it is visible)
-        if self.GetSelection() >= self._nFrom and self.GetSelection() < self._nFrom + len(vTabsInfo):
+            if nTabPage >= 0:
+            
+                if where == FNB_TAB:
+                    self.MoveTabPage(nTabPage, nIndex)
+                           
+        elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND:
         
-            hasImage = self.TabHasImage(self.GetSelection())
+            if wx.Platform in ["__WXMSW__", "__WXGTK__"]:
+                if nTabPage >= 0:
+                
+                    window = oldNotebook.GetPage(nTabPage)
 
-            dc.SetFont(boldFont)
-            width, pom = dc.GetTextExtent(self.GetPageText(self.GetSelection()))
+                    if window:
+                        where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y))
+                        caption = oldContainer.GetPageText(nTabPage)
+                        imageindex = oldContainer.GetPageImage(nTabPage)
+                        oldNotebook.RemovePage(nTabPage)
+                        window.Reparent(newNotebook)
 
-            tabWidth = self._pParent.GetPadding() * 2 + width
+                        if imageindex >= 0:
 
-            if hasImage:
-                tabWidth += 16 + self._pParent.GetPadding()
+                            bmp = oldNotebook.GetImageList().GetIcon(imageindex)
+                            newImageList = newNotebook.GetImageList()
+    
+                            if not newImageList:
+                                xbmp, ybmp = bmp.GetWidth(), bmp.GetHeight()
+                                newImageList = wx.ImageList(xbmp, ybmp)                                
+                                imageindex = 0
+                            else:
+                                imageindex = newImageList.GetImageCount()
+
+                            newImageList.AddIcon(bmp)
+                            newNotebook.SetImageList(newImageList)
+                                
+                        newNotebook.InsertPage(nIndex, window, caption, True, imageindex)
 
-            # Set the active tab font, pen brush and font-color
-            dc.SetPen(borderPen)
-            dc.SetBrush(selBrush)
-            dc.SetFont(boldFont)
-            dc.SetTextForeground(self._activeTextColor)
-            self.DrawVC8Tab(dc, activeTabPosx, self.GetSelection(), tabWidth, tabHeight)
+        self._isdragging = False
+        
+        return wx.DragMove
 
-            # Text drawing offset from the left border of the 
-            # rectangle
-            # The width of the images are 16 pixels
-            vc8ShapeLen = tabHeight - VERTICAL_BORDER_PADDING - 2
-            if hasImage:
-                textOffset = self._pParent.GetPadding() * 2 + 16 + vc8ShapeLen 
-            else:
-                textOffset = self._pParent.GetPadding() + vc8ShapeLen
 
-            # Draw the image for the tab if any
-            imageYCoord = (self.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
+    def MoveTabPage(self, nMove, nMoveTo):
+        """ Moves a tab inside the same L{FlatNotebook}. """
 
-            if hasImage:
-                imageXOffset = textOffset - 16 - self._pParent.GetPadding()
-                self._ImageList.Draw(self._pagesInfoVec[self.GetSelection()].GetImageIndex(), dc,
-                                     activeTabPosx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)            
+        if nMove == nMoveTo:
+            return
 
-            dc.DrawText(self.GetPageText(self.GetSelection()), activeTabPosx + textOffset, imageYCoord)
+        elif nMoveTo < len(self._pParent._windows):
+            nMoveTo = nMoveTo + 1
 
-        # Update all tabs that can not fit into the screen as non-visible
-        for xx in xrange(self._nFrom + len(vTabsInfo), len(self._pagesInfoVec)):
-        
-            self._pagesInfoVec[xx].SetPosition(wx.Point(-1, -1))
-            self._pagesInfoVec[xx].GetRegion().Clear()
+        self._pParent.Freeze()
         
-        # Draw the left/right/close buttons 
-        # Left arrow
-        self.DrawLeftArrow(dc)
-        self.DrawRightArrow(dc)
-        self.DrawX(dc)
+        # Remove the window from the main sizer
+        nCurSel = self._pParent._pages.GetSelection()
+        self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel])
+        self._pParent._windows[nCurSel].Hide()
 
+        pWindow = self._pParent._windows[nMove]
+        self._pParent._windows.pop(nMove)
+        self._pParent._windows.insert(nMoveTo-1, pWindow)
 
-    def DrawVC8Tab(self, dc, posx, tabIdx, tabWidth, tabHeight):
-        """ Draws the VC8 style tabs. """
+        pgInfo = self._pagesInfoVec[nMove]
 
-        borderPen = wx.Pen(self._colorBorder)
-        tabPoints = [wx.Point() for ii in xrange(8)]
+        self._pagesInfoVec.pop(nMove)
+        self._pagesInfoVec.insert(nMoveTo - 1, pgInfo)
 
-        # 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)
-        #
-        #
+        # Add the page according to the style
+        pSizer = self._pParent._mainSizer
+        style = self.GetParent().GetWindowStyleFlag()
+
+        if style & FNB_BOTTOM:
+        
+            pSizer.Insert(0, pWindow, 1, wx.EXPAND)
+        
+        else:
+        
+            # We leave a space of 1 pixel around the window
+            pSizer.Add(pWindow, 1, wx.EXPAND)
+        
+        pWindow.Show()
 
-        tabPoints[0].x = (self.HasFlag(FNB_BOTTOM) and [posx] or [posx+self._factor])[0]
-        tabPoints[0].y = (self.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 3])[0]
+        pSizer.Layout()
+        self._iActivePage = nMoveTo - 1
+        self._iPreviousActivePage = -1
+        self.DoSetSelection(self._iActivePage)
+        self.Refresh()
+        self._pParent.Thaw()
 
-        tabPoints[1].x = tabPoints[0].x + tabHeight - VERTICAL_BORDER_PADDING - 3 - self._factor
-        tabPoints[1].y = (self.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
 
-        tabPoints[2].x = tabPoints[1].x + 4
-        tabPoints[2].y = (self.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
+    def CanFitToScreen(self, page):
+        """ Returns wheter a tab can fit in the left space in the screen or not. """
 
-        tabPoints[3].x = tabPoints[2].x + tabWidth - 2
-        tabPoints[3].y = (self.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
+        # Incase the from is greater than page,
+        # we need to reset the self._nFrom, so in order
+        # to force the caller to do so, we return false
+        if self._nFrom > page:
+            return False
 
-        tabPoints[4].x = tabPoints[3].x + 1
-        tabPoints[4].y = (self.HasFlag(FNB_BOTTOM) and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
+        style = self.GetParent().GetWindowStyleFlag()
+        render = self._mgr.GetRenderer(style)
 
-        tabPoints[5].x = tabPoints[4].x + 1
-        tabPoints[5].y = (self.HasFlag(FNB_BOTTOM) and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
+        vTabInfo = render.NumberTabsCanFit(self)
 
-        tabPoints[6].x = tabPoints[2].x + tabWidth
-        tabPoints[6].y = tabPoints[0].y
+        if page - self._nFrom >= len(vTabInfo):
+            return False
+        
+        return True
 
-        tabPoints[7].x = tabPoints[0].x
-        tabPoints[7].y = tabPoints[0].y
 
-        self._pagesInfoVec[tabIdx].SetRegion(tabPoints)
+    def GetNumOfVisibleTabs(self):
+        """ Returns the number of visible tabs. """
 
-        # Draw the polygon
-        br = dc.GetBrush()
-        dc.SetBrush(wx.Brush((tabIdx == self.GetSelection() and [self._activeTabColor] or [self._colorTo])[0]))
-        dc.SetPen(wx.Pen((tabIdx == self.GetSelection() and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [self._colorBorder])[0]))
-        dc.DrawPolygon(tabPoints)
+        count = 0
+        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
+            if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
+                break
+            count = count + 1
 
-        # Restore the brush
-        dc.SetBrush(br)
+        return count
 
-        rect = self.GetClientRect()
 
-        if tabIdx != self.GetSelection() and not self.HasFlag(FNB_BOTTOM):
-        
-            # Top default tabs
-            dc.SetPen(wx.Pen(self._colorBorder))
-            lineY = rect.height
-            curPen = dc.GetPen()
-            curPen.SetWidth(1)
-            dc.SetPen(curPen)
-            dc.DrawLine(posx, lineY, posx+rect.width, lineY)
+    def GetEnabled(self, page):
+        """ Returns whether a tab is enabled or not. """
 
-        # In case we are drawing the selected tab, we draw the border of it as well
-        # but without the bottom (upper line incase of wxBOTTOM)
-        if tabIdx == self.GetSelection():
+        if page >= len(self._pagesInfoVec):
+            return True # Seems strange, but this is the default
         
-            borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-            brush = wx.TRANSPARENT_BRUSH
-            dc.SetPen(borderPen)
-            dc.SetBrush(brush)
-            dc.DrawPolygon(tabPoints)
+        return self._pagesInfoVec[page].GetEnabled()
 
-            # 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)
-        
-        self.FillVC8GradientColor(dc, tabPoints, tabIdx == self.GetSelection(), tabIdx)
 
-        # Draw a thin line to the right of the non-selected tab
-        if tabIdx != self.GetSelection():
+    def Enable(self, page, enabled=True):
+        """ Enables or disables a tab. """
+
+        if page >= len(self._pagesInfoVec):
+            return
         
-            dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
-            dc.DrawLine(tabPoints[4].x-1, tabPoints[4].y, tabPoints[5].x-1, tabPoints[5].y)
-            dc.DrawLine(tabPoints[5].x-1, tabPoints[5].y, tabPoints[6].x-1, tabPoints[6].y)
+        self._pagesInfoVec[page].Enable(enabled)
         
 
-    def FillVC8GradientColor(self, dc, tabPoints, bSelectedTab, tabIdx):
-        """ Fills a tab with a gradient colour. """
-
-        # calculate gradient coefficients
-        col2 = (self.HasFlag(FNB_BOTTOM) and [self._colorTo] or [self._colorFrom])[0]
-        col1 = (self.HasFlag(FNB_BOTTOM) and [self._colorFrom] or [self._colorTo])[0]
+    def GetSingleLineBorderColour(self):
+        """ Returns the colour for the single line border. """
 
-        # If colorful tabs style is set, override the tab color
-        if self.HasFlag(FNB_COLORFUL_TABS):
+        if self.HasFlag(FNB_FANCY_TABS):
+            return self._colorFrom
         
-            if not self._pagesInfoVec[tabIdx].GetColor():
-            
-                # First time, generate color, and keep it in the vector
-                tabColor = self.GenTabColour()
-                self._pagesInfoVec[tabIdx].SetColor(tabColor)
-            
-            if self.HasFlag(FNB_BOTTOM):
-            
-                col2 = LightColour(self._pagesInfoVec[tabIdx].GetColor(), 50 )
-                col1 = LightColour(self._pagesInfoVec[tabIdx].GetColor(), 80 )
-            
-            else:
-            
-                col1 = LightColour(self._pagesInfoVec[tabIdx].GetColor(), 50 )
-                col2 = LightColour(self._pagesInfoVec[tabIdx].GetColor(), 80 )
-            
-        size = abs(tabPoints[2].y - tabPoints[0].y) - 1
+        return wx.WHITE
 
-        rf, gf, bf = 0, 0, 0
-        rstep = float(col2.Red() - col1.Red())/float(size)
-        gstep = float(col2.Green() - col1.Green())/float(size)
-        bstep = float(col2.Blue() - col1.Blue())/float(size)
-        
-        y = tabPoints[0].y 
 
-        # If we are drawing the selected tab, we need also to draw a line 
-        # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
-        # by drawing the rectangle with transparent brush
-        # the line under the selected tab will be deleted by the drwaing loop
-        if bSelectedTab:
-            self.DrawTabsLine(dc)
+    def HasFlag(self, flag):
+        """ Returns whether a flag is present in the L{FlatNotebook} style. """
 
-        while 1:
-        
-            if self.HasFlag(FNB_BOTTOM):
-            
-                if y > tabPoints[0].y + size:
-                    break
-            
-            else:
-            
-                if y < tabPoints[0].y - size:
-                    break
-            
-            currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
+        style = self.GetParent().GetWindowStyleFlag()
+        res = (style & flag and [True] or [False])[0]
+        return res
 
-            dc.SetPen((bSelectedTab and [wx.Pen(self._activeTabColor)] or [wx.Pen(currCol)])[0])
-            startX = self.GetStartX(tabPoints, y) 
-            endX = self.GetEndX(tabPoints, y)
-            dc.DrawLine(startX, y, endX, y)
 
-            # Draw the border using the 'edge' point
-            dc.SetPen(wx.Pen((bSelectedTab and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [self._colorBorder])[0]))
-            
-            dc.DrawPoint(startX, y)
-            dc.DrawPoint(endX, y)
-            
-            # Progress the color 
-            rf += rstep
-            gf += gstep
-            bf += bstep
+    def ClearFlag(self, flag):
+        """ Deletes a flag from the L{FlatNotebook} style. """
 
-            if self.HasFlag(FNB_BOTTOM):
-                y = y + 1
-            else:
-                y = y - 1
+        style = self.GetParent().GetWindowStyleFlag()
+        style &= ~flag 
+        self.SetWindowStyleFlag(style)
 
 
-    def GetStartX(self, tabPoints, y):
-        """ Returns the x start position of a tab. """
+    def TabHasImage(self, tabIdx):
+        """ Returns whether a tab has an associated image index or not. """
 
-        x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
+        if self._ImageList:
+            return self._pagesInfoVec[tabIdx].GetImageIndex() != -1
+        
+        return False
 
-        # We check the 3 points to the left
-        style = self.GetParent().GetWindowStyleFlag()
-        bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
-        match = False
 
-        if bBottomStyle:
+    def OnLeftDClick(self, event):
+        """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
+
+        if self.HasFlag(FNB_DCLICK_CLOSES_TABS):
+        
+            where, tabIdx = self.HitTest(event.GetPosition())
+            
+            if where == FNB_TAB:
+                self.DeletePage(tabIdx)
         
-            for i in xrange(3):
-                
-                if y >= tabPoints[i].y and y < tabPoints[i+1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i+1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i+1].y
-                    match = True
-                    break
-                
         else:
         
-            for i in xrange(3):
-                
-                if y <= tabPoints[i].y and y > tabPoints[i+1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i+1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i+1].y
-                    match = True
-                    break
-                
-        if not match:
-            return tabPoints[2].x
+            event.Skip()
+        
 
-        # According to the equation y = ax + b => x = (y-b)/a
-        # We know the first 2 points
+    def PopupTabsMenu(self):
+        """ Pops up the menu activated with the drop down arrow in the navigation area. """
 
-        if x2 == x1:
-            return x2
-        else:
-            a = (y2 - y1)/(x2 - x1)
+        popupMenu = wx.Menu()
 
-        b = y1 - ((y2 - y1)/(x2 - x1))*x1
+        for i in xrange(len(self._pagesInfoVec)):
+            pi = self._pagesInfoVec[i]
+            item = wx.MenuItem(popupMenu, i, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
+            self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item)
 
-        if a == 0:
-            return int(x1)
+            # This code is commented, since there is an alignment problem with wx2.6.3 & Menus
+            # if self.TabHasImage(ii):
+            #   item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] );
 
-        x = (y - b)/a
-        
-        return int(x)
+            popupMenu.AppendItem(item)
+            item.Enable(pi.GetEnabled())
+            
+        self.PopupMenu(popupMenu)
 
 
-    def GetEndX(self, tabPoints, y):
-        """ Returns the x end position of a tab. """
+    def OnTabMenuSelection(self, event):
+        """ Handles the wx.EVT_MENU event for L{PageContainer}. """
 
-        x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
+        selection = event.GetId()
+        self.FireEvent(selection)
 
-        # We check the 3 points to the left
-        style = self.GetParent().GetWindowStyleFlag()
-        bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
-        match = False
 
-        if bBottomStyle:
+    def FireEvent(self, selection):
+        """
+        Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
+        called from other methods (from menu selection or Smart Tabbing).
+        Utility function.
+        """
 
-            for i in xrange(7, 3, -1):
-                
-                if y >= tabPoints[i].y and y < tabPoints[i-1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i-1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i-1].y
-                    match = True
-                    break
+        if selection == self._iActivePage:
+            # No events for the same selection
+            return
         
-        else:
+        oldSelection = self._iActivePage
+
+        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
+        event.SetSelection(selection)
+        event.SetOldSelection(oldSelection)
+        event.SetEventObject(self.GetParent())
         
-            for i in xrange(7, 3, -1):
-                
-                if y <= tabPoints[i].y and y > tabPoints[i-1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i-1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i-1].y
-                    match = True
-                    break
+        if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed():
+        
+            self.SetSelection(selection)
 
-        if not match:
-            return tabPoints[3].x
+            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
+            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
+            event.SetOldSelection(oldSelection)
+            self.GetParent().GetEventHandler().ProcessEvent(event)
+            
 
-        # According to the equation y = ax + b => x = (y-b)/a
-        # We know the first 2 points
+    def SetImageList(self, imglist):
+        """ Sets the image list for the page control. """
 
-        # Vertical line
-        if x1 == x2:
-            return int(x1)
-        
-        a = (y2 - y1)/(x2 - x1)
-        b = y1 - ((y2 - y1)/(x2 - x1)) * x1
+        self._ImageList = imglist
 
-        if a == 0:
-            return int(x1)
 
-        x = (y - b)/a
+    def GetImageList(self):
+        """ Returns the image list for the page control. """
+
+        return self._ImageList
 
-        return int(x)
 
+    def GetSelection(self):
+        """ Returns the current selected page. """
+
+        return self._iActivePage 
 
-    def GenTabColour(self):
-        """ Generates a random soft pleasant colour for a tab. """
 
-        return RandomColor()
+    def GetPageCount(self):
+        """ Returns the number of tabs in the L{FlatNotebook} control. """
 
+        return len(self._pagesInfoVec)
 
-    def GetSingleLineBorderColor(self):
 
-        if self.HasFlag(FNB_VC8):
-            return self._activeTabColor
-        else:
-            return PageContainerBase.GetSingleLineBorderColor(self)
+    def GetPageText(self, page):
+        """ Returns the tab caption of the page. """
 
+        return self._pagesInfoVec[page].GetCaption() 
 
-    def SetFactor(self, factor):
-        """ Sets the brighten colour factor. """
-        
-        self._factor = factor
-        self.Refresh()
 
+    def SetPageText(self, page, text):
+        """ Sets the tab caption of the page. """
 
-    def GetFactor(self):
-        """ Returns the brighten colour factor. """
+        self._pagesInfoVec[page].SetCaption(text)
+        return True 
 
-        return self._factor 
 
+    def DrawDragHint(self):
+        """ Draws small arrow at the place that the tab will be placed. """
 
+        # get the index of tab that will be replaced with the dragged tab
+        pt = wx.GetMousePosition()
+        client_pt = self.ScreenToClient(pt)
+        where, tabIdx = self.HitTest(client_pt)
+        self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()).DrawDragHint(self, tabIdx)