+ 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()