+            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
+
+        # According to the equation y = ax + b => x = (y-b)/a
+        # We know the first 2 points
+
+        # Vertical line
+        if x1 == x2:
+            return int(x1)
+        
+        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 NumberTabsCanFit(self, pageContainer, fr=-1):
+        """ Returns the number of tabs that can fit in the visible area. """
+
+        pc = pageContainer
+        
+        rect = pc.GetClientRect()
+        clientWidth = rect.width
+
+        # Empty results
+        vTabInfo = []
+        tabHeight = self.CalcTabHeight(pageContainer)
+
+        # The drawing starts from posx
+        posx = pc._pParent.GetPadding()
+        
+        if fr < 0:
+            fr = pc._nFrom
+
+        for i in xrange(fr, len(pc._pagesInfoVec)):
+        
+            vc8glitch = tabHeight + FNB_HEIGHT_SPACER
+            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
+
+            if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength(pc) >= clientWidth:
+                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
+    
+
+# ---------------------------------------------------------------------------- #
+# Class FlatNotebook
+# ---------------------------------------------------------------------------- #
+
+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"):
+        """
+        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)
+        
+        self._pages = PageContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style)
+
+        self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
+
+        self.Init()
+
+
+    def Init(self):
+        """ Initializes all the class attributes. """
+        
+        self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
+
+        self._mainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.SetSizer(self._mainSizer)
+
+        # 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)
+        
+        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)
+        
+        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()
+
+        self._pages._nFrom = self._nFrom
+        self._pDropTarget = FNBDropTarget(self)
+        self.SetDropTarget(self._pDropTarget)
+
+
+    def SetActiveTabTextColour(self, textColour):
+        """ Sets the text colour for the active tab. """
+
+        self._pages._activeTextColor = textColour
+
+
+    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 GetPreviousSelection(self):
+        """ Returns the previous selection. """
+
+        return self._pages._iPreviousActivePage
+
+
+    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.
+        
+        Return value:
+        True if successful, False otherwise.
+        """
+
+        # sanity check
+        if not page:
+            return False
+
+        # reparent the window to us
+        page.Reparent(self)
+
+        # Add tab
+        bSelected = select or len(self._windows) == 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()
+
+        if not self._pages.IsShown():
+            self._pages.Show()
+
+        self._pages.AddPage(text, bSelected, imageId)
+        self._windows.append(page)
+
+        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()
+            
+            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)
+
+            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
+            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
+            event.SetOldSelection(oldSelection)
+            self.GetEventHandler().ProcessEvent(event)
+            
+        else:
+
+            # Hide the page
+            page.Hide()
+
+        self.Thaw()        
+        self._mainSizer.Layout()