+ 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