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: 05 Oct 2006, 20.00 GMT
17 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
20 # andrea.gavana@gmail.com
23 # Or, Obviously, To The wxPython Mailing List!!!
27 # --------------------------------------------------------------------------- #
30 The FlatNotebook is a full implementation of the wx.Notebook, and designed to be
31 a drop-in replacement for wx.Notebook. The API functions are similar so one can
32 expect the function to behave in the same way.
35 - The buttons are highlighted a la Firefox style
36 - The scrolling is done for bulks of tabs (so, the scrolling is faster and better)
37 - The buttons area is never overdrawn by tabs (unlike many other implementations I saw)
38 - It is a generic control
39 - Currently there are 4 differnt styles - VC8, VC 71, Standard and Fancy.
40 - Mouse middle click can be used to close tabs
41 - A function to add right click menu for tabs (simple as SetRightClickMenu)
42 - All styles has bottom style as well (they can be drawn in the bottom of screen)
43 - An option to hide 'X' button or navigation buttons (separately)
44 - Gradient coloring of the selected tabs and border
45 - Support for drag 'n' drop of tabs, both in the same notebook or to another notebook
46 - Possibility to have closing button on the active tab directly
47 - Support for disabled tabs
48 - Colours for active/inactive tabs, and captions
49 - Background of tab area can be painted in gradient (VC8 style only)
50 - Colourful tabs - a random gentle colour is generated for each new tab (very cool,
58 The following example shows a simple implementation that uses FlatNotebook inside
62 import wx.lib.flatnotebook as FNB
64 class MyFrame(wx.Frame):
66 def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, size=(800, 600),
67 style=wx.DEFAULT_FRAME_STYLE | wx.MAXIMIZE |wx.NO_FULL_REPAINT_ON_RESIZE):
69 wx.Frame.__init__(self, parent, id, title, pos, size, style)
71 mainSizer = wx.BoxSizer(wx.VERTICAL)
72 self.SetSizer(mainSizer)
74 bookStyle = FNB.FNB_TABS_BORDER_SIMPLE
76 self.book = FNB.StyledNotebook(self, wx.ID_ANY, style=bookStyle)
77 mainSizer.Add(self.book, 1, wx.EXPAND)
79 # Add some pages to the notebook
82 text = wx.TextCtrl(self.book, -1, "Book Page 1", style=wx.TE_MULTILINE)
83 self.book.AddPage(text, "Book Page 1")
85 text = wx.TextCtrl(self.book, -1, "Book Page 2", style=wx.TE_MULTILINE)
86 self.book.AddPage(text, "Book Page 2")
93 # our normal wxApp-derived class, as usual
95 app = wx.PySimpleApp()
98 app.SetTopWindow(frame)
106 FlatNotebook Is Freeware And Distributed Under The wxPython License.
108 Latest Revision: Andrea Gavana @ 05 Oct 2006, 20.00 GMT
119 # Check for the new method in 2.7 (not present in 2.6.3.3)
120 if wx
.VERSION_STRING
< "2.7":
121 wx
.Rect
.Contains
= lambda self
, point
: wx
.Rect
.Inside(self
, point
)
123 FNB_HEIGHT_SPACER
= 10
125 # Use Visual Studio 2003 (VC7.1) Style for tabs
128 # Use fancy style - square tabs filled with gradient coloring
131 # Draw thin border around the page
132 FNB_TABS_BORDER_SIMPLE
= 4
134 # Do not display the 'X' button
137 # Do not display the Right / Left arrows
138 FNB_NO_NAV_BUTTONS
= 16
140 # Use the mouse middle button for cloing tabs
141 FNB_MOUSE_MIDDLE_CLOSES_TABS
= 32
143 # Place tabs at bottom - the default is to place them
147 # Disable dragging of tabs
150 # Use Visual Studio 2005 (VC8) Style for tabs
154 # Note: This style is not supported on VC8 style
157 FNB_BACKGROUND_GRADIENT
= 1024
159 FNB_COLORFUL_TABS
= 2048
161 # Style to close tab using double click - styles 1024, 2048 are reserved
162 FNB_DCLICK_CLOSES_TABS
= 4096
164 VERTICAL_BORDER_PADDING
= 4
166 # Button size is a 16x16 xpm bitmap
171 MASK_COLOR
= wx
.Color(0, 128, 128)
180 FNB_TAB
= 1 # On a tab
181 FNB_X
= 2 # On the X button
182 FNB_TAB_X
= 3 # On the 'X' button (tab's X button)
183 FNB_LEFT_ARROW
= 4 # On the rotate left arrow button
184 FNB_RIGHT_ARROW
= 5 # On the rotate right arrow button
185 FNB_NOWHERE
= 0 # Anywhere else
187 FNB_DEFAULT_STYLE
= FNB_MOUSE_MIDDLE_CLOSES_TABS
189 # FlatNotebook Events:
190 # wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page;
191 # wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch
192 # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call
193 # event.Skip() In Your Event Handler;
194 # wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But
195 # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip()
196 # In Your Event Handler;
197 # wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed.
198 # wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab.
200 wxEVT_FLATNOTEBOOK_PAGE_CHANGED
= wx
.NewEventType()
201 wxEVT_FLATNOTEBOOK_PAGE_CHANGING
= wx
.NewEventType()
202 wxEVT_FLATNOTEBOOK_PAGE_CLOSING
= wx
.NewEventType()
203 wxEVT_FLATNOTEBOOK_PAGE_CLOSED
= wx
.NewEventType()
204 wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
= wx
.NewEventType()
206 #-----------------------------------#
208 #-----------------------------------#
210 EVT_FLATNOTEBOOK_PAGE_CHANGED
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
, 1)
211 EVT_FLATNOTEBOOK_PAGE_CHANGING
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, 1)
212 EVT_FLATNOTEBOOK_PAGE_CLOSING
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, 1)
213 EVT_FLATNOTEBOOK_PAGE_CLOSED
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, 1)
214 EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
= wx
.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, 1)
216 # Some icons in XPM format
218 left_arrow_disabled_xpm
= [
246 x_button_pressed_xpm
= [
303 x_button_hilite_xpm
= [
359 left_arrow_pressed_xpm
= [
387 left_arrow_hilite_xpm
= [
415 right_arrow_disabled_xpm
= [
443 right_arrow_hilite_xpm
= [
471 right_arrow_pressed_xpm
= [
530 def LightColour(color
, percent
):
531 """ Brighten input colour by percent. """
535 rd
= end_color
.Red() - color
.Red()
536 gd
= end_color
.Green() - color
.Green()
537 bd
= end_color
.Blue() - color
.Blue()
541 # We take the percent way of the color from color -. white
543 r
= color
.Red() + ((i
*rd
*100)/high
)/100
544 g
= color
.Green() + ((i
*gd
*100)/high
)/100
545 b
= color
.Blue() + ((i
*bd
*100)/high
)/100
546 return wx
.Color(r
, g
, b
)
549 def PaintStraightGradientBox(dc
, rect
, startColor
, endColor
, vertical
=True):
550 """ Draws a gradient colored box from startColor to endColor. """
552 rd
= endColor
.Red() - startColor
.Red()
553 gd
= endColor
.Green() - startColor
.Green()
554 bd
= endColor
.Blue() - startColor
.Blue()
556 # Save the current pen and brush
557 savedPen
= dc
.GetPen()
558 savedBrush
= dc
.GetBrush()
561 high
= rect
.GetHeight()-1
563 high
= rect
.GetWidth()-1
568 for i
in xrange(high
+1):
570 r
= startColor
.Red() + ((i
*rd
*100)/high
)/100
571 g
= startColor
.Green() + ((i
*gd
*100)/high
)/100
572 b
= startColor
.Blue() + ((i
*bd
*100)/high
)/100
574 p
= wx
.Pen(wx
.Color(r
, g
, b
))
578 dc
.DrawLine(rect
.x
, rect
.y
+i
, rect
.x
+rect
.width
, rect
.y
+i
)
580 dc
.DrawLine(rect
.x
+i
, rect
.y
, rect
.x
+i
, rect
.y
+rect
.height
)
582 # Restore the pen and brush
584 dc
.SetBrush(savedBrush
)
588 """ Creates a random colour. """
590 r
= random
.randint(0, 255) # Random value betweem 0-255
591 g
= random
.randint(0, 255) # Random value betweem 0-255
592 b
= random
.randint(0, 255) # Random value betweem 0-255
594 return wx
.Color(r
, g
, b
)
597 # ---------------------------------------------------------------------------- #
599 # Stores All The Information To Allow Drag And Drop Between Different
601 # ---------------------------------------------------------------------------- #
605 _map
= weakref
.WeakValueDictionary()
607 def __init__(self
, container
, pageindex
):
608 """ Default class constructor. """
610 self
._id
= id(container
)
611 FNBDragInfo
._map
[self
._id
] = container
612 self
._pageindex
= pageindex
615 def GetContainer(self
):
616 """ Returns the FlatNotebook page (usually a panel). """
618 return FNBDragInfo
._map
.get(self
._id
, None)
621 def GetPageIndex(self
):
622 """ Returns the page index associated with a page. """
624 return self
._pageindex
627 # ---------------------------------------------------------------------------- #
628 # Class FNBDropTarget
629 # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between
630 # Different FlatNotebooks.
631 # ---------------------------------------------------------------------------- #
633 class FNBDropTarget(wx
.DropTarget
):
635 def __init__(self
, parent
):
636 """ Default class constructor. """
638 wx
.DropTarget
.__init
__(self
)
640 self
._parent
= parent
641 self
._dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
642 self
.SetDataObject(self
._dataobject
)
645 def OnData(self
, x
, y
, dragres
):
646 """ Handles the OnData() method to call the real DnD routine. """
648 if not self
.GetData():
651 draginfo
= self
._dataobject
.GetData()
652 drginfo
= cPickle
.loads(draginfo
)
654 return self
._parent
.OnDropTarget(x
, y
, drginfo
.GetPageIndex(), drginfo
.GetContainer())
657 # ---------------------------------------------------------------------------- #
659 # Contains parameters for every FlatNotebook page
660 # ---------------------------------------------------------------------------- #
664 def __init__(self
, caption
="", imageindex
=-1, tabangle
=0, enabled
=True):
666 Default Class Constructor.
669 - caption: the tab caption;
670 - imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
671 - tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
672 - enabled: sets enabled or disabled the tab.
675 self
._strCaption
= caption
676 self
._TabAngle
= tabangle
677 self
._ImageIndex
= imageindex
678 self
._bEnabled
= enabled
679 self
._pos
= wx
.Point(-1, -1)
680 self
._size
= wx
.Size(-1, -1)
681 self
._region
= wx
.Region()
682 self
._xRect
= wx
.Rect()
686 def SetCaption(self
, value
):
687 """ Sets the tab caption. """
689 self
._strCaption
= value
692 def GetCaption(self
):
693 """ Returns the tab caption. """
695 return self
._strCaption
698 def SetPosition(self
, value
):
699 """ Sets the tab position. """
704 def GetPosition(self
):
705 """ Returns the tab position. """
710 def SetSize(self
, value
):
711 """ Sets the tab size. """
717 """ Returns the tab size. """
722 def SetTabAngle(self
, value
):
723 """ Sets the tab header angle (0 <= tab <= 15 degrees). """
725 self
._TabAngle
= min(45, value
)
728 def GetTabAngle(self
):
729 """ Returns the tab angle. """
731 return self
._TabAngle
734 def SetImageIndex(self
, value
):
735 """ Sets the tab image index. """
737 self
._ImageIndex
= value
740 def GetImageIndex(self
):
741 """ Returns the tab umage index. """
743 return self
._ImageIndex
746 def GetEnabled(self
):
747 """ Returns whether the tab is enabled or not. """
749 return self
._bEnabled
752 def Enable(self
, enabled
):
753 """ Sets the tab enabled or disabled. """
755 self
._bEnabled
= enabled
758 def SetRegion(self
, points
=[]):
759 """ Sets the tab region. """
761 self
._region
= wx
.RegionFromPoints(points
)
765 """ Returns the tab region. """
770 def SetXRect(self
, xrect
):
771 """ Sets the button 'X' area rect. """
777 """ Returns the button 'X' area rect. """
783 """ Returns the tab colour. """
788 def SetColor(self
, color
):
789 """ Sets the tab colour. """
794 # ---------------------------------------------------------------------------- #
795 # Class FlatNotebookEvent
796 # ---------------------------------------------------------------------------- #
798 class FlatNotebookEvent(wx
.PyCommandEvent
):
800 This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
801 EVT_FLATNOTEBOOK_PAGE_CHANGING And EVT_FLATNOTEBOOK_PAGE_CLOSING is mapped in
805 def __init__(self
, eventType
, id=1, nSel
=-1, nOldSel
=-1):
806 """ Default class constructor. """
808 wx
.PyCommandEvent
.__init
__(self
, eventType
, id)
809 self
._eventType
= eventType
811 self
.notify
= wx
.NotifyEvent(eventType
, id)
814 def GetNotifyEvent(self
):
815 """Returns the actual wx.NotifyEvent."""
821 """Returns whether the event is allowed or not."""
823 return self
.notify
.IsAllowed()
827 """Vetos the event."""
833 """The event is allowed."""
838 def SetSelection(self
, nSel
):
839 """ Sets event selection. """
841 self
._selection
= nSel
844 def SetOldSelection(self
, nOldSel
):
845 """ Sets old event selection. """
847 self
._oldselection
= nOldSel
850 def GetSelection(self
):
851 """ Returns event selection. """
853 return self
._selection
856 def GetOldSelection(self
):
857 """ Returns old event selection """
859 return self
._oldselection
862 # ---------------------------------------------------------------------------- #
863 # Class FlatNotebookBase
864 # ---------------------------------------------------------------------------- #
866 class FlatNotebookBase(wx
.Panel
):
868 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
869 style
=0, name
="FlatNotebook"):
871 Default class constructor.
873 All the parameters are as in wxPython class construction, except the
874 'style': this can be assigned to whatever combination of FNB_* styles.
877 self
._bForceSelection
= False
880 style |
= wx
.TAB_TRAVERSAL
884 wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style
)
886 self
._pages
= StyledTabsContainer(self
, wx
.ID_ANY
, wx
.DefaultPosition
, wx
.DefaultSize
, style
)
888 self
.Bind(wx
.EVT_NAVIGATION_KEY
, self
.OnNavigationKey
)
890 self
._pages
._colorBorder
= wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
892 self
._mainSizer
= wx
.BoxSizer(wx
.VERTICAL
)
893 self
.SetSizer(self
._mainSizer
)
895 # The child panels will inherit this bg color, so leave it at the default value
896 #self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_APPWORKSPACE))
898 # Add the tab container to the sizer
899 self
._mainSizer
.Insert(0, self
._pages
, 0, wx
.EXPAND
)
901 # Set default page height
902 dc
= wx
.ClientDC(self
)
903 font
= self
.GetFont()
904 font
.SetWeight(wx
.FONTWEIGHT_BOLD
)
906 height
= dc
.GetCharHeight()
907 ##print height, font.Ok()
909 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
910 self
._pages
.SetSizeHints(-1, tabHeight
)
912 self
._mainSizer
.Layout()
914 self
._pages
._nFrom
= self
._nFrom
915 self
._pDropTarget
= FNBDropTarget(self
)
916 self
.SetDropTarget(self
._pDropTarget
)
919 def CreatePageContainer(self
):
920 """ Creates the page container for the tabs. """
922 return PageContainerBase(self
, wx
.ID_ANY
)
925 def SetActiveTabTextColour(self
, textColour
):
926 """ Sets the text colour for the active tab. """
928 self
._pages
._activeTextColor
= textColour
931 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
932 """ Handles the drop action from a DND operation. """
934 return self
._pages
.OnDropTarget(x
, y
, nTabPage
, wnd_oldContainer
)
937 def AddPage(self
, window
, caption
, selected
=True, imgindex
=-1):
939 Add a page to the FlatNotebook.
942 - window: Specifies the new page.
943 - caption: Specifies the text for the new page.
944 - selected: Specifies whether the page should be selected.
945 - imgindex: Specifies the optional image index for the new page.
948 True if successful, False otherwise.
955 # reparent the window to us
956 window
.Reparent(self
)
959 bSelected
= selected
or not self
._windows
960 curSel
= self
._pages
.GetSelection()
962 if not self
._pages
.IsShown():
965 self
._pages
.AddPage(caption
, bSelected
, imgindex
)
966 self
._windows
.append(window
)
970 # Check if a new selection was made
975 # Remove the window from the main sizer
976 self
._mainSizer
.Detach(self
._windows
[curSel
])
977 self
._windows
[curSel
].Hide()
979 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
981 self
._mainSizer
.Insert(0, window
, 1, wx
.EXPAND
)
985 # We leave a space of 1 pixel around the window
986 self
._mainSizer
.Add(window
, 1, wx
.EXPAND
)
993 self
._mainSizer
.Layout()
1000 def SetImageList(self
, imglist
):
1002 Sets the image list for the page control. It does not take ownership
1003 of the image list, you must delete it yourself.
1006 self
._pages
.SetImageList(imglist
)
1009 def GetImageList(self
):
1010 """ Returns the associated image list. """
1012 return self
._pages
.GetImageList()
1015 def InsertPage(self
, indx
, page
, text
, select
=True, imgindex
=-1):
1017 Inserts a new page at the specified position.
1020 - indx: Specifies the position of the new page.
1021 - page: Specifies the new page.
1022 - text: Specifies the text for the new page.
1023 - select: Specifies whether the page should be selected.
1024 - imgindex: Specifies the optional image index for the new page.
1027 True if successful, False otherwise.
1034 # reparent the window to us
1037 if not self
._windows
:
1039 self
.AddPage(page
, text
, select
, imgindex
)
1043 bSelected
= select
or not self
._windows
1044 curSel
= self
._pages
.GetSelection()
1046 indx
= max(0, min(indx
, len(self
._windows
)))
1048 if indx
<= len(self
._windows
):
1050 self
._windows
.insert(indx
, page
)
1054 self
._windows
.append(page
)
1056 self
._pages
.InsertPage(indx
, text
, bSelected
, imgindex
)
1063 # Check if a new selection was made
1068 # Remove the window from the main sizer
1069 self
._mainSizer
.Detach(self
._windows
[curSel
])
1070 self
._windows
[curSel
].Hide()
1072 self
._pages
.SetSelection(indx
)
1080 self
._mainSizer
.Layout()
1086 def SetSelection(self
, page
):
1088 Sets the selection for the given page.
1089 The call to this function generates the page changing events
1092 if page
>= len(self
._windows
) or not self
._windows
:
1095 # Support for disabed tabs
1096 if not self
._pages
.GetEnabled(page
) and len(self
._windows
) > 1 and not self
._bForceSelection
:
1099 curSel
= self
._pages
.GetSelection()
1101 # program allows the page change
1105 # Remove the window from the main sizer
1106 self
._mainSizer
.Detach(self
._windows
[curSel
])
1107 self
._windows
[curSel
].Hide()
1109 if self
.GetWindowStyleFlag() & FNB_BOTTOM
:
1111 self
._mainSizer
.Insert(0, self
._windows
[page
], 1, wx
.EXPAND
)
1115 # We leave a space of 1 pixel around the window
1116 self
._mainSizer
.Add(self
._windows
[page
], 1, wx
.EXPAND
)
1118 self
._windows
[page
].Show()
1120 self
._mainSizer
.Layout()
1121 self
._pages
._iActivePage
= page
1125 self
._pages
.DoSetSelection(page
)
1128 def DeletePage(self
, page
):
1130 Deletes the specified page, and the associated window.
1131 The call to this function generates the page changing events.
1134 if page
>= len(self
._windows
):
1137 # Fire a closing event
1138 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
1139 event
.SetSelection(page
)
1140 event
.SetEventObject(self
)
1141 self
.GetEventHandler().ProcessEvent(event
)
1143 # The event handler allows it?
1144 if not event
.IsAllowed():
1149 # Delete the requested page
1150 pageRemoved
= self
._windows
[page
]
1152 # If the page is the current window, remove it from the sizer
1154 if page
== self
._pages
.GetSelection():
1155 self
._mainSizer
.Detach(pageRemoved
)
1157 # Remove it from the array as well
1158 self
._windows
.pop(page
)
1160 # Now we can destroy it in wxWidgets use Destroy instead of delete
1161 pageRemoved
.Destroy()
1165 self
._pages
.DoDeletePage(page
)
1168 # Fire a closed event
1169 closedEvent
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED
, self
.GetId())
1170 closedEvent
.SetSelection(page
)
1171 closedEvent
.SetEventObject(self
)
1172 self
.GetEventHandler().ProcessEvent(closedEvent
)
1175 def DeleteAllPages(self
):
1176 """ Deletes all the pages. """
1178 if not self
._windows
:
1183 for page
in self
._windows
:
1189 # Clear the container of the tabs as well
1190 self
._pages
.DeleteAllPages()
1194 def GetCurrentPage(self
):
1195 """ Returns the currently selected notebook page or None. """
1197 sel
= self
._pages
.GetSelection()
1201 return self
._windows
[sel
]
1204 def GetPage(self
, page
):
1205 """ Returns the window at the given page position, or None. """
1207 if page
>= len(self
._windows
):
1210 return self
._windows
[page
]
1213 def GetPageIndex(self
, win
):
1214 """ Returns the index at which the window is found. """
1217 return self
._windows
.index(win
)
1222 def GetSelection(self
):
1223 """ Returns the currently selected page, or -1 if none was selected. """
1225 return self
._pages
.GetSelection()
1228 def AdvanceSelection(self
, bForward
=True):
1230 Cycles through the tabs.
1231 The call to this function generates the page changing events.
1234 self
._pages
.AdvanceSelection(bForward
)
1237 def GetPageCount(self
):
1238 """ Returns the number of pages in the FlatNotebook control. """
1239 return self
._pages
.GetPageCount()
1242 def OnNavigationKey(self
, event
):
1243 """ Handles the wx.EVT_NAVIGATION_KEY event for FlatNotebook. """
1245 if event
.IsWindowChange():
1247 self
.AdvanceSelection(event
.GetDirection())
1249 # pass to the parent
1250 if self
.GetParent():
1251 event
.SetCurrentFocus(self
)
1252 self
.GetParent().ProcessEvent(event
)
1255 def GetPageShapeAngle(self
, page_index
):
1256 """ Returns the angle associated to a tab. """
1258 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
1261 result
= self
._pages
._pagesInfoVec
[page_index
].GetTabAngle()
1265 def SetPageShapeAngle(self
, page_index
, angle
):
1266 """ Sets the angle associated to a tab. """
1268 if page_index
< 0 or page_index
>= len(self
._pages
._pagesInfoVec
):
1274 self
._pages
._pagesInfoVec
[page_index
].SetTabAngle(angle
)
1277 def SetAllPagesShapeAngle(self
, angle
):
1278 """ Sets the angle associated to all the tab. """
1283 for ii
in xrange(len(self
._pages
._pagesInfoVec
)):
1284 self
._pages
._pagesInfoVec
[ii
].SetTabAngle(angle
)
1289 def GetPageBestSize(self
):
1290 """ Return the page best size. """
1292 return self
._pages
.GetClientSize()
1295 def SetPageText(self
, page
, text
):
1296 """ Sets the text for the given page. """
1298 bVal
= self
._pages
.SetPageText(page
, text
)
1299 self
._pages
.Refresh()
1304 def SetPadding(self
, padding
):
1306 Sets the amount of space around each page's icon and label, in pixels.
1307 NB: only the horizontal padding is considered.
1310 self
._nPadding
= padding
.GetWidth()
1313 def GetTabArea(self
):
1314 """ Returns the associated page. """
1319 def GetPadding(self
):
1320 """ Returns the amount of space around each page's icon and label, in pixels. """
1322 return self
._nPadding
1325 def SetWindowStyleFlag(self
, style
):
1326 """ Sets the FlatNotebook window style flags. """
1328 wx
.Panel
.SetWindowStyleFlag(self
, style
)
1332 # For changing the tab position (i.e. placing them top/bottom)
1333 # refreshing the tab container is not enough
1334 self
.SetSelection(self
._pages
._iActivePage
)
1337 def RemovePage(self
, page
):
1338 """ Deletes the specified page, without deleting the associated window. """
1340 if page
>= len(self
._windows
):
1343 # Fire a closing event
1344 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING
, self
.GetId())
1345 event
.SetSelection(page
)
1346 event
.SetEventObject(self
)
1347 self
.GetEventHandler().ProcessEvent(event
)
1349 # The event handler allows it?
1350 if not event
.IsAllowed():
1355 # Remove the requested page
1356 pageRemoved
= self
._windows
[page
]
1358 # If the page is the current window, remove it from the sizer
1360 if page
== self
._pages
.GetSelection():
1361 self
._mainSizer
.Detach(pageRemoved
)
1363 # Remove it from the array as well
1364 self
._windows
.pop(page
)
1367 self
._pages
.DoDeletePage(page
)
1372 def SetRightClickMenu(self
, menu
):
1373 """ Sets the popup menu associated to a right click on a tab. """
1375 self
._pages
._pRightClickMenu
= menu
1378 def GetPageText(self
, page
):
1379 """ Returns the tab caption. """
1381 return self
._pages
.GetPageText(page
)
1384 def SetGradientColors(self
, fr
, to
, border
):
1385 """ Sets the gradient colours for the tab. """
1387 self
._pages
._colorFrom
= fr
1388 self
._pages
._colorTo
= to
1389 self
._pages
._colorBorder
= border
1392 def SetGradientColorFrom(self
, fr
):
1393 """ Sets the starting colour for the gradient. """
1395 self
._pages
._colorFrom
= fr
1398 def SetGradientColorTo(self
, to
):
1399 """ Sets the ending colour for the gradient. """
1401 self
._pages
._colorTo
= to
1404 def SetGradientColorBorder(self
, border
):
1405 """ Sets the tab border colour. """
1407 self
._pages
._colorBorder
= border
1410 def GetGradientColorFrom(self
):
1411 """ Gets first gradient colour. """
1413 return self
._pages
._colorFrom
1416 def GetGradientColorTo(self
):
1417 """ Gets second gradient colour. """
1419 return self
._pages
._colorTo
1422 def GetGradientColorBorder(self
):
1423 """ Gets the tab border colour. """
1425 return self
._pages
._colorBorder
1428 def GetActiveTabTextColour(self
):
1429 """ Get the active tab text colour. """
1431 return self
._pages
._activeTextColor
1434 def SetPageImage(self
, page
, imgindex
):
1436 Sets the image index for the given page. Image is an index into the
1437 image list which was set with SetImageList.
1440 self
._pages
.SetPageImage(page
, imgindex
)
1443 def GetPageImageIndex(self
, page
):
1445 Returns the image index for the given page. Image is an index into the
1446 image list which was set with SetImageList.
1449 return self
._pages
.GetPageImageIndex(page
)
1452 def GetEnabled(self
, page
):
1453 """ Returns whether a tab is enabled or not. """
1455 return self
._pages
.GetEnabled(page
)
1458 def Enable(self
, page
, enabled
=True):
1459 """ Enables or disables a tab. """
1461 if page
>= len(self
._windows
):
1464 self
._windows
[page
].Enable(enabled
)
1465 self
._pages
.Enable(page
, enabled
)
1468 def GetNonActiveTabTextColour(self
):
1469 """ Returns the non active tabs text colour. """
1471 return self
._pages
._nonActiveTextColor
1474 def SetNonActiveTabTextColour(self
, color
):
1475 """ Sets the non active tabs text colour. """
1477 self
._pages
._nonActiveTextColor
= color
1480 def SetTabAreaColour(self
, color
):
1481 """ Sets the area behind the tabs colour. """
1483 self
._pages
._tabAreaColor
= color
1486 def GetTabAreaColour(self
):
1487 """ Returns the area behind the tabs colour. """
1489 return self
._pages
._tabAreaColor
1492 def SetActiveTabColour(self
, color
):
1493 """ Sets the active tab colour. """
1495 self
._pages
._activeTabColor
= color
1498 def GetActiveTabColour(self
):
1499 """ Returns the active tab colour. """
1501 return self
._pages
._activeTabColor
1504 # ---------------------------------------------------------------------------- #
1505 # Class PageContainerBase
1506 # Acts as a container for the pages you add to FlatNotebook
1507 # ---------------------------------------------------------------------------- #
1509 class PageContainerBase(wx
.Panel
):
1511 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
,
1512 size
=wx
.DefaultSize
, style
=0):
1513 """ Default class constructor. """
1515 self
._ImageList
= None
1516 self
._iActivePage
= -1
1517 self
._pDropTarget
= None
1518 self
._nLeftClickZone
= FNB_NOWHERE
1519 self
._tabXBgBmp
= wx
.EmptyBitmap(16, 16)
1520 self
._xBgBmp
= wx
.EmptyBitmap(16, 14)
1521 self
._leftBgBmp
= wx
.EmptyBitmap(16, 14)
1522 self
._rightBgBmp
= wx
.EmptyBitmap(16, 14)
1524 self
._pRightClickMenu
= None
1525 self
._nXButtonStatus
= FNB_BTN_NONE
1526 self
._pParent
= parent
1527 self
._nRightButtonStatus
= FNB_BTN_NONE
1528 self
._nLeftButtonStatus
= FNB_BTN_NONE
1529 self
._nTabXButtonStatus
= FNB_BTN_NONE
1531 self
._pagesInfoVec
= []
1533 self
._colorTo
= wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_ACTIVECAPTION
)
1534 self
._colorFrom
= wx
.WHITE
1535 self
._activeTabColor
= wx
.WHITE
1536 self
._activeTextColor
= wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNTEXT
)
1537 self
._nonActiveTextColor
= wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
)
1538 self
._tabAreaColor
= wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNFACE
)
1541 self
._isdragging
= False
1543 wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style|wx
.TAB_TRAVERSAL
)
1545 self
._pDropTarget
= FNBDropTarget(self
)
1546 self
.SetDropTarget(self
._pDropTarget
)
1548 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
1549 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
1550 self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
)
1551 self
.Bind(wx
.EVT_LEFT_UP
, self
.OnLeftUp
)
1552 self
.Bind(wx
.EVT_RIGHT_DOWN
, self
.OnRightDown
)
1553 self
.Bind(wx
.EVT_MIDDLE_DOWN
, self
.OnMiddleDown
)
1554 self
.Bind(wx
.EVT_MOTION
, self
.OnMouseMove
)
1555 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
1556 self
.Bind(wx
.EVT_LEAVE_WINDOW
, self
.OnMouseLeave
)
1557 self
.Bind(wx
.EVT_ENTER_WINDOW
, self
.OnMouseEnterWindow
)
1558 self
.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnLeftDClick
)
1561 def GetButtonAreaWidth(self
):
1562 """ Returns the width of the navigation button area. """
1564 style
= self
.GetParent().GetWindowStyleFlag()
1565 btnareawidth
= 2*self
._pParent
._nPadding
1567 if style
& FNB_NO_X_BUTTON
== 0:
1568 btnareawidth
+= BUTTON_SPACE
1570 if style
& FNB_NO_NAV_BUTTONS
== 0:
1571 btnareawidth
+= 2*BUTTON_SPACE
1576 def OnEraseBackground(self
, event
):
1577 """ Handles the wx.EVT_ERASE_BACKGROUND event for PageContainerBase (does nothing)."""
1582 def OnPaint(self
, event
):
1583 """ Handles the wx.EVT_PAINT event for PageContainerBase."""
1585 dc
= wx
.BufferedPaintDC(self
)
1587 if "__WXMAC__" in wx
.PlatformInfo
:
1588 # Works well on MSW & GTK, however this lines should be skipped on MAC
1589 if len(self
._pagesInfoVec
) == 0 or self
._nFrom
>= len(self
._pagesInfoVec
):
1594 # Get the text hight
1595 style
= self
.GetParent().GetWindowStyleFlag()
1597 # For GTK it seems that we must do this steps in order
1598 # for the tabs will get the proper height on initialization
1599 # on MSW, preforming these steps yields wierd results
1600 normalFont
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1601 boldFont
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
1602 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
1603 if "__WXGTK__" in wx
.PlatformInfo
:
1604 dc
.SetFont(boldFont
)
1606 width
, height
= dc
.GetTextExtent("Tp")
1608 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
1610 # Calculate the number of rows required for drawing the tabs
1611 rect
= self
.GetClientRect()
1612 clientWidth
= rect
.width
1614 # Set the maximum client size
1615 self
.SetSizeHints(self
.GetButtonsAreaLength(), tabHeight
)
1616 borderPen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1618 if style
& FNB_VC71
:
1619 backBrush
= wx
.Brush(wx
.Colour(247, 243, 233))
1621 backBrush
= wx
.Brush(self
._tabAreaColor
)
1623 noselBrush
= wx
.Brush(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNFACE
))
1624 selBrush
= wx
.Brush(self
._activeTabColor
)
1626 size
= self
.GetSize()
1629 dc
.SetTextBackground((style
& FNB_VC71
and [wx
.Colour(247, 243, 233)] or [self
.GetBackgroundColour()])[0])
1630 dc
.SetTextForeground(self
._activeTextColor
)
1631 dc
.SetBrush(backBrush
)
1633 # If border style is set, set the pen to be border pen
1634 if style
& FNB_TABS_BORDER_SIMPLE
:
1635 dc
.SetPen(borderPen
)
1637 pc
= (self
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [self
.GetBackgroundColour()])[0]
1638 dc
.SetPen(wx
.Pen(pc
))
1640 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
1642 # Take 3 bitmaps for the background for the buttons
1644 mem_dc
= wx
.MemoryDC()
1646 #---------------------------------------
1648 #---------------------------------------
1649 rect
= wx
.Rect(self
.GetXPos(), 6, 16, 14)
1650 mem_dc
.SelectObject(self
._xBgBmp
)
1651 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1652 mem_dc
.SelectObject(wx
.NullBitmap
)
1654 #---------------------------------------
1656 #---------------------------------------
1657 rect
= wx
.Rect(self
.GetRightButtonPos(), 6, 16, 14)
1658 mem_dc
.SelectObject(self
._rightBgBmp
)
1659 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1660 mem_dc
.SelectObject(wx
.NullBitmap
)
1662 #---------------------------------------
1664 #---------------------------------------
1665 rect
= wx
.Rect(self
.GetLeftButtonPos(), 6, 16, 14)
1666 mem_dc
.SelectObject(self
._leftBgBmp
)
1667 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
1668 mem_dc
.SelectObject(wx
.NullBitmap
)
1670 # We always draw the bottom/upper line of the tabs
1671 # regradless the style
1672 dc
.SetPen(borderPen
)
1673 self
.DrawTabsLine(dc
)
1676 dc
.SetPen(borderPen
)
1678 if self
.HasFlag(FNB_VC71
):
1680 greyLineYVal
= self
.HasFlag((FNB_BOTTOM
and [0] or [size
.y
- 2])[0])
1681 whiteLineYVal
= self
.HasFlag((FNB_BOTTOM
and [3] or [size
.y
- 3])[0])
1683 pen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
))
1686 # Draw thik grey line between the windows area and
1689 for num
in xrange(3):
1690 dc
.DrawLine(0, greyLineYVal
+ num
, size
.x
, greyLineYVal
+ num
)
1692 wbPen
= wx
.Pen((self
.HasFlag(FNB_BOTTOM
) and [wx
.BLACK
] or [wx
.WHITE
])[0])
1694 dc
.DrawLine(1, whiteLineYVal
, size
.x
- 1, whiteLineYVal
)
1697 dc
.SetPen(borderPen
)
1699 if "__WXMAC__" in wx
.PlatformInfo
:
1700 # On MAC, Add these lines so the tab background gets painted
1701 if len(self
._pagesInfoVec
) == 0 or self
._nFrom
>= len(self
._pagesInfoVec
):
1706 dc
.SetFont(boldFont
)
1707 posx
= self
._pParent
.GetPadding()
1709 # Update all the tabs from 0 to '_nFrom' to be non visible
1710 for ii
in xrange(self
._nFrom
):
1711 self
._pagesInfoVec
[ii
].SetPosition(wx
.Point(-1, -1))
1712 self
._pagesInfoVec
[ii
].GetRegion().Clear()
1714 if style
& FNB_VC71
:
1715 tabHeight
= ((style
& FNB_BOTTOM
) and [tabHeight
- 4] or [tabHeight
])[0]
1716 elif style
& FNB_FANCY_TABS
:
1717 tabHeight
= ((style
& FNB_BOTTOM
) and [tabHeight
- 2] or [tabHeight
])[0]
1719 #----------------------------------------------------------
1720 # Go over and draw the visible tabs
1721 #----------------------------------------------------------
1725 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
1727 if style
!= FNB_VC71
:
1728 shapePoints
= int(tabHeight
*math
.tan(float(self
._pagesInfoVec
[ii
].GetTabAngle())/180.0*math
.pi
))
1732 dc
.SetPen(borderPen
)
1733 dc
.SetBrush((ii
==self
.GetSelection() and [selBrush
] or [noselBrush
])[0])
1735 # Calculate the text length using the bold font, so when selecting a tab
1736 # its width will not change
1737 dc
.SetFont(boldFont
)
1738 width
, pom
= dc
.GetTextExtent(self
.GetPageText(ii
))
1740 # Now set the font to the correct font
1741 dc
.SetFont((ii
==self
.GetSelection() and [boldFont
] or [normalFont
])[0])
1743 # Set a minimum size to a tab
1747 # Add the padding to the tab width
1749 # +-----------------------------------------------------------+
1750 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
1751 # +-----------------------------------------------------------+
1753 tabWidth
= 2*self
._pParent
._nPadding
+ width
1754 imageYCoord
= (self
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
1756 # Style to add a small 'x' button on the top right
1758 if style
& FNB_X_ON_TAB
and ii
== self
.GetSelection():
1760 # The xpm image that contains the 'x' button is 9 pixles
1761 tabWidth
+= self
._pParent
._nPadding
+ 9
1763 if not (style
& FNB_VC71
) and not (style
& FNB_FANCY_TABS
):
1765 tabWidth
+= 2*shapePoints
1767 hasImage
= self
._ImageList
!= None and self
._pagesInfoVec
[ii
].GetImageIndex() != -1
1769 # For VC71 style, we only add the icon size (16 pixels)
1772 if style
& FNB_VC71
or style
& FNB_FANCY_TABS
:
1773 tabWidth
+= 16 + self
._pParent
._nPadding
1776 tabWidth
+= 16 + self
._pParent
._nPadding
+ shapePoints
/2
1778 # Check if we can draw more
1779 if posx
+ tabWidth
+ self
.GetButtonsAreaLength() >= clientWidth
:
1784 # By default we clean the tab region
1785 self
._pagesInfoVec
[ii
].GetRegion().Clear()
1787 # Clean the 'x' buttn on the tab
1788 # 'Clean' rectanlge is a rectangle with width or height
1789 # with values lower than or equal to 0
1790 self
._pagesInfoVec
[ii
].GetXRect().SetSize(wx
.Size(-1, -1))
1793 if style
& FNB_FANCY_TABS
:
1794 self
.DrawFancyTab(dc
, posx
, ii
, tabWidth
, tabHeight
)
1795 elif style
& FNB_VC71
:
1796 self
.DrawVC71Tab(dc
, posx
, ii
, tabWidth
, tabHeight
)
1798 self
.DrawStandardTab(dc
, posx
, ii
, tabWidth
, tabHeight
)
1800 # The width of the images are 16 pixels
1802 textOffset
= 2*self
._pParent
._nPadding
+ 16 + shapePoints
/2
1804 textOffset
= self
._pParent
._nPadding
+ shapePoints
/2
1806 # After several testing, it seems that we can draw
1807 # the text 2 pixles to the right - this is done only
1808 # for the standard tabs
1810 if not self
.HasFlag(FNB_FANCY_TABS
):
1813 if ii
!= self
.GetSelection():
1814 # Set the text background to be like the vertical lines
1815 dc
.SetTextForeground(self
._nonActiveTextColor
)
1819 imageXOffset
= textOffset
- 16 - self
._pParent
._nPadding
1820 self
._ImageList
.Draw(self
._pagesInfoVec
[ii
].GetImageIndex(), dc
,
1821 posx
+ imageXOffset
, imageYCoord
,
1822 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
1824 dc
.DrawText(self
.GetPageText(ii
), posx
+ textOffset
, imageYCoord
)
1826 # From version 1.2 - a style to add 'x' button
1829 if self
.HasFlag(FNB_X_ON_TAB
) and ii
== self
.GetSelection():
1831 textWidth
, textHeight
= dc
.GetTextExtent(self
.GetPageText(ii
))
1832 tabCloseButtonXCoord
= posx
+ textOffset
+ textWidth
+ 1
1834 # take a bitmap from the position of the 'x' button (the x on tab button)
1835 # this bitmap will be used later to delete old buttons
1836 tabCloseButtonYCoord
= imageYCoord
1837 x_rect
= wx
.Rect(tabCloseButtonXCoord
, tabCloseButtonYCoord
, 16, 16)
1838 mem_dc
= wx
.MemoryDC()
1839 mem_dc
.SelectObject(self
._tabXBgBmp
)
1840 mem_dc
.Blit(0, 0, x_rect
.width
, x_rect
.height
, dc
, x_rect
.x
, x_rect
.y
)
1841 mem_dc
.SelectObject(wx
.NullBitmap
)
1844 self
.DrawTabX(dc
, x_rect
, ii
)
1846 # Restore the text forground
1847 dc
.SetTextForeground(self
._activeTextColor
)
1849 # Update the tab position & size
1850 posy
= (style
& FNB_BOTTOM
and [0] or [VERTICAL_BORDER_PADDING
])[0]
1852 self
._pagesInfoVec
[ii
].SetPosition(wx
.Point(posx
, posy
))
1853 self
._pagesInfoVec
[ii
].SetSize(wx
.Size(tabWidth
, tabHeight
))
1856 # Update all tabs that can not fit into the screen as non-visible
1857 for ii
in xrange(count
, len(self
._pagesInfoVec
)):
1859 self
._pagesInfoVec
[ii
].SetPosition(wx
.Point(-1, -1))
1860 self
._pagesInfoVec
[ii
].GetRegion().Clear()
1862 # Draw the left/right/close buttons
1864 self
.DrawLeftArrow(dc
)
1865 self
.DrawRightArrow(dc
)
1869 def DrawFancyTab(self
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
):
1871 Fancy tabs - like with VC71 but with the following differences:
1872 - The Selected tab is colored with gradient color
1875 borderPen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1876 pen
= (tabIdx
==self
.GetSelection() and [wx
.Pen(self
._colorBorder
)] \
1877 or [wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
))])[0]
1879 fnb_bottom
= self
.HasFlag(FNB_BOTTOM
)
1881 if tabIdx
== self
.GetSelection():
1883 posy
= (fnb_bottom
and [2] or [VERTICAL_BORDER_PADDING
])[0]
1884 th
= (fnb_bottom
and [tabHeight
- 2] or [tabHeight
- 5])[0]
1886 rect
= wx
.Rect(posx
, posy
, tabWidth
, th
)
1887 self
.FillGradientColor(dc
, rect
)
1888 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
1890 dc
.DrawRectangleRect(rect
)
1892 # erase the bottom/top line of the rectangle
1893 dc
.SetPen(wx
.Pen(self
._colorFrom
))
1895 dc
.DrawLine(rect
.x
, 2, rect
.x
+ rect
.width
, 2)
1897 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
, rect
.y
+ rect
.height
- 1)
1901 # We dont draw a rectangle for non selected tabs, but only
1902 # vertical line on the left
1903 dc
.SetPen(borderPen
)
1904 dc
.DrawLine(posx
+ tabWidth
, VERTICAL_BORDER_PADDING
+ 3, posx
+ tabWidth
, tabHeight
- 4)
1907 def DrawVC71Tab(self
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
):
1908 """ Draws tabs with VC71 style. """
1910 fnb_bottom
= self
.HasFlag(FNB_BOTTOM
)
1912 # Visual studio 7.1 style
1913 borderPen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1914 dc
.SetPen((tabIdx
==self
.GetSelection() and [wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
))] or [borderPen
])[0])
1915 dc
.SetBrush((tabIdx
==self
.GetSelection() and [wx
.Brush(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
))] or \
1916 [wx
.Brush(wx
.Colour(247, 243, 233))])[0])
1918 if tabIdx
== self
.GetSelection():
1920 posy
= (fnb_bottom
and [0] or [VERTICAL_BORDER_PADDING
])[0]
1921 dc
.DrawRectangle(posx
, posy
, tabWidth
, tabHeight
- 1)
1923 # Draw a black line on the left side of the
1925 dc
.SetPen(wx
.BLACK_PEN
)
1927 blackLineY1
= VERTICAL_BORDER_PADDING
1928 blackLineY2
= (fnb_bottom
and [self
.GetSize().y
- 5] or [self
.GetSize().y
- 3])[0]
1929 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
1931 # To give the tab more 3D look we do the following
1932 # Incase the tab is on top,
1933 # Draw a thick white line on top of the rectangle
1934 # Otherwise, draw a thin (1 pixel) black line at the bottom
1936 pen
= wx
.Pen((fnb_bottom
and [wx
.BLACK
] or [wx
.WHITE
])[0])
1938 whiteLinePosY
= (fnb_bottom
and [blackLineY2
] or [VERTICAL_BORDER_PADDING
])[0]
1939 dc
.DrawLine(posx
, whiteLinePosY
, posx
+ tabWidth
+ 1, whiteLinePosY
)
1941 # Draw a white vertical line to the left of the tab
1942 dc
.SetPen(wx
.WHITE_PEN
)
1946 dc
.DrawLine(posx
, blackLineY1
, posx
, blackLineY2
)
1950 # We dont draw a rectangle for non selected tabs, but only
1951 # vertical line on the left
1953 blackLineY1
= (fnb_bottom
and [VERTICAL_BORDER_PADDING
+ 2] or [VERTICAL_BORDER_PADDING
+ 1])[0]
1954 blackLineY2
= self
.GetSize().y
- 5
1955 dc
.DrawLine(posx
+ tabWidth
, blackLineY1
, posx
+ tabWidth
, blackLineY2
)
1958 def DrawStandardTab(self
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
):
1959 """ Draws tabs with standard style. """
1961 fnb_bottom
= self
.HasFlag(FNB_BOTTOM
)
1964 borderPen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
1966 tabPoints
= [wx
.Point() for ii
in xrange(7)]
1967 tabPoints
[0].x
= posx
1968 tabPoints
[0].y
= (fnb_bottom
and [2] or [tabHeight
- 2])[0]
1970 tabPoints
[1].x
= int(posx
+(tabHeight
-2)*math
.tan(float(self
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1971 tabPoints
[1].y
= (fnb_bottom
and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
1973 tabPoints
[2].x
= tabPoints
[1].x
+2
1974 tabPoints
[2].y
= (fnb_bottom
and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
1976 tabPoints
[3].x
= int(posx
+tabWidth
-(tabHeight
-2)*math
.tan(float(self
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))-2
1977 tabPoints
[3].y
= (fnb_bottom
and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
1979 tabPoints
[4].x
= tabPoints
[3].x
+2
1980 tabPoints
[4].y
= (fnb_bottom
and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
1982 tabPoints
[5].x
= int(tabPoints
[4].x
+(tabHeight
-2)*math
.tan(float(self
._pagesInfoVec
[tabIdx
].GetTabAngle())/180.0*math
.pi
))
1983 tabPoints
[5].y
= (fnb_bottom
and [2] or [tabHeight
- 2])[0]
1985 tabPoints
[6].x
= tabPoints
[0].x
1986 tabPoints
[6].y
= tabPoints
[0].y
1988 if tabIdx
== self
.GetSelection():
1990 # Draw the tab as rounded rectangle
1991 dc
.DrawPolygon(tabPoints
)
1995 if tabIdx
!= self
.GetSelection() - 1:
1997 # Draw a vertical line to the right of the text
1998 pt1x
= tabPoints
[5].x
1999 pt1y
= (fnb_bottom
and [4] or [tabHeight
- 6])[0]
2000 pt2x
= tabPoints
[5].x
2001 pt2y
= (fnb_bottom
and [tabHeight
- 4] or [4])[0]
2002 dc
.DrawLine(pt1x
, pt1y
, pt2x
, pt2y
)
2004 if tabIdx
== self
.GetSelection():
2006 savePen
= dc
.GetPen()
2007 whitePen
= wx
.Pen(wx
.WHITE
)
2008 whitePen
.SetWidth(1)
2011 secPt
= wx
.Point(tabPoints
[5].x
+ 1, tabPoints
[5].y
)
2012 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, secPt
.x
, secPt
.y
)
2018 def AddPage(self
, caption
, selected
=True, imgindex
=-1):
2020 Add a page to the FlatNotebook.
2023 - window: Specifies the new page.
2024 - caption: Specifies the text for the new page.
2025 - selected: Specifies whether the page should be selected.
2026 - imgindex: Specifies the optional image index for the new page.
2029 True if successful, False otherwise.
2034 self
._iActivePage
= len(self
._pagesInfoVec
)
2036 # Create page info and add it to the vector
2037 pageInfo
= PageInfo(caption
, imgindex
)
2038 self
._pagesInfoVec
.append(pageInfo
)
2042 def InsertPage(self
, indx
, text
, selected
=True, imgindex
=-1):
2044 Inserts a new page at the specified position.
2047 - indx: Specifies the position of the new page.
2048 - page: Specifies the new page.
2049 - text: Specifies the text for the new page.
2050 - select: Specifies whether the page should be selected.
2051 - imgindex: Specifies the optional image index for the new page.
2054 True if successful, False otherwise.
2059 self
._iActivePage
= len(self
._pagesInfoVec
)
2061 self
._pagesInfoVec
.insert(indx
, PageInfo(text
, imgindex
))
2067 def OnSize(self
, event
):
2068 """ Handles the wx.EVT_SIZE events for PageContainerBase. """
2070 self
.Refresh() # Call on paint
2074 def OnMiddleDown(self
, event
):
2075 """ Handles the wx.EVT_MIDDLE_DOWN events for PageContainerBase. """
2077 # Test if this style is enabled
2078 style
= self
.GetParent().GetWindowStyleFlag()
2080 if not style
& FNB_MOUSE_MIDDLE_CLOSES_TABS
:
2083 where
, tabIdx
= self
.HitTest(event
.GetPosition())
2085 if where
== FNB_TAB
:
2086 self
.DeletePage(tabIdx
)
2091 def OnRightDown(self
, event
):
2092 """ Handles the wx.EVT_RIGHT_DOWN events for PageContainerBase. """
2094 if self
._pRightClickMenu
:
2096 where
, tabIdx
= self
.HitTest(event
.GetPosition())
2098 if where
in [FNB_TAB
, FNB_TAB_X
]:
2100 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
2101 # Set the current tab to be active
2102 self
.SetSelection(tabIdx
)
2104 # If the owner has defined a context menu for the tabs,
2105 # popup the right click menu
2106 if self
._pRightClickMenu
:
2107 self
.PopupMenu(self
._pRightClickMenu
)
2109 # send a message to popup a custom menu
2110 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU
, self
.GetParent().GetId())
2111 event
.SetSelection(tabIdx
)
2112 event
.SetOldSelection(self
._iActivePage
)
2113 event
.SetEventObject(self
.GetParent())
2114 self
.GetParent().GetEventHandler().ProcessEvent(event
)
2119 def OnLeftDown(self
, event
):
2120 """ Handles the wx.EVT_LEFT_DOWN events for PageContainerBase. """
2122 # Reset buttons status
2123 self
._nXButtonStatus
= FNB_BTN_NONE
2124 self
._nLeftButtonStatus
= FNB_BTN_NONE
2125 self
._nRightButtonStatus
= FNB_BTN_NONE
2126 self
._nTabXButtonStatus
= FNB_BTN_NONE
2128 self
._nLeftClickZone
, tabIdx
= self
.HitTest(event
.GetPosition())
2130 if self
._nLeftClickZone
== FNB_LEFT_ARROW
:
2131 self
._nLeftButtonStatus
= FNB_BTN_PRESSED
2133 elif self
._nLeftClickZone
== FNB_RIGHT_ARROW
:
2134 self
._nRightButtonStatus
= FNB_BTN_PRESSED
2136 elif self
._nLeftClickZone
== FNB_X
:
2137 self
._nXButtonStatus
= FNB_BTN_PRESSED
2139 elif self
._nLeftClickZone
== FNB_TAB_X
:
2140 self
._nTabXButtonStatus
= FNB_BTN_PRESSED
2143 elif self
._nLeftClickZone
== FNB_TAB
:
2145 if self
._iActivePage
!= tabIdx
:
2147 # In case the tab is disabled, we dont allow to choose it
2148 if self
._pagesInfoVec
[tabIdx
].GetEnabled():
2150 oldSelection
= self
._iActivePage
2152 event
= FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING
, self
.GetParent().GetId())
2153 event
.SetSelection(tabIdx
)
2154 event
.SetOldSelection(oldSelection
)
2155 event
.SetEventObject(self
.GetParent())
2156 if not self
.GetParent().GetEventHandler().ProcessEvent(event
) or event
.IsAllowed():
2158 self
.SetSelection(tabIdx
)
2160 # Fire a wxEVT_TABBEDCTRL_PAGE_CHANGED event
2161 event
.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED
)
2162 event
.SetOldSelection(oldSelection
)
2163 self
.GetParent().GetEventHandler().ProcessEvent(event
)
2166 def OnLeftUp(self
, event
):
2167 """ Handles the wx.EVT_LEFT_UP events for PageContainerBase. """
2169 # forget the zone that was initially clicked
2170 self
._nLeftClickZone
= FNB_NOWHERE
2172 where
, tabIdx
= self
.HitTest(event
.GetPosition())
2174 if where
== FNB_LEFT_ARROW
:
2176 if self
._nFrom
== 0:
2179 # Make sure that the button was pressed before
2180 if self
._nLeftButtonStatus
!= FNB_BTN_PRESSED
:
2183 self
._nLeftButtonStatus
= FNB_BTN_HOVER
2185 # We scroll left with bulks of 5
2186 scrollLeft
= self
.GetNumTabsCanScrollLeft()
2188 self
._nFrom
-= scrollLeft
2194 elif where
== FNB_RIGHT_ARROW
:
2196 if self
._nFrom
>= len(self
._pagesInfoVec
) - 1:
2199 # Make sure that the button was pressed before
2200 if self
._nRightButtonStatus
!= FNB_BTN_PRESSED
:
2203 self
._nRightButtonStatus
= FNB_BTN_HOVER
2205 # Check if the right most tab is visible, if it is
2206 # don't rotate right anymore
2207 if self
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1):
2210 lastVisibleTab
= self
.GetLastVisibleTab()
2211 if lastVisibleTab
< 0:
2212 # Probably the screen is too small for displaying even a single
2213 # tab, in this case we do nothing
2216 self
._nFrom
+= self
.GetNumOfVisibleTabs()
2219 elif where
== FNB_X
:
2221 # Make sure that the button was pressed before
2222 if self
._nXButtonStatus
!= FNB_BTN_PRESSED
:
2225 self
._nXButtonStatus
= FNB_BTN_HOVER
2227 self
.DeletePage(self
._iActivePage
)
2229 elif where
== FNB_TAB_X
:
2231 # Make sure that the button was pressed before
2232 if self
._nTabXButtonStatus
!= FNB_BTN_PRESSED
:
2235 self
._nTabXButtonStatus
= FNB_BTN_HOVER
2237 self
.DeletePage(self
._iActivePage
)
2240 def HitTest(self
, pt
):
2242 HitTest method for PageContainerBase.
2243 Returns the flag (if any) and the hit page (if any).
2246 fullrect
= self
.GetClientRect()
2247 btnLeftPos
= self
.GetLeftButtonPos()
2248 btnRightPos
= self
.GetRightButtonPos()
2249 btnXPos
= self
.GetXPos()
2250 style
= self
.GetParent().GetWindowStyleFlag()
2254 if not self
._pagesInfoVec
:
2255 return FNB_NOWHERE
, -1
2257 rect
= wx
.Rect(btnXPos
, 6, 16, 16)
2258 if rect
.Contains(pt
):
2259 return (style
& FNB_NO_X_BUTTON
and [FNB_NOWHERE
] or [FNB_X
])[0], -1
2261 rect
= wx
.Rect(btnRightPos
, 6, 16, 16)
2262 if rect
.Contains(pt
):
2263 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_RIGHT_ARROW
])[0], -1
2265 rect
= wx
.Rect(btnLeftPos
, 6, 16, 16)
2266 if rect
.Contains(pt
):
2267 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_LEFT_ARROW
])[0], -1
2269 # Test whether a left click was made on a tab
2270 for cur
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
2272 pgInfo
= self
._pagesInfoVec
[cur
]
2274 if pgInfo
.GetPosition() == wx
.Point(-1, -1):
2277 if style
& FNB_X_ON_TAB
and cur
== self
.GetSelection():
2278 # 'x' button exists on a tab
2279 if self
._pagesInfoVec
[cur
].GetXRect().Contains(pt
):
2280 return FNB_TAB_X
, cur
2282 tabRect
= wx
.Rect(pgInfo
.GetPosition().x
, pgInfo
.GetPosition().y
, pgInfo
.GetSize().x
, pgInfo
.GetSize().y
)
2283 if tabRect
.Contains(pt
):
2287 if self
._isdragging
:
2288 # We are doing DND, so check also the region outside the tabs
2290 # try before the first tab
2291 pgInfo
= self
._pagesInfoVec
[0]
2292 tabRect
= wx
.Rect(0, pgInfo
.GetPosition().y
, pgInfo
.GetPosition().x
, self
.GetParent().GetSize().y
)
2293 if tabRect
.Contains(pt
):
2296 # try after the last tab
2297 pgInfo
= self
._pagesInfoVec
[-1]
2298 startpos
= pgInfo
.GetPosition().x
+pgInfo
.GetSize().x
2299 tabRect
= wx
.Rect(startpos
, pgInfo
.GetPosition().y
, fullrect
.width
-startpos
, self
.GetParent().GetSize().y
)
2301 if tabRect
.Contains(pt
):
2302 return FNB_TAB
, len(self
._pagesInfoVec
)-1
2305 return FNB_NOWHERE
, -1
2308 def SetSelection(self
, page
):
2309 """ Sets the selected page. """
2311 book
= self
.GetParent()
2312 book
.SetSelection(page
)
2313 self
.DoSetSelection(page
)
2316 def DoSetSelection(self
, page
):
2317 """ Does the actual selection of a page. """
2319 # Make sure that the selection is visible
2320 style
= self
.GetParent().GetWindowStyleFlag()
2321 if style
& FNB_NO_NAV_BUTTONS
:
2322 # Incase that we dont have navigation buttons,
2323 # there is no point of checking if the tab is visible
2324 # Just do the refresh
2328 if page
< len(self
._pagesInfoVec
):
2330 da_page
= self
._pParent
.GetPage(page
)
2332 # THIS IS GIVING TROUBLES!!
2336 if not self
.IsTabVisible(page
):
2338 if page
== len(self
._pagesInfoVec
) - 1:
2339 # Incase the added tab is last,
2340 # the function IsTabVisible() will always return False
2341 # and thus will cause an evil behaviour that the new
2342 # tab will hide all other tabs, we need to check if the
2343 # new selected tab can fit to the current screen
2344 if not self
.CanFitToScreen(page
):
2349 if not self
.CanFitToScreen(page
):
2350 # Redraw the tabs starting from page
2356 def DeletePage(self
, page
):
2357 """ Delete the specified page from FlatNotebook. """
2359 book
= self
.GetParent()
2360 book
.DeletePage(page
)
2364 def IsTabVisible(self
, page
):
2365 """ Returns whether a tab is visible or not. """
2367 iLastVisiblePage
= self
.GetLastVisibleTab()
2368 return page
<= iLastVisiblePage
and page
>= self
._nFrom
2371 def DoDeletePage(self
, page
):
2372 """ Does the actual page deletion. """
2374 # Remove the page from the vector
2375 book
= self
.GetParent()
2376 self
._pagesInfoVec
.pop(page
)
2378 # Thanks to Yiaanis AKA Mandrav
2379 if self
._iActivePage
>= page
:
2380 self
._iActivePage
= self
._iActivePage
- 1
2382 # The delete page was the last first on the array,
2383 # but the book still has more pages, so we set the
2384 # active page to be the first one (0)
2385 if self
._iActivePage
< 0 and self
._pagesInfoVec
:
2386 self
._iActivePage
= 0
2389 if self
._iActivePage
>= 0:
2391 book
._bForceSelection
= True
2392 book
.SetSelection(self
._iActivePage
)
2393 book
._bForceSelection
= False
2395 if not self
._pagesInfoVec
:
2396 # Erase the page container drawings
2397 dc
= wx
.ClientDC(self
)
2401 def DeleteAllPages(self
):
2402 """ Deletes all the pages. """
2404 self
._iActivePage
= -1
2406 self
._pagesInfoVec
= []
2408 # Erase the page container drawings
2409 dc
= wx
.ClientDC(self
)
2413 def DrawTabX(self
, dc
, rect
, tabIdx
):
2414 """ Draws the 'X' in the selected tab (VC8 style excluded). """
2416 if not self
.HasFlag(FNB_X_ON_TAB
) or not self
.CanDrawXOnTab():
2419 # We draw the 'x' on the active tab only
2420 if tabIdx
!= self
.GetSelection() or tabIdx
< 0:
2423 # Set the bitmap according to the button status
2424 if self
._nTabXButtonStatus
== FNB_BTN_HOVER
:
2425 xBmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
2426 elif self
._nTabXButtonStatus
== FNB_BTN_PRESSED
:
2427 xBmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
2429 xBmp
= wx
.BitmapFromXPMData(x_button_xpm
)
2432 xBmp
.SetMask(wx
.Mask(xBmp
, MASK_COLOR
))
2435 dc
.DrawBitmap(self
._tabXBgBmp
, rect
.x
, rect
.y
)
2437 # Draw the new bitmap
2438 dc
.DrawBitmap(xBmp
, rect
.x
, rect
.y
, True)
2441 self
._pagesInfoVec
[tabIdx
].SetXRect(rect
)
2444 def DrawLeftArrow(self
, dc
):
2445 """ Draw the left navigation arrow. """
2447 style
= self
.GetParent().GetWindowStyleFlag()
2448 if style
& FNB_NO_NAV_BUTTONS
:
2451 # Make sure that there are pages in the container
2452 if not self
._pagesInfoVec
:
2455 # Set the bitmap according to the button status
2456 if self
._nLeftButtonStatus
== FNB_BTN_HOVER
:
2457 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_hilite_xpm
)
2458 elif self
._nLeftButtonStatus
== FNB_BTN_PRESSED
:
2459 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_pressed_xpm
)
2461 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_xpm
)
2463 if self
._nFrom
== 0:
2464 # Handle disabled arrow
2465 arrowBmp
= wx
.BitmapFromXPMData(left_arrow_disabled_xpm
)
2467 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
2470 posx
= self
.GetLeftButtonPos()
2471 dc
.DrawBitmap(self
._leftBgBmp
, posx
, 6)
2473 # Draw the new bitmap
2474 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
2477 def DrawRightArrow(self
, dc
):
2478 """ Draw the right navigation arrow. """
2480 style
= self
.GetParent().GetWindowStyleFlag()
2481 if style
& FNB_NO_NAV_BUTTONS
:
2484 # Make sure that there are pages in the container
2485 if not self
._pagesInfoVec
:
2488 # Set the bitmap according to the button status
2489 if self
._nRightButtonStatus
== FNB_BTN_HOVER
:
2490 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_hilite_xpm
)
2491 elif self
._nRightButtonStatus
== FNB_BTN_PRESSED
:
2492 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_pressed_xpm
)
2494 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_xpm
)
2496 # Check if the right most tab is visible, if it is
2497 # don't rotate right anymore
2498 if self
._pagesInfoVec
[-1].GetPosition() != wx
.Point(-1, -1):
2499 arrowBmp
= wx
.BitmapFromXPMData(right_arrow_disabled_xpm
)
2501 arrowBmp
.SetMask(wx
.Mask(arrowBmp
, MASK_COLOR
))
2504 posx
= self
.GetRightButtonPos()
2505 dc
.DrawBitmap(self
._rightBgBmp
, posx
, 6)
2507 # Draw the new bitmap
2508 dc
.DrawBitmap(arrowBmp
, posx
, 6, True)
2511 def DrawX(self
, dc
):
2512 """ Draw the 'X' navigation button in the navigation area. """
2514 # Check if this style is enabled
2515 style
= self
.GetParent().GetWindowStyleFlag()
2516 if style
& FNB_NO_X_BUTTON
:
2519 # Make sure that there are pages in the container
2520 if not self
._pagesInfoVec
:
2523 # Set the bitmap according to the button status
2524 if self
._nXButtonStatus
== FNB_BTN_HOVER
:
2525 xbmp
= wx
.BitmapFromXPMData(x_button_hilite_xpm
)
2526 elif self
._nXButtonStatus
== FNB_BTN_PRESSED
:
2527 xbmp
= wx
.BitmapFromXPMData(x_button_pressed_xpm
)
2529 xbmp
= wx
.BitmapFromXPMData(x_button_xpm
)
2531 xbmp
.SetMask(wx
.Mask(xbmp
, MASK_COLOR
))
2534 posx
= self
.GetXPos()
2535 dc
.DrawBitmap(self
._xBgBmp
, posx
, 6)
2537 # Draw the new bitmap
2538 dc
.DrawBitmap(xbmp
, posx
, 6, True)
2541 def OnMouseMove(self
, event
):
2542 """ Handles the wx.EVT_MOTION for PageContainerBase. """
2544 if self
._pagesInfoVec
and self
.IsShown():
2546 xButtonStatus
= self
._nXButtonStatus
2547 xTabButtonStatus
= self
._nTabXButtonStatus
2548 rightButtonStatus
= self
._nRightButtonStatus
2549 leftButtonStatus
= self
._nLeftButtonStatus
2550 style
= self
.GetParent().GetWindowStyleFlag()
2552 self
._nXButtonStatus
= FNB_BTN_NONE
2553 self
._nRightButtonStatus
= FNB_BTN_NONE
2554 self
._nLeftButtonStatus
= FNB_BTN_NONE
2555 self
._nTabXButtonStatus
= FNB_BTN_NONE
2557 where
, tabIdx
= self
.HitTest(event
.GetPosition())
2560 if event
.LeftIsDown():
2562 self
._nXButtonStatus
= (self
._nLeftClickZone
==FNB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
2566 self
._nXButtonStatus
= FNB_BTN_HOVER
2568 elif where
== FNB_TAB_X
:
2569 if event
.LeftIsDown():
2571 self
._nTabXButtonStatus
= (self
._nLeftClickZone
==FNB_TAB_X
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
2575 self
._nTabXButtonStatus
= FNB_BTN_HOVER
2577 elif where
== FNB_RIGHT_ARROW
:
2578 if event
.LeftIsDown():
2580 self
._nRightButtonStatus
= (self
._nLeftClickZone
==FNB_RIGHT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
2584 self
._nRightButtonStatus
= FNB_BTN_HOVER
2586 elif where
== FNB_LEFT_ARROW
:
2587 if event
.LeftIsDown():
2589 self
._nLeftButtonStatus
= (self
._nLeftClickZone
==FNB_LEFT_ARROW
and [FNB_BTN_PRESSED
] or [FNB_BTN_NONE
])[0]
2593 self
._nLeftButtonStatus
= FNB_BTN_HOVER
2595 elif where
== FNB_TAB
:
2596 # Call virtual method for showing tooltip
2597 self
.ShowTabTooltip(tabIdx
)
2599 if not self
.GetEnabled(tabIdx
):
2600 # Set the cursor to be 'No-entry'
2601 wx
.SetCursor(wx
.StockCursor(wx
.CURSOR_NO_ENTRY
))
2603 # Support for drag and drop
2604 if event
.LeftIsDown() and not (style
& FNB_NODRAG
):
2606 self
._isdragging
= True
2607 draginfo
= FNBDragInfo(self
, tabIdx
)
2608 drginfo
= cPickle
.dumps(draginfo
)
2609 dataobject
= wx
.CustomDataObject(wx
.CustomDataFormat("FlatNotebook"))
2610 dataobject
.SetData(drginfo
)
2611 dragSource
= wx
.DropSource(self
)
2612 dragSource
.SetData(dataobject
)
2613 dragSource
.DoDragDrop(wx
.Drag_DefaultMove
)
2615 bRedrawX
= self
._nXButtonStatus
!= xButtonStatus
2616 bRedrawRight
= self
._nRightButtonStatus
!= rightButtonStatus
2617 bRedrawLeft
= self
._nLeftButtonStatus
!= leftButtonStatus
2618 bRedrawTabX
= self
._nTabXButtonStatus
!= xTabButtonStatus
2620 if (bRedrawX
or bRedrawRight
or bRedrawLeft
or bRedrawTabX
):
2622 dc
= wx
.ClientDC(self
)
2629 self
.DrawLeftArrow(dc
)
2633 self
.DrawRightArrow(dc
)
2637 self
.DrawTabX(dc
, self
._pagesInfoVec
[tabIdx
].GetXRect(), tabIdx
)
2642 def GetLastVisibleTab(self
):
2643 """ Returns the last visible tab. """
2647 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
2649 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
2655 def GetNumTabsCanScrollLeft(self
):
2656 """ Returns the number of tabs than can be scrolled left. """
2658 # Reserved area for the buttons (<>x)
2659 rect
= self
.GetClientRect()
2660 clientWidth
= rect
.width
2661 posx
= self
._pParent
._nPadding
2665 dc
= wx
.ClientDC(self
)
2667 # In case we have error prevent crash
2671 style
= self
.GetParent().GetWindowStyleFlag()
2673 for ii
in xrange(self
._nFrom
, -1, -1):
2675 boldFont
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
2676 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
2677 dc
.SetFont(boldFont
)
2679 width
, height
= dc
.GetTextExtent("Tp")
2681 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 6 pixels as padding
2682 if style
& FNB_VC71
:
2683 tabHeight
= (style
& FNB_BOTTOM
and [tabHeight
- 4] or [tabHeight
])[0]
2684 elif style
& FNB_FANCY_TABS
:
2685 tabHeight
= (style
& FNB_BOTTOM
and [tabHeight
- 3] or [tabHeight
])[0]
2687 width
, pom
= dc
.GetTextExtent(self
.GetPageText(ii
))
2688 if style
!= FNB_VC71
:
2689 shapePoints
= int(tabHeight
*math
.tan(float(self
._pagesInfoVec
[ii
].GetTabAngle())/180.0*math
.pi
))
2693 tabWidth
= self
._pParent
._nPadding
*2 + width
2695 if not (style
& FNB_VC71
):
2697 tabWidth
+= 2*shapePoints
2699 hasImage
= self
._ImageList
!= None and self
._pagesInfoVec
[ii
].GetImageIndex() != -1
2701 # For VC71 style, we only add the icon size (16 pixels)
2704 if not self
.IsDefaultTabs():
2705 tabWidth
+= 16 + self
._pParent
._nPadding
2708 tabWidth
+= 16 + self
._pParent
._nPadding
+ shapePoints
/2
2710 if posx
+ tabWidth
+ self
.GetButtonsAreaLength() >= clientWidth
:
2713 numTabs
= numTabs
+ 1
2719 def IsDefaultTabs(self
):
2720 """ Returns whether a tab has a default style. """
2722 style
= self
.GetParent().GetWindowStyleFlag()
2723 res
= (style
& FNB_VC71
) or (style
& FNB_FANCY_TABS
)
2727 def AdvanceSelection(self
, bForward
=True):
2729 Cycles through the tabs.
2730 The call to this function generates the page changing events.
2733 nSel
= self
.GetSelection()
2738 nMax
= self
.GetPageCount() - 1
2740 self
.SetSelection((nSel
== nMax
and [0] or [nSel
+ 1])[0])
2742 self
.SetSelection((nSel
== 0 and [nMax
] or [nSel
- 1])[0])
2745 def OnMouseLeave(self
, event
):
2746 """ Handles the wx.EVT_LEAVE_WINDOW event for PageContainerBase. """
2748 self
._nLeftButtonStatus
= FNB_BTN_NONE
2749 self
._nXButtonStatus
= FNB_BTN_NONE
2750 self
._nRightButtonStatus
= FNB_BTN_NONE
2751 self
._nTabXButtonStatus
= FNB_BTN_NONE
2753 dc
= wx
.ClientDC(self
)
2755 self
.DrawLeftArrow(dc
)
2756 self
.DrawRightArrow(dc
)
2758 selection
= self
.GetSelection()
2764 if not self
.IsTabVisible(selection
):
2765 if selection
== len(self
._pagesInfoVec
) - 1:
2766 if not self
.CanFitToScreen(selection
):
2773 self
.DrawTabX(dc
, self
._pagesInfoVec
[selection
].GetXRect(), selection
)
2778 def OnMouseEnterWindow(self
, event
):
2779 """ Handles the wx.EVT_ENTER_WINDOW event for PageContainerBase. """
2781 self
._nLeftButtonStatus
= FNB_BTN_NONE
2782 self
._nXButtonStatus
= FNB_BTN_NONE
2783 self
._nRightButtonStatus
= FNB_BTN_NONE
2784 self
._nLeftClickZone
= FNB_BTN_NONE
2789 def ShowTabTooltip(self
, tabIdx
):
2790 """ Shows a tab tooltip. """
2792 pWindow
= self
._pParent
.GetPage(tabIdx
)
2795 pToolTip
= pWindow
.GetToolTip()
2796 if pToolTip
and pToolTip
.GetWindow() == pWindow
:
2797 self
.SetToolTipString(pToolTip
.GetTip())
2800 def FillGradientColor(self
, dc
, rect
):
2801 """ Gradient fill from colour 1 to colour 2 with top to bottom. """
2803 if rect
.height
< 1 or rect
.width
< 1:
2808 # calculate gradient coefficients
2809 style
= self
.GetParent().GetWindowStyleFlag()
2810 col2
= ((style
& FNB_BOTTOM
) and [self
._colorTo
] or [self
._colorFrom
])[0]
2811 col1
= ((style
& FNB_BOTTOM
) and [self
._colorFrom
] or [self
._colorTo
])[0]
2813 rf
, gf
, bf
= 0, 0, 0
2814 rstep
= float(col2
.Red() - col1
.Red())/float(size
)
2815 gstep
= float(col2
.Green() - col1
.Green())/float(size
)
2816 bstep
= float(col2
.Blue() - col1
.Blue())/float(size
)
2818 for y
in xrange(rect
.y
, rect
.y
+ size
):
2819 currCol
= wx
.Colour(col1
.Red() + rf
, col1
.Green() + gf
, col1
.Blue() + bf
)
2820 dc
.SetBrush(wx
.Brush(currCol
))
2821 dc
.SetPen(wx
.Pen(currCol
))
2822 dc
.DrawLine(rect
.x
, y
, rect
.x
+ rect
.width
, y
)
2828 def SetPageImage(self
, page
, imgindex
):
2829 """ Sets the image index associated to a page. """
2831 if page
< len(self
._pagesInfoVec
):
2833 self
._pagesInfoVec
[page
].SetImageIndex(imgindex
)
2837 def GetPageImageIndex(self
, page
):
2838 """ Returns the image index associated to a page. """
2840 if page
< len(self
._pagesInfoVec
):
2842 return self
._pagesInfoVec
[page
].GetImageIndex()
2847 def OnDropTarget(self
, x
, y
, nTabPage
, wnd_oldContainer
):
2848 """ Handles the drop action from a DND operation. """
2850 # Disable drag'n'drop for disabled tab
2851 if not wnd_oldContainer
._pagesInfoVec
[nTabPage
].GetEnabled():
2852 return wx
.DragCancel
2854 self
._isdragging
= True
2855 oldContainer
= wnd_oldContainer
2858 where
, nIndex
= self
.HitTest(wx
.Point(x
, y
))
2860 oldNotebook
= oldContainer
.GetParent()
2861 newNotebook
= self
.GetParent()
2863 if oldNotebook
== newNotebook
:
2867 if where
== FNB_TAB
:
2868 self
.MoveTabPage(nTabPage
, nIndex
)
2872 if wx
.Platform
in ["__WXMSW__", "__WXGTK__"]:
2875 window
= oldNotebook
.GetPage(nTabPage
)
2878 where
, nIndex
= newNotebook
._pages
.HitTest(wx
.Point(x
, y
))
2879 caption
= oldContainer
.GetPageText(nTabPage
)
2880 imageindex
= oldContainer
.GetPageImageIndex(nTabPage
)
2881 oldNotebook
.RemovePage(nTabPage
)
2882 window
.Reparent(newNotebook
)
2884 newNotebook
.InsertPage(nIndex
, window
, caption
, True, imageindex
)
2886 self
._isdragging
= False
2891 def MoveTabPage(self
, nMove
, nMoveTo
):
2892 """ Moves a tab inside the same FlatNotebook. """
2894 if nMove
== nMoveTo
:
2897 elif nMoveTo
< len(self
._pParent
._windows
):
2898 nMoveTo
= nMoveTo
+ 1
2900 self
._pParent
.Freeze()
2902 # Remove the window from the main sizer
2903 nCurSel
= self
._pParent
._pages
.GetSelection()
2904 self
._pParent
._mainSizer
.Detach(self
._pParent
._windows
[nCurSel
])
2905 self
._pParent
._windows
[nCurSel
].Hide()
2907 pWindow
= self
._pParent
._windows
[nMove
]
2908 self
._pParent
._windows
.pop(nMove
)
2909 self
._pParent
._windows
.insert(nMoveTo
-1, pWindow
)
2911 pgInfo
= self
._pagesInfoVec
[nMove
]
2913 self
._pagesInfoVec
.pop(nMove
)
2914 self
._pagesInfoVec
.insert(nMoveTo
- 1, pgInfo
)
2916 # Add the page according to the style
2917 pSizer
= self
._pParent
._mainSizer
2918 style
= self
.GetParent().GetWindowStyleFlag()
2920 if style
& FNB_BOTTOM
:
2922 pSizer
.Insert(0, pWindow
, 1, wx
.EXPAND
)
2926 # We leave a space of 1 pixel around the window
2927 pSizer
.Add(pWindow
, 1, wx
.EXPAND
)
2932 self
._iActivePage
= nMoveTo
- 1
2933 self
.DoSetSelection(self
._iActivePage
)
2935 self
._pParent
.Thaw()
2938 def CanFitToScreen(self
, page
):
2939 """ Returns whether all the tabs can fit in the available space. """
2941 # Incase the from is greater than page,
2942 # we need to reset the self._nFrom, so in order
2943 # to force the caller to do so, we return False
2944 if self
._nFrom
> page
:
2947 # Calculate the tab width including borders and image if any
2948 dc
= wx
.ClientDC(self
)
2950 style
= self
.GetParent().GetWindowStyleFlag()
2952 width
, height
= dc
.GetTextExtent("Tp")
2953 width
, pom
= dc
.GetTextExtent(self
.GetPageText(page
))
2955 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 6 pixels as padding
2957 if style
& FNB_VC71
:
2958 tabHeight
= (style
& FNB_BOTTOM
and [tabHeight
- 4] or [tabHeight
])[0]
2959 elif style
& FNB_FANCY_TABS
:
2960 tabHeight
= (style
& FNB_BOTTOM
and [tabHeight
- 2] or [tabHeight
])[0]
2962 tabWidth
= self
._pParent
._nPadding
* 2 + width
2964 if not style
& FNB_VC71
:
2965 shapePoints
= int(tabHeight
*math
.tan(float(self
._pagesInfoVec
[page
].GetTabAngle())/180.0*math
.pi
))
2969 if not style
& FNB_VC71
:
2971 tabWidth
+= 2*shapePoints
2973 hasImage
= self
._ImageList
!= None
2976 hasImage
&= self
._pagesInfoVec
[page
].GetImageIndex() != -1
2978 # For VC71 style, we only add the icon size (16 pixels)
2979 if hasImage
and (style
& FNB_VC71
or style
& FNB_FANCY_TABS
):
2983 tabWidth
+= 16 + shapePoints
/2
2985 # Check if we can draw more
2986 posx
= self
._pParent
._nPadding
2988 if self
._nFrom
>= 0:
2989 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
2990 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
2992 posx
+= self
._pagesInfoVec
[ii
].GetSize().x
2994 rect
= self
.GetClientRect()
2995 clientWidth
= rect
.width
2997 if posx
+ tabWidth
+ self
.GetButtonsAreaLength() >= clientWidth
:
3003 def GetNumOfVisibleTabs(self
):
3004 """ Returns the number of visible tabs. """
3007 for ii
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
3008 if self
._pagesInfoVec
[ii
].GetPosition() == wx
.Point(-1, -1):
3015 def GetEnabled(self
, page
):
3016 """ Returns whether a tab is enabled or not. """
3018 if page
>= len(self
._pagesInfoVec
):
3019 return True # Seems strange, but this is the default
3021 return self
._pagesInfoVec
[page
].GetEnabled()
3024 def Enable(self
, page
, enabled
=True):
3025 """ Enables or disables a tab. """
3027 if page
>= len(self
._pagesInfoVec
):
3030 self
._pagesInfoVec
[page
].Enable(enabled
)
3033 def GetLeftButtonPos(self
):
3034 """ Returns the left button position in the navigation area. """
3036 style
= self
.GetParent().GetWindowStyleFlag()
3037 rect
= self
.GetClientRect()
3038 clientWidth
= rect
.width
3040 if style
& FNB_NO_X_BUTTON
:
3041 return clientWidth
- 38
3043 return clientWidth
- 54
3046 def GetRightButtonPos(self
):
3047 """ Returns the right button position in the navigation area. """
3049 style
= self
.GetParent().GetWindowStyleFlag()
3050 rect
= self
.GetClientRect()
3051 clientWidth
= rect
.width
3053 if style
& FNB_NO_X_BUTTON
:
3054 return clientWidth
- 22
3056 return clientWidth
- 38
3060 """ Returns the 'X' button position in the navigation area. """
3062 style
= self
.GetParent().GetWindowStyleFlag()
3063 rect
= self
.GetClientRect()
3064 clientWidth
= rect
.width
3066 if style
& FNB_NO_X_BUTTON
:
3069 return clientWidth
- 22
3072 def GetButtonsAreaLength(self
):
3073 """ Returns the navigation area width. """
3075 style
= self
.GetParent().GetWindowStyleFlag()
3077 if style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
:
3079 elif style
& FNB_NO_NAV_BUTTONS
and not style
& FNB_NO_X_BUTTON
:
3081 elif not style
& FNB_NO_NAV_BUTTONS
and style
& FNB_NO_X_BUTTON
:
3088 def GetSingleLineBorderColor(self
):
3090 if self
.HasFlag(FNB_FANCY_TABS
):
3091 return self
._colorFrom
3096 def DrawTabsLine(self
, dc
):
3097 """ Draws a line over the tabs. """
3099 clntRect
= self
.GetClientRect()
3100 clientRect3
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
)
3102 if self
.HasFlag(FNB_BOTTOM
):
3104 clientRect
= wx
.Rect(0, 2, clntRect
.width
, clntRect
.height
- 2)
3105 clientRect2
= wx
.Rect(0, 1, clntRect
.width
, clntRect
.height
- 1)
3109 clientRect
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 2)
3110 clientRect2
= wx
.Rect(0, 0, clntRect
.width
, clntRect
.height
- 1)
3112 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
3113 dc
.SetPen(wx
.Pen(self
.GetSingleLineBorderColor()))
3114 dc
.DrawRectangleRect(clientRect2
)
3115 dc
.DrawRectangleRect(clientRect3
)
3117 dc
.SetPen(wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
)))
3118 dc
.DrawRectangleRect(clientRect
)
3120 if not self
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
3122 dc
.SetPen(wx
.Pen((self
.HasFlag(FNB_VC71
) and [wx
.Colour(247, 243, 233)] or [self
._tabAreaColor
])[0]))
3123 dc
.DrawLine(0, 0, 0, clientRect
.height
+1)
3125 if self
.HasFlag(FNB_BOTTOM
):
3127 dc
.DrawLine(0, clientRect
.height
+1, clientRect
.width
, clientRect
.height
+1)
3130 dc
.DrawLine(0, 0, clientRect
.width
, 0)
3132 dc
.DrawLine(clientRect
.width
- 1, 0, clientRect
.width
- 1, clientRect
.height
+1)
3135 def HasFlag(self
, flag
):
3136 """ Returns whether a flag is present in the FlatNotebook style. """
3138 style
= self
.GetParent().GetWindowStyleFlag()
3139 res
= (style
& flag
and [True] or [False])[0]
3143 def ClearFlag(self
, flag
):
3144 """ Deletes a flag from the FlatNotebook style. """
3146 style
= self
.GetParent().GetWindowStyleFlag()
3148 self
.SetWindowStyleFlag(style
)
3151 def TabHasImage(self
, tabIdx
):
3152 """ Returns whether a tab has an associated image index or not. """
3155 return self
._pagesInfoVec
[tabIdx
].GetImageIndex() != -1
3160 def OnLeftDClick(self
, event
):
3161 """ Handles the wx.EVT_LEFT_DCLICK event for PageContainerBase. """
3163 if self
.HasFlag(FNB_DCLICK_CLOSES_TABS
):
3165 where
, tabIdx
= self
.HitTest(event
.GetPosition())
3167 if where
== FNB_TAB
:
3168 self
.DeletePage(tabIdx
)
3175 def SetImageList(self
, imglist
):
3176 """ Sets the image list for the page control. """
3178 self
._ImageList
= imglist
3181 def GetImageList(self
):
3182 """ Returns the image list for the page control. """
3184 return self
._ImageList
3187 def GetSelection(self
):
3188 """ Returns the current selected page. """
3190 return self
._iActivePage
3193 def GetPageCount(self
):
3194 """ Returns the number of tabs in the FlatNotebook control. """
3196 return len(self
._pagesInfoVec
)
3199 def GetPageText(self
, page
):
3200 """ Returns the tab caption of the page. """
3202 return self
._pagesInfoVec
[page
].GetCaption()
3205 def SetPageText(self
, page
, text
):
3206 """ Sets the tab caption of the page. """
3208 self
._pagesInfoVec
[page
].SetCaption(text
)
3212 def CanDrawXOnTab(self
):
3213 """ Returns whether an 'X' can be drawn on a tab (all styles except VC8. """
3218 # ---------------------------------------------------------------------------- #
3219 # Class FlatNotebook
3220 # Simple super class based on PageContainerBase
3221 # ---------------------------------------------------------------------------- #
3223 class FlatNotebook(FlatNotebookBase
):
3225 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
3226 style
=0, name
="FlatNotebook"):
3228 Default class constructor.
3230 It is better to use directly the StyledNotebook class (see below) and then
3231 assigning the style you wish instead of calling FlatNotebook.
3234 style |
= wx
.TAB_TRAVERSAL
3236 FlatNotebookBase
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
3237 self
._pages
= self
.CreatePageContainer()
3240 def CreatePageContainer(self
):
3241 """ Creates the page container. """
3243 return FlatNotebookBase
.CreatePageContainer(self
)
3246 #--------------------------------------------------------------------
3247 # StyledNotebook - a notebook with look n feel of Visual Studio 2005
3248 #--------------------------------------------------------------------
3250 class StyledNotebook(FlatNotebookBase
):
3252 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
3253 style
=0, name
="StyledNotebook"):
3254 """ Default class constructor.
3256 It is better to use directly the StyledNotebook class and then
3257 assigning the style you wish instead of calling FlatNotebook.
3260 style |
= wx
.TAB_TRAVERSAL
3262 FlatNotebookBase
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
3264 # Custom initialization of the tab area
3266 # Initialise the default style colors
3267 self
.SetNonActiveTabTextColour(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNTEXT
))
3270 def CreatePageContainer(self
):
3271 """ Creates the page container. """
3273 return StyledTabsContainer(self
, wx
.ID_ANY
)
3276 # ---------------------------------------------------------------------------- #
3277 # Class StyledTabsContainer
3278 # Acts as a container for the pages you add to FlatNotebook
3279 # A more generic and more powerful implementation of PageContainerBase, can
3280 # handle also VC8 tabs style
3281 # ---------------------------------------------------------------------------- #
3283 class StyledTabsContainer(PageContainerBase
):
3285 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
,
3287 """ Default class constructor. """
3291 self
._colorTo
= LightColour(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
), 0)
3292 self
._colorFrom
= LightColour(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
), 60)
3294 PageContainerBase
.__init
__(self
, parent
, id, pos
, size
, style
)
3296 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
3299 def NumberTabsCanFit(self
, dc
):
3300 """ Returns the number of tabs that can fit inside the available space. """
3302 rect
= self
.GetClientRect()
3303 clientWidth
= rect
.width
3308 # We take the maxmimum font size, this is
3309 # achieved by setting the font to be bold
3310 font
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3311 font
.SetWeight(wx
.FONTWEIGHT_BOLD
)
3314 width
, height
= dc
.GetTextExtent("Tp")
3316 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels
3317 # The drawing starts from posx
3318 posx
= self
._pParent
.GetPadding()
3320 for i
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
3322 width
, pom
= dc
.GetTextExtent(self
.GetPageText(i
))
3324 # Set a minimum size to a tab
3328 tabWidth
= self
._pParent
.GetPadding() * 2 + width
3330 # Add the image width if it exist
3331 if self
.TabHasImage(i
):
3332 tabWidth
+= 16 + self
._pParent
.GetPadding()
3334 vc8glitch
= tabHeight
+ FNB_HEIGHT_SPACER
3335 if posx
+ tabWidth
+ vc8glitch
+ self
.GetButtonsAreaLength() >= clientWidth
:
3338 # Add a result to the returned vector
3339 tabRect
= wx
.Rect(posx
, VERTICAL_BORDER_PADDING
, tabWidth
, tabHeight
)
3340 vTabInfo
.append(tabRect
)
3343 posx
+= tabWidth
+ FNB_HEIGHT_SPACER
3348 def GetNumTabsCanScrollLeft(self
):
3349 """ Returns the number of tabs than can be scrolled left. """
3351 # Reserved area for the buttons (<>x)
3352 rect
= self
.GetClientRect()
3353 clientWidth
= rect
.width
3354 posx
= self
._pParent
.GetPadding()
3358 dc
= wx
.ClientDC(self
)
3360 # Incase we have error prevent crash
3364 style
= self
.GetParent().GetWindowStyleFlag()
3366 for i
in xrange(self
._nFrom
, -1, -1):
3368 boldFont
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3369 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
3370 dc
.SetFont(boldFont
)
3372 width
, height
= dc
.GetTextExtent("Tp")
3374 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 6 pixels as padding
3376 if style
& FNB_VC71
:
3377 tabHeight
= (self
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 4] or [tabHeight
])[0]
3378 elif style
& FNB_FANCY_TABS
:
3379 tabHeight
= (self
.HasFlag(FNB_BOTTOM
) and [tabHeight
- 3] or [tabHeight
])[0]
3381 width
, pom
= dc
.GetTextExtent(self
.GetPageText(i
))
3383 if style
!= FNB_VC71
:
3384 shapePoints
= int(tabHeight
*math
.tan(float(self
._pagesInfoVec
[i
].GetTabAngle())/180.0*math
.pi
))
3388 tabWidth
= self
._pParent
.GetPadding() * 2 + width
3389 if not style
& FNB_VC71
:
3391 tabWidth
+= 2*shapePoints
3393 # For VC71 style, we only add the icon size (16 pixels)
3394 if self
.TabHasImage(i
):
3396 if not self
.IsDefaultTabs():
3397 tabWidth
+= 16 + self
._pParent
.GetPadding()
3400 tabWidth
+= 16 + self
._pParent
.GetPadding() + shapePoints
/2
3402 vc8glitch
= (style
& FNB_VC8
and [tabHeight
+ FNB_HEIGHT_SPACER
] or [0])[0]
3404 if posx
+ tabWidth
+ vc8glitch
+ self
.GetButtonsAreaLength() >= clientWidth
:
3407 numTabs
= numTabs
+ 1
3413 def CanDrawXOnTab(self
):
3414 """ Returns whether an 'X' button can be drawn on a tab (not VC8 style). """
3416 style
= self
.GetParent().GetWindowStyleFlag()
3417 isVC8
= (style
& FNB_VC8
and [True] or [False])[0]
3421 def IsDefaultTabs(self
):
3422 """ Returns whether a tab has a default style or not. """
3424 style
= self
.GetParent().GetWindowStyleFlag()
3425 res
= (style
& FNB_VC71
) or (style
& FNB_FANCY_TABS
) or (style
& FNB_VC8
)
3429 def HitTest(self
, pt
):
3430 """ HitTest specific method for VC8 style. """
3432 fullrect
= self
.GetClientRect()
3433 btnLeftPos
= self
.GetLeftButtonPos()
3434 btnRightPos
= self
.GetRightButtonPos()
3435 btnXPos
= self
.GetXPos()
3436 style
= self
.GetParent().GetWindowStyleFlag()
3439 if not self
._pagesInfoVec
:
3440 return FNB_NOWHERE
, -1
3442 rect
= wx
.Rect(btnXPos
, 8, 16, 16)
3444 if rect
.Contains(pt
):
3445 return (style
& FNB_NO_X_BUTTON
and [FNB_NOWHERE
] or [FNB_X
])[0], -1
3447 rect
= wx
.Rect(btnRightPos
, 8, 16, 16)
3449 if rect
.Contains(pt
):
3450 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_RIGHT_ARROW
])[0], -1
3452 rect
= wx
.Rect(btnLeftPos
, 8, 16, 16)
3454 if rect
.Contains(pt
):
3455 return (style
& FNB_NO_NAV_BUTTONS
and [FNB_NOWHERE
] or [FNB_LEFT_ARROW
])[0], -1
3457 # Test whether a left click was made on a tab
3460 for cur
in xrange(self
._nFrom
, len(self
._pagesInfoVec
)):
3462 pgInfo
= self
._pagesInfoVec
[cur
]
3464 if pgInfo
.GetPosition() == wx
.Point(-1, -1):
3469 if self
._pagesInfoVec
[cur
].GetRegion().Contains(pt
.x
, pt
.y
):
3471 if bFoundMatch
or cur
== self
.GetSelection():
3480 if style
& FNB_X_ON_TAB
and cur
== self
.GetSelection():
3482 # 'x' button exists on a tab
3483 if self
._pagesInfoVec
[cur
].GetXRect().Contains(pt
):
3484 return FNB_TAB_X
, cur
3486 tabRect
= wx
.Rect(pgInfo
.GetPosition().x
, pgInfo
.GetPosition().y
, pgInfo
.GetSize().x
, pgInfo
.GetSize().y
)
3488 if tabRect
.Contains(pt
):
3492 return FNB_TAB
, tabIdx
3494 if self
._isdragging
:
3495 # We are doing DND, so check also the region outside the tabs
3496 # try before the first tab
3497 pgInfo
= self
._pagesInfoVec
[0]
3498 tabRect
= wx
.Rect(0, pgInfo
.GetPosition().y
, pgInfo
.GetPosition().x
, self
.GetParent().GetSize().y
)
3499 if tabRect
.Contains(pt
):
3502 # try after the last tab
3503 pgInfo
= self
._pagesInfoVec
[-1]
3504 startpos
= pgInfo
.GetPosition().x
+pgInfo
.GetSize().x
3505 tabRect
= wx
.Rect(startpos
, pgInfo
.GetPosition().y
, fullrect
.width
-startpos
, self
.GetParent().GetSize().y
)
3507 if tabRect
.Contains(pt
):
3508 return FNB_TAB
, len(self
._pagesInfoVec
)
3511 return FNB_NOWHERE
, -1
3514 def OnPaint(self
, event
):
3516 Handles the wx.EVT_PAINT event for StyledTabsContainer.
3517 Switches to PageContainerBase.OnPaint() method if the style is not VC8.
3520 if not self
.HasFlag(FNB_VC8
):
3522 PageContainerBase
.OnPaint(self
, event
)
3525 # Visual studio 8 style
3526 dc
= wx
.BufferedPaintDC(self
)
3528 if "__WXMAC__" in wx
.PlatformInfo
:
3529 # Works well on MSW & GTK, however this lines should be skipped on MAC
3530 if not self
._pagesInfoVec
or self
._nFrom
>= len(self
._pagesInfoVec
):
3535 # Set the font for measuring the tab height
3536 normalFont
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3537 boldFont
= wx
.SystemSettings
.GetFont(wx
.SYS_DEFAULT_GUI_FONT
)
3538 boldFont
.SetWeight(wx
.FONTWEIGHT_BOLD
)
3540 if "__WXGTK__" in wx
.PlatformInfo
:
3541 dc
.SetFont(boldFont
)
3543 width
, height
= dc
.GetTextExtent("Tp")
3545 tabHeight
= height
+ FNB_HEIGHT_SPACER
# We use 8 pixels as padding
3547 # Calculate the number of rows required for drawing the tabs
3548 rect
= self
.GetClientRect()
3550 # Set the maximum client size
3551 self
.SetSizeHints(self
.GetButtonsAreaLength(), tabHeight
)
3552 borderPen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
3555 backBrush
= wx
.Brush(self
._tabAreaColor
)
3556 noselBrush
= wx
.Brush(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNFACE
))
3557 selBrush
= wx
.Brush(self
._activeTabColor
)
3558 size
= self
.GetSize()
3561 dc
.SetTextBackground(self
.GetBackgroundColour())
3562 dc
.SetTextForeground(self
._activeTextColor
)
3564 # If border style is set, set the pen to be border pen
3565 if self
.HasFlag(FNB_TABS_BORDER_SIMPLE
):
3566 dc
.SetPen(borderPen
)
3568 dc
.SetPen(wx
.TRANSPARENT_PEN
)
3570 lightFactor
= (self
.HasFlag(FNB_BACKGROUND_GRADIENT
) and [70] or [0])[0]
3571 # For VC8 style, we color the tab area in gradient coloring
3572 PaintStraightGradientBox(dc
, self
.GetClientRect(), self
._tabAreaColor
, LightColour(self
._tabAreaColor
, lightFactor
))
3574 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
3575 dc
.DrawRectangle(0, 0, size
.x
, size
.y
)
3577 # Take 3 bitmaps for the background for the buttons
3579 mem_dc
= wx
.MemoryDC()
3581 #---------------------------------------
3583 #---------------------------------------
3584 rect
= wx
.Rect(self
.GetXPos(), 6, 16, 14)
3585 mem_dc
.SelectObject(self
._xBgBmp
)
3586 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
3587 mem_dc
.SelectObject(wx
.NullBitmap
)
3589 #---------------------------------------
3591 #---------------------------------------
3592 rect
= wx
.Rect(self
.GetRightButtonPos(), 6, 16, 14)
3593 mem_dc
.SelectObject(self
._rightBgBmp
)
3594 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
3595 mem_dc
.SelectObject(wx
.NullBitmap
)
3597 #---------------------------------------
3599 #---------------------------------------
3600 rect
= wx
.Rect(self
.GetLeftButtonPos(), 6, 16, 14)
3601 mem_dc
.SelectObject(self
._leftBgBmp
)
3602 mem_dc
.Blit(0, 0, rect
.width
, rect
.height
, dc
, rect
.x
, rect
.y
)
3603 mem_dc
.SelectObject(wx
.NullBitmap
)
3605 # We always draw the bottom/upper line of the tabs
3606 # regradless the style
3607 dc
.SetPen(borderPen
)
3608 self
.DrawTabsLine(dc
)
3611 dc
.SetPen(borderPen
)
3614 dc
.SetFont(boldFont
)
3617 # Update all the tabs from 0 to 'self._nFrom' to be non visible
3618 for i
in xrange(self
._nFrom
):
3620 self
._pagesInfoVec
[i
].SetPosition(wx
.Point(-1, -1))
3621 self
._pagesInfoVec
[i
].GetRegion().Clear()
3623 # Draw the visible tabs, in VC8 style, we draw them from right to left
3624 vTabsInfo
= self
.NumberTabsCanFit(dc
)
3626 for cur
in xrange(len(vTabsInfo
) - 1, -1, -1):
3628 # 'i' points to the index of the currently drawn tab
3629 # in self._pagesInfoVec vector
3630 i
= self
._nFrom
+ cur
3631 dc
.SetPen(borderPen
)
3632 dc
.SetBrush((i
==self
.GetSelection() and [selBrush
] or [noselBrush
])[0])
3634 # Calculate the text length using the bold font, so when selecting a tab
3635 # its width will not change
3636 dc
.SetFont(boldFont
)
3637 width
, pom
= dc
.GetTextExtent(self
.GetPageText(i
))
3639 # Now set the font to the correct font
3640 dc
.SetFont((i
==self
.GetSelection() and [boldFont
] or [normalFont
])[0])
3642 # Set a minimum size to a tab
3646 # Add the padding to the tab width
3648 # +-----------------------------------------------------------+
3649 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
3650 # +-----------------------------------------------------------+
3652 tabWidth
= self
._pParent
.GetPadding() * 2 + width
3653 imageYCoord
= (self
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
3655 if self
.TabHasImage(i
):
3656 tabWidth
+= 16 + self
._pParent
.GetPadding()
3658 posx
= vTabsInfo
[cur
].x
3660 # By default we clean the tab region
3661 # incase we use the VC8 style which requires
3662 # the region, it will be filled by the function
3664 self
._pagesInfoVec
[i
].GetRegion().Clear()
3666 # Clean the 'x' buttn on the tab
3667 # 'Clean' rectanlge is a rectangle with width or height
3668 # with values lower than or equal to 0
3669 self
._pagesInfoVec
[i
].GetXRect().SetSize(wx
.Size(-1, -1))
3672 # Incase we are drawing the active tab
3673 # we need to redraw so it will appear on top
3675 if i
== self
.GetSelection():
3677 activeTabPosx
= posx
3681 self
.DrawVC8Tab(dc
, posx
, i
, tabWidth
, tabHeight
)
3683 # Text drawing offset from the left border of the
3685 # The width of the images are 16 pixels
3686 vc8ShapeLen
= tabHeight
3688 if self
.TabHasImage(i
):
3689 textOffset
= self
._pParent
.GetPadding() * 2 + 16 + vc8ShapeLen
3691 textOffset
= self
._pParent
.GetPadding() + vc8ShapeLen
3693 # Set the non-active text color
3694 if i
!= self
.GetSelection():
3695 dc
.SetTextForeground(self
._nonActiveTextColor
)
3697 if self
.TabHasImage(i
):
3698 imageXOffset
= textOffset
- 16 - self
._pParent
.GetPadding()
3699 self
._ImageList
.Draw(self
._pagesInfoVec
[i
].GetImageIndex(), dc
,
3700 posx
+ imageXOffset
, imageYCoord
,
3701 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
3703 dc
.DrawText(self
.GetPageText(i
), posx
+ textOffset
, imageYCoord
)
3705 textWidth
, textHeight
= dc
.GetTextExtent(self
.GetPageText(i
))
3707 # Restore the text forground
3708 dc
.SetTextForeground(self
._activeTextColor
)
3710 # Update the tab position & size
3711 self
._pagesInfoVec
[i
].SetPosition(wx
.Point(posx
, VERTICAL_BORDER_PADDING
))
3712 self
._pagesInfoVec
[i
].SetSize(wx
.Size(tabWidth
, tabHeight
))
3714 # Incase we are in VC8 style, redraw the active tab (incase it is visible)
3715 if self
.GetSelection() >= self
._nFrom
and self
.GetSelection() < self
._nFrom
+ len(vTabsInfo
):
3717 hasImage
= self
.TabHasImage(self
.GetSelection())
3719 dc
.SetFont(boldFont
)
3720 width
, pom
= dc
.GetTextExtent(self
.GetPageText(self
.GetSelection()))
3722 tabWidth
= self
._pParent
.GetPadding() * 2 + width
3725 tabWidth
+= 16 + self
._pParent
.GetPadding()
3727 # Set the active tab font, pen brush and font-color
3728 dc
.SetPen(borderPen
)
3729 dc
.SetBrush(selBrush
)
3730 dc
.SetFont(boldFont
)
3731 dc
.SetTextForeground(self
._activeTextColor
)
3732 self
.DrawVC8Tab(dc
, activeTabPosx
, self
.GetSelection(), tabWidth
, tabHeight
)
3734 # Text drawing offset from the left border of the
3736 # The width of the images are 16 pixels
3737 vc8ShapeLen
= tabHeight
- VERTICAL_BORDER_PADDING
- 2
3739 textOffset
= self
._pParent
.GetPadding() * 2 + 16 + vc8ShapeLen
3741 textOffset
= self
._pParent
.GetPadding() + vc8ShapeLen
3743 # Draw the image for the tab if any
3744 imageYCoord
= (self
.HasFlag(FNB_BOTTOM
) and [6] or [8])[0]
3747 imageXOffset
= textOffset
- 16 - self
._pParent
.GetPadding()
3748 self
._ImageList
.Draw(self
._pagesInfoVec
[self
.GetSelection()].GetImageIndex(), dc
,
3749 activeTabPosx
+ imageXOffset
, imageYCoord
,
3750 wx
.IMAGELIST_DRAW_TRANSPARENT
, True)
3752 dc
.DrawText(self
.GetPageText(self
.GetSelection()), activeTabPosx
+ textOffset
, imageYCoord
)
3754 # Update all tabs that can not fit into the screen as non-visible
3755 for xx
in xrange(self
._nFrom
+ len(vTabsInfo
), len(self
._pagesInfoVec
)):
3757 self
._pagesInfoVec
[xx
].SetPosition(wx
.Point(-1, -1))
3758 self
._pagesInfoVec
[xx
].GetRegion().Clear()
3760 # Draw the left/right/close buttons
3762 self
.DrawLeftArrow(dc
)
3763 self
.DrawRightArrow(dc
)
3767 def DrawVC8Tab(self
, dc
, posx
, tabIdx
, tabWidth
, tabHeight
):
3768 """ Draws the VC8 style tabs. """
3770 borderPen
= wx
.Pen(self
._colorBorder
)
3771 tabPoints
= [wx
.Point() for ii
in xrange(8)]
3773 # If we draw the first tab or the active tab,
3774 # we draw a full tab, else we draw a truncated tab
3785 tabPoints
[0].x
= (self
.HasFlag(FNB_BOTTOM
) and [posx
] or [posx
+self
._factor
])[0]
3786 tabPoints
[0].y
= (self
.HasFlag(FNB_BOTTOM
) and [2] or [tabHeight
- 3])[0]
3788 tabPoints
[1].x
= tabPoints
[0].x
+ tabHeight
- VERTICAL_BORDER_PADDING
- 3 - self
._factor
3789 tabPoints
[1].y
= (self
.HasFlag(FNB_BOTTOM
) and [tabHeight
- (VERTICAL_BORDER_PADDING
+2)] or [(VERTICAL_BORDER_PADDING
+2)])[0]
3791 tabPoints
[2].x
= tabPoints
[1].x
+ 4
3792 tabPoints
[2].y
= (self
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
3794 tabPoints
[3].x
= tabPoints
[2].x
+ tabWidth
- 2
3795 tabPoints
[3].y
= (self
.HasFlag(FNB_BOTTOM
) and [tabHeight
- VERTICAL_BORDER_PADDING
] or [VERTICAL_BORDER_PADDING
])[0]
3797 tabPoints
[4].x
= tabPoints
[3].x
+ 1
3798 tabPoints
[4].y
= (self
.HasFlag(FNB_BOTTOM
) and [tabPoints
[3].y
- 1] or [tabPoints
[3].y
+ 1])[0]
3800 tabPoints
[5].x
= tabPoints
[4].x
+ 1
3801 tabPoints
[5].y
= (self
.HasFlag(FNB_BOTTOM
) and [(tabPoints
[4].y
- 1)] or [tabPoints
[4].y
+ 1])[0]
3803 tabPoints
[6].x
= tabPoints
[2].x
+ tabWidth
3804 tabPoints
[6].y
= tabPoints
[0].y
3806 tabPoints
[7].x
= tabPoints
[0].x
3807 tabPoints
[7].y
= tabPoints
[0].y
3809 self
._pagesInfoVec
[tabIdx
].SetRegion(tabPoints
)
3813 dc
.SetBrush(wx
.Brush((tabIdx
== self
.GetSelection() and [self
._activeTabColor
] or [self
._colorTo
])[0]))
3814 dc
.SetPen(wx
.Pen((tabIdx
== self
.GetSelection() and [wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [self
._colorBorder
])[0]))
3815 dc
.DrawPolygon(tabPoints
)
3820 rect
= self
.GetClientRect()
3822 if tabIdx
!= self
.GetSelection() and not self
.HasFlag(FNB_BOTTOM
):
3825 dc
.SetPen(wx
.Pen(self
._colorBorder
))
3827 curPen
= dc
.GetPen()
3830 dc
.DrawLine(posx
, lineY
, posx
+rect
.width
, lineY
)
3832 # In case we are drawing the selected tab, we draw the border of it as well
3833 # but without the bottom (upper line incase of wxBOTTOM)
3834 if tabIdx
== self
.GetSelection():
3836 borderPen
= wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
))
3837 brush
= wx
.TRANSPARENT_BRUSH
3838 dc
.SetPen(borderPen
)
3840 dc
.DrawPolygon(tabPoints
)
3842 # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
3843 dc
.SetPen(wx
.WHITE_PEN
)
3844 dc
.DrawLine(tabPoints
[0].x
, tabPoints
[0].y
, tabPoints
[6].x
, tabPoints
[6].y
)
3846 self
.FillVC8GradientColor(dc
, tabPoints
, tabIdx
== self
.GetSelection(), tabIdx
)
3848 # Draw a thin line to the right of the non-selected tab
3849 if tabIdx
!= self
.GetSelection():
3851 dc
.SetPen(wx
.Pen(wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_3DFACE
)))
3852 dc
.DrawLine(tabPoints
[4].x
-1, tabPoints
[4].y
, tabPoints
[5].x
-1, tabPoints
[5].y
)
3853 dc
.DrawLine(tabPoints
[5].x
-1, tabPoints
[5].y
, tabPoints
[6].x
-1, tabPoints
[6].y
)
3856 def FillVC8GradientColor(self
, dc
, tabPoints
, bSelectedTab
, tabIdx
):
3857 """ Fills a tab with a gradient colour. """
3859 # calculate gradient coefficients
3860 col2
= (self
.HasFlag(FNB_BOTTOM
) and [self
._colorTo
] or [self
._colorFrom
])[0]
3861 col1
= (self
.HasFlag(FNB_BOTTOM
) and [self
._colorFrom
] or [self
._colorTo
])[0]
3863 # If colorful tabs style is set, override the tab color
3864 if self
.HasFlag(FNB_COLORFUL_TABS
):
3866 if not self
._pagesInfoVec
[tabIdx
].GetColor():
3868 # First time, generate color, and keep it in the vector
3869 tabColor
= self
.GenTabColour()
3870 self
._pagesInfoVec
[tabIdx
].SetColor(tabColor
)
3872 if self
.HasFlag(FNB_BOTTOM
):
3874 col2
= LightColour(self
._pagesInfoVec
[tabIdx
].GetColor(), 50 )
3875 col1
= LightColour(self
._pagesInfoVec
[tabIdx
].GetColor(), 80 )
3879 col1
= LightColour(self
._pagesInfoVec
[tabIdx
].GetColor(), 50 )
3880 col2
= LightColour(self
._pagesInfoVec
[tabIdx
].GetColor(), 80 )
3882 size
= abs(tabPoints
[2].y
- tabPoints
[0].y
) - 1
3884 rf
, gf
, bf
= 0, 0, 0
3885 rstep
= float(col2
.Red() - col1
.Red())/float(size
)
3886 gstep
= float(col2
.Green() - col1
.Green())/float(size
)
3887 bstep
= float(col2
.Blue() - col1
.Blue())/float(size
)
3891 # If we are drawing the selected tab, we need also to draw a line
3892 # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
3893 # by drawing the rectangle with transparent brush
3894 # the line under the selected tab will be deleted by the drwaing loop
3896 self
.DrawTabsLine(dc
)
3900 if self
.HasFlag(FNB_BOTTOM
):
3902 if y
> tabPoints
[0].y
+ size
:
3907 if y
< tabPoints
[0].y
- size
:
3910 currCol
= wx
.Colour(col1
.Red() + rf
, col1
.Green() + gf
, col1
.Blue() + bf
)
3912 dc
.SetPen((bSelectedTab
and [wx
.Pen(self
._activeTabColor
)] or [wx
.Pen(currCol
)])[0])
3913 startX
= self
.GetStartX(tabPoints
, y
)
3914 endX
= self
.GetEndX(tabPoints
, y
)
3915 dc
.DrawLine(startX
, y
, endX
, y
)
3917 # Draw the border using the 'edge' point
3918 dc
.SetPen(wx
.Pen((bSelectedTab
and [wx
.SystemSettings
.GetColour(wx
.SYS_COLOUR_BTNSHADOW
)] or [self
._colorBorder
])[0]))
3920 dc
.DrawPoint(startX
, y
)
3921 dc
.DrawPoint(endX
, y
)
3923 # Progress the color
3928 if self
.HasFlag(FNB_BOTTOM
):
3934 def GetStartX(self
, tabPoints
, y
):
3935 """ Returns the x start position of a tab. """
3937 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
3939 # We check the 3 points to the left
3940 style
= self
.GetParent().GetWindowStyleFlag()
3941 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
3948 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
+1].y
:
3951 x2
= tabPoints
[i
+1].x
3953 y2
= tabPoints
[i
+1].y
3961 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
+1].y
:
3964 x2
= tabPoints
[i
+1].x
3966 y2
= tabPoints
[i
+1].y
3971 return tabPoints
[2].x
3973 # According to the equation y = ax + b => x = (y-b)/a
3974 # We know the first 2 points
3979 a
= (y2
- y1
)/(x2
- x1
)
3981 b
= y1
- ((y2
- y1
)/(x2
- x1
))*x1
3991 def GetEndX(self
, tabPoints
, y
):
3992 """ Returns the x end position of a tab. """
3994 x1
, x2
, y1
, y2
= 0.0, 0.0, 0.0, 0.0
3996 # We check the 3 points to the left
3997 style
= self
.GetParent().GetWindowStyleFlag()
3998 bBottomStyle
= (style
& FNB_BOTTOM
and [True] or [False])[0]
4003 for i
in xrange(7, 3, -1):
4005 if y
>= tabPoints
[i
].y
and y
< tabPoints
[i
-1].y
:
4008 x2
= tabPoints
[i
-1].x
4010 y2
= tabPoints
[i
-1].y
4016 for i
in xrange(7, 3, -1):
4018 if y
<= tabPoints
[i
].y
and y
> tabPoints
[i
-1].y
:
4021 x2
= tabPoints
[i
-1].x
4023 y2
= tabPoints
[i
-1].y
4028 return tabPoints
[3].x
4030 # According to the equation y = ax + b => x = (y-b)/a
4031 # We know the first 2 points
4037 a
= (y2
- y1
)/(x2
- x1
)
4038 b
= y1
- ((y2
- y1
)/(x2
- x1
)) * x1
4048 def GenTabColour(self
):
4049 """ Generates a random soft pleasant colour for a tab. """
4051 return RandomColor()
4054 def GetSingleLineBorderColor(self
):
4056 if self
.HasFlag(FNB_VC8
):
4057 return self
._activeTabColor
4059 return PageContainerBase
.GetSingleLineBorderColor(self
)
4062 def SetFactor(self
, factor
):
4063 """ Sets the brighten colour factor. """
4065 self
._factor
= factor
4069 def GetFactor(self
):
4070 """ Returns the brighten colour factor. """