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: 10 Oct 2006, 21.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 @ 10 Oct 2006, 21.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 VERTICAL_BORDER_PADDING
= 4
151 # Button size is a 16x16 xpm bitmap
153 """Button size is a 16x16 xpm bitmap"""
157 MASK_COLOR
= wx
.Colour(0, 128, 128)
158 """Mask colour for the arrow bitmaps"""
162 """Navigation button is pressed"""
164 """Navigation button is hovered"""
169 FNB_TAB
= 1 # On a tab
170 """Indicates mouse coordinates inside a tab"""
171 FNB_X
= 2 # On the X button
172 """Indicates mouse coordinates inside the I{X} region"""
173 FNB_TAB_X
= 3 # On the 'X' button (tab's X button)
174 """Indicates mouse coordinates inside the I{X} region in a tab"""
175 FNB_LEFT_ARROW
= 4 # On the rotate left arrow button
176 """Indicates mouse coordinates inside the left arrow region"""
177 FNB_RIGHT_ARROW
= 5 # On the rotate right arrow button
178 """Indicates mouse coordinates inside the right arrow region"""
179 FNB_DROP_DOWN_ARROW
= 6 # On the drop down arrow button
180 """Indicates mouse coordinates inside the drop down arrow region"""
181 FNB_NOWHERE
= 0 # Anywhere else
182 """Indicates mouse coordinates not on any tab of the notebook"""
184 FNB_DEFAULT_STYLE
= FNB_MOUSE_MIDDLE_CLOSES_TABS
185 """L{FlatNotebook} default style"""
187 # FlatNotebook Events:
188 # wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page;
189 # wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch
190 # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call
191 # event.Skip() In Your Event Handler;
192 # wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But
193 # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip()
194 # In Your Event Handler;
195 # wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed.
196 # wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab.
198 wxEVT_FLATNOTEBOOK_PAGE_CHANGED
= wx
.NewEventType()
199 wxEVT_FLATNOTEBOOK_PAGE_CHANGING
= wx
.NewEventType()
200 wxEVT_FLATNOTEBOOK_PAGE_CLOSING
= wx
.NewEventType()
201 wxEVT_FLATNOTEBOOK_PAGE_CLOSED
= wx
.NewEventType()
202 wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
= wx
.NewEventType()
204 #-----------------------------------#
206 #-----------------------------------#
208 EVT_FLATNOTEBOOK_PAGE_CHANGED
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
, 1)
209 """Notify client objects when the active page in L{FlatNotebook}
211 EVT_FLATNOTEBOOK_PAGE_CHANGING
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, 1)
212 """Notify client objects when the active page in L{FlatNotebook}
213 is about to change."""
214 EVT_FLATNOTEBOOK_PAGE_CLOSING
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, 1)
215 """Notify client objects when a page in L{FlatNotebook} is closing."""
216 EVT_FLATNOTEBOOK_PAGE_CLOSED
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, 1)
217 """Notify client objects when a page in L{FlatNotebook} has been closed."""
218 EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, 1)
219 """Notify client objects when a pop-up menu should appear next to a tab."""
222 # Some icons in XPM format
224 left_arrow_disabled_xpm
= [
252 x_button_pressed_xpm
= [
309 x_button_hilite_xpm
= [
365 left_arrow_pressed_xpm
= [
393 left_arrow_hilite_xpm
= [
421 right_arrow_disabled_xpm
= [
449 right_arrow_hilite_xpm
= [
477 right_arrow_pressed_xpm
= [
534 down_arrow_hilite_xpm
= [
562 down_arrow_pressed_xpm
= [
620 #----------------------------------------------------------------------
621 def GetMondrianData():
623 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
624 \x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\
625 ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\
626 o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\
627 \xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\
628 \x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\
629 \x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82'
632 def GetMondrianBitmap():
633 return wx
.BitmapFromImage(GetMondrianImage().Scale(16, 16))
636 def GetMondrianImage():
638 stream
= cStringIO
.StringIO(GetMondrianData())
639 return wx
.ImageFromStream(stream
)
642 def GetMondrianIcon():
643 icon
= wx
.EmptyIcon()
644 icon
.CopyFromBitmap(GetMondrianBitmap())
646 #----------------------------------------------------------------------
649 def LightColour(color
, percent
):
650 """ Brighten input colour by percent. """
654 rd
= end_color
.Red() - color
.Red()
655 gd
= end_color
.Green() - color
.Green()
656 bd
= end_color
.Blue() - color
.Blue()
660 # We take the percent way of the color from color -. white
662 r
= color
.Red() + ((i
*rd
*100)/high
)/100
663 g
= color
.Green() + ((i
*gd
*100)/high
)/100
664 b
= color
.Blue() + ((i
*bd
*100)/high
)/100
665 return wx
.Colour(r
, g
, b
)
669 """ Creates a random colour. """
671 r
= random
.randint(0, 255) # Random value betweem 0-255
672 g
= random
.randint(0, 255) # Random value betweem 0-255
673 b
= random
.randint(0, 255) # Random value betweem 0-255
675 return wx
.Colour(r
, g
, b
)
678 def PaintStraightGradientBox(dc
, rect
, startColor
, endColor
, vertical
=True):
679 """ Draws a gradient colored box from startColor to endColor. """
681 rd
= endColor
.Red() - startColor
.Red()
682 gd
= endColor
.Green() - startColor
.Green()
683 bd
= endColor
.Blue() - startColor
.Blue()
685 # Save the current pen and brush
686 savedPen
= dc
.GetPen()
687 savedBrush
= dc
.GetBrush()
690 high
= rect
.GetHeight()-1
692 high
= rect
.GetWidth()-1
697 for i
in xrange(high
+1):
699 r
= startColor
.Red() + ((i
*rd
*100)/high
)/100
700 g
= startColor
.Green() + ((i
*gd
*100)/high
)/100
701 b
= startColor
.Blue() + ((i
*bd
*100)/high
)/100
703 p
= wx
.Pen(wx
.Colour(r
, g
, b
))
707 dc
.DrawLine(rect
.x
, rect
.y
+i
, rect
.x
+rect
.width
, rect
.y
+i
)
709 dc
.DrawLine(rect
.x
+i
, rect
.y
, rect
.x
+i
, rect
.y
+rect
.height
)
711 # Restore the pen and brush
713 dc
.SetBrush(savedBrush
)
717 # ---------------------------------------------------------------------------- #
719 # Stores All The Information To Allow Drag And Drop Between Different
721 # ---------------------------------------------------------------------------- #
725 _map
= weakref
.WeakValueDictionary()
727 def __init__(self
, container
, pageindex
):
728 """ Default class constructor. """
730 self
._id
= id(container
)
731 FNBDragInfo
._map
[self
._id
] = container
732 self
._pageindex
= pageindex
735 def GetContainer(self
):
736 """ Returns the L{FlatNotebook} page (usually a panel). """
738 return FNBDragInfo
._map
.get(self
._id
, None)
741 def GetPageIndex(self
):
742 """ Returns the page index associated with a page. """
744 return self
._pageindex
747 # ---------------------------------------------------------------------------- #
748 # Class FNBDropTarget
749 # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between
750 # Different FlatNotebooks.
751 # ---------------------------------------------------------------------------- #
753 class FNBDropTarget(wx
.DropTarget
):
755 def __init__(self
, parent
):
756 """ Default class constructor. """
758 wx
.DropTarget
.__init
__(self
)
760 self
._parent
= parent
761 self
._dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
762 self
.SetDataObject(self
._dataobject
)
765 def OnData(self
, x
, y
, dragres
):
766 """ Handles the OnData() method to call the real DnD routine. """
768 if not self
.GetData():
771 draginfo
= self
._dataobject
.GetData()
772 drginfo
= cPickle
.loads(draginfo
)
774 return self
._parent
.OnDropTarget(x
, y
, drginfo
.GetPageIndex(), drginfo
.GetContainer())
777 # ---------------------------------------------------------------------------- #
779 # Contains parameters for every FlatNotebook page
780 # ---------------------------------------------------------------------------- #
784 This class holds all the information (caption, image, etc...) belonging to a
785 single tab in L{FlatNotebook}.
788 def __init__(self
, caption
="", imageindex
=-1, tabangle
=0, enabled
=True):
790 Default Class Constructor.
793 @param caption: the tab caption;
794 @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
795 @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
796 @param enabled: sets enabled or disabled the tab.
799 self
._strCaption
= caption
800 self
._TabAngle
= tabangle
801 self
._ImageIndex
= imageindex
802 self
._bEnabled
= enabled
803 self
._pos
= wx
.Point(-1, -1)
804 self
._size
= wx
.Size(-1, -1)
805 self
._region
= wx
.Region()
806 self
._xRect
= wx
.Rect()
810 def SetCaption(self
, value
):
811 """ Sets the tab caption. """
813 self
._strCaption
= value
816 def GetCaption(self
):
817 """ Returns the tab caption. """
819 return self
._strCaption
822 def SetPosition(self
, value
):
823 """ Sets the tab position. """
828 def GetPosition(self
):
829 """ Returns the tab position. """
834 def SetSize(self
, value
):
835 """ Sets the tab size. """
841 """ Returns the tab size. """
846 def SetTabAngle(self
, value
):
847 """ Sets the tab header angle (0 <= tab <= 15 degrees). """
849 self
._TabAngle
= min(45, value
)
852 def GetTabAngle(self
):
853 """ Returns the tab angle. """
855 return self
._TabAngle
858 def SetImageIndex(self
, value
):
859 """ Sets the tab image index. """
861 self
._ImageIndex
= value
864 def GetImageIndex(self
):
865 """ Returns the tab umage index. """
867 return self
._ImageIndex
870 def GetEnabled(self
):
871 """ Returns whether the tab is enabled or not. """
873 return self
._bEnabled
876 def Enable(self
, enabled
):
877 """ Sets the tab enabled or disabled. """
879 self
._bEnabled
= enabled
882 def SetRegion(self
, points
=[]):
883 """ Sets the tab region. """
885 self
._region
= wx
.RegionFromPoints(points
)
889 """ Returns the tab region. """
894 def SetXRect(self
, xrect
):
895 """ Sets the button 'X' area rect. """
901 """ Returns the button 'X' area rect. """
907 """ Returns the tab colour. """
912 def SetColour(self
, color
):
913 """ Sets the tab colour. """
918 # ---------------------------------------------------------------------------- #
919 # Class FlatNotebookEvent
920 # ---------------------------------------------------------------------------- #
922 class FlatNotebookEvent(wx
.PyCommandEvent
):
924 This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
925 EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING,
926 EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is
927 mapped in the parent.
930 def __init__(self
, eventType
, id=1, nSel
=-1, nOldSel
=-1):
931 """ Default class constructor. """
933 wx
.PyCommandEvent
.__init
__(self
, eventType
, id)
934 self
._eventType
= eventType
936 self
.notify
= wx
.NotifyEvent(eventType
, id)
939 def GetNotifyEvent(self
):
940 """Returns the actual wx.NotifyEvent."""
946 """Returns whether the event is allowed or not."""
948 return self
.notify
.IsAllowed()
952 """Vetos the event."""
958 """The event is allowed."""
963 def SetSelection(self
, nSel
):
964 """ Sets event selection. """
966 self
._selection
= nSel
969 def SetOldSelection(self
, nOldSel
):
970 """ Sets old event selection. """
972 self
._oldselection
= nOldSel
975 def GetSelection(self
):
976 """ Returns event selection. """
978 return self
._selection
981 def GetOldSelection(self
):
982 """ Returns old event selection """
984 return self
._oldselection
987 # ---------------------------------------------------------------------------- #
988 # Class TabNavigatorWindow
989 # ---------------------------------------------------------------------------- #
991 class TabNavigatorWindow(wx
.Dialog
):
993 This class is used to create a modal dialog that enables "Smart Tabbing",
994 similar to what you would get by hitting Alt+Tab on Windows.
997 def __init__(self
, parent
=None):
998 """ Default class constructor. Used internally."""
1000 wx
.Dialog
.__init
__(self
, parent
, wx
.ID_ANY
, "", style
=0)
1002 self
._selectedItem
= -1
1005 self
._bmp
= GetMondrianBitmap()
1007 sz
= wx
.BoxSizer(wx
.VERTICAL
)
1009 self
._listBox
= wx
.ListBox(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, 150), [], wx
.LB_SINGLE | wx
.NO_BORDER
)
1011 mem_dc
= wx
.MemoryDC()
1012 mem_dc
.SelectObject(wx
.EmptyBitmap(10,10))
1013 font
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1014 font
.SetWeight(wx
.BOLD
)
1015 mem_dc
.SetFont(font
)
1017 panelHeight
= mem_dc
.GetCharHeight()
1018 panelHeight
+= 4 # Place a spacer of 2 pixels
1020 # Out signpost bitmap is 24 pixels
1021 if panelHeight
< 24:
1024 self
._panel
= wx
.Panel(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, panelHeight
))
1027 sz
.Add(self
._listBox
, 1, wx
.EXPAND
)
1031 # Connect events to the list box
1032 self
._listBox
.Bind(wx
.EVT_KEY_UP
, self
.OnKeyUp
)
1033 self
._listBox
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
1034 self
._listBox
.Bind(wx
.EVT_LISTBOX_DCLICK
, self
.OnItemSelected
)
1036 # Connect paint event to the panel
1037 self
._panel
.Bind(wx
.EVT_PAINT
, self
.OnPanelPaint
)
1038 self
._panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnPanelEraseBg
)
1040 self
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1041 self
._listBox
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1042 self
.PopulateListControl(parent
)
1044 self
.GetSizer().Fit(self
)
1045 self
.GetSizer().SetSizeHints(self
)
1046 self
.GetSizer().Layout()
1050 def OnKeyUp(self
, event
):
1051 """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}."""
1053 if event
.GetKeyCode() == wx
.WXK_CONTROL
:
1057 def OnNavigationKey(self
, event
):
1058 """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """
1060 selected
= self
._listBox
.GetSelection()
1061 bk
= self
.GetParent()
1062 maxItems
= bk
.GetPageCount()
1064 if event
.GetDirection():
1067 if selected
== maxItems
- 1:
1070 itemToSelect
= selected
+ 1
1076 itemToSelect
= maxItems
- 1
1078 itemToSelect
= selected
- 1
1080 self
._listBox
.SetSelection(itemToSelect
)
1083 def PopulateListControl(self
, book
):
1084 """Populates the L{TabNavigatorWindow} listbox with a list of tabs."""
1086 selection
= book
.GetSelection()
1087 count
= book
.GetPageCount()
1089 self
._listBox
.Append(book
.GetPageText(selection
))
1090 self
._indexMap
.append(selection
)
1092 prevSel
= book
.GetPreviousSelection()
1094 if prevSel
!= wx
.NOT_FOUND
:
1096 # Insert the previous selection as second entry
1097 self
._listBox
.Append(book
.GetPageText(prevSel
))
1098 self
._indexMap
.append(prevSel
)
1100 for c
in xrange(count
):
1102 # Skip selected page
1106 # Skip previous selected page as well
1110 self
._listBox
.Append(book
.GetPageText(c
))
1111 self
._indexMap
.append(c
)
1113 # Select the next entry after the current selection
1114 self
._listBox
.SetSelection(0)
1115 dummy
= wx
.NavigationKeyEvent()
1116 dummy
.SetDirection(True)
1117 self
.OnNavigationKey(dummy
)
1120 def OnItemSelected(self
, event
):
1121 """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """
1126 def CloseDialog(self
):
1127 """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}."""
1129 bk
= self
.GetParent()
1130 self
._selectedItem
= self
._listBox
.GetSelection()
1131 iter = self
._indexMap
[self
._selectedItem
]
1132 bk
.SetSelection(iter)
1133 self
.EndModal(wx
.ID_OK
)
1136 def OnPanelPaint(self
, event
):
1137 """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """
1139 dc
= wx
.PaintDC(self
._panel
)
1140 rect
= self
._panel
.GetClientRect()
1142 bmp
= wx
.EmptyBitmap(rect
.width
, rect
.height
)
1144 mem_dc
= wx
.MemoryDC()
1145 mem_dc
.SelectObject(bmp
)
1147 endColour
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
1148 startColour
= LightColour(endColour
, 50)
1149 PaintStraightGradientBox(mem_dc
, rect
, startColour
, endColour
)
1151 # Draw the caption title and place the bitmap
1152 # get the bitmap optimal position, and draw it
1153 bmpPt
, txtPt
= wx
.Point(), wx
.Point()
1154 bmpPt
.y
= (rect
.height
- self
._bmp
.GetHeight())/2
1156 mem_dc
.DrawBitmap(self
._bmp
, bmpPt
.x
, bmpPt
.y
, True)
1158 # get the text position, and draw it
1159 font
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1160 font
.SetWeight(wx
.BOLD
)
1161 mem_dc
.SetFont(font
)
1162 fontHeight
= mem_dc
.GetCharHeight()
1164 txtPt
.x
= bmpPt
.x
+ self
._bmp
.GetWidth() + 4
1165 txtPt
.y
= (rect
.height
- fontHeight
)/2
1166 mem_dc
.SetTextForeground(wx
.WHITE
)
1167 mem_dc
.DrawText("Opened tabs:", txtPt
.x
, txtPt
.y
)
1168 mem_dc
.SelectObject(wx
.NullBitmap
)
1170 dc
.DrawBitmap(bmp
, 0, 0)
1173 def OnPanelEraseBg(self
, event
):
1174 """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """
1179 # ---------------------------------------------------------------------------- #
1181 # ---------------------------------------------------------------------------- #
1185 Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy}
1186 and I{VC8}. This class implements the common methods of all 4 renderers.
1187 @undocumented: _GetBitmap*
1191 """Default class constructor. """
1193 self
._tabXBgBmp
= wx
.EmptyBitmap(16, 16)
1194 self
._xBgBmp
= wx
.EmptyBitmap(16, 14)
1195 self
._leftBgBmp
= wx
.EmptyBitmap(16, 14)
1196 self
._rightBgBmp
= wx
.EmptyBitmap(16, 14)
1199 def GetLeftButtonPos(self
, pageContainer
):
1200 """ Returns the left button position in the navigation area. """
1203 style
= pc
.GetParent().GetWindowStyleFlag()
1204 rect
= pc
.GetClientRect()
1205 clientWidth
= rect
.width
1207 if style
& FNB_NO_X_BUTTON
:
1208 return clientWidth
- 38
1210 return clientWidth
- 54
1214 def GetRightButtonPos(self
, pageContainer
):
1215 """ Returns the right button position in the navigation area. """
1218 style
= pc
.GetParent().GetWindowStyleFlag()
1219 rect
= pc
.GetClientRect()
1220 clientWidth
= rect
.width
1222 if style
& FNB_NO_X_BUTTON
:
1223 return clientWidth
- 22
1225 return clientWidth
- 38
1228 def GetDropArrowButtonPos(self
, pageContainer
):
1229 """ Returns the drop down button position in the navigation area. """
1231 return self
.GetRightButtonPos(pageContainer
)
1234 def GetXPos(self
, pageContainer
):
1235 """ Returns the 'X' button position in the navigation area. """
1238 style
= pc
.GetParent().GetWindowStyleFlag()
1239 rect
= pc
.GetClientRect()
1240 clientWidth
= rect
.width
1242 if style
& FNB_NO_X_BUTTON
:
1245 return clientWidth
- 22
1248 def GetButtonsAreaLength(self
, pageContainer
):
1249 """ Returns the navigation area width. """
1252 style
= pc
.GetParent().GetWindowStyleFlag()
1255 if style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1259 elif style
& FNB_NO_NAV_BUTTONS
and not style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1263 if not style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1267 if style
& FNB_DROPDOWN_TABS_LIST
and not style
& FNB_NO_X_BUTTON
:
1271 if style
& FNB_DROPDOWN_TABS_LIST
and style
& FNB_NO_X_BUTTON
:
1278 def DrawLeftArrow(self
, pageContainer
, dc
):
1279 """ Draw the left navigation arrow. """
1283 style
= pc
.GetParent().GetWindowStyleFlag()
1284 if style
& FNB_NO_NAV_BUTTONS
:
1287 # Make sure that there are pages in the container
1288 if not pc
._pagesInfoVec
:
1291 # Set the bitmap according to the button status
1292 if pc
._nLeftButtonStatus
== FNB_BTN_HOVER
:
1293 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_hilite_xpm
)
1294 elif pc
._nLeftButtonStatus
== FNB_BTN_PRESSED
:
1295 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_pressed_xpm
)
1297 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_xpm
)
1300 # Handle disabled arrow
1301 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_disabled_xpm
)
1303 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
1306 posx
= self
.GetLeftButtonPos(pc
)
1307 dc
.DrawBitmap(self
._leftBgBmp
, posx
, 6)
1309 # Draw the new bitmap
1310 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
1313 def DrawRightArrow(self
, pageContainer
, dc
):
1314 """ Draw the right navigation arrow. """
1318 style
= pc
.GetParent().GetWindowStyleFlag()
1319 if style
& FNB_NO_NAV_BUTTONS
:
1322 # Make sure that there are pages in the container
1323 if not pc
._pagesInfoVec
:
1326 # Set the bitmap according to the button status
1327 if pc
._nRightButtonStatus
== FNB_BTN_HOVER
:
1328 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_hilite_xpm
)
1329 elif pc
._nRightButtonStatus
== FNB_BTN_PRESSED
:
1330 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_pressed_xpm
)
1332 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_xpm
)
1334 # Check if the right most tab is visible, if it is
1335 # don't rotate right anymore
1336 if pc
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1):
1337 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_disabled_xpm
)
1339 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
1342 posx
= self
.GetRightButtonPos(pc
)
1343 dc
.DrawBitmap(self
._rightBgBmp
, posx
, 6)
1345 # Draw the new bitmap
1346 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
1349 def DrawDropDownArrow(self
, pageContainer
, dc
):
1350 """ Draws the drop-down arrow in the navigation area. """
1354 # Check if this style is enabled
1355 style
= pc
.GetParent().GetWindowStyleFlag()
1356 if not style
& FNB_DROPDOWN_TABS_LIST
:
1359 # Make sure that there are pages in the container
1360 if not pc
._pagesInfoVec
:
1363 if pc
._nArrowDownButtonStatus
== FNB_BTN_HOVER
:
1364 downBmp
= wx
.BitmapFromXPMData(down_arrow_hilite_xpm
)
1365 elif pc
._nArrowDownButtonStatus
== FNB_BTN_PRESSED
:
1366 downBmp
= wx
.BitmapFromXPMData(down_arrow_pressed_xpm
)
1368 downBmp
= wx
.BitmapFromXPMData(down_arrow_xpm
)
1370 downBmp
.SetMask(wx
.Mask(downBmp
, MASK_COLOR
))
1373 posx
= self
.GetDropArrowButtonPos(pc
)
1374 dc
.DrawBitmap(self
._xBgBmp
, posx
, 6)
1376 # Draw the new bitmap
1377 dc
.DrawBitmap(downBmp
, posx
, 6, True)
1380 def DrawX(self
, pageContainer
, dc
):
1381 """ Draw the 'X' navigation button in the navigation area. """
1385 # Check if this style is enabled
1386 style
= pc
.GetParent().GetWindowStyleFlag()
1387 if style
& FNB_NO_X_BUTTON
:
1390 # Make sure that there are pages in the container
1391 if not pc
._pagesInfoVec
:
1394 # Set the bitmap according to the button status
1395 if pc
._nXButtonStatus
== FNB_BTN_HOVER
:
1396 xbmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
1397 elif pc
._nXButtonStatus
== FNB_BTN_PRESSED
:
1398 xbmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
1400 xbmp
= wx
.BitmapFromXPMData(x_button_xpm
)
1402 xbmp
.SetMask(wx
.Mask(xbmp
, MASK_COLOR
))
1405 posx
= self
.GetXPos(pc
)
1406 dc
.DrawBitmap(self
._xBgBmp
, posx
, 6)
1408 # Draw the new bitmap
1409 dc
.DrawBitmap(xbmp
, posx
, 6, True)
1412 def DrawTabX(self
, pageContainer
, dc
, rect
, tabIdx
, btnStatus
):
1413 """ Draws the 'X' in the selected tab. """
1416 if not pc
.HasFlag(FNB_X_ON_TAB
):
1419 # We draw the 'x' on the active tab only
1420 if tabIdx
!= pc
.GetSelection() or tabIdx
< 0:
1423 # Set the bitmap according to the button status
1425 if btnStatus
== FNB_BTN_HOVER
:
1426 xBmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
1427 elif btnStatus
== FNB_BTN_PRESSED
:
1428 xBmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
1430 xBmp
= wx
.BitmapFromXPMData(x_button_xpm
)
1433 xBmp
.SetMask(wx
.Mask(xBmp
, MASK_COLOR
))
1436 dc
.DrawBitmap(self
._tabXBgBmp
, rect
.x
, rect
.y
)
1438 # Draw the new bitmap
1439 dc
.DrawBitmap(xBmp
, rect
.x
, rect
.y
, True)
1442 rr
= wx
.Rect(rect
.x
, rect
.y
, 14, 13)
1443 pc
._pagesInfoVec
[tabIdx
].SetXRect(rr
)
1446 def _GetBitmap(self
, dc
, rect
, bmp
):
1448 mem_dc
= wx
.MemoryDC()
1449 mem_dc
.SelectObject(bmp
)
1450 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1451 mem_dc
.SelectObject(wx
.NullBitmap
)
1455 def DrawTabsLine(self
, pageContainer
, dc
):
1456 """ Draws a line over the tabs. """
1460 clntRect
= pc
.GetClientRect()
1461 clientRect3
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
)
1463 if pc
.HasFlag(FNB_BOTTOM
):
1465 clientRect
= wx
.Rect(0, 2, clntRect
.width
, clntRect
.height
- 2)
1466 clientRect2
= wx
.Rect(0, 1, clntRect
.width
, clntRect
.height
- 1)
1470 clientRect
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 2)
1471 clientRect2
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 1)
1473 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1474 dc
.SetPen(wx
.Pen(pc
.GetSingleLineBorderColour()))
1475 dc
.DrawRectangleRect(clientRect2
)
1476 dc
.DrawRectangleRect(clientRect3
)
1478 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1479 dc
.DrawRectangleRect(clientRect
)
1481 if not pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
1483 dc
.SetPen(wx
.Pen((pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
._tabAreaColor
])[0]))
1484 dc
.DrawLine(0, 0, 0, clientRect
.height
+1)
1486 if pc
.HasFlag(FNB_BOTTOM
):
1488 dc
.DrawLine(0, clientRect
.height
+1, clientRect
.width
, clientRect
.height
+1)
1492 dc
.DrawLine(0, 0, clientRect
.width
, 0)
1494 dc
.DrawLine(clientRect
.width
- 1, 0, clientRect
.width
- 1, clientRect
.height
+1)
1497 def CalcTabWidth(self
, pageContainer
, tabIdx
, tabHeight
):
1498 """ Calculates the width of the input tab. """
1502 dc
.SelectObject(wx
.EmptyBitmap(10,10))
1504 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1505 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1507 if pc
.IsDefaultTabs():
1508 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1510 # Calculate the text length using the bold font, so when selecting a tab
1511 # its width will not change
1512 dc
.SetFont(boldFont
)
1513 width
, pom
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
1515 # Set a minimum size to a tab
1519 tabWidth
= 2*pc
._pParent
.GetPadding() + width
1521 # Style to add a small 'x' button on the top right
1523 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
1524 # The xpm image that contains the 'x' button is 9 pixels
1526 if pc
.HasFlag(FNB_VC8
):
1529 tabWidth
+= pc
._pParent
.GetPadding() + spacer
1531 if pc
.IsDefaultTabs():
1533 tabWidth
+= 2*shapePoints
1535 hasImage
= pc
._ImageList
!= None and pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
1537 # For VC71 style, we only add the icon size (16 pixels)
1540 if not pc
.IsDefaultTabs():
1541 tabWidth
+= 16 + pc
._pParent
.GetPadding()
1544 tabWidth
+= 16 + pc
._pParent
.GetPadding() + shapePoints
/2
1549 def CalcTabHeight(self
, pageContainer
):
1550 """ Calculates the height of the input tab. """
1554 dc
.SelectObject(wx
.EmptyBitmap(10,10))
1556 # For GTK it seems that we must do this steps in order
1557 # for the tabs will get the proper height on initialization
1558 # on MSW, preforming these steps yields wierd results
1559 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1560 boldFont
= normalFont
1561 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1562 dc
.SetFont(boldFont
)
1564 height
= dc
.GetCharHeight()
1566 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
1567 if "__WXGTK__" in wx
.PlatformInfo
:
1568 # On GTK the tabs are should be larger
1571 if pc
.HasFlag(FNB_VC71
):
1572 tabHeight
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 4] or [tabHeight
])[0]
1573 elif pc
.HasFlag(FNB_FANCY_TABS
):
1574 tabHeight
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 2] or [tabHeight
])[0]
1579 def DrawTabs(self
, pageContainer
, dc
):
1580 """ Actually draws the tabs in L{FlatNotebook}."""
1583 if "__WXMAC__" in wx
.PlatformInfo
:
1584 # Works well on MSW & GTK, however this lines should be skipped on MAC
1585 if not pc
._pagesInfoVec
or pc
._nFrom
>= len(pc
._pagesInfoVec
):
1589 # Get the text hight
1590 tabHeight
= self
.CalcTabHeight(pageContainer
)
1591 style
= pc
.GetParent().GetWindowStyleFlag()
1593 # Calculate the number of rows required for drawing the tabs
1594 rect
= pc
.GetClientRect()
1595 clientWidth
= rect
.width
1597 # Set the maximum client size
1598 pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
)
1599 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1601 if style
& FNB_VC71
:
1602 backBrush
= wx
.Brush(wx
.Colour(247, 243, 233))
1604 backBrush
= wx
.Brush(pc
._tabAreaColor
)
1606 noselBrush
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
))
1607 selBrush
= wx
.Brush(pc
._activeTabColor
)
1612 dc
.SetTextBackground((style
& FNB_VC71
and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0])
1613 dc
.SetTextForeground(pc
._activeTextColor
)
1614 dc
.SetBrush(backBrush
)
1616 # If border style is set, set the pen to be border pen
1617 if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
1618 dc
.SetPen(borderPen
)
1620 colr
= (pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0]
1621 dc
.SetPen(wx
.Pen(colr
))
1623 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
1625 # Take 3 bitmaps for the background for the buttons
1627 mem_dc
= wx
.MemoryDC()
1628 #---------------------------------------
1630 #---------------------------------------
1631 rect
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14)
1632 mem_dc
.SelectObject(self
._xBgBmp
)
1633 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1634 mem_dc
.SelectObject(wx
.NullBitmap
)
1636 #---------------------------------------
1638 #---------------------------------------
1639 rect
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14)
1640 mem_dc
.SelectObject(self
._rightBgBmp
)
1641 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1642 mem_dc
.SelectObject(wx
.NullBitmap
)
1644 #---------------------------------------
1646 #---------------------------------------
1647 rect
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14)
1648 mem_dc
.SelectObject(self
._leftBgBmp
)
1649 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1650 mem_dc
.SelectObject(wx
.NullBitmap
)
1652 # We always draw the bottom/upper line of the tabs
1653 # regradless the style
1654 dc
.SetPen(borderPen
)
1655 self
.DrawTabsLine(pc
, dc
)
1658 dc
.SetPen(borderPen
)
1660 if pc
.HasFlag(FNB_VC71
):
1662 greyLineYVal
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [size
.y
- 2])[0]
1663 whiteLineYVal
= (pc
.HasFlag(FNB_BOTTOM
) and [3] or [size
.y
- 3])[0]
1665 pen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1668 # Draw thik grey line between the windows area and
1670 for num
in xrange(3):
1671 dc
.DrawLine(0, greyLineYVal
+ num
, size
.x
, greyLineYVal
+ num
)
1673 wbPen
= (pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK_PEN
] or [wx
.WHITE_PEN
])[0]
1675 dc
.DrawLine(1, whiteLineYVal
, size
.x
- 1, whiteLineYVal
)
1678 dc
.SetPen(borderPen
)
1681 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1682 boldFont
= normalFont
1683 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1684 dc
.SetFont(boldFont
)
1686 posx
= pc
._pParent
.GetPadding()
1688 # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
1689 for i
in xrange(pc
._nFrom
):
1691 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
1692 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1696 #----------------------------------------------------------
1697 # Go over and draw the visible tabs
1698 #----------------------------------------------------------
1699 for i
in xrange(pc
._nFrom
, len(pc
._pagesInfoVec
)):
1701 dc
.SetPen(borderPen
)
1702 dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0])
1704 # Now set the font to the correct font
1705 dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0])
1707 # Add the padding to the tab width
1709 # +-----------------------------------------------------------+
1710 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
1711 # +-----------------------------------------------------------+
1712 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
1714 # Check if we can draw more
1715 if posx
+ tabWidth
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
1720 # By default we clean the tab region
1721 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1723 # Clean the 'x' buttn on the tab.
1724 # A 'Clean' rectangle, is a rectangle with width or height
1725 # with values lower than or equal to 0
1726 pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
1728 # Draw the tab (border, text, image & 'x' on tab)
1729 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
)
1731 # Restore the text forground
1732 dc
.SetTextForeground(pc
._activeTextColor
)
1734 # Update the tab position & size
1735 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0]
1737 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, posy
))
1738 pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
1741 # Update all tabs that can not fit into the screen as non-visible
1742 for i
in xrange(count
, len(pc
._pagesInfoVec
)):
1743 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
1744 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1746 # Draw the left/right/close buttons
1748 self
.DrawLeftArrow(pc
, dc
)
1749 self
.DrawRightArrow(pc
, dc
)
1751 self
.DrawDropDownArrow(pc
, dc
)
1754 # ---------------------------------------------------------------------------- #
1755 # Class FNBRendererMgr
1756 # A manager that handles all the renderers defined below and calls the
1757 # appropriate one when drawing is needed
1758 # ---------------------------------------------------------------------------- #
1760 class FNBRendererMgr
:
1762 This class represents a manager that handles all the 4 renderers defined
1763 and calls the appropriate one when drawing is needed.
1767 """ Default class constructor. """
1769 # register renderers
1771 self
._renderers
= {}
1772 self
._renderers
.update({-1: FNBRendererDefault()}
)
1773 self
._renderers
.update({FNB_VC71: FNBRendererVC71()}
)
1774 self
._renderers
.update({FNB_FANCY_TABS: FNBRendererFancy()}
)
1775 self
._renderers
.update({FNB_VC8: FNBRendererVC8()}
)
1778 def GetRenderer(self
, style
):
1779 """ Returns the current renderer based on the style selected. """
1781 # since we dont have a style for default tabs, we
1782 # test for all others - FIXME: add style for default tabs
1783 if not style
& FNB_VC71
and not style
& FNB_VC8
and not style
& FNB_FANCY_TABS
:
1784 return self
._renderers
[-1]
1786 if style
& FNB_VC71
:
1787 return self
._renderers
[FNB_VC71
]
1789 if style
& FNB_FANCY_TABS
:
1790 return self
._renderers
[FNB_FANCY_TABS
]
1793 return self
._renderers
[FNB_VC8
]
1795 # the default is to return the default renderer
1796 return self
._renderers
[-1]
1799 #------------------------------------------
1801 #------------------------------------------
1803 class FNBRendererDefault(FNBRenderer
):
1805 This class handles the drawing of tabs using the I{Standard} renderer.
1809 """ Default class constructor. """
1811 FNBRenderer
.__init
__(self
)
1814 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
1815 """ Draws a tab using the I{Standard} style. """
1818 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1821 tabPoints
= [wx
.Point() for ii
in xrange(7)]
1822 tabPoints
[0].x
= posx
1823 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
1825 tabPoints
[1].x
= int(posx
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1826 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
1828 tabPoints
[2].x
= tabPoints
[1].x
+2
1829 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
1831 tabPoints
[3].x
= int(posx
+tabWidth
-(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))-2
1832 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
1834 tabPoints
[4].x
= tabPoints
[3].x
+2
1835 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
1837 tabPoints
[5].x
= int(tabPoints
[4].x
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1838 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
1840 tabPoints
[6].x
= tabPoints
[0].x
1841 tabPoints
[6].y
= tabPoints
[0].y
1843 if tabIdx
== pc
.GetSelection():
1845 # Draw the tab as rounded rectangle
1846 dc
.DrawPolygon(tabPoints
)
1850 if tabIdx
!= pc
.GetSelection() - 1:
1852 # Draw a vertical line to the right of the text
1853 pt1x
= tabPoints
[5].x
1854 pt1y
= (pc
.HasFlag(FNB_BOTTOM
) and [4] or [tabHeight
- 6])[0]
1855 pt2x
= tabPoints
[5].x
1856 pt2y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 4] or [4])[0]
1857 dc
.DrawLine(pt1x
, pt1y
, pt2x
, pt2y
)
1859 if tabIdx
== pc
.GetSelection():
1861 savePen
= dc
.GetPen()
1862 whitePen
= wx
.Pen(wx
.WHITE
)
1863 whitePen
.SetWidth(1)
1866 secPt
= wx
.Point(tabPoints
[5].x
+ 1, tabPoints
[5].y
)
1867 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, secPt
.x
, secPt
.y
)
1872 # -----------------------------------
1873 # Text and image drawing
1874 # -----------------------------------
1876 # Text drawing offset from the left border of the
1879 # The width of the images are 16 pixels
1880 padding
= pc
.GetParent().GetPadding()
1881 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1882 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
1883 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
1886 textOffset
= 2*pc
._pParent
._nPadding
+ 16 + shapePoints
/2
1888 textOffset
= pc
._pParent
._nPadding
+ shapePoints
/2
1892 if tabIdx
!= pc
.GetSelection():
1894 # Set the text background to be like the vertical lines
1895 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
1899 imageXOffset
= textOffset
- 16 - padding
1900 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
1901 posx
+ imageXOffset
, imageYCoord
,
1902 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
1904 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
1906 # draw 'x' on tab (if enabled)
1907 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
1909 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
1910 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
1912 # take a bitmap from the position of the 'x' button (the x on tab button)
1913 # this bitmap will be used later to delete old buttons
1914 tabCloseButtonYCoord
= imageYCoord
1915 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
1916 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
1919 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
1922 #------------------------------------------------------------------
1924 #------------------------------------------------------------------
1926 class FNBRendererVC71(FNBRenderer
):
1928 This class handles the drawing of tabs using the I{VC71} renderer.
1932 """ Default class constructor. """
1934 FNBRenderer
.__init
__(self
)
1937 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
1938 """ Draws a tab using the I{VC71} style. """
1940 # Visual studio 7.1 style
1941 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1944 dc
.SetPen((tabIdx
== pc
.GetSelection() and [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [borderPen
])[0])
1945 dc
.SetBrush((tabIdx
== pc
.GetSelection() and [wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [wx
.Brush(wx
.Colour(247, 243, 233))])[0])
1947 if tabIdx
== pc
.GetSelection():
1949 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0]
1950 dc
.DrawRectangle(posx
, posy
, tabWidth
, tabHeight
- 1)
1952 # Draw a black line on the left side of the
1954 dc
.SetPen(wx
.BLACK_PEN
)
1956 blackLineY1
= VERTICAL_BORDER_PADDING
1957 blackLineY2
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
.GetSize().y
- 5] or [pc
.GetSize().y
- 3])[0]
1958 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
1960 # To give the tab more 3D look we do the following
1961 # Incase the tab is on top,
1962 # Draw a thik white line on topof the rectangle
1963 # Otherwise, draw a thin (1 pixel) black line at the bottom
1965 pen
= wx
.Pen((pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK
] or [wx
.WHITE
])[0])
1967 whiteLinePosY
= (pc
.HasFlag(FNB_BOTTOM
) and [blackLineY2
] or [VERTICAL_BORDER_PADDING
])[0]
1968 dc
.DrawLine(posx
, whiteLinePosY
, posx
+ tabWidth
+ 1, whiteLinePosY
)
1970 # Draw a white vertical line to the left of the tab
1971 dc
.SetPen(wx
.WHITE_PEN
)
1972 if not pc
.HasFlag(FNB_BOTTOM
):
1975 dc
.DrawLine(posx
, blackLineY1
, posx
, blackLineY2
)
1979 # We dont draw a rectangle for non selected tabs, but only
1980 # vertical line on the left
1982 blackLineY1
= (pc
.HasFlag(FNB_BOTTOM
) and [VERTICAL_BORDER_PADDING
+ 2] or [VERTICAL_BORDER_PADDING
+ 1])[0]
1983 blackLineY2
= pc
.GetSize().y
- 5
1984 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
1986 # -----------------------------------
1987 # Text and image drawing
1988 # -----------------------------------
1990 # Text drawing offset from the left border of the
1993 # The width of the images are 16 pixels
1994 padding
= pc
.GetParent().GetPadding()
1995 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
1996 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
1999 textOffset
= 2*pc
._pParent
._nPadding
+ 16
2001 textOffset
= pc
._pParent
._nPadding
2003 if tabIdx
!= pc
.GetSelection():
2005 # Set the text background to be like the vertical lines
2006 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2010 imageXOffset
= textOffset
- 16 - padding
2011 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2012 posx
+ imageXOffset
, imageYCoord
,
2013 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2015 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2017 # draw 'x' on tab (if enabled)
2018 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2020 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2021 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2023 # take a bitmap from the position of the 'x' button (the x on tab button)
2024 # this bitmap will be used later to delete old buttons
2025 tabCloseButtonYCoord
= imageYCoord
2026 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2027 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2030 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2033 #------------------------------------------------------------------
2035 #------------------------------------------------------------------
2037 class FNBRendererFancy(FNBRenderer
):
2039 This class handles the drawing of tabs using the I{Fancy} renderer.
2043 """ Default class constructor. """
2045 FNBRenderer
.__init
__(self
)
2048 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2049 """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
2051 # Fancy tabs - like with VC71 but with the following differences:
2052 # - The Selected tab is colored with gradient color
2053 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2056 pen
= (tabIdx
== pc
.GetSelection() and [wx
.Pen(pc
._pParent
.GetBorderColour())] or [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))])[0]
2058 if tabIdx
== pc
.GetSelection():
2060 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [VERTICAL_BORDER_PADDING
])[0]
2061 th
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 2] or [tabHeight
- 5])[0]
2063 rect
= wx
.Rect(posx
, posy
, tabWidth
, th
)
2065 col2
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourTo()] or [pc
._pParent
.GetGradientColourFrom()])[0]
2066 col1
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourFrom()] or [pc
._pParent
.GetGradientColourTo()])[0]
2068 PaintStraightGradientBox(dc
, rect
, col1
, col2
)
2069 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2071 dc
.DrawRectangleRect(rect
)
2073 # erase the bottom/top line of the rectangle
2074 dc
.SetPen(wx
.Pen(pc
._pParent
.GetGradientColourFrom()))
2075 if pc
.HasFlag(FNB_BOTTOM
):
2076 dc
.DrawLine(rect
.x
, 2, rect
.x
+ rect
.width
, 2)
2078 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
, rect
.y
+ rect
.height
- 1)
2082 # We dont draw a rectangle for non selected tabs, but only
2083 # vertical line on the left
2084 dc
.SetPen(borderPen
)
2085 dc
.DrawLine(posx
+ tabWidth
, VERTICAL_BORDER_PADDING
+ 3, posx
+ tabWidth
, tabHeight
- 4)
2088 # -----------------------------------
2089 # Text and image drawing
2090 # -----------------------------------
2092 # Text drawing offset from the left border of the
2095 # The width of the images are 16 pixels
2096 padding
= pc
.GetParent().GetPadding()
2097 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2098 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2101 textOffset
= 2*pc
._pParent
._nPadding
+ 16
2103 textOffset
= pc
._pParent
._nPadding
2107 if tabIdx
!= pc
.GetSelection():
2109 # Set the text background to be like the vertical lines
2110 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2114 imageXOffset
= textOffset
- 16 - padding
2115 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2116 posx
+ imageXOffset
, imageYCoord
,
2117 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2119 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2121 # draw 'x' on tab (if enabled)
2122 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2124 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2125 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2127 # take a bitmap from the position of the 'x' button (the x on tab button)
2128 # this bitmap will be used later to delete old buttons
2129 tabCloseButtonYCoord
= imageYCoord
2130 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2131 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2134 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2137 #------------------------------------------------------------------
2138 # Visual studio 2005 (VS8)
2139 #------------------------------------------------------------------
2140 class FNBRendererVC8(FNBRenderer
):
2142 This class handles the drawing of tabs using the I{VC8} renderer.
2146 """ Default class constructor. """
2148 FNBRenderer
.__init
__(self
)
2153 def DrawTabs(self
, pageContainer
, dc
):
2154 """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
2158 if "__WXMAC__" in wx
.PlatformInfo
:
2159 # Works well on MSW & GTK, however this lines should be skipped on MAC
2160 if not pc
._pagesInfoVec
or pc
._nFrom
>= len(pc
._pagesInfoVec
):
2164 # Get the text hight
2165 tabHeight
= self
.CalcTabHeight(pageContainer
)
2167 # Set the font for measuring the tab height
2168 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2169 boldFont
= normalFont
2170 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2172 # Calculate the number of rows required for drawing the tabs
2173 rect
= pc
.GetClientRect()
2175 # Set the maximum client size
2176 pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
)
2177 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2180 backBrush
= wx
.Brush(pc
._tabAreaColor
)
2181 noselBrush
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
))
2182 selBrush
= wx
.Brush(pc
._activeTabColor
)
2186 dc
.SetTextBackground(pc
.GetBackgroundColour())
2187 dc
.SetTextForeground(pc
._activeTextColor
)
2189 # If border style is set, set the pen to be border pen
2190 if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
2191 dc
.SetPen(borderPen
)
2193 dc
.SetPen(wx
.TRANSPARENT_PEN
)
2195 lightFactor
= (pc
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0]
2197 # For VC8 style, we color the tab area in gradient coloring
2198 lightcolour
= LightColour(pc
._tabAreaColor
, lightFactor
)
2199 PaintStraightGradientBox(dc
, pc
.GetClientRect(), pc
._tabAreaColor
, lightcolour
)
2201 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2202 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
2204 # Take 3 bitmaps for the background for the buttons
2206 mem_dc
= wx
.MemoryDC()
2207 #---------------------------------------
2209 #---------------------------------------
2210 rect
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14)
2211 mem_dc
.SelectObject(self
._xBgBmp
)
2212 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2213 mem_dc
.SelectObject(wx
.NullBitmap
)
2215 #---------------------------------------
2217 #---------------------------------------
2218 rect
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14)
2219 mem_dc
.SelectObject(self
._rightBgBmp
)
2220 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2221 mem_dc
.SelectObject(wx
.NullBitmap
)
2223 #---------------------------------------
2225 #---------------------------------------
2226 rect
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14)
2227 mem_dc
.SelectObject(self
._leftBgBmp
)
2228 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2229 mem_dc
.SelectObject(wx
.NullBitmap
)
2231 # We always draw the bottom/upper line of the tabs
2232 # regradless the style
2233 dc
.SetPen(borderPen
)
2234 self
.DrawTabsLine(pc
, dc
)
2237 dc
.SetPen(borderPen
)
2240 dc
.SetFont(boldFont
)
2242 # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
2243 for i
in xrange(pc
._nFrom
):
2245 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
2246 pc
._pagesInfoVec
[i
].GetRegion().Clear()
2248 # Draw the visible tabs, in VC8 style, we draw them from right to left
2249 vTabsInfo
= self
.NumberTabsCanFit(pc
)
2255 for cur
in xrange(len(vTabsInfo
)-1, -1, -1):
2257 # 'i' points to the index of the currently drawn tab
2258 # in pc.GetPageInfoVector() vector
2260 dc
.SetPen(borderPen
)
2261 dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0])
2263 # Now set the font to the correct font
2264 dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0])
2266 # Add the padding to the tab width
2268 # +-----------------------------------------------------------+
2269 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
2270 # +-----------------------------------------------------------+
2272 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
2273 posx
= vTabsInfo
[cur
].x
2275 # By default we clean the tab region
2276 # incase we use the VC8 style which requires
2277 # the region, it will be filled by the function
2279 pc
._pagesInfoVec
[i
].GetRegion().Clear()
2281 # Clean the 'x' buttn on the tab
2282 # 'Clean' rectanlge is a rectangle with width or height
2283 # with values lower than or equal to 0
2284 pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
2287 # Incase we are drawing the active tab
2288 # we need to redraw so it will appear on top
2291 # when using the vc8 style, we keep the position of the active tab so we will draw it again later
2292 if i
== pc
.GetSelection() and pc
.HasFlag(FNB_VC8
):
2294 activeTabPosx
= posx
2295 activeTabWidth
= tabWidth
2296 activeTabHeight
= tabHeight
2300 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
)
2302 # Restore the text forground
2303 dc
.SetTextForeground(pc
._activeTextColor
)
2305 # Update the tab position & size
2306 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, VERTICAL_BORDER_PADDING
))
2307 pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
2309 # Incase we are in VC8 style, redraw the active tab (incase it is visible)
2310 if pc
.GetSelection() >= pc
._nFrom
and pc
.GetSelection() < pc
._nFrom
+ len(vTabsInfo
):
2312 self
.DrawTab(pc
, dc
, activeTabPosx
, pc
.GetSelection(), activeTabWidth
, activeTabHeight
, pc
._nTabXButtonStatus
)
2314 # Update all tabs that can not fit into the screen as non-visible
2315 for xx
in xrange(pc
._nFrom
+ len(vTabsInfo
), len(pc
._pagesInfoVec
)):
2317 pc
._pagesInfoVec
[xx
].SetPosition(wx
.Point(-1, -1))
2318 pc
._pagesInfoVec
[xx
].GetRegion().Clear()
2320 # Draw the left/right/close buttons
2322 self
.DrawLeftArrow(pc
, dc
)
2323 self
.DrawRightArrow(pc
, dc
)
2325 self
.DrawDropDownArrow(pc
, dc
)
2328 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2329 """ Draws a tab using VC8 style. """
2332 borderPen
= wx
.Pen(pc
._pParent
.GetBorderColour())
2333 tabPoints
= [wx
.Point() for ii
in xrange(8)]
2335 # If we draw the first tab or the active tab,
2336 # we draw a full tab, else we draw a truncated tab
2347 tabPoints
[0].x
= (pc
.HasFlag(FNB_BOTTOM
) and [posx
] or [posx
+self
._factor
])[0]
2348 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 3])[0]
2350 tabPoints
[1].x
= tabPoints
[0].x
+ tabHeight
- VERTICAL_BORDER_PADDING
- 3 - self
._factor
2351 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2353 tabPoints
[2].x
= tabPoints
[1].x
+ 4
2354 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2356 tabPoints
[3].x
= tabPoints
[2].x
+ tabWidth
- 2
2357 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2359 tabPoints
[4].x
= tabPoints
[3].x
+ 1
2360 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabPoints
[3].y
- 1] or [tabPoints
[3].y
+ 1])[0]
2362 tabPoints
[5].x
= tabPoints
[4].x
+ 1
2363 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [(tabPoints
[4].y
- 1)] or [tabPoints
[4].y
+ 1])[0]
2365 tabPoints
[6].x
= tabPoints
[2].x
+ tabWidth
2366 tabPoints
[6].y
= tabPoints
[0].y
2368 tabPoints
[7].x
= tabPoints
[0].x
2369 tabPoints
[7].y
= tabPoints
[0].y
2371 pc
._pagesInfoVec
[tabIdx
].SetRegion(tabPoints
)
2375 dc
.SetBrush(wx
.Brush((tabIdx
== pc
.GetSelection() and [pc
._activeTabColor
] or [pc
._colorTo
])[0]))
2376 dc
.SetPen(wx
.Pen((tabIdx
== pc
.GetSelection() and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0]))
2377 dc
.DrawPolygon(tabPoints
)
2381 rect
= pc
.GetClientRect()
2383 if tabIdx
!= pc
.GetSelection() and not pc
.HasFlag(FNB_BOTTOM
):
2386 dc
.SetPen(wx
.Pen(pc
._pParent
.GetBorderColour()))
2388 curPen
= dc
.GetPen()
2391 dc
.DrawLine(posx
, lineY
, posx
+rect
.width
, lineY
)
2393 # Incase we are drawing the selected tab, we draw the border of it as well
2394 # but without the bottom (upper line incase of wxBOTTOM)
2395 if tabIdx
== pc
.GetSelection():
2397 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2398 dc
.SetPen(borderPen
)
2399 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2400 dc
.DrawPolygon(tabPoints
)
2402 # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
2403 dc
.SetPen(wx
.WHITE_PEN
)
2404 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, tabPoints
[6].x
, tabPoints
[6].y
)
2406 self
.FillVC8GradientColour(pc
, dc
, tabPoints
, tabIdx
== pc
.GetSelection(), tabIdx
)
2408 # Draw a thin line to the right of the non-selected tab
2409 if tabIdx
!= pc
.GetSelection():
2411 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)))
2412 dc
.DrawLine(tabPoints
[4].x
-1, tabPoints
[4].y
, tabPoints
[5].x
-1, tabPoints
[5].y
)
2413 dc
.DrawLine(tabPoints
[5].x
-1, tabPoints
[5].y
, tabPoints
[6].x
-1, tabPoints
[6].y
)
2415 # Text drawing offset from the left border of the
2418 # The width of the images are 16 pixels
2419 vc8ShapeLen
= tabHeight
- VERTICAL_BORDER_PADDING
- 2
2420 if pc
.TabHasImage(tabIdx
):
2421 textOffset
= 2*pc
._pParent
.GetPadding() + 16 + vc8ShapeLen
2423 textOffset
= pc
._pParent
.GetPadding() + vc8ShapeLen
2425 # Draw the image for the tab if any
2426 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2428 if pc
.TabHasImage(tabIdx
):
2430 imageXOffset
= textOffset
- 16 - pc
._pParent
.GetPadding()
2431 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2432 posx
+ imageXOffset
, imageYCoord
,
2433 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2435 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2437 # if selected tab, draw text in bold
2438 if tabIdx
== pc
.GetSelection():
2439 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2441 dc
.SetFont(boldFont
)
2442 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2444 # draw 'x' on tab (if enabled)
2445 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2447 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2448 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2450 # take a bitmap from the position of the 'x' button (the x on tab button)
2451 # this bitmap will be used later to delete old buttons
2452 tabCloseButtonYCoord
= imageYCoord
2453 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2454 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2456 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2459 def FillVC8GradientColour(self
, pageContainer
, dc
, tabPoints
, bSelectedTab
, tabIdx
):
2460 """ Fills a tab with a gradient shading. """
2462 # calculate gradient coefficients
2467 pc
._colorTo
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 0)
2468 pc
._colorFrom
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 60)
2470 col2
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourTo()] or [pc
._pParent
.GetGradientColourFrom()])[0]
2471 col1
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourFrom()] or [pc
._pParent
.GetGradientColourTo()])[0]
2473 # If colorful tabs style is set, override the tab color
2474 if pc
.HasFlag(FNB_COLORFUL_TABS
):
2476 if not pc
._pagesInfoVec
[tabIdx
].GetColour():
2478 # First time, generate color, and keep it in the vector
2479 tabColor
= RandomColour()
2480 pc
._pagesInfoVec
[tabIdx
].SetColour(tabColor
)
2482 if pc
.HasFlag(FNB_BOTTOM
):
2484 col2
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50)
2485 col1
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80)
2489 col1
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50)
2490 col2
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80)
2492 size
= abs(tabPoints
[2].y
- tabPoints
[0].y
) - 1
2494 rf
, gf
, bf
= 0, 0, 0
2495 rstep
= float(col2
.Red() - col1
.Red())/float(size
)
2496 gstep
= float(col2
.Green() - col1
.Green())/float(size
)
2497 bstep
= float(col2
.Blue() - col1
.Blue())/float(size
)
2501 # If we are drawing the selected tab, we need also to draw a line
2502 # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
2503 # by drawing the rectangle with transparent brush
2504 # the line under the selected tab will be deleted by the drwaing loop
2506 self
.DrawTabsLine(pc
, dc
)
2510 if pc
.HasFlag(FNB_BOTTOM
):
2512 if y
> tabPoints
[0].y
+ size
:
2517 if y
< tabPoints
[0].y
- size
:
2520 currCol
= wx
.Colour(col1
.Red() + rf
, col1
.Green() + gf
, col1
.Blue() + bf
)
2522 dc
.SetPen((bSelectedTab
and [wx
.Pen(pc
._activeTabColor
)] or [wx
.Pen(currCol
)])[0])
2523 startX
= self
.GetStartX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())
2524 endX
= self
.GetEndX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())
2525 dc
.DrawLine(startX
, y
, endX
, y
)
2527 # Draw the border using the 'edge' point
2528 dc
.SetPen(wx
.Pen((bSelectedTab
and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0]))
2530 dc
.DrawPoint(startX
, y
)
2531 dc
.DrawPoint(endX
, y
)
2533 # Progress the color
2538 if pc
.HasFlag(FNB_BOTTOM
):
2544 def GetStartX(self
, tabPoints
, y
, style
):
2545 """ Returns the x start position of a tab. """
2547 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
2549 # We check the 3 points to the left
2551 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
2558 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
+1].y
:
2561 x2
= tabPoints
[i
+1].x
2563 y2
= tabPoints
[i
+1].y
2571 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
+1].y
:
2574 x2
= tabPoints
[i
+1].x
2576 y2
= tabPoints
[i
+1].y
2581 return tabPoints
[2].x
2583 # According to the equation y = ax + b => x = (y-b)/a
2584 # We know the first 2 points
2589 a
= (y2
- y1
)/(x2
- x1
)
2591 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
2601 def GetEndX(self
, tabPoints
, y
, style
):
2602 """ Returns the x end position of a tab. """
2604 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
2606 # We check the 3 points to the left
2607 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
2612 for i
in xrange(7, 3, -1):
2614 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
-1].y
:
2617 x2
= tabPoints
[i
-1].x
2619 y2
= tabPoints
[i
-1].y
2625 for i
in xrange(7, 3, -1):
2627 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
-1].y
:
2630 x2
= tabPoints
[i
-1].x
2632 y2
= tabPoints
[i
-1].y
2637 return tabPoints
[3].x
2639 # According to the equation y = ax + b => x = (y-b)/a
2640 # We know the first 2 points
2646 a
= (y2
- y1
)/(x2
- x1
)
2647 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
2657 def NumberTabsCanFit(self
, pageContainer
, fr
=-1):
2658 """ Returns the number of tabs that can fit in the visible area. """
2662 rect
= pc
.GetClientRect()
2663 clientWidth
= rect
.width
2667 tabHeight
= self
.CalcTabHeight(pageContainer
)
2669 # The drawing starts from posx
2670 posx
= pc
._pParent
.GetPadding()
2675 for i
in xrange(fr
, len(pc
._pagesInfoVec
)):
2677 vc8glitch
= tabHeight
+ FNB_HEIGHT_SPACER
2678 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
2680 if posx
+ tabWidth
+ vc8glitch
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
2683 # Add a result to the returned vector
2684 tabRect
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
)
2685 vTabInfo
.append(tabRect
)
2688 posx
+= tabWidth
+ FNB_HEIGHT_SPACER
2693 # ---------------------------------------------------------------------------- #
2694 # Class FlatNotebook
2695 # ---------------------------------------------------------------------------- #
2697 class FlatNotebook(wx
.Panel
):
2699 Display one or more windows in a notebook.
2702 - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active
2703 page in the notebook is changing
2704 - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active
2705 page in the notebook has changed
2706 - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the
2708 - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the
2709 notebook has been closed
2710 - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
2711 clicks a tab in the notebook with the right mouse
2715 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
2716 style
=0, name
="FlatNotebook"):
2718 Default class constructor.
2720 All the parameters are as in wxPython class construction, except the
2721 'style': this can be assigned to whatever combination of FNB_* styles.
2725 self
._bForceSelection
= False
2728 style |
= wx
.TAB_TRAVERSAL
2731 self
._popupWin
= None
2733 wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style
)
2735 self
._pages
= PageContainer(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.DefaultSize
, style
)
2737 self
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
2743 """ Initializes all the class attributes. """
2745 self
._pages
._colorBorder
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
2747 self
._mainSizer
= wx
.BoxSizer(wx
.VERTICAL
)
2748 self
.SetSizer(self
._mainSizer
)
2750 # The child panels will inherit this bg color, so leave it at the default value
2751 #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
2753 # Set default page height
2754 dc
= wx
.ClientDC(self
)
2755 font
= self
.GetFont()
2756 font
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2758 height
= dc
.GetCharHeight()
2760 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
2762 if "__WXGTK__" in wx
.PlatformInfo
:
2765 self
._pages
.SetSizeHints(-1, tabHeight
)
2766 # Add the tab container to the sizer
2767 self
._mainSizer
.Insert(0, self
._pages
, 0, wx
.EXPAND
)
2768 self
._mainSizer
.Layout()
2770 self
._pages
._nFrom
= self
._nFrom
2771 self
._pDropTarget
= FNBDropTarget(self
)
2772 self
.SetDropTarget(self
._pDropTarget
)
2775 def SetActiveTabTextColour(self
, textColour
):
2776 """ Sets the text colour for the active tab. """
2778 self
._pages
._activeTextColor
= textColour
2781 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
2782 """ Handles the drop action from a DND operation. """
2784 return self
._pages
.OnDropTarget(x
, y
, nTabPage
, wnd_oldContainer
)
2787 def GetPreviousSelection(self
):
2788 """ Returns the previous selection. """
2790 return self
._pages
._iPreviousActivePage
2793 def AddPage(self
, page
, text
, select
=True, imageId
=-1):
2795 Add a page to the L{FlatNotebook}.
2797 @param page: Specifies the new page.
2798 @param text: Specifies the text for the new page.
2799 @param select: Specifies whether the page should be selected.
2800 @param imageId: Specifies the optional image index for the new page.
2803 True if successful, False otherwise.
2810 # reparent the window to us
2814 bSelected
= select
or len(self
._windows
) == 0
2820 # Check for selection and send events
2821 oldSelection
= self
._pages
._iActivePage
2822 tabIdx
= len(self
._windows
)
2824 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId())
2825 event
.SetSelection(tabIdx
)
2826 event
.SetOldSelection(oldSelection
)
2827 event
.SetEventObject(self
)
2829 if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
2832 curSel
= self
._pages
.GetSelection()
2834 if not self
._pages
.IsShown():
2837 self
._pages
.AddPage(text
, bSelected
, imageId
)
2838 self
._windows
.append(page
)
2842 # Check if a new selection was made
2847 # Remove the window from the main sizer
2848 self
._mainSizer
.Detach(self
._windows
[curSel
])
2849 self
._windows
[curSel
].Hide()
2851 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
2853 self
._mainSizer
.Insert(0, page
, 1, wx
.EXPAND
)
2857 # We leave a space of 1 pixel around the window
2858 self
._mainSizer
.Add(page
, 1, wx
.EXPAND
)
2860 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
2861 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
2862 event
.SetOldSelection(oldSelection
)
2863 self
.GetEventHandler().ProcessEvent(event
)
2870 self
._mainSizer
.Layout()
2877 def SetImageList(self
, imglist
):
2879 Sets the image list for the page control. It does not take ownership
2880 of the image list, you must delete it yourself.
2883 self
._pages
.SetImageList(imglist
)
2886 def GetImageList(self
):
2887 """ Returns the associated image list. """
2889 return self
._pages
.GetImageList()
2892 def InsertPage(self
, indx
, page
, text
, select
=True, imageId
=-1):
2894 Inserts a new page at the specified position.
2896 @param indx: Specifies the position of the new page.
2897 @param page: Specifies the new page.
2898 @param text: Specifies the text for the new page.
2899 @param select: Specifies whether the page should be selected.
2900 @param imageId: Specifies the optional image index for the new page.
2903 True if successful, False otherwise.
2910 # reparent the window to us
2913 if not self
._windows
:
2915 self
.AddPage(page
, text
, select
, imageId
)
2919 bSelected
= select
or not self
._windows
2920 curSel
= self
._pages
.GetSelection()
2922 indx
= max(0, min(indx
, len(self
._windows
)))
2924 if indx
<= len(self
._windows
):
2926 self
._windows
.insert(indx
, page
)
2930 self
._windows
.append(page
)
2936 # Check for selection and send events
2937 oldSelection
= self
._pages
._iActivePage
2939 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId())
2940 event
.SetSelection(indx
)
2941 event
.SetOldSelection(oldSelection
)
2942 event
.SetEventObject(self
)
2944 if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
2947 self
._pages
.InsertPage(indx
, text
, bSelected
, imageId
)
2954 # Check if a new selection was made
2959 # Remove the window from the main sizer
2960 self
._mainSizer
.Detach(self
._windows
[curSel
])
2961 self
._windows
[curSel
].Hide()
2963 self
._pages
.SetSelection(indx
)
2965 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
2966 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
2967 event
.SetOldSelection(oldSelection
)
2968 self
.GetEventHandler().ProcessEvent(event
)
2976 self
._mainSizer
.Layout()
2982 def SetSelection(self
, page
):
2984 Sets the selection for the given page.
2985 The call to this function generates the page changing events
2988 if page
>= len(self
._windows
) or not self
._windows
:
2991 # Support for disabed tabs
2992 if not self
._pages
.GetEnabled(page
) and len(self
._windows
) > 1 and not self
._bForceSelection
:
2995 curSel
= self
._pages
.GetSelection()
2997 # program allows the page change
3001 # Remove the window from the main sizer
3002 self
._mainSizer
.Detach(self
._windows
[curSel
])
3003 self
._windows
[curSel
].Hide()
3005 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
3007 self
._mainSizer
.Insert(0, self
._windows
[page
], 1, wx
.EXPAND
)
3011 # We leave a space of 1 pixel around the window
3012 self
._mainSizer
.Add(self
._windows
[page
], 1, wx
.EXPAND
)
3014 self
._windows
[page
].Show()
3017 self
._mainSizer
.Layout()
3019 if page
!= self
._pages
._iActivePage
:
3020 # there is a real page changing
3021 self
._pages
._iPreviousActivePage
= self
._pages
._iActivePage
3023 self
._pages
._iActivePage
= page
3024 self
._pages
.DoSetSelection(page
)
3027 def DeletePage(self
, page
):
3029 Deletes the specified page, and the associated window.
3030 The call to this function generates the page changing events.
3033 if page
>= len(self
._windows
) or page
< 0:
3036 # Fire a closing event
3037 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
3038 event
.SetSelection(page
)
3039 event
.SetEventObject(self
)
3040 self
.GetEventHandler().ProcessEvent(event
)
3042 # The event handler allows it?
3043 if not event
.IsAllowed():
3048 # Delete the requested page
3049 pageRemoved
= self
._windows
[page
]
3051 # If the page is the current window, remove it from the sizer
3053 if page
== self
._pages
.GetSelection():
3054 self
._mainSizer
.Detach(pageRemoved
)
3056 # Remove it from the array as well
3057 self
._windows
.pop(page
)
3059 # Now we can destroy it in wxWidgets use Destroy instead of delete
3060 pageRemoved
.Destroy()
3064 self
._pages
.DoDeletePage(page
)
3067 # Fire a closed event
3068 closedEvent
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, self
.GetId())
3069 closedEvent
.SetSelection(page
)
3070 closedEvent
.SetEventObject(self
)
3071 self
.GetEventHandler().ProcessEvent(closedEvent
)
3074 def DeleteAllPages(self
):
3075 """ Deletes all the pages. """
3077 if not self
._windows
:
3082 for page
in self
._windows
:
3088 # Clear the container of the tabs as well
3089 self
._pages
.DeleteAllPages()
3093 def GetCurrentPage(self
):
3094 """ Returns the currently selected notebook page or None. """
3096 sel
= self
._pages
.GetSelection()
3100 return self
._windows
[sel
]
3103 def GetPage(self
, page
):
3104 """ Returns the window at the given page position, or None. """
3106 if page
>= len(self
._windows
):
3109 return self
._windows
[page
]
3112 def GetPageIndex(self
, win
):
3113 """ Returns the index at which the window is found. """
3116 return self
._windows
.index(win
)
3121 def GetSelection(self
):
3122 """ Returns the currently selected page, or -1 if none was selected. """
3124 return self
._pages
.GetSelection()
3127 def AdvanceSelection(self
, bForward
=True):
3129 Cycles through the tabs.
3130 The call to this function generates the page changing events.
3133 self
._pages
.AdvanceSelection(bForward
)
3136 def GetPageCount(self
):
3137 """ Returns the number of pages in the L{FlatNotebook} control. """
3138 return self
._pages
.GetPageCount()
3141 def OnNavigationKey(self
, event
):
3142 """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
3144 if event
.IsWindowChange():
3146 if self
.HasFlag(FNB_SMART_TABS
):
3147 if not self
._popupWin
:
3148 self
._popupWin
= TabNavigatorWindow(self
)
3149 self
._popupWin
.SetReturnCode(wx
.ID_OK
)
3150 self
._popupWin
.ShowModal()
3151 self
._popupWin
.Destroy()
3152 self
._popupWin
= None
3154 # a dialog is already opened
3155 self
._popupWin
.OnNavigationKey(event
)
3159 self
.AdvanceSelection(event
.GetDirection())
3161 # pass to the parent
3162 if self
.GetParent():
3163 event
.SetCurrentFocus(self
)
3164 self
.GetParent().ProcessEvent(event
)
3167 def GetPageShapeAngle(self
, page_index
):
3168 """ Returns the angle associated to a tab. """
3170 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
3173 result
= self
._pages
._pagesInfoVec
[page_index
].GetTabAngle()
3177 def SetPageShapeAngle(self
, page_index
, angle
):
3178 """ Sets the angle associated to a tab. """
3180 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
3186 self
._pages
._pagesInfoVec
[page_index
].SetTabAngle(angle
)
3189 def SetAllPagesShapeAngle(self
, angle
):
3190 """ Sets the angle associated to all the tab. """
3195 for ii
in xrange(len(self
._pages
._pagesInfoVec
)):
3196 self
._pages
._pagesInfoVec
[ii
].SetTabAngle(angle
)
3201 def GetPageBestSize(self
):
3202 """ Return the page best size. """
3204 return self
._pages
.GetClientSize()
3207 def SetPageText(self
, page
, text
):
3208 """ Sets the text for the given page. """
3210 bVal
= self
._pages
.SetPageText(page
, text
)
3211 self
._pages
.Refresh()
3216 def SetPadding(self
, padding
):
3218 Sets the amount of space around each page's icon and label, in pixels.
3219 NB: only the horizontal padding is considered.
3222 self
._nPadding
= padding
.GetWidth()
3225 def GetTabArea(self
):
3226 """ Returns the associated page. """
3231 def GetPadding(self
):
3232 """ Returns the amount of space around each page's icon and label, in pixels. """
3234 return self
._nPadding
3237 def SetWindowStyleFlag(self
, style
):
3238 """ Sets the L{FlatNotebook} window style flags. """
3240 wx
.Panel
.SetWindowStyleFlag(self
, style
)
3244 # For changing the tab position (i.e. placing them top/bottom)
3245 # refreshing the tab container is not enough
3246 self
.SetSelection(self
._pages
._iActivePage
)
3249 def RemovePage(self
, page
):
3250 """ Deletes the specified page, without deleting the associated window. """
3252 if page
>= len(self
._windows
):
3255 # Fire a closing event
3256 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
3257 event
.SetSelection(page
)
3258 event
.SetEventObject(self
)
3259 self
.GetEventHandler().ProcessEvent(event
)
3261 # The event handler allows it?
3262 if not event
.IsAllowed():
3267 # Remove the requested page
3268 pageRemoved
= self
._windows
[page
]
3270 # If the page is the current window, remove it from the sizer
3272 if page
== self
._pages
.GetSelection():
3273 self
._mainSizer
.Detach(pageRemoved
)
3275 # Remove it from the array as well
3276 self
._windows
.pop(page
)
3279 self
._pages
.DoDeletePage(page
)
3284 def SetRightClickMenu(self
, menu
):
3285 """ Sets the popup menu associated to a right click on a tab. """
3287 self
._pages
._pRightClickMenu
= menu
3290 def GetPageText(self
, page
):
3291 """ Returns the tab caption. """
3293 return self
._pages
.GetPageText(page
)
3296 def SetGradientColours(self
, fr
, to
, border
):
3297 """ Sets the gradient colours for the tab. """
3299 self
._pages
._colorFrom
= fr
3300 self
._pages
._colorTo
= to
3301 self
._pages
._colorBorder
= border
3304 def SetGradientColourFrom(self
, fr
):
3305 """ Sets the starting colour for the gradient. """
3307 self
._pages
._colorFrom
= fr
3310 def SetGradientColourTo(self
, to
):
3311 """ Sets the ending colour for the gradient. """
3313 self
._pages
._colorTo
= to
3316 def SetGradientColourBorder(self
, border
):
3317 """ Sets the tab border colour. """
3319 self
._pages
._colorBorder
= border
3322 def GetGradientColourFrom(self
):
3323 """ Gets first gradient colour. """
3325 return self
._pages
._colorFrom
3328 def GetGradientColourTo(self
):
3329 """ Gets second gradient colour. """
3331 return self
._pages
._colorTo
3334 def GetGradientColourBorder(self
):
3335 """ Gets the tab border colour. """
3337 return self
._pages
._colorBorder
3340 def GetBorderColour(self
):
3341 """ Returns the border colour. """
3343 return self
._pages
._colorBorder
3346 def GetActiveTabTextColour(self
):
3347 """ Get the active tab text colour. """
3349 return self
._pages
._activeTextColor
3352 def SetPageImage(self
, page
, imgindex
):
3354 Sets the image index for the given page. Image is an index into the
3355 image list which was set with SetImageList.
3358 self
._pages
.SetPageImage(page
, imgindex
)
3361 def GetPageImage(self
, page
):
3363 Returns the image index for the given page. Image is an index into the
3364 image list which was set with SetImageList.
3367 return self
._pages
.GetPageImage(page
)
3370 def GetEnabled(self
, page
):
3371 """ Returns whether a tab is enabled or not. """
3373 return self
._pages
.GetEnabled(page
)
3376 def Enable(self
, page
, enabled
=True):
3377 """ Enables or disables a tab. """
3379 if page
>= len(self
._windows
):
3382 self
._windows
[page
].Enable(enabled
)
3383 self
._pages
.Enable(page
, enabled
)
3386 def GetNonActiveTabTextColour(self
):
3387 """ Returns the non active tabs text colour. """
3389 return self
._pages
._nonActiveTextColor
3392 def SetNonActiveTabTextColour(self
, color
):
3393 """ Sets the non active tabs text colour. """
3395 self
._pages
._nonActiveTextColor
= color
3398 def SetTabAreaColour(self
, color
):
3399 """ Sets the area behind the tabs colour. """
3401 self
._pages
._tabAreaColor
= color
3404 def GetTabAreaColour(self
):
3405 """ Returns the area behind the tabs colour. """
3407 return self
._pages
._tabAreaColor
3410 def SetActiveTabColour(self
, color
):
3411 """ Sets the active tab colour. """
3413 self
._pages
._activeTabColor
= color
3416 def GetActiveTabColour(self
):
3417 """ Returns the active tab colour. """
3419 return self
._pages
._activeTabColor
3422 # ---------------------------------------------------------------------------- #
3423 # Class PageContainer
3424 # Acts as a container for the pages you add to FlatNotebook
3425 # ---------------------------------------------------------------------------- #
3427 class PageContainer(wx
.Panel
):
3429 This class acts as a container for the pages you add to L{FlatNotebook}.
3432 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
,
3433 size
=wx
.DefaultSize
, style
=0):
3434 """ Default class constructor. """
3436 self
._ImageList
= None
3437 self
._iActivePage
= -1
3438 self
._pDropTarget
= None
3439 self
._nLeftClickZone
= FNB_NOWHERE
3440 self
._iPreviousActivePage
= -1
3442 self
._pRightClickMenu
= None
3443 self
._nXButtonStatus
= FNB_BTN_NONE
3444 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3445 self
._pParent
= parent
3446 self
._nRightButtonStatus
= FNB_BTN_NONE
3447 self
._nLeftButtonStatus
= FNB_BTN_NONE
3448 self
._nTabXButtonStatus
= FNB_BTN_NONE
3450 self
._pagesInfoVec
= []
3452 self
._colorTo
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_ACTIVECAPTION
)
3453 self
._colorFrom
= wx
.WHITE
3454 self
._activeTabColor
= wx
.WHITE
3455 self
._activeTextColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNTEXT
)
3456 self
._nonActiveTextColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
3457 self
._tabAreaColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
)
3460 self
._isdragging
= False
3462 # Set default page height, this is done according to the system font
3463 memDc
= wx
.MemoryDC()
3464 memDc
.SelectObject(wx
.EmptyBitmap(10,10))
3465 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3466 boldFont
= normalFont
3467 boldFont
.SetWeight(wx
.BOLD
)
3468 memDc
.SetFont(boldFont
)
3470 height
= memDc
.GetCharHeight()
3471 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 10 pixels as padding
3473 wx
.Panel
.__init
__(self
, parent
, id, pos
, wx
.Size(size
.x
, tabHeight
),
3474 style|wx
.NO_BORDER|wx
.NO_FULL_REPAINT_ON_RESIZE
)
3476 self
._pDropTarget
= FNBDropTarget(self
)
3477 self
.SetDropTarget(self
._pDropTarget
)
3478 self
._mgr
= FNBRendererMgr()
3480 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
3481 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
3482 self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
)
3483 self
.Bind(wx
.EVT_LEFT_UP
, self
.OnLeftUp
)
3484 self
.Bind(wx
.EVT_RIGHT_DOWN
, self
.OnRightDown
)
3485 self
.Bind(wx
.EVT_MIDDLE_DOWN
, self
.OnMiddleDown
)
3486 self
.Bind(wx
.EVT_MOTION
, self
.OnMouseMove
)
3487 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
3488 self
.Bind(wx
.EVT_LEAVE_WINDOW
, self
.OnMouseLeave
)
3489 self
.Bind(wx
.EVT_ENTER_WINDOW
, self
.OnMouseEnterWindow
)
3490 self
.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnLeftDClick
)
3493 def OnEraseBackground(self
, event
):
3494 """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
3499 def OnPaint(self
, event
):
3500 """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
3502 # Currently having problems with buffered DCs because of
3503 # recent changes. Just do the buffering ourselves instead.
3504 #dc = wx.BufferedPaintDC(self)
3505 size
= self
.GetSize()
3506 bmp
= wx
.EmptyBitmap(*size
)
3508 dc
.SelectObject(bmp
)
3510 renderer
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag())
3511 renderer
.DrawTabs(self
, dc
)
3513 pdc
= wx
.PaintDC(self
)
3514 pdc
.Blit(0,0, size
.width
, size
.height
, dc
, 0,0)
3517 def AddPage(self
, caption
, selected
=True, imgindex
=-1):
3519 Add a page to the L{FlatNotebook}.
3521 @param window: Specifies the new page.
3522 @param caption: Specifies the text for the new page.
3523 @param selected: Specifies whether the page should be selected.
3524 @param imgindex: Specifies the optional image index for the new page.
3527 True if successful, False otherwise.
3532 self
._iPreviousActivePage
= self
._iActivePage
3533 self
._iActivePage
= len(self
._pagesInfoVec
)
3535 # Create page info and add it to the vector
3536 pageInfo
= PageInfo(caption
, imgindex
)
3537 self
._pagesInfoVec
.append(pageInfo
)
3541 def InsertPage(self
, indx
, text
, selected
=True, imgindex
=-1):
3543 Inserts a new page at the specified position.
3545 @param indx: Specifies the position of the new page.
3546 @param page: Specifies the new page.
3547 @param text: Specifies the text for the new page.
3548 @param select: Specifies whether the page should be selected.
3549 @param imgindex: Specifies the optional image index for the new page.
3552 True if successful, False otherwise.
3557 self
._iPreviousActivePage
= self
._iActivePage
3558 self
._iActivePage
= len(self
._pagesInfoVec
)
3560 self
._pagesInfoVec
.insert(indx
, PageInfo(text
, imgindex
))
3566 def OnSize(self
, event
):
3567 """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
3569 self
.Refresh() # Call on paint
3573 def OnMiddleDown(self
, event
):
3574 """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
3576 # Test if this style is enabled
3577 style
= self
.GetParent().GetWindowStyleFlag()
3579 if not style
& FNB_MOUSE_MIDDLE_CLOSES_TABS
:
3582 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3584 if where
== FNB_TAB
:
3585 self
.DeletePage(tabIdx
)
3590 def OnRightDown(self
, event
):
3591 """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
3593 if self
._pRightClickMenu
:
3595 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3597 if where
in [FNB_TAB
, FNB_TAB_X
]:
3599 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
3600 # Set the current tab to be active
3601 self
.SetSelection(tabIdx
)
3603 # If the owner has defined a context menu for the tabs,
3604 # popup the right click menu
3605 if self
._pRightClickMenu
:
3606 self
.PopupMenu(self
._pRightClickMenu
)
3608 # send a message to popup a custom menu
3609 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, self
.GetParent().GetId())
3610 event
.SetSelection(tabIdx
)
3611 event
.SetOldSelection(self
._iActivePage
)
3612 event
.SetEventObject(self
.GetParent())
3613 self
.GetParent().GetEventHandler().ProcessEvent(event
)
3618 def OnLeftDown(self
, event
):
3619 """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
3621 # Reset buttons status
3622 self
._nXButtonStatus
= FNB_BTN_NONE
3623 self
._nLeftButtonStatus
= FNB_BTN_NONE
3624 self
._nRightButtonStatus
= FNB_BTN_NONE
3625 self
._nTabXButtonStatus
= FNB_BTN_NONE
3626 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3628 self
._nLeftClickZone
, tabIdx
= self
.HitTest(event
.GetPosition())
3630 if self
._nLeftClickZone
== FNB_DROP_DOWN_ARROW
:
3631 self
._nArrowDownButtonStatus
= FNB_BTN_PRESSED
3633 elif self
._nLeftClickZone
== FNB_LEFT_ARROW
:
3634 self
._nLeftButtonStatus
= FNB_BTN_PRESSED
3636 elif self
._nLeftClickZone
== FNB_RIGHT_ARROW
:
3637 self
._nRightButtonStatus
= FNB_BTN_PRESSED
3639 elif self
._nLeftClickZone
== FNB_X
:
3640 self
._nXButtonStatus
= FNB_BTN_PRESSED
3642 elif self
._nLeftClickZone
== FNB_TAB_X
:
3643 self
._nTabXButtonStatus
= FNB_BTN_PRESSED
3646 elif self
._nLeftClickZone
== FNB_TAB
:
3648 if self
._iActivePage
!= tabIdx
:
3650 # In case the tab is disabled, we dont allow to choose it
3651 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
3653 oldSelection
= self
._iActivePage
3655 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
3656 event
.SetSelection(tabIdx
)
3657 event
.SetOldSelection(oldSelection
)
3658 event
.SetEventObject(self
.GetParent())
3660 if not self
.GetParent().GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
3662 self
.SetSelection(tabIdx
)
3664 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3665 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
3666 event
.SetOldSelection(oldSelection
)
3667 self
.GetParent().GetEventHandler().ProcessEvent(event
)
3670 def OnLeftUp(self
, event
):
3671 """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
3673 # forget the zone that was initially clicked
3674 self
._nLeftClickZone
= FNB_NOWHERE
3676 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3678 if where
== FNB_LEFT_ARROW
:
3680 if self
._nFrom
== 0:
3683 # Make sure that the button was pressed before
3684 if self
._nLeftButtonStatus
!= FNB_BTN_PRESSED
:
3687 self
._nLeftButtonStatus
= FNB_BTN_HOVER
3689 # We scroll left with bulks of 5
3690 scrollLeft
= self
.GetNumTabsCanScrollLeft()
3692 self
._nFrom
-= scrollLeft
3698 elif where
== FNB_RIGHT_ARROW
:
3700 if self
._nFrom
>= len(self
._pagesInfoVec
) - 1:
3703 # Make sure that the button was pressed before
3704 if self
._nRightButtonStatus
!= FNB_BTN_PRESSED
:
3707 self
._nRightButtonStatus
= FNB_BTN_HOVER
3709 # Check if the right most tab is visible, if it is
3710 # don't rotate right anymore
3711 if self
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1):
3714 lastVisibleTab
= self
.GetLastVisibleTab()
3715 if lastVisibleTab
< 0:
3716 # Probably the screen is too small for displaying even a single
3717 # tab, in this case we do nothing
3720 self
._nFrom
+= self
.GetNumOfVisibleTabs()
3723 elif where
== FNB_X
:
3725 # Make sure that the button was pressed before
3726 if self
._nXButtonStatus
!= FNB_BTN_PRESSED
:
3729 self
._nXButtonStatus
= FNB_BTN_HOVER
3731 self
.DeletePage(self
._iActivePage
)
3733 elif where
== FNB_TAB_X
:
3735 # Make sure that the button was pressed before
3736 if self
._nTabXButtonStatus
!= FNB_BTN_PRESSED
:
3739 self
._nTabXButtonStatus
= FNB_BTN_HOVER
3741 self
.DeletePage(self
._iActivePage
)
3743 elif where
== FNB_DROP_DOWN_ARROW
:
3745 # Make sure that the button was pressed before
3746 if self
._nArrowDownButtonStatus
!= FNB_BTN_PRESSED
:
3749 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3751 # Refresh the button status
3752 renderer
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag())
3753 dc
= wx
.ClientDC(self
)
3754 renderer
.DrawDropDownArrow(self
, dc
)
3756 self
.PopupTabsMenu()
3759 def HitTest(self
, pt
):
3761 HitTest method for L{PageContainer}.
3762 Returns the flag (if any) and the hit page (if any).
3765 style
= self
.GetParent().GetWindowStyleFlag()
3766 render
= self
._mgr
.GetRenderer(style
)
3768 fullrect
= self
.GetClientRect()
3769 btnLeftPos
= render
.GetLeftButtonPos(self
)
3770 btnRightPos
= render
.GetRightButtonPos(self
)
3771 btnXPos
= render
.GetXPos(self
)
3775 if len(self
._pagesInfoVec
) == 0:
3776 return FNB_NOWHERE
, tabIdx
3778 rect
= wx
.Rect(btnXPos
, 8, 16, 16)
3779 if rect
.Contains(pt
):
3780 return (style
& FNB_NO_X_BUTTON
and [FNB_NOWHERE
] or [FNB_X
])[0], tabIdx
3782 rect
= wx
.Rect(btnRightPos
, 8, 16, 16)
3783 if style
& FNB_DROPDOWN_TABS_LIST
:
3784 rect
= wx
.Rect(render
.GetDropArrowButtonPos(self
), 8, 16, 16)
3785 if rect
.Contains(pt
):
3786 return FNB_DROP_DOWN_ARROW
, tabIdx
3788 if rect
.Contains(pt
):
3789 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_RIGHT_ARROW
])[0], tabIdx
3791 rect
= wx
.Rect(btnLeftPos
, 8, 16, 16)
3792 if rect
.Contains(pt
):
3793 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_LEFT_ARROW
])[0], tabIdx
3795 # Test whether a left click was made on a tab
3798 for cur
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
3800 pgInfo
= self
._pagesInfoVec
[cur
]
3802 if pgInfo
.GetPosition() == wx
.Point(-1, -1):
3805 if style
& FNB_X_ON_TAB
and cur
== self
.GetSelection():
3806 # 'x' button exists on a tab
3807 if self
._pagesInfoVec
[cur
].GetXRect().Contains(pt
):
3808 return FNB_TAB_X
, cur
3812 if self
._pagesInfoVec
[cur
].GetRegion().Contains(pt
.x
, pt
.y
):
3813 if bFoundMatch
or cur
== self
.GetSelection():
3821 tabRect
= wx
.Rect(pgInfo
.GetPosition().x
, pgInfo
.GetPosition().y
,
3822 pgInfo
.GetSize().x
, pgInfo
.GetSize().y
)
3824 if tabRect
.Contains(pt
):
3829 return FNB_TAB
, tabIdx
3831 if self
._isdragging
:
3832 # We are doing DND, so check also the region outside the tabs
3833 # try before the first tab
3834 pgInfo
= self
._pagesInfoVec
[0]
3835 tabRect
= wx
.Rect(0, pgInfo
.GetPosition().y
, pgInfo
.GetPosition().x
, self
.GetParent().GetSize().y
)
3836 if tabRect
.Contains(pt
):
3839 # try after the last tab
3840 pgInfo
= self
._pagesInfoVec
[-1]
3841 startpos
= pgInfo
.GetPosition().x
+pgInfo
.GetSize().x
3842 tabRect
= wx
.Rect(startpos
, pgInfo
.GetPosition().y
, fullrect
.width
-startpos
, self
.GetParent().GetSize().y
)
3844 if tabRect
.Contains(pt
):
3845 return FNB_TAB
, len(self
._pagesInfoVec
)
3848 return FNB_NOWHERE
, -1
3851 def SetSelection(self
, page
):
3852 """ Sets the selected page. """
3854 book
= self
.GetParent()
3855 book
.SetSelection(page
)
3856 self
.DoSetSelection(page
)
3859 def DoSetSelection(self
, page
):
3860 """ Does the actual selection of a page. """
3862 if page
< len(self
._pagesInfoVec
):
3864 da_page
= self
._pParent
.GetPage(page
)
3869 if not self
.IsTabVisible(page
):
3871 if page
== len(self
._pagesInfoVec
) - 1:
3872 # Incase the added tab is last,
3873 # the function IsTabVisible() will always return False
3874 # and thus will cause an evil behaviour that the new
3875 # tab will hide all other tabs, we need to check if the
3876 # new selected tab can fit to the current screen
3877 if not self
.CanFitToScreen(page
):
3882 if not self
.CanFitToScreen(page
):
3883 # Redraw the tabs starting from page
3889 def DeletePage(self
, page
):
3890 """ Delete the specified page from L{FlatNotebook}. """
3892 book
= self
.GetParent()
3893 book
.DeletePage(page
)
3897 def IsTabVisible(self
, page
):
3898 """ Returns whether a tab is visible or not. """
3900 iLastVisiblePage
= self
.GetLastVisibleTab()
3901 return page
<= iLastVisiblePage
and page
>= self
._nFrom
3904 def DoDeletePage(self
, page
):
3905 """ Does the actual page deletion. """
3907 # Remove the page from the vector
3908 book
= self
.GetParent()
3909 self
._pagesInfoVec
.pop(page
)
3911 # Thanks to Yiaanis AKA Mandrav
3912 if self
._iActivePage
>= page
:
3913 self
._iActivePage
= self
._iActivePage
- 1
3914 self
._iPreviousActivePage
= -1
3916 # The delete page was the last first on the array,
3917 # but the book still has more pages, so we set the
3918 # active page to be the first one (0)
3919 if self
._iActivePage
< 0 and len(self
._pagesInfoVec
) > 0:
3920 self
._iActivePage
= 0
3921 self
._iPreviousActivePage
= -1
3924 if self
._iActivePage
>= 0:
3926 book
._bForceSelection
= True
3928 # Check for selection and send event
3929 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
3930 event
.SetSelection(self
._iActivePage
)
3931 event
.SetOldSelection(self
._iPreviousActivePage
)
3932 event
.SetEventObject(self
.GetParent())
3934 book
.SetSelection(self
._iActivePage
)
3935 book
._bForceSelection
= False
3937 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3938 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
3939 event
.SetOldSelection(self
._iPreviousActivePage
)
3940 self
.GetParent().GetEventHandler().ProcessEvent(event
)
3942 if not self
._pagesInfoVec
:
3943 # Erase the page container drawings
3944 dc
= wx
.ClientDC(self
)
3948 def DeleteAllPages(self
):
3949 """ Deletes all the pages. """
3951 self
._iActivePage
= -1
3952 self
._iPreviousActivePage
= -1
3954 self
._pagesInfoVec
= []
3956 # Erase the page container drawings
3957 dc
= wx
.ClientDC(self
)
3961 def OnMouseMove(self
, event
):
3962 """ Handles the wx.EVT_MOTION for L{PageContainer}. """
3964 if self
._pagesInfoVec
and self
.IsShown():
3966 xButtonStatus
= self
._nXButtonStatus
3967 xTabButtonStatus
= self
._nTabXButtonStatus
3968 rightButtonStatus
= self
._nRightButtonStatus
3969 leftButtonStatus
= self
._nLeftButtonStatus
3970 dropDownButtonStatus
= self
._nArrowDownButtonStatus
3972 style
= self
.GetParent().GetWindowStyleFlag()
3974 self
._nXButtonStatus
= FNB_BTN_NONE
3975 self
._nRightButtonStatus
= FNB_BTN_NONE
3976 self
._nLeftButtonStatus
= FNB_BTN_NONE
3977 self
._nTabXButtonStatus
= FNB_BTN_NONE
3978 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3980 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3983 if event
.LeftIsDown():
3985 self
._nXButtonStatus
= (self
._nLeftClickZone
==FNB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
3989 self
._nXButtonStatus
= FNB_BTN_HOVER
3991 elif where
== FNB_DROP_DOWN_ARROW
:
3992 if event
.LeftIsDown():
3994 self
._nArrowDownButtonStatus
= (self
._nLeftClickZone
==FNB_DROP_DOWN_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
3998 self
._nArrowDownButtonStatus
= FNB_BTN_HOVER
4000 elif where
== FNB_TAB_X
:
4001 if event
.LeftIsDown():
4003 self
._nTabXButtonStatus
= (self
._nLeftClickZone
==FNB_TAB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4007 self
._nTabXButtonStatus
= FNB_BTN_HOVER
4009 elif where
== FNB_RIGHT_ARROW
:
4010 if event
.LeftIsDown():
4012 self
._nRightButtonStatus
= (self
._nLeftClickZone
==FNB_RIGHT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4016 self
._nRightButtonStatus
= FNB_BTN_HOVER
4018 elif where
== FNB_LEFT_ARROW
:
4019 if event
.LeftIsDown():
4021 self
._nLeftButtonStatus
= (self
._nLeftClickZone
==FNB_LEFT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4025 self
._nLeftButtonStatus
= FNB_BTN_HOVER
4027 elif where
== FNB_TAB
:
4028 # Call virtual method for showing tooltip
4029 self
.ShowTabTooltip(tabIdx
)
4031 if not self
.GetEnabled(tabIdx
):
4032 # Set the cursor to be 'No-entry'
4033 wx
.SetCursor(wx
.StockCursor(wx
.CURSOR_NO_ENTRY
))
4035 # Support for drag and drop
4036 if event
.LeftIsDown() and not (style
& FNB_NODRAG
):
4038 self
._isdragging
= True
4039 draginfo
= FNBDragInfo(self
, tabIdx
)
4040 drginfo
= cPickle
.dumps(draginfo
)
4041 dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
4042 dataobject
.SetData(drginfo
)
4043 dragSource
= wx
.DropSource(self
)
4044 dragSource
.SetData(dataobject
)
4045 dragSource
.DoDragDrop(wx
.Drag_DefaultMove
)
4047 bRedrawX
= self
._nXButtonStatus
!= xButtonStatus
4048 bRedrawRight
= self
._nRightButtonStatus
!= rightButtonStatus
4049 bRedrawLeft
= self
._nLeftButtonStatus
!= leftButtonStatus
4050 bRedrawTabX
= self
._nTabXButtonStatus
!= xTabButtonStatus
4051 bRedrawDropArrow
= self
._nArrowDownButtonStatus
!= dropDownButtonStatus
4053 render
= self
._mgr
.GetRenderer(style
)
4055 if (bRedrawX
or bRedrawRight
or bRedrawLeft
or bRedrawTabX
or bRedrawDropArrow
):
4057 dc
= wx
.ClientDC(self
)
4061 render
.DrawX(self
, dc
)
4065 render
.DrawLeftArrow(self
, dc
)
4069 render
.DrawRightArrow(self
, dc
)
4073 render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[tabIdx
].GetXRect(), tabIdx
, self
._nTabXButtonStatus
)
4075 if bRedrawDropArrow
:
4077 render
.DrawDropDownArrow(self
, dc
)
4082 def GetLastVisibleTab(self
):
4083 """ Returns the last visible tab. """
4087 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4089 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
4095 def GetNumTabsCanScrollLeft(self
):
4096 """ Returns the number of tabs than can be scrolled left. """
4098 # Reserved area for the buttons (<>x)
4099 rect
= self
.GetClientRect()
4100 clientWidth
= rect
.width
4101 posx
= self
._pParent
._nPadding
4105 # In case we have error prevent crash
4109 dc
= wx
.ClientDC(self
)
4111 style
= self
.GetParent().GetWindowStyleFlag()
4112 render
= self
._mgr
.GetRenderer(style
)
4114 for ii
in xrange(self
._nFrom
, -1, -1):
4116 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
4117 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
4118 dc
.SetFont(boldFont
)
4120 height
= dc
.GetCharHeight()
4122 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 6 pixels as padding
4123 if style
& FNB_VC71
:
4124 tabHeight
= (style
& FNB_BOTTOM
and [tabHeight
- 4] or [tabHeight
])[0]
4125 elif style
& FNB_FANCY_TABS
:
4126 tabHeight
= (style
& FNB_BOTTOM
and [tabHeight
- 3] or [tabHeight
])[0]
4128 width
, pom
= dc
.GetTextExtent(self
.GetPageText(ii
))
4129 if style
!= FNB_VC71
:
4130 shapePoints
= int(tabHeight
*math
.tan(float(self
._pagesInfoVec
[ii
].GetTabAngle())/180.0*math
.pi
))
4134 tabWidth
= 2*self
._pParent
._nPadding
+ width
4136 if not (style
& FNB_VC71
):
4138 tabWidth
+= 2*shapePoints
4140 hasImage
= self
._ImageList
!= None and self
._pagesInfoVec
[ii
].GetImageIndex() != -1
4142 # For VC71 style, we only add the icon size (16 pixels)
4145 if not self
.IsDefaultTabs():
4146 tabWidth
+= 16 + self
._pParent
._nPadding
4149 tabWidth
+= 16 + self
._pParent
._nPadding
+ shapePoints
/2
4151 if posx
+ tabWidth
+ render
.GetButtonsAreaLength(self
) >= clientWidth
:
4154 numTabs
= numTabs
+ 1
4160 def IsDefaultTabs(self
):
4161 """ Returns whether a tab has a default style. """
4163 style
= self
.GetParent().GetWindowStyleFlag()
4164 res
= (style
& FNB_VC71
) or (style
& FNB_FANCY_TABS
) or (style
& FNB_VC8
)
4168 def AdvanceSelection(self
, bForward
=True):
4170 Cycles through the tabs.
4171 The call to this function generates the page changing events.
4174 nSel
= self
.GetSelection()
4179 nMax
= self
.GetPageCount() - 1
4181 oldSelection
= self
._iActivePage
4183 newSelection
= (nSel
== nMax
and [0] or [nSel
+ 1])[0]
4185 newSelection
= (nSel
== 0 and [nMax
] or [nSel
- 1])[0]
4187 if not self
._pagesInfoVec
[newSelection
].GetEnabled():
4190 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
4191 event
.SetSelection(newSelection
)
4192 event
.SetOldSelection(oldSelection
)
4193 event
.SetEventObject(self
.GetParent())
4195 if not self
.GetParent().GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
4197 self
.SetSelection(newSelection
)
4199 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4200 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
4201 event
.SetOldSelection(oldSelection
)
4202 self
.GetParent().GetEventHandler().ProcessEvent(event
)
4205 def OnMouseLeave(self
, event
):
4206 """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
4208 self
._nLeftButtonStatus
= FNB_BTN_NONE
4209 self
._nXButtonStatus
= FNB_BTN_NONE
4210 self
._nRightButtonStatus
= FNB_BTN_NONE
4211 self
._nTabXButtonStatus
= FNB_BTN_NONE
4212 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4214 style
= self
.GetParent().GetWindowStyleFlag()
4215 render
= self
._mgr
.GetRenderer(style
)
4217 dc
= wx
.ClientDC(self
)
4219 render
.DrawX(self
, dc
)
4220 render
.DrawLeftArrow(self
, dc
)
4221 render
.DrawRightArrow(self
, dc
)
4223 selection
= self
.GetSelection()
4229 if not self
.IsTabVisible(selection
):
4230 if selection
== len(self
._pagesInfoVec
) - 1:
4231 if not self
.CanFitToScreen(selection
):
4238 render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[selection
].GetXRect(), selection
, self
._nTabXButtonStatus
)
4243 def OnMouseEnterWindow(self
, event
):
4244 """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
4246 self
._nLeftButtonStatus
= FNB_BTN_NONE
4247 self
._nXButtonStatus
= FNB_BTN_NONE
4248 self
._nRightButtonStatus
= FNB_BTN_NONE
4249 self
._nLeftClickZone
= FNB_BTN_NONE
4250 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4255 def ShowTabTooltip(self
, tabIdx
):
4256 """ Shows a tab tooltip. """
4258 pWindow
= self
._pParent
.GetPage(tabIdx
)
4261 pToolTip
= pWindow
.GetToolTip()
4262 if pToolTip
and pToolTip
.GetWindow() == pWindow
:
4263 self
.SetToolTipString(pToolTip
.GetTip())
4266 def SetPageImage(self
, page
, imgindex
):
4267 """ Sets the image index associated to a page. """
4269 if page
< len(self
._pagesInfoVec
):
4271 self
._pagesInfoVec
[page
].SetImageIndex(imgindex
)
4275 def GetPageImage(self
, page
):
4276 """ Returns the image index associated to a page. """
4278 if page
< len(self
._pagesInfoVec
):
4280 return self
._pagesInfoVec
[page
].GetImageIndex()
4285 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
4286 """ Handles the drop action from a DND operation. """
4288 # Disable drag'n'drop for disabled tab
4289 if not wnd_oldContainer
._pagesInfoVec
[nTabPage
].GetEnabled():
4290 return wx
.DragCancel
4292 self
._isdragging
= True
4293 oldContainer
= wnd_oldContainer
4296 where
, nIndex
= self
.HitTest(wx
.Point(x
, y
))
4298 oldNotebook
= oldContainer
.GetParent()
4299 newNotebook
= self
.GetParent()
4301 if oldNotebook
== newNotebook
:
4305 if where
== FNB_TAB
:
4306 self
.MoveTabPage(nTabPage
, nIndex
)
4308 elif self
.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND
:
4310 if wx
.Platform
in ["__WXMSW__", "__WXGTK__"]:
4313 window
= oldNotebook
.GetPage(nTabPage
)
4316 where
, nIndex
= newNotebook
._pages
.HitTest(wx
.Point(x
, y
))
4317 caption
= oldContainer
.GetPageText(nTabPage
)
4318 imageindex
= oldContainer
.GetPageImage(nTabPage
)
4319 oldNotebook
.RemovePage(nTabPage
)
4320 window
.Reparent(newNotebook
)
4324 bmp
= oldNotebook
.GetImageList().GetBitmap(imageindex
)
4325 newImageList
= newNotebook
.GetImageList()
4327 if not newImageList
:
4328 xbmp
, ybmp
= bmp
.GetWidth(), bmp
.GetHeight()
4329 newImageList
= wx
.ImageList(xbmp
, ybmp
)
4332 imageindex
= newImageList
.GetImageCount()
4334 newImageList
.Add(bmp
)
4335 newNotebook
.SetImageList(newImageList
)
4337 newNotebook
.InsertPage(nIndex
, window
, caption
, True, imageindex
)
4339 self
._isdragging
= False
4344 def MoveTabPage(self
, nMove
, nMoveTo
):
4345 """ Moves a tab inside the same L{FlatNotebook}. """
4347 if nMove
== nMoveTo
:
4350 elif nMoveTo
< len(self
._pParent
._windows
):
4351 nMoveTo
= nMoveTo
+ 1
4353 self
._pParent
.Freeze()
4355 # Remove the window from the main sizer
4356 nCurSel
= self
._pParent
._pages
.GetSelection()
4357 self
._pParent
._mainSizer
.Detach(self
._pParent
._windows
[nCurSel
])
4358 self
._pParent
._windows
[nCurSel
].Hide()
4360 pWindow
= self
._pParent
._windows
[nMove
]
4361 self
._pParent
._windows
.pop(nMove
)
4362 self
._pParent
._windows
.insert(nMoveTo
-1, pWindow
)
4364 pgInfo
= self
._pagesInfoVec
[nMove
]
4366 self
._pagesInfoVec
.pop(nMove
)
4367 self
._pagesInfoVec
.insert(nMoveTo
- 1, pgInfo
)
4369 # Add the page according to the style
4370 pSizer
= self
._pParent
._mainSizer
4371 style
= self
.GetParent().GetWindowStyleFlag()
4373 if style
& FNB_BOTTOM
:
4375 pSizer
.Insert(0, pWindow
, 1, wx
.EXPAND
)
4379 # We leave a space of 1 pixel around the window
4380 pSizer
.Add(pWindow
, 1, wx
.EXPAND
)
4385 self
._iActivePage
= nMoveTo
- 1
4386 self
._iPreviousActivePage
= -1
4387 self
.DoSetSelection(self
._iActivePage
)
4389 self
._pParent
.Thaw()
4392 def CanFitToScreen(self
, page
):
4393 """ Returns wheter a tab can fit in the left space in the screen or not. """
4395 # Incase the from is greater than page,
4396 # we need to reset the self._nFrom, so in order
4397 # to force the caller to do so, we return false
4398 if self
._nFrom
> page
:
4401 style
= self
.GetParent().GetWindowStyleFlag()
4402 render
= self
._mgr
.GetRenderer(style
)
4404 if not self
.HasFlag(FNB_VC8
):
4405 rect
= self
.GetClientRect();
4406 clientWidth
= rect
.width
;
4407 tabHeight
= render
.CalcTabHeight(self
)
4408 tabWidth
= render
.CalcTabWidth(self
, page
, tabHeight
)
4410 posx
= self
._pParent
._nPadding
4412 if self
._nFrom
>= 0:
4414 for i
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4416 if self
._pagesInfoVec
[i
].GetPosition() == wx
.Point(-1, -1):
4419 posx
+= self
._pagesInfoVec
[i
].GetSize().x
4421 if posx
+ tabWidth
+ render
.GetButtonsAreaLength(self
) >= clientWidth
:
4428 # TODO:: this is ugly and should be improved, we should *never* access the
4429 # raw pointer directly like we do here (render.Get())
4431 vTabInfo
= vc8_render
.NumberTabsCanFit(self
)
4433 if page
- self
._nFrom
>= len(vTabInfo
):
4439 def GetNumOfVisibleTabs(self
):
4440 """ Returns the number of visible tabs. """
4443 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4444 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
4451 def GetEnabled(self
, page
):
4452 """ Returns whether a tab is enabled or not. """
4454 if page
>= len(self
._pagesInfoVec
):
4455 return True # Seems strange, but this is the default
4457 return self
._pagesInfoVec
[page
].GetEnabled()
4460 def Enable(self
, page
, enabled
=True):
4461 """ Enables or disables a tab. """
4463 if page
>= len(self
._pagesInfoVec
):
4466 self
._pagesInfoVec
[page
].Enable(enabled
)
4469 def GetSingleLineBorderColour(self
):
4470 """ Returns the colour for the single line border. """
4472 if self
.HasFlag(FNB_FANCY_TABS
):
4473 return self
._colorFrom
4478 def HasFlag(self
, flag
):
4479 """ Returns whether a flag is present in the L{FlatNotebook} style. """
4481 style
= self
.GetParent().GetWindowStyleFlag()
4482 res
= (style
& flag
and [True] or [False])[0]
4486 def ClearFlag(self
, flag
):
4487 """ Deletes a flag from the L{FlatNotebook} style. """
4489 style
= self
.GetParent().GetWindowStyleFlag()
4491 self
.SetWindowStyleFlag(style
)
4494 def TabHasImage(self
, tabIdx
):
4495 """ Returns whether a tab has an associated image index or not. """
4498 return self
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
4503 def OnLeftDClick(self
, event
):
4504 """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
4506 if self
.HasFlag(FNB_DCLICK_CLOSES_TABS
):
4508 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4510 if where
== FNB_TAB
:
4511 self
.DeletePage(tabIdx
)
4518 def PopupTabsMenu(self
):
4519 """ Pops up the menu activated with the drop down arrow in the navigation area. """
4521 popupMenu
= wx
.Menu()
4523 for i
in xrange(len(self
._pagesInfoVec
)):
4524 pi
= self
._pagesInfoVec
[i
]
4525 item
= wx
.MenuItem(popupMenu
, i
, pi
.GetCaption(), pi
.GetCaption(), wx
.ITEM_NORMAL
)
4526 self
.Bind(wx
.EVT_MENU
, self
.OnTabMenuSelection
, item
)
4528 # This code is commented, since there is an alignment problem with wx2.6.3 & Menus
4529 # if self.TabHasImage(ii):
4530 # item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] );
4532 popupMenu
.AppendItem(item
)
4534 self
.PopupMenu(popupMenu
)
4537 def OnTabMenuSelection(self
, event
):
4538 """ Handles the wx.EVT_MENU event for L{PageContainer}. """
4540 selection
= event
.GetId()
4541 self
._pParent
.SetSelection(selection
)
4544 def SetImageList(self
, imglist
):
4545 """ Sets the image list for the page control. """
4547 self
._ImageList
= imglist
4550 def GetImageList(self
):
4551 """ Returns the image list for the page control. """
4553 return self
._ImageList
4556 def GetSelection(self
):
4557 """ Returns the current selected page. """
4559 return self
._iActivePage
4562 def GetPageCount(self
):
4563 """ Returns the number of tabs in the L{FlatNotebook} control. """
4565 return len(self
._pagesInfoVec
)
4568 def GetPageText(self
, page
):
4569 """ Returns the tab caption of the page. """
4571 return self
._pagesInfoVec
[page
].GetCaption()
4574 def SetPageText(self
, page
, text
):
4575 """ Sets the tab caption of the page. """
4577 self
._pagesInfoVec
[page
].SetCaption(text
)