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: 26 Jun 2007, 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 5 differnt styles - VC8, VC 71, Standard, Fancy and Firefox 2;
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 @ 26 Jun 2007, 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"""
126 # Firefox 2 tabs style
128 """Use Firefox 2 style for tabs"""
132 """Place 'X' close button on the active tab"""
134 FNB_BACKGROUND_GRADIENT
= 1024
135 """Use gradients to paint the tabs background"""
137 FNB_COLORFUL_TABS
= 2048
138 """Use colourful tabs (VC8 style only)"""
140 # Style to close tab using double click - styles 1024, 2048 are reserved
141 FNB_DCLICK_CLOSES_TABS
= 4096
142 """Style to close tab using double click"""
144 FNB_SMART_TABS
= 8192
145 """Use Smart Tabbing, like Alt+Tab on Windows"""
147 FNB_DROPDOWN_TABS_LIST
= 16384
148 """Use a dropdown menu on the left in place of the arrows"""
150 FNB_ALLOW_FOREIGN_DND
= 32768
151 """Allows drag 'n' drop operations between different L{FlatNotebook}s"""
153 FNB_HIDE_ON_SINGLE_TAB
= 65536
154 """Hides the Page Container when there is one or fewer tabs"""
156 VERTICAL_BORDER_PADDING
= 4
158 # Button size is a 16x16 xpm bitmap
160 """Button size is a 16x16 xpm bitmap"""
164 MASK_COLOR
= wx
.Colour(0, 128, 128)
165 """Mask colour for the arrow bitmaps"""
169 """Navigation button is pressed"""
171 """Navigation button is hovered"""
176 FNB_TAB
= 1 # On a tab
177 """Indicates mouse coordinates inside a tab"""
178 FNB_X
= 2 # On the X button
179 """Indicates mouse coordinates inside the I{X} region"""
180 FNB_TAB_X
= 3 # On the 'X' button (tab's X button)
181 """Indicates mouse coordinates inside the I{X} region in a tab"""
182 FNB_LEFT_ARROW
= 4 # On the rotate left arrow button
183 """Indicates mouse coordinates inside the left arrow region"""
184 FNB_RIGHT_ARROW
= 5 # On the rotate right arrow button
185 """Indicates mouse coordinates inside the right arrow region"""
186 FNB_DROP_DOWN_ARROW
= 6 # On the drop down arrow button
187 """Indicates mouse coordinates inside the drop down arrow region"""
188 FNB_NOWHERE
= 0 # Anywhere else
189 """Indicates mouse coordinates not on any tab of the notebook"""
191 FNB_DEFAULT_STYLE
= FNB_MOUSE_MIDDLE_CLOSES_TABS | FNB_HIDE_ON_SINGLE_TAB
192 """L{FlatNotebook} default style"""
194 # FlatNotebook Events:
195 # wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page;
196 # wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch
197 # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call
198 # event.Skip() In Your Event Handler;
199 # wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But
200 # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip()
201 # In Your Event Handler;
202 # wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed.
203 # wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab.
205 wxEVT_FLATNOTEBOOK_PAGE_CHANGED
= wx
.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
206 wxEVT_FLATNOTEBOOK_PAGE_CHANGING
= wx
.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
207 wxEVT_FLATNOTEBOOK_PAGE_CLOSING
= wx
.NewEventType()
208 wxEVT_FLATNOTEBOOK_PAGE_CLOSED
= wx
.NewEventType()
209 wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
= wx
.NewEventType()
211 #-----------------------------------#
213 #-----------------------------------#
215 EVT_FLATNOTEBOOK_PAGE_CHANGED
= wx
.EVT_NOTEBOOK_PAGE_CHANGED
216 """Notify client objects when the active page in L{FlatNotebook}
218 EVT_FLATNOTEBOOK_PAGE_CHANGING
= wx
.EVT_NOTEBOOK_PAGE_CHANGING
219 """Notify client objects when the active page in L{FlatNotebook}
220 is about to change."""
221 EVT_FLATNOTEBOOK_PAGE_CLOSING
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, 1)
222 """Notify client objects when a page in L{FlatNotebook} is closing."""
223 EVT_FLATNOTEBOOK_PAGE_CLOSED
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, 1)
224 """Notify client objects when a page in L{FlatNotebook} has been closed."""
225 EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, 1)
226 """Notify client objects when a pop-up menu should appear next to a tab."""
229 # Some icons in XPM format
231 left_arrow_disabled_xpm
= [
259 x_button_pressed_xpm
= [
316 x_button_hilite_xpm
= [
372 left_arrow_pressed_xpm
= [
400 left_arrow_hilite_xpm
= [
428 right_arrow_disabled_xpm
= [
456 right_arrow_hilite_xpm
= [
484 right_arrow_pressed_xpm
= [
541 down_arrow_hilite_xpm
= [
569 down_arrow_pressed_xpm
= [
627 #----------------------------------------------------------------------
628 def GetMondrianData():
630 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
631 \x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\
632 ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\
633 o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\
634 \xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\
635 \x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\
636 \x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82'
639 def GetMondrianBitmap():
640 return wx
.BitmapFromImage(GetMondrianImage().Scale(16, 16))
643 def GetMondrianImage():
645 stream
= cStringIO
.StringIO(GetMondrianData())
646 return wx
.ImageFromStream(stream
)
649 def GetMondrianIcon():
650 icon
= wx
.EmptyIcon()
651 icon
.CopyFromBitmap(GetMondrianBitmap())
653 #----------------------------------------------------------------------
656 def LightColour(color
, percent
):
657 """ Brighten input colour by percent. """
661 rd
= end_color
.Red() - color
.Red()
662 gd
= end_color
.Green() - color
.Green()
663 bd
= end_color
.Blue() - color
.Blue()
667 # We take the percent way of the color from color -. white
669 r
= color
.Red() + ((i
*rd
*100)/high
)/100
670 g
= color
.Green() + ((i
*gd
*100)/high
)/100
671 b
= color
.Blue() + ((i
*bd
*100)/high
)/100
672 return wx
.Colour(r
, g
, b
)
676 """ Creates a random colour. """
678 r
= random
.randint(0, 255) # Random value betweem 0-255
679 g
= random
.randint(0, 255) # Random value betweem 0-255
680 b
= random
.randint(0, 255) # Random value betweem 0-255
682 return wx
.Colour(r
, g
, b
)
685 def PaintStraightGradientBox(dc
, rect
, startColor
, endColor
, vertical
=True):
686 """ Draws a gradient colored box from startColor to endColor. """
688 rd
= endColor
.Red() - startColor
.Red()
689 gd
= endColor
.Green() - startColor
.Green()
690 bd
= endColor
.Blue() - startColor
.Blue()
692 # Save the current pen and brush
693 savedPen
= dc
.GetPen()
694 savedBrush
= dc
.GetBrush()
697 high
= rect
.GetHeight()-1
699 high
= rect
.GetWidth()-1
704 for i
in xrange(high
+1):
706 r
= startColor
.Red() + ((i
*rd
*100)/high
)/100
707 g
= startColor
.Green() + ((i
*gd
*100)/high
)/100
708 b
= startColor
.Blue() + ((i
*bd
*100)/high
)/100
710 p
= wx
.Pen(wx
.Colour(r
, g
, b
))
714 dc
.DrawLine(rect
.x
, rect
.y
+i
, rect
.x
+rect
.width
, rect
.y
+i
)
716 dc
.DrawLine(rect
.x
+i
, rect
.y
, rect
.x
+i
, rect
.y
+rect
.height
)
718 # Restore the pen and brush
720 dc
.SetBrush(savedBrush
)
724 # -----------------------------------------------------------------------------
726 # -----------------------------------------------------------------------------
728 def DrawButton(dc
, rect
, focus
, upperTabs
):
730 # Define the rounded rectangle base on the given rect
731 # we need an array of 9 points for it
732 regPts
= [wx
.Point() for indx
in xrange(9)]
736 leftPt
= wx
.Point(rect
.x
, rect
.y
+ (rect
.height
/ 10)*8)
737 rightPt
= wx
.Point(rect
.x
+ rect
.width
- 2, rect
.y
+ (rect
.height
/ 10)*8)
739 leftPt
= wx
.Point(rect
.x
, rect
.y
+ (rect
.height
/ 10)*5)
740 rightPt
= wx
.Point(rect
.x
+ rect
.width
- 2, rect
.y
+ (rect
.height
/ 10)*5)
742 leftPt
= wx
.Point(rect
.x
, rect
.y
+ (rect
.height
/ 2))
743 rightPt
= wx
.Point(rect
.x
+ rect
.width
- 2, rect
.y
+ (rect
.height
/ 2))
745 # Define the top region
746 top
= wx
.RectPP(rect
.GetTopLeft(), rightPt
)
747 bottom
= wx
.RectPP(leftPt
, rect
.GetBottomRight())
749 topStartColor
= wx
.WHITE
752 topStartColor
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 50)
754 topEndColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)
755 bottomStartColor
= topEndColor
756 bottomEndColor
= topEndColor
758 # Incase we use bottom tabs, switch the colors
761 PaintStraightGradientBox(dc
, top
, topStartColor
, topEndColor
)
762 PaintStraightGradientBox(dc
, bottom
, bottomStartColor
, bottomEndColor
)
764 PaintStraightGradientBox(dc
, top
, topEndColor
, topStartColor
)
765 PaintStraightGradientBox(dc
, bottom
, bottomStartColor
, bottomEndColor
)
769 PaintStraightGradientBox(dc
, bottom
, topEndColor
, bottomEndColor
)
770 PaintStraightGradientBox(dc
, top
,topStartColor
, topStartColor
)
772 PaintStraightGradientBox(dc
, bottom
, bottomStartColor
, bottomEndColor
)
773 PaintStraightGradientBox(dc
, top
, topEndColor
, topStartColor
)
775 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
778 # ---------------------------------------------------------------------------- #
779 # Class FNBDropSource
780 # Gives Some Custom UI Feedback during the DnD Operations
781 # ---------------------------------------------------------------------------- #
783 class FNBDropSource(wx
.DropSource
):
785 Give some custom UI feedback during the drag and drop operation in this
786 function. It is called on each mouse move, so your implementation must
790 def __init__(self
, win
):
791 """ Default class constructor. Used internally. """
793 wx
.DropSource
.__init
__(self
, win
)
797 def GiveFeedback(self
, effect
):
798 """ Provides user with a nice feedback when tab is being dragged. """
800 self
._win
.DrawDragHint()
804 # ---------------------------------------------------------------------------- #
806 # Stores All The Information To Allow Drag And Drop Between Different
808 # ---------------------------------------------------------------------------- #
812 _map
= weakref
.WeakValueDictionary()
814 def __init__(self
, container
, pageindex
):
815 """ Default class constructor. """
817 self
._id
= id(container
)
818 FNBDragInfo
._map
[self
._id
] = container
819 self
._pageindex
= pageindex
822 def GetContainer(self
):
823 """ Returns the L{FlatNotebook} page (usually a panel). """
825 return FNBDragInfo
._map
.get(self
._id
, None)
828 def GetPageIndex(self
):
829 """ Returns the page index associated with a page. """
831 return self
._pageindex
834 # ---------------------------------------------------------------------------- #
835 # Class FNBDropTarget
836 # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between
837 # Different FlatNotebooks.
838 # ---------------------------------------------------------------------------- #
840 class FNBDropTarget(wx
.DropTarget
):
842 def __init__(self
, parent
):
843 """ Default class constructor. """
845 wx
.DropTarget
.__init
__(self
)
847 self
._parent
= parent
848 self
._dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
849 self
.SetDataObject(self
._dataobject
)
852 def OnData(self
, x
, y
, dragres
):
853 """ Handles the OnData() method to call the real DnD routine. """
855 if not self
.GetData():
858 draginfo
= self
._dataobject
.GetData()
859 drginfo
= cPickle
.loads(draginfo
)
861 return self
._parent
.OnDropTarget(x
, y
, drginfo
.GetPageIndex(), drginfo
.GetContainer())
864 # ---------------------------------------------------------------------------- #
866 # Contains parameters for every FlatNotebook page
867 # ---------------------------------------------------------------------------- #
871 This class holds all the information (caption, image, etc...) belonging to a
872 single tab in L{FlatNotebook}.
875 def __init__(self
, caption
="", imageindex
=-1, tabangle
=0, enabled
=True):
877 Default Class Constructor.
880 @param caption: the tab caption;
881 @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
882 @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
883 @param enabled: sets enabled or disabled the tab.
886 self
._strCaption
= caption
887 self
._TabAngle
= tabangle
888 self
._ImageIndex
= imageindex
889 self
._bEnabled
= enabled
890 self
._pos
= wx
.Point(-1, -1)
891 self
._size
= wx
.Size(-1, -1)
892 self
._region
= wx
.Region()
893 self
._xRect
= wx
.Rect()
895 self
._hasFocus
= False
898 def SetCaption(self
, value
):
899 """ Sets the tab caption. """
901 self
._strCaption
= value
904 def GetCaption(self
):
905 """ Returns the tab caption. """
907 return self
._strCaption
910 def SetPosition(self
, value
):
911 """ Sets the tab position. """
916 def GetPosition(self
):
917 """ Returns the tab position. """
922 def SetSize(self
, value
):
923 """ Sets the tab size. """
929 """ Returns the tab size. """
934 def SetTabAngle(self
, value
):
935 """ Sets the tab header angle (0 <= tab <= 15 degrees). """
937 self
._TabAngle
= min(45, value
)
940 def GetTabAngle(self
):
941 """ Returns the tab angle. """
943 return self
._TabAngle
946 def SetImageIndex(self
, value
):
947 """ Sets the tab image index. """
949 self
._ImageIndex
= value
952 def GetImageIndex(self
):
953 """ Returns the tab umage index. """
955 return self
._ImageIndex
958 def GetEnabled(self
):
959 """ Returns whether the tab is enabled or not. """
961 return self
._bEnabled
964 def EnableTab(self
, enabled
):
965 """ Sets the tab enabled or disabled. """
967 self
._bEnabled
= enabled
970 def SetRegion(self
, points
=[]):
971 """ Sets the tab region. """
973 self
._region
= wx
.RegionFromPoints(points
)
977 """ Returns the tab region. """
982 def SetXRect(self
, xrect
):
983 """ Sets the button 'X' area rect. """
989 """ Returns the button 'X' area rect. """
995 """ Returns the tab colour. """
1000 def SetColour(self
, color
):
1001 """ Sets the tab colour. """
1006 # ---------------------------------------------------------------------------- #
1007 # Class FlatNotebookEvent
1008 # ---------------------------------------------------------------------------- #
1010 class FlatNotebookEvent(wx
.PyCommandEvent
):
1012 This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
1013 EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING,
1014 EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is
1015 mapped in the parent.
1018 def __init__(self
, eventType
, id=1, nSel
=-1, nOldSel
=-1):
1019 """ Default class constructor. """
1021 wx
.PyCommandEvent
.__init
__(self
, eventType
, id)
1022 self
._eventType
= eventType
1024 self
.notify
= wx
.NotifyEvent(eventType
, id)
1027 def GetNotifyEvent(self
):
1028 """Returns the actual wx.NotifyEvent."""
1033 def IsAllowed(self
):
1034 """Returns whether the event is allowed or not."""
1036 return self
.notify
.IsAllowed()
1040 """Vetos the event."""
1046 """The event is allowed."""
1051 def SetSelection(self
, nSel
):
1052 """ Sets event selection. """
1054 self
._selection
= nSel
1057 def SetOldSelection(self
, nOldSel
):
1058 """ Sets old event selection. """
1060 self
._oldselection
= nOldSel
1063 def GetSelection(self
):
1064 """ Returns event selection. """
1066 return self
._selection
1069 def GetOldSelection(self
):
1070 """ Returns old event selection """
1072 return self
._oldselection
1075 # ---------------------------------------------------------------------------- #
1076 # Class TabNavigatorWindow
1077 # ---------------------------------------------------------------------------- #
1079 class TabNavigatorWindow(wx
.Dialog
):
1081 This class is used to create a modal dialog that enables "Smart Tabbing",
1082 similar to what you would get by hitting Alt+Tab on Windows.
1085 def __init__(self
, parent
=None):
1086 """ Default class constructor. Used internally."""
1088 wx
.Dialog
.__init
__(self
, parent
, wx
.ID_ANY
, "", style
=0)
1090 self
._selectedItem
= -1
1093 self
._bmp
= GetMondrianBitmap()
1095 sz
= wx
.BoxSizer(wx
.VERTICAL
)
1097 self
._listBox
= wx
.ListBox(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, 150), [], wx
.LB_SINGLE | wx
.NO_BORDER
)
1099 mem_dc
= wx
.MemoryDC()
1100 mem_dc
.SelectObject(wx
.EmptyBitmap(1,1))
1101 font
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1102 font
.SetWeight(wx
.BOLD
)
1103 mem_dc
.SetFont(font
)
1105 panelHeight
= mem_dc
.GetCharHeight()
1106 panelHeight
+= 4 # Place a spacer of 2 pixels
1108 # Out signpost bitmap is 24 pixels
1109 if panelHeight
< 24:
1112 self
._panel
= wx
.Panel(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, panelHeight
))
1115 sz
.Add(self
._listBox
, 1, wx
.EXPAND
)
1119 # Connect events to the list box
1120 self
._listBox
.Bind(wx
.EVT_KEY_UP
, self
.OnKeyUp
)
1121 self
._listBox
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
1122 self
._listBox
.Bind(wx
.EVT_LISTBOX_DCLICK
, self
.OnItemSelected
)
1124 # Connect paint event to the panel
1125 self
._panel
.Bind(wx
.EVT_PAINT
, self
.OnPanelPaint
)
1126 self
._panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnPanelEraseBg
)
1128 self
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1129 self
._listBox
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1130 self
.PopulateListControl(parent
)
1132 self
.GetSizer().Fit(self
)
1133 self
.GetSizer().SetSizeHints(self
)
1134 self
.GetSizer().Layout()
1138 def OnKeyUp(self
, event
):
1139 """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}."""
1141 if event
.GetKeyCode() == wx
.WXK_CONTROL
:
1145 def OnNavigationKey(self
, event
):
1146 """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """
1148 selected
= self
._listBox
.GetSelection()
1149 bk
= self
.GetParent()
1150 maxItems
= bk
.GetPageCount()
1152 if event
.GetDirection():
1155 if selected
== maxItems
- 1:
1158 itemToSelect
= selected
+ 1
1164 itemToSelect
= maxItems
- 1
1166 itemToSelect
= selected
- 1
1168 self
._listBox
.SetSelection(itemToSelect
)
1171 def PopulateListControl(self
, book
):
1172 """Populates the L{TabNavigatorWindow} listbox with a list of tabs."""
1174 selection
= book
.GetSelection()
1175 count
= book
.GetPageCount()
1177 self
._listBox
.Append(book
.GetPageText(selection
))
1178 self
._indexMap
.append(selection
)
1180 prevSel
= book
.GetPreviousSelection()
1182 if prevSel
!= wx
.NOT_FOUND
:
1184 # Insert the previous selection as second entry
1185 self
._listBox
.Append(book
.GetPageText(prevSel
))
1186 self
._indexMap
.append(prevSel
)
1188 for c
in xrange(count
):
1190 # Skip selected page
1194 # Skip previous selected page as well
1198 self
._listBox
.Append(book
.GetPageText(c
))
1199 self
._indexMap
.append(c
)
1201 # Select the next entry after the current selection
1202 self
._listBox
.SetSelection(0)
1203 dummy
= wx
.NavigationKeyEvent()
1204 dummy
.SetDirection(True)
1205 self
.OnNavigationKey(dummy
)
1208 def OnItemSelected(self
, event
):
1209 """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """
1214 def CloseDialog(self
):
1215 """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}."""
1217 bk
= self
.GetParent()
1218 self
._selectedItem
= self
._listBox
.GetSelection()
1219 iter = self
._indexMap
[self
._selectedItem
]
1220 bk
._pages
.FireEvent(iter)
1221 self
.EndModal(wx
.ID_OK
)
1224 def OnPanelPaint(self
, event
):
1225 """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """
1227 dc
= wx
.PaintDC(self
._panel
)
1228 rect
= self
._panel
.GetClientRect()
1230 bmp
= wx
.EmptyBitmap(rect
.width
, rect
.height
)
1232 mem_dc
= wx
.MemoryDC()
1233 mem_dc
.SelectObject(bmp
)
1235 endColour
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
1236 startColour
= LightColour(endColour
, 50)
1237 PaintStraightGradientBox(mem_dc
, rect
, startColour
, endColour
)
1239 # Draw the caption title and place the bitmap
1240 # get the bitmap optimal position, and draw it
1241 bmpPt
, txtPt
= wx
.Point(), wx
.Point()
1242 bmpPt
.y
= (rect
.height
- self
._bmp
.GetHeight())/2
1244 mem_dc
.DrawBitmap(self
._bmp
, bmpPt
.x
, bmpPt
.y
, True)
1246 # get the text position, and draw it
1247 font
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1248 font
.SetWeight(wx
.BOLD
)
1249 mem_dc
.SetFont(font
)
1250 fontHeight
= mem_dc
.GetCharHeight()
1252 txtPt
.x
= bmpPt
.x
+ self
._bmp
.GetWidth() + 4
1253 txtPt
.y
= (rect
.height
- fontHeight
)/2
1254 mem_dc
.SetTextForeground(wx
.WHITE
)
1255 mem_dc
.DrawText("Opened tabs:", txtPt
.x
, txtPt
.y
)
1256 mem_dc
.SelectObject(wx
.NullBitmap
)
1258 dc
.DrawBitmap(bmp
, 0, 0)
1261 def OnPanelEraseBg(self
, event
):
1262 """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """
1267 # ---------------------------------------------------------------------------- #
1269 # ---------------------------------------------------------------------------- #
1273 Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy}
1274 and I{VC8}. This class implements the common methods of all 4 renderers.
1275 @undocumented: _GetBitmap*
1279 """Default class constructor. """
1281 self
._tabXBgBmp
= wx
.EmptyBitmap(16, 16)
1282 self
._xBgBmp
= wx
.EmptyBitmap(16, 14)
1283 self
._leftBgBmp
= wx
.EmptyBitmap(16, 14)
1284 self
._rightBgBmp
= wx
.EmptyBitmap(16, 14)
1285 self
._tabHeight
= None
1287 if wx
.Platform
== "__WXMAC__":
1288 self
._focusPen
= wx
.Pen(wx
.BLACK
, 1, wx
.SOLID
)
1290 self
._focusPen
= wx
.Pen(wx
.BLACK
, 1, wx
.USER_DASH
)
1291 self
._focusPen
.SetDashes([1, 1])
1292 self
._focusPen
.SetCap(wx
.CAP_BUTT
)
1295 def GetLeftButtonPos(self
, pageContainer
):
1296 """ Returns the left button position in the navigation area. """
1299 style
= pc
.GetParent().GetWindowStyleFlag()
1300 rect
= pc
.GetClientRect()
1301 clientWidth
= rect
.width
1303 if style
& FNB_NO_X_BUTTON
:
1304 return clientWidth
- 38
1306 return clientWidth
- 54
1310 def GetRightButtonPos(self
, pageContainer
):
1311 """ Returns the right button position in the navigation area. """
1314 style
= pc
.GetParent().GetWindowStyleFlag()
1315 rect
= pc
.GetClientRect()
1316 clientWidth
= rect
.width
1318 if style
& FNB_NO_X_BUTTON
:
1319 return clientWidth
- 22
1321 return clientWidth
- 38
1324 def GetDropArrowButtonPos(self
, pageContainer
):
1325 """ Returns the drop down button position in the navigation area. """
1327 return self
.GetRightButtonPos(pageContainer
)
1330 def GetXPos(self
, pageContainer
):
1331 """ Returns the 'X' button position in the navigation area. """
1334 style
= pc
.GetParent().GetWindowStyleFlag()
1335 rect
= pc
.GetClientRect()
1336 clientWidth
= rect
.width
1338 if style
& FNB_NO_X_BUTTON
:
1341 return clientWidth
- 22
1344 def GetButtonsAreaLength(self
, pageContainer
):
1345 """ Returns the navigation area width. """
1348 style
= pc
.GetParent().GetWindowStyleFlag()
1351 if style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1355 elif style
& FNB_NO_NAV_BUTTONS
and not style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1359 if not style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1363 if style
& FNB_DROPDOWN_TABS_LIST
and not style
& FNB_NO_X_BUTTON
:
1367 if style
& FNB_DROPDOWN_TABS_LIST
and style
& FNB_NO_X_BUTTON
:
1374 def DrawLeftArrow(self
, pageContainer
, dc
):
1375 """ Draw the left navigation arrow. """
1379 style
= pc
.GetParent().GetWindowStyleFlag()
1380 if style
& FNB_NO_NAV_BUTTONS
:
1383 # Make sure that there are pages in the container
1384 if not pc
._pagesInfoVec
:
1387 # Set the bitmap according to the button status
1388 if pc
._nLeftButtonStatus
== FNB_BTN_HOVER
:
1389 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_hilite_xpm
)
1390 elif pc
._nLeftButtonStatus
== FNB_BTN_PRESSED
:
1391 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_pressed_xpm
)
1393 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_xpm
)
1396 # Handle disabled arrow
1397 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_disabled_xpm
)
1399 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
1402 posx
= self
.GetLeftButtonPos(pc
)
1403 dc
.DrawBitmap(self
._leftBgBmp
, posx
, 6)
1405 # Draw the new bitmap
1406 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
1409 def DrawRightArrow(self
, pageContainer
, dc
):
1410 """ Draw the right navigation arrow. """
1414 style
= pc
.GetParent().GetWindowStyleFlag()
1415 if style
& FNB_NO_NAV_BUTTONS
:
1418 # Make sure that there are pages in the container
1419 if not pc
._pagesInfoVec
:
1422 # Set the bitmap according to the button status
1423 if pc
._nRightButtonStatus
== FNB_BTN_HOVER
:
1424 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_hilite_xpm
)
1425 elif pc
._nRightButtonStatus
== FNB_BTN_PRESSED
:
1426 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_pressed_xpm
)
1428 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_xpm
)
1430 # Check if the right most tab is visible, if it is
1431 # don't rotate right anymore
1432 if pc
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1):
1433 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_disabled_xpm
)
1435 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
1438 posx
= self
.GetRightButtonPos(pc
)
1439 dc
.DrawBitmap(self
._rightBgBmp
, posx
, 6)
1441 # Draw the new bitmap
1442 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
1445 def DrawDropDownArrow(self
, pageContainer
, dc
):
1446 """ Draws the drop-down arrow in the navigation area. """
1450 # Check if this style is enabled
1451 style
= pc
.GetParent().GetWindowStyleFlag()
1452 if not style
& FNB_DROPDOWN_TABS_LIST
:
1455 # Make sure that there are pages in the container
1456 if not pc
._pagesInfoVec
:
1459 if pc
._nArrowDownButtonStatus
== FNB_BTN_HOVER
:
1460 downBmp
= wx
.BitmapFromXPMData(down_arrow_hilite_xpm
)
1461 elif pc
._nArrowDownButtonStatus
== FNB_BTN_PRESSED
:
1462 downBmp
= wx
.BitmapFromXPMData(down_arrow_pressed_xpm
)
1464 downBmp
= wx
.BitmapFromXPMData(down_arrow_xpm
)
1466 downBmp
.SetMask(wx
.Mask(downBmp
, MASK_COLOR
))
1469 posx
= self
.GetDropArrowButtonPos(pc
)
1470 dc
.DrawBitmap(self
._rightBgBmp
, posx
, 6)
1472 # Draw the new bitmap
1473 dc
.DrawBitmap(downBmp
, posx
, 6, True)
1476 def DrawX(self
, pageContainer
, dc
):
1477 """ Draw the 'X' navigation button in the navigation area. """
1481 # Check if this style is enabled
1482 style
= pc
.GetParent().GetWindowStyleFlag()
1483 if style
& FNB_NO_X_BUTTON
:
1486 # Make sure that there are pages in the container
1487 if not pc
._pagesInfoVec
:
1490 # Set the bitmap according to the button status
1491 if pc
._nXButtonStatus
== FNB_BTN_HOVER
:
1492 xbmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
1493 elif pc
._nXButtonStatus
== FNB_BTN_PRESSED
:
1494 xbmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
1496 xbmp
= wx
.BitmapFromXPMData(x_button_xpm
)
1498 xbmp
.SetMask(wx
.Mask(xbmp
, MASK_COLOR
))
1501 posx
= self
.GetXPos(pc
)
1502 dc
.DrawBitmap(self
._xBgBmp
, posx
, 6)
1504 # Draw the new bitmap
1505 dc
.DrawBitmap(xbmp
, posx
, 6, True)
1508 def DrawTabX(self
, pageContainer
, dc
, rect
, tabIdx
, btnStatus
):
1509 """ Draws the 'X' in the selected tab. """
1512 if not pc
.HasFlag(FNB_X_ON_TAB
):
1515 # We draw the 'x' on the active tab only
1516 if tabIdx
!= pc
.GetSelection() or tabIdx
< 0:
1519 # Set the bitmap according to the button status
1521 if btnStatus
== FNB_BTN_HOVER
:
1522 xBmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
1523 elif btnStatus
== FNB_BTN_PRESSED
:
1524 xBmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
1526 xBmp
= wx
.BitmapFromXPMData(x_button_xpm
)
1529 xBmp
.SetMask(wx
.Mask(xBmp
, MASK_COLOR
))
1532 dc
.DrawBitmap(self
._tabXBgBmp
, rect
.x
, rect
.y
)
1534 # Draw the new bitmap
1535 dc
.DrawBitmap(xBmp
, rect
.x
, rect
.y
, True)
1538 rr
= wx
.Rect(rect
.x
, rect
.y
, 14, 13)
1539 pc
._pagesInfoVec
[tabIdx
].SetXRect(rr
)
1542 def _GetBitmap(self
, dc
, rect
, bmp
):
1544 mem_dc
= wx
.MemoryDC()
1545 mem_dc
.SelectObject(bmp
)
1546 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1547 mem_dc
.SelectObject(wx
.NullBitmap
)
1551 def DrawTabsLine(self
, pageContainer
, dc
, selTabX1
=-1, selTabX2
=-1):
1552 """ Draws a line over the tabs. """
1556 clntRect
= pc
.GetClientRect()
1557 clientRect3
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
)
1559 if pc
.HasFlag(FNB_FF2
):
1560 if not pc
.HasFlag(FNB_BOTTOM
):
1561 fillColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)
1563 fillColor
= wx
.WHITE
1565 dc
.SetPen(wx
.Pen(fillColor
))
1567 if pc
.HasFlag(FNB_BOTTOM
):
1569 dc
.DrawLine(1, 0, clntRect
.width
-1, 0)
1570 dc
.DrawLine(1, 1, clntRect
.width
-1, 1)
1572 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1573 dc
.DrawLine(1, 2, clntRect
.width
-1, 2)
1575 dc
.SetPen(wx
.Pen(fillColor
))
1576 dc
.DrawLine(selTabX1
+ 2, 2, selTabX2
- 1, 2)
1580 dc
.DrawLine(1, clntRect
.height
, clntRect
.width
-1, clntRect
.height
)
1581 dc
.DrawLine(1, clntRect
.height
-1, clntRect
.width
-1, clntRect
.height
-1)
1583 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1584 dc
.DrawLine(1, clntRect
.height
-2, clntRect
.width
-1, clntRect
.height
-2)
1586 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)))
1587 dc
.DrawLine(selTabX1
+ 2, clntRect
.height
-2, selTabX2
-1, clntRect
.height
-2)
1591 if pc
.HasFlag(FNB_BOTTOM
):
1593 clientRect
= wx
.Rect(0, 2, clntRect
.width
, clntRect
.height
- 2)
1594 clientRect2
= wx
.Rect(0, 1, clntRect
.width
, clntRect
.height
- 1)
1598 clientRect
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 2)
1599 clientRect2
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 1)
1601 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1602 dc
.SetPen(wx
.Pen(pc
.GetSingleLineBorderColour()))
1603 dc
.DrawRectangleRect(clientRect2
)
1604 dc
.DrawRectangleRect(clientRect3
)
1606 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1607 dc
.DrawRectangleRect(clientRect
)
1609 if not pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
1611 dc
.SetPen(wx
.Pen((pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
._tabAreaColor
])[0]))
1612 dc
.DrawLine(0, 0, 0, clientRect
.height
+1)
1614 if pc
.HasFlag(FNB_BOTTOM
):
1616 dc
.DrawLine(0, clientRect
.height
+1, clientRect
.width
, clientRect
.height
+1)
1620 dc
.DrawLine(0, 0, clientRect
.width
, 0)
1622 dc
.DrawLine(clientRect
.width
- 1, 0, clientRect
.width
- 1, clientRect
.height
+1)
1625 def CalcTabWidth(self
, pageContainer
, tabIdx
, tabHeight
):
1626 """ Calculates the width of the input tab. """
1630 dc
.SelectObject(wx
.EmptyBitmap(1,1))
1632 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1633 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1635 if pc
.IsDefaultTabs():
1636 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1638 # Calculate the text length using the bold font, so when selecting a tab
1639 # its width will not change
1640 dc
.SetFont(boldFont
)
1641 width
, pom
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
1643 # Set a minimum size to a tab
1647 tabWidth
= 2*pc
._pParent
.GetPadding() + width
1649 # Style to add a small 'x' button on the top right
1651 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
1652 # The xpm image that contains the 'x' button is 9 pixels
1654 if pc
.HasFlag(FNB_VC8
):
1657 tabWidth
+= pc
._pParent
.GetPadding() + spacer
1659 if pc
.IsDefaultTabs():
1661 tabWidth
+= 2*shapePoints
1663 hasImage
= pc
._ImageList
!= None and pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
1665 # For VC71 style, we only add the icon size (16 pixels)
1668 if not pc
.IsDefaultTabs():
1669 tabWidth
+= 16 + pc
._pParent
.GetPadding()
1672 tabWidth
+= 16 + pc
._pParent
.GetPadding() + shapePoints
/2
1677 def CalcTabHeight(self
, pageContainer
):
1678 """ Calculates the height of the input tab. """
1681 return self
._tabHeight
1685 dc
.SelectObject(wx
.EmptyBitmap(1,1))
1687 # For GTK it seems that we must do this steps in order
1688 # for the tabs will get the proper height on initialization
1689 # on MSW, preforming these steps yields wierd results
1690 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1691 boldFont
= normalFont
1693 if "__WXGTK__" in wx
.PlatformInfo
:
1694 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1695 dc
.SetFont(boldFont
)
1697 height
= dc
.GetCharHeight()
1699 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
1700 if "__WXGTK__" in wx
.PlatformInfo
:
1701 # On GTK the tabs are should be larger
1704 self
._tabHeight
= tabHeight
1709 def DrawTabs(self
, pageContainer
, dc
):
1710 """ Actually draws the tabs in L{FlatNotebook}."""
1713 if "__WXMAC__" in wx
.PlatformInfo
:
1714 # Works well on MSW & GTK, however this lines should be skipped on MAC
1715 if not pc
._pagesInfoVec
or pc
._nFrom
>= len(pc
._pagesInfoVec
):
1719 # Get the text hight
1720 tabHeight
= self
.CalcTabHeight(pageContainer
)
1721 style
= pc
.GetParent().GetWindowStyleFlag()
1723 # Calculate the number of rows required for drawing the tabs
1724 rect
= pc
.GetClientRect()
1725 clientWidth
= rect
.width
1727 # Set the maximum client size
1728 pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
)
1729 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1731 if style
& FNB_VC71
:
1732 backBrush
= wx
.Brush(wx
.Colour(247, 243, 233))
1734 backBrush
= wx
.Brush(pc
._tabAreaColor
)
1736 noselBrush
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
))
1737 selBrush
= wx
.Brush(pc
._activeTabColor
)
1742 dc
.SetTextBackground((style
& FNB_VC71
and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0])
1743 dc
.SetTextForeground(pc
._activeTextColor
)
1744 dc
.SetBrush(backBrush
)
1746 # If border style is set, set the pen to be border pen
1747 if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
1748 dc
.SetPen(borderPen
)
1750 colr
= (pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0]
1751 dc
.SetPen(wx
.Pen(colr
))
1753 if pc
.HasFlag(FNB_FF2
):
1754 lightFactor
= (pc
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0]
1755 PaintStraightGradientBox(dc
, pc
.GetClientRect(), pc
._tabAreaColor
, LightColour(pc
._tabAreaColor
, lightFactor
))
1756 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1758 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
1760 # Take 3 bitmaps for the background for the buttons
1762 mem_dc
= wx
.MemoryDC()
1763 #---------------------------------------
1765 #---------------------------------------
1766 rect
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14)
1767 mem_dc
.SelectObject(self
._xBgBmp
)
1768 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1769 mem_dc
.SelectObject(wx
.NullBitmap
)
1771 #---------------------------------------
1773 #---------------------------------------
1774 rect
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14)
1775 mem_dc
.SelectObject(self
._rightBgBmp
)
1776 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1777 mem_dc
.SelectObject(wx
.NullBitmap
)
1779 #---------------------------------------
1781 #---------------------------------------
1782 rect
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14)
1783 mem_dc
.SelectObject(self
._leftBgBmp
)
1784 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1785 mem_dc
.SelectObject(wx
.NullBitmap
)
1787 # We always draw the bottom/upper line of the tabs
1788 # regradless the style
1789 dc
.SetPen(borderPen
)
1791 if not pc
.HasFlag(FNB_FF2
):
1792 self
.DrawTabsLine(pc
, dc
)
1795 dc
.SetPen(borderPen
)
1797 if pc
.HasFlag(FNB_VC71
):
1799 greyLineYVal
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [size
.y
- 2])[0]
1800 whiteLineYVal
= (pc
.HasFlag(FNB_BOTTOM
) and [3] or [size
.y
- 3])[0]
1802 pen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1805 # Draw thik grey line between the windows area and
1807 for num
in xrange(3):
1808 dc
.DrawLine(0, greyLineYVal
+ num
, size
.x
, greyLineYVal
+ num
)
1810 wbPen
= (pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK_PEN
] or [wx
.WHITE_PEN
])[0]
1812 dc
.DrawLine(1, whiteLineYVal
, size
.x
- 1, whiteLineYVal
)
1815 dc
.SetPen(borderPen
)
1818 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1819 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1820 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1821 dc
.SetFont(boldFont
)
1823 posx
= pc
._pParent
.GetPadding()
1825 # Update all the tabs from 0 to 'pc._nFrom' to be non visible
1826 for i
in xrange(pc
._nFrom
):
1828 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
1829 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1833 #----------------------------------------------------------
1834 # Go over and draw the visible tabs
1835 #----------------------------------------------------------
1837 for i
in xrange(pc
._nFrom
, len(pc
._pagesInfoVec
)):
1839 dc
.SetPen(borderPen
)
1841 if not pc
.HasFlag(FNB_FF2
):
1842 dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0])
1844 # Now set the font to the correct font
1845 dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0])
1847 # Add the padding to the tab width
1849 # +-----------------------------------------------------------+
1850 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
1851 # +-----------------------------------------------------------+
1852 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
1854 # Check if we can draw more
1855 if posx
+ tabWidth
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
1860 # By default we clean the tab region
1861 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1863 # Clean the 'x' buttn on the tab.
1864 # A 'Clean' rectangle, is a rectangle with width or height
1865 # with values lower than or equal to 0
1866 pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
1868 # Draw the tab (border, text, image & 'x' on tab)
1869 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
)
1871 if pc
.GetSelection() == i
:
1873 x2
= posx
+ tabWidth
+ 2
1875 # Restore the text forground
1876 dc
.SetTextForeground(pc
._activeTextColor
)
1878 # Update the tab position & size
1879 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0]
1881 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, posy
))
1882 pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
1883 self
.DrawFocusRectangle(dc
, pc
, pc
._pagesInfoVec
[i
])
1887 # Update all tabs that can not fit into the screen as non-visible
1888 for i
in xrange(count
, len(pc
._pagesInfoVec
)):
1889 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
1890 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1892 # Draw the left/right/close buttons
1894 self
.DrawLeftArrow(pc
, dc
)
1895 self
.DrawRightArrow(pc
, dc
)
1897 self
.DrawDropDownArrow(pc
, dc
)
1899 if pc
.HasFlag(FNB_FF2
):
1900 self
.DrawTabsLine(pc
, dc
, x1
, x2
)
1903 def DrawFocusRectangle(self
, dc
, pageContainer
, page
):
1904 """ Draws a focus rectangle like the native Notebooks. """
1906 if not page
._hasFocus
:
1909 tabPos
= page
.GetPosition()
1910 if pageContainer
.GetParent().GetWindowStyleFlag() & FNB_VC8
:
1911 vc8ShapeLen
= self
.CalcTabHeight(pageContainer
) - VERTICAL_BORDER_PADDING
- 2
1912 tabPos
.x
+= vc8ShapeLen
1914 rect
= wx
.RectPS(tabPos
, page
.GetSize())
1915 rect
= wx
.Rect(rect
.x
+2, rect
.y
+2, rect
.width
-4, rect
.height
-8)
1917 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1918 dc
.SetPen(self
._focusPen
)
1919 dc
.DrawRoundedRectangleRect(rect
, 2)
1922 def DrawDragHint(self
, pc
, tabIdx
):
1924 Draws tab drag hint, the default implementation is to do nothing.
1925 You can override this function to provide a nice feedback to user.
1931 def NumberTabsCanFit(self
, pageContainer
, fr
=-1):
1935 rect
= pc
.GetClientRect()
1936 clientWidth
= rect
.width
1940 tabHeight
= self
.CalcTabHeight(pageContainer
)
1942 # The drawing starts from posx
1943 posx
= pc
._pParent
.GetPadding()
1948 for i
in xrange(fr
, len(pc
._pagesInfoVec
)):
1950 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
1951 if posx
+ tabWidth
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
1954 # Add a result to the returned vector
1955 tabRect
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
)
1956 vTabInfo
.append(tabRect
)
1959 posx
+= tabWidth
+ FNB_HEIGHT_SPACER
1964 # ---------------------------------------------------------------------------- #
1965 # Class FNBRendererMgr
1966 # A manager that handles all the renderers defined below and calls the
1967 # appropriate one when drawing is needed
1968 # ---------------------------------------------------------------------------- #
1970 class FNBRendererMgr
:
1972 This class represents a manager that handles all the 4 renderers defined
1973 and calls the appropriate one when drawing is needed.
1977 """ Default class constructor. """
1979 # register renderers
1981 self
._renderers
= {}
1982 self
._renderers
.update({-1: FNBRendererDefault()}
)
1983 self
._renderers
.update({FNB_VC71: FNBRendererVC71()}
)
1984 self
._renderers
.update({FNB_FANCY_TABS: FNBRendererFancy()}
)
1985 self
._renderers
.update({FNB_VC8: FNBRendererVC8()}
)
1986 self
._renderers
.update({FNB_FF2: FNBRendererFirefox2()}
)
1989 def GetRenderer(self
, style
):
1990 """ Returns the current renderer based on the style selected. """
1992 if style
& FNB_VC71
:
1993 return self
._renderers
[FNB_VC71
]
1995 if style
& FNB_FANCY_TABS
:
1996 return self
._renderers
[FNB_FANCY_TABS
]
1999 return self
._renderers
[FNB_VC8
]
2002 return self
._renderers
[FNB_FF2
]
2004 # the default is to return the default renderer
2005 return self
._renderers
[-1]
2008 #------------------------------------------
2010 #------------------------------------------
2012 class FNBRendererDefault(FNBRenderer
):
2014 This class handles the drawing of tabs using the I{Standard} renderer.
2018 """ Default class constructor. """
2020 FNBRenderer
.__init
__(self
)
2023 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2024 """ Draws a tab using the I{Standard} style. """
2027 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2030 tabPoints
= [wx
.Point() for ii
in xrange(7)]
2031 tabPoints
[0].x
= posx
2032 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2034 tabPoints
[1].x
= int(posx
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2035 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2037 tabPoints
[2].x
= tabPoints
[1].x
+2
2038 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2040 tabPoints
[3].x
= int(posx
+tabWidth
-(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))-2
2041 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2043 tabPoints
[4].x
= tabPoints
[3].x
+2
2044 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2046 tabPoints
[5].x
= int(tabPoints
[4].x
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2047 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2049 tabPoints
[6].x
= tabPoints
[0].x
2050 tabPoints
[6].y
= tabPoints
[0].y
2052 if tabIdx
== pc
.GetSelection():
2054 # Draw the tab as rounded rectangle
2055 dc
.DrawPolygon(tabPoints
)
2059 if tabIdx
!= pc
.GetSelection() - 1:
2061 # Draw a vertical line to the right of the text
2062 pt1x
= tabPoints
[5].x
2063 pt1y
= (pc
.HasFlag(FNB_BOTTOM
) and [4] or [tabHeight
- 6])[0]
2064 pt2x
= tabPoints
[5].x
2065 pt2y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 4] or [4])[0]
2066 dc
.DrawLine(pt1x
, pt1y
, pt2x
, pt2y
)
2068 if tabIdx
== pc
.GetSelection():
2070 savePen
= dc
.GetPen()
2071 whitePen
= wx
.Pen(wx
.WHITE
)
2072 whitePen
.SetWidth(1)
2075 secPt
= wx
.Point(tabPoints
[5].x
+ 1, tabPoints
[5].y
)
2076 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, secPt
.x
, secPt
.y
)
2081 # -----------------------------------
2082 # Text and image drawing
2083 # -----------------------------------
2085 # Text drawing offset from the left border of the
2088 # The width of the images are 16 pixels
2089 padding
= pc
.GetParent().GetPadding()
2090 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2091 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2092 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2095 textOffset
= 2*pc
._pParent
._nPadding
+ 16 + shapePoints
/2
2097 textOffset
= pc
._pParent
._nPadding
+ shapePoints
/2
2101 if tabIdx
!= pc
.GetSelection():
2103 # Set the text background to be like the vertical lines
2104 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2108 imageXOffset
= textOffset
- 16 - padding
2109 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2110 posx
+ imageXOffset
, imageYCoord
,
2111 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2113 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2115 # draw 'x' on tab (if enabled)
2116 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2118 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2119 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2121 # take a bitmap from the position of the 'x' button (the x on tab button)
2122 # this bitmap will be used later to delete old buttons
2123 tabCloseButtonYCoord
= imageYCoord
2124 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2125 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2128 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2131 #------------------------------------------
2133 #------------------------------------------
2134 class FNBRendererFirefox2(FNBRenderer
):
2136 This class handles the drawing of tabs using the I{Firefox 2} renderer.
2140 """ Default class constructor. """
2142 FNBRenderer
.__init
__(self
)
2145 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2146 """ Draws a tab using the I{Firefox 2} style. """
2148 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2151 tabPoints
= [wx
.Point() for indx
in xrange(7)]
2152 tabPoints
[0].x
= posx
+ 2
2153 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2155 tabPoints
[1].x
= tabPoints
[0].x
2156 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2158 tabPoints
[2].x
= tabPoints
[1].x
+2
2159 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2161 tabPoints
[3].x
= posx
+ tabWidth
- 2
2162 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2164 tabPoints
[4].x
= tabPoints
[3].x
+ 2
2165 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2167 tabPoints
[5].x
= tabPoints
[4].x
2168 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2170 tabPoints
[6].x
= tabPoints
[0].x
2171 tabPoints
[6].y
= tabPoints
[0].y
2173 #------------------------------------
2174 # Paint the tab with gradient
2175 #------------------------------------
2176 rr
= wx
.RectPP(tabPoints
[2], tabPoints
[5])
2177 DrawButton(dc
, rr
, pc
.GetSelection() == tabIdx
, not pc
.HasFlag(FNB_BOTTOM
))
2179 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2180 dc
.SetPen(borderPen
)
2182 # Draw the tab as rounded rectangle
2183 dc
.DrawPolygon(tabPoints
)
2185 # -----------------------------------
2186 # Text and image drawing
2187 # -----------------------------------
2189 # The width of the images are 16 pixels
2190 padding
= pc
.GetParent().GetPadding()
2191 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2192 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2193 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2196 textOffset
= 2*padding
+ 16 + shapePoints
/2
2198 textOffset
= padding
+ shapePoints
/2
2202 if tabIdx
!= pc
.GetSelection():
2204 # Set the text background to be like the vertical lines
2205 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2208 imageXOffset
= textOffset
- 16 - padding
2209 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2210 posx
+ imageXOffset
, imageYCoord
,
2211 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2213 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2215 # draw 'x' on tab (if enabled)
2216 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2218 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2219 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2221 # take a bitmap from the position of the 'x' button (the x on tab button)
2222 # this bitmap will be used later to delete old buttons
2223 tabCloseButtonYCoord
= imageYCoord
2224 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2225 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2228 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2231 #------------------------------------------------------------------
2233 #------------------------------------------------------------------
2235 class FNBRendererVC71(FNBRenderer
):
2237 This class handles the drawing of tabs using the I{VC71} renderer.
2241 """ Default class constructor. """
2243 FNBRenderer
.__init
__(self
)
2246 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2247 """ Draws a tab using the I{VC71} style. """
2249 # Visual studio 7.1 style
2250 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2253 dc
.SetPen((tabIdx
== pc
.GetSelection() and [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [borderPen
])[0])
2254 dc
.SetBrush((tabIdx
== pc
.GetSelection() and [wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [wx
.Brush(wx
.Colour(247, 243, 233))])[0])
2256 if tabIdx
== pc
.GetSelection():
2258 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0]
2259 tabH
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 5] or [tabHeight
- 3])[0]
2260 dc
.DrawRectangle(posx
, posy
, tabWidth
, tabH
)
2262 # Draw a black line on the left side of the
2264 dc
.SetPen(wx
.BLACK_PEN
)
2266 blackLineY1
= VERTICAL_BORDER_PADDING
2268 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
2270 # To give the tab more 3D look we do the following
2271 # Incase the tab is on top,
2272 # Draw a thik white line on topof the rectangle
2273 # Otherwise, draw a thin (1 pixel) black line at the bottom
2275 pen
= wx
.Pen((pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK
] or [wx
.WHITE
])[0])
2277 whiteLinePosY
= (pc
.HasFlag(FNB_BOTTOM
) and [blackLineY2
] or [VERTICAL_BORDER_PADDING
])[0]
2278 dc
.DrawLine(posx
, whiteLinePosY
, posx
+ tabWidth
+ 1, whiteLinePosY
)
2280 # Draw a white vertical line to the left of the tab
2281 dc
.SetPen(wx
.WHITE_PEN
)
2282 if not pc
.HasFlag(FNB_BOTTOM
):
2285 dc
.DrawLine(posx
, blackLineY1
, posx
, blackLineY2
)
2289 # We dont draw a rectangle for non selected tabs, but only
2290 # vertical line on the left
2292 blackLineY1
= (pc
.HasFlag(FNB_BOTTOM
) and [VERTICAL_BORDER_PADDING
+ 2] or [VERTICAL_BORDER_PADDING
+ 1])[0]
2293 blackLineY2
= pc
.GetSize().y
- 5
2294 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
2296 # -----------------------------------
2297 # Text and image drawing
2298 # -----------------------------------
2300 # Text drawing offset from the left border of the
2303 # The width of the images are 16 pixels
2304 padding
= pc
.GetParent().GetPadding()
2305 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2306 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [5] or [8])[0]
2309 textOffset
= 2*pc
._pParent
._nPadding
+ 16
2311 textOffset
= pc
._pParent
._nPadding
2313 if tabIdx
!= pc
.GetSelection():
2315 # Set the text background to be like the vertical lines
2316 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2320 imageXOffset
= textOffset
- 16 - padding
2321 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2322 posx
+ imageXOffset
, imageYCoord
,
2323 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2325 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2327 # draw 'x' on tab (if enabled)
2328 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2330 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2331 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2333 # take a bitmap from the position of the 'x' button (the x on tab button)
2334 # this bitmap will be used later to delete old buttons
2335 tabCloseButtonYCoord
= imageYCoord
2336 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2337 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2340 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2343 #------------------------------------------------------------------
2345 #------------------------------------------------------------------
2347 class FNBRendererFancy(FNBRenderer
):
2349 This class handles the drawing of tabs using the I{Fancy} renderer.
2353 """ Default class constructor. """
2355 FNBRenderer
.__init
__(self
)
2358 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2359 """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
2361 # Fancy tabs - like with VC71 but with the following differences:
2362 # - The Selected tab is colored with gradient color
2363 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2366 pen
= (tabIdx
== pc
.GetSelection() and [wx
.Pen(pc
._pParent
.GetBorderColour())] or [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))])[0]
2368 if tabIdx
== pc
.GetSelection():
2370 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [VERTICAL_BORDER_PADDING
])[0]
2373 rect
= wx
.Rect(posx
, posy
, tabWidth
, th
)
2375 col2
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourTo()] or [pc
._pParent
.GetGradientColourFrom()])[0]
2376 col1
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourFrom()] or [pc
._pParent
.GetGradientColourTo()])[0]
2378 PaintStraightGradientBox(dc
, rect
, col1
, col2
)
2379 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2381 dc
.DrawRectangleRect(rect
)
2383 # erase the bottom/top line of the rectangle
2384 dc
.SetPen(wx
.Pen(pc
._pParent
.GetGradientColourFrom()))
2385 if pc
.HasFlag(FNB_BOTTOM
):
2386 dc
.DrawLine(rect
.x
, 2, rect
.x
+ rect
.width
, 2)
2388 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
, rect
.y
+ rect
.height
- 1)
2392 # We dont draw a rectangle for non selected tabs, but only
2393 # vertical line on the left
2394 dc
.SetPen(borderPen
)
2395 dc
.DrawLine(posx
+ tabWidth
, VERTICAL_BORDER_PADDING
+ 3, posx
+ tabWidth
, tabHeight
- 4)
2398 # -----------------------------------
2399 # Text and image drawing
2400 # -----------------------------------
2402 # Text drawing offset from the left border of the
2405 # The width of the images are 16 pixels
2406 padding
= pc
.GetParent().GetPadding()
2407 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2408 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2411 textOffset
= 2*pc
._pParent
._nPadding
+ 16
2413 textOffset
= pc
._pParent
._nPadding
2417 if tabIdx
!= pc
.GetSelection():
2419 # Set the text background to be like the vertical lines
2420 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2424 imageXOffset
= textOffset
- 16 - padding
2425 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2426 posx
+ imageXOffset
, imageYCoord
,
2427 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2429 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2431 # draw 'x' on tab (if enabled)
2432 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2434 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2435 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2437 # take a bitmap from the position of the 'x' button (the x on tab button)
2438 # this bitmap will be used later to delete old buttons
2439 tabCloseButtonYCoord
= imageYCoord
2440 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2441 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2444 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2447 #------------------------------------------------------------------
2448 # Visual studio 2005 (VS8)
2449 #------------------------------------------------------------------
2450 class FNBRendererVC8(FNBRenderer
):
2452 This class handles the drawing of tabs using the I{VC8} renderer.
2456 """ Default class constructor. """
2458 FNBRenderer
.__init
__(self
)
2463 def DrawTabs(self
, pageContainer
, dc
):
2464 """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
2468 if "__WXMAC__" in wx
.PlatformInfo
:
2469 # Works well on MSW & GTK, however this lines should be skipped on MAC
2470 if not pc
._pagesInfoVec
or pc
._nFrom
>= len(pc
._pagesInfoVec
):
2474 # Get the text hight
2475 tabHeight
= self
.CalcTabHeight(pageContainer
)
2477 # Set the font for measuring the tab height
2478 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2479 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2480 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2482 # Calculate the number of rows required for drawing the tabs
2483 rect
= pc
.GetClientRect()
2485 # Set the maximum client size
2486 pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
)
2487 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2490 backBrush
= wx
.Brush(pc
._tabAreaColor
)
2491 noselBrush
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
))
2492 selBrush
= wx
.Brush(pc
._activeTabColor
)
2496 dc
.SetTextBackground(pc
.GetBackgroundColour())
2497 dc
.SetTextForeground(pc
._activeTextColor
)
2499 # If border style is set, set the pen to be border pen
2500 if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
2501 dc
.SetPen(borderPen
)
2503 dc
.SetPen(wx
.TRANSPARENT_PEN
)
2505 lightFactor
= (pc
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0]
2507 # For VC8 style, we color the tab area in gradient coloring
2508 lightcolour
= LightColour(pc
._tabAreaColor
, lightFactor
)
2509 PaintStraightGradientBox(dc
, pc
.GetClientRect(), pc
._tabAreaColor
, lightcolour
)
2511 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2512 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
2514 # Take 3 bitmaps for the background for the buttons
2516 mem_dc
= wx
.MemoryDC()
2517 #---------------------------------------
2519 #---------------------------------------
2520 rect
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14)
2521 mem_dc
.SelectObject(self
._xBgBmp
)
2522 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2523 mem_dc
.SelectObject(wx
.NullBitmap
)
2525 #---------------------------------------
2527 #---------------------------------------
2528 rect
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14)
2529 mem_dc
.SelectObject(self
._rightBgBmp
)
2530 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2531 mem_dc
.SelectObject(wx
.NullBitmap
)
2533 #---------------------------------------
2535 #---------------------------------------
2536 rect
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14)
2537 mem_dc
.SelectObject(self
._leftBgBmp
)
2538 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2539 mem_dc
.SelectObject(wx
.NullBitmap
)
2541 # We always draw the bottom/upper line of the tabs
2542 # regradless the style
2543 dc
.SetPen(borderPen
)
2544 self
.DrawTabsLine(pc
, dc
)
2547 dc
.SetPen(borderPen
)
2550 dc
.SetFont(boldFont
)
2552 # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
2553 for i
in xrange(pc
._nFrom
):
2555 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
2556 pc
._pagesInfoVec
[i
].GetRegion().Clear()
2558 # Draw the visible tabs, in VC8 style, we draw them from right to left
2559 vTabsInfo
= self
.NumberTabsCanFit(pc
)
2565 for cur
in xrange(len(vTabsInfo
)-1, -1, -1):
2567 # 'i' points to the index of the currently drawn tab
2568 # in pc.GetPageInfoVector() vector
2570 dc
.SetPen(borderPen
)
2571 dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0])
2573 # Now set the font to the correct font
2574 dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0])
2576 # Add the padding to the tab width
2578 # +-----------------------------------------------------------+
2579 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
2580 # +-----------------------------------------------------------+
2582 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
2583 posx
= vTabsInfo
[cur
].x
2585 # By default we clean the tab region
2586 # incase we use the VC8 style which requires
2587 # the region, it will be filled by the function
2589 pc
._pagesInfoVec
[i
].GetRegion().Clear()
2591 # Clean the 'x' buttn on the tab
2592 # 'Clean' rectanlge is a rectangle with width or height
2593 # with values lower than or equal to 0
2594 pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
2597 # Incase we are drawing the active tab
2598 # we need to redraw so it will appear on top
2601 # when using the vc8 style, we keep the position of the active tab so we will draw it again later
2602 if i
== pc
.GetSelection() and pc
.HasFlag(FNB_VC8
):
2604 activeTabPosx
= posx
2605 activeTabWidth
= tabWidth
2606 activeTabHeight
= tabHeight
2610 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
)
2612 # Restore the text forground
2613 dc
.SetTextForeground(pc
._activeTextColor
)
2615 # Update the tab position & size
2616 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, VERTICAL_BORDER_PADDING
))
2617 pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
2619 # Incase we are in VC8 style, redraw the active tab (incase it is visible)
2620 if pc
.GetSelection() >= pc
._nFrom
and pc
.GetSelection() < pc
._nFrom
+ len(vTabsInfo
):
2622 self
.DrawTab(pc
, dc
, activeTabPosx
, pc
.GetSelection(), activeTabWidth
, activeTabHeight
, pc
._nTabXButtonStatus
)
2624 # Update all tabs that can not fit into the screen as non-visible
2625 for xx
in xrange(pc
._nFrom
+ len(vTabsInfo
), len(pc
._pagesInfoVec
)):
2627 pc
._pagesInfoVec
[xx
].SetPosition(wx
.Point(-1, -1))
2628 pc
._pagesInfoVec
[xx
].GetRegion().Clear()
2630 # Draw the left/right/close buttons
2632 self
.DrawLeftArrow(pc
, dc
)
2633 self
.DrawRightArrow(pc
, dc
)
2635 self
.DrawDropDownArrow(pc
, dc
)
2638 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2639 """ Draws a tab using VC8 style. """
2642 borderPen
= wx
.Pen(pc
._pParent
.GetBorderColour())
2643 tabPoints
= [wx
.Point() for ii
in xrange(8)]
2645 # If we draw the first tab or the active tab,
2646 # we draw a full tab, else we draw a truncated tab
2657 tabPoints
[0].x
= (pc
.HasFlag(FNB_BOTTOM
) and [posx
] or [posx
+self
._factor
])[0]
2658 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 3])[0]
2660 tabPoints
[1].x
= tabPoints
[0].x
+ tabHeight
- VERTICAL_BORDER_PADDING
- 3 - self
._factor
2661 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2663 tabPoints
[2].x
= tabPoints
[1].x
+ 4
2664 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2666 tabPoints
[3].x
= tabPoints
[2].x
+ tabWidth
- 2
2667 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2669 tabPoints
[4].x
= tabPoints
[3].x
+ 1
2670 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabPoints
[3].y
- 1] or [tabPoints
[3].y
+ 1])[0]
2672 tabPoints
[5].x
= tabPoints
[4].x
+ 1
2673 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [(tabPoints
[4].y
- 1)] or [tabPoints
[4].y
+ 1])[0]
2675 tabPoints
[6].x
= tabPoints
[2].x
+ tabWidth
2676 tabPoints
[6].y
= tabPoints
[0].y
2678 tabPoints
[7].x
= tabPoints
[0].x
2679 tabPoints
[7].y
= tabPoints
[0].y
2681 pc
._pagesInfoVec
[tabIdx
].SetRegion(tabPoints
)
2685 dc
.SetBrush(wx
.Brush((tabIdx
== pc
.GetSelection() and [pc
._activeTabColor
] or [pc
._colorTo
])[0]))
2686 dc
.SetPen(wx
.Pen((tabIdx
== pc
.GetSelection() and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0]))
2687 dc
.DrawPolygon(tabPoints
)
2691 rect
= pc
.GetClientRect()
2693 if tabIdx
!= pc
.GetSelection() and not pc
.HasFlag(FNB_BOTTOM
):
2696 dc
.SetPen(wx
.Pen(pc
._pParent
.GetBorderColour()))
2698 curPen
= dc
.GetPen()
2701 dc
.DrawLine(posx
, lineY
, posx
+rect
.width
, lineY
)
2703 # Incase we are drawing the selected tab, we draw the border of it as well
2704 # but without the bottom (upper line incase of wxBOTTOM)
2705 if tabIdx
== pc
.GetSelection():
2707 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2708 dc
.SetPen(borderPen
)
2709 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2710 dc
.DrawPolygon(tabPoints
)
2712 # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
2713 dc
.SetPen(wx
.WHITE_PEN
)
2714 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, tabPoints
[6].x
, tabPoints
[6].y
)
2716 self
.FillVC8GradientColour(pc
, dc
, tabPoints
, tabIdx
== pc
.GetSelection(), tabIdx
)
2718 # Draw a thin line to the right of the non-selected tab
2719 if tabIdx
!= pc
.GetSelection():
2721 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)))
2722 dc
.DrawLine(tabPoints
[4].x
-1, tabPoints
[4].y
, tabPoints
[5].x
-1, tabPoints
[5].y
)
2723 dc
.DrawLine(tabPoints
[5].x
-1, tabPoints
[5].y
, tabPoints
[6].x
-1, tabPoints
[6].y
)
2725 # Text drawing offset from the left border of the
2728 # The width of the images are 16 pixels
2729 vc8ShapeLen
= tabHeight
- VERTICAL_BORDER_PADDING
- 2
2730 if pc
.TabHasImage(tabIdx
):
2731 textOffset
= 2*pc
._pParent
.GetPadding() + 16 + vc8ShapeLen
2733 textOffset
= pc
._pParent
.GetPadding() + vc8ShapeLen
2735 # Draw the image for the tab if any
2736 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2738 if pc
.TabHasImage(tabIdx
):
2740 imageXOffset
= textOffset
- 16 - pc
._pParent
.GetPadding()
2741 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2742 posx
+ imageXOffset
, imageYCoord
,
2743 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2745 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2747 # if selected tab, draw text in bold
2748 if tabIdx
== pc
.GetSelection():
2749 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2751 dc
.SetFont(boldFont
)
2752 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2754 # draw 'x' on tab (if enabled)
2755 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2757 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2758 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2760 # take a bitmap from the position of the 'x' button (the x on tab button)
2761 # this bitmap will be used later to delete old buttons
2762 tabCloseButtonYCoord
= imageYCoord
2763 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2764 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2766 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2768 self
.DrawFocusRectangle(dc
, pc
, pc
._pagesInfoVec
[tabIdx
])
2771 def FillVC8GradientColour(self
, pageContainer
, dc
, tabPoints
, bSelectedTab
, tabIdx
):
2772 """ Fills a tab with a gradient shading. """
2774 # calculate gradient coefficients
2779 pc
._colorTo
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 0)
2780 pc
._colorFrom
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 60)
2782 col2
= pc
._pParent
.GetGradientColourTo()
2783 col1
= pc
._pParent
.GetGradientColourFrom()
2785 # If colorful tabs style is set, override the tab color
2786 if pc
.HasFlag(FNB_COLORFUL_TABS
):
2788 if not pc
._pagesInfoVec
[tabIdx
].GetColour():
2790 # First time, generate color, and keep it in the vector
2791 tabColor
= RandomColour()
2792 pc
._pagesInfoVec
[tabIdx
].SetColour(tabColor
)
2794 if pc
.HasFlag(FNB_BOTTOM
):
2796 col2
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50)
2797 col1
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80)
2801 col1
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50)
2802 col2
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80)
2804 size
= abs(tabPoints
[2].y
- tabPoints
[0].y
) - 1
2806 rf
, gf
, bf
= 0, 0, 0
2807 rstep
= float(col2
.Red() - col1
.Red())/float(size
)
2808 gstep
= float(col2
.Green() - col1
.Green())/float(size
)
2809 bstep
= float(col2
.Blue() - col1
.Blue())/float(size
)
2813 # If we are drawing the selected tab, we need also to draw a line
2814 # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
2815 # by drawing the rectangle with transparent brush
2816 # the line under the selected tab will be deleted by the drwaing loop
2818 self
.DrawTabsLine(pc
, dc
)
2822 if pc
.HasFlag(FNB_BOTTOM
):
2824 if y
> tabPoints
[0].y
+ size
:
2829 if y
< tabPoints
[0].y
- size
:
2832 currCol
= wx
.Colour(col1
.Red() + rf
, col1
.Green() + gf
, col1
.Blue() + bf
)
2834 dc
.SetPen((bSelectedTab
and [wx
.Pen(pc
._activeTabColor
)] or [wx
.Pen(currCol
)])[0])
2835 startX
= self
.GetStartX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())
2836 endX
= self
.GetEndX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())
2837 dc
.DrawLine(startX
, y
, endX
, y
)
2839 # Draw the border using the 'edge' point
2840 dc
.SetPen(wx
.Pen((bSelectedTab
and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0]))
2842 dc
.DrawPoint(startX
, y
)
2843 dc
.DrawPoint(endX
, y
)
2845 # Progress the color
2850 if pc
.HasFlag(FNB_BOTTOM
):
2856 def GetStartX(self
, tabPoints
, y
, style
):
2857 """ Returns the x start position of a tab. """
2859 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
2861 # We check the 3 points to the left
2863 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
2870 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
+1].y
:
2873 x2
= tabPoints
[i
+1].x
2875 y2
= tabPoints
[i
+1].y
2883 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
+1].y
:
2886 x2
= tabPoints
[i
+1].x
2888 y2
= tabPoints
[i
+1].y
2893 return tabPoints
[2].x
2895 # According to the equation y = ax + b => x = (y-b)/a
2896 # We know the first 2 points
2901 a
= (y2
- y1
)/(x2
- x1
)
2903 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
2913 def GetEndX(self
, tabPoints
, y
, style
):
2914 """ Returns the x end position of a tab. """
2916 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
2918 # We check the 3 points to the left
2919 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
2924 for i
in xrange(7, 3, -1):
2926 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
-1].y
:
2929 x2
= tabPoints
[i
-1].x
2931 y2
= tabPoints
[i
-1].y
2937 for i
in xrange(7, 3, -1):
2939 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
-1].y
:
2942 x2
= tabPoints
[i
-1].x
2944 y2
= tabPoints
[i
-1].y
2949 return tabPoints
[3].x
2951 # According to the equation y = ax + b => x = (y-b)/a
2952 # We know the first 2 points
2958 a
= (y2
- y1
)/(x2
- x1
)
2959 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
2969 def NumberTabsCanFit(self
, pageContainer
, fr
=-1):
2970 """ Returns the number of tabs that can fit in the visible area. """
2974 rect
= pc
.GetClientRect()
2975 clientWidth
= rect
.width
2979 tabHeight
= self
.CalcTabHeight(pageContainer
)
2981 # The drawing starts from posx
2982 posx
= pc
._pParent
.GetPadding()
2987 for i
in xrange(fr
, len(pc
._pagesInfoVec
)):
2989 vc8glitch
= tabHeight
+ FNB_HEIGHT_SPACER
2990 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
2992 if posx
+ tabWidth
+ vc8glitch
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
2995 # Add a result to the returned vector
2996 tabRect
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
)
2997 vTabInfo
.append(tabRect
)
3000 posx
+= tabWidth
+ FNB_HEIGHT_SPACER
3005 # ---------------------------------------------------------------------------- #
3006 # Class FlatNotebook
3007 # ---------------------------------------------------------------------------- #
3009 class FlatNotebook(wx
.PyPanel
):
3011 Display one or more windows in a notebook.
3014 - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active
3015 page in the notebook is changing
3016 - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active
3017 page in the notebook has changed
3018 - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the
3020 - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the
3021 notebook has been closed
3022 - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
3023 clicks a tab in the notebook with the right mouse
3027 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
3028 style
=0, name
="FlatNotebook"):
3030 Default class constructor.
3032 All the parameters are as in wxPython class construction, except the
3033 'style': this can be assigned to whatever combination of FNB_* styles.
3037 self
._bForceSelection
= False
3040 style |
= wx
.TAB_TRAVERSAL
3043 self
._popupWin
= None
3045 wx
.PyPanel
.__init
__(self
, parent
, id, pos
, size
, style
)
3047 self
._pages
= PageContainer(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.DefaultSize
, style
)
3049 self
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
3055 """ Initializes all the class attributes. """
3057 self
._pages
._colorBorder
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
3059 self
._mainSizer
= wx
.BoxSizer(wx
.VERTICAL
)
3060 self
.SetSizer(self
._mainSizer
)
3062 # The child panels will inherit this bg color, so leave it at the default value
3063 #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
3065 # Set default page height
3066 dc
= wx
.ClientDC(self
)
3068 if "__WXGTK__" in wx
.PlatformInfo
:
3069 # For GTK it seems that we must do this steps in order
3070 # for the tabs will get the proper height on initialization
3071 # on MSW, preforming these steps yields wierd results
3072 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3073 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
3074 dc
.SetFont(boldFont
)
3076 height
= dc
.GetCharHeight()
3078 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
3080 if "__WXGTK__" in wx
.PlatformInfo
:
3083 self
._pages
.SetSizeHints(-1, tabHeight
)
3084 # Add the tab container to the sizer
3085 self
._mainSizer
.Insert(0, self
._pages
, 0, wx
.EXPAND
)
3086 self
._mainSizer
.Layout()
3088 self
._pages
._nFrom
= self
._nFrom
3089 self
._pDropTarget
= FNBDropTarget(self
)
3090 self
.SetDropTarget(self
._pDropTarget
)
3093 def DoGetBestSize(self
):
3094 """ Overrides DoGetBestSize to handle sizers nicely. """
3096 if not self
._windows
:
3097 # Something is better than nothing... no pages!
3098 return wx
.Size(20, 20)
3100 maxWidth
= maxHeight
= 0
3101 tabHeight
= self
.GetPageBestSize().height
3103 for win
in self
._windows
:
3104 # Loop over all the windows to get their best size
3105 width
, height
= win
.GetBestSize()
3106 maxWidth
, maxHeight
= max(maxWidth
, width
), max(maxHeight
, height
)
3108 return wx
.Size(maxWidth
, maxHeight
+tabHeight
)
3111 def SetActiveTabTextColour(self
, textColour
):
3112 """ Sets the text colour for the active tab. """
3114 self
._pages
._activeTextColor
= textColour
3117 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
3118 """ Handles the drop action from a DND operation. """
3120 return self
._pages
.OnDropTarget(x
, y
, nTabPage
, wnd_oldContainer
)
3123 def GetPreviousSelection(self
):
3124 """ Returns the previous selection. """
3126 return self
._pages
._iPreviousActivePage
3129 def AddPage(self
, page
, text
, select
=True, imageId
=-1):
3131 Add a page to the L{FlatNotebook}.
3133 @param page: Specifies the new page.
3134 @param text: Specifies the text for the new page.
3135 @param select: Specifies whether the page should be selected.
3136 @param imageId: Specifies the optional image index for the new page.
3139 True if successful, False otherwise.
3146 # reparent the window to us
3150 bSelected
= select
or len(self
._windows
) == 0
3156 # Check for selection and send events
3157 oldSelection
= self
._pages
._iActivePage
3158 tabIdx
= len(self
._windows
)
3160 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId())
3161 event
.SetSelection(tabIdx
)
3162 event
.SetOldSelection(oldSelection
)
3163 event
.SetEventObject(self
)
3165 if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed() or len(self
._windows
) == 0:
3168 curSel
= self
._pages
.GetSelection()
3170 if not self
._pages
.IsShown():
3173 self
._pages
.AddPage(text
, bSelected
, imageId
)
3174 self
._windows
.append(page
)
3178 # Check if a new selection was made
3183 # Remove the window from the main sizer
3184 self
._mainSizer
.Detach(self
._windows
[curSel
])
3185 self
._windows
[curSel
].Hide()
3187 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
3189 self
._mainSizer
.Insert(0, page
, 1, wx
.EXPAND
)
3193 # We leave a space of 1 pixel around the window
3194 self
._mainSizer
.Add(page
, 1, wx
.EXPAND
)
3196 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3197 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
3198 event
.SetOldSelection(oldSelection
)
3199 self
.GetEventHandler().ProcessEvent(event
)
3207 self
._mainSizer
.Layout()
3213 def SetImageList(self
, imageList
):
3214 """ Sets the image list for the page control. """
3216 self
._pages
.SetImageList(imageList
)
3219 def AssignImageList(self
, imageList
):
3220 """ Assigns the image list for the page control. """
3222 self
._pages
.AssignImageList(imageList
)
3225 def GetImageList(self
):
3226 """ Returns the associated image list. """
3228 return self
._pages
.GetImageList()
3231 def InsertPage(self
, indx
, page
, text
, select
=True, imageId
=-1):
3233 Inserts a new page at the specified position.
3235 @param indx: Specifies the position of the new page.
3236 @param page: Specifies the new page.
3237 @param text: Specifies the text for the new page.
3238 @param select: Specifies whether the page should be selected.
3239 @param imageId: Specifies the optional image index for the new page.
3242 True if successful, False otherwise.
3249 # reparent the window to us
3252 if not self
._windows
:
3254 self
.AddPage(page
, text
, select
, imageId
)
3258 bSelected
= select
or not self
._windows
3259 curSel
= self
._pages
.GetSelection()
3261 indx
= max(0, min(indx
, len(self
._windows
)))
3263 if indx
<= len(self
._windows
):
3265 self
._windows
.insert(indx
, page
)
3269 self
._windows
.append(page
)
3275 # Check for selection and send events
3276 oldSelection
= self
._pages
._iActivePage
3278 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId())
3279 event
.SetSelection(indx
)
3280 event
.SetOldSelection(oldSelection
)
3281 event
.SetEventObject(self
)
3283 if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed() or len(self
._windows
) == 0:
3286 self
._pages
.InsertPage(indx
, text
, bSelected
, imageId
)
3293 # Check if a new selection was made
3298 # Remove the window from the main sizer
3299 self
._mainSizer
.Detach(self
._windows
[curSel
])
3300 self
._windows
[curSel
].Hide()
3302 self
._pages
.SetSelection(indx
)
3304 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3305 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
3306 event
.SetOldSelection(oldSelection
)
3307 self
.GetEventHandler().ProcessEvent(event
)
3315 self
._mainSizer
.Layout()
3321 def SetSelection(self
, page
):
3323 Sets the selection for the given page.
3324 The call to this function generates the page changing events
3327 if page
>= len(self
._windows
) or not self
._windows
:
3330 # Support for disabed tabs
3331 if not self
._pages
.GetEnabled(page
) and len(self
._windows
) > 1 and not self
._bForceSelection
:
3334 curSel
= self
._pages
.GetSelection()
3336 # program allows the page change
3340 # Remove the window from the main sizer
3341 self
._mainSizer
.Detach(self
._windows
[curSel
])
3342 self
._windows
[curSel
].Hide()
3344 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
3346 self
._mainSizer
.Insert(0, self
._windows
[page
], 1, wx
.EXPAND
)
3350 # We leave a space of 1 pixel around the window
3351 self
._mainSizer
.Add(self
._windows
[page
], 1, wx
.EXPAND
)
3353 self
._windows
[page
].Show()
3356 self
._mainSizer
.Layout()
3358 if page
!= self
._pages
._iActivePage
:
3359 # there is a real page changing
3360 self
._pages
._iPreviousActivePage
= self
._pages
._iActivePage
3362 self
._pages
._iActivePage
= page
3363 self
._pages
.DoSetSelection(page
)
3366 def DeletePage(self
, page
):
3368 Deletes the specified page, and the associated window.
3369 The call to this function generates the page changing events.
3372 if page
>= len(self
._windows
) or page
< 0:
3375 # Fire a closing event
3376 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
3377 event
.SetSelection(page
)
3378 event
.SetEventObject(self
)
3379 self
.GetEventHandler().ProcessEvent(event
)
3381 # The event handler allows it?
3382 if not event
.IsAllowed():
3387 # Delete the requested page
3388 pageRemoved
= self
._windows
[page
]
3390 # If the page is the current window, remove it from the sizer
3392 if page
== self
._pages
.GetSelection():
3393 self
._mainSizer
.Detach(pageRemoved
)
3395 # Remove it from the array as well
3396 self
._windows
.pop(page
)
3398 # Now we can destroy it in wxWidgets use Destroy instead of delete
3399 pageRemoved
.Destroy()
3403 self
._pages
.DoDeletePage(page
)
3407 # Fire a closed event
3408 closedEvent
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, self
.GetId())
3409 closedEvent
.SetSelection(page
)
3410 closedEvent
.SetEventObject(self
)
3411 self
.GetEventHandler().ProcessEvent(closedEvent
)
3414 def DeleteAllPages(self
):
3415 """ Deletes all the pages. """
3417 if not self
._windows
:
3422 for page
in self
._windows
:
3428 # Clear the container of the tabs as well
3429 self
._pages
.DeleteAllPages()
3433 def GetCurrentPage(self
):
3434 """ Returns the currently selected notebook page or None. """
3436 sel
= self
._pages
.GetSelection()
3440 return self
._windows
[sel
]
3443 def GetPage(self
, page
):
3444 """ Returns the window at the given page position, or None. """
3446 if page
>= len(self
._windows
):
3449 return self
._windows
[page
]
3452 def GetPageIndex(self
, win
):
3453 """ Returns the index at which the window is found. """
3456 return self
._windows
.index(win
)
3461 def GetSelection(self
):
3462 """ Returns the currently selected page, or -1 if none was selected. """
3464 return self
._pages
.GetSelection()
3467 def AdvanceSelection(self
, forward
=True):
3469 Cycles through the tabs.
3470 The call to this function generates the page changing events.
3473 self
._pages
.AdvanceSelection(forward
)
3476 def GetPageCount(self
):
3477 """ Returns the number of pages in the L{FlatNotebook} control. """
3479 return self
._pages
.GetPageCount()
3482 def OnNavigationKey(self
, event
):
3483 """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
3485 if event
.IsWindowChange():
3486 if len(self
._windows
) == 0:
3489 if self
.HasFlag(FNB_SMART_TABS
):
3490 if not self
._popupWin
:
3491 self
._popupWin
= TabNavigatorWindow(self
)
3492 self
._popupWin
.SetReturnCode(wx
.ID_OK
)
3493 self
._popupWin
.ShowModal()
3494 self
._popupWin
.Destroy()
3495 self
._popupWin
= None
3497 # a dialog is already opened
3498 self
._popupWin
.OnNavigationKey(event
)
3502 self
.AdvanceSelection(event
.GetDirection())
3507 def GetPageShapeAngle(self
, page_index
):
3508 """ Returns the angle associated to a tab. """
3510 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
3513 result
= self
._pages
._pagesInfoVec
[page_index
].GetTabAngle()
3517 def SetPageShapeAngle(self
, page_index
, angle
):
3518 """ Sets the angle associated to a tab. """
3520 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
3526 self
._pages
._pagesInfoVec
[page_index
].SetTabAngle(angle
)
3529 def SetAllPagesShapeAngle(self
, angle
):
3530 """ Sets the angle associated to all the tab. """
3535 for ii
in xrange(len(self
._pages
._pagesInfoVec
)):
3536 self
._pages
._pagesInfoVec
[ii
].SetTabAngle(angle
)
3541 def GetPageBestSize(self
):
3542 """ Return the page best size. """
3544 return self
._pages
.GetClientSize()
3547 def SetPageText(self
, page
, text
):
3548 """ Sets the text for the given page. """
3550 bVal
= self
._pages
.SetPageText(page
, text
)
3551 self
._pages
.Refresh()
3556 def SetPadding(self
, padding
):
3558 Sets the amount of space around each page's icon and label, in pixels.
3559 NB: only the horizontal padding is considered.
3562 self
._nPadding
= padding
.GetWidth()
3565 def GetTabArea(self
):
3566 """ Returns the associated page. """
3571 def GetPadding(self
):
3572 """ Returns the amount of space around each page's icon and label, in pixels. """
3574 return self
._nPadding
3577 def SetWindowStyleFlag(self
, style
):
3578 """ Sets the L{FlatNotebook} window style flags. """
3580 wx
.PyPanel
.SetWindowStyleFlag(self
, style
)
3581 renderer
= self
._pages
._mgr
.GetRenderer(self
.GetWindowStyleFlag())
3582 renderer
._tabHeight
= None
3586 # For changing the tab position (i.e. placing them top/bottom)
3587 # refreshing the tab container is not enough
3588 self
.SetSelection(self
._pages
._iActivePage
)
3590 if not self
._pages
.HasFlag(FNB_HIDE_ON_SINGLE_TAB
):
3591 #For Redrawing the Tabs once you remove the Hide tyle
3592 self
._pages
._ReShow
()
3595 def RemovePage(self
, page
):
3596 """ Deletes the specified page, without deleting the associated window. """
3598 if page
>= len(self
._windows
):
3601 # Fire a closing event
3602 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
3603 event
.SetSelection(page
)
3604 event
.SetEventObject(self
)
3605 self
.GetEventHandler().ProcessEvent(event
)
3607 # The event handler allows it?
3608 if not event
.IsAllowed():
3613 # Remove the requested page
3614 pageRemoved
= self
._windows
[page
]
3616 # If the page is the current window, remove it from the sizer
3618 if page
== self
._pages
.GetSelection():
3619 self
._mainSizer
.Detach(pageRemoved
)
3621 # Remove it from the array as well
3622 self
._windows
.pop(page
)
3625 self
._pages
.DoDeletePage(page
)
3630 def SetRightClickMenu(self
, menu
):
3631 """ Sets the popup menu associated to a right click on a tab. """
3633 self
._pages
._pRightClickMenu
= menu
3636 def GetPageText(self
, nPage
):
3637 """ Returns the tab caption. """
3639 return self
._pages
.GetPageText(nPage
)
3642 def SetGradientColours(self
, fr
, to
, border
):
3643 """ Sets the gradient colours for the tab. """
3645 self
._pages
._colorFrom
= fr
3646 self
._pages
._colorTo
= to
3647 self
._pages
._colorBorder
= border
3650 def SetGradientColourFrom(self
, fr
):
3651 """ Sets the starting colour for the gradient. """
3653 self
._pages
._colorFrom
= fr
3656 def SetGradientColourTo(self
, to
):
3657 """ Sets the ending colour for the gradient. """
3659 self
._pages
._colorTo
= to
3662 def SetGradientColourBorder(self
, border
):
3663 """ Sets the tab border colour. """
3665 self
._pages
._colorBorder
= border
3668 def GetGradientColourFrom(self
):
3669 """ Gets first gradient colour. """
3671 return self
._pages
._colorFrom
3674 def GetGradientColourTo(self
):
3675 """ Gets second gradient colour. """
3677 return self
._pages
._colorTo
3680 def GetGradientColourBorder(self
):
3681 """ Gets the tab border colour. """
3683 return self
._pages
._colorBorder
3686 def GetBorderColour(self
):
3687 """ Returns the border colour. """
3689 return self
._pages
._colorBorder
3692 def GetActiveTabTextColour(self
):
3693 """ Get the active tab text colour. """
3695 return self
._pages
._activeTextColor
3698 def SetPageImage(self
, page
, image
):
3700 Sets the image index for the given page. Image is an index into the
3701 image list which was set with SetImageList.
3704 self
._pages
.SetPageImage(page
, image
)
3707 def GetPageImage(self
, nPage
):
3709 Returns the image index for the given page. Image is an index into the
3710 image list which was set with SetImageList.
3713 return self
._pages
.GetPageImage(nPage
)
3716 def GetEnabled(self
, page
):
3717 """ Returns whether a tab is enabled or not. """
3719 return self
._pages
.GetEnabled(page
)
3722 def EnableTab(self
, page
, enabled
=True):
3723 """ Enables or disables a tab. """
3725 if page
>= len(self
._windows
):
3728 self
._windows
[page
].Enable(enabled
)
3729 self
._pages
.EnableTab(page
, enabled
)
3732 def GetNonActiveTabTextColour(self
):
3733 """ Returns the non active tabs text colour. """
3735 return self
._pages
._nonActiveTextColor
3738 def SetNonActiveTabTextColour(self
, color
):
3739 """ Sets the non active tabs text colour. """
3741 self
._pages
._nonActiveTextColor
= color
3744 def SetTabAreaColour(self
, color
):
3745 """ Sets the area behind the tabs colour. """
3747 self
._pages
._tabAreaColor
= color
3750 def GetTabAreaColour(self
):
3751 """ Returns the area behind the tabs colour. """
3753 return self
._pages
._tabAreaColor
3756 def SetActiveTabColour(self
, color
):
3757 """ Sets the active tab colour. """
3759 self
._pages
._activeTabColor
= color
3762 def GetActiveTabColour(self
):
3763 """ Returns the active tab colour. """
3765 return self
._pages
._activeTabColor
3768 # ---------------------------------------------------------------------------- #
3769 # Class PageContainer
3770 # Acts as a container for the pages you add to FlatNotebook
3771 # ---------------------------------------------------------------------------- #
3773 class PageContainer(wx
.Panel
):
3775 This class acts as a container for the pages you add to L{FlatNotebook}.
3778 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
,
3779 size
=wx
.DefaultSize
, style
=0):
3780 """ Default class constructor. """
3782 self
._ImageList
= None
3783 self
._iActivePage
= -1
3784 self
._pDropTarget
= None
3785 self
._nLeftClickZone
= FNB_NOWHERE
3786 self
._iPreviousActivePage
= -1
3788 self
._pRightClickMenu
= None
3789 self
._nXButtonStatus
= FNB_BTN_NONE
3790 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3791 self
._pParent
= parent
3792 self
._nRightButtonStatus
= FNB_BTN_NONE
3793 self
._nLeftButtonStatus
= FNB_BTN_NONE
3794 self
._nTabXButtonStatus
= FNB_BTN_NONE
3796 self
._pagesInfoVec
= []
3798 self
._colorTo
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_ACTIVECAPTION
)
3799 self
._colorFrom
= wx
.WHITE
3800 self
._activeTabColor
= wx
.WHITE
3801 self
._activeTextColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNTEXT
)
3802 self
._nonActiveTextColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNTEXT
)
3803 self
._tabAreaColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
)
3806 self
._isdragging
= False
3808 # Set default page height, this is done according to the system font
3809 memDc
= wx
.MemoryDC()
3810 memDc
.SelectObject(wx
.EmptyBitmap(1,1))
3812 if "__WXGTK__" in wx
.PlatformInfo
:
3813 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3814 boldFont
.SetWeight(wx
.BOLD
)
3815 memDc
.SetFont(boldFont
)
3817 height
= memDc
.GetCharHeight()
3818 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 10 pixels as padding
3820 wx
.Panel
.__init
__(self
, parent
, id, pos
, wx
.Size(size
.x
, tabHeight
),
3821 style|wx
.NO_BORDER|wx
.NO_FULL_REPAINT_ON_RESIZE
)
3823 self
._pDropTarget
= FNBDropTarget(self
)
3824 self
.SetDropTarget(self
._pDropTarget
)
3825 self
._mgr
= FNBRendererMgr()
3827 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
3828 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
3829 self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
)
3830 self
.Bind(wx
.EVT_LEFT_UP
, self
.OnLeftUp
)
3831 self
.Bind(wx
.EVT_RIGHT_DOWN
, self
.OnRightDown
)
3832 self
.Bind(wx
.EVT_MIDDLE_DOWN
, self
.OnMiddleDown
)
3833 self
.Bind(wx
.EVT_MOTION
, self
.OnMouseMove
)
3834 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
3835 self
.Bind(wx
.EVT_LEAVE_WINDOW
, self
.OnMouseLeave
)
3836 self
.Bind(wx
.EVT_ENTER_WINDOW
, self
.OnMouseEnterWindow
)
3837 self
.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnLeftDClick
)
3838 self
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
3839 self
.Bind(wx
.EVT_KILL_FOCUS
, self
.OnKillFocus
)
3842 def OnEraseBackground(self
, event
):
3843 """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
3849 """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """
3851 self
.GetParent()._mainSizer
.Layout()
3855 def OnPaint(self
, event
):
3856 """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
3858 dc
= wx
.BufferedPaintDC(self
)
3859 renderer
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag())
3860 renderer
.DrawTabs(self
, dc
)
3862 if self
.HasFlag(FNB_HIDE_ON_SINGLE_TAB
) and len(self
._pagesInfoVec
) <= 1:
3864 self
.GetParent()._mainSizer
.Layout()
3868 def AddPage(self
, caption
, selected
=True, imgindex
=-1):
3870 Add a page to the L{FlatNotebook}.
3872 @param window: Specifies the new page.
3873 @param caption: Specifies the text for the new page.
3874 @param selected: Specifies whether the page should be selected.
3875 @param imgindex: Specifies the optional image index for the new page.
3878 True if successful, False otherwise.
3883 self
._iPreviousActivePage
= self
._iActivePage
3884 self
._iActivePage
= len(self
._pagesInfoVec
)
3886 # Create page info and add it to the vector
3887 pageInfo
= PageInfo(caption
, imgindex
)
3888 self
._pagesInfoVec
.append(pageInfo
)
3892 def InsertPage(self
, indx
, text
, selected
=True, imgindex
=-1):
3894 Inserts a new page at the specified position.
3896 @param indx: Specifies the position of the new page.
3897 @param page: Specifies the new page.
3898 @param text: Specifies the text for the new page.
3899 @param select: Specifies whether the page should be selected.
3900 @param imgindex: Specifies the optional image index for the new page.
3903 True if successful, False otherwise.
3908 self
._iPreviousActivePage
= self
._iActivePage
3909 self
._iActivePage
= len(self
._pagesInfoVec
)
3911 self
._pagesInfoVec
.insert(indx
, PageInfo(text
, imgindex
))
3917 def OnSize(self
, event
):
3918 """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
3920 # When resizing the control, try to fit to screen as many tabs as we can
3921 style
= self
.GetParent().GetWindowStyleFlag()
3922 renderer
= self
._mgr
.GetRenderer(style
)
3925 page
= self
.GetSelection()
3927 for fr
in xrange(self
._nFrom
):
3928 vTabInfo
= renderer
.NumberTabsCanFit(self
, fr
)
3929 if page
- fr
>= len(vTabInfo
):
3935 self
.Refresh() # Call on paint
3939 def OnMiddleDown(self
, event
):
3940 """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
3942 # Test if this style is enabled
3943 style
= self
.GetParent().GetWindowStyleFlag()
3945 if not style
& FNB_MOUSE_MIDDLE_CLOSES_TABS
:
3948 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3950 if where
== FNB_TAB
:
3951 self
.DeletePage(tabIdx
)
3956 def OnRightDown(self
, event
):
3957 """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
3959 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3961 if where
in [FNB_TAB
, FNB_TAB_X
]:
3963 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
3964 # Fire events and eventually (if allowed) change selection
3965 self
.FireEvent(tabIdx
)
3967 # send a message to popup a custom menu
3968 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, self
.GetParent().GetId())
3969 event
.SetSelection(tabIdx
)
3970 event
.SetOldSelection(self
._iActivePage
)
3971 event
.SetEventObject(self
.GetParent())
3972 self
.GetParent().GetEventHandler().ProcessEvent(event
)
3974 if self
._pRightClickMenu
:
3975 self
.PopupMenu(self
._pRightClickMenu
)
3980 def OnLeftDown(self
, event
):
3981 """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
3983 # Reset buttons status
3984 self
._nXButtonStatus
= FNB_BTN_NONE
3985 self
._nLeftButtonStatus
= FNB_BTN_NONE
3986 self
._nRightButtonStatus
= FNB_BTN_NONE
3987 self
._nTabXButtonStatus
= FNB_BTN_NONE
3988 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3990 self
._nLeftClickZone
, tabIdx
= self
.HitTest(event
.GetPosition())
3992 if self
._nLeftClickZone
== FNB_DROP_DOWN_ARROW
:
3993 self
._nArrowDownButtonStatus
= FNB_BTN_PRESSED
3995 elif self
._nLeftClickZone
== FNB_LEFT_ARROW
:
3996 self
._nLeftButtonStatus
= FNB_BTN_PRESSED
3998 elif self
._nLeftClickZone
== FNB_RIGHT_ARROW
:
3999 self
._nRightButtonStatus
= FNB_BTN_PRESSED
4001 elif self
._nLeftClickZone
== FNB_X
:
4002 self
._nXButtonStatus
= FNB_BTN_PRESSED
4004 elif self
._nLeftClickZone
== FNB_TAB_X
:
4005 self
._nTabXButtonStatus
= FNB_BTN_PRESSED
4008 elif self
._nLeftClickZone
== FNB_TAB
:
4010 if self
._iActivePage
!= tabIdx
:
4012 # In case the tab is disabled, we dont allow to choose it
4013 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
4014 self
.FireEvent(tabIdx
)
4017 def RotateLeft(self
):
4019 if self
._nFrom
== 0:
4022 # Make sure that the button was pressed before
4023 if self
._nLeftButtonStatus
!= FNB_BTN_PRESSED
:
4026 self
._nLeftButtonStatus
= FNB_BTN_HOVER
4028 # We scroll left with bulks of 5
4029 scrollLeft
= self
.GetNumTabsCanScrollLeft()
4031 self
._nFrom
-= scrollLeft
4038 def RotateRight(self
):
4040 if self
._nFrom
>= len(self
._pagesInfoVec
) - 1:
4043 # Make sure that the button was pressed before
4044 if self
._nRightButtonStatus
!= FNB_BTN_PRESSED
:
4047 self
._nRightButtonStatus
= FNB_BTN_HOVER
4049 # Check if the right most tab is visible, if it is
4050 # don't rotate right anymore
4051 if self
._pagesInfoVec
[len(self
._pagesInfoVec
)-1].GetPosition() != wx
.Point(-1, -1):
4058 def OnLeftUp(self
, event
):
4059 """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
4061 # forget the zone that was initially clicked
4062 self
._nLeftClickZone
= FNB_NOWHERE
4064 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4066 if where
== FNB_LEFT_ARROW
:
4069 elif where
== FNB_RIGHT_ARROW
:
4072 elif where
== FNB_X
:
4074 # Make sure that the button was pressed before
4075 if self
._nXButtonStatus
!= FNB_BTN_PRESSED
:
4078 self
._nXButtonStatus
= FNB_BTN_HOVER
4080 self
.DeletePage(self
._iActivePage
)
4082 elif where
== FNB_TAB_X
:
4084 # Make sure that the button was pressed before
4085 if self
._nTabXButtonStatus
!= FNB_BTN_PRESSED
:
4088 self
._nTabXButtonStatus
= FNB_BTN_HOVER
4090 self
.DeletePage(self
._iActivePage
)
4092 elif where
== FNB_DROP_DOWN_ARROW
:
4094 # Make sure that the button was pressed before
4095 if self
._nArrowDownButtonStatus
!= FNB_BTN_PRESSED
:
4098 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4100 # Refresh the button status
4101 renderer
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag())
4102 dc
= wx
.ClientDC(self
)
4103 renderer
.DrawDropDownArrow(self
, dc
)
4105 self
.PopupTabsMenu()
4110 def HitTest(self
, pt
):
4112 HitTest method for L{PageContainer}.
4113 Returns the flag (if any) and the hit page (if any).
4116 style
= self
.GetParent().GetWindowStyleFlag()
4117 render
= self
._mgr
.GetRenderer(style
)
4119 fullrect
= self
.GetClientRect()
4120 btnLeftPos
= render
.GetLeftButtonPos(self
)
4121 btnRightPos
= render
.GetRightButtonPos(self
)
4122 btnXPos
= render
.GetXPos(self
)
4126 if len(self
._pagesInfoVec
) == 0:
4127 return FNB_NOWHERE
, tabIdx
4129 rect
= wx
.Rect(btnXPos
, 8, 16, 16)
4130 if rect
.Contains(pt
):
4131 return (style
& FNB_NO_X_BUTTON
and [FNB_NOWHERE
] or [FNB_X
])[0], tabIdx
4133 rect
= wx
.Rect(btnRightPos
, 8, 16, 16)
4134 if style
& FNB_DROPDOWN_TABS_LIST
:
4135 rect
= wx
.Rect(render
.GetDropArrowButtonPos(self
), 8, 16, 16)
4136 if rect
.Contains(pt
):
4137 return FNB_DROP_DOWN_ARROW
, tabIdx
4139 if rect
.Contains(pt
):
4140 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_RIGHT_ARROW
])[0], tabIdx
4142 rect
= wx
.Rect(btnLeftPos
, 8, 16, 16)
4143 if rect
.Contains(pt
):
4144 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_LEFT_ARROW
])[0], tabIdx
4146 # Test whether a left click was made on a tab
4149 for cur
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4151 pgInfo
= self
._pagesInfoVec
[cur
]
4153 if pgInfo
.GetPosition() == wx
.Point(-1, -1):
4156 if style
& FNB_X_ON_TAB
and cur
== self
.GetSelection():
4157 # 'x' button exists on a tab
4158 if self
._pagesInfoVec
[cur
].GetXRect().Contains(pt
):
4159 return FNB_TAB_X
, cur
4163 if self
._pagesInfoVec
[cur
].GetRegion().Contains(pt
.x
, pt
.y
):
4164 if bFoundMatch
or cur
== self
.GetSelection():
4172 tabRect
= wx
.Rect(pgInfo
.GetPosition().x
, pgInfo
.GetPosition().y
,
4173 pgInfo
.GetSize().x
, pgInfo
.GetSize().y
)
4175 if tabRect
.Contains(pt
):
4180 return FNB_TAB
, tabIdx
4182 if self
._isdragging
:
4183 # We are doing DND, so check also the region outside the tabs
4184 # try before the first tab
4185 pgInfo
= self
._pagesInfoVec
[0]
4186 tabRect
= wx
.Rect(0, pgInfo
.GetPosition().y
, pgInfo
.GetPosition().x
, self
.GetParent().GetSize().y
)
4187 if tabRect
.Contains(pt
):
4190 # try after the last tab
4191 pgInfo
= self
._pagesInfoVec
[-1]
4192 startpos
= pgInfo
.GetPosition().x
+pgInfo
.GetSize().x
4193 tabRect
= wx
.Rect(startpos
, pgInfo
.GetPosition().y
, fullrect
.width
-startpos
, self
.GetParent().GetSize().y
)
4195 if tabRect
.Contains(pt
):
4196 return FNB_TAB
, len(self
._pagesInfoVec
)
4199 return FNB_NOWHERE
, -1
4202 def SetSelection(self
, page
):
4203 """ Sets the selected page. """
4205 book
= self
.GetParent()
4206 book
.SetSelection(page
)
4207 self
.DoSetSelection(page
)
4210 def DoSetSelection(self
, page
):
4211 """ Does the actual selection of a page. """
4213 if page
< len(self
._pagesInfoVec
):
4215 da_page
= self
._pParent
.GetPage(page
)
4220 if not self
.IsTabVisible(page
):
4221 # Try to remove one tab from start and try again
4223 if not self
.CanFitToScreen(page
):
4225 if self
._nFrom
> page
:
4228 while self
._nFrom
< page
:
4230 if self
.CanFitToScreen(page
):
4236 def DeletePage(self
, page
):
4237 """ Delete the specified page from L{FlatNotebook}. """
4239 book
= self
.GetParent()
4240 book
.DeletePage(page
)
4244 def IsTabVisible(self
, page
):
4245 """ Returns whether a tab is visible or not. """
4247 iLastVisiblePage
= self
.GetLastVisibleTab()
4248 return page
<= iLastVisiblePage
and page
>= self
._nFrom
4251 def DoDeletePage(self
, page
):
4252 """ Does the actual page deletion. """
4254 # Remove the page from the vector
4255 book
= self
.GetParent()
4256 self
._pagesInfoVec
.pop(page
)
4258 # Thanks to Yiaanis AKA Mandrav
4259 if self
._iActivePage
>= page
:
4260 self
._iActivePage
= self
._iActivePage
- 1
4261 self
._iPreviousActivePage
= -1
4263 # The delete page was the last first on the array,
4264 # but the book still has more pages, so we set the
4265 # active page to be the first one (0)
4266 if self
._iActivePage
< 0 and len(self
._pagesInfoVec
) > 0:
4267 self
._iActivePage
= 0
4268 self
._iPreviousActivePage
= -1
4271 if self
._iActivePage
>= 0:
4273 book
._bForceSelection
= True
4275 # Check for selection and send event
4276 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
4277 event
.SetSelection(self
._iActivePage
)
4278 event
.SetOldSelection(self
._iPreviousActivePage
)
4279 event
.SetEventObject(self
.GetParent())
4281 book
.SetSelection(self
._iActivePage
)
4282 book
._bForceSelection
= False
4284 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4285 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
4286 event
.SetOldSelection(self
._iPreviousActivePage
)
4287 self
.GetParent().GetEventHandler().ProcessEvent(event
)
4289 if not self
._pagesInfoVec
:
4290 # Erase the page container drawings
4291 dc
= wx
.ClientDC(self
)
4295 def DeleteAllPages(self
):
4296 """ Deletes all the pages. """
4298 self
._iActivePage
= -1
4299 self
._iPreviousActivePage
= -1
4301 self
._pagesInfoVec
= []
4303 # Erase the page container drawings
4304 dc
= wx
.ClientDC(self
)
4308 def OnMouseMove(self
, event
):
4309 """ Handles the wx.EVT_MOTION for L{PageContainer}. """
4311 if self
._pagesInfoVec
and self
.IsShown():
4313 xButtonStatus
= self
._nXButtonStatus
4314 xTabButtonStatus
= self
._nTabXButtonStatus
4315 rightButtonStatus
= self
._nRightButtonStatus
4316 leftButtonStatus
= self
._nLeftButtonStatus
4317 dropDownButtonStatus
= self
._nArrowDownButtonStatus
4319 style
= self
.GetParent().GetWindowStyleFlag()
4321 self
._nXButtonStatus
= FNB_BTN_NONE
4322 self
._nRightButtonStatus
= FNB_BTN_NONE
4323 self
._nLeftButtonStatus
= FNB_BTN_NONE
4324 self
._nTabXButtonStatus
= FNB_BTN_NONE
4325 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4327 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4330 if event
.LeftIsDown():
4332 self
._nXButtonStatus
= (self
._nLeftClickZone
==FNB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4336 self
._nXButtonStatus
= FNB_BTN_HOVER
4338 elif where
== FNB_DROP_DOWN_ARROW
:
4339 if event
.LeftIsDown():
4341 self
._nArrowDownButtonStatus
= (self
._nLeftClickZone
==FNB_DROP_DOWN_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4345 self
._nArrowDownButtonStatus
= FNB_BTN_HOVER
4347 elif where
== FNB_TAB_X
:
4348 if event
.LeftIsDown():
4350 self
._nTabXButtonStatus
= (self
._nLeftClickZone
==FNB_TAB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4354 self
._nTabXButtonStatus
= FNB_BTN_HOVER
4356 elif where
== FNB_RIGHT_ARROW
:
4357 if event
.LeftIsDown():
4359 self
._nRightButtonStatus
= (self
._nLeftClickZone
==FNB_RIGHT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4363 self
._nRightButtonStatus
= FNB_BTN_HOVER
4365 elif where
== FNB_LEFT_ARROW
:
4366 if event
.LeftIsDown():
4368 self
._nLeftButtonStatus
= (self
._nLeftClickZone
==FNB_LEFT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4372 self
._nLeftButtonStatus
= FNB_BTN_HOVER
4374 elif where
== FNB_TAB
:
4375 # Call virtual method for showing tooltip
4376 self
.ShowTabTooltip(tabIdx
)
4378 if not self
.GetEnabled(tabIdx
):
4379 # Set the cursor to be 'No-entry'
4380 wx
.SetCursor(wx
.StockCursor(wx
.CURSOR_NO_ENTRY
))
4382 # Support for drag and drop
4383 if event
.Dragging() and not (style
& FNB_NODRAG
):
4385 self
._isdragging
= True
4386 draginfo
= FNBDragInfo(self
, tabIdx
)
4387 drginfo
= cPickle
.dumps(draginfo
)
4388 dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
4389 dataobject
.SetData(drginfo
)
4390 dragSource
= FNBDropSource(self
)
4391 dragSource
.SetData(dataobject
)
4392 dragSource
.DoDragDrop(wx
.Drag_DefaultMove
)
4394 bRedrawX
= self
._nXButtonStatus
!= xButtonStatus
4395 bRedrawRight
= self
._nRightButtonStatus
!= rightButtonStatus
4396 bRedrawLeft
= self
._nLeftButtonStatus
!= leftButtonStatus
4397 bRedrawTabX
= self
._nTabXButtonStatus
!= xTabButtonStatus
4398 bRedrawDropArrow
= self
._nArrowDownButtonStatus
!= dropDownButtonStatus
4400 render
= self
._mgr
.GetRenderer(style
)
4402 if (bRedrawX
or bRedrawRight
or bRedrawLeft
or bRedrawTabX
or bRedrawDropArrow
):
4404 dc
= wx
.ClientDC(self
)
4408 render
.DrawX(self
, dc
)
4412 render
.DrawLeftArrow(self
, dc
)
4416 render
.DrawRightArrow(self
, dc
)
4422 if bRedrawDropArrow
:
4424 render
.DrawDropDownArrow(self
, dc
)
4429 def GetLastVisibleTab(self
):
4430 """ Returns the last visible tab. """
4437 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4439 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
4445 def GetNumTabsCanScrollLeft(self
):
4446 """ Returns the number of tabs than can be scrolled left. """
4448 if self
._nFrom
- 1 >= 0:
4454 def IsDefaultTabs(self
):
4455 """ Returns whether a tab has a default style. """
4457 style
= self
.GetParent().GetWindowStyleFlag()
4458 res
= (style
& FNB_VC71
) or (style
& FNB_FANCY_TABS
) or (style
& FNB_VC8
)
4462 def AdvanceSelection(self
, bForward
=True):
4464 Cycles through the tabs.
4465 The call to this function generates the page changing events.
4468 nSel
= self
.GetSelection()
4473 nMax
= self
.GetPageCount() - 1
4476 newSelection
= (nSel
== nMax
and [0] or [nSel
+ 1])[0]
4478 newSelection
= (nSel
== 0 and [nMax
] or [nSel
- 1])[0]
4480 if not self
._pagesInfoVec
[newSelection
].GetEnabled():
4483 self
.FireEvent(newSelection
)
4486 def OnMouseLeave(self
, event
):
4487 """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
4489 self
._nLeftButtonStatus
= FNB_BTN_NONE
4490 self
._nXButtonStatus
= FNB_BTN_NONE
4491 self
._nRightButtonStatus
= FNB_BTN_NONE
4492 self
._nTabXButtonStatus
= FNB_BTN_NONE
4493 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4495 style
= self
.GetParent().GetWindowStyleFlag()
4496 render
= self
._mgr
.GetRenderer(style
)
4498 dc
= wx
.ClientDC(self
)
4500 render
.DrawX(self
, dc
)
4501 render
.DrawLeftArrow(self
, dc
)
4502 render
.DrawRightArrow(self
, dc
)
4504 selection
= self
.GetSelection()
4510 if not self
.IsTabVisible(selection
):
4511 if selection
== len(self
._pagesInfoVec
) - 1:
4512 if not self
.CanFitToScreen(selection
):
4519 render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[selection
].GetXRect(), selection
, self
._nTabXButtonStatus
)
4524 def OnMouseEnterWindow(self
, event
):
4525 """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
4527 self
._nLeftButtonStatus
= FNB_BTN_NONE
4528 self
._nXButtonStatus
= FNB_BTN_NONE
4529 self
._nRightButtonStatus
= FNB_BTN_NONE
4530 self
._nLeftClickZone
= FNB_BTN_NONE
4531 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4536 def ShowTabTooltip(self
, tabIdx
):
4537 """ Shows a tab tooltip. """
4539 pWindow
= self
._pParent
.GetPage(tabIdx
)
4542 pToolTip
= pWindow
.GetToolTip()
4543 if pToolTip
and pToolTip
.GetWindow() == pWindow
:
4544 self
.SetToolTipString(pToolTip
.GetTip())
4547 def SetPageImage(self
, page
, imgindex
):
4548 """ Sets the image index associated to a page. """
4550 if page
< len(self
._pagesInfoVec
):
4552 self
._pagesInfoVec
[page
].SetImageIndex(imgindex
)
4556 def GetPageImage(self
, page
):
4557 """ Returns the image index associated to a page. """
4559 if page
< len(self
._pagesInfoVec
):
4561 return self
._pagesInfoVec
[page
].GetImageIndex()
4566 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
4567 """ Handles the drop action from a DND operation. """
4569 # Disable drag'n'drop for disabled tab
4570 if not wnd_oldContainer
._pagesInfoVec
[nTabPage
].GetEnabled():
4571 return wx
.DragCancel
4573 self
._isdragging
= True
4574 oldContainer
= wnd_oldContainer
4577 where
, nIndex
= self
.HitTest(wx
.Point(x
, y
))
4579 oldNotebook
= oldContainer
.GetParent()
4580 newNotebook
= self
.GetParent()
4582 if oldNotebook
== newNotebook
:
4586 if where
== FNB_TAB
:
4587 self
.MoveTabPage(nTabPage
, nIndex
)
4589 elif self
.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND
:
4591 if wx
.Platform
in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]:
4594 window
= oldNotebook
.GetPage(nTabPage
)
4597 where
, nIndex
= newNotebook
._pages
.HitTest(wx
.Point(x
, y
))
4598 caption
= oldContainer
.GetPageText(nTabPage
)
4599 imageindex
= oldContainer
.GetPageImage(nTabPage
)
4600 oldNotebook
.RemovePage(nTabPage
)
4601 window
.Reparent(newNotebook
)
4605 bmp
= oldNotebook
.GetImageList().GetIcon(imageindex
)
4606 newImageList
= newNotebook
.GetImageList()
4608 if not newImageList
:
4609 xbmp
, ybmp
= bmp
.GetWidth(), bmp
.GetHeight()
4610 newImageList
= wx
.ImageList(xbmp
, ybmp
)
4613 imageindex
= newImageList
.GetImageCount()
4615 newImageList
.AddIcon(bmp
)
4616 newNotebook
.SetImageList(newImageList
)
4618 newNotebook
.InsertPage(nIndex
, window
, caption
, True, imageindex
)
4620 self
._isdragging
= False
4625 def MoveTabPage(self
, nMove
, nMoveTo
):
4626 """ Moves a tab inside the same L{FlatNotebook}. """
4628 if nMove
== nMoveTo
:
4631 elif nMoveTo
< len(self
._pParent
._windows
):
4632 nMoveTo
= nMoveTo
+ 1
4634 self
._pParent
.Freeze()
4636 # Remove the window from the main sizer
4637 nCurSel
= self
._pParent
._pages
.GetSelection()
4638 self
._pParent
._mainSizer
.Detach(self
._pParent
._windows
[nCurSel
])
4639 self
._pParent
._windows
[nCurSel
].Hide()
4641 pWindow
= self
._pParent
._windows
[nMove
]
4642 self
._pParent
._windows
.pop(nMove
)
4643 self
._pParent
._windows
.insert(nMoveTo
-1, pWindow
)
4645 pgInfo
= self
._pagesInfoVec
[nMove
]
4647 self
._pagesInfoVec
.pop(nMove
)
4648 self
._pagesInfoVec
.insert(nMoveTo
- 1, pgInfo
)
4650 # Add the page according to the style
4651 pSizer
= self
._pParent
._mainSizer
4652 style
= self
.GetParent().GetWindowStyleFlag()
4654 if style
& FNB_BOTTOM
:
4656 pSizer
.Insert(0, pWindow
, 1, wx
.EXPAND
)
4660 # We leave a space of 1 pixel around the window
4661 pSizer
.Add(pWindow
, 1, wx
.EXPAND
)
4666 self
._iActivePage
= nMoveTo
- 1
4667 self
._iPreviousActivePage
= -1
4668 self
.DoSetSelection(self
._iActivePage
)
4670 self
._pParent
.Thaw()
4673 def CanFitToScreen(self
, page
):
4674 """ Returns wheter a tab can fit in the left space in the screen or not. """
4676 # Incase the from is greater than page,
4677 # we need to reset the self._nFrom, so in order
4678 # to force the caller to do so, we return false
4679 if self
._nFrom
> page
:
4682 style
= self
.GetParent().GetWindowStyleFlag()
4683 render
= self
._mgr
.GetRenderer(style
)
4685 vTabInfo
= render
.NumberTabsCanFit(self
)
4687 if page
- self
._nFrom
>= len(vTabInfo
):
4693 def GetNumOfVisibleTabs(self
):
4694 """ Returns the number of visible tabs. """
4697 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4698 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
4705 def GetEnabled(self
, page
):
4706 """ Returns whether a tab is enabled or not. """
4708 if page
>= len(self
._pagesInfoVec
):
4709 return True # Seems strange, but this is the default
4711 return self
._pagesInfoVec
[page
].GetEnabled()
4714 def EnableTab(self
, page
, enabled
=True):
4715 """ Enables or disables a tab. """
4717 if page
>= len(self
._pagesInfoVec
):
4720 self
._pagesInfoVec
[page
].EnableTab(enabled
)
4723 def GetSingleLineBorderColour(self
):
4724 """ Returns the colour for the single line border. """
4726 if self
.HasFlag(FNB_FANCY_TABS
):
4727 return self
._colorFrom
4732 def HasFlag(self
, flag
):
4733 """ Returns whether a flag is present in the L{FlatNotebook} style. """
4735 style
= self
.GetParent().GetWindowStyleFlag()
4736 res
= (style
& flag
and [True] or [False])[0]
4740 def ClearFlag(self
, flag
):
4741 """ Deletes a flag from the L{FlatNotebook} style. """
4743 style
= self
.GetParent().GetWindowStyleFlag()
4745 self
.SetWindowStyleFlag(style
)
4748 def TabHasImage(self
, tabIdx
):
4749 """ Returns whether a tab has an associated image index or not. """
4752 return self
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
4757 def OnLeftDClick(self
, event
):
4758 """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
4760 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4762 if where
== FNB_RIGHT_ARROW
:
4765 elif where
== FNB_LEFT_ARROW
:
4768 elif self
.HasFlag(FNB_DCLICK_CLOSES_TABS
):
4770 if where
== FNB_TAB
:
4771 self
.DeletePage(tabIdx
)
4778 def OnSetFocus(self
, event
):
4779 """ Handles the wx.EVT_SET_FOCUS event for L{PageContainer}. """
4781 if self
._iActivePage
< 0:
4785 self
.SetFocusedPage(self
._iActivePage
)
4788 def OnKillFocus(self
, event
):
4789 """ Handles the wx.EVT_KILL_FOCUS event for L{PageContainer}. """
4791 self
.SetFocusedPage()
4794 def SetFocusedPage(self
, pageIndex
=-1):
4796 Sets/Unsets the focus on the appropriate page.
4797 If pageIndex is defaulted, we have lost focus and no focus indicator is drawn.
4800 for indx
, page
in enumerate(self
._pagesInfoVec
):
4801 if indx
== pageIndex
:
4802 page
._hasFocus
= True
4804 page
._hasFocus
= False
4809 def PopupTabsMenu(self
):
4810 """ Pops up the menu activated with the drop down arrow in the navigation area. """
4812 popupMenu
= wx
.Menu()
4814 for i
in xrange(len(self
._pagesInfoVec
)):
4815 pi
= self
._pagesInfoVec
[i
]
4816 item
= wx
.MenuItem(popupMenu
, i
+1, pi
.GetCaption(), pi
.GetCaption(), wx
.ITEM_NORMAL
)
4817 self
.Bind(wx
.EVT_MENU
, self
.OnTabMenuSelection
, item
)
4819 # There is an alignment problem with wx2.6.3 & Menus so only use
4820 # images for versions above 2.6.3
4821 if wx
.VERSION
> (2, 6, 3, 0) and self
.TabHasImage(i
):
4822 item
.SetBitmap(self
.GetImageList().GetBitmap(pi
.GetImageIndex()))
4824 popupMenu
.AppendItem(item
)
4825 item
.EnableTab(pi
.GetEnabled())
4827 self
.PopupMenu(popupMenu
)
4830 def OnTabMenuSelection(self
, event
):
4831 """ Handles the wx.EVT_MENU event for L{PageContainer}. """
4833 selection
= event
.GetId() - 1
4834 self
.FireEvent(selection
)
4837 def FireEvent(self
, selection
):
4839 Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
4840 called from other methods (from menu selection or Smart Tabbing).
4844 if selection
== self
._iActivePage
:
4845 # No events for the same selection
4848 oldSelection
= self
._iActivePage
4850 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
4851 event
.SetSelection(selection
)
4852 event
.SetOldSelection(oldSelection
)
4853 event
.SetEventObject(self
.GetParent())
4855 if not self
.GetParent().GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
4857 self
.SetSelection(selection
)
4859 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4860 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
4861 event
.SetOldSelection(oldSelection
)
4862 self
.GetParent().GetEventHandler().ProcessEvent(event
)
4866 def SetImageList(self
, imglist
):
4867 """ Sets the image list for the page control. """
4869 self
._ImageList
= imglist
4872 def AssignImageList(self
, imglist
):
4873 """ Assigns the image list for the page control. """
4875 self
._ImageList
= imglist
4878 def GetImageList(self
):
4879 """ Returns the image list for the page control. """
4881 return self
._ImageList
4884 def GetSelection(self
):
4885 """ Returns the current selected page. """
4887 return self
._iActivePage
4890 def GetPageCount(self
):
4891 """ Returns the number of tabs in the L{FlatNotebook} control. """
4893 return len(self
._pagesInfoVec
)
4896 def GetPageText(self
, page
):
4897 """ Returns the tab caption of the page. """
4899 return self
._pagesInfoVec
[page
].GetCaption()
4902 def SetPageText(self
, page
, text
):
4903 """ Sets the tab caption of the page. """
4905 self
._pagesInfoVec
[page
].SetCaption(text
)
4909 def DrawDragHint(self
):
4910 """ Draws small arrow at the place that the tab will be placed. """
4912 # get the index of tab that will be replaced with the dragged tab
4913 pt
= wx
.GetMousePosition()
4914 client_pt
= self
.ScreenToClient(pt
)
4915 where
, tabIdx
= self
.HitTest(client_pt
)
4916 self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag()).DrawDragHint(self
, tabIdx
)