1 # --------------------------------------------------------------------------- # 
   2 # FLATNOTEBOOK Widget wxPython IMPLEMENTATION 
   4 # Original C++ Code From Eran. You Can Find It At: 
   6 # http://wxforum.shadonet.com/viewtopic.php?t=5761&start=0 
   8 # License: wxWidgets license 
  13 # Andrea Gavana, @ 02 Oct 2006 
  14 # Latest Revision: 12 Oct 2006, 20.00 GMT 
  17 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please 
  20 # andrea.gavana@gmail.com 
  23 # Or, Obviously, To The wxPython Mailing List!!! 
  27 # --------------------------------------------------------------------------- # 
  30 The FlatNotebook is a full implementation of the wx.Notebook, and designed to be 
  31 a drop-in replacement for wx.Notebook. The API functions are similar so one can 
  32 expect the function to behave in the same way.  
  36   - The buttons are highlighted a la Firefox style 
  37   - The scrolling is done for bulks of tabs (so, the scrolling is faster and better) 
  38   - The buttons area is never overdrawn by tabs (unlike many other implementations I saw) 
  39   - It is a generic control 
  40   - Currently there are 4 differnt styles - VC8, VC 71, Standard and Fancy 
  41   - Mouse middle click can be used to close tabs 
  42   - A function to add right click menu for tabs (simple as SetRightClickMenu) 
  43   - All styles has bottom style as well (they can be drawn in the bottom of screen) 
  44   - An option to hide 'X' button or navigation buttons (separately) 
  45   - Gradient coloring of the selected tabs and border 
  46   - Support for drag 'n' drop of tabs, both in the same notebook or to another notebook 
  47   - Possibility to have closing button on the active tab directly 
  48   - Support for disabled tabs 
  49   - Colours for active/inactive tabs, and captions 
  50   - Background of tab area can be painted in gradient (VC8 style only) 
  51   - Colourful tabs - a random gentle colour is generated for each new tab (very cool, VC8 style only) 
  59 FlatNotebook Is Freeware And Distributed Under The wxPython License.  
  61 Latest Revision: Andrea Gavana @ 12 Oct 2006, 20.00 GMT 
  65 @undocumented: FNB_HEIGHT_SPACER, VERTICAL_BORDER_PADDING, VC8_SHAPE_LEN, 
  66     wxEVT*, left_arrow_*, right_arrow*, x_button*, down_arrow*, 
  67     FNBDragInfo, FNBDropTarget, GetMondrian* 
  70 __docformat__ 
= "epytext" 
  73 #---------------------------------------------------------------------- 
  74 # Beginning Of FLATNOTEBOOK wxPython Code 
  75 #---------------------------------------------------------------------- 
  83 # Check for the new method in 2.7 (not present in 2.6.3.3) 
  84 if wx
.VERSION_STRING 
< "2.7": 
  85     wx
.Rect
.Contains 
= lambda self
, point
: wx
.Rect
.Inside(self
, point
) 
  87 FNB_HEIGHT_SPACER 
= 10 
  89 # Use Visual Studio 2003 (VC7.1) style for tabs 
  91 """Use Visual Studio 2003 (VC7.1) style for tabs""" 
  93 # Use fancy style - square tabs filled with gradient coloring 
  95 """Use fancy style - square tabs filled with gradient coloring""" 
  97 # Draw thin border around the page 
  98 FNB_TABS_BORDER_SIMPLE 
= 4 
  99 """Draw thin border around the page""" 
 101 # Do not display the 'X' button 
 103 """Do not display the 'X' button""" 
 105 # Do not display the Right / Left arrows 
 106 FNB_NO_NAV_BUTTONS 
= 16 
 107 """Do not display the right/left arrows""" 
 109 # Use the mouse middle button for cloing tabs 
 110 FNB_MOUSE_MIDDLE_CLOSES_TABS 
= 32 
 111 """Use the mouse middle button for cloing tabs""" 
 113 # Place tabs at bottom - the default is to place them 
 116 """Place tabs at bottom - the default is to place them at top""" 
 118 # Disable dragging of tabs 
 120 """Disable dragging of tabs""" 
 122 # Use Visual Studio 2005 (VC8) style for tabs 
 124 """Use Visual Studio 2005 (VC8) style for tabs""" 
 128 """Place 'X' close button on the active tab""" 
 130 FNB_BACKGROUND_GRADIENT 
= 1024 
 131 """Use gradients to paint the tabs background""" 
 133 FNB_COLORFUL_TABS 
= 2048 
 134 """Use colourful tabs (VC8 style only)""" 
 136 # Style to close tab using double click - styles 1024, 2048 are reserved 
 137 FNB_DCLICK_CLOSES_TABS 
= 4096 
 138 """Style to close tab using double click""" 
 140 FNB_SMART_TABS 
= 8192 
 141 """Use Smart Tabbing, like Alt+Tab on Windows""" 
 143 FNB_DROPDOWN_TABS_LIST 
= 16384 
 144 """Use a dropdown menu on the left in place of the arrows""" 
 146 FNB_ALLOW_FOREIGN_DND 
= 32768 
 147 """Allows drag 'n' drop operations between different L{FlatNotebook}s""" 
 149 FNB_HIDE_ON_SINGLE_TAB 
= 65536 
 150 """Hides the Page Container when there is one or fewer tabs""" 
 152 VERTICAL_BORDER_PADDING 
= 4 
 154 # Button size is a 16x16 xpm bitmap 
 156 """Button size is a 16x16 xpm bitmap""" 
 160 MASK_COLOR  
= wx
.Colour(0, 128, 128) 
 161 """Mask colour for the arrow bitmaps""" 
 165 """Navigation button is pressed""" 
 167 """Navigation button is hovered""" 
 172 FNB_TAB 
= 1             # On a tab 
 173 """Indicates mouse coordinates inside a tab""" 
 174 FNB_X 
= 2               # On the X button 
 175 """Indicates mouse coordinates inside the I{X} region""" 
 176 FNB_TAB_X 
= 3           # On the 'X' button (tab's X button) 
 177 """Indicates mouse coordinates inside the I{X} region in a tab""" 
 178 FNB_LEFT_ARROW 
= 4      # On the rotate left arrow button 
 179 """Indicates mouse coordinates inside the left arrow region""" 
 180 FNB_RIGHT_ARROW 
= 5     # On the rotate right arrow button 
 181 """Indicates mouse coordinates inside the right arrow region""" 
 182 FNB_DROP_DOWN_ARROW 
= 6 # On the drop down arrow button 
 183 """Indicates mouse coordinates inside the drop down arrow region""" 
 184 FNB_NOWHERE 
= 0         # Anywhere else 
 185 """Indicates mouse coordinates not on any tab of the notebook""" 
 187 FNB_DEFAULT_STYLE 
= FNB_MOUSE_MIDDLE_CLOSES_TABS | FNB_HIDE_ON_SINGLE_TAB
 
 188 """L{FlatNotebook} default style""" 
 190 # FlatNotebook Events: 
 191 # wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page; 
 192 # wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch 
 193 # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call 
 194 # event.Skip() In Your Event Handler; 
 195 # wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But 
 196 # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip() 
 197 # In Your Event Handler; 
 198 # wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed. 
 199 # wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab. 
 201 wxEVT_FLATNOTEBOOK_PAGE_CHANGED 
= wx
.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
 
 202 wxEVT_FLATNOTEBOOK_PAGE_CHANGING 
= wx
.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
 
 203 wxEVT_FLATNOTEBOOK_PAGE_CLOSING 
= wx
.NewEventType() 
 204 wxEVT_FLATNOTEBOOK_PAGE_CLOSED 
= wx
.NewEventType() 
 205 wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU 
= wx
.NewEventType() 
 207 #-----------------------------------# 
 209 #-----------------------------------# 
 211 EVT_FLATNOTEBOOK_PAGE_CHANGED 
= wx
.EVT_NOTEBOOK_PAGE_CHANGED
 
 212 """Notify client objects when the active page in L{FlatNotebook}  
 214 EVT_FLATNOTEBOOK_PAGE_CHANGING 
= wx
.EVT_NOTEBOOK_PAGE_CHANGING
 
 215 """Notify client objects when the active page in L{FlatNotebook}  
 216 is about to change.""" 
 217 EVT_FLATNOTEBOOK_PAGE_CLOSING 
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, 1) 
 218 """Notify client objects when a page in L{FlatNotebook} is closing.""" 
 219 EVT_FLATNOTEBOOK_PAGE_CLOSED 
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, 1) 
 220 """Notify client objects when a page in L{FlatNotebook} has been closed.""" 
 221 EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU 
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, 1) 
 222 """Notify client objects when a pop-up menu should appear next to a tab.""" 
 225 # Some icons in XPM format 
 227 left_arrow_disabled_xpm 
= [ 
 255 x_button_pressed_xpm 
= [ 
 312 x_button_hilite_xpm 
= [ 
 368 left_arrow_pressed_xpm 
= [ 
 396 left_arrow_hilite_xpm 
= [ 
 424 right_arrow_disabled_xpm 
= [ 
 452 right_arrow_hilite_xpm 
= [ 
 480 right_arrow_pressed_xpm 
= [ 
 537 down_arrow_hilite_xpm 
= [ 
 565 down_arrow_pressed_xpm 
= [ 
 623 #---------------------------------------------------------------------- 
 624 def GetMondrianData(): 
 626 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ 
 627 \x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\ 
 628 ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\ 
 629 o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\ 
 630 \xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\ 
 631 \x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\ 
 632 \x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82'  
 635 def GetMondrianBitmap(): 
 636     return wx
.BitmapFromImage(GetMondrianImage().Scale(16, 16)) 
 639 def GetMondrianImage(): 
 641     stream 
= cStringIO
.StringIO(GetMondrianData()) 
 642     return wx
.ImageFromStream(stream
) 
 645 def GetMondrianIcon(): 
 646     icon 
= wx
.EmptyIcon() 
 647     icon
.CopyFromBitmap(GetMondrianBitmap()) 
 649 #---------------------------------------------------------------------- 
 652 def LightColour(color
, percent
): 
 653     """ Brighten input colour by percent. """ 
 657     rd 
= end_color
.Red() - color
.Red() 
 658     gd 
= end_color
.Green() - color
.Green() 
 659     bd 
= end_color
.Blue() - color
.Blue() 
 663     # We take the percent way of the color from color -. white 
 665     r 
= color
.Red() + ((i
*rd
*100)/high
)/100 
 666     g 
= color
.Green() + ((i
*gd
*100)/high
)/100 
 667     b 
= color
.Blue() + ((i
*bd
*100)/high
)/100 
 668     return wx
.Colour(r
, g
, b
) 
 672     """ Creates a random colour. """ 
 674     r 
= random
.randint(0, 255) # Random value betweem 0-255 
 675     g 
= random
.randint(0, 255) # Random value betweem 0-255 
 676     b 
= random
.randint(0, 255) # Random value betweem 0-255 
 678     return wx
.Colour(r
, g
, b
) 
 681 def PaintStraightGradientBox(dc
, rect
, startColor
, endColor
, vertical
=True): 
 682     """ Draws a gradient colored box from startColor to endColor. """ 
 684     rd 
= endColor
.Red() - startColor
.Red() 
 685     gd 
= endColor
.Green() - startColor
.Green() 
 686     bd 
= endColor
.Blue() - startColor
.Blue() 
 688     # Save the current pen and brush 
 689     savedPen 
= dc
.GetPen() 
 690     savedBrush 
= dc
.GetBrush() 
 693         high 
= rect
.GetHeight()-1 
 695         high 
= rect
.GetWidth()-1 
 700     for i 
in xrange(high
+1): 
 702         r 
= startColor
.Red() + ((i
*rd
*100)/high
)/100 
 703         g 
= startColor
.Green() + ((i
*gd
*100)/high
)/100 
 704         b 
= startColor
.Blue() + ((i
*bd
*100)/high
)/100 
 706         p 
= wx
.Pen(wx
.Colour(r
, g
, b
)) 
 710             dc
.DrawLine(rect
.x
, rect
.y
+i
, rect
.x
+rect
.width
, rect
.y
+i
) 
 712             dc
.DrawLine(rect
.x
+i
, rect
.y
, rect
.x
+i
, rect
.y
+rect
.height
) 
 714     # Restore the pen and brush 
 716     dc
.SetBrush(savedBrush
) 
 719 # ---------------------------------------------------------------------------- # 
 720 # Class FNBDropSource 
 721 # Gives Some Custom UI Feedback during the DnD Operations 
 722 # ---------------------------------------------------------------------------- # 
 724 class FNBDropSource(wx
.DropSource
): 
 726     Give some custom UI feedback during the drag and drop operation in this 
 727     function. It is called on each mouse move, so your implementation must 
 731     def __init__(self
, win
): 
 732         """ Default class constructor. Used internally. """ 
 734         wx
.DropSource
.__init
__(self
, win
) 
 738     def GiveFeedback(self
, effect
): 
 739         """ Provides user with a nice feedback when tab is being dragged. """ 
 741         self
._win
.DrawDragHint() 
 745 # ---------------------------------------------------------------------------- # 
 747 # Stores All The Information To Allow Drag And Drop Between Different 
 749 # ---------------------------------------------------------------------------- # 
 753     _map 
= weakref
.WeakValueDictionary() 
 755     def __init__(self
, container
, pageindex
): 
 756         """ Default class constructor. """ 
 758         self
._id 
= id(container
) 
 759         FNBDragInfo
._map
[self
._id
] = container
 
 760         self
._pageindex 
= pageindex
 
 763     def GetContainer(self
): 
 764         """ Returns the L{FlatNotebook} page (usually a panel). """ 
 766         return FNBDragInfo
._map
.get(self
._id
, None) 
 769     def GetPageIndex(self
): 
 770         """ Returns the page index associated with a page. """ 
 772         return self
._pageindex        
 
 775 # ---------------------------------------------------------------------------- # 
 776 # Class FNBDropTarget 
 777 # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between 
 778 # Different FlatNotebooks. 
 779 # ---------------------------------------------------------------------------- # 
 781 class FNBDropTarget(wx
.DropTarget
): 
 783     def __init__(self
, parent
): 
 784         """ Default class constructor. """ 
 786         wx
.DropTarget
.__init
__(self
) 
 788         self
._parent 
= parent
 
 789         self
._dataobject 
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook")) 
 790         self
.SetDataObject(self
._dataobject
) 
 793     def OnData(self
, x
, y
, dragres
): 
 794         """ Handles the OnData() method to call the real DnD routine. """ 
 796         if not self
.GetData(): 
 799         draginfo 
= self
._dataobject
.GetData() 
 800         drginfo 
= cPickle
.loads(draginfo
) 
 802         return self
._parent
.OnDropTarget(x
, y
, drginfo
.GetPageIndex(), drginfo
.GetContainer()) 
 805 # ---------------------------------------------------------------------------- # 
 807 # Contains parameters for every FlatNotebook page 
 808 # ---------------------------------------------------------------------------- # 
 812     This class holds all the information (caption, image, etc...) belonging to a 
 813     single tab in L{FlatNotebook}. 
 816     def __init__(self
, caption
="", imageindex
=-1, tabangle
=0, enabled
=True): 
 818         Default Class Constructor. 
 821         @param caption: the tab caption; 
 822         @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any); 
 823         @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees); 
 824         @param enabled: sets enabled or disabled the tab. 
 827         self
._strCaption 
= caption
 
 828         self
._TabAngle 
= tabangle
 
 829         self
._ImageIndex 
= imageindex
 
 830         self
._bEnabled 
= enabled
 
 831         self
._pos 
= wx
.Point(-1, -1) 
 832         self
._size 
= wx
.Size(-1, -1) 
 833         self
._region 
= wx
.Region() 
 834         self
._xRect 
= wx
.Rect() 
 838     def SetCaption(self
, value
): 
 839         """ Sets the tab caption. """ 
 841         self
._strCaption 
= value
 
 844     def GetCaption(self
): 
 845         """ Returns the tab caption. """ 
 847         return self
._strCaption
 
 850     def SetPosition(self
, value
): 
 851         """ Sets the tab position. """ 
 856     def GetPosition(self
): 
 857         """ Returns the tab position. """ 
 862     def SetSize(self
, value
): 
 863         """ Sets the tab size. """ 
 869         """ Returns the tab size. """ 
 874     def SetTabAngle(self
, value
): 
 875         """ Sets the tab header angle (0 <= tab <= 15 degrees). """ 
 877         self
._TabAngle 
= min(45, value
) 
 880     def GetTabAngle(self
): 
 881         """ Returns the tab angle. """ 
 883         return self
._TabAngle
 
 886     def SetImageIndex(self
, value
): 
 887         """ Sets the tab image index. """ 
 889         self
._ImageIndex 
= value
 
 892     def GetImageIndex(self
): 
 893         """ Returns the tab umage index. """ 
 895         return self
._ImageIndex
 
 898     def GetEnabled(self
): 
 899         """ Returns whether the tab is enabled or not. """ 
 901         return self
._bEnabled 
 
 904     def Enable(self
, enabled
): 
 905         """ Sets the tab enabled or disabled. """ 
 907         self
._bEnabled 
= enabled 
 
 910     def SetRegion(self
, points
=[]): 
 911         """ Sets the tab region. """ 
 913         self
._region 
= wx
.RegionFromPoints(points
)  
 917         """ Returns the tab region. """ 
 922     def SetXRect(self
, xrect
): 
 923         """ Sets the button 'X' area rect. """ 
 929         """ Returns the button 'X' area rect. """ 
 935         """ Returns the tab colour. """ 
 940     def SetColour(self
, color
): 
 941         """ Sets the tab colour. """ 
 946 # ---------------------------------------------------------------------------- # 
 947 # Class FlatNotebookEvent 
 948 # ---------------------------------------------------------------------------- # 
 950 class FlatNotebookEvent(wx
.PyCommandEvent
): 
 952     This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED, 
 953     EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING, 
 954     EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is 
 955     mapped in the parent. 
 958     def __init__(self
, eventType
, id=1, nSel
=-1, nOldSel
=-1): 
 959         """ Default class constructor. """ 
 961         wx
.PyCommandEvent
.__init
__(self
, eventType
, id) 
 962         self
._eventType 
= eventType
 
 964         self
.notify 
= wx
.NotifyEvent(eventType
, id) 
 967     def GetNotifyEvent(self
): 
 968         """Returns the actual wx.NotifyEvent.""" 
 974         """Returns whether the event is allowed or not.""" 
 976         return self
.notify
.IsAllowed() 
 980         """Vetos the event.""" 
 986         """The event is allowed.""" 
 991     def SetSelection(self
, nSel
): 
 992         """ Sets event selection. """ 
 994         self
._selection 
= nSel
 
 997     def SetOldSelection(self
, nOldSel
): 
 998         """ Sets old event selection. """ 
1000         self
._oldselection 
= nOldSel
 
1003     def GetSelection(self
): 
1004         """ Returns event selection. """ 
1006         return self
._selection
 
1009     def GetOldSelection(self
): 
1010         """ Returns old event selection """ 
1012         return self
._oldselection
 
1015 # ---------------------------------------------------------------------------- # 
1016 # Class TabNavigatorWindow 
1017 # ---------------------------------------------------------------------------- # 
1019 class TabNavigatorWindow(wx
.Dialog
): 
1021     This class is used to create a modal dialog that enables "Smart Tabbing", 
1022     similar to what you would get by hitting Alt+Tab on Windows. 
1025     def __init__(self
, parent
=None): 
1026         """ Default class constructor. Used internally.""" 
1028         wx
.Dialog
.__init
__(self
, parent
, wx
.ID_ANY
, "", style
=0) 
1030         self
._selectedItem 
= -1 
1033         self
._bmp 
= GetMondrianBitmap() 
1035         sz 
= wx
.BoxSizer(wx
.VERTICAL
) 
1037         self
._listBox 
= wx
.ListBox(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, 150), [], wx
.LB_SINGLE | wx
.NO_BORDER
) 
1039         mem_dc 
= wx
.MemoryDC() 
1040         mem_dc
.SelectObject(wx
.EmptyBitmap(1,1)) 
1041         font 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
1042         font
.SetWeight(wx
.BOLD
) 
1043         mem_dc
.SetFont(font
) 
1045         panelHeight 
= mem_dc
.GetCharHeight() 
1046         panelHeight 
+= 4 # Place a spacer of 2 pixels 
1048         # Out signpost bitmap is 24 pixels 
1049         if panelHeight 
< 24: 
1052         self
._panel 
= wx
.Panel(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, panelHeight
)) 
1055         sz
.Add(self
._listBox
, 1, wx
.EXPAND
) 
1059         # Connect events to the list box 
1060         self
._listBox
.Bind(wx
.EVT_KEY_UP
, self
.OnKeyUp
) 
1061         self
._listBox
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
) 
1062         self
._listBox
.Bind(wx
.EVT_LISTBOX_DCLICK
, self
.OnItemSelected
) 
1064         # Connect paint event to the panel 
1065         self
._panel
.Bind(wx
.EVT_PAINT
, self
.OnPanelPaint
) 
1066         self
._panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnPanelEraseBg
) 
1068         self
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)) 
1069         self
._listBox
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)) 
1070         self
.PopulateListControl(parent
) 
1072         self
.GetSizer().Fit(self
) 
1073         self
.GetSizer().SetSizeHints(self
) 
1074         self
.GetSizer().Layout() 
1078     def OnKeyUp(self
, event
): 
1079         """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}.""" 
1081         if event
.GetKeyCode() == wx
.WXK_CONTROL
: 
1085     def OnNavigationKey(self
, event
): 
1086         """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """ 
1088         selected 
= self
._listBox
.GetSelection() 
1089         bk 
= self
.GetParent() 
1090         maxItems 
= bk
.GetPageCount() 
1092         if event
.GetDirection(): 
1095             if selected 
== maxItems 
- 1: 
1098                 itemToSelect 
= selected 
+ 1 
1104                 itemToSelect 
= maxItems 
- 1 
1106                 itemToSelect 
= selected 
- 1 
1108         self
._listBox
.SetSelection(itemToSelect
) 
1111     def PopulateListControl(self
, book
): 
1112         """Populates the L{TabNavigatorWindow} listbox with a list of tabs.""" 
1114         selection 
= book
.GetSelection() 
1115         count 
= book
.GetPageCount() 
1117         self
._listBox
.Append(book
.GetPageText(selection
)) 
1118         self
._indexMap
.append(selection
) 
1120         prevSel 
= book
.GetPreviousSelection() 
1122         if prevSel 
!= wx
.NOT_FOUND
: 
1124             # Insert the previous selection as second entry  
1125             self
._listBox
.Append(book
.GetPageText(prevSel
)) 
1126             self
._indexMap
.append(prevSel
) 
1128         for c 
in xrange(count
): 
1130             # Skip selected page 
1134             # Skip previous selected page as well 
1138             self
._listBox
.Append(book
.GetPageText(c
)) 
1139             self
._indexMap
.append(c
) 
1141         # Select the next entry after the current selection 
1142         self
._listBox
.SetSelection(0) 
1143         dummy 
= wx
.NavigationKeyEvent() 
1144         dummy
.SetDirection(True) 
1145         self
.OnNavigationKey(dummy
) 
1148     def OnItemSelected(self
, event
): 
1149         """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """ 
1154     def CloseDialog(self
): 
1155         """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}.""" 
1157         bk 
= self
.GetParent() 
1158         self
._selectedItem 
= self
._listBox
.GetSelection() 
1159         iter = self
._indexMap
[self
._selectedItem
] 
1160         bk
._pages
.FireEvent(iter) 
1161         self
.EndModal(wx
.ID_OK
) 
1164     def OnPanelPaint(self
, event
): 
1165         """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """ 
1167         dc 
= wx
.PaintDC(self
._panel
) 
1168         rect 
= self
._panel
.GetClientRect() 
1170         bmp 
= wx
.EmptyBitmap(rect
.width
, rect
.height
) 
1172         mem_dc 
= wx
.MemoryDC() 
1173         mem_dc
.SelectObject(bmp
) 
1175         endColour 
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
) 
1176         startColour 
= LightColour(endColour
, 50) 
1177         PaintStraightGradientBox(mem_dc
, rect
, startColour
, endColour
) 
1179         # Draw the caption title and place the bitmap 
1180         # get the bitmap optimal position, and draw it 
1181         bmpPt
, txtPt 
= wx
.Point(), wx
.Point() 
1182         bmpPt
.y 
= (rect
.height 
- self
._bmp
.GetHeight())/2 
1184         mem_dc
.DrawBitmap(self
._bmp
, bmpPt
.x
, bmpPt
.y
, True) 
1186         # get the text position, and draw it 
1187         font 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
1188         font
.SetWeight(wx
.BOLD
) 
1189         mem_dc
.SetFont(font
) 
1190         fontHeight 
= mem_dc
.GetCharHeight() 
1192         txtPt
.x 
= bmpPt
.x 
+ self
._bmp
.GetWidth() + 4 
1193         txtPt
.y 
= (rect
.height 
- fontHeight
)/2 
1194         mem_dc
.SetTextForeground(wx
.WHITE
) 
1195         mem_dc
.DrawText("Opened tabs:", txtPt
.x
, txtPt
.y
) 
1196         mem_dc
.SelectObject(wx
.NullBitmap
) 
1198         dc
.DrawBitmap(bmp
, 0, 0) 
1201     def OnPanelEraseBg(self
, event
): 
1202         """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """ 
1207 # ---------------------------------------------------------------------------- # 
1209 # ---------------------------------------------------------------------------- # 
1213     Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy} 
1214     and I{VC8}. This class implements the common methods of all 4 renderers. 
1215     @undocumented: _GetBitmap* 
1219         """Default class constructor. """ 
1221         self
._tabXBgBmp 
= wx
.EmptyBitmap(16, 16) 
1222         self
._xBgBmp 
= wx
.EmptyBitmap(16, 14) 
1223         self
._leftBgBmp 
= wx
.EmptyBitmap(16, 14) 
1224         self
._rightBgBmp 
= wx
.EmptyBitmap(16, 14) 
1225         self
._tabHeight 
= None 
1228     def GetLeftButtonPos(self
, pageContainer
): 
1229         """ Returns the left button position in the navigation area. """ 
1232         style 
= pc
.GetParent().GetWindowStyleFlag() 
1233         rect 
= pc
.GetClientRect() 
1234         clientWidth 
= rect
.width
 
1236         if style 
& FNB_NO_X_BUTTON
: 
1237             return clientWidth 
- 38 
1239             return clientWidth 
- 54 
1243     def GetRightButtonPos(self
, pageContainer
): 
1244         """ Returns the right button position in the navigation area. """ 
1247         style 
= pc
.GetParent().GetWindowStyleFlag() 
1248         rect 
= pc
.GetClientRect() 
1249         clientWidth 
= rect
.width
 
1251         if style 
& FNB_NO_X_BUTTON
: 
1252             return clientWidth 
- 22 
1254             return clientWidth 
- 38 
1257     def GetDropArrowButtonPos(self
, pageContainer
): 
1258         """ Returns the drop down button position in the navigation area. """ 
1260         return self
.GetRightButtonPos(pageContainer
) 
1263     def GetXPos(self
, pageContainer
): 
1264         """ Returns the 'X' button position in the navigation area. """ 
1267         style 
= pc
.GetParent().GetWindowStyleFlag() 
1268         rect 
= pc
.GetClientRect() 
1269         clientWidth 
= rect
.width
 
1271         if style 
& FNB_NO_X_BUTTON
: 
1274             return clientWidth 
- 22 
1277     def GetButtonsAreaLength(self
, pageContainer
): 
1278         """ Returns the navigation area width. """ 
1281         style 
= pc
.GetParent().GetWindowStyleFlag() 
1284         if style 
& FNB_NO_NAV_BUTTONS 
and style 
& FNB_NO_X_BUTTON 
and not style 
& FNB_DROPDOWN_TABS_LIST
: 
1288         elif style 
& FNB_NO_NAV_BUTTONS 
and not style 
& FNB_NO_X_BUTTON 
and not style 
& FNB_DROPDOWN_TABS_LIST
: 
1292         if not style 
& FNB_NO_NAV_BUTTONS 
and style 
& FNB_NO_X_BUTTON 
and not style 
& FNB_DROPDOWN_TABS_LIST
: 
1296         if style 
& FNB_DROPDOWN_TABS_LIST 
and not style 
& FNB_NO_X_BUTTON
: 
1300         if style 
& FNB_DROPDOWN_TABS_LIST 
and style 
& FNB_NO_X_BUTTON
: 
1307     def DrawLeftArrow(self
, pageContainer
, dc
): 
1308         """ Draw the left navigation arrow. """ 
1312         style 
= pc
.GetParent().GetWindowStyleFlag() 
1313         if style 
& FNB_NO_NAV_BUTTONS
: 
1316         # Make sure that there are pages in the container 
1317         if not pc
._pagesInfoVec
: 
1320         # Set the bitmap according to the button status 
1321         if pc
._nLeftButtonStatus 
== FNB_BTN_HOVER
: 
1322             arrowBmp 
= wx
.BitmapFromXPMData(left_arrow_hilite_xpm
) 
1323         elif pc
._nLeftButtonStatus 
== FNB_BTN_PRESSED
: 
1324             arrowBmp 
= wx
.BitmapFromXPMData(left_arrow_pressed_xpm
) 
1326             arrowBmp 
= wx
.BitmapFromXPMData(left_arrow_xpm
) 
1329             # Handle disabled arrow 
1330             arrowBmp 
= wx
.BitmapFromXPMData(left_arrow_disabled_xpm
) 
1332         arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
)) 
1335         posx 
= self
.GetLeftButtonPos(pc
) 
1336         dc
.DrawBitmap(self
._leftBgBmp
, posx
, 6) 
1338         # Draw the new bitmap 
1339         dc
.DrawBitmap(arrowBmp
, posx
, 6, True) 
1342     def DrawRightArrow(self
, pageContainer
, dc
): 
1343         """ Draw the right navigation arrow. """ 
1347         style 
= pc
.GetParent().GetWindowStyleFlag() 
1348         if style 
& FNB_NO_NAV_BUTTONS
: 
1351         # Make sure that there are pages in the container 
1352         if not pc
._pagesInfoVec
: 
1355         # Set the bitmap according to the button status 
1356         if pc
._nRightButtonStatus 
== FNB_BTN_HOVER
:         
1357             arrowBmp 
= wx
.BitmapFromXPMData(right_arrow_hilite_xpm
) 
1358         elif pc
._nRightButtonStatus 
== FNB_BTN_PRESSED
: 
1359             arrowBmp 
= wx
.BitmapFromXPMData(right_arrow_pressed_xpm
) 
1361             arrowBmp 
= wx
.BitmapFromXPMData(right_arrow_xpm
) 
1363         # Check if the right most tab is visible, if it is 
1364         # don't rotate right anymore 
1365         if pc
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1): 
1366             arrowBmp 
= wx
.BitmapFromXPMData(right_arrow_disabled_xpm
) 
1368         arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
)) 
1371         posx 
= self
.GetRightButtonPos(pc
) 
1372         dc
.DrawBitmap(self
._rightBgBmp
, posx
, 6) 
1374         # Draw the new bitmap 
1375         dc
.DrawBitmap(arrowBmp
, posx
, 6, True) 
1378     def DrawDropDownArrow(self
, pageContainer
, dc
): 
1379         """ Draws the drop-down arrow in the navigation area. """ 
1383         # Check if this style is enabled 
1384         style 
= pc
.GetParent().GetWindowStyleFlag() 
1385         if not style 
& FNB_DROPDOWN_TABS_LIST
: 
1388         # Make sure that there are pages in the container 
1389         if not pc
._pagesInfoVec
: 
1392         if pc
._nArrowDownButtonStatus 
== FNB_BTN_HOVER
: 
1393             downBmp 
= wx
.BitmapFromXPMData(down_arrow_hilite_xpm
) 
1394         elif pc
._nArrowDownButtonStatus 
== FNB_BTN_PRESSED
: 
1395             downBmp 
= wx
.BitmapFromXPMData(down_arrow_pressed_xpm
) 
1397             downBmp 
= wx
.BitmapFromXPMData(down_arrow_xpm
) 
1399         downBmp
.SetMask(wx
.Mask(downBmp
, MASK_COLOR
)) 
1402         posx 
= self
.GetDropArrowButtonPos(pc
) 
1403         dc
.DrawBitmap(self
._xBgBmp
, posx
, 6) 
1405         # Draw the new bitmap 
1406         dc
.DrawBitmap(downBmp
, posx
, 6, True) 
1409     def DrawX(self
, pageContainer
, dc
): 
1410         """ Draw the 'X' navigation button in the navigation area. """ 
1414         # Check if this style is enabled 
1415         style 
= pc
.GetParent().GetWindowStyleFlag() 
1416         if style 
& FNB_NO_X_BUTTON
: 
1419         # Make sure that there are pages in the container 
1420         if not pc
._pagesInfoVec
: 
1423         # Set the bitmap according to the button status 
1424         if pc
._nXButtonStatus 
== FNB_BTN_HOVER
: 
1425             xbmp 
= wx
.BitmapFromXPMData(x_button_hilite_xpm
) 
1426         elif pc
._nXButtonStatus 
== FNB_BTN_PRESSED
: 
1427             xbmp 
= wx
.BitmapFromXPMData(x_button_pressed_xpm
) 
1429             xbmp 
= wx
.BitmapFromXPMData(x_button_xpm
) 
1431         xbmp
.SetMask(wx
.Mask(xbmp
, MASK_COLOR
)) 
1434         posx 
= self
.GetXPos(pc
)  
1435         dc
.DrawBitmap(self
._xBgBmp
, posx
, 6) 
1437         # Draw the new bitmap 
1438         dc
.DrawBitmap(xbmp
, posx
, 6, True) 
1441     def DrawTabX(self
, pageContainer
, dc
, rect
, tabIdx
, btnStatus
): 
1442         """ Draws the 'X' in the selected tab. """ 
1445         if not pc
.HasFlag(FNB_X_ON_TAB
): 
1448         # We draw the 'x' on the active tab only 
1449         if tabIdx 
!= pc
.GetSelection() or tabIdx 
< 0: 
1452         # Set the bitmap according to the button status 
1454         if btnStatus 
== FNB_BTN_HOVER
: 
1455             xBmp 
= wx
.BitmapFromXPMData(x_button_hilite_xpm
) 
1456         elif btnStatus 
== FNB_BTN_PRESSED
: 
1457             xBmp 
= wx
.BitmapFromXPMData(x_button_pressed_xpm
) 
1459             xBmp 
= wx
.BitmapFromXPMData(x_button_xpm
) 
1462         xBmp
.SetMask(wx
.Mask(xBmp
, MASK_COLOR
)) 
1465         dc
.DrawBitmap(self
._tabXBgBmp
, rect
.x
, rect
.y
) 
1467         # Draw the new bitmap 
1468         dc
.DrawBitmap(xBmp
, rect
.x
, rect
.y
, True) 
1471         rr 
= wx
.Rect(rect
.x
, rect
.y
, 14, 13) 
1472         pc
._pagesInfoVec
[tabIdx
].SetXRect(rr
) 
1475     def _GetBitmap(self
, dc
, rect
, bmp
): 
1477         mem_dc 
= wx
.MemoryDC() 
1478         mem_dc
.SelectObject(bmp
) 
1479         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
1480         mem_dc
.SelectObject(wx
.NullBitmap
) 
1484     def DrawTabsLine(self
, pageContainer
, dc
): 
1485         """ Draws a line over the tabs. """ 
1489         clntRect 
= pc
.GetClientRect() 
1490         clientRect3 
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
) 
1492         if pc
.HasFlag(FNB_BOTTOM
): 
1494             clientRect 
= wx
.Rect(0, 2, clntRect
.width
, clntRect
.height 
- 2) 
1495             clientRect2 
= wx
.Rect(0, 1, clntRect
.width
, clntRect
.height 
- 1) 
1499             clientRect 
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height 
- 2) 
1500             clientRect2 
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height 
- 1) 
1502         dc
.SetBrush(wx
.TRANSPARENT_BRUSH
) 
1503         dc
.SetPen(wx
.Pen(pc
.GetSingleLineBorderColour())) 
1504         dc
.DrawRectangleRect(clientRect2
) 
1505         dc
.DrawRectangleRect(clientRect3
) 
1507         dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))) 
1508         dc
.DrawRectangleRect(clientRect
) 
1510         if not pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
): 
1512             dc
.SetPen(wx
.Pen((pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
._tabAreaColor
])[0])) 
1513             dc
.DrawLine(0, 0, 0, clientRect
.height
+1) 
1515             if pc
.HasFlag(FNB_BOTTOM
): 
1517                 dc
.DrawLine(0, clientRect
.height
+1, clientRect
.width
, clientRect
.height
+1) 
1521                 dc
.DrawLine(0, 0, clientRect
.width
, 0) 
1523             dc
.DrawLine(clientRect
.width 
- 1, 0, clientRect
.width 
- 1, clientRect
.height
+1) 
1526     def CalcTabWidth(self
, pageContainer
, tabIdx
, tabHeight
): 
1527         """ Calculates the width of the input tab. """ 
1531         dc
.SelectObject(wx
.EmptyBitmap(1,1)) 
1533         boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
1534         boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
1536         if pc
.IsDefaultTabs(): 
1537             shapePoints 
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
)) 
1539         # Calculate the text length using the bold font, so when selecting a tab 
1540         # its width will not change 
1541         dc
.SetFont(boldFont
) 
1542         width
, pom 
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
)) 
1544         # Set a minimum size to a tab 
1548         tabWidth 
= 2*pc
._pParent
.GetPadding() + width
 
1550         # Style to add a small 'x' button on the top right 
1552         if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx 
== pc
.GetSelection(): 
1553             # The xpm image that contains the 'x' button is 9 pixels 
1555             if pc
.HasFlag(FNB_VC8
): 
1558             tabWidth 
+= pc
._pParent
.GetPadding() + spacer
 
1560         if pc
.IsDefaultTabs(): 
1562             tabWidth 
+= 2*shapePoints
 
1564         hasImage 
= pc
._ImageList 
!= None and pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1 
1566         # For VC71 style, we only add the icon size (16 pixels) 
1569             if not pc
.IsDefaultTabs(): 
1570                 tabWidth 
+= 16 + pc
._pParent
.GetPadding() 
1573                 tabWidth 
+= 16 + pc
._pParent
.GetPadding() + shapePoints
/2 
1578     def CalcTabHeight(self
, pageContainer
): 
1579         """ Calculates the height of the input tab. """ 
1582             return self
._tabHeight
 
1586         dc
.SelectObject(wx
.EmptyBitmap(1,1)) 
1588         # For GTK it seems that we must do this steps in order 
1589         # for the tabs will get the proper height on initialization 
1590         # on MSW, preforming these steps yields wierd results 
1591         normalFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
1592         boldFont 
= normalFont
 
1594         if "__WXGTK__" in wx
.PlatformInfo
: 
1595             boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
1596             dc
.SetFont(boldFont
) 
1598         height 
= dc
.GetCharHeight() 
1600         tabHeight 
= height 
+ FNB_HEIGHT_SPACER 
# We use 8 pixels as padding 
1601         if "__WXGTK__" in wx
.PlatformInfo
: 
1602             # On GTK the tabs are should be larger 
1605         self
._tabHeight 
= tabHeight
 
1610     def DrawTabs(self
, pageContainer
, dc
): 
1611         """ Actually draws the tabs in L{FlatNotebook}.""" 
1614         if "__WXMAC__" in wx
.PlatformInfo
: 
1615             # Works well on MSW & GTK, however this lines should be skipped on MAC 
1616             if not pc
._pagesInfoVec 
or pc
._nFrom 
>= len(pc
._pagesInfoVec
): 
1620         # Get the text hight 
1621         tabHeight 
= self
.CalcTabHeight(pageContainer
) 
1622         style 
= pc
.GetParent().GetWindowStyleFlag() 
1624         # Calculate the number of rows required for drawing the tabs 
1625         rect 
= pc
.GetClientRect() 
1626         clientWidth 
= rect
.width
 
1628         # Set the maximum client size 
1629         pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
) 
1630         borderPen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)) 
1632         if style 
& FNB_VC71
: 
1633             backBrush 
= wx
.Brush(wx
.Colour(247, 243, 233)) 
1635             backBrush 
= wx
.Brush(pc
._tabAreaColor
) 
1637         noselBrush 
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
)) 
1638         selBrush 
= wx
.Brush(pc
._activeTabColor
) 
1643         dc
.SetTextBackground((style 
& FNB_VC71 
and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0]) 
1644         dc
.SetTextForeground(pc
._activeTextColor
) 
1645         dc
.SetBrush(backBrush
) 
1647         # If border style is set, set the pen to be border pen 
1648         if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
): 
1649             dc
.SetPen(borderPen
) 
1651             colr 
= (pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0] 
1652             dc
.SetPen(wx
.Pen(colr
)) 
1654         dc
.DrawRectangle(0, 0, size
.x
, size
.y
) 
1656         # Take 3 bitmaps for the background for the buttons 
1658         mem_dc 
= wx
.MemoryDC() 
1659         #--------------------------------------- 
1661         #--------------------------------------- 
1662         rect 
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14) 
1663         mem_dc
.SelectObject(self
._xBgBmp
) 
1664         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
1665         mem_dc
.SelectObject(wx
.NullBitmap
) 
1667         #--------------------------------------- 
1669         #--------------------------------------- 
1670         rect 
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14) 
1671         mem_dc
.SelectObject(self
._rightBgBmp
) 
1672         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
1673         mem_dc
.SelectObject(wx
.NullBitmap
) 
1675         #--------------------------------------- 
1677         #--------------------------------------- 
1678         rect 
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14) 
1679         mem_dc
.SelectObject(self
._leftBgBmp
) 
1680         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
1681         mem_dc
.SelectObject(wx
.NullBitmap
) 
1683         # We always draw the bottom/upper line of the tabs 
1684         # regradless the style 
1685         dc
.SetPen(borderPen
) 
1686         self
.DrawTabsLine(pc
, dc
) 
1689         dc
.SetPen(borderPen
) 
1691         if pc
.HasFlag(FNB_VC71
): 
1693             greyLineYVal  
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [size
.y 
- 2])[0] 
1694             whiteLineYVal 
= (pc
.HasFlag(FNB_BOTTOM
) and [3] or [size
.y 
- 3])[0] 
1696             pen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)) 
1699             # Draw thik grey line between the windows area and 
1701             for num 
in xrange(3): 
1702                 dc
.DrawLine(0, greyLineYVal 
+ num
, size
.x
, greyLineYVal 
+ num
) 
1704             wbPen 
= (pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK_PEN
] or [wx
.WHITE_PEN
])[0] 
1706             dc
.DrawLine(1, whiteLineYVal
, size
.x 
- 1, whiteLineYVal
) 
1709             dc
.SetPen(borderPen
) 
1712         normalFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
1713         boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
1714         boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
1715         dc
.SetFont(boldFont
) 
1717         posx 
= pc
._pParent
.GetPadding() 
1719         # Update all the tabs from 0 to 'pc._nFrom' to be non visible 
1720         for i 
in xrange(pc
._nFrom
): 
1722             pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1)) 
1723             pc
._pagesInfoVec
[i
].GetRegion().Clear() 
1727         #---------------------------------------------------------- 
1728         # Go over and draw the visible tabs 
1729         #---------------------------------------------------------- 
1730         for i 
in xrange(pc
._nFrom
, len(pc
._pagesInfoVec
)): 
1732             dc
.SetPen(borderPen
) 
1733             dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0]) 
1735             # Now set the font to the correct font 
1736             dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0]) 
1738             # Add the padding to the tab width 
1740             # +-----------------------------------------------------------+ 
1741             # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING | 
1742             # +-----------------------------------------------------------+ 
1743             tabWidth 
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
) 
1745             # Check if we can draw more 
1746             if posx 
+ tabWidth 
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
: 
1751             # By default we clean the tab region 
1752             pc
._pagesInfoVec
[i
].GetRegion().Clear() 
1754             # Clean the 'x' buttn on the tab. 
1755             # A 'Clean' rectangle, is a rectangle with width or height 
1756             # with values lower than or equal to 0 
1757             pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1)) 
1759             # Draw the tab (border, text, image & 'x' on tab) 
1760             self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
) 
1762             # Restore the text forground 
1763             dc
.SetTextForeground(pc
._activeTextColor
) 
1765             # Update the tab position & size 
1766             posy 
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0] 
1768             pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, posy
)) 
1769             pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
)) 
1772         # Update all tabs that can not fit into the screen as non-visible 
1773         for i 
in xrange(count
, len(pc
._pagesInfoVec
)): 
1774             pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1)) 
1775             pc
._pagesInfoVec
[i
].GetRegion().Clear() 
1777         # Draw the left/right/close buttons 
1779         self
.DrawLeftArrow(pc
, dc
) 
1780         self
.DrawRightArrow(pc
, dc
) 
1782         self
.DrawDropDownArrow(pc
, dc
) 
1785     def DrawDragHint(self
, pc
, tabIdx
): 
1787         Draws tab drag hint, the default implementation is to do nothing. 
1788         You can override this function to provide a nice feedback to user. 
1794     def NumberTabsCanFit(self
, pageContainer
, fr
=-1): 
1798         rect 
= pc
.GetClientRect() 
1799         clientWidth 
= rect
.width
 
1803         tabHeight 
= self
.CalcTabHeight(pageContainer
) 
1805         # The drawing starts from posx  
1806         posx 
= pc
._pParent
.GetPadding() 
1811         for i 
in xrange(fr
, len(pc
._pagesInfoVec
)): 
1813             tabWidth 
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)  
1814             if posx 
+ tabWidth 
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
: 
1817             # Add a result to the returned vector  
1818             tabRect 
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth 
, tabHeight
) 
1819             vTabInfo
.append(tabRect
) 
1822             posx 
+= tabWidth 
+ FNB_HEIGHT_SPACER
 
1827 # ---------------------------------------------------------------------------- # 
1828 # Class FNBRendererMgr 
1829 # A manager that handles all the renderers defined below and calls the 
1830 # appropriate one when drawing is needed 
1831 # ---------------------------------------------------------------------------- # 
1833 class FNBRendererMgr
: 
1835     This class represents a manager that handles all the 4 renderers defined 
1836     and calls the appropriate one when drawing is needed. 
1840         """ Default class constructor. """ 
1842         # register renderers 
1844         self
._renderers 
= {}         
1845         self
._renderers
.update({-1: FNBRendererDefault()}
) 
1846         self
._renderers
.update({FNB_VC71: FNBRendererVC71()}
) 
1847         self
._renderers
.update({FNB_FANCY_TABS: FNBRendererFancy()}
) 
1848         self
._renderers
.update({FNB_VC8: FNBRendererVC8()}
) 
1851     def GetRenderer(self
, style
): 
1852         """ Returns the current renderer based on the style selected. """ 
1854         # since we dont have a style for default tabs, we  
1855         # test for all others - FIXME: add style for default tabs 
1856         if not style 
& FNB_VC71 
and not style 
& FNB_VC8 
and not style 
& FNB_FANCY_TABS
: 
1857             return self
._renderers
[-1] 
1859         if style 
& FNB_VC71
: 
1860             return self
._renderers
[FNB_VC71
] 
1862         if style 
& FNB_FANCY_TABS
: 
1863             return self
._renderers
[FNB_FANCY_TABS
] 
1866             return self
._renderers
[FNB_VC8
] 
1868         # the default is to return the default renderer 
1869         return self
._renderers
[-1] 
1872 #------------------------------------------ 
1874 #------------------------------------------ 
1876 class FNBRendererDefault(FNBRenderer
): 
1878     This class handles the drawing of tabs using the I{Standard} renderer. 
1882         """ Default class constructor. """ 
1884         FNBRenderer
.__init
__(self
) 
1887     def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
): 
1888         """ Draws a tab using the I{Standard} style. """ 
1891         borderPen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)) 
1894         tabPoints 
= [wx
.Point() for ii 
in xrange(7)] 
1895         tabPoints
[0].x 
= posx
 
1896         tabPoints
[0].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight 
- 2])[0] 
1898         tabPoints
[1].x 
= int(posx
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
)) 
1899         tabPoints
[1].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0] 
1901         tabPoints
[2].x 
= tabPoints
[1].x
+2 
1902         tabPoints
[2].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0] 
1904         tabPoints
[3].x 
= int(posx
+tabWidth
-(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))-2 
1905         tabPoints
[3].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0] 
1907         tabPoints
[4].x 
= tabPoints
[3].x
+2 
1908         tabPoints
[4].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0] 
1910         tabPoints
[5].x 
= int(tabPoints
[4].x
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
)) 
1911         tabPoints
[5].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight 
- 2])[0] 
1913         tabPoints
[6].x 
= tabPoints
[0].x
 
1914         tabPoints
[6].y 
= tabPoints
[0].y
 
1916         if tabIdx 
== pc
.GetSelection(): 
1918             # Draw the tab as rounded rectangle 
1919             dc
.DrawPolygon(tabPoints
) 
1923             if tabIdx 
!= pc
.GetSelection() - 1: 
1925                 # Draw a vertical line to the right of the text 
1926                 pt1x 
= tabPoints
[5].x
 
1927                 pt1y 
= (pc
.HasFlag(FNB_BOTTOM
) and [4] or [tabHeight 
- 6])[0] 
1928                 pt2x 
= tabPoints
[5].x
 
1929                 pt2y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- 4] or [4])[0] 
1930                 dc
.DrawLine(pt1x
, pt1y
, pt2x
, pt2y
) 
1932         if tabIdx 
== pc
.GetSelection(): 
1934             savePen 
= dc
.GetPen() 
1935             whitePen 
= wx
.Pen(wx
.WHITE
) 
1936             whitePen
.SetWidth(1) 
1939             secPt 
= wx
.Point(tabPoints
[5].x 
+ 1, tabPoints
[5].y
) 
1940             dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, secPt
.x
, secPt
.y
) 
1945         # ----------------------------------- 
1946         # Text and image drawing 
1947         # ----------------------------------- 
1949         # Text drawing offset from the left border of the 
1952         # The width of the images are 16 pixels 
1953         padding 
= pc
.GetParent().GetPadding() 
1954         shapePoints 
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
)) 
1955         hasImage 
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1 
1956         imageYCoord 
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0] 
1959             textOffset 
= 2*pc
._pParent
._nPadding 
+ 16 + shapePoints
/2  
1961             textOffset 
= pc
._pParent
._nPadding 
+ shapePoints
/2  
1965         if tabIdx 
!= pc
.GetSelection(): 
1967             # Set the text background to be like the vertical lines 
1968             dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour()) 
1972             imageXOffset 
= textOffset 
- 16 - padding
 
1973             pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
, 
1974                                      posx 
+ imageXOffset
, imageYCoord
, 
1975                                      wx
.IMAGELIST_DRAW_TRANSPARENT
, True) 
1977         dc
.DrawText(pc
.GetPageText(tabIdx
), posx 
+ textOffset
, imageYCoord
) 
1979         # draw 'x' on tab (if enabled) 
1980         if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx 
== pc
.GetSelection(): 
1982             textWidth
, textHeight 
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
)) 
1983             tabCloseButtonXCoord 
= posx 
+ textOffset 
+ textWidth 
+ 1 
1985             # take a bitmap from the position of the 'x' button (the x on tab button) 
1986             # this bitmap will be used later to delete old buttons 
1987             tabCloseButtonYCoord 
= imageYCoord
 
1988             x_rect 
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16) 
1989             self
._tabXBgBmp 
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
) 
1992             self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)             
1995 #------------------------------------------------------------------ 
1997 #------------------------------------------------------------------ 
1999 class FNBRendererVC71(FNBRenderer
): 
2001     This class handles the drawing of tabs using the I{VC71} renderer. 
2005         """ Default class constructor. """ 
2007         FNBRenderer
.__init
__(self
) 
2010     def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
): 
2011         """ Draws a tab using the I{VC71} style. """ 
2013         # Visual studio 7.1 style 
2014         borderPen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)) 
2017         dc
.SetPen((tabIdx 
== pc
.GetSelection() and [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [borderPen
])[0]) 
2018         dc
.SetBrush((tabIdx 
== pc
.GetSelection() and [wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [wx
.Brush(wx
.Colour(247, 243, 233))])[0]) 
2020         if tabIdx 
== pc
.GetSelection(): 
2022             posy 
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0] 
2023             tabH 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- 5] or [tabHeight 
- 3])[0] 
2024             dc
.DrawRectangle(posx
, posy
, tabWidth
, tabH
)  
2026             # Draw a black line on the left side of the 
2028             dc
.SetPen(wx
.BLACK_PEN
) 
2030             blackLineY1 
= VERTICAL_BORDER_PADDING
 
2032             dc
.DrawLine(posx 
+ tabWidth
, blackLineY1
, posx 
+ tabWidth
, blackLineY2
) 
2034             # To give the tab more 3D look we do the following 
2035             # Incase the tab is on top, 
2036             # Draw a thik white line on topof the rectangle 
2037             # Otherwise, draw a thin (1 pixel) black line at the bottom 
2039             pen 
= wx
.Pen((pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK
] or [wx
.WHITE
])[0]) 
2041             whiteLinePosY 
= (pc
.HasFlag(FNB_BOTTOM
) and [blackLineY2
] or [VERTICAL_BORDER_PADDING 
])[0] 
2042             dc
.DrawLine(posx 
, whiteLinePosY
, posx 
+ tabWidth 
+ 1, whiteLinePosY
) 
2044             # Draw a white vertical line to the left of the tab 
2045             dc
.SetPen(wx
.WHITE_PEN
) 
2046             if not pc
.HasFlag(FNB_BOTTOM
): 
2049             dc
.DrawLine(posx
, blackLineY1
, posx
, blackLineY2
) 
2053             # We dont draw a rectangle for non selected tabs, but only 
2054             # vertical line on the left 
2056             blackLineY1 
= (pc
.HasFlag(FNB_BOTTOM
) and [VERTICAL_BORDER_PADDING 
+ 2] or [VERTICAL_BORDER_PADDING 
+ 1])[0] 
2057             blackLineY2 
= pc
.GetSize().y 
- 5  
2058             dc
.DrawLine(posx 
+ tabWidth
, blackLineY1
, posx 
+ tabWidth
, blackLineY2
) 
2060         # ----------------------------------- 
2061         # Text and image drawing 
2062         # ----------------------------------- 
2064         # Text drawing offset from the left border of the 
2067         # The width of the images are 16 pixels 
2068         padding 
= pc
.GetParent().GetPadding() 
2069         hasImage 
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1 
2070         imageYCoord 
= (pc
.HasFlag(FNB_BOTTOM
) and [5] or [8])[0] 
2073             textOffset 
= 2*pc
._pParent
._nPadding 
+ 16 
2075             textOffset 
= pc
._pParent
._nPadding
 
2077         if tabIdx 
!= pc
.GetSelection(): 
2079             # Set the text background to be like the vertical lines 
2080             dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour()) 
2084             imageXOffset 
= textOffset 
- 16 - padding
 
2085             pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
, 
2086                                      posx 
+ imageXOffset
, imageYCoord
, 
2087                                      wx
.IMAGELIST_DRAW_TRANSPARENT
, True) 
2089         dc
.DrawText(pc
.GetPageText(tabIdx
), posx 
+ textOffset
, imageYCoord
) 
2091         # draw 'x' on tab (if enabled) 
2092         if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx 
== pc
.GetSelection(): 
2094             textWidth
, textHeight 
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
)) 
2095             tabCloseButtonXCoord 
= posx 
+ textOffset 
+ textWidth 
+ 1 
2097             # take a bitmap from the position of the 'x' button (the x on tab button) 
2098             # this bitmap will be used later to delete old buttons 
2099             tabCloseButtonYCoord 
= imageYCoord
 
2100             x_rect 
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16) 
2101             self
._tabXBgBmp 
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
) 
2104             self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)                     
2107 #------------------------------------------------------------------ 
2109 #------------------------------------------------------------------ 
2111 class FNBRendererFancy(FNBRenderer
): 
2113     This class handles the drawing of tabs using the I{Fancy} renderer. 
2117         """ Default class constructor. """ 
2119         FNBRenderer
.__init
__(self
) 
2122     def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
): 
2123         """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """ 
2125         # Fancy tabs - like with VC71 but with the following differences: 
2126         # - The Selected tab is colored with gradient color 
2127         borderPen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)) 
2130         pen 
= (tabIdx 
== pc
.GetSelection() and [wx
.Pen(pc
._pParent
.GetBorderColour())] or [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))])[0] 
2132         if tabIdx 
== pc
.GetSelection(): 
2134             posy 
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [VERTICAL_BORDER_PADDING
])[0] 
2137             rect 
= wx
.Rect(posx
, posy
, tabWidth
, th
) 
2139             col2 
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourTo()] or [pc
._pParent
.GetGradientColourFrom()])[0] 
2140             col1 
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourFrom()] or [pc
._pParent
.GetGradientColourTo()])[0] 
2142             PaintStraightGradientBox(dc
, rect
, col1
, col2
) 
2143             dc
.SetBrush(wx
.TRANSPARENT_BRUSH
) 
2145             dc
.DrawRectangleRect(rect
) 
2147             # erase the bottom/top line of the rectangle 
2148             dc
.SetPen(wx
.Pen(pc
._pParent
.GetGradientColourFrom())) 
2149             if pc
.HasFlag(FNB_BOTTOM
): 
2150                 dc
.DrawLine(rect
.x
, 2, rect
.x 
+ rect
.width
, 2) 
2152                 dc
.DrawLine(rect
.x
, rect
.y 
+ rect
.height 
- 1, rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height 
- 1) 
2156             # We dont draw a rectangle for non selected tabs, but only 
2157             # vertical line on the left 
2158             dc
.SetPen(borderPen
) 
2159             dc
.DrawLine(posx 
+ tabWidth
, VERTICAL_BORDER_PADDING 
+ 3, posx 
+ tabWidth
, tabHeight 
- 4) 
2162         # ----------------------------------- 
2163         # Text and image drawing 
2164         # ----------------------------------- 
2166         # Text drawing offset from the left border of the 
2169         # The width of the images are 16 pixels 
2170         padding 
= pc
.GetParent().GetPadding() 
2171         hasImage 
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1 
2172         imageYCoord 
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0] 
2175             textOffset 
= 2*pc
._pParent
._nPadding 
+ 16 
2177             textOffset 
= pc
._pParent
._nPadding 
 
2181         if tabIdx 
!= pc
.GetSelection(): 
2183             # Set the text background to be like the vertical lines 
2184             dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour()) 
2188             imageXOffset 
= textOffset 
- 16 - padding
 
2189             pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
, 
2190                                      posx 
+ imageXOffset
, imageYCoord
, 
2191                                      wx
.IMAGELIST_DRAW_TRANSPARENT
, True) 
2193         dc
.DrawText(pc
.GetPageText(tabIdx
), posx 
+ textOffset
, imageYCoord
) 
2195         # draw 'x' on tab (if enabled) 
2196         if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx 
== pc
.GetSelection(): 
2198             textWidth
, textHeight 
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
)) 
2199             tabCloseButtonXCoord 
= posx 
+ textOffset 
+ textWidth 
+ 1 
2201             # take a bitmap from the position of the 'x' button (the x on tab button) 
2202             # this bitmap will be used later to delete old buttons 
2203             tabCloseButtonYCoord 
= imageYCoord
 
2204             x_rect 
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16) 
2205             self
._tabXBgBmp 
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
) 
2208             self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)             
2211 #------------------------------------------------------------------ 
2212 # Visual studio 2005 (VS8) 
2213 #------------------------------------------------------------------ 
2214 class FNBRendererVC8(FNBRenderer
):     
2216     This class handles the drawing of tabs using the I{VC8} renderer. 
2220         """ Default class constructor. """ 
2222         FNBRenderer
.__init
__(self
) 
2227     def DrawTabs(self
, pageContainer
, dc
): 
2228         """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """ 
2232         if "__WXMAC__" in wx
.PlatformInfo
: 
2233             # Works well on MSW & GTK, however this lines should be skipped on MAC 
2234             if not pc
._pagesInfoVec 
or pc
._nFrom 
>= len(pc
._pagesInfoVec
): 
2238         # Get the text hight 
2239         tabHeight 
= self
.CalcTabHeight(pageContainer
) 
2241         # Set the font for measuring the tab height 
2242         normalFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
2243         boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
2244         boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
2246         # Calculate the number of rows required for drawing the tabs 
2247         rect 
= pc
.GetClientRect() 
2249         # Set the maximum client size 
2250         pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
) 
2251         borderPen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)) 
2254         backBrush 
= wx
.Brush(pc
._tabAreaColor
) 
2255         noselBrush 
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
)) 
2256         selBrush 
= wx
.Brush(pc
._activeTabColor
) 
2260         dc
.SetTextBackground(pc
.GetBackgroundColour()) 
2261         dc
.SetTextForeground(pc
._activeTextColor
) 
2263         # If border style is set, set the pen to be border pen 
2264         if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
): 
2265             dc
.SetPen(borderPen
) 
2267             dc
.SetPen(wx
.TRANSPARENT_PEN
) 
2269         lightFactor 
= (pc
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0] 
2271         # For VC8 style, we color the tab area in gradient coloring 
2272         lightcolour 
= LightColour(pc
._tabAreaColor
, lightFactor
) 
2273         PaintStraightGradientBox(dc
, pc
.GetClientRect(), pc
._tabAreaColor
, lightcolour
) 
2275         dc
.SetBrush(wx
.TRANSPARENT_BRUSH
) 
2276         dc
.DrawRectangle(0, 0, size
.x
, size
.y
) 
2278         # Take 3 bitmaps for the background for the buttons 
2280         mem_dc 
= wx
.MemoryDC() 
2281         #--------------------------------------- 
2283         #--------------------------------------- 
2284         rect 
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14) 
2285         mem_dc
.SelectObject(self
._xBgBmp
) 
2286         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
2287         mem_dc
.SelectObject(wx
.NullBitmap
) 
2289         #--------------------------------------- 
2291         #--------------------------------------- 
2292         rect 
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14) 
2293         mem_dc
.SelectObject(self
._rightBgBmp
) 
2294         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
2295         mem_dc
.SelectObject(wx
.NullBitmap
) 
2297         #--------------------------------------- 
2299         #--------------------------------------- 
2300         rect 
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14) 
2301         mem_dc
.SelectObject(self
._leftBgBmp
) 
2302         mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
) 
2303         mem_dc
.SelectObject(wx
.NullBitmap
) 
2305         # We always draw the bottom/upper line of the tabs 
2306         # regradless the style 
2307         dc
.SetPen(borderPen
) 
2308         self
.DrawTabsLine(pc
, dc
) 
2311         dc
.SetPen(borderPen
) 
2314         dc
.SetFont(boldFont
) 
2316         # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible 
2317         for i 
in xrange(pc
._nFrom
): 
2319             pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1)) 
2320             pc
._pagesInfoVec
[i
].GetRegion().Clear() 
2322         # Draw the visible tabs, in VC8 style, we draw them from right to left 
2323         vTabsInfo 
= self
.NumberTabsCanFit(pc
) 
2329         for cur 
in xrange(len(vTabsInfo
)-1, -1, -1): 
2331             # 'i' points to the index of the currently drawn tab 
2332             # in pc.GetPageInfoVector() vector 
2334             dc
.SetPen(borderPen
) 
2335             dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0]) 
2337             # Now set the font to the correct font 
2338             dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0]) 
2340             # Add the padding to the tab width 
2342             # +-----------------------------------------------------------+ 
2343             # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING | 
2344             # +-----------------------------------------------------------+ 
2346             tabWidth 
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
) 
2347             posx 
= vTabsInfo
[cur
].x
 
2349             # By default we clean the tab region 
2350             # incase we use the VC8 style which requires 
2351             # the region, it will be filled by the function 
2353             pc
._pagesInfoVec
[i
].GetRegion().Clear() 
2355             # Clean the 'x' buttn on the tab  
2356             # 'Clean' rectanlge is a rectangle with width or height 
2357             # with values lower than or equal to 0 
2358             pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1)) 
2361             # Incase we are drawing the active tab 
2362             # we need to redraw so it will appear on top 
2365             # when using the vc8 style, we keep the position of the active tab so we will draw it again later 
2366             if i 
== pc
.GetSelection() and pc
.HasFlag(FNB_VC8
): 
2368                 activeTabPosx 
= posx
 
2369                 activeTabWidth 
= tabWidth
 
2370                 activeTabHeight 
= tabHeight
 
2374                 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
) 
2376             # Restore the text forground 
2377             dc
.SetTextForeground(pc
._activeTextColor
) 
2379             # Update the tab position & size 
2380             pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, VERTICAL_BORDER_PADDING
)) 
2381             pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
)) 
2383         # Incase we are in VC8 style, redraw the active tab (incase it is visible) 
2384         if pc
.GetSelection() >= pc
._nFrom 
and pc
.GetSelection() < pc
._nFrom 
+ len(vTabsInfo
): 
2386             self
.DrawTab(pc
, dc
, activeTabPosx
, pc
.GetSelection(), activeTabWidth
, activeTabHeight
, pc
._nTabXButtonStatus
) 
2388         # Update all tabs that can not fit into the screen as non-visible 
2389         for xx 
in xrange(pc
._nFrom 
+ len(vTabsInfo
), len(pc
._pagesInfoVec
)): 
2391             pc
._pagesInfoVec
[xx
].SetPosition(wx
.Point(-1, -1)) 
2392             pc
._pagesInfoVec
[xx
].GetRegion().Clear() 
2394         # Draw the left/right/close buttons  
2396         self
.DrawLeftArrow(pc
, dc
) 
2397         self
.DrawRightArrow(pc
, dc
) 
2399         self
.DrawDropDownArrow(pc
, dc
) 
2402     def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
): 
2403         """ Draws a tab using VC8 style. """ 
2406         borderPen 
= wx
.Pen(pc
._pParent
.GetBorderColour()) 
2407         tabPoints 
= [wx
.Point() for ii 
in xrange(8)] 
2409         # If we draw the first tab or the active tab,  
2410         # we draw a full tab, else we draw a truncated tab 
2421         tabPoints
[0].x 
= (pc
.HasFlag(FNB_BOTTOM
) and [posx
] or [posx
+self
._factor
])[0] 
2422         tabPoints
[0].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight 
- 3])[0] 
2424         tabPoints
[1].x 
= tabPoints
[0].x 
+ tabHeight 
- VERTICAL_BORDER_PADDING 
- 3 - self
._factor
 
2425         tabPoints
[1].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0] 
2427         tabPoints
[2].x 
= tabPoints
[1].x 
+ 4 
2428         tabPoints
[2].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0] 
2430         tabPoints
[3].x 
= tabPoints
[2].x 
+ tabWidth 
- 2 
2431         tabPoints
[3].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight 
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0] 
2433         tabPoints
[4].x 
= tabPoints
[3].x 
+ 1 
2434         tabPoints
[4].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [tabPoints
[3].y 
- 1] or [tabPoints
[3].y 
+ 1])[0] 
2436         tabPoints
[5].x 
= tabPoints
[4].x 
+ 1 
2437         tabPoints
[5].y 
= (pc
.HasFlag(FNB_BOTTOM
) and [(tabPoints
[4].y 
- 1)] or [tabPoints
[4].y 
+ 1])[0] 
2439         tabPoints
[6].x 
= tabPoints
[2].x 
+ tabWidth
 
2440         tabPoints
[6].y 
= tabPoints
[0].y
 
2442         tabPoints
[7].x 
= tabPoints
[0].x
 
2443         tabPoints
[7].y 
= tabPoints
[0].y
 
2445         pc
._pagesInfoVec
[tabIdx
].SetRegion(tabPoints
) 
2449         dc
.SetBrush(wx
.Brush((tabIdx 
== pc
.GetSelection() and [pc
._activeTabColor
] or [pc
._colorTo
])[0])) 
2450         dc
.SetPen(wx
.Pen((tabIdx 
== pc
.GetSelection() and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0])) 
2451         dc
.DrawPolygon(tabPoints
) 
2455         rect 
= pc
.GetClientRect() 
2457         if tabIdx 
!= pc
.GetSelection() and not pc
.HasFlag(FNB_BOTTOM
): 
2460             dc
.SetPen(wx
.Pen(pc
._pParent
.GetBorderColour())) 
2462             curPen 
= dc
.GetPen() 
2465             dc
.DrawLine(posx
, lineY
, posx
+rect
.width
, lineY
) 
2467         # Incase we are drawing the selected tab, we draw the border of it as well 
2468         # but without the bottom (upper line incase of wxBOTTOM) 
2469         if tabIdx 
== pc
.GetSelection(): 
2471             borderPen 
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)) 
2472             dc
.SetPen(borderPen
) 
2473             dc
.SetBrush(wx
.TRANSPARENT_BRUSH
) 
2474             dc
.DrawPolygon(tabPoints
) 
2476             # Delete the bottom line (or the upper one, incase we use wxBOTTOM)  
2477             dc
.SetPen(wx
.WHITE_PEN
) 
2478             dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, tabPoints
[6].x
, tabPoints
[6].y
) 
2480         self
.FillVC8GradientColour(pc
, dc
, tabPoints
, tabIdx 
== pc
.GetSelection(), tabIdx
) 
2482         # Draw a thin line to the right of the non-selected tab 
2483         if tabIdx 
!= pc
.GetSelection(): 
2485             dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))) 
2486             dc
.DrawLine(tabPoints
[4].x
-1, tabPoints
[4].y
, tabPoints
[5].x
-1, tabPoints
[5].y
) 
2487             dc
.DrawLine(tabPoints
[5].x
-1, tabPoints
[5].y
, tabPoints
[6].x
-1, tabPoints
[6].y
) 
2489         # Text drawing offset from the left border of the  
2492         # The width of the images are 16 pixels 
2493         vc8ShapeLen 
= tabHeight 
- VERTICAL_BORDER_PADDING 
- 2 
2494         if pc
.TabHasImage(tabIdx
): 
2495             textOffset 
= 2*pc
._pParent
.GetPadding() + 16 + vc8ShapeLen 
 
2497             textOffset 
= pc
._pParent
.GetPadding() + vc8ShapeLen
 
2499         # Draw the image for the tab if any 
2500         imageYCoord 
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0] 
2502         if pc
.TabHasImage(tabIdx
): 
2504             imageXOffset 
= textOffset 
- 16 - pc
._pParent
.GetPadding() 
2505             pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
, 
2506                                      posx 
+ imageXOffset
, imageYCoord
, 
2507                                      wx
.IMAGELIST_DRAW_TRANSPARENT
, True)         
2509         boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
2511         # if selected tab, draw text in bold 
2512         if tabIdx 
== pc
.GetSelection(): 
2513             boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
2515         dc
.SetFont(boldFont
) 
2516         dc
.DrawText(pc
.GetPageText(tabIdx
), posx 
+ textOffset
, imageYCoord
) 
2518         # draw 'x' on tab (if enabled) 
2519         if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx 
== pc
.GetSelection(): 
2521             textWidth
, textHeight 
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
)) 
2522             tabCloseButtonXCoord 
= posx 
+ textOffset 
+ textWidth 
+ 1 
2524             # take a bitmap from the position of the 'x' button (the x on tab button) 
2525             # this bitmap will be used later to delete old buttons 
2526             tabCloseButtonYCoord 
= imageYCoord
 
2527             x_rect 
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16) 
2528             self
._tabXBgBmp 
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
) 
2530             self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
) 
2533     def FillVC8GradientColour(self
, pageContainer
, dc
, tabPoints
, bSelectedTab
, tabIdx
): 
2534         """ Fills a tab with a gradient shading. """ 
2536         # calculate gradient coefficients 
2541             pc
._colorTo   
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 0)  
2542             pc
._colorFrom 
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 60) 
2544         col2 
= pc
._pParent
.GetGradientColourTo() 
2545         col1 
= pc
._pParent
.GetGradientColourFrom() 
2547         # If colorful tabs style is set, override the tab color 
2548         if pc
.HasFlag(FNB_COLORFUL_TABS
): 
2550             if not pc
._pagesInfoVec
[tabIdx
].GetColour(): 
2552                 # First time, generate color, and keep it in the vector 
2553                 tabColor 
= RandomColour() 
2554                 pc
._pagesInfoVec
[tabIdx
].SetColour(tabColor
) 
2556             if pc
.HasFlag(FNB_BOTTOM
): 
2558                 col2 
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50) 
2559                 col1 
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80) 
2563                 col1 
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50) 
2564                 col2 
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80) 
2566         size 
= abs(tabPoints
[2].y 
- tabPoints
[0].y
) - 1 
2568         rf
, gf
, bf 
= 0, 0, 0 
2569         rstep 
= float(col2
.Red() - col1
.Red())/float(size
) 
2570         gstep 
= float(col2
.Green() - col1
.Green())/float(size
) 
2571         bstep 
= float(col2
.Blue() - col1
.Blue())/float(size
) 
2575         # If we are drawing the selected tab, we need also to draw a line  
2576         # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this 
2577         # by drawing the rectangle with transparent brush 
2578         # the line under the selected tab will be deleted by the drwaing loop 
2580             self
.DrawTabsLine(pc
, dc
) 
2584             if pc
.HasFlag(FNB_BOTTOM
): 
2586                 if y 
> tabPoints
[0].y 
+ size
: 
2591                 if y 
< tabPoints
[0].y 
- size
: 
2594             currCol 
= wx
.Colour(col1
.Red() + rf
, col1
.Green() + gf
, col1
.Blue() + bf
) 
2596             dc
.SetPen((bSelectedTab 
and [wx
.Pen(pc
._activeTabColor
)] or [wx
.Pen(currCol
)])[0]) 
2597             startX 
= self
.GetStartX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())  
2598             endX 
= self
.GetEndX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag()) 
2599             dc
.DrawLine(startX
, y
, endX
, y
) 
2601             # Draw the border using the 'edge' point 
2602             dc
.SetPen(wx
.Pen((bSelectedTab 
and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0])) 
2604             dc
.DrawPoint(startX
, y
) 
2605             dc
.DrawPoint(endX
, y
) 
2607             # Progress the color  
2612             if pc
.HasFlag(FNB_BOTTOM
): 
2618     def GetStartX(self
, tabPoints
, y
, style
): 
2619         """ Returns the x start position of a tab. """ 
2621         x1
, x2
, y1
, y2 
= 0.0, 0.0, 0.0, 0.0 
2623         # We check the 3 points to the left 
2625         bBottomStyle 
= (style 
& FNB_BOTTOM 
and [True] or [False])[0] 
2632                 if y 
>= tabPoints
[i
].y 
and y 
< tabPoints
[i
+1].y
: 
2635                     x2 
= tabPoints
[i
+1].x
 
2637                     y2 
= tabPoints
[i
+1].y
 
2645                 if y 
<= tabPoints
[i
].y 
and y 
> tabPoints
[i
+1].y
: 
2648                     x2 
= tabPoints
[i
+1].x
 
2650                     y2 
= tabPoints
[i
+1].y
 
2655             return tabPoints
[2].x
 
2657         # According to the equation y = ax + b => x = (y-b)/a 
2658         # We know the first 2 points 
2663             a 
= (y2 
- y1
)/(x2 
- x1
) 
2665         b 
= y1 
- ((y2 
- y1
)/(x2 
- x1
))*x1
 
2675     def GetEndX(self
, tabPoints
, y
, style
): 
2676         """ Returns the x end position of a tab. """ 
2678         x1
, x2
, y1
, y2 
= 0.0, 0.0, 0.0, 0.0 
2680         # We check the 3 points to the left 
2681         bBottomStyle 
= (style 
& FNB_BOTTOM 
and [True] or [False])[0] 
2686             for i 
in xrange(7, 3, -1): 
2688                 if y 
>= tabPoints
[i
].y 
and y 
< tabPoints
[i
-1].y
: 
2691                     x2 
= tabPoints
[i
-1].x
 
2693                     y2 
= tabPoints
[i
-1].y
 
2699             for i 
in xrange(7, 3, -1): 
2701                 if y 
<= tabPoints
[i
].y 
and y 
> tabPoints
[i
-1].y
: 
2704                     x2 
= tabPoints
[i
-1].x
 
2706                     y2 
= tabPoints
[i
-1].y
 
2711             return tabPoints
[3].x
 
2713         # According to the equation y = ax + b => x = (y-b)/a 
2714         # We know the first 2 points 
2720         a 
= (y2 
- y1
)/(x2 
- x1
) 
2721         b 
= y1 
- ((y2 
- y1
)/(x2 
- x1
))*x1
 
2731     def NumberTabsCanFit(self
, pageContainer
, fr
=-1): 
2732         """ Returns the number of tabs that can fit in the visible area. """ 
2736         rect 
= pc
.GetClientRect() 
2737         clientWidth 
= rect
.width
 
2741         tabHeight 
= self
.CalcTabHeight(pageContainer
) 
2743         # The drawing starts from posx 
2744         posx 
= pc
._pParent
.GetPadding() 
2749         for i 
in xrange(fr
, len(pc
._pagesInfoVec
)): 
2751             vc8glitch 
= tabHeight 
+ FNB_HEIGHT_SPACER
 
2752             tabWidth 
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
) 
2754             if posx 
+ tabWidth 
+ vc8glitch 
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
: 
2757             # Add a result to the returned vector 
2758             tabRect 
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
) 
2759             vTabInfo
.append(tabRect
) 
2762             posx 
+= tabWidth 
+ FNB_HEIGHT_SPACER
 
2767 # ---------------------------------------------------------------------------- # 
2768 # Class FlatNotebook 
2769 # ---------------------------------------------------------------------------- # 
2771 class FlatNotebook(wx
.Panel
): 
2773     Display one or more windows in a notebook. 
2776         - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active  
2777             page in the notebook is changing 
2778         - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active  
2779             page in the notebook has changed 
2780         - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the  
2782         - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the  
2783             notebook has been closed 
2784         - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user 
2785             clicks a tab in the notebook with the right mouse 
2789     def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
, 
2790                  style
=0, name
="FlatNotebook"): 
2792         Default class constructor. 
2794         All the parameters are as in wxPython class construction, except the 
2795         'style': this can be assigned to whatever combination of FNB_* styles. 
2799         self
._bForceSelection 
= False 
2802         style |
= wx
.TAB_TRAVERSAL
 
2805         self
._popupWin 
= None 
2807         wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style
) 
2809         self
._pages 
= PageContainer(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.DefaultSize
, style
) 
2811         self
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
) 
2817         """ Initializes all the class attributes. """ 
2819         self
._pages
._colorBorder 
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
) 
2821         self
._mainSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
2822         self
.SetSizer(self
._mainSizer
) 
2824         # The child panels will inherit this bg color, so leave it at the default value 
2825         #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE)) 
2827         # Set default page height 
2828         dc 
= wx
.ClientDC(self
) 
2830         if "__WXGTK__" in wx
.PlatformInfo
: 
2831             # For GTK it seems that we must do this steps in order 
2832             # for the tabs will get the proper height on initialization 
2833             # on MSW, preforming these steps yields wierd results 
2834             boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
2835             boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
2836             dc
.SetFont(boldFont
) 
2838         height 
= dc
.GetCharHeight() 
2840         tabHeight 
= height 
+ FNB_HEIGHT_SPACER         
# We use 8 pixels as padding 
2842         if "__WXGTK__" in wx
.PlatformInfo
: 
2845         self
._pages
.SetSizeHints(-1, tabHeight
) 
2846         # Add the tab container to the sizer 
2847         self
._mainSizer
.Insert(0, self
._pages
, 0, wx
.EXPAND
) 
2848         self
._mainSizer
.Layout() 
2850         self
._pages
._nFrom 
= self
._nFrom
 
2851         self
._pDropTarget 
= FNBDropTarget(self
) 
2852         self
.SetDropTarget(self
._pDropTarget
) 
2855     def SetActiveTabTextColour(self
, textColour
): 
2856         """ Sets the text colour for the active tab. """ 
2858         self
._pages
._activeTextColor 
= textColour
 
2861     def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
): 
2862         """ Handles the drop action from a DND operation. """ 
2864         return self
._pages
.OnDropTarget(x
, y
, nTabPage
, wnd_oldContainer
) 
2867     def GetPreviousSelection(self
): 
2868         """ Returns the previous selection. """ 
2870         return self
._pages
._iPreviousActivePage
 
2873     def AddPage(self
, page
, text
, select
=True, imageId
=-1): 
2875         Add a page to the L{FlatNotebook}. 
2877         @param page: Specifies the new page. 
2878         @param text: Specifies the text for the new page. 
2879         @param select: Specifies whether the page should be selected. 
2880         @param imageId: Specifies the optional image index for the new page. 
2883         True if successful, False otherwise. 
2890         # reparent the window to us 
2894         bSelected 
= select 
or len(self
._windows
) == 0 
2900             # Check for selection and send events 
2901             oldSelection 
= self
._pages
._iActivePage
 
2902             tabIdx 
= len(self
._windows
) 
2904             event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId()) 
2905             event
.SetSelection(tabIdx
) 
2906             event
.SetOldSelection(oldSelection
) 
2907             event
.SetEventObject(self
) 
2909             if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed() or len(self
._windows
) == 0: 
2912         curSel 
= self
._pages
.GetSelection() 
2914         if not self
._pages
.IsShown(): 
2917         self
._pages
.AddPage(text
, bSelected
, imageId
) 
2918         self
._windows
.append(page
) 
2922         # Check if a new selection was made 
2927                 # Remove the window from the main sizer 
2928                 self
._mainSizer
.Detach(self
._windows
[curSel
]) 
2929                 self
._windows
[curSel
].Hide() 
2931             if self
.GetWindowStyleFlag() & FNB_BOTTOM
: 
2933                 self
._mainSizer
.Insert(0, page
, 1, wx
.EXPAND
) 
2937                 # We leave a space of 1 pixel around the window 
2938                 self
._mainSizer
.Add(page
, 1, wx
.EXPAND
) 
2940             # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event 
2941             event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
) 
2942             event
.SetOldSelection(oldSelection
) 
2943             self
.GetEventHandler().ProcessEvent(event
) 
2951         self
._mainSizer
.Layout() 
2957     def SetImageList(self
, imageList
): 
2958         """ Sets the image list for the page control. """ 
2960         self
._pages
.SetImageList(imageList
) 
2963     def AssignImageList(self
, imageList
): 
2964         """ Assigns the image list for the page control. """ 
2966         self
._pages
.AssignImageList(imageList
) 
2969     def GetImageList(self
): 
2970         """ Returns the associated image list. """ 
2972         return self
._pages
.GetImageList() 
2975     def InsertPage(self
, indx
, page
, text
, select
=True, imageId
=-1): 
2977         Inserts a new page at the specified position. 
2979         @param indx: Specifies the position of the new page. 
2980         @param page: Specifies the new page. 
2981         @param text: Specifies the text for the new page. 
2982         @param select: Specifies whether the page should be selected. 
2983         @param imageId: Specifies the optional image index for the new page. 
2986         True if successful, False otherwise. 
2993         # reparent the window to us 
2996         if not self
._windows
: 
2998             self
.AddPage(page
, text
, select
, imageId
) 
3002         bSelected 
= select 
or not self
._windows
 
3003         curSel 
= self
._pages
.GetSelection() 
3005         indx 
= max(0, min(indx
, len(self
._windows
))) 
3007         if indx 
<= len(self
._windows
): 
3009             self
._windows
.insert(indx
, page
) 
3013             self
._windows
.append(page
) 
3019             # Check for selection and send events 
3020             oldSelection 
= self
._pages
._iActivePage
 
3022             event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId()) 
3023             event
.SetSelection(indx
) 
3024             event
.SetOldSelection(oldSelection
) 
3025             event
.SetEventObject(self
) 
3027             if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed() or len(self
._windows
) == 0: 
3030         self
._pages
.InsertPage(indx
, text
, bSelected
, imageId
) 
3037         # Check if a new selection was made 
3042                 # Remove the window from the main sizer 
3043                 self
._mainSizer
.Detach(self
._windows
[curSel
]) 
3044                 self
._windows
[curSel
].Hide() 
3046             self
._pages
.SetSelection(indx
) 
3048             # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event 
3049             event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
) 
3050             event
.SetOldSelection(oldSelection
) 
3051             self
.GetEventHandler().ProcessEvent(event
) 
3059         self
._mainSizer
.Layout()         
3065     def SetSelection(self
, page
): 
3067         Sets the selection for the given page. 
3068         The call to this function generates the page changing events 
3071         if page 
>= len(self
._windows
) or not self
._windows
: 
3074         # Support for disabed tabs 
3075         if not self
._pages
.GetEnabled(page
) and len(self
._windows
) > 1 and not self
._bForceSelection
: 
3078         curSel 
= self
._pages
.GetSelection() 
3080         # program allows the page change 
3084             # Remove the window from the main sizer 
3085             self
._mainSizer
.Detach(self
._windows
[curSel
]) 
3086             self
._windows
[curSel
].Hide() 
3088         if self
.GetWindowStyleFlag() & FNB_BOTTOM
: 
3090             self
._mainSizer
.Insert(0, self
._windows
[page
], 1, wx
.EXPAND
) 
3094             # We leave a space of 1 pixel around the window 
3095             self
._mainSizer
.Add(self
._windows
[page
], 1, wx
.EXPAND
) 
3097         self
._windows
[page
].Show() 
3100         self
._mainSizer
.Layout() 
3102         if page 
!= self
._pages
._iActivePage
: 
3103             # there is a real page changing 
3104             self
._pages
._iPreviousActivePage 
= self
._pages
._iActivePage
 
3106         self
._pages
._iActivePage 
= page
 
3107         self
._pages
.DoSetSelection(page
) 
3110     def DeletePage(self
, page
): 
3112         Deletes the specified page, and the associated window. 
3113         The call to this function generates the page changing events. 
3116         if page 
>= len(self
._windows
) or page 
< 0: 
3119         # Fire a closing event 
3120         event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId()) 
3121         event
.SetSelection(page
) 
3122         event
.SetEventObject(self
) 
3123         self
.GetEventHandler().ProcessEvent(event
) 
3125         # The event handler allows it? 
3126         if not event
.IsAllowed(): 
3131         # Delete the requested page 
3132         pageRemoved 
= self
._windows
[page
] 
3134         # If the page is the current window, remove it from the sizer 
3136         if page 
== self
._pages
.GetSelection(): 
3137             self
._mainSizer
.Detach(pageRemoved
) 
3139         # Remove it from the array as well 
3140         self
._windows
.pop(page
) 
3142         # Now we can destroy it in wxWidgets use Destroy instead of delete 
3143         pageRemoved
.Destroy() 
3147         self
._pages
.DoDeletePage(page
) 
3150         # Fire a closed event 
3151         closedEvent 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, self
.GetId()) 
3152         closedEvent
.SetSelection(page
) 
3153         closedEvent
.SetEventObject(self
) 
3154         self
.GetEventHandler().ProcessEvent(closedEvent
) 
3157     def DeleteAllPages(self
): 
3158         """ Deletes all the pages. """ 
3160         if not self
._windows
: 
3165         for page 
in self
._windows
: 
3171         # Clear the container of the tabs as well 
3172         self
._pages
.DeleteAllPages() 
3176     def GetCurrentPage(self
): 
3177         """ Returns the currently selected notebook page or None. """ 
3179         sel 
= self
._pages
.GetSelection() 
3183         return self
._windows
[sel
] 
3186     def GetPage(self
, page
): 
3187         """ Returns the window at the given page position, or None. """ 
3189         if page 
>= len(self
._windows
): 
3192         return self
._windows
[page
] 
3195     def GetPageIndex(self
, win
): 
3196         """ Returns the index at which the window is found. """ 
3199             return self
._windows
.index(win
) 
3204     def GetSelection(self
): 
3205         """ Returns the currently selected page, or -1 if none was selected. """ 
3207         return self
._pages
.GetSelection() 
3210     def AdvanceSelection(self
, forward
=True): 
3212         Cycles through the tabs. 
3213         The call to this function generates the page changing events. 
3216         self
._pages
.AdvanceSelection(forward
) 
3219     def GetPageCount(self
): 
3220         """ Returns the number of pages in the L{FlatNotebook} control. """ 
3222         return self
._pages
.GetPageCount() 
3225     def OnNavigationKey(self
, event
): 
3226         """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """ 
3228         if event
.IsWindowChange(): 
3229             if len(self
._windows
) == 0: 
3232             if self
.HasFlag(FNB_SMART_TABS
): 
3233                 if not self
._popupWin
: 
3234                     self
._popupWin 
= TabNavigatorWindow(self
) 
3235                     self
._popupWin
.SetReturnCode(wx
.ID_OK
) 
3236                     self
._popupWin
.ShowModal() 
3237                     self
._popupWin
.Destroy() 
3238                     self
._popupWin 
= None 
3240                     # a dialog is already opened 
3241                     self
._popupWin
.OnNavigationKey(event
) 
3245                 self
.AdvanceSelection(event
.GetDirection()) 
3247             # pass to the parent 
3248             if self
.GetParent(): 
3249                 event
.SetCurrentFocus(self
) 
3250                 self
.GetParent().ProcessEvent(event
) 
3253     def GetPageShapeAngle(self
, page_index
): 
3254         """ Returns the angle associated to a tab. """ 
3256         if page_index 
< 0 or page_index 
>= len(self
._pages
._pagesInfoVec
): 
3259         result 
= self
._pages
._pagesInfoVec
[page_index
].GetTabAngle() 
3263     def SetPageShapeAngle(self
, page_index
, angle
): 
3264         """ Sets the angle associated to a tab. """ 
3266         if page_index 
< 0 or page_index 
>= len(self
._pages
._pagesInfoVec
): 
3272         self
._pages
._pagesInfoVec
[page_index
].SetTabAngle(angle
) 
3275     def SetAllPagesShapeAngle(self
, angle
): 
3276         """ Sets the angle associated to all the tab. """ 
3281         for ii 
in xrange(len(self
._pages
._pagesInfoVec
)): 
3282             self
._pages
._pagesInfoVec
[ii
].SetTabAngle(angle
) 
3287     def GetPageBestSize(self
): 
3288         """ Return the page best size. """ 
3290         return self
._pages
.GetClientSize() 
3293     def SetPageText(self
, page
, text
): 
3294         """ Sets the text for the given page. """ 
3296         bVal 
= self
._pages
.SetPageText(page
, text
) 
3297         self
._pages
.Refresh() 
3302     def SetPadding(self
, padding
): 
3304         Sets the amount of space around each page's icon and label, in pixels. 
3305         NB: only the horizontal padding is considered. 
3308         self
._nPadding 
= padding
.GetWidth() 
3311     def GetTabArea(self
): 
3312         """ Returns the associated page. """ 
3317     def GetPadding(self
): 
3318         """ Returns the amount of space around each page's icon and label, in pixels. """ 
3320         return self
._nPadding 
 
3323     def SetWindowStyleFlag(self
, style
): 
3324         """ Sets the L{FlatNotebook} window style flags. """ 
3326         wx
.Panel
.SetWindowStyleFlag(self
, style
) 
3327         renderer 
= self
._pages
._mgr
.GetRenderer(self
.GetWindowStyleFlag()) 
3328         renderer
._tabHeight 
= None 
3332             # For changing the tab position (i.e. placing them top/bottom) 
3333             # refreshing the tab container is not enough 
3334             self
.SetSelection(self
._pages
._iActivePage
) 
3336         if not self
._pages
.HasFlag(FNB_HIDE_ON_SINGLE_TAB
): 
3337             #For Redrawing the Tabs once you remove the Hide tyle 
3338             self
._pages
._ReShow
() 
3341     def RemovePage(self
, page
): 
3342         """ Deletes the specified page, without deleting the associated window. """ 
3344         if page 
>= len(self
._windows
): 
3347         # Fire a closing event 
3348         event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId()) 
3349         event
.SetSelection(page
) 
3350         event
.SetEventObject(self
) 
3351         self
.GetEventHandler().ProcessEvent(event
) 
3353         # The event handler allows it? 
3354         if not event
.IsAllowed(): 
3359         # Remove the requested page 
3360         pageRemoved 
= self
._windows
[page
] 
3362         # If the page is the current window, remove it from the sizer 
3364         if page 
== self
._pages
.GetSelection(): 
3365             self
._mainSizer
.Detach(pageRemoved
) 
3367         # Remove it from the array as well 
3368         self
._windows
.pop(page
) 
3371         self
._pages
.DoDeletePage(page
) 
3376     def SetRightClickMenu(self
, menu
): 
3377         """ Sets the popup menu associated to a right click on a tab. """ 
3379         self
._pages
._pRightClickMenu 
= menu
 
3382     def GetPageText(self
, nPage
): 
3383         """ Returns the tab caption. """ 
3385         return self
._pages
.GetPageText(nPage
) 
3388     def SetGradientColours(self
, fr
, to
, border
): 
3389         """ Sets the gradient colours for the tab. """ 
3391         self
._pages
._colorFrom 
= fr
 
3392         self
._pages
._colorTo   
= to
 
3393         self
._pages
._colorBorder 
= border
 
3396     def SetGradientColourFrom(self
, fr
): 
3397         """ Sets the starting colour for the gradient. """ 
3399         self
._pages
._colorFrom 
= fr
 
3402     def SetGradientColourTo(self
, to
): 
3403         """ Sets the ending colour for the gradient. """ 
3405         self
._pages
._colorTo 
= to
 
3408     def SetGradientColourBorder(self
, border
): 
3409         """ Sets the tab border colour. """ 
3411         self
._pages
._colorBorder 
= border
 
3414     def GetGradientColourFrom(self
): 
3415         """ Gets first gradient colour. """ 
3417         return self
._pages
._colorFrom
 
3420     def GetGradientColourTo(self
): 
3421         """ Gets second gradient colour. """ 
3423         return self
._pages
._colorTo
 
3426     def GetGradientColourBorder(self
): 
3427         """ Gets the tab border colour. """ 
3429         return self
._pages
._colorBorder
 
3432     def GetBorderColour(self
): 
3433         """ Returns the border colour. """ 
3435         return self
._pages
._colorBorder
 
3438     def GetActiveTabTextColour(self
): 
3439         """ Get the active tab text colour. """ 
3441         return self
._pages
._activeTextColor
 
3444     def SetPageImage(self
, page
, image
): 
3446         Sets the image index for the given page. Image is an index into the 
3447         image list which was set with SetImageList. 
3450         self
._pages
.SetPageImage(page
, image
) 
3453     def GetPageImage(self
, nPage
): 
3455         Returns the image index for the given page. Image is an index into the 
3456         image list which was set with SetImageList. 
3459         return self
._pages
.GetPageImage(nPage
) 
3462     def GetEnabled(self
, page
): 
3463         """ Returns whether a tab is enabled or not. """ 
3465         return self
._pages
.GetEnabled(page
) 
3468     def Enable(self
, page
, enabled
=True): 
3469         """ Enables or disables a tab. """ 
3471         if page 
>= len(self
._windows
): 
3474         self
._windows
[page
].Enable(enabled
) 
3475         self
._pages
.Enable(page
, enabled
) 
3478     def GetNonActiveTabTextColour(self
): 
3479         """ Returns the non active tabs text colour. """ 
3481         return self
._pages
._nonActiveTextColor
 
3484     def SetNonActiveTabTextColour(self
, color
): 
3485         """ Sets the non active tabs text colour. """ 
3487         self
._pages
._nonActiveTextColor 
= color
 
3490     def SetTabAreaColour(self
, color
): 
3491         """ Sets the area behind the tabs colour. """ 
3493         self
._pages
._tabAreaColor 
= color
 
3496     def GetTabAreaColour(self
): 
3497         """ Returns the area behind the tabs colour. """ 
3499         return self
._pages
._tabAreaColor
 
3502     def SetActiveTabColour(self
, color
): 
3503         """ Sets the active tab colour. """ 
3505         self
._pages
._activeTabColor 
= color
 
3508     def GetActiveTabColour(self
): 
3509         """ Returns the active tab colour. """ 
3511         return self
._pages
._activeTabColor
 
3514 # ---------------------------------------------------------------------------- # 
3515 # Class PageContainer 
3516 # Acts as a container for the pages you add to FlatNotebook 
3517 # ---------------------------------------------------------------------------- # 
3519 class PageContainer(wx
.Panel
): 
3521     This class acts as a container for the pages you add to L{FlatNotebook}. 
3524     def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, 
3525                  size
=wx
.DefaultSize
, style
=0): 
3526         """ Default class constructor. """ 
3528         self
._ImageList 
= None 
3529         self
._iActivePage 
= -1 
3530         self
._pDropTarget 
= None 
3531         self
._nLeftClickZone 
= FNB_NOWHERE
 
3532         self
._iPreviousActivePage 
= -1 
3534         self
._pRightClickMenu 
= None 
3535         self
._nXButtonStatus 
= FNB_BTN_NONE
 
3536         self
._nArrowDownButtonStatus 
= FNB_BTN_NONE
 
3537         self
._pParent 
= parent
 
3538         self
._nRightButtonStatus 
= FNB_BTN_NONE
 
3539         self
._nLeftButtonStatus 
= FNB_BTN_NONE
 
3540         self
._nTabXButtonStatus 
= FNB_BTN_NONE
 
3542         self
._pagesInfoVec 
= []         
3544         self
._colorTo 
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_ACTIVECAPTION
) 
3545         self
._colorFrom 
= wx
.WHITE
 
3546         self
._activeTabColor 
= wx
.WHITE
 
3547         self
._activeTextColor 
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNTEXT
) 
3548         self
._nonActiveTextColor 
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
) 
3549         self
._tabAreaColor 
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
) 
3552         self
._isdragging 
= False 
3554         # Set default page height, this is done according to the system font 
3555         memDc 
= wx
.MemoryDC() 
3556         memDc
.SelectObject(wx
.EmptyBitmap(1,1)) 
3558         if "__WXGTK__" in wx
.PlatformInfo
: 
3559             boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
) 
3560             boldFont
.SetWeight(wx
.BOLD
) 
3561             memDc
.SetFont(boldFont
) 
3563         height 
= memDc
.GetCharHeight() 
3564         tabHeight 
= height 
+ FNB_HEIGHT_SPACER 
# We use 10 pixels as padding 
3566         wx
.Panel
.__init
__(self
, parent
, id, pos
, wx
.Size(size
.x
, tabHeight
), 
3567                           style|wx
.NO_BORDER|wx
.NO_FULL_REPAINT_ON_RESIZE
) 
3569         self
._pDropTarget 
= FNBDropTarget(self
) 
3570         self
.SetDropTarget(self
._pDropTarget
) 
3571         self
._mgr 
= FNBRendererMgr() 
3573         self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
) 
3574         self
.Bind(wx
.EVT_SIZE
, self
.OnSize
) 
3575         self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
) 
3576         self
.Bind(wx
.EVT_LEFT_UP
, self
.OnLeftUp
) 
3577         self
.Bind(wx
.EVT_RIGHT_DOWN
, self
.OnRightDown
) 
3578         self
.Bind(wx
.EVT_MIDDLE_DOWN
, self
.OnMiddleDown
) 
3579         self
.Bind(wx
.EVT_MOTION
, self
.OnMouseMove
) 
3580         self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
) 
3581         self
.Bind(wx
.EVT_LEAVE_WINDOW
, self
.OnMouseLeave
) 
3582         self
.Bind(wx
.EVT_ENTER_WINDOW
, self
.OnMouseEnterWindow
) 
3583         self
.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnLeftDClick
) 
3586     def OnEraseBackground(self
, event
): 
3587         """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing).""" 
3593         """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """ 
3595         self
.GetParent()._mainSizer
.Layout() 
3599     def OnPaint(self
, event
): 
3600         """ Handles the wx.EVT_PAINT event for L{PageContainer}.""" 
3602         dc 
= wx
.BufferedPaintDC(self
) 
3603         renderer 
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag()) 
3604         renderer
.DrawTabs(self
, dc
) 
3606         if self
.HasFlag(FNB_HIDE_ON_SINGLE_TAB
) and len(self
._pagesInfoVec
) <= 1: 
3608             self
.GetParent()._mainSizer
.Layout() 
3612     def AddPage(self
, caption
, selected
=True, imgindex
=-1): 
3614         Add a page to the L{FlatNotebook}. 
3616         @param window: Specifies the new page. 
3617         @param caption: Specifies the text for the new page. 
3618         @param selected: Specifies whether the page should be selected. 
3619         @param imgindex: Specifies the optional image index for the new page. 
3622         True if successful, False otherwise. 
3627             self
._iPreviousActivePage 
= self
._iActivePage        
 
3628             self
._iActivePage 
= len(self
._pagesInfoVec
) 
3630         # Create page info and add it to the vector 
3631         pageInfo 
= PageInfo(caption
, imgindex
) 
3632         self
._pagesInfoVec
.append(pageInfo
) 
3636     def InsertPage(self
, indx
, text
, selected
=True, imgindex
=-1): 
3638         Inserts a new page at the specified position. 
3640         @param indx: Specifies the position of the new page. 
3641         @param page: Specifies the new page. 
3642         @param text: Specifies the text for the new page. 
3643         @param select: Specifies whether the page should be selected. 
3644         @param imgindex: Specifies the optional image index for the new page. 
3647         True if successful, False otherwise. 
3652             self
._iPreviousActivePage 
= self
._iActivePage        
 
3653             self
._iActivePage 
= len(self
._pagesInfoVec
) 
3655         self
._pagesInfoVec
.insert(indx
, PageInfo(text
, imgindex
)) 
3661     def OnSize(self
, event
): 
3662         """ Handles the wx.EVT_SIZE events for L{PageContainer}. """ 
3664         # When resizing the control, try to fit to screen as many tabs as we can  
3665         style 
= self
.GetParent().GetWindowStyleFlag()  
3666         renderer 
= self
._mgr
.GetRenderer(style
) 
3669         page 
= self
.GetSelection() 
3671         for fr 
in xrange(self
._nFrom
): 
3672             vTabInfo 
= renderer
.NumberTabsCanFit(self
, fr
) 
3673             if page 
- fr 
>= len(vTabInfo
): 
3679         self
.Refresh() # Call on paint 
3683     def OnMiddleDown(self
, event
): 
3684         """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """ 
3686         # Test if this style is enabled 
3687         style 
= self
.GetParent().GetWindowStyleFlag() 
3689         if not style 
& FNB_MOUSE_MIDDLE_CLOSES_TABS
: 
3692         where
, tabIdx 
= self
.HitTest(event
.GetPosition()) 
3694         if where 
== FNB_TAB
: 
3695             self
.DeletePage(tabIdx
) 
3700     def OnRightDown(self
, event
): 
3701         """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """ 
3703         where
, tabIdx 
= self
.HitTest(event
.GetPosition()) 
3705         if where 
in [FNB_TAB
, FNB_TAB_X
]: 
3707             if self
._pagesInfoVec
[tabIdx
].GetEnabled(): 
3708                 # Fire events and eventually (if allowed) change selection 
3709                 self
.FireEvent(tabIdx
) 
3711                 # send a message to popup a custom menu 
3712                 event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, self
.GetParent().GetId()) 
3713                 event
.SetSelection(tabIdx
) 
3714                 event
.SetOldSelection(self
._iActivePage
) 
3715                 event
.SetEventObject(self
.GetParent()) 
3716                 self
.GetParent().GetEventHandler().ProcessEvent(event
) 
3718                 if self
._pRightClickMenu
: 
3719                     self
.PopupMenu(self
._pRightClickMenu
) 
3724     def OnLeftDown(self
, event
): 
3725         """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """ 
3727         # Reset buttons status 
3728         self
._nXButtonStatus     
= FNB_BTN_NONE
 
3729         self
._nLeftButtonStatus  
= FNB_BTN_NONE
 
3730         self
._nRightButtonStatus 
= FNB_BTN_NONE
 
3731         self
._nTabXButtonStatus  
= FNB_BTN_NONE
 
3732         self
._nArrowDownButtonStatus 
= FNB_BTN_NONE
 
3734         self
._nLeftClickZone
, tabIdx 
= self
.HitTest(event
.GetPosition()) 
3736         if self
._nLeftClickZone 
== FNB_DROP_DOWN_ARROW
: 
3737             self
._nArrowDownButtonStatus 
= FNB_BTN_PRESSED
 
3739         elif self
._nLeftClickZone 
== FNB_LEFT_ARROW
: 
3740             self
._nLeftButtonStatus 
= FNB_BTN_PRESSED
 
3742         elif self
._nLeftClickZone 
== FNB_RIGHT_ARROW
: 
3743             self
._nRightButtonStatus 
= FNB_BTN_PRESSED
 
3745         elif self
._nLeftClickZone 
== FNB_X
: 
3746             self
._nXButtonStatus 
= FNB_BTN_PRESSED
 
3748         elif self
._nLeftClickZone 
== FNB_TAB_X
: 
3749             self
._nTabXButtonStatus 
= FNB_BTN_PRESSED
 
3752         elif self
._nLeftClickZone 
== FNB_TAB
: 
3754             if self
._iActivePage 
!= tabIdx
: 
3756                 # In case the tab is disabled, we dont allow to choose it 
3757                 if self
._pagesInfoVec
[tabIdx
].GetEnabled(): 
3758                     self
.FireEvent(tabIdx
) 
3761     def OnLeftUp(self
, event
): 
3762         """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """ 
3764         # forget the zone that was initially clicked 
3765         self
._nLeftClickZone 
= FNB_NOWHERE
 
3767         where
, tabIdx 
= self
.HitTest(event
.GetPosition()) 
3769         if where 
== FNB_LEFT_ARROW
: 
3771             if self
._nFrom 
== 0: 
3774             # Make sure that the button was pressed before 
3775             if self
._nLeftButtonStatus 
!= FNB_BTN_PRESSED
: 
3778             self
._nLeftButtonStatus 
= FNB_BTN_HOVER
 
3780             # We scroll left with bulks of 5 
3781             scrollLeft 
= self
.GetNumTabsCanScrollLeft() 
3783             self
._nFrom 
-= scrollLeft
 
3789         elif where 
== FNB_RIGHT_ARROW
: 
3791             if self
._nFrom 
>= len(self
._pagesInfoVec
) - 1: 
3794             # Make sure that the button was pressed before 
3795             if self
._nRightButtonStatus 
!= FNB_BTN_PRESSED
: 
3798             self
._nRightButtonStatus 
= FNB_BTN_HOVER
 
3800             # Check if the right most tab is visible, if it is 
3801             # don't rotate right anymore 
3802             if self
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1): 
3805             lastVisibleTab 
= self
.GetLastVisibleTab() 
3806             if lastVisibleTab 
< 0: 
3807                 # Probably the screen is too small for displaying even a single 
3808                 # tab, in this case we do nothing 
3811             self
._nFrom 
+= self
.GetNumOfVisibleTabs() 
3814         elif where 
== FNB_X
: 
3816             # Make sure that the button was pressed before 
3817             if self
._nXButtonStatus 
!= FNB_BTN_PRESSED
: 
3820             self
._nXButtonStatus 
= FNB_BTN_HOVER
 
3822             self
.DeletePage(self
._iActivePage
) 
3824         elif where 
== FNB_TAB_X
: 
3826             # Make sure that the button was pressed before 
3827             if self
._nTabXButtonStatus 
!= FNB_BTN_PRESSED
: 
3830             self
._nTabXButtonStatus 
= FNB_BTN_HOVER
 
3832             self
.DeletePage(self
._iActivePage
) 
3834         elif where 
== FNB_DROP_DOWN_ARROW
: 
3836             # Make sure that the button was pressed before 
3837             if self
._nArrowDownButtonStatus 
!= FNB_BTN_PRESSED
: 
3840             self
._nArrowDownButtonStatus 
= FNB_BTN_NONE
 
3842             # Refresh the button status 
3843             renderer 
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag()) 
3844             dc 
= wx
.ClientDC(self
) 
3845             renderer
.DrawDropDownArrow(self
, dc
) 
3847             self
.PopupTabsMenu() 
3850     def HitTest(self
, pt
): 
3852         HitTest method for L{PageContainer}. 
3853         Returns the flag (if any) and the hit page (if any). 
3856         style 
= self
.GetParent().GetWindowStyleFlag() 
3857         render 
= self
._mgr
.GetRenderer(style
) 
3859         fullrect 
= self
.GetClientRect() 
3860         btnLeftPos 
= render
.GetLeftButtonPos(self
) 
3861         btnRightPos 
= render
.GetRightButtonPos(self
) 
3862         btnXPos 
= render
.GetXPos(self
) 
3866         if len(self
._pagesInfoVec
) == 0: 
3867             return FNB_NOWHERE
, tabIdx
 
3869         rect 
= wx
.Rect(btnXPos
, 8, 16, 16) 
3870         if rect
.Contains(pt
): 
3871             return (style 
& FNB_NO_X_BUTTON 
and [FNB_NOWHERE
] or [FNB_X
])[0], tabIdx
 
3873         rect 
= wx
.Rect(btnRightPos
, 8, 16, 16) 
3874         if style 
& FNB_DROPDOWN_TABS_LIST
: 
3875             rect 
= wx
.Rect(render
.GetDropArrowButtonPos(self
), 8, 16, 16) 
3876             if rect
.Contains(pt
): 
3877                 return FNB_DROP_DOWN_ARROW
, tabIdx
 
3879         if rect
.Contains(pt
): 
3880             return (style 
& FNB_NO_NAV_BUTTONS 
and [FNB_NOWHERE
] or [FNB_RIGHT_ARROW
])[0], tabIdx
 
3882         rect 
= wx
.Rect(btnLeftPos
, 8, 16, 16) 
3883         if rect
.Contains(pt
): 
3884             return (style 
& FNB_NO_NAV_BUTTONS 
and [FNB_NOWHERE
] or [FNB_LEFT_ARROW
])[0], tabIdx
 
3886         # Test whether a left click was made on a tab 
3889         for cur 
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)): 
3891             pgInfo 
= self
._pagesInfoVec
[cur
] 
3893             if pgInfo
.GetPosition() == wx
.Point(-1, -1): 
3896             if style 
& FNB_X_ON_TAB 
and cur 
== self
.GetSelection(): 
3897                 # 'x' button exists on a tab 
3898                 if self
._pagesInfoVec
[cur
].GetXRect().Contains(pt
): 
3899                     return FNB_TAB_X
, cur
 
3903                 if self
._pagesInfoVec
[cur
].GetRegion().Contains(pt
.x
, pt
.y
): 
3904                     if bFoundMatch 
or cur 
== self
.GetSelection():     
3912                 tabRect 
= wx
.Rect(pgInfo
.GetPosition().x
, pgInfo
.GetPosition().y
, 
3913                                   pgInfo
.GetSize().x
, pgInfo
.GetSize().y
) 
3915                 if tabRect
.Contains(pt
): 
3920             return FNB_TAB
, tabIdx
 
3922         if self
._isdragging
: 
3923             # We are doing DND, so check also the region outside the tabs 
3924             # try before the first tab 
3925             pgInfo 
= self
._pagesInfoVec
[0] 
3926             tabRect 
= wx
.Rect(0, pgInfo
.GetPosition().y
, pgInfo
.GetPosition().x
, self
.GetParent().GetSize().y
) 
3927             if tabRect
.Contains(pt
): 
3930             # try after the last tab 
3931             pgInfo 
= self
._pagesInfoVec
[-1] 
3932             startpos 
= pgInfo
.GetPosition().x
+pgInfo
.GetSize().x
 
3933             tabRect 
= wx
.Rect(startpos
, pgInfo
.GetPosition().y
, fullrect
.width
-startpos
, self
.GetParent().GetSize().y
) 
3935             if tabRect
.Contains(pt
): 
3936                 return FNB_TAB
, len(self
._pagesInfoVec
)         
3939         return FNB_NOWHERE
, -1 
3942     def SetSelection(self
, page
): 
3943         """ Sets the selected page. """ 
3945         book 
= self
.GetParent() 
3946         book
.SetSelection(page
) 
3947         self
.DoSetSelection(page
) 
3950     def DoSetSelection(self
, page
): 
3951         """ Does the actual selection of a page. """ 
3953         if page 
< len(self
._pagesInfoVec
): 
3955             da_page 
= self
._pParent
.GetPage(page
) 
3960         if not self
.IsTabVisible(page
): 
3961             # Try to remove one tab from start and try again 
3963             if not self
.CanFitToScreen(page
): 
3965                 if self
._nFrom 
> page
: 
3968                     while self
._nFrom 
< page
: 
3970                         if self
.CanFitToScreen(page
): 
3976     def DeletePage(self
, page
): 
3977         """ Delete the specified page from L{FlatNotebook}. """ 
3979         book 
= self
.GetParent() 
3980         book
.DeletePage(page
) 
3984     def IsTabVisible(self
, page
): 
3985         """ Returns whether a tab is visible or not. """ 
3987         iLastVisiblePage 
= self
.GetLastVisibleTab() 
3988         return page 
<= iLastVisiblePage 
and page 
>= self
._nFrom
 
3991     def DoDeletePage(self
, page
): 
3992         """ Does the actual page deletion. """ 
3994         # Remove the page from the vector 
3995         book 
= self
.GetParent() 
3996         self
._pagesInfoVec
.pop(page
) 
3998         # Thanks to Yiaanis AKA Mandrav 
3999         if self
._iActivePage 
>= page
: 
4000             self
._iActivePage 
= self
._iActivePage 
- 1 
4001             self
._iPreviousActivePage 
= -1 
4003         # The delete page was the last first on the array, 
4004         # but the book still has more pages, so we set the 
4005         # active page to be the first one (0) 
4006         if self
._iActivePage 
< 0 and len(self
._pagesInfoVec
) > 0: 
4007             self
._iActivePage 
= 0 
4008             self
._iPreviousActivePage 
= -1 
4011         if self
._iActivePage 
>= 0: 
4013             book
._bForceSelection 
= True 
4015             # Check for selection and send event 
4016             event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId()) 
4017             event
.SetSelection(self
._iActivePage
) 
4018             event
.SetOldSelection(self
._iPreviousActivePage
) 
4019             event
.SetEventObject(self
.GetParent()) 
4021             book
.SetSelection(self
._iActivePage
) 
4022             book
._bForceSelection 
= False 
4024             # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event 
4025             event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
) 
4026             event
.SetOldSelection(self
._iPreviousActivePage
) 
4027             self
.GetParent().GetEventHandler().ProcessEvent(event
)             
4029         if not self
._pagesInfoVec
:         
4030             # Erase the page container drawings 
4031             dc 
= wx
.ClientDC(self
) 
4035     def DeleteAllPages(self
): 
4036         """ Deletes all the pages. """ 
4038         self
._iActivePage 
= -1 
4039         self
._iPreviousActivePage 
= -1 
4041         self
._pagesInfoVec 
= [] 
4043         # Erase the page container drawings 
4044         dc 
= wx
.ClientDC(self
) 
4048     def OnMouseMove(self
, event
): 
4049         """ Handles the wx.EVT_MOTION for L{PageContainer}. """ 
4051         if self
._pagesInfoVec 
and self
.IsShown(): 
4053             xButtonStatus 
= self
._nXButtonStatus
 
4054             xTabButtonStatus 
= self
._nTabXButtonStatus
 
4055             rightButtonStatus 
= self
._nRightButtonStatus
 
4056             leftButtonStatus 
= self
._nLeftButtonStatus
 
4057             dropDownButtonStatus 
= self
._nArrowDownButtonStatus
 
4059             style 
= self
.GetParent().GetWindowStyleFlag() 
4061             self
._nXButtonStatus 
= FNB_BTN_NONE
 
4062             self
._nRightButtonStatus 
= FNB_BTN_NONE
 
4063             self
._nLeftButtonStatus 
= FNB_BTN_NONE
 
4064             self
._nTabXButtonStatus 
= FNB_BTN_NONE
 
4065             self
._nArrowDownButtonStatus 
= FNB_BTN_NONE
 
4067             where
, tabIdx 
= self
.HitTest(event
.GetPosition()) 
4070                 if event
.LeftIsDown(): 
4072                     self
._nXButtonStatus 
= (self
._nLeftClickZone
==FNB_X 
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0] 
4076                     self
._nXButtonStatus 
= FNB_BTN_HOVER
 
4078             elif where 
== FNB_DROP_DOWN_ARROW
: 
4079                 if event
.LeftIsDown(): 
4081                     self
._nArrowDownButtonStatus 
= (self
._nLeftClickZone
==FNB_DROP_DOWN_ARROW 
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0] 
4085                     self
._nArrowDownButtonStatus 
= FNB_BTN_HOVER
 
4087             elif where 
== FNB_TAB_X
: 
4088                 if event
.LeftIsDown(): 
4090                     self
._nTabXButtonStatus 
= (self
._nLeftClickZone
==FNB_TAB_X 
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0] 
4094                     self
._nTabXButtonStatus 
= FNB_BTN_HOVER
 
4096             elif where 
== FNB_RIGHT_ARROW
: 
4097                 if event
.LeftIsDown(): 
4099                     self
._nRightButtonStatus 
= (self
._nLeftClickZone
==FNB_RIGHT_ARROW 
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0] 
4103                     self
._nRightButtonStatus 
= FNB_BTN_HOVER
 
4105             elif where 
== FNB_LEFT_ARROW
: 
4106                 if event
.LeftIsDown(): 
4108                     self
._nLeftButtonStatus 
= (self
._nLeftClickZone
==FNB_LEFT_ARROW 
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0] 
4112                     self
._nLeftButtonStatus 
= FNB_BTN_HOVER
 
4114             elif where 
== FNB_TAB
: 
4115                 # Call virtual method for showing tooltip 
4116                 self
.ShowTabTooltip(tabIdx
) 
4118                 if not self
.GetEnabled(tabIdx
):                 
4119                     # Set the cursor to be 'No-entry' 
4120                     wx
.SetCursor(wx
.StockCursor(wx
.CURSOR_NO_ENTRY
)) 
4122                 # Support for drag and drop 
4123                 if event
.Dragging() and not (style 
& FNB_NODRAG
): 
4125                     self
._isdragging 
= True                 
4126                     draginfo 
= FNBDragInfo(self
, tabIdx
) 
4127                     drginfo 
= cPickle
.dumps(draginfo
) 
4128                     dataobject 
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook")) 
4129                     dataobject
.SetData(drginfo
) 
4130                     dragSource 
= FNBDropSource(self
) 
4131                     dragSource
.SetData(dataobject
) 
4132                     dragSource
.DoDragDrop(wx
.Drag_DefaultMove
) 
4134             bRedrawX 
= self
._nXButtonStatus 
!= xButtonStatus
 
4135             bRedrawRight 
= self
._nRightButtonStatus 
!= rightButtonStatus
 
4136             bRedrawLeft 
= self
._nLeftButtonStatus 
!= leftButtonStatus
 
4137             bRedrawTabX 
= self
._nTabXButtonStatus 
!= xTabButtonStatus
 
4138             bRedrawDropArrow 
= self
._nArrowDownButtonStatus 
!= dropDownButtonStatus
 
4140             render 
= self
._mgr
.GetRenderer(style
) 
4142             if (bRedrawX 
or bRedrawRight 
or bRedrawLeft 
or bRedrawTabX 
or bRedrawDropArrow
): 
4144                 dc 
= wx
.ClientDC(self
) 
4148                     render
.DrawX(self
, dc
) 
4152                     render
.DrawLeftArrow(self
, dc
) 
4156                     render
.DrawRightArrow(self
, dc
) 
4160                     render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[tabIdx
].GetXRect(), tabIdx
, self
._nTabXButtonStatus
) 
4162                 if bRedrawDropArrow
: 
4164                     render
.DrawDropDownArrow(self
, dc
) 
4169     def GetLastVisibleTab(self
): 
4170         """ Returns the last visible tab. """ 
4177         for ii 
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)): 
4179             if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1): 
4185     def GetNumTabsCanScrollLeft(self
): 
4186         """ Returns the number of tabs than can be scrolled left. """ 
4188         # Reserved area for the buttons (<>x) 
4189         rect 
= self
.GetClientRect() 
4190         clientWidth 
= rect
.width
 
4191         posx 
= self
._pParent
._nPadding
 
4195         # In case we have error prevent crash 
4199         dc 
= wx
.ClientDC(self
) 
4201         style 
= self
.GetParent().GetWindowStyleFlag() 
4202         render 
= self
._mgr
.GetRenderer(style
) 
4204         for ii 
in xrange(self
._nFrom
, -1, -1): 
4206             boldFont 
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)         
4207             boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
) 
4208             dc
.SetFont(boldFont
) 
4210             height 
= dc
.GetCharHeight() 
4212             tabHeight 
= height 
+ FNB_HEIGHT_SPACER 
# We use 6 pixels as padding 
4213             if style 
& FNB_VC71
: 
4214                 tabHeight 
= (style 
& FNB_BOTTOM 
and [tabHeight 
- 4] or [tabHeight
])[0] 
4215             elif style 
& FNB_FANCY_TABS
: 
4216                 tabHeight 
= (style 
& FNB_BOTTOM 
and [tabHeight 
- 3] or [tabHeight
])[0] 
4218             width
, pom 
= dc
.GetTextExtent(self
.GetPageText(ii
)) 
4219             if style 
!= FNB_VC71
: 
4220                 shapePoints 
= int(tabHeight
*math
.tan(float(self
._pagesInfoVec
[ii
].GetTabAngle())/180.0*math
.pi
)) 
4224             tabWidth 
= 2*self
._pParent
._nPadding 
+ width
 
4226             if not (style 
& FNB_VC71
): 
4228                 tabWidth 
+= 2*shapePoints
 
4230             hasImage 
= self
._ImageList 
!= None and self
._pagesInfoVec
[ii
].GetImageIndex() != -1 
4232             # For VC71 style, we only add the icon size (16 pixels) 
4235                 if not self
.IsDefaultTabs(): 
4236                     tabWidth 
+= 16 + self
._pParent
._nPadding
 
4239                     tabWidth 
+= 16 + self
._pParent
._nPadding 
+ shapePoints
/2 
4241             if posx 
+ tabWidth 
+ render
.GetButtonsAreaLength(self
) >= clientWidth
: 
4244             numTabs 
= numTabs 
+ 1 
4250     def IsDefaultTabs(self
): 
4251         """ Returns whether a tab has a default style. """ 
4253         style 
= self
.GetParent().GetWindowStyleFlag() 
4254         res 
= (style 
& FNB_VC71
) or (style 
& FNB_FANCY_TABS
) or (style 
& FNB_VC8
) 
4258     def AdvanceSelection(self
, bForward
=True): 
4260         Cycles through the tabs. 
4261         The call to this function generates the page changing events. 
4264         nSel 
= self
.GetSelection() 
4269         nMax 
= self
.GetPageCount() - 1 
4272             newSelection 
= (nSel 
== nMax 
and [0] or [nSel 
+ 1])[0] 
4274             newSelection 
= (nSel 
== 0 and [nMax
] or [nSel 
- 1])[0] 
4276         if not self
._pagesInfoVec
[newSelection
].GetEnabled(): 
4279         self
.FireEvent(newSelection
) 
4282     def OnMouseLeave(self
, event
): 
4283         """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """ 
4285         self
._nLeftButtonStatus 
= FNB_BTN_NONE
 
4286         self
._nXButtonStatus 
= FNB_BTN_NONE
 
4287         self
._nRightButtonStatus 
= FNB_BTN_NONE
 
4288         self
._nTabXButtonStatus 
= FNB_BTN_NONE
 
4289         self
._nArrowDownButtonStatus 
= FNB_BTN_NONE
 
4291         style 
= self
.GetParent().GetWindowStyleFlag()         
4292         render 
= self
._mgr
.GetRenderer(style
) 
4294         dc 
= wx
.ClientDC(self
) 
4296         render
.DrawX(self
, dc
) 
4297         render
.DrawLeftArrow(self
, dc
) 
4298         render
.DrawRightArrow(self
, dc
) 
4300         selection 
= self
.GetSelection() 
4306         if not self
.IsTabVisible(selection
): 
4307             if selection 
== len(self
._pagesInfoVec
) - 1: 
4308                 if not self
.CanFitToScreen(selection
): 
4315         render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[selection
].GetXRect(), selection
, self
._nTabXButtonStatus
) 
4320     def OnMouseEnterWindow(self
, event
): 
4321         """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """ 
4323         self
._nLeftButtonStatus 
= FNB_BTN_NONE
 
4324         self
._nXButtonStatus 
= FNB_BTN_NONE
 
4325         self
._nRightButtonStatus 
= FNB_BTN_NONE
 
4326         self
._nLeftClickZone 
= FNB_BTN_NONE
 
4327         self
._nArrowDownButtonStatus 
= FNB_BTN_NONE
 
4332     def ShowTabTooltip(self
, tabIdx
): 
4333         """ Shows a tab tooltip. """ 
4335         pWindow 
= self
._pParent
.GetPage(tabIdx
) 
4338             pToolTip 
= pWindow
.GetToolTip() 
4339             if pToolTip 
and pToolTip
.GetWindow() == pWindow
: 
4340                 self
.SetToolTipString(pToolTip
.GetTip()) 
4343     def SetPageImage(self
, page
, imgindex
): 
4344         """ Sets the image index associated to a page. """ 
4346         if page 
< len(self
._pagesInfoVec
): 
4348             self
._pagesInfoVec
[page
].SetImageIndex(imgindex
) 
4352     def GetPageImage(self
, page
): 
4353         """ Returns the image index associated to a page. """ 
4355         if page 
< len(self
._pagesInfoVec
): 
4357             return self
._pagesInfoVec
[page
].GetImageIndex() 
4362     def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
): 
4363         """ Handles the drop action from a DND operation. """ 
4365         # Disable drag'n'drop for disabled tab 
4366         if not wnd_oldContainer
._pagesInfoVec
[nTabPage
].GetEnabled(): 
4367             return wx
.DragCancel
 
4369         self
._isdragging 
= True 
4370         oldContainer 
= wnd_oldContainer
 
4373         where
, nIndex 
= self
.HitTest(wx
.Point(x
, y
)) 
4375         oldNotebook 
= oldContainer
.GetParent() 
4376         newNotebook 
= self
.GetParent() 
4378         if oldNotebook 
== newNotebook
: 
4382                 if where 
== FNB_TAB
: 
4383                     self
.MoveTabPage(nTabPage
, nIndex
) 
4385         elif self
.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND
: 
4387             if wx
.Platform 
in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]: 
4390                     window 
= oldNotebook
.GetPage(nTabPage
) 
4393                         where
, nIndex 
= newNotebook
._pages
.HitTest(wx
.Point(x
, y
)) 
4394                         caption 
= oldContainer
.GetPageText(nTabPage
) 
4395                         imageindex 
= oldContainer
.GetPageImage(nTabPage
) 
4396                         oldNotebook
.RemovePage(nTabPage
) 
4397                         window
.Reparent(newNotebook
) 
4401                             bmp 
= oldNotebook
.GetImageList().GetIcon(imageindex
) 
4402                             newImageList 
= newNotebook
.GetImageList() 
4404                             if not newImageList
: 
4405                                 xbmp
, ybmp 
= bmp
.GetWidth(), bmp
.GetHeight() 
4406                                 newImageList 
= wx
.ImageList(xbmp
, ybmp
)                                 
4409                                 imageindex 
= newImageList
.GetImageCount() 
4411                             newImageList
.AddIcon(bmp
) 
4412                             newNotebook
.SetImageList(newImageList
) 
4414                         newNotebook
.InsertPage(nIndex
, window
, caption
, True, imageindex
) 
4416         self
._isdragging 
= False 
4421     def MoveTabPage(self
, nMove
, nMoveTo
): 
4422         """ Moves a tab inside the same L{FlatNotebook}. """ 
4424         if nMove 
== nMoveTo
: 
4427         elif nMoveTo 
< len(self
._pParent
._windows
): 
4428             nMoveTo 
= nMoveTo 
+ 1 
4430         self
._pParent
.Freeze() 
4432         # Remove the window from the main sizer 
4433         nCurSel 
= self
._pParent
._pages
.GetSelection() 
4434         self
._pParent
._mainSizer
.Detach(self
._pParent
._windows
[nCurSel
]) 
4435         self
._pParent
._windows
[nCurSel
].Hide() 
4437         pWindow 
= self
._pParent
._windows
[nMove
] 
4438         self
._pParent
._windows
.pop(nMove
) 
4439         self
._pParent
._windows
.insert(nMoveTo
-1, pWindow
) 
4441         pgInfo 
= self
._pagesInfoVec
[nMove
] 
4443         self
._pagesInfoVec
.pop(nMove
) 
4444         self
._pagesInfoVec
.insert(nMoveTo 
- 1, pgInfo
) 
4446         # Add the page according to the style 
4447         pSizer 
= self
._pParent
._mainSizer
 
4448         style 
= self
.GetParent().GetWindowStyleFlag() 
4450         if style 
& FNB_BOTTOM
: 
4452             pSizer
.Insert(0, pWindow
, 1, wx
.EXPAND
) 
4456             # We leave a space of 1 pixel around the window 
4457             pSizer
.Add(pWindow
, 1, wx
.EXPAND
) 
4462         self
._iActivePage 
= nMoveTo 
- 1 
4463         self
._iPreviousActivePage 
= -1 
4464         self
.DoSetSelection(self
._iActivePage
) 
4466         self
._pParent
.Thaw() 
4469     def CanFitToScreen(self
, page
): 
4470         """ Returns wheter a tab can fit in the left space in the screen or not. """ 
4472         # Incase the from is greater than page, 
4473         # we need to reset the self._nFrom, so in order 
4474         # to force the caller to do so, we return false 
4475         if self
._nFrom 
> page
: 
4478         style 
= self
.GetParent().GetWindowStyleFlag() 
4479         render 
= self
._mgr
.GetRenderer(style
) 
4481         vTabInfo 
= render
.NumberTabsCanFit(self
) 
4483         if page 
- self
._nFrom 
>= len(vTabInfo
): 
4489     def GetNumOfVisibleTabs(self
): 
4490         """ Returns the number of visible tabs. """ 
4493         for ii 
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)): 
4494             if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1): 
4501     def GetEnabled(self
, page
): 
4502         """ Returns whether a tab is enabled or not. """ 
4504         if page 
>= len(self
._pagesInfoVec
): 
4505             return True # Seems strange, but this is the default 
4507         return self
._pagesInfoVec
[page
].GetEnabled() 
4510     def Enable(self
, page
, enabled
=True): 
4511         """ Enables or disables a tab. """ 
4513         if page 
>= len(self
._pagesInfoVec
): 
4516         self
._pagesInfoVec
[page
].Enable(enabled
) 
4519     def GetSingleLineBorderColour(self
): 
4520         """ Returns the colour for the single line border. """ 
4522         if self
.HasFlag(FNB_FANCY_TABS
): 
4523             return self
._colorFrom
 
4528     def HasFlag(self
, flag
): 
4529         """ Returns whether a flag is present in the L{FlatNotebook} style. """ 
4531         style 
= self
.GetParent().GetWindowStyleFlag() 
4532         res 
= (style 
& flag 
and [True] or [False])[0] 
4536     def ClearFlag(self
, flag
): 
4537         """ Deletes a flag from the L{FlatNotebook} style. """ 
4539         style 
= self
.GetParent().GetWindowStyleFlag() 
4541         self
.SetWindowStyleFlag(style
) 
4544     def TabHasImage(self
, tabIdx
): 
4545         """ Returns whether a tab has an associated image index or not. """ 
4548             return self
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1 
4553     def OnLeftDClick(self
, event
): 
4554         """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """ 
4556         if self
.HasFlag(FNB_DCLICK_CLOSES_TABS
): 
4558             where
, tabIdx 
= self
.HitTest(event
.GetPosition()) 
4560             if where 
== FNB_TAB
: 
4561                 self
.DeletePage(tabIdx
) 
4568     def PopupTabsMenu(self
): 
4569         """ Pops up the menu activated with the drop down arrow in the navigation area. """ 
4571         popupMenu 
= wx
.Menu() 
4573         for i 
in xrange(len(self
._pagesInfoVec
)): 
4574             pi 
= self
._pagesInfoVec
[i
] 
4575             item 
= wx
.MenuItem(popupMenu
, i
, pi
.GetCaption(), pi
.GetCaption(), wx
.ITEM_NORMAL
) 
4576             self
.Bind(wx
.EVT_MENU
, self
.OnTabMenuSelection
, item
) 
4578             # This code is commented, since there is an alignment problem with wx2.6.3 & Menus 
4579             # if self.TabHasImage(ii): 
4580             #   item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] ); 
4582             popupMenu
.AppendItem(item
) 
4583             item
.Enable(pi
.GetEnabled()) 
4585         self
.PopupMenu(popupMenu
) 
4588     def OnTabMenuSelection(self
, event
): 
4589         """ Handles the wx.EVT_MENU event for L{PageContainer}. """ 
4591         selection 
= event
.GetId() 
4592         self
.FireEvent(selection
) 
4595     def FireEvent(self
, selection
): 
4597         Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events 
4598         called from other methods (from menu selection or Smart Tabbing). 
4602         if selection 
== self
._iActivePage
: 
4603             # No events for the same selection 
4606         oldSelection 
= self
._iActivePage
 
4608         event 
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId()) 
4609         event
.SetSelection(selection
) 
4610         event
.SetOldSelection(oldSelection
) 
4611         event
.SetEventObject(self
.GetParent()) 
4613         if not self
.GetParent().GetEventHandler().ProcessEvent(event
) or event
.IsAllowed(): 
4615             self
.SetSelection(selection
) 
4617             # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event 
4618             event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
) 
4619             event
.SetOldSelection(oldSelection
) 
4620             self
.GetParent().GetEventHandler().ProcessEvent(event
) 
4623     def SetImageList(self
, imglist
): 
4624         """ Sets the image list for the page control. """ 
4626         self
._ImageList 
= imglist
 
4629     def AssignImageList(self
, imglist
): 
4630         """ Assigns the image list for the page control. """ 
4632         self
._ImageList 
= imglist
 
4635     def GetImageList(self
): 
4636         """ Returns the image list for the page control. """ 
4638         return self
._ImageList
 
4641     def GetSelection(self
): 
4642         """ Returns the current selected page. """ 
4644         return self
._iActivePage 
 
4647     def GetPageCount(self
): 
4648         """ Returns the number of tabs in the L{FlatNotebook} control. """ 
4650         return len(self
._pagesInfoVec
) 
4653     def GetPageText(self
, page
): 
4654         """ Returns the tab caption of the page. """ 
4656         return self
._pagesInfoVec
[page
].GetCaption()  
4659     def SetPageText(self
, page
, text
): 
4660         """ Sets the tab caption of the page. """ 
4662         self
._pagesInfoVec
[page
].SetCaption(text
) 
4666     def DrawDragHint(self
): 
4667         """ Draws small arrow at the place that the tab will be placed. """ 
4669         # get the index of tab that will be replaced with the dragged tab 
4670         pt 
= wx
.GetMousePosition() 
4671         client_pt 
= self
.ScreenToClient(pt
) 
4672         where
, tabIdx 
= self
.HitTest(client_pt
) 
4673         self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag()).DrawDragHint(self
, tabIdx
)