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: 16 Apr 2007, 11.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 @ 16 Apr 2007, 11.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()
897 def SetCaption(self
, value
):
898 """ Sets the tab caption. """
900 self
._strCaption
= value
903 def GetCaption(self
):
904 """ Returns the tab caption. """
906 return self
._strCaption
909 def SetPosition(self
, value
):
910 """ Sets the tab position. """
915 def GetPosition(self
):
916 """ Returns the tab position. """
921 def SetSize(self
, value
):
922 """ Sets the tab size. """
928 """ Returns the tab size. """
933 def SetTabAngle(self
, value
):
934 """ Sets the tab header angle (0 <= tab <= 15 degrees). """
936 self
._TabAngle
= min(45, value
)
939 def GetTabAngle(self
):
940 """ Returns the tab angle. """
942 return self
._TabAngle
945 def SetImageIndex(self
, value
):
946 """ Sets the tab image index. """
948 self
._ImageIndex
= value
951 def GetImageIndex(self
):
952 """ Returns the tab umage index. """
954 return self
._ImageIndex
957 def GetEnabled(self
):
958 """ Returns whether the tab is enabled or not. """
960 return self
._bEnabled
963 def Enable(self
, enabled
):
964 """ Sets the tab enabled or disabled. """
966 self
._bEnabled
= enabled
969 def SetRegion(self
, points
=[]):
970 """ Sets the tab region. """
972 self
._region
= wx
.RegionFromPoints(points
)
976 """ Returns the tab region. """
981 def SetXRect(self
, xrect
):
982 """ Sets the button 'X' area rect. """
988 """ Returns the button 'X' area rect. """
994 """ Returns the tab colour. """
999 def SetColour(self
, color
):
1000 """ Sets the tab colour. """
1005 # ---------------------------------------------------------------------------- #
1006 # Class FlatNotebookEvent
1007 # ---------------------------------------------------------------------------- #
1009 class FlatNotebookEvent(wx
.PyCommandEvent
):
1011 This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
1012 EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING,
1013 EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is
1014 mapped in the parent.
1017 def __init__(self
, eventType
, id=1, nSel
=-1, nOldSel
=-1):
1018 """ Default class constructor. """
1020 wx
.PyCommandEvent
.__init
__(self
, eventType
, id)
1021 self
._eventType
= eventType
1023 self
.notify
= wx
.NotifyEvent(eventType
, id)
1026 def GetNotifyEvent(self
):
1027 """Returns the actual wx.NotifyEvent."""
1032 def IsAllowed(self
):
1033 """Returns whether the event is allowed or not."""
1035 return self
.notify
.IsAllowed()
1039 """Vetos the event."""
1045 """The event is allowed."""
1050 def SetSelection(self
, nSel
):
1051 """ Sets event selection. """
1053 self
._selection
= nSel
1056 def SetOldSelection(self
, nOldSel
):
1057 """ Sets old event selection. """
1059 self
._oldselection
= nOldSel
1062 def GetSelection(self
):
1063 """ Returns event selection. """
1065 return self
._selection
1068 def GetOldSelection(self
):
1069 """ Returns old event selection """
1071 return self
._oldselection
1074 # ---------------------------------------------------------------------------- #
1075 # Class TabNavigatorWindow
1076 # ---------------------------------------------------------------------------- #
1078 class TabNavigatorWindow(wx
.Dialog
):
1080 This class is used to create a modal dialog that enables "Smart Tabbing",
1081 similar to what you would get by hitting Alt+Tab on Windows.
1084 def __init__(self
, parent
=None):
1085 """ Default class constructor. Used internally."""
1087 wx
.Dialog
.__init
__(self
, parent
, wx
.ID_ANY
, "", style
=0)
1089 self
._selectedItem
= -1
1092 self
._bmp
= GetMondrianBitmap()
1094 sz
= wx
.BoxSizer(wx
.VERTICAL
)
1096 self
._listBox
= wx
.ListBox(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, 150), [], wx
.LB_SINGLE | wx
.NO_BORDER
)
1098 mem_dc
= wx
.MemoryDC()
1099 mem_dc
.SelectObject(wx
.EmptyBitmap(1,1))
1100 font
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1101 font
.SetWeight(wx
.BOLD
)
1102 mem_dc
.SetFont(font
)
1104 panelHeight
= mem_dc
.GetCharHeight()
1105 panelHeight
+= 4 # Place a spacer of 2 pixels
1107 # Out signpost bitmap is 24 pixels
1108 if panelHeight
< 24:
1111 self
._panel
= wx
.Panel(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.Size(200, panelHeight
))
1114 sz
.Add(self
._listBox
, 1, wx
.EXPAND
)
1118 # Connect events to the list box
1119 self
._listBox
.Bind(wx
.EVT_KEY_UP
, self
.OnKeyUp
)
1120 self
._listBox
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
1121 self
._listBox
.Bind(wx
.EVT_LISTBOX_DCLICK
, self
.OnItemSelected
)
1123 # Connect paint event to the panel
1124 self
._panel
.Bind(wx
.EVT_PAINT
, self
.OnPanelPaint
)
1125 self
._panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnPanelEraseBg
)
1127 self
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1128 self
._listBox
.SetBackgroundColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1129 self
.PopulateListControl(parent
)
1131 self
.GetSizer().Fit(self
)
1132 self
.GetSizer().SetSizeHints(self
)
1133 self
.GetSizer().Layout()
1137 def OnKeyUp(self
, event
):
1138 """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}."""
1140 if event
.GetKeyCode() == wx
.WXK_CONTROL
:
1144 def OnNavigationKey(self
, event
):
1145 """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """
1147 selected
= self
._listBox
.GetSelection()
1148 bk
= self
.GetParent()
1149 maxItems
= bk
.GetPageCount()
1151 if event
.GetDirection():
1154 if selected
== maxItems
- 1:
1157 itemToSelect
= selected
+ 1
1163 itemToSelect
= maxItems
- 1
1165 itemToSelect
= selected
- 1
1167 self
._listBox
.SetSelection(itemToSelect
)
1170 def PopulateListControl(self
, book
):
1171 """Populates the L{TabNavigatorWindow} listbox with a list of tabs."""
1173 selection
= book
.GetSelection()
1174 count
= book
.GetPageCount()
1176 self
._listBox
.Append(book
.GetPageText(selection
))
1177 self
._indexMap
.append(selection
)
1179 prevSel
= book
.GetPreviousSelection()
1181 if prevSel
!= wx
.NOT_FOUND
:
1183 # Insert the previous selection as second entry
1184 self
._listBox
.Append(book
.GetPageText(prevSel
))
1185 self
._indexMap
.append(prevSel
)
1187 for c
in xrange(count
):
1189 # Skip selected page
1193 # Skip previous selected page as well
1197 self
._listBox
.Append(book
.GetPageText(c
))
1198 self
._indexMap
.append(c
)
1200 # Select the next entry after the current selection
1201 self
._listBox
.SetSelection(0)
1202 dummy
= wx
.NavigationKeyEvent()
1203 dummy
.SetDirection(True)
1204 self
.OnNavigationKey(dummy
)
1207 def OnItemSelected(self
, event
):
1208 """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """
1213 def CloseDialog(self
):
1214 """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}."""
1216 bk
= self
.GetParent()
1217 self
._selectedItem
= self
._listBox
.GetSelection()
1218 iter = self
._indexMap
[self
._selectedItem
]
1219 bk
._pages
.FireEvent(iter)
1220 self
.EndModal(wx
.ID_OK
)
1223 def OnPanelPaint(self
, event
):
1224 """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """
1226 dc
= wx
.PaintDC(self
._panel
)
1227 rect
= self
._panel
.GetClientRect()
1229 bmp
= wx
.EmptyBitmap(rect
.width
, rect
.height
)
1231 mem_dc
= wx
.MemoryDC()
1232 mem_dc
.SelectObject(bmp
)
1234 endColour
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
1235 startColour
= LightColour(endColour
, 50)
1236 PaintStraightGradientBox(mem_dc
, rect
, startColour
, endColour
)
1238 # Draw the caption title and place the bitmap
1239 # get the bitmap optimal position, and draw it
1240 bmpPt
, txtPt
= wx
.Point(), wx
.Point()
1241 bmpPt
.y
= (rect
.height
- self
._bmp
.GetHeight())/2
1243 mem_dc
.DrawBitmap(self
._bmp
, bmpPt
.x
, bmpPt
.y
, True)
1245 # get the text position, and draw it
1246 font
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1247 font
.SetWeight(wx
.BOLD
)
1248 mem_dc
.SetFont(font
)
1249 fontHeight
= mem_dc
.GetCharHeight()
1251 txtPt
.x
= bmpPt
.x
+ self
._bmp
.GetWidth() + 4
1252 txtPt
.y
= (rect
.height
- fontHeight
)/2
1253 mem_dc
.SetTextForeground(wx
.WHITE
)
1254 mem_dc
.DrawText("Opened tabs:", txtPt
.x
, txtPt
.y
)
1255 mem_dc
.SelectObject(wx
.NullBitmap
)
1257 dc
.DrawBitmap(bmp
, 0, 0)
1260 def OnPanelEraseBg(self
, event
):
1261 """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """
1266 # ---------------------------------------------------------------------------- #
1268 # ---------------------------------------------------------------------------- #
1272 Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy}
1273 and I{VC8}. This class implements the common methods of all 4 renderers.
1274 @undocumented: _GetBitmap*
1278 """Default class constructor. """
1280 self
._tabXBgBmp
= wx
.EmptyBitmap(16, 16)
1281 self
._xBgBmp
= wx
.EmptyBitmap(16, 14)
1282 self
._leftBgBmp
= wx
.EmptyBitmap(16, 14)
1283 self
._rightBgBmp
= wx
.EmptyBitmap(16, 14)
1284 self
._tabHeight
= None
1287 def GetLeftButtonPos(self
, pageContainer
):
1288 """ Returns the left button position in the navigation area. """
1291 style
= pc
.GetParent().GetWindowStyleFlag()
1292 rect
= pc
.GetClientRect()
1293 clientWidth
= rect
.width
1295 if style
& FNB_NO_X_BUTTON
:
1296 return clientWidth
- 38
1298 return clientWidth
- 54
1302 def GetRightButtonPos(self
, pageContainer
):
1303 """ Returns the right button position in the navigation area. """
1306 style
= pc
.GetParent().GetWindowStyleFlag()
1307 rect
= pc
.GetClientRect()
1308 clientWidth
= rect
.width
1310 if style
& FNB_NO_X_BUTTON
:
1311 return clientWidth
- 22
1313 return clientWidth
- 38
1316 def GetDropArrowButtonPos(self
, pageContainer
):
1317 """ Returns the drop down button position in the navigation area. """
1319 return self
.GetRightButtonPos(pageContainer
)
1322 def GetXPos(self
, pageContainer
):
1323 """ Returns the 'X' button position in the navigation area. """
1326 style
= pc
.GetParent().GetWindowStyleFlag()
1327 rect
= pc
.GetClientRect()
1328 clientWidth
= rect
.width
1330 if style
& FNB_NO_X_BUTTON
:
1333 return clientWidth
- 22
1336 def GetButtonsAreaLength(self
, pageContainer
):
1337 """ Returns the navigation area width. """
1340 style
= pc
.GetParent().GetWindowStyleFlag()
1343 if style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1347 elif style
& FNB_NO_NAV_BUTTONS
and not style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1351 if not style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
and not style
& FNB_DROPDOWN_TABS_LIST
:
1355 if style
& FNB_DROPDOWN_TABS_LIST
and not style
& FNB_NO_X_BUTTON
:
1359 if style
& FNB_DROPDOWN_TABS_LIST
and style
& FNB_NO_X_BUTTON
:
1366 def DrawLeftArrow(self
, pageContainer
, dc
):
1367 """ Draw the left navigation arrow. """
1371 style
= pc
.GetParent().GetWindowStyleFlag()
1372 if style
& FNB_NO_NAV_BUTTONS
:
1375 # Make sure that there are pages in the container
1376 if not pc
._pagesInfoVec
:
1379 # Set the bitmap according to the button status
1380 if pc
._nLeftButtonStatus
== FNB_BTN_HOVER
:
1381 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_hilite_xpm
)
1382 elif pc
._nLeftButtonStatus
== FNB_BTN_PRESSED
:
1383 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_pressed_xpm
)
1385 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_xpm
)
1388 # Handle disabled arrow
1389 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_disabled_xpm
)
1391 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
1394 posx
= self
.GetLeftButtonPos(pc
)
1395 dc
.DrawBitmap(self
._leftBgBmp
, posx
, 6)
1397 # Draw the new bitmap
1398 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
1401 def DrawRightArrow(self
, pageContainer
, dc
):
1402 """ Draw the right navigation arrow. """
1406 style
= pc
.GetParent().GetWindowStyleFlag()
1407 if style
& FNB_NO_NAV_BUTTONS
:
1410 # Make sure that there are pages in the container
1411 if not pc
._pagesInfoVec
:
1414 # Set the bitmap according to the button status
1415 if pc
._nRightButtonStatus
== FNB_BTN_HOVER
:
1416 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_hilite_xpm
)
1417 elif pc
._nRightButtonStatus
== FNB_BTN_PRESSED
:
1418 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_pressed_xpm
)
1420 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_xpm
)
1422 # Check if the right most tab is visible, if it is
1423 # don't rotate right anymore
1424 if pc
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1):
1425 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_disabled_xpm
)
1427 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
1430 posx
= self
.GetRightButtonPos(pc
)
1431 dc
.DrawBitmap(self
._rightBgBmp
, posx
, 6)
1433 # Draw the new bitmap
1434 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
1437 def DrawDropDownArrow(self
, pageContainer
, dc
):
1438 """ Draws the drop-down arrow in the navigation area. """
1442 # Check if this style is enabled
1443 style
= pc
.GetParent().GetWindowStyleFlag()
1444 if not style
& FNB_DROPDOWN_TABS_LIST
:
1447 # Make sure that there are pages in the container
1448 if not pc
._pagesInfoVec
:
1451 if pc
._nArrowDownButtonStatus
== FNB_BTN_HOVER
:
1452 downBmp
= wx
.BitmapFromXPMData(down_arrow_hilite_xpm
)
1453 elif pc
._nArrowDownButtonStatus
== FNB_BTN_PRESSED
:
1454 downBmp
= wx
.BitmapFromXPMData(down_arrow_pressed_xpm
)
1456 downBmp
= wx
.BitmapFromXPMData(down_arrow_xpm
)
1458 downBmp
.SetMask(wx
.Mask(downBmp
, MASK_COLOR
))
1461 posx
= self
.GetDropArrowButtonPos(pc
)
1462 dc
.DrawBitmap(self
._xBgBmp
, posx
, 6)
1464 # Draw the new bitmap
1465 dc
.DrawBitmap(downBmp
, posx
, 6, True)
1468 def DrawX(self
, pageContainer
, dc
):
1469 """ Draw the 'X' navigation button in the navigation area. """
1473 # Check if this style is enabled
1474 style
= pc
.GetParent().GetWindowStyleFlag()
1475 if style
& FNB_NO_X_BUTTON
:
1478 # Make sure that there are pages in the container
1479 if not pc
._pagesInfoVec
:
1482 # Set the bitmap according to the button status
1483 if pc
._nXButtonStatus
== FNB_BTN_HOVER
:
1484 xbmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
1485 elif pc
._nXButtonStatus
== FNB_BTN_PRESSED
:
1486 xbmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
1488 xbmp
= wx
.BitmapFromXPMData(x_button_xpm
)
1490 xbmp
.SetMask(wx
.Mask(xbmp
, MASK_COLOR
))
1493 posx
= self
.GetXPos(pc
)
1494 dc
.DrawBitmap(self
._xBgBmp
, posx
, 6)
1496 # Draw the new bitmap
1497 dc
.DrawBitmap(xbmp
, posx
, 6, True)
1500 def DrawTabX(self
, pageContainer
, dc
, rect
, tabIdx
, btnStatus
):
1501 """ Draws the 'X' in the selected tab. """
1504 if not pc
.HasFlag(FNB_X_ON_TAB
):
1507 # We draw the 'x' on the active tab only
1508 if tabIdx
!= pc
.GetSelection() or tabIdx
< 0:
1511 # Set the bitmap according to the button status
1513 if btnStatus
== FNB_BTN_HOVER
:
1514 xBmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
1515 elif btnStatus
== FNB_BTN_PRESSED
:
1516 xBmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
1518 xBmp
= wx
.BitmapFromXPMData(x_button_xpm
)
1521 xBmp
.SetMask(wx
.Mask(xBmp
, MASK_COLOR
))
1524 dc
.DrawBitmap(self
._tabXBgBmp
, rect
.x
, rect
.y
)
1526 # Draw the new bitmap
1527 dc
.DrawBitmap(xBmp
, rect
.x
, rect
.y
, True)
1530 rr
= wx
.Rect(rect
.x
, rect
.y
, 14, 13)
1531 pc
._pagesInfoVec
[tabIdx
].SetXRect(rr
)
1534 def _GetBitmap(self
, dc
, rect
, bmp
):
1536 mem_dc
= wx
.MemoryDC()
1537 mem_dc
.SelectObject(bmp
)
1538 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1539 mem_dc
.SelectObject(wx
.NullBitmap
)
1543 def DrawTabsLine(self
, pageContainer
, dc
, selTabX1
=-1, selTabX2
=-1):
1544 """ Draws a line over the tabs. """
1548 clntRect
= pc
.GetClientRect()
1549 clientRect3
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
)
1551 if pc
.HasFlag(FNB_FF2
):
1552 if not pc
.HasFlag(FNB_BOTTOM
):
1553 fillColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)
1555 fillColor
= wx
.WHITE
1557 dc
.SetPen(wx
.Pen(fillColor
))
1559 if pc
.HasFlag(FNB_BOTTOM
):
1561 dc
.DrawLine(1, 0, clntRect
.width
-1, 0)
1562 dc
.DrawLine(1, 1, clntRect
.width
-1, 1)
1564 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1565 dc
.DrawLine(1, 2, clntRect
.width
-1, 2)
1567 dc
.SetPen(wx
.Pen(fillColor
))
1568 dc
.DrawLine(selTabX1
+ 2, 2, selTabX2
- 1, 2)
1572 dc
.DrawLine(1, clntRect
.height
, clntRect
.width
-1, clntRect
.height
)
1573 dc
.DrawLine(1, clntRect
.height
-1, clntRect
.width
-1, clntRect
.height
-1)
1575 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1576 dc
.DrawLine(1, clntRect
.height
-2, clntRect
.width
-1, clntRect
.height
-2)
1578 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)))
1579 dc
.DrawLine(selTabX1
+ 2, clntRect
.height
-2, selTabX2
-1, clntRect
.height
-2)
1583 if pc
.HasFlag(FNB_BOTTOM
):
1585 clientRect
= wx
.Rect(0, 2, clntRect
.width
, clntRect
.height
- 2)
1586 clientRect2
= wx
.Rect(0, 1, clntRect
.width
, clntRect
.height
- 1)
1590 clientRect
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 2)
1591 clientRect2
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 1)
1593 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1594 dc
.SetPen(wx
.Pen(pc
.GetSingleLineBorderColour()))
1595 dc
.DrawRectangleRect(clientRect2
)
1596 dc
.DrawRectangleRect(clientRect3
)
1598 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
1599 dc
.DrawRectangleRect(clientRect
)
1601 if not pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
1603 dc
.SetPen(wx
.Pen((pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
._tabAreaColor
])[0]))
1604 dc
.DrawLine(0, 0, 0, clientRect
.height
+1)
1606 if pc
.HasFlag(FNB_BOTTOM
):
1608 dc
.DrawLine(0, clientRect
.height
+1, clientRect
.width
, clientRect
.height
+1)
1612 dc
.DrawLine(0, 0, clientRect
.width
, 0)
1614 dc
.DrawLine(clientRect
.width
- 1, 0, clientRect
.width
- 1, clientRect
.height
+1)
1617 def CalcTabWidth(self
, pageContainer
, tabIdx
, tabHeight
):
1618 """ Calculates the width of the input tab. """
1622 dc
.SelectObject(wx
.EmptyBitmap(1,1))
1624 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1625 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1627 if pc
.IsDefaultTabs():
1628 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1630 # Calculate the text length using the bold font, so when selecting a tab
1631 # its width will not change
1632 dc
.SetFont(boldFont
)
1633 width
, pom
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
1635 # Set a minimum size to a tab
1639 tabWidth
= 2*pc
._pParent
.GetPadding() + width
1641 # Style to add a small 'x' button on the top right
1643 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
1644 # The xpm image that contains the 'x' button is 9 pixels
1646 if pc
.HasFlag(FNB_VC8
):
1649 tabWidth
+= pc
._pParent
.GetPadding() + spacer
1651 if pc
.IsDefaultTabs():
1653 tabWidth
+= 2*shapePoints
1655 hasImage
= pc
._ImageList
!= None and pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
1657 # For VC71 style, we only add the icon size (16 pixels)
1660 if not pc
.IsDefaultTabs():
1661 tabWidth
+= 16 + pc
._pParent
.GetPadding()
1664 tabWidth
+= 16 + pc
._pParent
.GetPadding() + shapePoints
/2
1669 def CalcTabHeight(self
, pageContainer
):
1670 """ Calculates the height of the input tab. """
1673 return self
._tabHeight
1677 dc
.SelectObject(wx
.EmptyBitmap(1,1))
1679 # For GTK it seems that we must do this steps in order
1680 # for the tabs will get the proper height on initialization
1681 # on MSW, preforming these steps yields wierd results
1682 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1683 boldFont
= normalFont
1685 if "__WXGTK__" in wx
.PlatformInfo
:
1686 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1687 dc
.SetFont(boldFont
)
1689 height
= dc
.GetCharHeight()
1691 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
1692 if "__WXGTK__" in wx
.PlatformInfo
:
1693 # On GTK the tabs are should be larger
1696 self
._tabHeight
= tabHeight
1701 def DrawTabs(self
, pageContainer
, dc
):
1702 """ Actually draws the tabs in L{FlatNotebook}."""
1705 if "__WXMAC__" in wx
.PlatformInfo
:
1706 # Works well on MSW & GTK, however this lines should be skipped on MAC
1707 if not pc
._pagesInfoVec
or pc
._nFrom
>= len(pc
._pagesInfoVec
):
1711 # Get the text hight
1712 tabHeight
= self
.CalcTabHeight(pageContainer
)
1713 style
= pc
.GetParent().GetWindowStyleFlag()
1715 # Calculate the number of rows required for drawing the tabs
1716 rect
= pc
.GetClientRect()
1717 clientWidth
= rect
.width
1719 # Set the maximum client size
1720 pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
)
1721 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1723 if style
& FNB_VC71
:
1724 backBrush
= wx
.Brush(wx
.Colour(247, 243, 233))
1726 backBrush
= wx
.Brush(pc
._tabAreaColor
)
1728 noselBrush
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
))
1729 selBrush
= wx
.Brush(pc
._activeTabColor
)
1734 dc
.SetTextBackground((style
& FNB_VC71
and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0])
1735 dc
.SetTextForeground(pc
._activeTextColor
)
1736 dc
.SetBrush(backBrush
)
1738 # If border style is set, set the pen to be border pen
1739 if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
1740 dc
.SetPen(borderPen
)
1742 colr
= (pc
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [pc
.GetBackgroundColour()])[0]
1743 dc
.SetPen(wx
.Pen(colr
))
1745 if pc
.HasFlag(FNB_FF2
):
1746 lightFactor
= (pc
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0]
1747 PaintStraightGradientBox(dc
, pc
.GetClientRect(), pc
._tabAreaColor
, LightColour(pc
._tabAreaColor
, lightFactor
))
1748 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1750 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
1752 # Take 3 bitmaps for the background for the buttons
1754 mem_dc
= wx
.MemoryDC()
1755 #---------------------------------------
1757 #---------------------------------------
1758 rect
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14)
1759 mem_dc
.SelectObject(self
._xBgBmp
)
1760 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1761 mem_dc
.SelectObject(wx
.NullBitmap
)
1763 #---------------------------------------
1765 #---------------------------------------
1766 rect
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14)
1767 mem_dc
.SelectObject(self
._rightBgBmp
)
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
.GetLeftButtonPos(pc
), 6, 16, 14)
1775 mem_dc
.SelectObject(self
._leftBgBmp
)
1776 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1777 mem_dc
.SelectObject(wx
.NullBitmap
)
1779 # We always draw the bottom/upper line of the tabs
1780 # regradless the style
1781 dc
.SetPen(borderPen
)
1783 if not pc
.HasFlag(FNB_FF2
):
1784 self
.DrawTabsLine(pc
, dc
)
1787 dc
.SetPen(borderPen
)
1789 if pc
.HasFlag(FNB_VC71
):
1791 greyLineYVal
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [size
.y
- 2])[0]
1792 whiteLineYVal
= (pc
.HasFlag(FNB_BOTTOM
) and [3] or [size
.y
- 3])[0]
1794 pen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))
1797 # Draw thik grey line between the windows area and
1799 for num
in xrange(3):
1800 dc
.DrawLine(0, greyLineYVal
+ num
, size
.x
, greyLineYVal
+ num
)
1802 wbPen
= (pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK_PEN
] or [wx
.WHITE_PEN
])[0]
1804 dc
.DrawLine(1, whiteLineYVal
, size
.x
- 1, whiteLineYVal
)
1807 dc
.SetPen(borderPen
)
1810 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1811 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1812 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1813 dc
.SetFont(boldFont
)
1815 posx
= pc
._pParent
.GetPadding()
1817 # Update all the tabs from 0 to 'pc._nFrom' to be non visible
1818 for i
in xrange(pc
._nFrom
):
1820 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
1821 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1825 #----------------------------------------------------------
1826 # Go over and draw the visible tabs
1827 #----------------------------------------------------------
1829 for i
in xrange(pc
._nFrom
, len(pc
._pagesInfoVec
)):
1831 dc
.SetPen(borderPen
)
1833 if not pc
.HasFlag(FNB_FF2
):
1834 dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0])
1836 # Now set the font to the correct font
1837 dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0])
1839 # Add the padding to the tab width
1841 # +-----------------------------------------------------------+
1842 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
1843 # +-----------------------------------------------------------+
1844 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
1846 # Check if we can draw more
1847 if posx
+ tabWidth
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
1852 # By default we clean the tab region
1853 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1855 # Clean the 'x' buttn on the tab.
1856 # A 'Clean' rectangle, is a rectangle with width or height
1857 # with values lower than or equal to 0
1858 pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
1860 # Draw the tab (border, text, image & 'x' on tab)
1861 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
)
1863 if pc
.GetSelection() == i
:
1865 x2
= posx
+ tabWidth
+ 2
1867 # Restore the text forground
1868 dc
.SetTextForeground(pc
._activeTextColor
)
1870 # Update the tab position & size
1871 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0]
1873 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, posy
))
1874 pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
1877 # Update all tabs that can not fit into the screen as non-visible
1878 for i
in xrange(count
, len(pc
._pagesInfoVec
)):
1879 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
1880 pc
._pagesInfoVec
[i
].GetRegion().Clear()
1882 # Draw the left/right/close buttons
1884 self
.DrawLeftArrow(pc
, dc
)
1885 self
.DrawRightArrow(pc
, dc
)
1887 self
.DrawDropDownArrow(pc
, dc
)
1889 if pc
.HasFlag(FNB_FF2
):
1890 self
.DrawTabsLine(pc
, dc
, x1
, x2
)
1893 def DrawDragHint(self
, pc
, tabIdx
):
1895 Draws tab drag hint, the default implementation is to do nothing.
1896 You can override this function to provide a nice feedback to user.
1902 def NumberTabsCanFit(self
, pageContainer
, fr
=-1):
1906 rect
= pc
.GetClientRect()
1907 clientWidth
= rect
.width
1911 tabHeight
= self
.CalcTabHeight(pageContainer
)
1913 # The drawing starts from posx
1914 posx
= pc
._pParent
.GetPadding()
1919 for i
in xrange(fr
, len(pc
._pagesInfoVec
)):
1921 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
1922 if posx
+ tabWidth
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
1925 # Add a result to the returned vector
1926 tabRect
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
)
1927 vTabInfo
.append(tabRect
)
1930 posx
+= tabWidth
+ FNB_HEIGHT_SPACER
1935 # ---------------------------------------------------------------------------- #
1936 # Class FNBRendererMgr
1937 # A manager that handles all the renderers defined below and calls the
1938 # appropriate one when drawing is needed
1939 # ---------------------------------------------------------------------------- #
1941 class FNBRendererMgr
:
1943 This class represents a manager that handles all the 4 renderers defined
1944 and calls the appropriate one when drawing is needed.
1948 """ Default class constructor. """
1950 # register renderers
1952 self
._renderers
= {}
1953 self
._renderers
.update({-1: FNBRendererDefault()}
)
1954 self
._renderers
.update({FNB_VC71: FNBRendererVC71()}
)
1955 self
._renderers
.update({FNB_FANCY_TABS: FNBRendererFancy()}
)
1956 self
._renderers
.update({FNB_VC8: FNBRendererVC8()}
)
1957 self
._renderers
.update({FNB_FF2: FNBRendererFirefox2()}
)
1960 def GetRenderer(self
, style
):
1961 """ Returns the current renderer based on the style selected. """
1963 if style
& FNB_VC71
:
1964 return self
._renderers
[FNB_VC71
]
1966 if style
& FNB_FANCY_TABS
:
1967 return self
._renderers
[FNB_FANCY_TABS
]
1970 return self
._renderers
[FNB_VC8
]
1973 return self
._renderers
[FNB_FF2
]
1975 # the default is to return the default renderer
1976 return self
._renderers
[-1]
1979 #------------------------------------------
1981 #------------------------------------------
1983 class FNBRendererDefault(FNBRenderer
):
1985 This class handles the drawing of tabs using the I{Standard} renderer.
1989 """ Default class constructor. """
1991 FNBRenderer
.__init
__(self
)
1994 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
1995 """ Draws a tab using the I{Standard} style. """
1998 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2001 tabPoints
= [wx
.Point() for ii
in xrange(7)]
2002 tabPoints
[0].x
= posx
2003 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2005 tabPoints
[1].x
= int(posx
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2006 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2008 tabPoints
[2].x
= tabPoints
[1].x
+2
2009 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2011 tabPoints
[3].x
= int(posx
+tabWidth
-(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))-2
2012 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2014 tabPoints
[4].x
= tabPoints
[3].x
+2
2015 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2017 tabPoints
[5].x
= int(tabPoints
[4].x
+(tabHeight
-2)*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2018 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2020 tabPoints
[6].x
= tabPoints
[0].x
2021 tabPoints
[6].y
= tabPoints
[0].y
2023 if tabIdx
== pc
.GetSelection():
2025 # Draw the tab as rounded rectangle
2026 dc
.DrawPolygon(tabPoints
)
2030 if tabIdx
!= pc
.GetSelection() - 1:
2032 # Draw a vertical line to the right of the text
2033 pt1x
= tabPoints
[5].x
2034 pt1y
= (pc
.HasFlag(FNB_BOTTOM
) and [4] or [tabHeight
- 6])[0]
2035 pt2x
= tabPoints
[5].x
2036 pt2y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 4] or [4])[0]
2037 dc
.DrawLine(pt1x
, pt1y
, pt2x
, pt2y
)
2039 if tabIdx
== pc
.GetSelection():
2041 savePen
= dc
.GetPen()
2042 whitePen
= wx
.Pen(wx
.WHITE
)
2043 whitePen
.SetWidth(1)
2046 secPt
= wx
.Point(tabPoints
[5].x
+ 1, tabPoints
[5].y
)
2047 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, secPt
.x
, secPt
.y
)
2052 # -----------------------------------
2053 # Text and image drawing
2054 # -----------------------------------
2056 # Text drawing offset from the left border of the
2059 # The width of the images are 16 pixels
2060 padding
= pc
.GetParent().GetPadding()
2061 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2062 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2063 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2066 textOffset
= 2*pc
._pParent
._nPadding
+ 16 + shapePoints
/2
2068 textOffset
= pc
._pParent
._nPadding
+ shapePoints
/2
2072 if tabIdx
!= pc
.GetSelection():
2074 # Set the text background to be like the vertical lines
2075 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2079 imageXOffset
= textOffset
- 16 - padding
2080 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2081 posx
+ imageXOffset
, imageYCoord
,
2082 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2084 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2086 # draw 'x' on tab (if enabled)
2087 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2089 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2090 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2092 # take a bitmap from the position of the 'x' button (the x on tab button)
2093 # this bitmap will be used later to delete old buttons
2094 tabCloseButtonYCoord
= imageYCoord
2095 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2096 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2099 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2102 #------------------------------------------
2104 #------------------------------------------
2105 class FNBRendererFirefox2(FNBRenderer
):
2107 This class handles the drawing of tabs using the I{Firefox 2} renderer.
2111 """ Default class constructor. """
2113 FNBRenderer
.__init
__(self
)
2116 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2117 """ Draws a tab using the I{Firefox 2} style. """
2119 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2122 tabPoints
= [wx
.Point() for indx
in xrange(7)]
2123 tabPoints
[0].x
= posx
+ 2
2124 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2126 tabPoints
[1].x
= tabPoints
[0].x
2127 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2129 tabPoints
[2].x
= tabPoints
[1].x
+2
2130 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2132 tabPoints
[3].x
= posx
+ tabWidth
- 2
2133 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2135 tabPoints
[4].x
= tabPoints
[3].x
+ 2
2136 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2138 tabPoints
[5].x
= tabPoints
[4].x
2139 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 2])[0]
2141 tabPoints
[6].x
= tabPoints
[0].x
2142 tabPoints
[6].y
= tabPoints
[0].y
2144 #------------------------------------
2145 # Paint the tab with gradient
2146 #------------------------------------
2147 rr
= wx
.RectPP(tabPoints
[2], tabPoints
[5])
2148 DrawButton(dc
, rr
, pc
.GetSelection() == tabIdx
, not pc
.HasFlag(FNB_BOTTOM
))
2150 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2151 dc
.SetPen(borderPen
)
2153 # Draw the tab as rounded rectangle
2154 dc
.DrawPolygon(tabPoints
)
2156 # -----------------------------------
2157 # Text and image drawing
2158 # -----------------------------------
2160 # The width of the images are 16 pixels
2161 padding
= pc
.GetParent().GetPadding()
2162 shapePoints
= int(tabHeight
*math
.tan(float(pc
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
2163 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2164 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2167 textOffset
= 2*padding
+ 16 + shapePoints
/2
2169 textOffset
= padding
+ shapePoints
/2
2173 if tabIdx
!= pc
.GetSelection():
2175 # Set the text background to be like the vertical lines
2176 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2179 imageXOffset
= textOffset
- 16 - padding
2180 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2181 posx
+ imageXOffset
, imageYCoord
,
2182 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2184 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2186 # draw 'x' on tab (if enabled)
2187 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2189 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2190 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2192 # take a bitmap from the position of the 'x' button (the x on tab button)
2193 # this bitmap will be used later to delete old buttons
2194 tabCloseButtonYCoord
= imageYCoord
2195 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2196 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2199 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2202 #------------------------------------------------------------------
2204 #------------------------------------------------------------------
2206 class FNBRendererVC71(FNBRenderer
):
2208 This class handles the drawing of tabs using the I{VC71} renderer.
2212 """ Default class constructor. """
2214 FNBRenderer
.__init
__(self
)
2217 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2218 """ Draws a tab using the I{VC71} style. """
2220 # Visual studio 7.1 style
2221 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2224 dc
.SetPen((tabIdx
== pc
.GetSelection() and [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [borderPen
])[0])
2225 dc
.SetBrush((tabIdx
== pc
.GetSelection() and [wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))] or [wx
.Brush(wx
.Colour(247, 243, 233))])[0])
2227 if tabIdx
== pc
.GetSelection():
2229 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [0] or [VERTICAL_BORDER_PADDING
])[0]
2230 tabH
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 5] or [tabHeight
- 3])[0]
2231 dc
.DrawRectangle(posx
, posy
, tabWidth
, tabH
)
2233 # Draw a black line on the left side of the
2235 dc
.SetPen(wx
.BLACK_PEN
)
2237 blackLineY1
= VERTICAL_BORDER_PADDING
2239 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
2241 # To give the tab more 3D look we do the following
2242 # Incase the tab is on top,
2243 # Draw a thik white line on topof the rectangle
2244 # Otherwise, draw a thin (1 pixel) black line at the bottom
2246 pen
= wx
.Pen((pc
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK
] or [wx
.WHITE
])[0])
2248 whiteLinePosY
= (pc
.HasFlag(FNB_BOTTOM
) and [blackLineY2
] or [VERTICAL_BORDER_PADDING
])[0]
2249 dc
.DrawLine(posx
, whiteLinePosY
, posx
+ tabWidth
+ 1, whiteLinePosY
)
2251 # Draw a white vertical line to the left of the tab
2252 dc
.SetPen(wx
.WHITE_PEN
)
2253 if not pc
.HasFlag(FNB_BOTTOM
):
2256 dc
.DrawLine(posx
, blackLineY1
, posx
, blackLineY2
)
2260 # We dont draw a rectangle for non selected tabs, but only
2261 # vertical line on the left
2263 blackLineY1
= (pc
.HasFlag(FNB_BOTTOM
) and [VERTICAL_BORDER_PADDING
+ 2] or [VERTICAL_BORDER_PADDING
+ 1])[0]
2264 blackLineY2
= pc
.GetSize().y
- 5
2265 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
2267 # -----------------------------------
2268 # Text and image drawing
2269 # -----------------------------------
2271 # Text drawing offset from the left border of the
2274 # The width of the images are 16 pixels
2275 padding
= pc
.GetParent().GetPadding()
2276 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2277 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [5] or [8])[0]
2280 textOffset
= 2*pc
._pParent
._nPadding
+ 16
2282 textOffset
= pc
._pParent
._nPadding
2284 if tabIdx
!= pc
.GetSelection():
2286 # Set the text background to be like the vertical lines
2287 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2291 imageXOffset
= textOffset
- 16 - padding
2292 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2293 posx
+ imageXOffset
, imageYCoord
,
2294 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2296 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2298 # draw 'x' on tab (if enabled)
2299 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2301 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2302 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2304 # take a bitmap from the position of the 'x' button (the x on tab button)
2305 # this bitmap will be used later to delete old buttons
2306 tabCloseButtonYCoord
= imageYCoord
2307 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2308 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2311 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2314 #------------------------------------------------------------------
2316 #------------------------------------------------------------------
2318 class FNBRendererFancy(FNBRenderer
):
2320 This class handles the drawing of tabs using the I{Fancy} renderer.
2324 """ Default class constructor. """
2326 FNBRenderer
.__init
__(self
)
2329 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2330 """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
2332 # Fancy tabs - like with VC71 but with the following differences:
2333 # - The Selected tab is colored with gradient color
2334 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2337 pen
= (tabIdx
== pc
.GetSelection() and [wx
.Pen(pc
._pParent
.GetBorderColour())] or [wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
))])[0]
2339 if tabIdx
== pc
.GetSelection():
2341 posy
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [VERTICAL_BORDER_PADDING
])[0]
2344 rect
= wx
.Rect(posx
, posy
, tabWidth
, th
)
2346 col2
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourTo()] or [pc
._pParent
.GetGradientColourFrom()])[0]
2347 col1
= (pc
.HasFlag(FNB_BOTTOM
) and [pc
._pParent
.GetGradientColourFrom()] or [pc
._pParent
.GetGradientColourTo()])[0]
2349 PaintStraightGradientBox(dc
, rect
, col1
, col2
)
2350 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2352 dc
.DrawRectangleRect(rect
)
2354 # erase the bottom/top line of the rectangle
2355 dc
.SetPen(wx
.Pen(pc
._pParent
.GetGradientColourFrom()))
2356 if pc
.HasFlag(FNB_BOTTOM
):
2357 dc
.DrawLine(rect
.x
, 2, rect
.x
+ rect
.width
, 2)
2359 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
, rect
.y
+ rect
.height
- 1)
2363 # We dont draw a rectangle for non selected tabs, but only
2364 # vertical line on the left
2365 dc
.SetPen(borderPen
)
2366 dc
.DrawLine(posx
+ tabWidth
, VERTICAL_BORDER_PADDING
+ 3, posx
+ tabWidth
, tabHeight
- 4)
2369 # -----------------------------------
2370 # Text and image drawing
2371 # -----------------------------------
2373 # Text drawing offset from the left border of the
2376 # The width of the images are 16 pixels
2377 padding
= pc
.GetParent().GetPadding()
2378 hasImage
= pc
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
2379 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2382 textOffset
= 2*pc
._pParent
._nPadding
+ 16
2384 textOffset
= pc
._pParent
._nPadding
2388 if tabIdx
!= pc
.GetSelection():
2390 # Set the text background to be like the vertical lines
2391 dc
.SetTextForeground(pc
._pParent
.GetNonActiveTabTextColour())
2395 imageXOffset
= textOffset
- 16 - padding
2396 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2397 posx
+ imageXOffset
, imageYCoord
,
2398 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2400 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2402 # draw 'x' on tab (if enabled)
2403 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2405 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2406 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2408 # take a bitmap from the position of the 'x' button (the x on tab button)
2409 # this bitmap will be used later to delete old buttons
2410 tabCloseButtonYCoord
= imageYCoord
2411 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2412 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2415 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2418 #------------------------------------------------------------------
2419 # Visual studio 2005 (VS8)
2420 #------------------------------------------------------------------
2421 class FNBRendererVC8(FNBRenderer
):
2423 This class handles the drawing of tabs using the I{VC8} renderer.
2427 """ Default class constructor. """
2429 FNBRenderer
.__init
__(self
)
2434 def DrawTabs(self
, pageContainer
, dc
):
2435 """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
2439 if "__WXMAC__" in wx
.PlatformInfo
:
2440 # Works well on MSW & GTK, however this lines should be skipped on MAC
2441 if not pc
._pagesInfoVec
or pc
._nFrom
>= len(pc
._pagesInfoVec
):
2445 # Get the text hight
2446 tabHeight
= self
.CalcTabHeight(pageContainer
)
2448 # Set the font for measuring the tab height
2449 normalFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2450 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2451 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2453 # Calculate the number of rows required for drawing the tabs
2454 rect
= pc
.GetClientRect()
2456 # Set the maximum client size
2457 pc
.SetSizeHints(self
.GetButtonsAreaLength(pc
), tabHeight
)
2458 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2461 backBrush
= wx
.Brush(pc
._tabAreaColor
)
2462 noselBrush
= wx
.Brush(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
))
2463 selBrush
= wx
.Brush(pc
._activeTabColor
)
2467 dc
.SetTextBackground(pc
.GetBackgroundColour())
2468 dc
.SetTextForeground(pc
._activeTextColor
)
2470 # If border style is set, set the pen to be border pen
2471 if pc
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
2472 dc
.SetPen(borderPen
)
2474 dc
.SetPen(wx
.TRANSPARENT_PEN
)
2476 lightFactor
= (pc
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0]
2478 # For VC8 style, we color the tab area in gradient coloring
2479 lightcolour
= LightColour(pc
._tabAreaColor
, lightFactor
)
2480 PaintStraightGradientBox(dc
, pc
.GetClientRect(), pc
._tabAreaColor
, lightcolour
)
2482 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2483 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
2485 # Take 3 bitmaps for the background for the buttons
2487 mem_dc
= wx
.MemoryDC()
2488 #---------------------------------------
2490 #---------------------------------------
2491 rect
= wx
.Rect(self
.GetXPos(pc
), 6, 16, 14)
2492 mem_dc
.SelectObject(self
._xBgBmp
)
2493 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2494 mem_dc
.SelectObject(wx
.NullBitmap
)
2496 #---------------------------------------
2498 #---------------------------------------
2499 rect
= wx
.Rect(self
.GetRightButtonPos(pc
), 6, 16, 14)
2500 mem_dc
.SelectObject(self
._rightBgBmp
)
2501 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2502 mem_dc
.SelectObject(wx
.NullBitmap
)
2504 #---------------------------------------
2506 #---------------------------------------
2507 rect
= wx
.Rect(self
.GetLeftButtonPos(pc
), 6, 16, 14)
2508 mem_dc
.SelectObject(self
._leftBgBmp
)
2509 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
2510 mem_dc
.SelectObject(wx
.NullBitmap
)
2512 # We always draw the bottom/upper line of the tabs
2513 # regradless the style
2514 dc
.SetPen(borderPen
)
2515 self
.DrawTabsLine(pc
, dc
)
2518 dc
.SetPen(borderPen
)
2521 dc
.SetFont(boldFont
)
2523 # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
2524 for i
in xrange(pc
._nFrom
):
2526 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
2527 pc
._pagesInfoVec
[i
].GetRegion().Clear()
2529 # Draw the visible tabs, in VC8 style, we draw them from right to left
2530 vTabsInfo
= self
.NumberTabsCanFit(pc
)
2536 for cur
in xrange(len(vTabsInfo
)-1, -1, -1):
2538 # 'i' points to the index of the currently drawn tab
2539 # in pc.GetPageInfoVector() vector
2541 dc
.SetPen(borderPen
)
2542 dc
.SetBrush((i
==pc
.GetSelection() and [selBrush
] or [noselBrush
])[0])
2544 # Now set the font to the correct font
2545 dc
.SetFont((i
==pc
.GetSelection() and [boldFont
] or [normalFont
])[0])
2547 # Add the padding to the tab width
2549 # +-----------------------------------------------------------+
2550 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
2551 # +-----------------------------------------------------------+
2553 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
2554 posx
= vTabsInfo
[cur
].x
2556 # By default we clean the tab region
2557 # incase we use the VC8 style which requires
2558 # the region, it will be filled by the function
2560 pc
._pagesInfoVec
[i
].GetRegion().Clear()
2562 # Clean the 'x' buttn on the tab
2563 # 'Clean' rectanlge is a rectangle with width or height
2564 # with values lower than or equal to 0
2565 pc
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
2568 # Incase we are drawing the active tab
2569 # we need to redraw so it will appear on top
2572 # when using the vc8 style, we keep the position of the active tab so we will draw it again later
2573 if i
== pc
.GetSelection() and pc
.HasFlag(FNB_VC8
):
2575 activeTabPosx
= posx
2576 activeTabWidth
= tabWidth
2577 activeTabHeight
= tabHeight
2581 self
.DrawTab(pc
, dc
, posx
, i
, tabWidth
, tabHeight
, pc
._nTabXButtonStatus
)
2583 # Restore the text forground
2584 dc
.SetTextForeground(pc
._activeTextColor
)
2586 # Update the tab position & size
2587 pc
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, VERTICAL_BORDER_PADDING
))
2588 pc
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
2590 # Incase we are in VC8 style, redraw the active tab (incase it is visible)
2591 if pc
.GetSelection() >= pc
._nFrom
and pc
.GetSelection() < pc
._nFrom
+ len(vTabsInfo
):
2593 self
.DrawTab(pc
, dc
, activeTabPosx
, pc
.GetSelection(), activeTabWidth
, activeTabHeight
, pc
._nTabXButtonStatus
)
2595 # Update all tabs that can not fit into the screen as non-visible
2596 for xx
in xrange(pc
._nFrom
+ len(vTabsInfo
), len(pc
._pagesInfoVec
)):
2598 pc
._pagesInfoVec
[xx
].SetPosition(wx
.Point(-1, -1))
2599 pc
._pagesInfoVec
[xx
].GetRegion().Clear()
2601 # Draw the left/right/close buttons
2603 self
.DrawLeftArrow(pc
, dc
)
2604 self
.DrawRightArrow(pc
, dc
)
2606 self
.DrawDropDownArrow(pc
, dc
)
2609 def DrawTab(self
, pageContainer
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
, btnStatus
):
2610 """ Draws a tab using VC8 style. """
2613 borderPen
= wx
.Pen(pc
._pParent
.GetBorderColour())
2614 tabPoints
= [wx
.Point() for ii
in xrange(8)]
2616 # If we draw the first tab or the active tab,
2617 # we draw a full tab, else we draw a truncated tab
2628 tabPoints
[0].x
= (pc
.HasFlag(FNB_BOTTOM
) and [posx
] or [posx
+self
._factor
])[0]
2629 tabPoints
[0].y
= (pc
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 3])[0]
2631 tabPoints
[1].x
= tabPoints
[0].x
+ tabHeight
- VERTICAL_BORDER_PADDING
- 3 - self
._factor
2632 tabPoints
[1].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
2634 tabPoints
[2].x
= tabPoints
[1].x
+ 4
2635 tabPoints
[2].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2637 tabPoints
[3].x
= tabPoints
[2].x
+ tabWidth
- 2
2638 tabPoints
[3].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
2640 tabPoints
[4].x
= tabPoints
[3].x
+ 1
2641 tabPoints
[4].y
= (pc
.HasFlag(FNB_BOTTOM
) and [tabPoints
[3].y
- 1] or [tabPoints
[3].y
+ 1])[0]
2643 tabPoints
[5].x
= tabPoints
[4].x
+ 1
2644 tabPoints
[5].y
= (pc
.HasFlag(FNB_BOTTOM
) and [(tabPoints
[4].y
- 1)] or [tabPoints
[4].y
+ 1])[0]
2646 tabPoints
[6].x
= tabPoints
[2].x
+ tabWidth
2647 tabPoints
[6].y
= tabPoints
[0].y
2649 tabPoints
[7].x
= tabPoints
[0].x
2650 tabPoints
[7].y
= tabPoints
[0].y
2652 pc
._pagesInfoVec
[tabIdx
].SetRegion(tabPoints
)
2656 dc
.SetBrush(wx
.Brush((tabIdx
== pc
.GetSelection() and [pc
._activeTabColor
] or [pc
._colorTo
])[0]))
2657 dc
.SetPen(wx
.Pen((tabIdx
== pc
.GetSelection() and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0]))
2658 dc
.DrawPolygon(tabPoints
)
2662 rect
= pc
.GetClientRect()
2664 if tabIdx
!= pc
.GetSelection() and not pc
.HasFlag(FNB_BOTTOM
):
2667 dc
.SetPen(wx
.Pen(pc
._pParent
.GetBorderColour()))
2669 curPen
= dc
.GetPen()
2672 dc
.DrawLine(posx
, lineY
, posx
+rect
.width
, lineY
)
2674 # Incase we are drawing the selected tab, we draw the border of it as well
2675 # but without the bottom (upper line incase of wxBOTTOM)
2676 if tabIdx
== pc
.GetSelection():
2678 borderPen
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
2679 dc
.SetPen(borderPen
)
2680 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
2681 dc
.DrawPolygon(tabPoints
)
2683 # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
2684 dc
.SetPen(wx
.WHITE_PEN
)
2685 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, tabPoints
[6].x
, tabPoints
[6].y
)
2687 self
.FillVC8GradientColour(pc
, dc
, tabPoints
, tabIdx
== pc
.GetSelection(), tabIdx
)
2689 # Draw a thin line to the right of the non-selected tab
2690 if tabIdx
!= pc
.GetSelection():
2692 dc
.SetPen(wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
)))
2693 dc
.DrawLine(tabPoints
[4].x
-1, tabPoints
[4].y
, tabPoints
[5].x
-1, tabPoints
[5].y
)
2694 dc
.DrawLine(tabPoints
[5].x
-1, tabPoints
[5].y
, tabPoints
[6].x
-1, tabPoints
[6].y
)
2696 # Text drawing offset from the left border of the
2699 # The width of the images are 16 pixels
2700 vc8ShapeLen
= tabHeight
- VERTICAL_BORDER_PADDING
- 2
2701 if pc
.TabHasImage(tabIdx
):
2702 textOffset
= 2*pc
._pParent
.GetPadding() + 16 + vc8ShapeLen
2704 textOffset
= pc
._pParent
.GetPadding() + vc8ShapeLen
2706 # Draw the image for the tab if any
2707 imageYCoord
= (pc
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
2709 if pc
.TabHasImage(tabIdx
):
2711 imageXOffset
= textOffset
- 16 - pc
._pParent
.GetPadding()
2712 pc
._ImageList
.Draw(pc
._pagesInfoVec
[tabIdx
].GetImageIndex(), dc
,
2713 posx
+ imageXOffset
, imageYCoord
,
2714 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
2716 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2718 # if selected tab, draw text in bold
2719 if tabIdx
== pc
.GetSelection():
2720 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2722 dc
.SetFont(boldFont
)
2723 dc
.DrawText(pc
.GetPageText(tabIdx
), posx
+ textOffset
, imageYCoord
)
2725 # draw 'x' on tab (if enabled)
2726 if pc
.HasFlag(FNB_X_ON_TAB
) and tabIdx
== pc
.GetSelection():
2728 textWidth
, textHeight
= dc
.GetTextExtent(pc
.GetPageText(tabIdx
))
2729 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
2731 # take a bitmap from the position of the 'x' button (the x on tab button)
2732 # this bitmap will be used later to delete old buttons
2733 tabCloseButtonYCoord
= imageYCoord
2734 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
2735 self
._tabXBgBmp
= self
._GetBitmap
(dc
, x_rect
, self
._tabXBgBmp
)
2737 self
.DrawTabX(pc
, dc
, x_rect
, tabIdx
, btnStatus
)
2740 def FillVC8GradientColour(self
, pageContainer
, dc
, tabPoints
, bSelectedTab
, tabIdx
):
2741 """ Fills a tab with a gradient shading. """
2743 # calculate gradient coefficients
2748 pc
._colorTo
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 0)
2749 pc
._colorFrom
= LightColour(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_3DFACE
), 60)
2751 col2
= pc
._pParent
.GetGradientColourTo()
2752 col1
= pc
._pParent
.GetGradientColourFrom()
2754 # If colorful tabs style is set, override the tab color
2755 if pc
.HasFlag(FNB_COLORFUL_TABS
):
2757 if not pc
._pagesInfoVec
[tabIdx
].GetColour():
2759 # First time, generate color, and keep it in the vector
2760 tabColor
= RandomColour()
2761 pc
._pagesInfoVec
[tabIdx
].SetColour(tabColor
)
2763 if pc
.HasFlag(FNB_BOTTOM
):
2765 col2
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50)
2766 col1
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80)
2770 col1
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 50)
2771 col2
= LightColour(pc
._pagesInfoVec
[tabIdx
].GetColour(), 80)
2773 size
= abs(tabPoints
[2].y
- tabPoints
[0].y
) - 1
2775 rf
, gf
, bf
= 0, 0, 0
2776 rstep
= float(col2
.Red() - col1
.Red())/float(size
)
2777 gstep
= float(col2
.Green() - col1
.Green())/float(size
)
2778 bstep
= float(col2
.Blue() - col1
.Blue())/float(size
)
2782 # If we are drawing the selected tab, we need also to draw a line
2783 # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
2784 # by drawing the rectangle with transparent brush
2785 # the line under the selected tab will be deleted by the drwaing loop
2787 self
.DrawTabsLine(pc
, dc
)
2791 if pc
.HasFlag(FNB_BOTTOM
):
2793 if y
> tabPoints
[0].y
+ size
:
2798 if y
< tabPoints
[0].y
- size
:
2801 currCol
= wx
.Colour(col1
.Red() + rf
, col1
.Green() + gf
, col1
.Blue() + bf
)
2803 dc
.SetPen((bSelectedTab
and [wx
.Pen(pc
._activeTabColor
)] or [wx
.Pen(currCol
)])[0])
2804 startX
= self
.GetStartX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())
2805 endX
= self
.GetEndX(tabPoints
, y
, pc
.GetParent().GetWindowStyleFlag())
2806 dc
.DrawLine(startX
, y
, endX
, y
)
2808 # Draw the border using the 'edge' point
2809 dc
.SetPen(wx
.Pen((bSelectedTab
and [wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [pc
._colorBorder
])[0]))
2811 dc
.DrawPoint(startX
, y
)
2812 dc
.DrawPoint(endX
, y
)
2814 # Progress the color
2819 if pc
.HasFlag(FNB_BOTTOM
):
2825 def GetStartX(self
, tabPoints
, y
, style
):
2826 """ Returns the x start position of a tab. """
2828 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
2830 # We check the 3 points to the left
2832 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
2839 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
+1].y
:
2842 x2
= tabPoints
[i
+1].x
2844 y2
= tabPoints
[i
+1].y
2852 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
+1].y
:
2855 x2
= tabPoints
[i
+1].x
2857 y2
= tabPoints
[i
+1].y
2862 return tabPoints
[2].x
2864 # According to the equation y = ax + b => x = (y-b)/a
2865 # We know the first 2 points
2870 a
= (y2
- y1
)/(x2
- x1
)
2872 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
2882 def GetEndX(self
, tabPoints
, y
, style
):
2883 """ Returns the x end position of a tab. """
2885 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
2887 # We check the 3 points to the left
2888 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
2893 for i
in xrange(7, 3, -1):
2895 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
-1].y
:
2898 x2
= tabPoints
[i
-1].x
2900 y2
= tabPoints
[i
-1].y
2906 for i
in xrange(7, 3, -1):
2908 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
-1].y
:
2911 x2
= tabPoints
[i
-1].x
2913 y2
= tabPoints
[i
-1].y
2918 return tabPoints
[3].x
2920 # According to the equation y = ax + b => x = (y-b)/a
2921 # We know the first 2 points
2927 a
= (y2
- y1
)/(x2
- x1
)
2928 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
2938 def NumberTabsCanFit(self
, pageContainer
, fr
=-1):
2939 """ Returns the number of tabs that can fit in the visible area. """
2943 rect
= pc
.GetClientRect()
2944 clientWidth
= rect
.width
2948 tabHeight
= self
.CalcTabHeight(pageContainer
)
2950 # The drawing starts from posx
2951 posx
= pc
._pParent
.GetPadding()
2956 for i
in xrange(fr
, len(pc
._pagesInfoVec
)):
2958 vc8glitch
= tabHeight
+ FNB_HEIGHT_SPACER
2959 tabWidth
= self
.CalcTabWidth(pageContainer
, i
, tabHeight
)
2961 if posx
+ tabWidth
+ vc8glitch
+ self
.GetButtonsAreaLength(pc
) >= clientWidth
:
2964 # Add a result to the returned vector
2965 tabRect
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
)
2966 vTabInfo
.append(tabRect
)
2969 posx
+= tabWidth
+ FNB_HEIGHT_SPACER
2974 # ---------------------------------------------------------------------------- #
2975 # Class FlatNotebook
2976 # ---------------------------------------------------------------------------- #
2978 class FlatNotebook(wx
.Panel
):
2980 Display one or more windows in a notebook.
2983 - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active
2984 page in the notebook is changing
2985 - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active
2986 page in the notebook has changed
2987 - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the
2989 - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the
2990 notebook has been closed
2991 - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
2992 clicks a tab in the notebook with the right mouse
2996 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
2997 style
=0, name
="FlatNotebook"):
2999 Default class constructor.
3001 All the parameters are as in wxPython class construction, except the
3002 'style': this can be assigned to whatever combination of FNB_* styles.
3006 self
._bForceSelection
= False
3009 style |
= wx
.TAB_TRAVERSAL
3012 self
._popupWin
= None
3014 wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style
)
3016 self
._pages
= PageContainer(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.DefaultSize
, style
)
3018 self
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
3024 """ Initializes all the class attributes. """
3026 self
._pages
._colorBorder
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
3028 self
._mainSizer
= wx
.BoxSizer(wx
.VERTICAL
)
3029 self
.SetSizer(self
._mainSizer
)
3031 # The child panels will inherit this bg color, so leave it at the default value
3032 #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
3034 # Set default page height
3035 dc
= wx
.ClientDC(self
)
3037 if "__WXGTK__" in wx
.PlatformInfo
:
3038 # For GTK it seems that we must do this steps in order
3039 # for the tabs will get the proper height on initialization
3040 # on MSW, preforming these steps yields wierd results
3041 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3042 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
3043 dc
.SetFont(boldFont
)
3045 height
= dc
.GetCharHeight()
3047 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
3049 if "__WXGTK__" in wx
.PlatformInfo
:
3052 self
._pages
.SetSizeHints(-1, tabHeight
)
3053 # Add the tab container to the sizer
3054 self
._mainSizer
.Insert(0, self
._pages
, 0, wx
.EXPAND
)
3055 self
._mainSizer
.Layout()
3057 self
._pages
._nFrom
= self
._nFrom
3058 self
._pDropTarget
= FNBDropTarget(self
)
3059 self
.SetDropTarget(self
._pDropTarget
)
3062 def SetActiveTabTextColour(self
, textColour
):
3063 """ Sets the text colour for the active tab. """
3065 self
._pages
._activeTextColor
= textColour
3068 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
3069 """ Handles the drop action from a DND operation. """
3071 return self
._pages
.OnDropTarget(x
, y
, nTabPage
, wnd_oldContainer
)
3074 def GetPreviousSelection(self
):
3075 """ Returns the previous selection. """
3077 return self
._pages
._iPreviousActivePage
3080 def AddPage(self
, page
, text
, select
=True, imageId
=-1):
3082 Add a page to the L{FlatNotebook}.
3084 @param page: Specifies the new page.
3085 @param text: Specifies the text for the new page.
3086 @param select: Specifies whether the page should be selected.
3087 @param imageId: Specifies the optional image index for the new page.
3090 True if successful, False otherwise.
3097 # reparent the window to us
3101 bSelected
= select
or len(self
._windows
) == 0
3107 # Check for selection and send events
3108 oldSelection
= self
._pages
._iActivePage
3109 tabIdx
= len(self
._windows
)
3111 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId())
3112 event
.SetSelection(tabIdx
)
3113 event
.SetOldSelection(oldSelection
)
3114 event
.SetEventObject(self
)
3116 if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed() or len(self
._windows
) == 0:
3119 curSel
= self
._pages
.GetSelection()
3121 if not self
._pages
.IsShown():
3124 self
._pages
.AddPage(text
, bSelected
, imageId
)
3125 self
._windows
.append(page
)
3129 # Check if a new selection was made
3134 # Remove the window from the main sizer
3135 self
._mainSizer
.Detach(self
._windows
[curSel
])
3136 self
._windows
[curSel
].Hide()
3138 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
3140 self
._mainSizer
.Insert(0, page
, 1, wx
.EXPAND
)
3144 # We leave a space of 1 pixel around the window
3145 self
._mainSizer
.Add(page
, 1, wx
.EXPAND
)
3147 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3148 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
3149 event
.SetOldSelection(oldSelection
)
3150 self
.GetEventHandler().ProcessEvent(event
)
3158 self
._mainSizer
.Layout()
3164 def SetImageList(self
, imageList
):
3165 """ Sets the image list for the page control. """
3167 self
._pages
.SetImageList(imageList
)
3170 def AssignImageList(self
, imageList
):
3171 """ Assigns the image list for the page control. """
3173 self
._pages
.AssignImageList(imageList
)
3176 def GetImageList(self
):
3177 """ Returns the associated image list. """
3179 return self
._pages
.GetImageList()
3182 def InsertPage(self
, indx
, page
, text
, select
=True, imageId
=-1):
3184 Inserts a new page at the specified position.
3186 @param indx: Specifies the position of the new page.
3187 @param page: Specifies the new page.
3188 @param text: Specifies the text for the new page.
3189 @param select: Specifies whether the page should be selected.
3190 @param imageId: Specifies the optional image index for the new page.
3193 True if successful, False otherwise.
3200 # reparent the window to us
3203 if not self
._windows
:
3205 self
.AddPage(page
, text
, select
, imageId
)
3209 bSelected
= select
or not self
._windows
3210 curSel
= self
._pages
.GetSelection()
3212 indx
= max(0, min(indx
, len(self
._windows
)))
3214 if indx
<= len(self
._windows
):
3216 self
._windows
.insert(indx
, page
)
3220 self
._windows
.append(page
)
3226 # Check for selection and send events
3227 oldSelection
= self
._pages
._iActivePage
3229 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetId())
3230 event
.SetSelection(indx
)
3231 event
.SetOldSelection(oldSelection
)
3232 event
.SetEventObject(self
)
3234 if not self
.GetEventHandler().ProcessEvent(event
) or event
.IsAllowed() or len(self
._windows
) == 0:
3237 self
._pages
.InsertPage(indx
, text
, bSelected
, imageId
)
3244 # Check if a new selection was made
3249 # Remove the window from the main sizer
3250 self
._mainSizer
.Detach(self
._windows
[curSel
])
3251 self
._windows
[curSel
].Hide()
3253 self
._pages
.SetSelection(indx
)
3255 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3256 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
3257 event
.SetOldSelection(oldSelection
)
3258 self
.GetEventHandler().ProcessEvent(event
)
3266 self
._mainSizer
.Layout()
3272 def SetSelection(self
, page
):
3274 Sets the selection for the given page.
3275 The call to this function generates the page changing events
3278 if page
>= len(self
._windows
) or not self
._windows
:
3281 # Support for disabed tabs
3282 if not self
._pages
.GetEnabled(page
) and len(self
._windows
) > 1 and not self
._bForceSelection
:
3285 curSel
= self
._pages
.GetSelection()
3287 # program allows the page change
3291 # Remove the window from the main sizer
3292 self
._mainSizer
.Detach(self
._windows
[curSel
])
3293 self
._windows
[curSel
].Hide()
3295 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
3297 self
._mainSizer
.Insert(0, self
._windows
[page
], 1, wx
.EXPAND
)
3301 # We leave a space of 1 pixel around the window
3302 self
._mainSizer
.Add(self
._windows
[page
], 1, wx
.EXPAND
)
3304 self
._windows
[page
].Show()
3307 self
._mainSizer
.Layout()
3309 if page
!= self
._pages
._iActivePage
:
3310 # there is a real page changing
3311 self
._pages
._iPreviousActivePage
= self
._pages
._iActivePage
3313 self
._pages
._iActivePage
= page
3314 self
._pages
.DoSetSelection(page
)
3317 def DeletePage(self
, page
):
3319 Deletes the specified page, and the associated window.
3320 The call to this function generates the page changing events.
3323 if page
>= len(self
._windows
) or page
< 0:
3326 # Fire a closing event
3327 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
3328 event
.SetSelection(page
)
3329 event
.SetEventObject(self
)
3330 self
.GetEventHandler().ProcessEvent(event
)
3332 # The event handler allows it?
3333 if not event
.IsAllowed():
3338 # Delete the requested page
3339 pageRemoved
= self
._windows
[page
]
3341 # If the page is the current window, remove it from the sizer
3343 if page
== self
._pages
.GetSelection():
3344 self
._mainSizer
.Detach(pageRemoved
)
3346 # Remove it from the array as well
3347 self
._windows
.pop(page
)
3349 # Now we can destroy it in wxWidgets use Destroy instead of delete
3350 pageRemoved
.Destroy()
3354 self
._pages
.DoDeletePage(page
)
3357 # Fire a closed event
3358 closedEvent
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, self
.GetId())
3359 closedEvent
.SetSelection(page
)
3360 closedEvent
.SetEventObject(self
)
3361 self
.GetEventHandler().ProcessEvent(closedEvent
)
3364 def DeleteAllPages(self
):
3365 """ Deletes all the pages. """
3367 if not self
._windows
:
3372 for page
in self
._windows
:
3378 # Clear the container of the tabs as well
3379 self
._pages
.DeleteAllPages()
3383 def GetCurrentPage(self
):
3384 """ Returns the currently selected notebook page or None. """
3386 sel
= self
._pages
.GetSelection()
3390 return self
._windows
[sel
]
3393 def GetPage(self
, page
):
3394 """ Returns the window at the given page position, or None. """
3396 if page
>= len(self
._windows
):
3399 return self
._windows
[page
]
3402 def GetPageIndex(self
, win
):
3403 """ Returns the index at which the window is found. """
3406 return self
._windows
.index(win
)
3411 def GetSelection(self
):
3412 """ Returns the currently selected page, or -1 if none was selected. """
3414 return self
._pages
.GetSelection()
3417 def AdvanceSelection(self
, forward
=True):
3419 Cycles through the tabs.
3420 The call to this function generates the page changing events.
3423 self
._pages
.AdvanceSelection(forward
)
3426 def GetPageCount(self
):
3427 """ Returns the number of pages in the L{FlatNotebook} control. """
3429 return self
._pages
.GetPageCount()
3432 def OnNavigationKey(self
, event
):
3433 """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
3435 if event
.IsWindowChange():
3436 if len(self
._windows
) == 0:
3439 if self
.HasFlag(FNB_SMART_TABS
):
3440 if not self
._popupWin
:
3441 self
._popupWin
= TabNavigatorWindow(self
)
3442 self
._popupWin
.SetReturnCode(wx
.ID_OK
)
3443 self
._popupWin
.ShowModal()
3444 self
._popupWin
.Destroy()
3445 self
._popupWin
= None
3447 # a dialog is already opened
3448 self
._popupWin
.OnNavigationKey(event
)
3452 self
.AdvanceSelection(event
.GetDirection())
3454 # pass to the parent
3455 if self
.GetParent():
3456 event
.SetCurrentFocus(self
)
3457 self
.GetParent().ProcessEvent(event
)
3460 def GetPageShapeAngle(self
, page_index
):
3461 """ Returns the angle associated to a tab. """
3463 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
3466 result
= self
._pages
._pagesInfoVec
[page_index
].GetTabAngle()
3470 def SetPageShapeAngle(self
, page_index
, angle
):
3471 """ Sets the angle associated to a tab. """
3473 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
3479 self
._pages
._pagesInfoVec
[page_index
].SetTabAngle(angle
)
3482 def SetAllPagesShapeAngle(self
, angle
):
3483 """ Sets the angle associated to all the tab. """
3488 for ii
in xrange(len(self
._pages
._pagesInfoVec
)):
3489 self
._pages
._pagesInfoVec
[ii
].SetTabAngle(angle
)
3494 def GetPageBestSize(self
):
3495 """ Return the page best size. """
3497 return self
._pages
.GetClientSize()
3500 def SetPageText(self
, page
, text
):
3501 """ Sets the text for the given page. """
3503 bVal
= self
._pages
.SetPageText(page
, text
)
3504 self
._pages
.Refresh()
3509 def SetPadding(self
, padding
):
3511 Sets the amount of space around each page's icon and label, in pixels.
3512 NB: only the horizontal padding is considered.
3515 self
._nPadding
= padding
.GetWidth()
3518 def GetTabArea(self
):
3519 """ Returns the associated page. """
3524 def GetPadding(self
):
3525 """ Returns the amount of space around each page's icon and label, in pixels. """
3527 return self
._nPadding
3530 def SetWindowStyleFlag(self
, style
):
3531 """ Sets the L{FlatNotebook} window style flags. """
3533 wx
.Panel
.SetWindowStyleFlag(self
, style
)
3534 renderer
= self
._pages
._mgr
.GetRenderer(self
.GetWindowStyleFlag())
3535 renderer
._tabHeight
= None
3539 # For changing the tab position (i.e. placing them top/bottom)
3540 # refreshing the tab container is not enough
3541 self
.SetSelection(self
._pages
._iActivePage
)
3543 if not self
._pages
.HasFlag(FNB_HIDE_ON_SINGLE_TAB
):
3544 #For Redrawing the Tabs once you remove the Hide tyle
3545 self
._pages
._ReShow
()
3548 def RemovePage(self
, page
):
3549 """ Deletes the specified page, without deleting the associated window. """
3551 if page
>= len(self
._windows
):
3554 # Fire a closing event
3555 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
3556 event
.SetSelection(page
)
3557 event
.SetEventObject(self
)
3558 self
.GetEventHandler().ProcessEvent(event
)
3560 # The event handler allows it?
3561 if not event
.IsAllowed():
3566 # Remove the requested page
3567 pageRemoved
= self
._windows
[page
]
3569 # If the page is the current window, remove it from the sizer
3571 if page
== self
._pages
.GetSelection():
3572 self
._mainSizer
.Detach(pageRemoved
)
3574 # Remove it from the array as well
3575 self
._windows
.pop(page
)
3578 self
._pages
.DoDeletePage(page
)
3583 def SetRightClickMenu(self
, menu
):
3584 """ Sets the popup menu associated to a right click on a tab. """
3586 self
._pages
._pRightClickMenu
= menu
3589 def GetPageText(self
, nPage
):
3590 """ Returns the tab caption. """
3592 return self
._pages
.GetPageText(nPage
)
3595 def SetGradientColours(self
, fr
, to
, border
):
3596 """ Sets the gradient colours for the tab. """
3598 self
._pages
._colorFrom
= fr
3599 self
._pages
._colorTo
= to
3600 self
._pages
._colorBorder
= border
3603 def SetGradientColourFrom(self
, fr
):
3604 """ Sets the starting colour for the gradient. """
3606 self
._pages
._colorFrom
= fr
3609 def SetGradientColourTo(self
, to
):
3610 """ Sets the ending colour for the gradient. """
3612 self
._pages
._colorTo
= to
3615 def SetGradientColourBorder(self
, border
):
3616 """ Sets the tab border colour. """
3618 self
._pages
._colorBorder
= border
3621 def GetGradientColourFrom(self
):
3622 """ Gets first gradient colour. """
3624 return self
._pages
._colorFrom
3627 def GetGradientColourTo(self
):
3628 """ Gets second gradient colour. """
3630 return self
._pages
._colorTo
3633 def GetGradientColourBorder(self
):
3634 """ Gets the tab border colour. """
3636 return self
._pages
._colorBorder
3639 def GetBorderColour(self
):
3640 """ Returns the border colour. """
3642 return self
._pages
._colorBorder
3645 def GetActiveTabTextColour(self
):
3646 """ Get the active tab text colour. """
3648 return self
._pages
._activeTextColor
3651 def SetPageImage(self
, page
, image
):
3653 Sets the image index for the given page. Image is an index into the
3654 image list which was set with SetImageList.
3657 self
._pages
.SetPageImage(page
, image
)
3660 def GetPageImage(self
, nPage
):
3662 Returns the image index for the given page. Image is an index into the
3663 image list which was set with SetImageList.
3666 return self
._pages
.GetPageImage(nPage
)
3669 def GetEnabled(self
, page
):
3670 """ Returns whether a tab is enabled or not. """
3672 return self
._pages
.GetEnabled(page
)
3675 def Enable(self
, page
, enabled
=True):
3676 """ Enables or disables a tab. """
3678 if page
>= len(self
._windows
):
3681 self
._windows
[page
].Enable(enabled
)
3682 self
._pages
.Enable(page
, enabled
)
3685 def GetNonActiveTabTextColour(self
):
3686 """ Returns the non active tabs text colour. """
3688 return self
._pages
._nonActiveTextColor
3691 def SetNonActiveTabTextColour(self
, color
):
3692 """ Sets the non active tabs text colour. """
3694 self
._pages
._nonActiveTextColor
= color
3697 def SetTabAreaColour(self
, color
):
3698 """ Sets the area behind the tabs colour. """
3700 self
._pages
._tabAreaColor
= color
3703 def GetTabAreaColour(self
):
3704 """ Returns the area behind the tabs colour. """
3706 return self
._pages
._tabAreaColor
3709 def SetActiveTabColour(self
, color
):
3710 """ Sets the active tab colour. """
3712 self
._pages
._activeTabColor
= color
3715 def GetActiveTabColour(self
):
3716 """ Returns the active tab colour. """
3718 return self
._pages
._activeTabColor
3721 # ---------------------------------------------------------------------------- #
3722 # Class PageContainer
3723 # Acts as a container for the pages you add to FlatNotebook
3724 # ---------------------------------------------------------------------------- #
3726 class PageContainer(wx
.Panel
):
3728 This class acts as a container for the pages you add to L{FlatNotebook}.
3731 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
,
3732 size
=wx
.DefaultSize
, style
=0):
3733 """ Default class constructor. """
3735 self
._ImageList
= None
3736 self
._iActivePage
= -1
3737 self
._pDropTarget
= None
3738 self
._nLeftClickZone
= FNB_NOWHERE
3739 self
._iPreviousActivePage
= -1
3741 self
._pRightClickMenu
= None
3742 self
._nXButtonStatus
= FNB_BTN_NONE
3743 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3744 self
._pParent
= parent
3745 self
._nRightButtonStatus
= FNB_BTN_NONE
3746 self
._nLeftButtonStatus
= FNB_BTN_NONE
3747 self
._nTabXButtonStatus
= FNB_BTN_NONE
3749 self
._pagesInfoVec
= []
3751 self
._colorTo
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_ACTIVECAPTION
)
3752 self
._colorFrom
= wx
.WHITE
3753 self
._activeTabColor
= wx
.WHITE
3754 self
._activeTextColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNTEXT
)
3755 self
._nonActiveTextColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNTEXT
)
3756 self
._tabAreaColor
= wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNFACE
)
3759 self
._isdragging
= False
3761 # Set default page height, this is done according to the system font
3762 memDc
= wx
.MemoryDC()
3763 memDc
.SelectObject(wx
.EmptyBitmap(1,1))
3765 if "__WXGTK__" in wx
.PlatformInfo
:
3766 boldFont
= wx
.SystemSettings_GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3767 boldFont
.SetWeight(wx
.BOLD
)
3768 memDc
.SetFont(boldFont
)
3770 height
= memDc
.GetCharHeight()
3771 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 10 pixels as padding
3773 wx
.Panel
.__init
__(self
, parent
, id, pos
, wx
.Size(size
.x
, tabHeight
),
3774 style|wx
.NO_BORDER|wx
.NO_FULL_REPAINT_ON_RESIZE
)
3776 self
._pDropTarget
= FNBDropTarget(self
)
3777 self
.SetDropTarget(self
._pDropTarget
)
3778 self
._mgr
= FNBRendererMgr()
3780 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
3781 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
3782 self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
)
3783 self
.Bind(wx
.EVT_LEFT_UP
, self
.OnLeftUp
)
3784 self
.Bind(wx
.EVT_RIGHT_DOWN
, self
.OnRightDown
)
3785 self
.Bind(wx
.EVT_MIDDLE_DOWN
, self
.OnMiddleDown
)
3786 self
.Bind(wx
.EVT_MOTION
, self
.OnMouseMove
)
3787 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
3788 self
.Bind(wx
.EVT_LEAVE_WINDOW
, self
.OnMouseLeave
)
3789 self
.Bind(wx
.EVT_ENTER_WINDOW
, self
.OnMouseEnterWindow
)
3790 self
.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnLeftDClick
)
3793 def OnEraseBackground(self
, event
):
3794 """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
3800 """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """
3802 self
.GetParent()._mainSizer
.Layout()
3806 def OnPaint(self
, event
):
3807 """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
3809 dc
= wx
.BufferedPaintDC(self
)
3810 renderer
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag())
3811 renderer
.DrawTabs(self
, dc
)
3813 if self
.HasFlag(FNB_HIDE_ON_SINGLE_TAB
) and len(self
._pagesInfoVec
) <= 1:
3815 self
.GetParent()._mainSizer
.Layout()
3819 def AddPage(self
, caption
, selected
=True, imgindex
=-1):
3821 Add a page to the L{FlatNotebook}.
3823 @param window: Specifies the new page.
3824 @param caption: Specifies the text for the new page.
3825 @param selected: Specifies whether the page should be selected.
3826 @param imgindex: Specifies the optional image index for the new page.
3829 True if successful, False otherwise.
3834 self
._iPreviousActivePage
= self
._iActivePage
3835 self
._iActivePage
= len(self
._pagesInfoVec
)
3837 # Create page info and add it to the vector
3838 pageInfo
= PageInfo(caption
, imgindex
)
3839 self
._pagesInfoVec
.append(pageInfo
)
3843 def InsertPage(self
, indx
, text
, selected
=True, imgindex
=-1):
3845 Inserts a new page at the specified position.
3847 @param indx: Specifies the position of the new page.
3848 @param page: Specifies the new page.
3849 @param text: Specifies the text for the new page.
3850 @param select: Specifies whether the page should be selected.
3851 @param imgindex: Specifies the optional image index for the new page.
3854 True if successful, False otherwise.
3859 self
._iPreviousActivePage
= self
._iActivePage
3860 self
._iActivePage
= len(self
._pagesInfoVec
)
3862 self
._pagesInfoVec
.insert(indx
, PageInfo(text
, imgindex
))
3868 def OnSize(self
, event
):
3869 """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
3871 # When resizing the control, try to fit to screen as many tabs as we can
3872 style
= self
.GetParent().GetWindowStyleFlag()
3873 renderer
= self
._mgr
.GetRenderer(style
)
3876 page
= self
.GetSelection()
3878 for fr
in xrange(self
._nFrom
):
3879 vTabInfo
= renderer
.NumberTabsCanFit(self
, fr
)
3880 if page
- fr
>= len(vTabInfo
):
3886 self
.Refresh() # Call on paint
3890 def OnMiddleDown(self
, event
):
3891 """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
3893 # Test if this style is enabled
3894 style
= self
.GetParent().GetWindowStyleFlag()
3896 if not style
& FNB_MOUSE_MIDDLE_CLOSES_TABS
:
3899 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3901 if where
== FNB_TAB
:
3902 self
.DeletePage(tabIdx
)
3907 def OnRightDown(self
, event
):
3908 """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
3910 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3912 if where
in [FNB_TAB
, FNB_TAB_X
]:
3914 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
3915 # Fire events and eventually (if allowed) change selection
3916 self
.FireEvent(tabIdx
)
3918 # send a message to popup a custom menu
3919 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, self
.GetParent().GetId())
3920 event
.SetSelection(tabIdx
)
3921 event
.SetOldSelection(self
._iActivePage
)
3922 event
.SetEventObject(self
.GetParent())
3923 self
.GetParent().GetEventHandler().ProcessEvent(event
)
3925 if self
._pRightClickMenu
:
3926 self
.PopupMenu(self
._pRightClickMenu
)
3931 def OnLeftDown(self
, event
):
3932 """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
3934 # Reset buttons status
3935 self
._nXButtonStatus
= FNB_BTN_NONE
3936 self
._nLeftButtonStatus
= FNB_BTN_NONE
3937 self
._nRightButtonStatus
= FNB_BTN_NONE
3938 self
._nTabXButtonStatus
= FNB_BTN_NONE
3939 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
3941 self
._nLeftClickZone
, tabIdx
= self
.HitTest(event
.GetPosition())
3943 if self
._nLeftClickZone
== FNB_DROP_DOWN_ARROW
:
3944 self
._nArrowDownButtonStatus
= FNB_BTN_PRESSED
3946 elif self
._nLeftClickZone
== FNB_LEFT_ARROW
:
3947 self
._nLeftButtonStatus
= FNB_BTN_PRESSED
3949 elif self
._nLeftClickZone
== FNB_RIGHT_ARROW
:
3950 self
._nRightButtonStatus
= FNB_BTN_PRESSED
3952 elif self
._nLeftClickZone
== FNB_X
:
3953 self
._nXButtonStatus
= FNB_BTN_PRESSED
3955 elif self
._nLeftClickZone
== FNB_TAB_X
:
3956 self
._nTabXButtonStatus
= FNB_BTN_PRESSED
3959 elif self
._nLeftClickZone
== FNB_TAB
:
3961 if self
._iActivePage
!= tabIdx
:
3963 # In case the tab is disabled, we dont allow to choose it
3964 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
3965 self
.FireEvent(tabIdx
)
3968 def RotateLeft(self
):
3970 if self
._nFrom
== 0:
3973 # Make sure that the button was pressed before
3974 if self
._nLeftButtonStatus
!= FNB_BTN_PRESSED
:
3977 self
._nLeftButtonStatus
= FNB_BTN_HOVER
3979 # We scroll left with bulks of 5
3980 scrollLeft
= self
.GetNumTabsCanScrollLeft()
3982 self
._nFrom
-= scrollLeft
3989 def RotateRight(self
):
3991 if self
._nFrom
>= len(self
._pagesInfoVec
) - 1:
3994 # Make sure that the button was pressed before
3995 if self
._nRightButtonStatus
!= FNB_BTN_PRESSED
:
3998 self
._nRightButtonStatus
= FNB_BTN_HOVER
4000 # Check if the right most tab is visible, if it is
4001 # don't rotate right anymore
4002 if self
._pagesInfoVec
[len(self
._pagesInfoVec
)-1].GetPosition() != wx
.Point(-1, -1):
4009 def OnLeftUp(self
, event
):
4010 """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
4012 # forget the zone that was initially clicked
4013 self
._nLeftClickZone
= FNB_NOWHERE
4015 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4017 if where
== FNB_LEFT_ARROW
:
4020 elif where
== FNB_RIGHT_ARROW
:
4023 elif where
== FNB_X
:
4025 # Make sure that the button was pressed before
4026 if self
._nXButtonStatus
!= FNB_BTN_PRESSED
:
4029 self
._nXButtonStatus
= FNB_BTN_HOVER
4031 self
.DeletePage(self
._iActivePage
)
4033 elif where
== FNB_TAB_X
:
4035 # Make sure that the button was pressed before
4036 if self
._nTabXButtonStatus
!= FNB_BTN_PRESSED
:
4039 self
._nTabXButtonStatus
= FNB_BTN_HOVER
4041 self
.DeletePage(self
._iActivePage
)
4043 elif where
== FNB_DROP_DOWN_ARROW
:
4045 # Make sure that the button was pressed before
4046 if self
._nArrowDownButtonStatus
!= FNB_BTN_PRESSED
:
4049 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4051 # Refresh the button status
4052 renderer
= self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag())
4053 dc
= wx
.ClientDC(self
)
4054 renderer
.DrawDropDownArrow(self
, dc
)
4056 self
.PopupTabsMenu()
4061 def HitTest(self
, pt
):
4063 HitTest method for L{PageContainer}.
4064 Returns the flag (if any) and the hit page (if any).
4067 style
= self
.GetParent().GetWindowStyleFlag()
4068 render
= self
._mgr
.GetRenderer(style
)
4070 fullrect
= self
.GetClientRect()
4071 btnLeftPos
= render
.GetLeftButtonPos(self
)
4072 btnRightPos
= render
.GetRightButtonPos(self
)
4073 btnXPos
= render
.GetXPos(self
)
4077 if len(self
._pagesInfoVec
) == 0:
4078 return FNB_NOWHERE
, tabIdx
4080 rect
= wx
.Rect(btnXPos
, 8, 16, 16)
4081 if rect
.Contains(pt
):
4082 return (style
& FNB_NO_X_BUTTON
and [FNB_NOWHERE
] or [FNB_X
])[0], tabIdx
4084 rect
= wx
.Rect(btnRightPos
, 8, 16, 16)
4085 if style
& FNB_DROPDOWN_TABS_LIST
:
4086 rect
= wx
.Rect(render
.GetDropArrowButtonPos(self
), 8, 16, 16)
4087 if rect
.Contains(pt
):
4088 return FNB_DROP_DOWN_ARROW
, tabIdx
4090 if rect
.Contains(pt
):
4091 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_RIGHT_ARROW
])[0], tabIdx
4093 rect
= wx
.Rect(btnLeftPos
, 8, 16, 16)
4094 if rect
.Contains(pt
):
4095 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_LEFT_ARROW
])[0], tabIdx
4097 # Test whether a left click was made on a tab
4100 for cur
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4102 pgInfo
= self
._pagesInfoVec
[cur
]
4104 if pgInfo
.GetPosition() == wx
.Point(-1, -1):
4107 if style
& FNB_X_ON_TAB
and cur
== self
.GetSelection():
4108 # 'x' button exists on a tab
4109 if self
._pagesInfoVec
[cur
].GetXRect().Contains(pt
):
4110 return FNB_TAB_X
, cur
4114 if self
._pagesInfoVec
[cur
].GetRegion().Contains(pt
.x
, pt
.y
):
4115 if bFoundMatch
or cur
== self
.GetSelection():
4123 tabRect
= wx
.Rect(pgInfo
.GetPosition().x
, pgInfo
.GetPosition().y
,
4124 pgInfo
.GetSize().x
, pgInfo
.GetSize().y
)
4126 if tabRect
.Contains(pt
):
4131 return FNB_TAB
, tabIdx
4133 if self
._isdragging
:
4134 # We are doing DND, so check also the region outside the tabs
4135 # try before the first tab
4136 pgInfo
= self
._pagesInfoVec
[0]
4137 tabRect
= wx
.Rect(0, pgInfo
.GetPosition().y
, pgInfo
.GetPosition().x
, self
.GetParent().GetSize().y
)
4138 if tabRect
.Contains(pt
):
4141 # try after the last tab
4142 pgInfo
= self
._pagesInfoVec
[-1]
4143 startpos
= pgInfo
.GetPosition().x
+pgInfo
.GetSize().x
4144 tabRect
= wx
.Rect(startpos
, pgInfo
.GetPosition().y
, fullrect
.width
-startpos
, self
.GetParent().GetSize().y
)
4146 if tabRect
.Contains(pt
):
4147 return FNB_TAB
, len(self
._pagesInfoVec
)
4150 return FNB_NOWHERE
, -1
4153 def SetSelection(self
, page
):
4154 """ Sets the selected page. """
4156 book
= self
.GetParent()
4157 book
.SetSelection(page
)
4158 self
.DoSetSelection(page
)
4161 def DoSetSelection(self
, page
):
4162 """ Does the actual selection of a page. """
4164 if page
< len(self
._pagesInfoVec
):
4166 da_page
= self
._pParent
.GetPage(page
)
4171 if not self
.IsTabVisible(page
):
4172 # Try to remove one tab from start and try again
4174 if not self
.CanFitToScreen(page
):
4176 if self
._nFrom
> page
:
4179 while self
._nFrom
< page
:
4181 if self
.CanFitToScreen(page
):
4187 def DeletePage(self
, page
):
4188 """ Delete the specified page from L{FlatNotebook}. """
4190 book
= self
.GetParent()
4191 book
.DeletePage(page
)
4195 def IsTabVisible(self
, page
):
4196 """ Returns whether a tab is visible or not. """
4198 iLastVisiblePage
= self
.GetLastVisibleTab()
4199 return page
<= iLastVisiblePage
and page
>= self
._nFrom
4202 def DoDeletePage(self
, page
):
4203 """ Does the actual page deletion. """
4205 # Remove the page from the vector
4206 book
= self
.GetParent()
4207 self
._pagesInfoVec
.pop(page
)
4209 # Thanks to Yiaanis AKA Mandrav
4210 if self
._iActivePage
>= page
:
4211 self
._iActivePage
= self
._iActivePage
- 1
4212 self
._iPreviousActivePage
= -1
4214 # The delete page was the last first on the array,
4215 # but the book still has more pages, so we set the
4216 # active page to be the first one (0)
4217 if self
._iActivePage
< 0 and len(self
._pagesInfoVec
) > 0:
4218 self
._iActivePage
= 0
4219 self
._iPreviousActivePage
= -1
4222 if self
._iActivePage
>= 0:
4224 book
._bForceSelection
= True
4226 # Check for selection and send event
4227 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
4228 event
.SetSelection(self
._iActivePage
)
4229 event
.SetOldSelection(self
._iPreviousActivePage
)
4230 event
.SetEventObject(self
.GetParent())
4232 book
.SetSelection(self
._iActivePage
)
4233 book
._bForceSelection
= False
4235 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4236 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
4237 event
.SetOldSelection(self
._iPreviousActivePage
)
4238 self
.GetParent().GetEventHandler().ProcessEvent(event
)
4240 if not self
._pagesInfoVec
:
4241 # Erase the page container drawings
4242 dc
= wx
.ClientDC(self
)
4246 def DeleteAllPages(self
):
4247 """ Deletes all the pages. """
4249 self
._iActivePage
= -1
4250 self
._iPreviousActivePage
= -1
4252 self
._pagesInfoVec
= []
4254 # Erase the page container drawings
4255 dc
= wx
.ClientDC(self
)
4259 def OnMouseMove(self
, event
):
4260 """ Handles the wx.EVT_MOTION for L{PageContainer}. """
4262 if self
._pagesInfoVec
and self
.IsShown():
4264 xButtonStatus
= self
._nXButtonStatus
4265 xTabButtonStatus
= self
._nTabXButtonStatus
4266 rightButtonStatus
= self
._nRightButtonStatus
4267 leftButtonStatus
= self
._nLeftButtonStatus
4268 dropDownButtonStatus
= self
._nArrowDownButtonStatus
4270 style
= self
.GetParent().GetWindowStyleFlag()
4272 self
._nXButtonStatus
= FNB_BTN_NONE
4273 self
._nRightButtonStatus
= FNB_BTN_NONE
4274 self
._nLeftButtonStatus
= FNB_BTN_NONE
4275 self
._nTabXButtonStatus
= FNB_BTN_NONE
4276 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4278 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4281 if event
.LeftIsDown():
4283 self
._nXButtonStatus
= (self
._nLeftClickZone
==FNB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4287 self
._nXButtonStatus
= FNB_BTN_HOVER
4289 elif where
== FNB_DROP_DOWN_ARROW
:
4290 if event
.LeftIsDown():
4292 self
._nArrowDownButtonStatus
= (self
._nLeftClickZone
==FNB_DROP_DOWN_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4296 self
._nArrowDownButtonStatus
= FNB_BTN_HOVER
4298 elif where
== FNB_TAB_X
:
4299 if event
.LeftIsDown():
4301 self
._nTabXButtonStatus
= (self
._nLeftClickZone
==FNB_TAB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4305 self
._nTabXButtonStatus
= FNB_BTN_HOVER
4307 elif where
== FNB_RIGHT_ARROW
:
4308 if event
.LeftIsDown():
4310 self
._nRightButtonStatus
= (self
._nLeftClickZone
==FNB_RIGHT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4314 self
._nRightButtonStatus
= FNB_BTN_HOVER
4316 elif where
== FNB_LEFT_ARROW
:
4317 if event
.LeftIsDown():
4319 self
._nLeftButtonStatus
= (self
._nLeftClickZone
==FNB_LEFT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
4323 self
._nLeftButtonStatus
= FNB_BTN_HOVER
4325 elif where
== FNB_TAB
:
4326 # Call virtual method for showing tooltip
4327 self
.ShowTabTooltip(tabIdx
)
4329 if not self
.GetEnabled(tabIdx
):
4330 # Set the cursor to be 'No-entry'
4331 wx
.SetCursor(wx
.StockCursor(wx
.CURSOR_NO_ENTRY
))
4333 # Support for drag and drop
4334 if event
.Dragging() and not (style
& FNB_NODRAG
):
4336 self
._isdragging
= True
4337 draginfo
= FNBDragInfo(self
, tabIdx
)
4338 drginfo
= cPickle
.dumps(draginfo
)
4339 dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
4340 dataobject
.SetData(drginfo
)
4341 dragSource
= FNBDropSource(self
)
4342 dragSource
.SetData(dataobject
)
4343 dragSource
.DoDragDrop(wx
.Drag_DefaultMove
)
4345 bRedrawX
= self
._nXButtonStatus
!= xButtonStatus
4346 bRedrawRight
= self
._nRightButtonStatus
!= rightButtonStatus
4347 bRedrawLeft
= self
._nLeftButtonStatus
!= leftButtonStatus
4348 bRedrawTabX
= self
._nTabXButtonStatus
!= xTabButtonStatus
4349 bRedrawDropArrow
= self
._nArrowDownButtonStatus
!= dropDownButtonStatus
4351 render
= self
._mgr
.GetRenderer(style
)
4353 if (bRedrawX
or bRedrawRight
or bRedrawLeft
or bRedrawTabX
or bRedrawDropArrow
):
4355 dc
= wx
.ClientDC(self
)
4359 render
.DrawX(self
, dc
)
4363 render
.DrawLeftArrow(self
, dc
)
4367 render
.DrawRightArrow(self
, dc
)
4371 render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[tabIdx
].GetXRect(), tabIdx
, self
._nTabXButtonStatus
)
4373 if bRedrawDropArrow
:
4375 render
.DrawDropDownArrow(self
, dc
)
4380 def GetLastVisibleTab(self
):
4381 """ Returns the last visible tab. """
4388 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4390 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
4396 def GetNumTabsCanScrollLeft(self
):
4397 """ Returns the number of tabs than can be scrolled left. """
4399 if self
._nFrom
- 1 >= 0:
4405 def IsDefaultTabs(self
):
4406 """ Returns whether a tab has a default style. """
4408 style
= self
.GetParent().GetWindowStyleFlag()
4409 res
= (style
& FNB_VC71
) or (style
& FNB_FANCY_TABS
) or (style
& FNB_VC8
)
4413 def AdvanceSelection(self
, bForward
=True):
4415 Cycles through the tabs.
4416 The call to this function generates the page changing events.
4419 nSel
= self
.GetSelection()
4424 nMax
= self
.GetPageCount() - 1
4427 newSelection
= (nSel
== nMax
and [0] or [nSel
+ 1])[0]
4429 newSelection
= (nSel
== 0 and [nMax
] or [nSel
- 1])[0]
4431 if not self
._pagesInfoVec
[newSelection
].GetEnabled():
4434 self
.FireEvent(newSelection
)
4437 def OnMouseLeave(self
, event
):
4438 """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
4440 self
._nLeftButtonStatus
= FNB_BTN_NONE
4441 self
._nXButtonStatus
= FNB_BTN_NONE
4442 self
._nRightButtonStatus
= FNB_BTN_NONE
4443 self
._nTabXButtonStatus
= FNB_BTN_NONE
4444 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4446 style
= self
.GetParent().GetWindowStyleFlag()
4447 render
= self
._mgr
.GetRenderer(style
)
4449 dc
= wx
.ClientDC(self
)
4451 render
.DrawX(self
, dc
)
4452 render
.DrawLeftArrow(self
, dc
)
4453 render
.DrawRightArrow(self
, dc
)
4455 selection
= self
.GetSelection()
4461 if not self
.IsTabVisible(selection
):
4462 if selection
== len(self
._pagesInfoVec
) - 1:
4463 if not self
.CanFitToScreen(selection
):
4470 render
.DrawTabX(self
, dc
, self
._pagesInfoVec
[selection
].GetXRect(), selection
, self
._nTabXButtonStatus
)
4475 def OnMouseEnterWindow(self
, event
):
4476 """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
4478 self
._nLeftButtonStatus
= FNB_BTN_NONE
4479 self
._nXButtonStatus
= FNB_BTN_NONE
4480 self
._nRightButtonStatus
= FNB_BTN_NONE
4481 self
._nLeftClickZone
= FNB_BTN_NONE
4482 self
._nArrowDownButtonStatus
= FNB_BTN_NONE
4487 def ShowTabTooltip(self
, tabIdx
):
4488 """ Shows a tab tooltip. """
4490 pWindow
= self
._pParent
.GetPage(tabIdx
)
4493 pToolTip
= pWindow
.GetToolTip()
4494 if pToolTip
and pToolTip
.GetWindow() == pWindow
:
4495 self
.SetToolTipString(pToolTip
.GetTip())
4498 def SetPageImage(self
, page
, imgindex
):
4499 """ Sets the image index associated to a page. """
4501 if page
< len(self
._pagesInfoVec
):
4503 self
._pagesInfoVec
[page
].SetImageIndex(imgindex
)
4507 def GetPageImage(self
, page
):
4508 """ Returns the image index associated to a page. """
4510 if page
< len(self
._pagesInfoVec
):
4512 return self
._pagesInfoVec
[page
].GetImageIndex()
4517 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
4518 """ Handles the drop action from a DND operation. """
4520 # Disable drag'n'drop for disabled tab
4521 if not wnd_oldContainer
._pagesInfoVec
[nTabPage
].GetEnabled():
4522 return wx
.DragCancel
4524 self
._isdragging
= True
4525 oldContainer
= wnd_oldContainer
4528 where
, nIndex
= self
.HitTest(wx
.Point(x
, y
))
4530 oldNotebook
= oldContainer
.GetParent()
4531 newNotebook
= self
.GetParent()
4533 if oldNotebook
== newNotebook
:
4537 if where
== FNB_TAB
:
4538 self
.MoveTabPage(nTabPage
, nIndex
)
4540 elif self
.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND
:
4542 if wx
.Platform
in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]:
4545 window
= oldNotebook
.GetPage(nTabPage
)
4548 where
, nIndex
= newNotebook
._pages
.HitTest(wx
.Point(x
, y
))
4549 caption
= oldContainer
.GetPageText(nTabPage
)
4550 imageindex
= oldContainer
.GetPageImage(nTabPage
)
4551 oldNotebook
.RemovePage(nTabPage
)
4552 window
.Reparent(newNotebook
)
4556 bmp
= oldNotebook
.GetImageList().GetIcon(imageindex
)
4557 newImageList
= newNotebook
.GetImageList()
4559 if not newImageList
:
4560 xbmp
, ybmp
= bmp
.GetWidth(), bmp
.GetHeight()
4561 newImageList
= wx
.ImageList(xbmp
, ybmp
)
4564 imageindex
= newImageList
.GetImageCount()
4566 newImageList
.AddIcon(bmp
)
4567 newNotebook
.SetImageList(newImageList
)
4569 newNotebook
.InsertPage(nIndex
, window
, caption
, True, imageindex
)
4571 self
._isdragging
= False
4576 def MoveTabPage(self
, nMove
, nMoveTo
):
4577 """ Moves a tab inside the same L{FlatNotebook}. """
4579 if nMove
== nMoveTo
:
4582 elif nMoveTo
< len(self
._pParent
._windows
):
4583 nMoveTo
= nMoveTo
+ 1
4585 self
._pParent
.Freeze()
4587 # Remove the window from the main sizer
4588 nCurSel
= self
._pParent
._pages
.GetSelection()
4589 self
._pParent
._mainSizer
.Detach(self
._pParent
._windows
[nCurSel
])
4590 self
._pParent
._windows
[nCurSel
].Hide()
4592 pWindow
= self
._pParent
._windows
[nMove
]
4593 self
._pParent
._windows
.pop(nMove
)
4594 self
._pParent
._windows
.insert(nMoveTo
-1, pWindow
)
4596 pgInfo
= self
._pagesInfoVec
[nMove
]
4598 self
._pagesInfoVec
.pop(nMove
)
4599 self
._pagesInfoVec
.insert(nMoveTo
- 1, pgInfo
)
4601 # Add the page according to the style
4602 pSizer
= self
._pParent
._mainSizer
4603 style
= self
.GetParent().GetWindowStyleFlag()
4605 if style
& FNB_BOTTOM
:
4607 pSizer
.Insert(0, pWindow
, 1, wx
.EXPAND
)
4611 # We leave a space of 1 pixel around the window
4612 pSizer
.Add(pWindow
, 1, wx
.EXPAND
)
4617 self
._iActivePage
= nMoveTo
- 1
4618 self
._iPreviousActivePage
= -1
4619 self
.DoSetSelection(self
._iActivePage
)
4621 self
._pParent
.Thaw()
4624 def CanFitToScreen(self
, page
):
4625 """ Returns wheter a tab can fit in the left space in the screen or not. """
4627 # Incase the from is greater than page,
4628 # we need to reset the self._nFrom, so in order
4629 # to force the caller to do so, we return false
4630 if self
._nFrom
> page
:
4633 style
= self
.GetParent().GetWindowStyleFlag()
4634 render
= self
._mgr
.GetRenderer(style
)
4636 vTabInfo
= render
.NumberTabsCanFit(self
)
4638 if page
- self
._nFrom
>= len(vTabInfo
):
4644 def GetNumOfVisibleTabs(self
):
4645 """ Returns the number of visible tabs. """
4648 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
4649 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
4656 def GetEnabled(self
, page
):
4657 """ Returns whether a tab is enabled or not. """
4659 if page
>= len(self
._pagesInfoVec
):
4660 return True # Seems strange, but this is the default
4662 return self
._pagesInfoVec
[page
].GetEnabled()
4665 def Enable(self
, page
, enabled
=True):
4666 """ Enables or disables a tab. """
4668 if page
>= len(self
._pagesInfoVec
):
4671 self
._pagesInfoVec
[page
].Enable(enabled
)
4674 def GetSingleLineBorderColour(self
):
4675 """ Returns the colour for the single line border. """
4677 if self
.HasFlag(FNB_FANCY_TABS
):
4678 return self
._colorFrom
4683 def HasFlag(self
, flag
):
4684 """ Returns whether a flag is present in the L{FlatNotebook} style. """
4686 style
= self
.GetParent().GetWindowStyleFlag()
4687 res
= (style
& flag
and [True] or [False])[0]
4691 def ClearFlag(self
, flag
):
4692 """ Deletes a flag from the L{FlatNotebook} style. """
4694 style
= self
.GetParent().GetWindowStyleFlag()
4696 self
.SetWindowStyleFlag(style
)
4699 def TabHasImage(self
, tabIdx
):
4700 """ Returns whether a tab has an associated image index or not. """
4703 return self
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
4708 def OnLeftDClick(self
, event
):
4709 """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
4711 where
, tabIdx
= self
.HitTest(event
.GetPosition())
4713 if where
== FNB_RIGHT_ARROW
:
4716 elif where
== FNB_LEFT_ARROW
:
4719 elif self
.HasFlag(FNB_DCLICK_CLOSES_TABS
):
4721 if where
== FNB_TAB
:
4722 self
.DeletePage(tabIdx
)
4729 def PopupTabsMenu(self
):
4730 """ Pops up the menu activated with the drop down arrow in the navigation area. """
4732 popupMenu
= wx
.Menu()
4734 for i
in xrange(len(self
._pagesInfoVec
)):
4735 pi
= self
._pagesInfoVec
[i
]
4736 item
= wx
.MenuItem(popupMenu
, i
, pi
.GetCaption(), pi
.GetCaption(), wx
.ITEM_NORMAL
)
4737 self
.Bind(wx
.EVT_MENU
, self
.OnTabMenuSelection
, item
)
4739 # This code is commented, since there is an alignment problem with wx2.6.3 & Menus
4740 # if self.TabHasImage(ii):
4741 # item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] );
4743 popupMenu
.AppendItem(item
)
4744 item
.Enable(pi
.GetEnabled())
4746 self
.PopupMenu(popupMenu
)
4749 def OnTabMenuSelection(self
, event
):
4750 """ Handles the wx.EVT_MENU event for L{PageContainer}. """
4752 selection
= event
.GetId()
4753 self
.FireEvent(selection
)
4756 def FireEvent(self
, selection
):
4758 Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
4759 called from other methods (from menu selection or Smart Tabbing).
4763 if selection
== self
._iActivePage
:
4764 # No events for the same selection
4767 oldSelection
= self
._iActivePage
4769 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
4770 event
.SetSelection(selection
)
4771 event
.SetOldSelection(oldSelection
)
4772 event
.SetEventObject(self
.GetParent())
4774 if not self
.GetParent().GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
4776 self
.SetSelection(selection
)
4778 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4779 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
4780 event
.SetOldSelection(oldSelection
)
4781 self
.GetParent().GetEventHandler().ProcessEvent(event
)
4784 def SetImageList(self
, imglist
):
4785 """ Sets the image list for the page control. """
4787 self
._ImageList
= imglist
4790 def AssignImageList(self
, imglist
):
4791 """ Assigns the image list for the page control. """
4793 self
._ImageList
= imglist
4796 def GetImageList(self
):
4797 """ Returns the image list for the page control. """
4799 return self
._ImageList
4802 def GetSelection(self
):
4803 """ Returns the current selected page. """
4805 return self
._iActivePage
4808 def GetPageCount(self
):
4809 """ Returns the number of tabs in the L{FlatNotebook} control. """
4811 return len(self
._pagesInfoVec
)
4814 def GetPageText(self
, page
):
4815 """ Returns the tab caption of the page. """
4817 return self
._pagesInfoVec
[page
].GetCaption()
4820 def SetPageText(self
, page
, text
):
4821 """ Sets the tab caption of the page. """
4823 self
._pagesInfoVec
[page
].SetCaption(text
)
4827 def DrawDragHint(self
):
4828 """ Draws small arrow at the place that the tab will be placed. """
4830 # get the index of tab that will be replaced with the dragged tab
4831 pt
= wx
.GetMousePosition()
4832 client_pt
= self
.ScreenToClient(pt
)
4833 where
, tabIdx
= self
.HitTest(client_pt
)
4834 self
._mgr
.GetRenderer(self
.GetParent().GetWindowStyleFlag()).DrawDragHint(self
, tabIdx
)