Mercurial > traipse_dev
view orpg/tools/NotebookCtrl.py @ 226:b29454610f36 beta
Traipse Beta 'OpenRPG' {100503-00}
Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for
developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to
the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user.
Update Summary (Patch-2)
Moved to Stable!
New Features:
New Namespace method with two new syntaxes
New Namespace Internal is context sensitive, always!
New Namespace External is 'as narrow as you make it'
New Namespace FutureCheck helps ensure you don't receive an incorrect node
New Namespace 2.0 documentation in the User Manual
New Namespace plugin, Allows Traipse users to use the Standard syntax !@ :: @!
New Mini Library with minis from Devin Knight
New PluginDB access for URL2Link plugin
New to Forms, they now show their content in Design Mode
New to Update Manager, checks Repo for updates on software start
New to Mini Lib node, change title in design mode
New to Game Tree, never lose a node, appends a number to the end of corrupted trees
New to Server GUI, Traipse Suite's Debug Console
New Warhammer PC Sheet
Updates:
Update to White Board layer, uses a pencil image for color button
Update to Grid Layer, uses a grid image for color button
Update to Chat Window, size of drop down menus
Update to default lobby message
Update to template Text node
Update to 4e PC Sheet node
Update to how display names are acquired
Update to Server, added some 'Pious' technology
Update to features node
Fixes:
Fix to Server GUI startup errors
Fix to Server GUI Rooms tab updating
Fix to Chat and Settings if non existant die roller is picked
Fix to Dieroller and .open() used with .vs(). Successes are correctly calculated
Fix to Alias Lib's Export to Tree, Open, Save features
Fix to alias node, now works properly
Fix to Splitter node, minor GUI cleanup
Fix to Backgrounds not loading through remote loader
Fix to Node name errors
Fix to rolling dice in chat Whispers
Fix to Splitters Sizing issues
Fix to URL2Link plugin, modified regex compilation should remove memory leak
Fix to mapy.py, a roll back due to zoomed grid issues
Fix to whiteboard_handler, Circles work by you clicking the center of the circle
Fix to Servers parse_incoming_dom which was outdated and did not respect XML
Fix to a broken link in the server welcome message
Fix to InterParse and logger requiring traceback
Fix to Update Manager Status Bar
Fix to failed image and erroneous pop up
Fix to Mini Lib node that was preventing use
Fix to plugins that parce dice but did not call InterParse
Fix to nodes for name changing by double click
Fix to Game Tree, node ordering on drag and drop corrected
Fix to Game Tree, corrupted error message was not showing
Fix to Update Manager, checks for internet connection
Fix to Update Manager, Auto Update corrections
Fix to Server GUI's broadcast, room, player messaging
author | sirebral |
---|---|
date | Mon, 03 May 2010 03:29:14 -0500 |
parents | 4385a7d0efd1 |
children |
line wrap: on
line source
# --------------------------------------------------------------------------- # # NOTEBOOKCTRL Control wxPython IMPLEMENTATION # Python Code By: # # Andrea Gavana, @ 11 Nov 2005 # Latest Revision: 06 Oct 2006, 18.10 GMT # # # AKNOWLEDGEMENTS # # A big load of thanks goes to Julianne Sharer that has implemented the new # features of left/right tabs, rotated or horizontal, with the ability to # switch between the two views by a single mouse click. Moreover, all the # work done to refactor NotebookCtrl in a more readable way has been done # by Julianne Sharer. Thanks Julianne. # # # TODO List/Caveats # # 1. Ay Idea? # # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please # Write To Me At: # # andrea.gavana@gmail.com # gavana@kpo.kz # # Or, Obviously, To The wxPython Mailing List!!! # # # End Of Comments # --------------------------------------------------------------------------- # """ A full-featured notebook control, worked out by Andrea Gavana And Julianne Sharer. Description: NotebookCtrl Mimics The Behavior Of wx.Notebook, And Most Of Its Functionalities Are Implemented In NotebookCtrl. However, NotebookCtrl Has A Lot Of Options That wx.Notebook Does Not Have, And It Is Therefore Quite Customizable. wx.Notebook Styles Not Implemented in NotebookCtrl Are: - wx.NB_MULTILINE (But NotebookCtrl Has A SpinButton To Navigate Through Tabs). Supported Customizations For NotebookCtrl Include: - Setting Individual Tab Font And Text Colour; - Images On Tabs (Line wx.Notebook); - Setting Individual Tab Colours; - Disabling/Enabling Individual Tabs (Also Visually Effective); Now Supports Grayed Out Icons When A Page Is Disabled; - Drawing Of A Small Closing "X" At The Right Of Every Tab, That Enable The User To Close A Tab With A Mouse Click (Like eMule Tab Style); - Enabling Highlighted Tabs On Selection; - Drawing Focus Indicator In Each Tab (Like wx.Notebook); - Ctrl-Tab Keyboard Navigation Between Pages; - Tab With Animated Icons (Animation On Tabs); - Drag And Drop Tabs In NotebookCtrl (Plus A Visual Arrow Effect To Indicate Dropping Position); - Drag And Drop Event; - ToolTips On Individual Tabs, With Customizable ToolTip Time Popup And ToolTip Window Size For Individual Tabs; - Possibility To Hide The TabCtrl There Is Only One Tab (Thus Maximizing The Corresponding Window); - Possibility To Convert The Tab Image Into A Close Button While Mouse Is Hovering On The Tab Image; - Popup Menus On Tabs (Popup Menus Specific To Each Tab); - Showing Pages In "Column/Row Mode", Which Means That All Pages Will Be Shown In NotebookCtrl While The Tabs Are Hidden. They Can Be Shown In Columns (Default) Or In Rows; - Possibility To Hide Tabs On User Request, Thus Showing Only The Current Panel; - Multiple Tabs Selection (Hold Ctrl Key Down And Left Mouse Click), Useful When You Use The Show All The Panels In Columns/Rows. In This Case, Only The Selected Tabs Are Shown In Columns/Rows; - Events For Mouse Events (Left Double Click, Middle Click, Right Click); - Possibility To Reparent A NotebookCtrl Page To A Freshly Created Frame As A Simple Panel Or To A New NotebookCtrl Created Inside That New Frame. - Possibility To Add A Custom Panel To Show A Logo Or HTML Information Or Whatever You Like When There Are No Tabs In NotebookCtrl; - Possibility To Change The ToolTip Window Background Colour; - Possibility To Draw Vertical Or Horizontal Gradient Coloured Tabs (2 Colours); - Themes On Tabs: Built-In Themes Are KDE (Unix/Linux), Metal, Aqua Light And Aqua Dark (MacOS), Windows Silver (Windows) Or Generic Gradient Coloured Tabs. It's Also Possible To Define A Separate Theme For Selected Tabs And Control Background (The Last Two Are Work In Progress); - Contour Line Colour Around Tabs Is Customizable; - Highlight Colour Of Selected Tab Is Customizable; - Each Tab Can Have Its Own Gradient Colouring (2 Colours For Every Tab); - Custom Images May Be Drawn As A "X" Close Buttons On Tabs; - Possibility To Hide A Particular Tab Using A wx.PopupMenu That Is Shown If You Call EnableHiding(True). Look At The Top Right Of NotebookCtrl; - Allows Drag And Drop Of Tabs/Pages Between Different NotebookCtrls In The Same Application. - Draw tabs on the left or right side, rotated or horizontal - Allow user to switch between rotated and horizontal displays of tabs on the left or right side. Usage: NotebookCtrl Construction Is Quite Similar To wx.Notebook:: NotebookCtrl.__init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=style, sizer=nbsizer) See L{NotebookCtrl.__init__} Method For The Definition Of Non Standard (Non wxPython) Parameters. NotebookCtrl Control Is Freeware And Distributed Under The wxPython License. Latest Revision: Andrea Gavana @ 06 Oct 2006, 18.10 GMT @undocumented: NC_MAC*, topaqua*, botaqua*, distaqua*, disbaqua*, kdetheme, silvertheme*, wxEVT*, attrs, GetMenuButton*, NCDragInfo, NCDropTarget, TabbedPage, TabCtrl, TransientTipWindow, macPopupWindow, macTransientTipWindow, NCFrame, DEFAULT_SIZE, NotebookSpinButton, NotebookMenuButton """ __docformat__ = "epytext" #---------------------------------------------------------------------- # Beginning Of NOTEBOOKCTRL wxPython Code #---------------------------------------------------------------------- from orpg.orpg_wx import * from wx.lib.buttons import GenBitmapButton as BitmapButton import wx.xrc as xrc import cStringIO, zlib import cPickle import weakref # HitTest Results NC_HITTEST_NOWHERE = 0 # Not On Tab """Indicates mouse coordinates not on any tab of the notebook""" NC_HITTEST_ONICON = 1 # On Icon """Indicates mouse coordinates on an icon in a tab of the notebook""" NC_HITTEST_ONLABEL = 2 # On Label """Indicates mouse coordinates on a label in a tab of the notebook""" NC_HITTEST_ONITEM = 4 # Generic, On Item """Indicates mouse coordinates on a tab of the notebook""" NC_HITTEST_ONX = 8 # On Small Square On Every Page """Indicates mouse coordinates on the closing I{X} in a tab of the notebook""" # NotebookCtrl Styles # NotebookCtrl Placed On Top (Default) NC_TOP = 1 """Specify tabs at the top of the notebook control.""" # NotebookCtrl Placed At The Bottom NC_BOTTOM = 2 """Specify tabs at the bottom of the notebook control.""" # NotebookCtrl With Fixed Width Tabs NC_FIXED_WIDTH = 4 """Specify tabs of a fixed width in the notebook control.""" # NotebookCtrl Placed At The Left NC_LEFT = 8 """Specify tabs on the left side of the notebook control.""" # NotebookCtrl Placed At The Right NC_RIGHT = 16 """Specify tabs on the right side of the notebook control.""" # NotebookCtrl tab rotated NC_ROTATE = 32 """Specify rotated tabs (with vertical text) in the notebook control.""" # NotebookCtrl switchable between compact and expanded sizes NC_EXPANDABLE = 64 """Specify that the notebook control includes a toggle button to switch between compact tabs (rotated on the left or right side) expanded tabs (horizontal on the left or right side).""" NC_DEFAULT_STYLE = NC_TOP | wx.NO_BORDER """The default style for the notebook control (tabs on top with no border)""" # Also wx.STATIC_BORDER Is Supported # NotebookCtrl theme styles NC_GRADIENT_VERTICAL = 1 """Specify tabs rendered with a vertical gradient background.""" NC_GRADIENT_HORIZONTAL = 2 """Specify tabs rendered with a horizontal gradient background.""" NC_GRADIENT_SELECTION = 4 NC_AQUA_LIGHT = 8 """Specify tabs rendered with a Mac I{Light Aqua}-like background.""" NC_AQUA_DARK = 16 """Specify tabs rendered with a Mac I{Dark Aqua}-like background.""" NC_AQUA = NC_AQUA_LIGHT """Specify tabs rendered with a Mac I{Light Aqua}-like background.""" NC_METAL = 32 """Specify tabs rendered with a Mac I{Metal}-like background.""" NC_SILVER = 64 """Specify tabs rendered with a Windows I{Silver}-like background.""" NC_KDE = 128 """Specify tabs rendered with a KDE-style background.""" # Patch To Make NotebookCtrl Working Also On MacOS: Thanks To Stani ;-) if wx.Platform == '__WXMAC__': DEFAULT_SIZE = wx.Size(26, 26) else: DEFAULT_SIZE = wx.DefaultSize # Themes On Mac... This May Slow Down The Paint Event If You Turn It On! NC_MAC_LIGHT = (240, 236) NC_MAC_DARK = (232, 228) topaqua1 = [wx.Colour(106, 152, 231), wx.Colour(124, 173, 236)] botaqua1 = [wx.Colour(54, 128, 213), wx.Colour(130, 225, 249)] topaqua2 = [wx.Colour(176, 222, 251), wx.Colour(166, 211, 245)] botaqua2 = [wx.Colour(120, 182, 244), wx.Colour(162, 230, 245)] distaqua = [wx.Colour(248, 248, 248), wx.Colour(243, 243, 243)] disbaqua = [wx.Colour(219, 219, 219), wx.Colour(248, 248, 248)] # Themes On KDE... This May Slow Down The Paint Event If You Turn It On! kdetheme = [wx.Colour(0xf3,0xf7,0xf9), wx.Colour(0xf3,0xf7,0xf9), wx.Colour(0xee,0xf3,0xf7), wx.Colour(0xee,0xf3,0xf7), wx.Colour(0xea,0xf0,0xf4), wx.Colour(0xea,0xf0,0xf4), wx.Colour(0xe6,0xec,0xf1), wx.Colour(0xe6,0xec,0xf1), wx.Colour(0xe2,0xe9,0xef), wx.Colour(0xe2,0xe9,0xef), wx.Colour(0xdd,0xe5,0xec), wx.Colour(0xdd,0xe5,0xec), wx.Colour(0xd9,0xe2,0xea), wx.Colour(0xd9,0xe2,0xea)] # Themes On Windows... This May Slow Down The Paint Event If You Turn It On! silvertheme2 = [wx.Colour(255, 255, 255), wx.Colour(190, 190, 216), wx.Colour(180, 180, 200)] silvertheme1 = [wx.Colour(252, 252, 254), wx.Colour(252, 252, 254)] # NotebookCtrl Events: # wxEVT_NOTEBOOKCTRL_PAGE_CHANGED: Event Fired When You Switch Page; # wxEVT_NOTEBOOKCTRL_PAGE_CHANGING: Event Fired When You Are About To Switch # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call # event.Skip() In Your Event Handler; # wxEVT_NOTEBOOKCTRL_PAGE_CLOSING: Event Fired When A Page Is Closing, But # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip() # In Your Event Handler; # wxEVT_NOTEBOOKCTRL_PAGE_DND: Event Fired When A Drag And Drop Action On # Tabs Ends. wxEVT_NOTEBOOKCTRL_PAGE_CHANGED = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_CHANGING = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_CLOSING = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_DND = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_DCLICK = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_RIGHT = wx.NewEventType() wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE = wx.NewEventType() #-----------------------------------# # NotebookCtrlEvent #-----------------------------------# EVT_NOTEBOOKCTRL_PAGE_CHANGED = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED, 1) """Notify client objects when the active page in the notebook control has changed.""" EVT_NOTEBOOKCTRL_PAGE_CHANGING = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, 1) """Notify client objects when the active page in the notebook control is changing.""" EVT_NOTEBOOKCTRL_PAGE_CLOSING = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CLOSING, 1) """Notify client objects when a page in the notebook control is closing.""" EVT_NOTEBOOKCTRL_PAGE_DND = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_DND, 1) """Enable client objects to override the behavior of the notebook control when a dragged tab is dropped onto it.""" EVT_NOTEBOOKCTRL_PAGE_DCLICK = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_DCLICK, 1) """Notify client objects when the user double-clicks a tab in the notebook control.""" EVT_NOTEBOOKCTRL_PAGE_RIGHT = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_RIGHT, 1) """Notify client objects when the user right-clicks a tab in the notebook control.""" EVT_NOTEBOOKCTRL_PAGE_MIDDLE = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE, 1) """Notify client objects when the user clicks with the middle mouse button on a tab in the notebook control.""" attrs = ["_backstyle", "_backtooltip", "_borderpen", "_convertimage", "_drawx", "_drawxstyle", "_enabledragging", "_focusindpen", "_hideonsingletab", "_highlight", "_padding", "_selectioncolour", "_selstyle", "_tabstyle", "_upperhigh", "_usefocus", "_usegradients"] # Check for the new method in 2.7 (not present in 2.6.3.3) if wx.VERSION_STRING < "2.7": wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point) # ---------------------------------------------------------------------------- # def GetMenuButtonData(): return zlib.decompress( "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\x9c \xcc\xc1\ \x06$\x1fLd\x13\x00R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4[x\xba8\x86HL\xed\ \xbd`\xc8\xc7\xa0\xc0\xe1|q\xdb\x9d\xff'\xba\xb4\x1d\x05v\xff}\xe2\xab\x9a:c\ \x99\xc4\xbe\xe9\xfd+\x9a\xc5W%t\x1a\xe5\x08\xa6\xd6,\xe2\xf0\x9a\xc2\xc8\ \xf0\xe1\xf9r\xe6\xa3\xc9\x02b\xd9\x0c35\x80f0x\xba\xfa\xb9\xacsJh\x02\x00\ \xcd-%1") def GetMenuButtonBitmap(): return wx.BitmapFromImage(GetMenuButtonImage()) def GetMenuButtonImage(): stream = cStringIO.StringIO(GetMenuButtonData()) return wx.ImageFromStream(stream) # ---------------------------------------------------------------------------- # def GrayOut(anImage): """ Convert The Given Image (In Place) To A Grayed-Out Version, Appropriate For A 'Disabled' Appearance. """ factor = 0.7 # 0 < f < 1. Higher Is Grayer if anImage.HasMask(): maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue()) else: maskColor = None data = map(ord, list(anImage.GetData())) for i in range(0, len(data), 3): pixel = (data[i], data[i+1], data[i+2]) pixel = MakeGray(pixel, factor, maskColor) for x in range(3): data[i+x] = pixel[x] anImage.SetData(''.join(map(chr, data))) return anImage def MakeGray((r,g,b), factor, maskColor): """ Make A Pixel Grayed-Out. If The Pixel Matches The MaskColor, It Won't Be Changed. """ if (r,g,b) != maskColor: return map(lambda x: int((230 - x) * factor) + x, (r,g,b)) else: return (r,g,b) def GetDefaultTabStyle(): tabstyle = ThemeStyle() # Draw Mac Themes On Tabs? if wx.Platform == "__WXMAC__" or wx.Platform == "__WXCOCOA__": tabstyle.EnableAquaTheme(True, 2) # Draw Windows Silver Theme On Tabs? elif wx.Platform == "__WXMSW__": tabstyle.EnableSilverTheme(True) else: tabstyle.EnableKDETheme(True) return tabstyle # ---------------------------------------------------------------------------- # # Class NotebookCtrlEvent # ---------------------------------------------------------------------------- # class NotebookCtrlEvent(wx.PyCommandEvent): """ Represent details of the events that the L{NotebookCtrl} object sends. """ def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1): """ Default Class Constructor. """ wx.PyCommandEvent.__init__(self, eventType, id) self._eventType = eventType def SetSelection(self, nSel): """ Sets Event Selection. """ self._selection = nSel def SetOldSelection(self, nOldSel): """ Sets Old Event Selection. """ self._oldselection = nOldSel def GetSelection(self): """ Returns Event Selection. """ return self._selection def GetOldSelection(self): """ Returns Old Event Selection """ return self._oldselection def SetOldPosition(self, pos): """ Sets Old Event Position. """ self._oldposition = pos def SetNewPosition(self, pos): """ Sets New Event Position. """ self._newposition = pos def GetOldPosition(self): """ Returns Old Event Position. """ return self._oldposition def GetNewPosition(self): """ Returns New Event Position. """ return self._newposition # ---------------------------------------------------------------------------- # # Class NCDragInfo # Stores All The Information To Allow Drag And Drop Between Different # NotebookCtrls In The Same Application. # ---------------------------------------------------------------------------- # class NCDragInfo: _map = weakref.WeakValueDictionary() def __init__(self, container, pageindex): """ Default Class Constructor. """ self._id = id(container) NCDragInfo._map[self._id] = container self._pageindex = pageindex def GetContainer(self): """ Returns The NotebookCtrl Page (Usually A Panel). """ return NCDragInfo._map.get(self._id, None) def GetPageIndex(self): """ Returns The Page Index Associated With A Page. """ return self._pageindex # ---------------------------------------------------------------------------- # # Class NCDropTarget # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between # Different NotebookCtrls. # ---------------------------------------------------------------------------- # class NCDropTarget(wx.DropTarget): def __init__(self, parent): """ Default Class Constructor. """ wx.DropTarget.__init__(self) self._parent = parent self._dataobject = wx.CustomDataObject(wx.CustomDataFormat("NotebookCtrl")) self.SetDataObject(self._dataobject) def OnData(self, x, y, dragres): """ Handles The OnData() Method TO Call The Real DnD Routine. """ if not self.GetData(): return wx.DragNone draginfo = self._dataobject.GetData() drginfo = cPickle.loads(draginfo) return self._parent.OnDropTarget(x, y, drginfo.GetPageIndex(), drginfo.GetContainer()) # ---------------------------------------------------------------------------- # # Class ThemeStyle. Used To Define A Custom Style For Tabs And Control # Background Colour. # ---------------------------------------------------------------------------- # class ThemeStyle: """ Represent the style for rendering a notebook tab. """ GRADIENT_VERTICAL = 1 GRADIENT_HORIZONTAL = 2 DIFFERENT_GRADIENT_FOR_SELECTED = 4 def __init__(self): """ Default Constructor For This Class.""" self.ResetDefaults() def ResetDefaults(self): """ Resets Default Theme. """ self._normal = True self._aqua = False self._metal = False self._macstyle = False self._kdetheme = False self._silver = False self._gradient = False self._firstcolour = wx.WHITE self._secondcolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self._firstcolourselected = wx.WHITE self._secondcolourselected = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) def EnableMacTheme(self, enable=True, style=1): """ Enables/Disables Mac Themes. style=1 Is The Light Style, While style=2 Is The Dark Style. Mainly Used For Control Background Colour, Not For Tabs. """ if enable: self._normal = False self._macstyle = style self._kdetheme = False self._metal = False self._aqua = False self._silver = False self._gradient = False else: self._macstyle = 0 def EnableKDETheme(self, enable=True): """ Globally Enables/Disables Unix-Like KDE Theme For Tabs. """ self._kdetheme = enable if enable: self._normal = False self._macstyle = False self._metal = False self._aqua = False self._silver = False self._gradient = False def EnableMetalTheme(self, enable=True): """ Globally Enables/Disables Mac-Like Metal Theme For Tabs. """ self._metal = enable if enable: self._normal = False self._macstyle = False self._kdetheme = False self._aqua = False self._silver = False self._gradient = False def EnableAquaTheme(self, enable=True, style=1): """ Globally Enables/Disables Mac-Like Aqua Theme For Tabs. """ if enable: self._aqua = style self._normal = False self._macstyle = False self._kdetheme = False self._metal = False self._silver = False self._gradient = False else: self._aqua = 0 def EnableSilverTheme(self, enable=True): """ Globally Enables/Disables Windows Silver Theme For Tabs. """ self._silver = enable if enable: self._normal = False self._macstyle = False self._kdetheme = False self._metal = False self._aqua = False self._gradient = False def EnableGradientStyle(self, enable=True, style=1): """ Enables/Disables Gradient Drawing On Tabs. style=1 Is The Vertical Gradient, While style=2 Is The Horizontal Gradient. If style flag 4 is set, the style has a separate set of colors for the selected tab. """ if enable: self._normal = False if style & self.GRADIENT_VERTICAL == 0 and style & self.GRADIENT_HORIZONTAL == 0: style |= self.GRADIENT_VERTICAL self._gradient = style self._macstyle = False self._kdetheme = False self._metal = False self._aqua = False self._silver = False else: self._gradient = 0 def SetFirstGradientColour(self, colour=None): """ Sets The First Gradient Colour. """ if colour is None: colour = wx.WHITE self._firstcolour = colour def SetFirstGradientColourSelected(self, colour=None): """Sets The First Gradient Colour For The Selected Tab.""" if colour is None: colour = wx.WHITE self._firstcolourselected = colour def SetSecondGradientColour(self, colour=None): """ Sets The Second Gradient Colour. """ if colour is None: color = self.GetBackgroundColour() r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._secondcolour = colour def SetSecondGradientColourSelected(self, colour=None): """ Sets The Second Gradient Colour For The Selected Tab. """ if colour is None: color = self.GetBackgroundColour() r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._secondcolourselected = colour def GetFirstGradientColour(self, selected=False): """ Returns The First Gradient Colour. """ if selected and self._gradient & self.DIFFERENT_GRADIENT_FOR_SELECTED: return self._firstcolourselected else: return self._firstcolour def GetSecondGradientColour(self, selected=False): """ Returns The Second Gradient Colour. """ if selected and self._gradient & self.DIFFERENT_GRADIENT_FOR_SELECTED: return self._secondcolourselected else: return self._secondcolour # ---------------------------------------------------------------------------- # # Class TabbedPage # This Is Just A Container Class That Initialize All The Default Settings For # Every Tab. # ---------------------------------------------------------------------------- # class TabbedPage: def __init__(self, text="", image=-1, hidden=False): """ Default Class Constructor. """ self._text = text self._image = image self._font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._secondaryfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._pagetextcolour = wx.BLACK self._pagecolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self._enable = True self._animationimages = [] self._tooltip = "" self._tooltiptime = 500 self._winsize = 400 self._menu = None self._ishidden = hidden self._firstcolour = color = wx.WHITE r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._secondcolour = colour # ---------------------------------------------------------------------------- # # Class NotebookSpinButton # This SpinButton Is Created/Shown Only When The Total Tabs Size Exceed The # Client Size, Allowing The User To Navigate Between Tabs By Clicking On The # SpinButton. It Is Very Similar To The wx.Notebook SpinButton # ---------------------------------------------------------------------------- # class NotebookSpinButton(wx.SpinButton): def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.SP_HORIZONTAL): """ Default Class Constructor. """ wx.SpinButton.__init__(self, parent, id, pos, size, style) self._nb = parent self._oldvalue = 0 self._style = style self.Bind(wx.EVT_SPIN, self.OnSpin) def GetValue(self): result = super(NotebookSpinButton, self).GetValue() if self._style & wx.SP_VERTICAL: result = -result return result def OnSpin(self, event): """ Handles The User's Clicks On The SpinButton. """ if type(event) != type(1): pos = event.GetPosition() else: pos = event if pos < self.GetMin(): self.SetValue(self.GetMin()) return if type(event) != type(1): if self._nb._enablehiding: if pos < self._oldvalue: incr = -1 else: incr = 1 while self._nb._pages[pos]._ishidden: pos = pos + incr self.SetValue(pos) if self._nb.IsLastVisible(): if (self._style & wx.SP_HORIZONTAL and self._oldvalue < pos) or \ (self._style & wx.SP_VERTICAL and self._oldvalue > pos): self.SetValue(self._oldvalue) return self._oldvalue = pos self._nb.Refresh() # ---------------------------------------------------------------------------- # # Class NotebookMenuButton # This MenuButton Is Created/Shown Only When You Activate The Option EnableHiding # Of NotebookCtrl. This Small Button Will Be Shown Right Above The Spin Button # (If Present), Or In The Position Of The Spin Button. # ---------------------------------------------------------------------------- # class NotebookMenuButton(BitmapButton): def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=(15, 11), style=0): """ Default Class Constructor. """ bmp = GetMenuButtonBitmap() BitmapButton.__init__(self, parent, id, bmp, pos, size, style) self.SetUseFocusIndicator(False) self.SetBezelWidth(1) self._originalcolour = self.GetBackgroundColour() self._nb = parent self.Bind(wx.EVT_BUTTON, self.OnButton) self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) self.Bind(wx.EVT_MENU, self.OnMenu) def OnButton(self, event): """ Handles The wx.EVT_BUTTON For NotebookMenuButton (Opens The wx.PopupMenu) """ count = self._nb.GetPageCount() if count <= 0: return menu = wx.Menu() id = wx.NewId() myids = [] for ii in xrange(count): id = id + 1 myids.append(id) name = self._nb.GetPageText(ii) if self._nb._pages[ii]._ishidden: msg = "Page Hidden" check = False else: msg = "Page Shown" check = True item = wx.MenuItem(menu, id, name, msg, wx.ITEM_CHECK) menu.AppendItem(item) if not self._nb._pages[ii]._ishidden: item.Check() menu.SetHelpString(id, msg) self._myids = myids self.PopupMenu(menu) event.Skip() def OnMenu(self, event): """ Handles The wx.EVT_MENU For NotebookMenuButton. Calls HideTab(). """ indx = self._myids.index(event.GetId()) checked = not event.GetEventObject().IsChecked(event.GetId()) self._nb.HideTab(indx, not checked) event.Skip() def OnEnterWindow(self, event): """ Changes The NotebookMenuButton Background Colour When The Mouse Enters The Button Region. """ entercolour = self.GetBackgroundColour() firstcolour = entercolour.Red() secondcolour = entercolour.Green() thirdcolour = entercolour.Blue() if entercolour.Red() > 235: firstcolour = entercolour.Red() - 40 if entercolour.Green() > 235: secondcolour = entercolour.Green() - 40 if entercolour.Blue() > 235: thirdcolour = entercolour.Blue() - 40 entercolour = wx.Colour(firstcolour+20, secondcolour+20, thirdcolour+20) self.SetBackgroundColour(entercolour) self.Refresh() event.Skip() def OnLeaveWindow(self, event): """ Restore The NotebookMenuButton Background Colour When The Mouse Leaves The Button Region. """ self.SetBackgroundColour(self._originalcolour) self.Refresh() event.Skip() class _TabCtrlPaintTools(object): # Structure-like object for passing data among # private rendering methods def __init__(self, backBrush, backPen, borderPen, highlightPen, shadowPen, upperHighlightPen, selectionPen, selectionEdgePen, xPen, focusPen): self.BackBrush = backBrush self.BackPen = backPen self.BorderPen = borderPen self.HighlightPen = highlightPen self.ShadowPen = shadowPen self.UpperHighlightPen = upperHighlightPen self.SelectionPen = selectionPen self.SelectionEdgePen = selectionEdgePen self.XPen = xPen self.FocusPen = focusPen # ---------------------------------------------------------------------------- # # Class TabCtrl # This Class Handles The Drawing Of Every Tab In The NotebookCtrl, And Also # All Settings/Methods For Every Tab. # ---------------------------------------------------------------------------- # class TabCtrl(wx.PyControl): def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=DEFAULT_SIZE, style=NC_DEFAULT_STYLE, validator=wx.DefaultValidator, name="TabCtrl"): """ Default Class Constructor. Used Internally. Do Not Call It Explicitely! """ wx.PyControl.__init__(self, parent, id, pos, size, wx.NO_BORDER | wx.WANTS_CHARS, validator, name) # Set All The Default Parameters For TabCtrl self._selection = -1 self._imglist = 0 self._style = style self._expanded = False self._pages = [] self._enabledpages = [] self._padding = wx.Point(8, 4) self._spacetabs = 2 self._xrect = [] self._xrefreshed = False self._imageconverted = False self._convertimage = False self._disabledcolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT) self._hover = False self._parent = parent self._firsttime = True self._somethingchanged = True self._isdragging = False self._tabID = -1 self._enabledragging = False self._olddragpos = -1 self._fromdnd = False self._isleaving = False self._highlight = False self._usefocus = True self._hideonsingletab = False self._selectioncolour = wx.Colour(255, 200, 60) self._selectionedgecolour = wx.Colour(230, 139, 44) self._tabstyle = ThemeStyle() self._backstyle = ThemeStyle() self._selstyle = ThemeStyle() self._usegradients = False self._insidetab = -1 self._showtooltip = False self._istooltipshown = False self._tipwindow = None self._tiptimer = wx.PyTimer(self.OnShowToolTip) self._backtooltip = wx.Colour(255, 255, 230) self._xvideo = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) self._yvideo = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) self._selectedtabs = [] self._timers = [] self._dragcursor = wx.StockCursor(wx.CURSOR_HAND) self._dragstartpos = wx.Point() self._drawx = False self._drawxstyle = 1 self._pmenu = None self._enablehiding = False if (style & NC_LEFT or style & NC_RIGHT) and style & NC_EXPANDABLE: self._InitExpandableStyles(style) self._InitExpandableTabStyles(self._style, self._expanded, self._tabstyle) self._CreateSizeToggleButton() else: self._sizeToggleButton = None self.SetDefaultPage() if style & NC_TOP or style & NC_BOTTOM: self.SetBestSize((-1, 28)) self._firsttabpos = wx.Point(3, 0) else: self.SetBestSize((28, -1)) self._firsttabpos = wx.Point(0, 3 + self._CalcSizeToggleBestSize()[1]) self._borderpen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) self._highlightpen2 = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) self._highlightpen = wx.Pen((145, 167, 180)) self._upperhigh = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) self._shadowpen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DDKSHADOW), 2) self._shadowpen.SetCap(wx.CAP_BUTT) self._highlightpen.SetCap(wx.CAP_BUTT) self._highlightpen2.SetCap(wx.CAP_BUTT) if wx.Platform == "__WXMAC__": self._focusindpen = wx.Pen(wx.BLACK, 1, wx.SOLID) else: self._focusindpen = wx.Pen(wx.BLACK, 1, wx.USER_DASH) self._focusindpen.SetDashes([1,1]) self._focusindpen.SetCap(wx.CAP_BUTT) self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) self.Bind(wx.EVT_LEFT_DCLICK, self.OnMouseLeftDClick) self.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) self.Bind(wx.EVT_RIGHT_UP, self.OnMouseRightUp) self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRightDown) self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMouseMiddleDown) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) self.Bind(wx.EVT_TIMER, self.AnimateTab) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) self._droptarget = NCDropTarget(self) self.SetDropTarget(self._droptarget) def Contract(self): if self._style & NC_EXPANDABLE and self._expanded: self._ToggleSize() def Expand(self): if self._style & NC_EXPANDABLE and not self._expanded: self._ToggleSize() def _ToggleSize(self, event=None): if self._style & NC_EXPANDABLE and not self._expanded: # contract self._style = self._expandedstyle self._tabstyle = self._expandedtabstyle self._expanded = True self._sizeToggleButton.SetLabel("<<") elif self._style & NC_EXPANDABLE and self._expanded: # expand self._style = self._contractedstyle self._tabstyle = self._contractedtabstyle self._expanded = False self._sizeToggleButton.SetLabel(">>") self._OnStyleChange() def OnDropTarget(self, x, y, nPage, oldcont): """ Handles The OnDrop Action For Drag And Drop Between Different NotebookCtrl. """ where = self.HitTest(wx.Point(x, y)) oldNotebook = oldcont.GetParent() newNotebook = self.GetParent() if oldNotebook == newNotebook: if where >= 0 and where != self._tabID: self._isdragging = False self._olddragpos = -1 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, self.GetId()) eventOut.SetOldPosition(self._tabID) eventOut.SetNewPosition(where) eventOut.SetEventObject(self) if self.GetEventHandler().ProcessEvent(eventOut): self._tabID = -1 self._olddragpos = -1 self.SetCursor(wx.STANDARD_CURSOR) self.Refresh() return self._parent.Freeze() try: text = self.GetPageText(self._tabID) image = self.GetPageImage(self._tabID) font1 = self.GetPageTextFont(self._tabID) font2 = self.GetPageTextSecondaryFont(self._tabID) fontcolour = self.GetPageTextColour(self._tabID) pagecolour = self.GetPageColour(self._tabID) enabled = self.IsPageEnabled(self._tabID) tooltip, ontime, winsize = self.GetPageToolTip(self._tabID) menu = self.GetPagePopupMenu(self._tabID) firstcol = self.GetPageFirstGradientColour(self._tabID) secondcol = self.GetPageSecondGradientColour(self._tabID) ishidden = self._pages[self._tabID]._ishidden except: self._parent.Thaw() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) return isanimated = 0 if self._timers[self._tabID].IsRunning(): isanimated = 1 timer = self._timers[self._tabID].GetInterval() self.StopAnimation(self._tabID) animatedimages = self.GetAnimationImages(self._tabID) pagerange = range(self.GetPageCount()) newrange = pagerange[:] newrange.remove(self._tabID) newrange.insert(where, self._tabID) newpages = [] counter = self.GetPageCount() - 1 for ii in xrange(self.GetPageCount()): newpages.append(self._parent.GetPage(ii)) self._parent.bsizer.Detach(counter-ii) cc = 0 self._parent._notebookpages = [] for jj in newrange: self._parent.bsizer.Add(newpages[jj], 1, wx.EXPAND | wx.ALL, 2) self._parent.bsizer.Show(cc, False) self._parent._notebookpages.append(newpages[jj]) cc = cc + 1 self.DeletePage(self._tabID) if enabled: if id == self.GetPageCount(): self.AddPage(text, True, image) else: self.InsertPage(where, text, True, image) else: if id == self.GetPageCount(): self.AddPage(text, False, image) else: self.InsertPage(where, text, False, image) self.SetPageImage(where, image) self.SetPageText(where, text) self.SetPageTextFont(where, font1) self.SetPageTextSecondaryFont(where, font2) self.SetPageTextColour(where, fontcolour) self.SetPageColour(where, pagecolour) self.EnablePage(where, enabled) self.SetPageToolTip(where, tooltip, ontime, winsize) self.SetPagePopupMenu(where, menu) self.SetPageFirstGradientColour(where, firstcol) self.SetPageSecondGradientColour(where, secondcol) self._pages[where]._ishidden = ishidden if isanimated and len(animatedimages) > 1: self.SetAnimationImages(where, animatedimages) self.StartAnimation(where, timer) if enabled: self._parent.bsizer.Show(where, True) else: sel = self.GetSelection() if sel == -1: sel = 0 self._parent.bsizer.Show(where, False) self._parent.SetSelection(sel) self._parent.bsizer.Show(sel, True) self._parent.bsizer.Layout() self._parent.Thaw() self._isdragging = False self._olddragpos = -1 self._fromdnd = True self.Refresh() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) return if nPage >= 0 and where >= 0: panel = oldNotebook.GetPage(nPage) if panel: eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, oldNotebook.GetId()) eventOut.SetOldPosition(nPage) eventOut.SetNewPosition(where) eventOut.SetEventObject(oldNotebook) if oldNotebook.GetEventHandler().ProcessEvent(eventOut): oldNotebook.nb._tabID = -1 oldNotebook.nb._olddragpos = -1 oldNotebook.SetCursor(wx.STANDARD_CURSOR) oldNotebook.Refresh() return oldNotebook.Freeze() infos = oldNotebook.GetPageInfo(nPage) text = infos["text"] image = infos["image"] hidden = infos["ishidden"] panel.Reparent(newNotebook) newNotebook.InsertPage(where, panel, text, True, image, hidden) newNotebook.SetPageInfo(where, infos) oldNotebook.nb.DeletePage(nPage) oldNotebook.bsizer.Detach(nPage) oldNotebook.bsizer.Layout() oldNotebook.sizer.Layout() oldNotebook._notebookpages.pop(nPage) oldNotebook.AdvanceSelection() if oldNotebook.GetPageCount() == 0: if oldNotebook._style & NC_TOP: oldNotebook.sizer.Show(0, False) oldNotebook.sizer.Show(1, False) else: oldNotebook.sizer.Show(1, False) oldNotebook.sizer.Show(2, False) oldNotebook.sizer.Layout() oldNotebook.Thaw() newNotebook.Refresh() return wx.DragMove def OnLeaveWindow(self, event): """ Handles The wx.EVT_LEAVE_WINDOW Events For TabCtrl. """ if self._enabledragging: if self._isdragging: page = self._parent.GetPage(self._tabID) draginfo = NCDragInfo(page, self._tabID) drginfo = cPickle.dumps(draginfo) dataobject = wx.CustomDataObject(wx.CustomDataFormat("NotebookCtrl")) dataobject.SetData(drginfo) dragSource = wx.DropSource(self) dragSource.SetData(dataobject) dragSource.DoDragDrop(wx.Drag_DefaultMove) self._isleaving = True self.Refresh() if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() event.Skip() def OnKeyDown(self, event): """ Handles The wx.EVT_KEY_DOWN Event For TabCtrl. This Is Only Processed If The User Navigate Through Tabs With Ctrl-Tab Keyboard Navigation. """ if event.GetKeyCode == wx.WXK_TAB: if event.ControlDown(): sel = self.GetSelection() if sel == self.GetPageCount() - 1: sel = 0 else: sel = sel + 1 while not self.IsPageEnabled(sel): sel = sel + 1 if sel == self.GetPageCount() - 1: sel = 0 self._parent.SetSelection(sel) event.Skip() def AddPage(self, text, select=False, img=-1, hidden=False): """ Add A Page To The Notebook. @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. """ self._pages.append(TabbedPage(text, img, hidden)) self._somethingchanged = True self._firsttime = True self._timers.append(wx.Timer(self)) # JS: The following two lines caused this control not to fire # the EVT_NOTEBOOKCTRL_PAGE_CHANGING/CHANGED events for the # first page. The NotebookCtrl sets the selection later anyway, # and without these two lines, the events fire. ## if select or self.GetSelection() == -1: ## self._selection = self.GetPageCount() - 1 if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self.Refresh() def InsertPage(self, nPage, text, select=False, img=-1, hidden=False): """ Insert A Page Into The Notebook. @param nPage: Specifies The Position For The New Page; @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In InsertPage: (" + str(nPage) + ")" oldselection = self.GetSelection() self._pages.insert(nPage, TabbedPage(text, img, hidden)) self._timers.insert(nPage, wx.Timer(self)) self._somethingchanged = True self._firsttime = True if select or self.GetSelection() == -1: self._selection = nPage self.SetSelection(nPage) else: if nPage <= oldselection: self._selection = self._selection + 1 if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self.Refresh() def DeleteAllPages(self): """ Deletes All NotebookCtrl Pages. """ for tims in self._timers: if tims.IsRunning(): tims.Stop() tims.Destroy() self._timers = [] self._pages = [] self._selection = -1 self._somethingchanged = True self._firsttime = True self.Refresh() def DeletePage(self, nPage, oncontinue=True): """ Deletes The Page nPage, And The Associated Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In DeletePage: (" + str(nPage) + ")" oldselection = self.GetSelection() self._pages.pop(nPage) if self._timers[nPage].IsRunning(): self._timers[nPage].Stop() self._timers[nPage].Destroy() if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False if not oncontinue: self._somethingchanged = True self._firsttime = True self.Refresh() return if nPage < self._selection: self._selection = self._selection - 1 elif self._selection == nPage and self._selection == self.GetPageCount(): self._selection = self._selection - 1 else: self._selection = oldselection self._somethingchanged = True self._firsttime = True self.Refresh() def SetSelection(self, nPage): """ Sets The Current Tab Selection To The Given nPage. This Call Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetSelection: (" + str(nPage) + ")" oldselection = self._selection if nPage != self._selection: if not self.IsPageEnabled(nPage): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, self.GetId()) eventOut.SetSelection(nPage) eventOut.SetOldSelection(self._selection) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): # Prevent full paint unless never fully painted if hasattr(self, "_initrect"): self._firsttime = False # Program Allows The Page Change self._selection = nPage eventOut.SetEventType(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED) eventOut.SetOldSelection(self._selection) self.GetEventHandler().ProcessEvent(eventOut) if oldselection != -1: self._parent.bsizer.Show(oldselection, False) self.EnsureVisible(self._selection) self._parent.bsizer.Show(self._selection, True) self._parent.bsizer.Layout() self.Refresh() self._shown = nPage def EnsureVisible(self, selection): if self.GetPageCount() < 2: return if not self.HasSpinButton(): return fullrect = self.GetClientSize() count = self._tabvisible[0:selection].count(0) currect = self._tabrect[selection-self._firstvisible-count] spinval = self._spinbutton.GetValue() firstrect = self._initrect[spinval] if self._style & NC_LEFT or self._style & NC_RIGHT: pos = currect.y size = currect.height posIndex = 1 else: pos = currect.x size = currect.width posIndex = 0 torefresh = 0 while pos + size > fullrect[posIndex] - self._spinbutton.GetSize()[posIndex]: if self._style & NC_LEFT or self._style & NC_RIGHT: pos -= firstrect.height else: pos -= firstrect.width if not self._enablehiding: spinval = spinval + 1 else: oldspinval = spinval spinval = spinval + self._tabvisible[0:selection].count(0) if spinval == oldspinval: spinval = spinval + 1 if spinval >= len(self._initrect): spinval = spinval - 1 firstrect = self._initrect[spinval] if self._style & NC_LEFT or self._style & NC_RIGHT: self._spinbutton.OnSpin(-spinval) self._spinbutton.SetValue(-spinval) else: self._spinbutton.OnSpin(spinval) self._spinbutton.SetValue(spinval) torefresh = 1 if torefresh: self.Refresh() def GetPageCount(self): """ Returns The Number Of Pages In NotebookCtrl. """ return len(self._pages) def GetSelection(self): """ Returns The Current Selection. """ return self._selection def GetImageList(self): """ Returns The Image List Associated With The NotebookCtrl. """ return self._imglist def SetImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self._imglist = imagelist self._grayedlist = wx.ImageList(16, 16, True, 0) for ii in xrange(imagelist.GetImageCount()): bmp = imagelist.GetBitmap(ii) image = wx.ImageFromBitmap(bmp) image = GrayOut(image) newbmp = wx.BitmapFromImage(image) self._grayedlist.Add(newbmp) def AssignImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self._imglist = imagelist self._grayedlist = wx.ImageList(16, 16, True, 0) for ii in xrange(imagelist.GetImageCount()): bmp = imagelist.GetBitmap(ii) image = wx.ImageFromBitmap(bmp) image = GrayOut(image) newbmp = wx.BitmapFromImage(image) self._grayedlist.Add(newbmp) def GetPadding(self): """ Returns The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ return self._padding def SetPadding(self, padding): """ Sets The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ self._padding = padding self._somethingchanged = True self._firsttime = True self.Refresh() def GetPageText(self, nPage): """ Returns The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageText: (" + str(nPage) + ")" return self._pages[nPage]._text def SetPageText(self, nPage, text): """ Sets The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageText: (" + str(nPage) + ")" if self._pages[nPage]._text != text: self._pages[nPage]._text = text self._somethingchanged = True self._firsttime = True self.Refresh() def GetPageImage(self, nPage): """ Returns The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageImage: (" + str(nPage) + ")" return self._pages[nPage]._image def SetPageImage(self, nPage, img): """ Sets The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageImage: (" + str(nPage) + ")" if self._pages[nPage]._image != img: self._pages[nPage]._image = img self._somethingchanged = True self._firsttime = True if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self._parent.GetSizer().Layout() self.Refresh() def SetPageTextFont(self, nPage, font=None): """ Sets The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) normalfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._pages[nPage]._font = font if font == normalfont: self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() return dc = wx.ClientDC(self) dc.SetFont(font) w1, h1 = dc.GetTextExtent("Aq") dc.SetFont(normalfont) wn, hn = dc.GetTextExtent("Aq") w2, h2 = (0, 0) if hasattr(self._pages[nPage], "_secondaryfont"): dc.SetFont(self._pages[nPage]._secondaryfont) w2, h2 = dc.GetTextExtent("Aq") h = max(h1, h2) if h < hn: self._somethingchanged = True self._firsttime = True self.Refresh() return if h + 2*self._padding.y < 24: newheight = 24 else: newheight = h + 2*self._padding.y oldsize = self.GetSize() if newheight < oldsize[1]: newheight = oldsize[1] if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, newheight)) else: self.SetBestSize((self._CalcBestWidth(dc), -1)) self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() def SetTabHeight(self, height=28): """ Sets The Tabs Height. """ if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, height)) self._bestsize = height def SetControlBackgroundColour(self, colour=None): """ Sets The TabCtrl Background Colour (Behind The Tabs). """ if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) self.SetBackgroundColour(colour) self.Refresh() def GetPageTextFont(self, nPage): """ Returns The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextFont: (" + str(nPage) + ")" return self._pages[nPage]._font def SetPageTextSecondaryFont(self, nPage, font=None): """ Sets The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextSecondaryFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) normalfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self._pages[nPage]._secondaryfont = font if font == normalfont: self._somethingchanged = True self._firsttime = True self.Refresh() return dc = wx.ClientDC(self) dc.SetFont(font) w1, h1 = dc.GetTextExtent("Aq") dc.SetFont(normalfont) wn, hn = dc.GetTextExtent("Aq") w2, h2 = (0, 0) if hasattr(self._pages[nPage], "_font"): dc.SetFont(self._pages[nPage]._font) w2, h2 = dc.GetTextExtent("Aq") h = max(h1, h2) if h < hn: self._somethingchanged = True self._firsttime = True self.Refresh() return if h + 2*self._padding.y < 24: newheight = 24 else: newheight = h + 2*self._padding.y oldsize = self.GetSize() if newheight < oldsize[-1]: newheight = oldsize[-1] if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, newheight)) else: self.SetBestSize((self._CalcBestWidth(dc), -1)) self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() def GetPageTextSecondaryFont(self, nPage): """ Returns The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextSecondaryFont: (" + str(nPage) + ")" return self._pages[nPage]._secondaryfont def SetPageTextColour(self, nPage, colour=None): """ Sets The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextColour: (" + str(nPage) + ")" if colour is None: colour = wx.BLACK self._pages[nPage]._pagetextcolour = colour self._somethingchanged = True self.Refresh() def GetPageTextColour(self, nPage): """ Returns The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextColour: (" + str(nPage) + ")" return self._pages[nPage]._pagetextcolour def SetPageColour(self, nPage, colour=None): """ Sets The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageColour: (" + str(nPage) + ")" if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self._pages[nPage]._pagecolour = colour self._somethingchanged = True self.Refresh() def GetPageColour(self, nPage): """ Returns The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageColour: (" + str(nPage) + ")" if not self._tabstyle._normal or self._usegradients: if self._usegradients: return self._tabstyle._firstcolour else: return self._GetThemePageColour(nPage) else: return self._pages[nPage]._pagecolour def EnablePage(self, nPage, enable=True): """ Enable/Disable The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In EnablePage: (" + str(nPage) + ")" self._pages[nPage]._enable = enable if not enable and self.GetSelection() == nPage: defpage = self.GetDefaultPage() if defpage < 0: self.AdvanceSelection() else: if defpage >= self.GetPageCount(): self.AdvanceSelection() else: if defpage == nPage: self.AdvanceSelection() else: self.SetSelection(defpage) self.Refresh() def IsPageEnabled(self, nPage): """ Returns Whether A Page Is Enabled Or Not. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In IsPageEnabled: (" + str(nPage) + ")" return self._pages[nPage]._enable def SetHighlightSelection(self, highlight=True): """ Globally Enables/Disables Tab Highlighting On Tab Selection. """ self._highlight = highlight self.Refresh() def GetHighlightSelection(self): """ Returns Globally Enable/Disable State For Tab Highlighting On Tab Selection. """ return self._highlight def SetUseFocusIndicator(self, focus=True): """ Globally Enables/Disables Tab Focus Indicator. """ self._usefocus = focus self.Refresh() def GetUseFocusIndicator(self): """ Returns Globally Enable/Disable State For Tab Focus Indicator. """ return self._usefocus def SetPageToolTip(self, nPage, tooltip="", timer=500, winsize=400): """ Sets A ToolTip For The Given Page nPage. @param nPage: The Given Page; @param tooltip: The ToolTip String; @param timer: The Timer After Which The Tip Window Is Popped Up; @param winsize: The Maximum Width Of The Tip Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageToolTip: (" + str(nPage) + ")" self._pages[nPage]._tooltip = tooltip self._pages[nPage]._tooltiptime = timer self._pages[nPage]._winsize = winsize def GetPageToolTip(self, nPage): """ Returns A Tuple With All Page ToolTip Parameters. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageToolTip: (" + str(nPage) + ")" return self._pages[nPage]._tooltip, self._pages[nPage]._tooltiptime, \ self._pages[nPage]._winsize def EnableToolTip(self, show=True): """ Globally Enables/Disables Tab ToolTips. """ self._showtooltip = show if show: try: wx.PopupWindow(self) self.TransientTipWindow = TransientTipWindow except NotImplementedError: self.TransientTipWindow = macTransientTipWindow else: if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() if self._tiptimer.IsRunning(): self._tiptimer.Stop() def GetToolTipBackgroundColour(self): """ Returns The ToolTip Window Background Colour. """ return self._backtooltip def SetToolTipBackgroundColour(self, colour=None): """ Sets The ToolTip Window Background Colour. """ if colour is None: colour = wx.Colour(255, 255, 230) self._backtooltip = colour def EnableTabGradients(self, enable=True): """ Globally Enables/Disables Drawing Of Gradient Coloured Tabs For Each Tab. """ self._usegradients = enable if enable: self._tabstyle.ResetDefaults() self._selstyle.ResetDefaults() self.Refresh() def SetPageFirstGradientColour(self, nPage, colour=None): """ Sets The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageFirstGradientColour: (" + str(nPage) + ")" if colour is None: colour = wx.WHITE self._pages[nPage]._firstcolour = colour self.Refresh() def SetPageSecondGradientColour(self, nPage, colour=None): """ Sets The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageSecondGradientColour: (" + str(nPage) + ")" if colour is None: color = self._pages[nPage]._firstcolour r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) colour = wx.Colour(color[0], color[1], color[2]) self._pages[nPage]._secondcolour = colour self.Refresh() def GetPageFirstGradientColour(self, nPage): """ Returns The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageFirstGradientColour: (" + str(nPage) + ")" return self._pages[nPage]._firstcolour def GetPageSecondGradientColour(self, nPage): """ Returns The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageSecondGradientColour: (" + str(nPage) + ")" return self._pages[nPage]._secondcolour def CancelTip(self): """ Destroys The Tip Window (Probably You Won't Need This One). """ if self._istooltipshown: self._istooltipshown = False self._tipwindow.Destroy() self.Refresh() def AdvanceSelection(self, forward=True): """ Cycles Through The Tabs. The Call To This Function Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ if self.GetPageCount() <= 1: return sel = self.GetSelection() count = 0 if forward: if sel == self.GetPageCount() - 1: sel = 0 else: sel = sel + 1 while not self.IsPageEnabled(sel) or \ (self._enablehiding and self._pages[sel]._ishidden): count = count + 1 sel = sel + 1 if self._enablehiding and self._pages[sel]._ishidden: count = count + 1 sel = sel + 1 if sel == self.GetPageCount() - 1: sel = 0 if count > self.GetPageCount() + 1: return None else: if sel == 0: sel = self.GetPageCount() - 1 else: sel = sel - 1 while not self.IsPageEnabled(sel): count = count + 1 sel = sel - 1 if sel == 0: sel = self.GetPageCount() - 1 if count > self.GetPageCount() + 1: return None self._parent.SetSelection(sel) def SetDefaultPage(self, defaultpage=-1): """ Sets The Default Page That Will Be Selected When An Active And Selected Tab Is Made Inactive. """ if defaultpage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetDefaultPage: (" + str(defaultpage) + ")" self._defaultpage = defaultpage def GetDefaultPage(self): """ Returns The Default Page. """ return self._defaultpage def UpdateSpinButton(self): """ Update The NotebookSpinButton. Used Internally. """ count = self.GetPageCount() if count == 0: return nbsize = [] nbsize.append(self._initrect[-1][0] + self._initrect[-1][2]) nbsize.append(self._initrect[-1][1] + self._initrect[-1][3]) clsize = self.GetClientSize() if self._style & NC_TOP or self._style & NC_BOTTOM: spinstyle = wx.SP_HORIZONTAL showspin = nbsize[0] > clsize[0] else: spinstyle = wx.SP_VERTICAL showspin = nbsize[1] > clsize[1] if showspin: if not hasattr(self, "_spinbutton"): self._spinbutton = NotebookSpinButton(self, pos=(10000,10000), style=spinstyle) self._spinbutton.SetValue(0) self._originalspinsize = self._spinbutton.GetSize() sbsize = self._spinbutton.GetSize() if self._style & NC_LEFT or self._style & NC_RIGHT: ypos = clsize[1] - sbsize[1] if self._style & NC_LEFT: xpos = nbsize[0] - (2 + sbsize[0]) else: xpos = 2 else: xpos = clsize[0] - sbsize[0] if self._style & NC_BOTTOM: ypos = 2 else: ypos = clsize[1] - sbsize[1] if self.HasMenuButton(): self._spinbutton.SetSize((-1, 16)) else: self._spinbutton.SetSize(self._originalspinsize) self._spinbutton.Move((xpos, ypos)) self._spinbutton.Show() if self._style & NC_LEFT or self._style & NC_RIGHT: self._spinbutton.SetRange(-(count-1), 0) else: self._spinbutton.SetRange(0, count-1) else: if hasattr(self, "_spinbutton") and self._spinbutton.IsShown(): self._spinbutton.Hide() self._spinbutton.SetValue(0) def HasSpinButton(self): """ Returns Wheter The NotebookSpinButton Exists And Is Shown. """ return hasattr(self, "_spinbutton") and self._spinbutton.IsShown() def IsLastVisible(self): """ Returns Whether The Last Tab Is Visible Or Not. """ if self.HasSpinButton(): if self._style & NC_LEFT or self._style & NC_RIGHT: pos, size = (1, 3) else: pos, size = (0, 2) lastpos = self._tabrect[-1][pos] + self._tabrect[-1][size] if lastpos < self._spinbutton.GetPosition()[pos]: return True return False def UpdateMenuButton(self, show): """ Updates The Notebook Menu Button To Show/Hide Tabs. Used Internally. """ count = self.GetPageCount() if count == 0: return if not hasattr(self, "_initrect"): return if not show and not hasattr(self, "_menubutton"): return if not hasattr(self, "_menubutton"): self._menubutton = NotebookMenuButton(self, pos=(10000,10000)) sbsize = self._menubutton.GetSize() nbsize = [] nbsize.append(self._initrect[-1][0] + self._initrect[-1][2]) nbsize.append(self._initrect[-1][1] + self._initrect[-1][3]) clsize = self.GetClientSize() xpos = clsize[0] - sbsize[0] ypos = clsize[1] - sbsize[1] if self.HasSpinButton(): self._menubutton.Move((xpos-1, ypos-16)) else: self._menubutton.Move((xpos-1, ypos-1)) self._menubutton.Show(show) def HasMenuButton(self): """ Returns Wheter The NotebookMenuButton Exists And Is Shown. """ return hasattr(self, "_menubutton") and self._menubutton.IsShown() def HideTab(self, nPage, hide=True): """ Hides A Tab In The NotebookCtrl. """ if hide: self._pages[nPage]._ishidden = True else: self._pages[nPage]._ishidden = False if nPage == self.GetSelection(): self.AdvanceSelection() self._firsttime = True self.Refresh() def HitTest(self, point, flags=0): """ Standard NotebookCtrl HitTest() Method. If Called With 2 Outputs, It Returns The Page Clicked (If Any) And One Of These Flags: NC_HITTEST_NOWHERE = 0 ==> Hit Not On Tab NC_HITTEST_ONICON = 1 ==> Hit On Icon NC_HITTEST_ONLABEL = 2 ==> Hit On Label NC_HITTEST_ONITEM = 4 ==> Hit Generic, On Item NC_HITTEST_ONX = 8 ==> Hit On Closing "X" On Every Page """ mirror = self._style & NC_BOTTOM size = self.GetSize() dc = wx.ClientDC(self) height = self._tabrect[0].height if flags: flags = wx.NB_HITTEST_NOWHERE if point.x <= 0 or point.x >= size.x: if flags: return wx.NOT_FOUND, flags else: return wx.NOT_FOUND if not point.y >= self._tabrect[0].y and point.y < self._tabrect[0].y + height: if flags: return wx.NOT_FOUND, flags else: return wx.NOT_FOUND posx = self._firsttabpos.x posy = self._firsttabpos.y maxwidth = max(self._maxtabwidths) for ii in xrange(self._firstvisible, self.GetPageCount()): if not self._enablehiding or not self._pages[ii]._ishidden: width = self._CalcTabTextWidth(dc, ii) bmpWidth, bmpHeight = self._CalcTabBitmapSize(ii) tabrect = self._CalcTabRect(ii, posx, posy, width, bmpWidth, bmpHeight) if tabrect.Contains(point): if flags: flags = NC_HITTEST_ONITEM #onx attempt if self.GetDrawX()[0]: count = self._tabvisible[0:ii].count(0) if flags and self._xrect[ii-self._firstvisible-count].Contains(point): flags = NC_HITTEST_ONX #onicon attempt if flags and bmpWidth > 0 and \ wx.RectPS(wx.Point(*self._CalcTabBitmapPosition(ii, bmpWidth, bmpHeight, tabrect)), wx.Size(bmpWidth, bmpHeight)).Contains(point): flags = NC_HITTEST_ONICON #onlabel attempt elif flags and wx.RectPS(wx.Point(*self._CalcTabTextPosition(ii, tabrect, self._CalcTabBitmapSpace(bmpWidth, bmpHeight))), wx.Size(width, height)).Contains(point): flags = NC_HITTEST_ONLABEL if flags: return ii, flags else: return ii if self._style & NC_TOP or self._style & NC_BOTTOM: posx += tabrect.width else: posy += tabrect.height if flags: return wx.NOT_FOUND, flags else: return wx.NOT_FOUND def EnableDragAndDrop(self, enable=True): """ Globall Enables/Disables Tabs Drag And Drop. """ self._enabledragging = enable def EnableHiding(self, enable=True): """ Globally Enables/Disables Hiding On Tabs In Runtime. """ self._enablehiding = enable self.UpdateMenuButton(enable) wx.FutureCall(1000, self.UpdateMenuButton, enable) def SetAnimationImages(self, nPage, imgarray): """ Sets An Animation List Associated To The Given Page nPage. @param nPage: The Given Page @param imgarray: A List Of Image Indexes Of Images Inside The ImageList Associated To NotebookCtrl. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetAnimationImages: (" + str(nPage) + ")" if not imgarray: raise "\nERROR: Invalid Image Array In SetAnimationImages: (" + repr(imgarray) + ")" if min(imgarray) < 0: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Min(ImgArray) = " + \ str(min(imgarray)) + " < 0)" if max(imgarray) > self.GetImageList().GetImageCount() - 1: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Max(ImgArray) = " + \ str(max(imgarray)) + " > " + str(self.GetImageList().GetImageCount()-1) + ")" self._pages[nPage]._animationimages = imgarray def GetAnimationImages(self, nPage): """ Returns The Animation Images List Associated To The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetAnimationImages: (" + str(nPage) + ")" return self._pages[nPage]._animationimages def AnimateTab(self, event): """ Called When The Refreshing Animation Timer Expires. Used Internally""" obj = event.GetEventObject() nPage = self._timers.index(obj) if not self.IsPageEnabled(nPage): return indx = self.GetPageImage(nPage) images = self.GetAnimationImages(nPage) myindx = images.index(indx) if indx == images[-1]: myindx = -1 myindx = myindx + 1 self.SetPageImage(nPage, images[myindx]) def StartAnimation(self, nPage, timer=500): """ Starts The Animation On The Given Page, With Refreshing Time Rate "timer". """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StartAnimation: (" + str(nPage) + ")" images = self.GetAnimationImages(nPage) if not images: raise "\nERROR: No Images Array Defined For Page: (" + str(nPage) + ")" if len(images) == 1: raise "\nERROR: Impossible To Animate Tab: " + str(nPage) + " With Only One Image" self._timers[nPage].Start(timer) def StopAnimation(self, nPage): """ Stops The Animation On The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StopAnimation: (" + str(nPage) + ")" if self._timers[nPage].IsRunning(): self._timers[nPage].Stop() def SetDrawX(self, drawx=True, style=1, image1=None, image2=None): """ Globally Enables/Disables The Drawing Of A Closing "X" In The Tab. @param drawx: C{True} to enable drawing a closing "X"; C{False} to disable it @param style: the style of the X to draw when C{drawx} is C{True}; possible values are: - C{1}: Small "X" At The Top-Right Of The Tab; - C{2}: Bigger "X" In The Middle Vertical Of The Tab (Like Opera Notebook); - C{3}: Custom "X" Image Is Drawn On Tabs. @param image1: if C{style} is C{3}, the image to use when drawing the X on an unhighlighted tab @param image2: if C{style} is C{3}, the image to use when drawing the X on a highlighted tab """ self._drawx = drawx self._drawxstyle = style if style == 3: self._imglist2 = wx.ImageList(16, 16, True, 0) self._imglist2.Add(image1) self._imglist2.Add(image2) if self._style & NC_LEFT or self._style & NC_RIGHT: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self._parent.GetSizer().Layout() self.Refresh() def GetDrawX(self): """ Returns The Enable/Disable State Of Drawing Of A Small "X" At The Top-Right Of Every Page. """ return self._drawx, self._drawxstyle def GetInsideTab(self, pt): """ Returns The Tab On Which The Mouse Is Hovering On. """ count = 0 for tabs in self._tabrect: if tabs.Contains(pt): return count count = count + 1 return -1 def GetInsideX(self, pt): """ Returns The Tab On Which The Mouse Is Hovering On The "X" Button. """ count = 0 for rects in self._xrect: if rects.Contains(pt): return count count = count + 1 return -1 def SetImageToCloseButton(self, convert=True): """ Set Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ self._convertimage = convert def GetImageToCloseButton(self): """ Get Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ return self._convertimage def ConvertImageToCloseButton(self, page): """ Globally Converts The Page Image To The "Opera" Style Close Button. """ bmpindex = self.GetPageImage(page) if bmpindex < 0: return tabrect = self._tabrect[page] size = self.GetSize() maxfont = self._maxfont dc = wx.ClientDC(self) dc.SetFont(maxfont) pom, height = dc.GetTextExtent("Aq") bmp = self._imglist.GetBitmap(bmpindex) bmpposx = tabrect.x + self._padding.x bmpposy = size.y - (height + 2*self._padding.y + bmp.GetHeight())/2 - 1 ypos = size.y - height - self._padding.y*2 ysize = height + self._padding.y*2 + 3 if page == self.GetSelection(): bmpposx = bmpposx + 1 bmpposy = bmpposy - 1 ypos = ypos - 3 ysize = ysize + 2 colour = self.GetPageColour(page) bmprect = wx.Rect(bmpposx, bmpposy, bmp.GetWidth()+self._padding.x, bmp.GetHeight()) dc.SetBrush(wx.Brush(colour)) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangleRect(bmprect) colour = self.GetPageTextColour(page) r = colour.Red() g = colour.Green() b = colour.Blue() hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64) colour = wx.Colour(hr, hg, hb) back_colour = wx.WHITE yypos = ypos+(ysize-height-self._padding.y/2)/2 xrect = wx.Rect(bmprect.x+(bmprect.width - self._padding.x - height)/2, yypos, height, height) # Opera Style dc.SetPen(wx.Pen(colour, 1)) dc.SetBrush(wx.Brush(colour)) dc.DrawRoundedRectangleRect(xrect, 2) dc.SetPen(wx.Pen(back_colour, 2)) dc.DrawLine(xrect[0]+2, xrect[1]+2, xrect[0]+xrect[2]-3, xrect[1]+xrect[3]-3) dc.DrawLine(xrect[0]+2, xrect[1]+xrect[3]-3, xrect[0]+xrect[2]-3, xrect[1]+2) def RedrawClosingX(self, pt, insidex, drawx, highlight=False): """ Redraw The Closing "X" Accordingly To The Mouse "Hovering" Position. """ colour = self.GetPageTextColour(insidex) back_colour = self.GetBackgroundColour() imagelist = 0 if highlight: r = colour.Red() g = colour.Green() b = colour.Blue() hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64) colour = wx.Colour(hr, hg, hb) back_colour = wx.WHITE imagelist = 1 dc = wx.ClientDC(self) xrect = self._xrect[insidex] if drawx == 1: # Emule Style dc.SetPen(wx.Pen(colour, 1)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawRectangleRect(xrect) elif drawx == 2: # Opera Style dc.SetPen(wx.Pen(colour, 1)) dc.SetBrush(wx.Brush(colour)) dc.DrawRoundedRectangleRect(xrect, 2) dc.SetPen(wx.Pen(back_colour, 2)) dc.DrawLine(xrect[0]+2, xrect[1]+2, xrect[0]+xrect[2]-3, xrect[1]+xrect[3]-3) dc.DrawLine(xrect[0]+2, xrect[1]+xrect[3]-3, xrect[0]+xrect[2]-3, xrect[1]+2) else: self._imglist2.Draw(imagelist, dc, xrect[0], xrect[1], wx.IMAGELIST_DRAW_TRANSPARENT, True) def HideOnSingleTab(self, hide=True): """ Hides The TabCtrl When There Is Only One Tab In NotebookCtrl. """ self._hideonsingletab = hide def SetPagePopupMenu(self, nPage, menu): """ Sets A Popup Menu Specific To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPagePopupMenu: (" + str(nPage) + ")" self._pages[nPage]._menu = menu def GetPagePopupMenu(self, nPage): """ Returns The Popup Menu Associated To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPagePopupMenu: (" + str(nPage) + ")" return self._pages[nPage]._menu def DrawInsertionMark(self, dc, nPage): """ Draw An Insertion Arrow To Let The User Understand Where A Dragged Tab Will Be Dropped (Between Which Tabs). """ if not self._enablehiding: if nPage < 0 or nPage >= len(self._tabrect): return else: if nPage < 0 or nPage >= len(self._tabrect) + self._tabvisible.count(0): return colour = wx.BLACK somehidden = False if self._enablehiding: for ii in xrange(nPage): if self._pages[ii]._ishidden: nPage = nPage - 1 somehidden = True rect = self._tabrect[nPage] x1 = rect.x - 4 y1 = rect.y - 1 x2 = rect.x y2 = y1 + 5 x3 = rect.x + 3 y3 = y1 mybrush = wx.Brush(self.GetPageTextColour(nPage)) if not self._enablehiding: if nPage > self._tabID: x1 = x1 + rect.width x2 = x2 + rect.width x3 = x3 + rect.width else: mybrush = wx.Brush(self.GetPageTextColour(nPage)) if nPage >= self._tabID: x1 = x1 + rect.width x2 = x2 + rect.width x3 = x3 + rect.width dc.SetPen(wx.Pen(wx.BLACK, 1)) dc.SetBrush(mybrush) dc.DrawPolygon([(x1, y1), (x2, y2), (x3, y3)]) def OnMouseMotion(self, event): """ Handles The wx.EVT_MOTION Event For TabCtrl. """ pt = event.GetPosition() if self._enabledragging: if event.Dragging() and not event.RightIsDown() and not event.MiddleIsDown(): tolerance = 2 dx = abs(pt.x - self._dragstartpos.x) dy = abs(pt.y - self._dragstartpos.y) if dx <= tolerance and dy <= tolerance: self.SetCursor(wx.STANDARD_CURSOR) return self.SetCursor(self._dragcursor) self._isdragging = True self._isleaving = False newpos = self.HitTest(pt) if newpos >= 0 and newpos != self._olddragpos: self._olddragpos = newpos self.Refresh() else: self._isdragging = False self.SetCursor(wx.STANDARD_CURSOR) if not event.Dragging(): drawx = self.GetDrawX() if drawx[0]: insidex = self.GetInsideX(pt) if insidex >= 0: if self.IsPageEnabled(insidex): self.RedrawClosingX(pt, insidex, drawx[1], True) self._xrefreshed = False else: if not self._xrefreshed: insidetab = self.GetInsideTab(pt) if insidetab >= 0: if self.IsPageEnabled(insidetab): self.RedrawClosingX(pt, insidetab, drawx[1]) self._xrefreshed = True else: if self.GetImageToCloseButton(): page, flags = self.HitTest(pt, 1) if page >= 0: if self.IsPageEnabled(page): if flags == NC_HITTEST_ONICON: if not self._imageconverted: self.ConvertImageToCloseButton(page) self._imageconverted = True else: if self._imageconverted: self.Refresh() self._imageconverted = False if self._showtooltip: if not event.Dragging(): if not event.LeftDown(): oldinside = self._insidetab self._insidetab = self.GetInsideTab(pt) if self._insidetab >= 0: if oldinside != self._insidetab: if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() if self._tiptimer.IsRunning(): self._tiptimer.Stop() tip, ontime, winsize= self.GetPageToolTip(self._insidetab) if tip.strip() != "": self._currenttip = tip self._currentwinsize = winsize self._tiptimer.Start(ontime, wx.TIMER_ONE_SHOT) else: if self._istooltipshown: self._tipwindow.Destroy() self._istooltipshown = False self.Refresh() self._mousepos = pt event.Skip() def OnShowToolTip(self): """ Called When The Timer For The ToolTip Expires. Used Internally. """ pt = self.ScreenToClient(wx.GetMousePosition()) oldinside = self._insidetab self._insidetab = self.GetInsideTab(pt) if self._insidetab != oldinside or self._insidetab < 0: return self._istooltipshown = True self._tipwindow = self.TransientTipWindow(self, self._currenttip, self._currentwinsize) xsize, ysize = self._tipwindow.GetSize() xpos, ypos = self.ClientToScreen(self._mousepos) if xpos + xsize > self._xvideo - 10: if ypos + ysize > self._yvideo - 10: # SW Tip Positioning posx = xpos - xsize posy = ypos - ysize else: # NE Tip Positioning posx = xpos - xsize posy = ypos else: if ypos + ysize > self._yvideo - 10: # SE Tip Positioning posx = xpos + 10 posy = ypos - ysize else: # NW Tip Positioning posx = xpos + 10 posy = ypos if posy < 0: posy = ypos if posx < 0: posx = xpos self._tipwindow.SetPosition((posx, posy)) self._tipwindow.Show() def OnMouseLeftDown(self, event): """ Handles The wx.EVT_LEFT_DOWN Event For TabCtrl. """ pos = event.GetPosition() page, flags = self.HitTest(pos, 1) self._dragstartpos = pos if page != wx.NOT_FOUND: if self.IsPageEnabled(page): if event.m_controlDown: if page in self._selectedtabs: self._selectedtabs.remove(page) else: self._selectedtabs.append(page) self.Refresh() else: self._selectedtabs = [] if flags == NC_HITTEST_ONX or (flags == NC_HITTEST_ONICON and self.GetImageToCloseButton()): eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CLOSING, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): self._parent.DeletePage(page) self._parent.bsizer.Layout() else: self.SetSelection(page) self._tabID = page event.Skip() def OnMouseLeftDClick(self, event): """ Handles The wx.EVT_LEFT_DCLICK Event For TabCtrl. """ pos = event.GetPosition() page = self.HitTest(pos) self._selectedtabs = [] if page == wx.NOT_FOUND: return if not self.IsPageEnabled(page): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DCLICK, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): return event.Skip() def OnMouseLeftUp(self, event): """ Handles The wx.EVT_LEFT_UP Event For TabCtrl. """ if not self._enabledragging: event.Skip() return if not self._isdragging: self.SetCursor(wx.STANDARD_CURSOR) event.Skip() return id = self.HitTest(wx.Point(event.GetX(), event.GetY())) if id >= 0 and id != self._tabID: self._isdragging = False self._olddragpos = -1 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, self.GetId()) eventOut.SetOldPosition(self._tabID) eventOut.SetNewPosition(id) eventOut.SetEventObject(self) if self.GetEventHandler().ProcessEvent(eventOut): self._tabID = -1 self._olddragpos = -1 self.SetCursor(wx.STANDARD_CURSOR) self.Refresh() return self._parent.Freeze() try: text = self.GetPageText(self._tabID) image = self.GetPageImage(self._tabID) font1 = self.GetPageTextFont(self._tabID) font2 = self.GetPageTextSecondaryFont(self._tabID) fontcolour = self.GetPageTextColour(self._tabID) pagecolour = self.GetPageColour(self._tabID) enabled = self.IsPageEnabled(self._tabID) tooltip, ontime, winsize = self.GetPageToolTip(self._tabID) menu = self.GetPagePopupMenu(self._tabID) firstcol = self.GetPageFirstGradientColour(self._tabID) secondcol = self.GetPageSecondGradientColour(self._tabID) ishidden = self._pages[self._tabID]._ishidden except: self._parent.Thaw() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) return isanimated = 0 if self._timers[self._tabID].IsRunning(): isanimated = 1 timer = self._timers[self._tabID].GetInterval() self.StopAnimation(self._tabID) animatedimages = self.GetAnimationImages(self._tabID) pagerange = range(self.GetPageCount()) newrange = pagerange[:] newrange.remove(self._tabID) newrange.insert(id, self._tabID) newpages = [] counter = self.GetPageCount() - 1 for ii in xrange(self.GetPageCount()): newpages.append(self._parent.GetPage(ii)) self._parent.bsizer.Detach(counter-ii) cc = 0 self._parent._notebookpages = [] for jj in newrange: self._parent.bsizer.Add(newpages[jj], 1, wx.EXPAND | wx.ALL, 2) self._parent.bsizer.Show(cc, False) self._parent._notebookpages.append(newpages[jj]) cc = cc + 1 self.DeletePage(self._tabID) if enabled: if id == self.GetPageCount(): self.AddPage(text, True, image) else: self.InsertPage(id, text, True, image) else: if id == self.GetPageCount(): self.AddPage(text, False, image) else: self.InsertPage(id, text, False, image) self.SetPageImage(id, image) self.SetPageText(id, text) self.SetPageTextFont(id, font1) self.SetPageTextSecondaryFont(id, font2) self.SetPageTextColour(id, fontcolour) self.SetPageColour(id, pagecolour) self.EnablePage(id, enabled) self.SetPageToolTip(id, tooltip, ontime, winsize) self.SetPagePopupMenu(id, menu) self.SetPageFirstGradientColour(id, firstcol) self.SetPageSecondGradientColour(id, secondcol) self._pages[id]._ishidden = ishidden if isanimated and len(animatedimages) > 1: self.SetAnimationImages(id, animatedimages) self.StartAnimation(id, timer) if enabled: self._parent.bsizer.Show(id, True) else: sel = self.GetSelection() if sel == -1: sel = 0 self._parent.bsizer.Show(id, False) self._parent.SetSelection(sel) self._parent.bsizer.Show(sel, True) self._parent.bsizer.Layout() self._parent.Thaw() self._isdragging = False self._olddragpos = -1 self._fromdnd = True self.Refresh() self._tabID = -1 self.SetCursor(wx.STANDARD_CURSOR) event.Skip() def OnSize(self, event=None): """ Handles The wx.EVT_SIZE Event For TabCtrl. """ if self._sizeToggleButton: width = self.GetSize()[0] height = self._CalcSizeToggleBestSize()[1] self._sizeToggleButton.SetSize(wx.Size(width, height)) self.Refresh() if event is not None: event.Skip() def OnMouseRightUp(self, event): """ Handles The wx.EVT_RIGHT_UP Event For TabCtrl. """ pt = event.GetPosition() id = self.HitTest(pt) self._selectedtabs = [] if id >= 0: if self.IsPageEnabled(id): menu = self.GetPagePopupMenu(id) if menu: self.PopupMenu(menu) event.Skip() def OnMouseRightDown(self, event): """ Handles The wx.EVT_RIGHT_DOWN Event For TabCtrl. """ pos = event.GetPosition() page = self.HitTest(pos) self._selectedtabs = [] if page == wx.NOT_FOUND: return if not self.IsPageEnabled(page): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_RIGHT, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): return event.Skip() def OnMouseMiddleDown(self, event): """ Handles The wx.EVT_MIDDLE_DOWN Event For TabCtrl. """ pos = event.GetPosition() page = self.HitTest(pos) self._selectedtabs = [] if page == wx.NOT_FOUND: return if not self.IsPageEnabled(page): return eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE, self.GetId()) eventOut.SetOldSelection(self._selection) eventOut.SetSelection(page) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): return event.Skip() def SetSelectionColour(self, colour=None): """ Sets The Tab Selection Colour (Thin Line Above The Selected Tab). """ if colour is None: colour = wx.Colour(255, 180, 0) self._selectioncolour = colour def SetContourLineColour(self, colour=None): """ Sets The Contour Line Colour (Controur Line Around Tabs). """ if colour is None: if not self._tabstyle._normal or self._usegradients: colour = wx.Colour(145, 167, 180) else: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) if not self._tabstyle._normal or self._usegradients: self._highlightpen = wx.Pen(colour) self._highlightpen.SetCap(wx.CAP_BUTT) else: self._highlightpen2 = wx.Pen(colour) self._highlightpen2.SetCap(wx.CAP_BUTT) self.Refresh() def ApplyTabTheme(self, theme=None): """ Applies A Particular Theme To Be Drawn On Tabs. """ if theme is None: theme = ThemeStyle() self._tabstyle = theme if self._style & NC_EXPANDABLE: self._InitExpandableTabStyles(self._style, self._expanded, theme) self.Refresh() def DrawMacTheme(self, dc, tabrect, theme): """ Draws The Mac Theme On Tabs, If It Is Enabled. """ if theme == 1: col1, col2 = NC_MAC_LIGHT else: col1, col2 = NC_MAC_DARK colour1 = wx.Colour(col1, col1, col1) colour2 = wx.Colour(col2, col2, col2) x, y, w, h = tabrect endrange = self._style & NC_ROTATE and w or h index = 0 for ii in xrange(0, endrange, 2): if index%2 == 0: colour = colour1 else: colour = colour2 dc.SetBrush(wx.Brush(colour)) dc.SetPen(wx.Pen(colour)) if self._style & NC_ROTATE: if ii > 3: dc.DrawRectangle(x+ii, y, 2, w) else: dc.DrawRoundedRectangle(x+ii, y, 3, 3) else: if ii > 3: dc.DrawRectangle(x, y+ii, w, 2) else: dc.DrawRoundedRectangle(x, y+ii, w, 3, 3) index = index + 1 self._lastcolour = colour def DrawKDETheme(self, dc, rect): """ Draws Unix-Style KDE Theme On Tabs. """ x, y, w, h = rect if self._style & NC_ROTATE and self._style & NC_RIGHT: bandrange = xrange(13, -1, -1) self._lastcolour = kdetheme[13] brush = wx.Brush(kdetheme[0], wx.SOLID) else: bandrange = xrange(14) self._lastcolour = kdetheme[0] brush = wx.Brush(kdetheme[13], wx.SOLID) dc.SetBackground(brush) for band in bandrange: pen = wx.Pen(kdetheme[band]) dc.SetPen(pen) if self._style & NC_ROTATE: if self._style & NC_RIGHT: dc.DrawLine(x+1+band, y+1, x+1+band, y+h-1) dc.DrawLine(x+w-(1+band), y+1, x+w-(1+band), y+h-2) else: dc.DrawLine(x+1+band, y+1, x+1+band, y+h-1) dc.DrawLine(x+w-(2+band), y+1, x+w-(2+band), y+h-2) else: dc.DrawLine(x+1, y+band, x+w-1, y+band) dc.DrawLine(x+1, y+h-1-band, x+w-2, y+h-1-band) def DrawSilverTheme(self, dc, rect, selected): """ Draws Windows XP Silver-Like Theme. """ x, y, w, h = rect if selected: r1 = silvertheme1[0].Red() g1 = silvertheme1[0].Green() b1 = silvertheme1[0].Blue() r2 = silvertheme1[1].Red() g2 = silvertheme1[1].Green() b2 = silvertheme1[1].Blue() else: r1 = silvertheme2[0].Red() g1 = silvertheme2[0].Green() b1 = silvertheme2[0].Blue() r2 = silvertheme2[1].Red() g2 = silvertheme2[1].Green() b2 = silvertheme2[1].Blue() rend = silvertheme2[2].Red() gend = silvertheme2[2].Green() bend = silvertheme2[2].Blue() if self._style & NC_ROTATE: flrect = float(w-2) else: flrect = float(h-2) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 if self._style & NC_ROTATE: if self._style & NC_RIGHT: bandrange = xrange(x+w-2, x, -1) else: bandrange = xrange(x+1, x+w-1) else: bandrange = xrange(y+1, y+h) for band in bandrange: currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) dc.SetPen(wx.Pen(currCol)) if self._style & NC_ROTATE: if counter == 0: ypos = y + 2 yend = h - 4 elif counter == 1: ypos = y + 1 yend = h - 2 else: ypos = y + 1 yend = h - 2 dc.DrawRectangle(band, ypos, 1, yend) else: if counter == 0: xpos = x + 2 xend = w - 4 elif counter == 1: xpos = x + 1 xend = w - 2 else: xpos = x + 1 xend = w - 2 dc.DrawRectangle(xpos, band, xend, 1) counter = counter + 1 rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol if not selected and self._style & NC_TOP: dc.SetBrush(wx.Brush((rend, gend, bend))) dc.SetPen(wx.Pen((rend, gend, bend))) if self._style & NC_ROTATE: if self._style & NC_LEFT: xpos = x + w - 4 else: xpos = x dc.DrawRectangle(xpos, ypos, 3, yend) else: dc.DrawRectangle(xpos, y+h-3, xend, 3) self._lastcolour = wx.Colour(rend, gend, bend) def DrawAquaTheme(self, dc, rect, style, selected): """ Draws Mac-Style Aqua Theme On Tabs. """ x, y, w, h = rect if selected: if style == 1: # Dark Aqua r1 = topaqua1[0].Red() g1 = topaqua1[0].Green() b1 = topaqua1[0].Blue() r2 = topaqua1[1].Red() g2 = topaqua1[1].Green() b2 = topaqua1[1].Blue() else: r1 = topaqua2[0].Red() g1 = topaqua2[0].Green() b1 = topaqua2[0].Blue() r2 = topaqua2[1].Red() g2 = topaqua2[1].Green() b2 = topaqua2[1].Blue() else: r1 = distaqua[0].Red() g1 = distaqua[0].Green() b1 = distaqua[0].Blue() r2 = distaqua[1].Red() g2 = distaqua[1].Green() b2 = distaqua[1].Blue() flrect = float((h-2)/2) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 dc.SetPen(wx.TRANSPARENT_PEN) if self._style & NC_ROTATE: startrange, endrange = (x, w) else: startrange, endrange = (y, h) if self._style & NC_ROTATE and self._style & NC_RIGHT: bandrange = xrange(startrange+endrange, startrange+endrange/2, -1) else: bandrange = xrange(startrange+1, startrange+endrange/2) for band in bandrange: currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) if self._style & NC_ROTATE: if counter == 0: ypos = y + 2 yend = h - 4 elif counter == 1: ypos = y + 1 yend = h - 2 else: ypos = y + 1 yend = h - 2 dc.DrawRectangle(band, ypos, 1, yend) else: if counter == 0: xpos = x + 2 xend = w - 4 elif counter == 1: xpos = x + 1 xend = w - 2 else: xpos = x + 1 xend = w - 2 dc.DrawRectangle(xpos, band, xend, 1) counter = counter + 1 rf = rf + rstep gf = gf + gstep bf = bf + bstep if selected: if style == 1: # Dark Aqua r1 = botaqua1[0].Red() g1 = botaqua1[0].Green() b1 = botaqua1[0].Blue() r2 = botaqua1[1].Red() g2 = botaqua1[1].Green() b2 = botaqua1[1].Blue() else: r1 = botaqua2[0].Red() g1 = botaqua2[0].Green() b1 = botaqua2[0].Blue() r2 = botaqua2[1].Red() g2 = botaqua2[1].Green() b2 = botaqua2[1].Blue() else: r1 = disbaqua[0].Red() g1 = disbaqua[0].Green() b1 = disbaqua[0].Blue() r2 = disbaqua[1].Red() g2 = disbaqua[1].Green() b2 = disbaqua[1].Blue() flrect = float((h-2)/2) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 if self._style & NC_ROTATE and self._style & NC_RIGHT: bandrange = xrange(startrange+endrange/2, startrange+1, -1) else: bandrange = xrange(startrange+endrange/2, startrange+endrange) for band in bandrange: currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) if self._style & NC_ROTATE: dc.DrawRectangle(band, y + 1, 1, h-2) else: dc.DrawRectangle(x+1, band, w-2, 1) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def DrawMetalTheme(self, dc, rect): """ Draws Mac-Style Metal Gradient On Tabs. """ x, y, w, h = rect dc.SetPen(wx.TRANSPARENT_PEN) counter = 0 if self._style & NC_ROTATE: bandrange = xrange(x+1, x+w) else: bandrange = xrange(y+1, h+y) for band in bandrange: if self._style & NC_ROTATE: intens = (230 + 80 * (x-band)/w) else: intens = (230 + 80 * (y-band)/h) colour = wx.Colour(intens, intens, intens) dc.SetBrush(wx.Brush(colour)) if self._style & NC_ROTATE: if counter == 0: ypos = y + 2 yend = h - 4 elif counter == 1: ypos = y + 1 yend = h - 2 else: ypos = y + 1 yend = h - 2 if self._style & NC_RIGHT: dc.DrawRectangle(x+w-band, ypos, 1, yend) else: dc.DrawRectangle(x+band, ypos, 1, yend) else: if counter == 0: xpos = x + 2 xend = w - 4 elif counter == 1: xpos = x + 1 xend = w - 2 else: xpos = x + 1 xend = w - 2 dc.DrawRectangle(xpos, band, xend, 1) counter = counter + 1 self._lastcolour = colour def DrawVerticalGradient(self, dc, rect, index): """ Gradient Fill From Colour 1 To Colour 2 From Top To Bottom. """ dc.SetPen(wx.TRANSPARENT_PEN) # calculate gradient coefficients col2 = self._tabstyle.GetSecondGradientColour(index == self.GetSelection()) col1 = self._tabstyle.GetFirstGradientColour(index == self.GetSelection()) r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) flrect = float(rect.height) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 bandrange = xrange(rect.y+1, rect.y + rect.height-1) lenc = len(bandrange) for y in bandrange: currCol = (r1 + rf, g1 + gf, b1 + bf) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) # adjust along x-axis to preserve the curved tab edge def GetXAdjust(counter): if counter >=2 or counter <=lenc-2: return 1 if self._style & NC_LEFT or self._style & NC_RIGHT and not self._style & NC_ROTATE: if counter == 0 and self._style & NC_RIGHT or \ counter == lenc - 1 and self._style & NC_LEFT: return 3 elif counter == 1 and self._style & NC_RIGHT or \ counter == lend - 2 and self._style & NC_LEFT: return 2 else: return 1 else: if counter == lenc - 2: return 2 elif counter == lenc - 1: return 3 else: return 1 xadjust = GetXAdjust(counter) xpos = rect.x + xadjust xend = rect.width - xadjust counter = counter + 1 dc.DrawRectangle(xpos, y, xend, 1) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def DrawHorizontalGradient(self, dc, rect, index): """ Gradient Fill From Colour 1 To Colour 2 From Left To Right. """ dc.SetPen(wx.TRANSPARENT_PEN) # calculate gradient coefficients col2 = self._tabstyle.GetSecondGradientColour(index == self.GetSelection()) col1 = self._tabstyle.GetFirstGradientColour(index == self.GetSelection()) r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) flrect = float(rect.width) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 bandrange = xrange(rect.x + 1, rect.x + rect.width - 1) lenc = len(bandrange) for x in bandrange: currCol = (r1 + rf, g1 + gf, b1 + bf) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) # adjust along y-axis to preserve the curved tab edge def GetYAdjust(counter): if counter >=2 or counter <=lenc-2: return 1 if self._style & NC_TOP or self._style & NC_BOTTOM or \ (self._style & NC_LEFT and self._style & NC_ROTATE): if counter == 0 or counter == lenc - 1 and not self._style & NC_LEFT: return 3 elif counter == 1 or counter == lenc - 2 and not self._style & NC_LEFT: return 2 else: return 1 else: if counter == lenc - 2: return 2 elif counter == lenc - 1: return 3 else: return 1 yadjust = GetYAdjust(counter) ypos = rect.y + yadjust yend = rect.height - yadjust counter = counter + 1 dc.DrawRectangle(x, ypos, 1, yend) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def GetAllTextExtents(self, dc): """ Returns All Tabs Text Extents. Used Internally. """ self._mintabwidths = [] self._maxtabwidths = [] self._mintabheights = [] self._maxtabheights = [] self._incrtext = [] minheight = 0 for ii in xrange(self.GetPageCount()): txts = self.GetPageText(ii) font1 = self.GetPageTextFont(ii) dc.SetFont(font1) w1, h1 = dc.GetTextExtent(txts) minheight = max(minheight, h1) self._mintabwidths.append(w1) self._mintabheights.append(h1) font2 = self.GetPageTextSecondaryFont(ii) dc.SetFont(font2) w2, h2 = dc.GetTextExtent(txts) minheight = max(minheight, h2) self._maxtabwidths.append(w2) self._maxtabheights.append(h2) self._incrtext.append(abs(self._mintabwidths[ii] - self._maxtabwidths[ii])) mh1 = max(self._mintabheights) font1 = self.GetPageTextFont(self._mintabheights.index(mh1)) mh2 = max(self._maxtabheights) font2 = self.GetPageTextSecondaryFont(self._maxtabheights.index(mh2)) mhend = max(mh1, mh2) if mhend == mh1: maxfont = font1 else: maxfont = font2 minheight = self.GetSize()[1] return minheight, maxfont def DrawBuiltinStyle(self, dc, style, rect, index, selection): """ Methods That Holds All The Theme Styles. """ if style._aqua: if self._selstyle._normal: self.DrawAquaTheme(dc, rect, style._aqua, index==selection) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._metal: if self._selstyle._normal: self.DrawMetalTheme(dc, rect) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._kdetheme: if self._selstyle._normal: self.DrawKDETheme(dc, rect) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._macstyle: if self._selstyle._normal: self.DrawMacTheme(dc, rect, style._macstyle) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._gradient: if self._selstyle._normal: if style._gradient & ThemeStyle.GRADIENT_VERTICAL: self.DrawVerticalGradient(dc, rect, index) else: self.DrawHorizontalGradient(dc, rect, index) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle elif style._silver: if self._selstyle._normal: self.DrawSilverTheme(dc, rect, index==selection) else: oldselstyle = self._selstyle[:] self._selstyle._normal = True self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) self._selstyle = oldselstyle def DrawGradientOnTab(self, dc, rect, col1, col2): """ Draw A Gradient Coloured Tab. """ dc.SetPen(wx.TRANSPARENT_PEN) r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) flrect = float(rect.height) rstep = float((r2 - r1)) / flrect gstep = float((g2 - g1)) / flrect bstep = float((b2 - b1)) / flrect rf, gf, bf = 0, 0, 0 counter = 0 for y in xrange(rect.y+1, rect.y + rect.height): currCol = (r1 + rf, g1 + gf, b1 + bf) dc.SetBrush(wx.Brush(currCol, wx.SOLID)) if counter == 0: xpos = rect.x + 2 xend = rect.width - 4 elif counter == 1: xpos = rect.x + 1 xend = rect.width - 2 else: xpos = rect.x xend = rect.width counter = counter + 1 dc.DrawRectangle(xpos, y, xend, 1) rf = rf + rstep gf = gf + gstep bf = bf + bstep self._lastcolour = currCol def _CalcBestWidth(self, dc): return max(self._CalcMaxTabWidth(dc), self._CalcSizeToggleBestSize()[0]) def _CalcMaxTabWidth(self, dc): self._CalcMaxTextHeight(dc) textWidth = max(self._maxtabwidths) tabIndex = self._maxtabwidths.index(textWidth) bmpWidth, bmpHeight = self._CalcTabBitmapSize(tabIndex) tabrect = self._CalcTabRect(tabIndex, 0, 0, textWidth, bmpWidth, bmpHeight) # return the width based on the longest label, plus 3 for # the additional width of the selected tab return tabrect.width + 3 def _CalcMaxTextHeight(self, dc): if self._somethingchanged: minheight, maxfont = self.GetAllTextExtents(dc) self._minheight = minheight self._maxfont = maxfont else: minheight = self._minheight maxfont = self._maxfont dc.SetFont(maxfont) _, height = dc.GetTextExtent("Aq") self._maxtextheight = height def _CalcSizeToggleBestSize(self): if self._sizeToggleButton: return self._sizeToggleButton.GetBestSize() else: return wx.Size(0,0) def _CalcTabBitmapPosition(self, tabIndex, bmpWidth, bmpHeight, tabrect): if self._style & NC_ROTATE: bmpposx = tabrect.x + (tabrect.width - bmpWidth) / 2 yoffset = self._padding.x if self._style & NC_LEFT: bmpposx += 1 bmpposy = tabrect.y + tabrect.height - (yoffset + bmpHeight) else: bmpposy = tabrect.y + yoffset if tabIndex == self.GetSelection(): bmpposx += self._style & NC_LEFT and -1 or 1 else: bmpposx = tabrect.x + self._padding.x bmpposy = tabrect.y + (tabrect.height - bmpHeight) / 2 if tabIndex == self.GetSelection() and self._style & NC_TOP: bmpposy -= 1 return (bmpposx, bmpposy) def _CalcTabBitmapSize(self, tabIndex): result = (0, 0) bmp = self._GetTabBitmap(tabIndex) bmpOk = bmp.Ok() if bmpOk: result = (bmp.GetWidth(), bmp.GetHeight()) return result def _CalcTabBitmapSpace(self, bmpWidth, bmpHeight): space = self._padding.x bmpSpace = self._style & NC_ROTATE and bmpHeight or bmpWidth if bmpSpace: space = space + self._padding.x + bmpSpace return space def _CalcTabRect(self, tabIndex, posx, posy, textWidth, bmpWidth, bmpHeight): xpos = posx if self._style & NC_BOTTOM: ypos = 1 elif self._style & NC_TOP: ypos = self.GetSize().y - self._maxtextheight - self._padding.y*2 else: ypos = posy xsize = textWidth + self._CalcTabBitmapSpace(bmpWidth, bmpHeight) + \ self._padding.x + self._incrtext[tabIndex] + \ self._CalcXWidth() ysize = self._maxtextheight + self._padding.y*2 if self._style & NC_TOP: ysize += 3 if self._style & NC_ROTATE: xsize, ysize = (ysize, xsize) if tabIndex == self.GetSelection(): if self._style & NC_TOP or self._style & NC_BOTTOM: xsize = xsize + self._spacetabs if tabIndex > 0: xpos = xpos - self._spacetabs xsize = xsize + self._spacetabs if self._style & NC_TOP: ypos -= 3 ysize = ysize + 2 else: xsize += 3 if self._style & NC_LEFT: xpos = self.GetSize().width - xsize return wx.Rect(xpos, ypos, xsize, ysize) def _CalcTabTextPosition(self, tabIndex, tabrect, space): xtextpos = tabrect.x + space + self._incrtext[tabIndex]/2 if self._style & NC_BOTTOM: ytextpos = self._padding.y else: ytextpos = tabrect.y + self._padding.y + 1 if tabIndex == self.GetSelection(): if tabIndex == 0 and self._style & NC_TOP or self._style & NC_BOTTOM: xtextpos = xtextpos + self._spacetabs/2.0 + 1 if self._style & NC_BOTTOM: ytextpos += 2 elif self._style & NC_TOP: ytextpos -= 2 if self._style & NC_ROTATE: xoffset = ytextpos - tabrect.y yoffset = xtextpos - tabrect.x if self._style & NC_LEFT: xtextpos, ytextpos = (tabrect.x + xoffset - 1, tabrect.y + tabrect.height - yoffset) else: yoffset += self._CalcXWidth() xtextpos, ytextpos = (tabrect.x + tabrect.width - xoffset, tabrect.y + yoffset) return (xtextpos, ytextpos) def _CalcTabTextWidth(self, dc, tabIndex): if self._style & NC_FIXED_WIDTH: result = max(self._maxtabwidths) else: dc.SetFont(self.GetPageTextFont(tabIndex)) result, _ = dc.GetTextExtent(self.GetPageText(tabIndex)) return result def _CalcXRect(self, tabrect): result = None drawx, dxstyle = self.GetDrawX() if drawx: if dxstyle == 1: mins = min(self._padding.x, self._padding.y) + 1 mins = min(mins, 6) xoffset = tabrect.width-mins-3 yoffset = 2 xsize = ysize = mins+1 else: if self._style & NC_ROTATE: xoffset = (tabrect.width-self._maxtextheight-self._padding.y/2)/2 yoffset = self._padding.x/2 else: xoffset = tabrect.width-self._maxtextheight-self._padding.x yoffset = (tabrect.height-self._maxtextheight-self._padding.y/2)/2 xsize = ysize = self._maxtextheight result = wx.Rect(tabrect.x+xoffset, tabrect.y+yoffset, xsize, ysize) return result def _CalcXWidth(self): drawx, dxstyle = self.GetDrawX() if drawx: if dxstyle == 1: xxspace = self._padding.x/2 else: xxspace = self._padding.x + self._maxtextheight else: xxspace = 0 return xxspace def _ClipAtPaperEdge(self, dc, tabrect, tabIndex): selected = tabIndex == self.GetSelection() if self._style & NC_TOP: cliprect = (tabrect.x, tabrect.y, tabrect.width, selected and tabrect.height - 2 or tabrect.height-3) elif self._style & NC_LEFT: cliprect = (tabrect.x, tabrect.y, tabrect.width - 2, tabrect.height) elif self._style & NC_BOTTOM: cliprect = (tabrect.x, tabrect.y + 2, tabrect.width, tabrect.height - 2) else: cliprect = (tabrect.x + 2, tabrect.y, tabrect.width - 2, tabrect.height) dc.SetClippingRegion(*cliprect) def _CreateSizeToggleButton(self): buttonlabel = self._expanded and "<<" or ">>" self._sizeToggleButton = wx.Button(self, wx.NewId(), pos = wx.Point(0,0,), label = buttonlabel, style=wx.BU_EXACTFIT) font = self._sizeToggleButton.GetFont() if font.GetPointSize() > 6: font.SetPointSize(6) self._sizeToggleButton.SetFont(font) self.Bind(wx.EVT_BUTTON, self._ToggleSize, self._sizeToggleButton) def _DrawBackground(self, dc, paintTools): #background size = self.GetSize() dc.SetBrush(paintTools.BackBrush) if not (self._style & wx.NO_BORDER): # full border dc.SetPen(paintTools.BorderPen) dc.SetPen(paintTools.HighlightPen) dc.DrawRectangle(0, 0, size.x, size.y) else: dc.SetPen(paintTools.BackPen) dc.DrawRectangle(0, 0, size.x, size.y) self._DrawPageEdge(dc, paintTools) def _DrawFocusIndicator(self, dc, paintTools, tabrect): if self.GetUseFocusIndicator(): dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(paintTools.FocusPen) dc.DrawRoundedRectangle(tabrect.x+self._padding.x/2, tabrect.y+self._padding.y/2, tabrect.width-self._padding.x, tabrect.height-self._padding.y-2, 2) def _DrawPageEdge(self, dc, paintTools): if self._style & NC_TOP: dc.SetPen(paintTools.HighlightPen) dc.DrawLine(0, self.GetSize().y-1, self.GetSize().x, self.GetSize().y-1) else: if not self._tabstyle._normal or self._usegradients: dc.SetPen(paintTools.HighlightPen) else: dc.SetPen(paintTools.BorderPen) if self._style & NC_BOTTOM: dc.DrawLine(0, 1, self.GetSize().x, 1) elif self._style & NC_LEFT: dc.DrawLine(self.GetSize().width - 1, 0, self.GetSize().width - 1, self.GetSize().height) elif self._style & NC_RIGHT: dc.DrawLine(0, 0, 0, self.GetSize().height) def _DrawTab(self, dc, paintTools, tabrect, tabIndex): size = self.GetSize() self._DrawTabGradientOutline(dc, paintTools, tabrect, tabIndex) self._FillTab(dc, paintTools, tabrect, tabIndex) self._DrawTabOutline(dc, paintTools, tabrect, tabIndex) self._DrawTabPageEdge(dc, paintTools, tabrect, tabIndex) self._HighlightTabEdge(dc, paintTools, tabrect) self._ShadowTabEdge(dc, paintTools, tabrect) def _DrawTabBitmap(self, dc, tabIndex, bmpposx, bmpposy): bmpindex = self.GetPageImage(tabIndex) if self.IsPageEnabled(tabIndex): self._imglist.Draw(bmpindex, dc, bmpposx, bmpposy, wx.IMAGELIST_DRAW_TRANSPARENT, True) else: self._grayedlist.Draw(bmpindex, dc, bmpposx, bmpposy, wx.IMAGELIST_DRAW_TRANSPARENT, True) def _DrawTabGradientOutline(self, dc, paintTools, tabrect, tabIndex): if not self._tabstyle._normal or self._usegradients: if tabIndex != self.GetSelection() and self._style & NC_TOP: dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(paintTools.ShadowPen) dc.DrawRoundedRectangle(tabrect.x+1, tabrect.y+1, tabrect.width, tabrect.height-1, 3) def _DrawTabOutline(self, dc, paintTools, tabrect, tabIndex): if not self._tabstyle._normal or self._usegradients: dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(paintTools.HighlightPen) else: dc.SetBrush(wx.Brush(self.GetPageColour(tabIndex))) if self._style & NC_TOP: dc.SetPen(paintTools.HighlightPen) else: dc.SetPen(paintTools.BorderPen) self._ClipAtPaperEdge(dc, tabrect, tabIndex) dc.DrawRoundedRectangle(tabrect.x, tabrect.y, tabrect.width, tabrect.height, 3) dc.DestroyClippingRegion() def _DrawTabPageEdge(self, dc, paintTools, tabrect, tabIndex): if not self._tabstyle._normal or self._usegradients: edgePen = paintTools.HighlightPen else: if self._style & NC_TOP: edgePen = paintTools.HighlightPen else: edgePen = paintTools.BorderPen if tabIndex == self.GetSelection(): # un-paint the line at the paper edge cancelPen = wx.Pen(self.GetPageColour(tabIndex)) dc.SetPen(cancelPen) if self._style & NC_BOTTOM: dc.DrawLine(tabrect.x+1, tabrect.y, tabrect.x + tabrect.width, tabrect.y) elif self._style & NC_LEFT: dc.DrawLine(tabrect.x + tabrect.width-1, tabrect.y, tabrect.x + tabrect.width-1, tabrect.y + tabrect.height) elif self._style & NC_RIGHT: dc.DrawLine(tabrect.x, tabrect.y, tabrect.x, tabrect.y + tabrect.height) if tabIndex != self.GetSelection(): if self._style & NC_TOP: dc.DrawLine(tabrect.x, self.GetSize().y-1, tabrect.x + tabrect.width, self.GetSize().y-1) # draw sharp corners at the paper edge dc.SetPen(edgePen) if self._style & NC_BOTTOM: dc.DrawLine(tabrect.x, tabrect.y, tabrect.x, tabrect.y + 2) dc.DrawLine((tabrect.x + tabrect.width)-1, tabrect.y, (tabrect.x + tabrect.width)-1, tabrect.y + 2) elif self._style & NC_LEFT: dc.DrawLine(self.GetSize().width - 2, tabrect.y, self.GetSize().width, tabrect.y) dc.DrawLine(self.GetSize().width - 2, tabrect.y + tabrect.height - 1, self.GetSize().width, tabrect.y + tabrect.height - 1) elif self._style & NC_RIGHT: dc.DrawLine(tabrect.x, tabrect.y, tabrect.x + 2, tabrect.y) dc.DrawLine(tabrect.x, tabrect.y + tabrect.height - 1, tabrect.x + 2, tabrect.y + tabrect.height - 1) def _DrawTabText(self, dc, tabIndex, xtextpos, ytextpos): dc.SetFont(self.GetPageTextFont(tabIndex)) dc.SetTextForeground(self._GetTabTextColour(tabIndex)) dc.SetBrush(wx.TRANSPARENT_BRUSH) if self._style & NC_ROTATE: angle = (self._style & NC_LEFT) and 90.0 or 270.0 dc.DrawRotatedText(self.GetPageText(tabIndex), xtextpos, ytextpos, angle) else: dc.DrawText(self.GetPageText(tabIndex), xtextpos, ytextpos) def _DrawX(self, dc, tabrect, xrect, textColour): drawx, dxstyle = self.GetDrawX() if drawx: if dxstyle == 1: mins = min(self._padding.x, self._padding.y) + 1 mins = min(mins, 6) dc.SetPen(wx.Pen(textColour, 1)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawLine(xrect.x, xrect.y, tabrect.x+tabrect.width-2, tabrect.y+3+mins) dc.DrawLine(xrect.x, xrect.y+mins, tabrect.x+tabrect.width-2, tabrect.y+1) dc.DrawRectangle(xrect.x, xrect.y, xrect.width, xrect.height) elif dxstyle == 2: dc.SetPen(wx.Pen(textColour)) dc.SetBrush(wx.Brush(textColour)) dc.DrawRoundedRectangle(xrect.x, xrect.y, xrect.width, xrect.height, 2) dc.SetPen(wx.Pen(self.GetBackgroundColour(), 2)) dc.DrawLine(xrect.x+2, xrect.y+2, xrect.x+xrect.width-3, xrect.y+xrect.height-3) dc.DrawLine(xrect.x+2, xrect.y+xrect.height-3, xrect.x+xrect.width-3, xrect.y+2) else: self._imglist2.Draw(0, dc, xrect.x, xrect.y, wx.IMAGELIST_DRAW_TRANSPARENT, True) def _EnhanceMultiSelectedTab(self, dc, tabIndex, tabrect): dc.SetPen(wx.Pen(self._GetTabTextColour(tabIndex), 1, wx.DOT_DASH)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.DrawRoundedRectangle(tabrect.x+self._padding.x/2+1, tabrect.y+self._padding.y/2+1, tabrect.width-self._padding.x-2, tabrect.height-self._padding.y-2-2, 2) def _EnhanceSelectedTab(self, dc, paintTools, tabrect): xselpos = tabrect.x xselsize = tabrect.width yselsize = tabrect.height if self._style & NC_BOTTOM: yselpos = (tabrect.y + tabrect.height) - 2 elif self._style & NC_TOP: yselpos = tabrect.y self._HighlightSelectedTabEdge(dc, paintTools, tabrect) self._ShadowTabEdge(dc, paintTools, tabrect) self._DrawFocusIndicator(dc, paintTools, tabrect) def _FillTab(self, dc, paintTools, tabrect, tabIndex): if self._usegradients: self.DrawGradientOnTab(dc, tabrect, self._pages[tabIndex]._firstcolour, self._pages[tabIndex]._secondcolour) elif not self._tabstyle._normal: self.DrawBuiltinStyle(dc, self._tabstyle, tabrect, tabIndex, self.GetSelection()) def _GetPaintTools(self): back_colour = self.GetBackgroundColour() back_brush = wx.Brush(back_colour) back_pen = wx.Pen(back_colour) border_pen = self._borderpen highlightpen = self._highlightpen if self._tabstyle._normal and not self._usegradients: highlightpen = self._highlightpen2 shadowpen = self._shadowpen upperhighpen = self._upperhigh if self.GetHighlightSelection(): selectionpen = wx.Pen(self._selectioncolour) selectionEdgePen = wx.Pen(self._selectionedgecolour) else: selectionpen = selectionEdgePen = None x_pen = self.GetDrawX() == 1 and wx.BLACK_PEN or None focusindpen = self.GetUseFocusIndicator() and self._focusindpen or None return _TabCtrlPaintTools(back_brush, back_pen, border_pen, highlightpen, shadowpen, upperhighpen, selectionpen, selectionEdgePen, x_pen, focusindpen) def _GetTabBitmap(self, tabIndex): bmp = wx.NullBitmap if self.GetPageImage(tabIndex) >= 0: bmpindex = self.GetPageImage(tabIndex) if self.IsPageEnabled(tabIndex): bmp = self._imglist.GetBitmap(bmpindex) else: bmp = self._grayedlist.GetBitmap(bmpindex) return bmp def _GetTabTextColour(self, tabIndex): if self.IsPageEnabled(tabIndex): result = self.GetPageTextColour(tabIndex) else: result = self._disabledcolour return result def _GetThemePageColour(self, index): if self._tabstyle._macstyle: return NC_MAC_LIGHT elif self._tabstyle._kdetheme: return kdetheme[0] elif self._tabstyle._aqua: if index == self.GetSelection(): return topaqua1[0] else: return distaqua[0] elif self._tabstyle._metal: intens = (230 + 80 * (self._tabrect[0].y-self._tabrect[0].y+1)/self._tabrect[0].height) return wx.Colour(intens, intens, intens) elif self._tabstyle._silver: if index == self.GetSelection(): return silvertheme1[0] else: return silvertheme2[0] elif self._tabstyle._gradient: color = wx.WHITE if self._tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL: if self._style & NC_TOP: color = self._tabstyle.GetSecondGradientColour(index) elif self._style & NC_BOTTOM: color = self._tabstyle.GetFirstGradientColour(index) elif self._tabstyle._gradient & ThemeStyle.GRADIENT_HORIZONTAL and \ self._style & NC_ROTATE: if self._style & NC_LEFT: color = self._tabstyle.GetSecondGradientColour(index) else: color = self._tabstyle.GetFirstGradientColour(index) return color def _HighlightSelectedTabEdge(self, dc, paintTools, tabrect): if self._style & NC_ROTATE: yselpos = tabrect.y + 3 yselsize = tabrect.height - 6 xselpos = self._style & NC_RIGHT and tabrect.x + tabrect.width - 1 or tabrect.x if self.GetHighlightSelection(): dc.SetBrush(paintTools.BackBrush) dc.SetPen(paintTools.SelectionEdgePen) dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) dc.SetPen(paintTools.SelectionPen) for band in range(2): if self._style & NC_RIGHT: xselpos -= 1 else: xselpos += 1 yselpos -= 1 yselsize += 2 dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) else: dc.SetPen(paintTools.HighlightPen) dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) else: xselpos = tabrect.x + 3 xselsize = tabrect.width - 6 if self._style & NC_BOTTOM: yselpos = tabrect.y + tabrect.height - 1 else: yselpos = tabrect.y dc.SetPen(paintTools.HighlightPen) dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) if self.GetHighlightSelection(): dc.SetBrush(paintTools.BackBrush) dc.SetPen(paintTools.SelectionEdgePen) dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) dc.SetPen(paintTools.SelectionPen) for band in range(2): if self._style & NC_BOTTOM: yselpos -= 1 else: yselpos += 1 xselpos -= 1 xselsize += 2 dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) def _HighlightTabEdge(self, dc, paintTools, tabrect): if not self._tabstyle._normal or self._usegradients: if self._style & NC_TOP: dc.SetPen(paintTools.UpperHighlightPen) dc.DrawLine(tabrect.x+2, tabrect.y-1, tabrect.x + tabrect.width - 2, tabrect.y-1) else: if self._style & NC_TOP: dc.SetPen(paintTools.HighlightPen) dc.DrawLine(tabrect.x + 3, tabrect.y, tabrect.x + tabrect.width - 3, tabrect.y) def _InitExpandableStyles(self, style): self._expanded = not style & NC_ROTATE if self._expanded: self._expandedstyle = style self._contractedstyle = style | NC_ROTATE else: self._contractedstyle = style self._expandedstyle = (style ^ NC_ROTATE) | NC_FIXED_WIDTH def _InitExpandableTabStyles(self, style, expanded, tabstyle): if tabstyle._gradient: alternatestyle = ThemeStyle() firstcolor = tabstyle.GetFirstGradientColour() secondcolor = tabstyle.GetSecondGradientColour() swapcolors = (tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL and style & NC_RIGHT and expanded) or \ (tabstyle._gradient & ThemeStyle.GRADIENT_HORIZONTAL and style & NC_RIGHT and not expanded) if swapcolors: firstcolor, secondcolor = (secondcolor, firstcolor) if tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL: othergradient = (tabstyle._gradient ^ ThemeStyle.GRADIENT_VERTICAL) | ThemeStyle.GRADIENT_HORIZONTAL else: othergradient = (tabstyle._gradient ^ ThemeStyle.GRADIENT_HORIZONTAL) | ThemeStyle.GRADIENT_VERTICAL alternatestyle.EnableGradientStyle(True, othergradient) alternatestyle.SetFirstGradientColour(firstcolor) alternatestyle.SetSecondGradientColour(secondcolor) if tabstyle._gradient & ThemeStyle.DIFFERENT_GRADIENT_FOR_SELECTED: firstcolor = tabstyle.GetFirstGradientColour(True) secondcolor = tabstyle.GetSecondGradientColour(True) if swapcolors: firstcolor, secondcolor = (secondcolor, firstcolor) alternatestyle.SetFirstGradientColourSelected(firstcolor) alternatestyle.SetSecondGradientColourSelected(secondcolor) if expanded: self._expandedtabstyle = tabstyle self._contractedtabstyle = alternatestyle else: self._contractedtabstyle = tabstyle self._expandedtabstyle = alternatestyle else: self._expandedtabstyle = tabstyle self._contractedtabstyle = tabstyle def _OnStyleChange(self): if self._style & NC_TOP or self._style & NC_BOTTOM: self.SetBestSize((-1, newheight)) else: self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) self._parent.GetSizer().Layout() self._somethingchanged = True self._firsttime = True self.Refresh() def _ShadowTabEdge(self, dc, paintTools, tabrect): dc.SetPen(paintTools.ShadowPen) if self._style & NC_BOTTOM: dc.DrawLine((tabrect.x + tabrect.width), tabrect.y+1, (tabrect.x+tabrect.width), tabrect.y + tabrect.height-4) elif self._style & NC_TOP: dc.DrawLine(tabrect.x + tabrect.width, tabrect.y+3, tabrect.x+tabrect.width, tabrect.y+tabrect.height-4) def OnPaint(self, event): """ Handles The wx.EVT_PAINT Event For TabCtrl. """ dc = wx.BufferedPaintDC(self) if self.GetPageCount() == 0: event.Skip() return pt = self._GetPaintTools() dc.BeginDrawing() self._DrawBackground(dc, pt) self._CalcMaxTextHeight(dc) posx = self._firsttabpos.x posy = self._firsttabpos.y if self._style & NC_LEFT: _ = 1 if self._firsttime: if not hasattr(self, "_initrect"): self._initrect = [] if self.HasSpinButton() and self._fromdnd: self._firstvisible = self._spinbutton.GetValue() self._firsttime = False self._fromdnd = False else: self._initrect = [] self._firstvisible = 0 else: if self.HasSpinButton(): self._firstvisible = self._spinbutton.GetValue() else: self._firstvisible = 0 lastvisible = self.GetPageCount() #and tabs oncount = -1 self._tabvisible = [1]*self.GetPageCount() tabrect = [] # some theme style rendering routines expect this to exist, so # set it now: self._tabrect = tabrect Xrect = [] for ii in xrange(self._firstvisible, lastvisible): if not self._enablehiding or not self._pages[ii]._ishidden: oncount = oncount + 1 self._tabvisible[ii] = 1 newwidth = self._CalcTabTextWidth(dc, ii) bmpWidth, bmpHeight = self._CalcTabBitmapSize(ii) tabrect.append(self._CalcTabRect(ii, posx, posy, newwidth, bmpWidth, bmpHeight)) self._DrawTab(dc, pt, tabrect[-1], ii) self._DrawTabText(dc, ii, *self._CalcTabTextPosition(ii, tabrect[-1], self._CalcTabBitmapSpace(bmpWidth, bmpHeight))) if bmpWidth: self._DrawTabBitmap(dc, ii, *self._CalcTabBitmapPosition(ii, bmpWidth, bmpHeight, tabrect[-1])) if self.GetSelection() in [ii, ii - 1]: # Handle this special case on the selected tab and # on the tab that follows it (if there is one), to ensure # proper rendering of the selected tab's right edge self._EnhanceSelectedTab(dc, pt, tabrect[self.GetSelection() - self._firstvisible]) if self.GetDrawX()[0]: Xrect.append(self._CalcXRect(tabrect[-1])) self._DrawX(dc, tabrect[-1], Xrect[-1], self._GetTabTextColour(ii)) if ii in self._selectedtabs: self._EnhanceMultiSelectedTab(dc, ii, tabrect[-1]) if self._style & NC_TOP or self._style & NC_BOTTOM: # horizontally positioned tabs along top or bottom posx = posx + tabrect[-1].width else: # vertically stacked tabs along side posy = posy + tabrect[-1].height if self._firsttime: self._initrect.append(tabrect[oncount]) else: self._tabvisible[ii] = 0 self._xrect = Xrect if self._firsttime: self._firsttime = False self.UpdateMenuButton(self.HasMenuButton()) self.UpdateSpinButton() if self._enabledragging: if self._isdragging and not self._isleaving: self.DrawInsertionMark(dc, self._olddragpos) dc.EndDrawing() # ---------------------------------------------------------------------------- # # Class NotebookCtrl # This Is The Main Class Implementation # ---------------------------------------------------------------------------- # class NotebookCtrl(wx.Panel): """ Display one or more windows in a notebook. B{Events}: - B{EVT_NOTEBOOKCTRL_PAGE_CHANGING}: sent when the active page in the notebook is changing - B{EVT_NOTEBOOKCTRL_PAGE_CHANGED}: sent when the active page in the notebook has changed - B{EVT_NOTEBOOKCTRL_PAGE_CLOSING}: sent when a page in the notebook is closing - B{EVT_NOTEBOOKCTRL_PAGE_DND}: sent when a page has been dropped onto the notebook in a drag-drop operation - B{EVT_NOTEBOOKCTRL_PAGE_DCLICK}: sent when the user double-clicks a tab in the notebook - B{EVT_NOTEBOOKCTRL_PAGE_RIGHT}: sent when the user clicks a tab in the notebook with the right mouse button - B{EVT_NOTEBOOKCTRL_PAGE_MIDDLE}: sent when the user clicks a tab in the notebook with the middle mouse button """ def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=NC_DEFAULT_STYLE, sizer=wx.HORIZONTAL, margin=2, name="NotebookCtrl"): """ Default Class Constructor. @param style: Style For The NotebookCtrl, Which May Be: a) NC_TOP: NotebookCtrl Placed On Top (Default); b) NC_BOTTOM: NotebookCtrl Placed At The Bottom; c) NC_LEFT: NotebookCtrl Placed At The Left; d) NC_RIGHT: NotebookCtrl Placed At The Right; e) NC_FIXED_WIDTH: All Tabs Have The Same Width; f) wx.NO_BORDER: Shows No Border For The Control (Default, Looks Better); g) wx.STATIC_BORDER: Shows A Static Border On The Control. @param sizer: The Sizer Orientation For The Sizer That Holds All The Panels: Changing This Style Is Only Useful When You Use The Tile Method. In This Case, If sizer=wx.HORIZONTAL, All The Panels Will Be Shown In Columns, While If sizer=wx.VERTICAL All The Panels Will Be Shown In Rows. @param margin: An Integer Number Of Pixels That Add Space Above TabCtrl If style=NC_TOP, Or Below It If style=NC_BOTTOM """ wx.Panel.__init__(self, parent, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE | wx.CLIP_CHILDREN, name=name) self.nb = TabCtrl(self, -1, pos, size, style) self._notebookpages = [] if style & NC_TOP == 0 and style & NC_BOTTOM == 0 \ and style & NC_LEFT == 0 and style & NC_RIGHT == 0: style = style | NC_TOP if style & wx.NO_BORDER == 0 and \ style & wx.STATIC_BORDER == 0: style = style | wx.NO_BORDER self._style = style self._showcolumns = False self._showtabs = True self._sizerstyle = sizer self._custompanel = None self._focusswitch = False self._oldfocus = None if style & NC_TOP or style & NC_BOTTOM: self.sizer = wx.BoxSizer(wx.VERTICAL) self.tabsizer = wx.BoxSizer(wx.VERTICAL) else: self.sizer = wx.BoxSizer(wx.HORIZONTAL) self.tabsizer = wx.BoxSizer(wx.HORIZONTAL) self.bsizer = wx.BoxSizer(sizer) if style & NC_TOP or style & NC_BOTTOM: tabBorderFlag = wx.LEFT | wx.RIGHT else: tabBorderFlag = wx.TOP | wx.BOTTOM if style & NC_TOP or style & NC_LEFT: self.sizer.Add(self.tabsizer, 0, wx.EXPAND | tabBorderFlag, 2) self._AddMargin(style, margin) self.tabsizer.Add(self.nb, 0, wx.EXPAND) self.sizer.Add(self.bsizer, 1, wx.EXPAND) elif style & NC_BOTTOM or style & NC_RIGHT: self.sizer.Add(self.bsizer, 1, wx.EXPAND) self.sizer.Add(self.tabsizer, 0, wx.EXPAND | tabBorderFlag, 2) self.tabsizer.Add(self.nb, 0, wx.EXPAND) self._AddMargin(style, margin) self.SetSizer(self.sizer) self.tabsizer.Show(self.nb, False) self.sizer.Layout() self.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) def OnKeyDown(self, event): """ Handles The wx.EVT_KEY_DOWN Event For NotebookCtrl. This Is Only Processed If The User Navigate Through Tabs With Ctrl-Tab Keyboard Navigation. """ if event.GetKeyCode == wx.WXK_TAB: if event.ControlDown(): sel = self.GetSelection() if sel == self.GetPageCount() - 1: sel = 0 else: sel = sel + 1 while not self.IsPageEnabled(sel): sel = sel + 1 if sel == self.GetPageCount() - 1: sel = 0 self.SetSelection(sel) event.Skip() def OnMouseMotion(self, event): """ Handles The wx.EVT_MOTION Event For NotebookCtrl. """ if self.nb._enabledragging: if event.Dragging() and not event.RightIsDown() and not event.MiddleIsDown(): tolerance = 2 pt = event.GetPosition() dx = abs(pt.x - self.nb._dragstartpos.x) dy = abs(pt.y - self.nb._dragstartpos.y) if dx <= tolerance and dy <= tolerance: self.SetCursor(wx.STANDARD_CURSOR) return self.SetCursor(self.nb._dragcursor) self.nb._isdragging = True else: self.nb._isdragging = False self.SetCursor(wx.STANDARD_CURSOR) if self.nb._showtooltip: if self.nb._istooltipshown: pt = event.GetPosition() self.nb._insidetab = self.nb.GetInsideTab(pt) if self.nb._insidetab < 0: try: self.nb._tipwindow.Destroy() self.nb._istooltipshown = False except: self.nb._istooltipshown = False self.nb.Refresh() event.Skip() def EnableChildFocus(self, enable=True): """ Enables/Disables Sending EVT_NOTEBOOKCTRL_PAGE_CHANGING When In Tile Mode. """ self._focusswitch = enable def FindFocusedPage(self, obj): """ Find Which NotebookCtrl Page Has The Focus Based On Its Child Focus. """ while 1: if obj in self._notebookpages: return obj try: obj = obj.GetParent() except: return None return None def OnFocus(self, event): """ Handles The wx.EVT_CHILD_FOCUS Event For NotebookCtrl. """ if not self._focusswitch: event.Skip() return newfocus = self.FindFocusedPage(event.GetEventObject()) if newfocus == self._oldfocus or newfocus is None: event.Skip() return self._oldfocus = newfocus eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, self.GetId()) nPage = self._notebookpages.index(newfocus) eventOut.SetSelection(nPage) eventOut.SetOldSelection(self.GetSelection()) eventOut.SetEventObject(self) if not self.GetEventHandler().ProcessEvent(eventOut): # Program Allows The Page Change self.nb._selection = nPage eventOut.SetEventType(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED) eventOut.SetOldSelection(self.nb._selection) self.GetEventHandler().ProcessEvent(eventOut) event.Skip() def AddPage(self, page, text, select=False, img=-1, hidden=False): """ Add A Page To The Notebook. @param page: Specifies The New Page; @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. """ self.Freeze() oldselection = self.nb.GetSelection() if self.GetPageCount() == 0: if self.GetCustomPage() is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) self.bsizer.Layout() self.bsizer.Add(page, 1, wx.EXPAND | wx.ALL, 2) self.nb.AddPage(text, select, img, hidden) self._notebookpages.append(page) page.Bind(wx.EVT_CHILD_FOCUS, self.OnFocus) if select: if oldselection >= 0: self.bsizer.Show(self.GetPage(oldselection), False) self.nb.SetSelection(self.GetPageCount()-1) self.bsizer.Layout() else: if oldselection >= 0: self.bsizer.Show(page, False) else: self.bsizer.Show(page, True) self.nb.SetSelection(self.GetPageCount()-1) self.bsizer.Layout() if self.GetPageCount() == 1: self.bsizer.Show(page, True) if self.nb._hideonsingletab: self._ShowTabCtrl(False) else: self.nb.Show(True) self._ShowTabCtrl(True) else: self.nb.Show(True) self._ShowTabCtrl(True) self.bsizer.Layout() self.sizer.Layout() self.Thaw() self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def InsertPage(self, nPage, page, text, select=False, img=-1, hidden=False): """ Insert A Page Into The Notebook. @param page: Specifies The New Page; @param nPage: Specifies The Position For The New Page; @param text: The Tab Text; @param select: Whether The Page Should Be Selected Or Not; @param img: Specifies The Optional Image Index For The New Page. @param hidden: C{True} to hide the page; C{False} to display it """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In InsertPage: (" + str(nPage) + ")" self.Freeze() oldselection = self.nb.GetSelection() if self.GetPageCount() == 0: if self.GetCustomPage() is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) if oldselection >= 0: self.bsizer.Show(oldselection, False) self.bsizer.Layout() if oldselection >= nPage: oldselection = oldselection + 1 self.nb.InsertPage(nPage, text, select, img, hidden) self.bsizer.Insert(nPage, page, 1, wx.EXPAND | wx.ALL, 2) self._notebookpages.insert(nPage, page) self.bsizer.Layout() page.Bind(wx.EVT_CHILD_FOCUS, self.OnFocus) for ii in xrange(self.GetPageCount()): self.bsizer.Show(ii, False) self.bsizer.Layout() if select: self.bsizer.Show(nPage, True) self.bsizer.Layout() else: if oldselection >= 0: self.bsizer.Show(oldselection, True) self.bsizer.Layout() else: self.bsizer.Show(nPage, True) self.bsizer.Layout() if self.GetPageCount() == 1: if self.nb._hideonsingletab: self._ShowTabCtrl(False) else: self.nb.Show(True) self._ShowTabCtrl(True) else: self.nb.Show(True) self._ShowTabCtrl(True) self.sizer.Layout() self.Thaw() self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def GetPage(self, nPage): """ Returns The Window At The Given Position nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPage: (" + str(nPage) + ")" return self._notebookpages[nPage] def DeleteAllPages(self): """ Deletes All NotebookCtrl Pages. """ self.Freeze() counter = self.GetPageCount() - 1 for ii in xrange(self.GetPageCount()): self.bsizer.Detach(counter-ii) panels = self.GetPage(counter-ii) panels.Destroy() self.nb.DeleteAllPages() self._notebookpages = [] self.nb._selection = -1 self.nb.Show(False) custom = self.GetCustomPage() if custom is not None: self.SetCustomPage(custom) custom.Show(True) self.bsizer.Layout() self._ShowTabCtrl(False) self.sizer.Layout() self.Thaw() def DeletePage(self, nPage): """ Deletes The Page nPage, And The Associated Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In DeletePage: (" + str(nPage) + ")" oldselection = self.GetSelection() self.Freeze() panel = self.GetPage(nPage) self.bsizer.Detach(nPage) self.bsizer.Layout() self._notebookpages.pop(nPage) self.nb.DeletePage(nPage) panel.Destroy() if self.GetPageCount() > 0: if oldselection == nPage: if self.GetSelection() > 0: self.SetSelection(self.GetSelection()-1) else: self.SetSelection(self.GetSelection()) self.bsizer.Show(self.GetSelection()) self.bsizer.Layout() if self.GetPageCount() == 0: self.nb.Show(False) self._ShowTabCtrl(False) custom = self.GetCustomPage() if custom is not None: self.bsizer.Add(custom, 1, wx.EXPAND | wx.ALL, 2) custom.Show(True) self.bsizer.Layout() self.sizer.Layout() self.Thaw() return if self.GetPageCount() == 1: if self.nb._hideonsingletab: self._ShowTabCtrl(False) else: self.nb.Show(True) self._ShowTabCtrl(True) else: self.nb.Show(True) self._ShowTabCtrl(True) self.sizer.Layout() self.Thaw() self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def SetSelection(self, nPage): """ Sets The Current Tab Selection To The Given nPage. This Call Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetSelection: (" + str(nPage) + ")" oldselection = self.GetSelection() if oldselection == nPage: return self.nb.SetSelection(nPage) self.Tile(self._showcolumns) self.ShowTabs(self._showtabs) def GetPageCount(self): """ Returns The Number Of Pages In NotebookCtrl. """ return self.nb.GetPageCount() def GetSelection(self): """ Returns The Current Selection. """ return self.nb.GetSelection() def GetImageList(self): """ Returns The Image List Associated With The NotebookCtrl. """ return self.nb.GetImageList() def SetImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self.nb.SetImageList(imagelist) def AssignImageList(self, imagelist): """ Associate An Image List To NotebookCtrl. """ self.nb.AssignImageList(imagelist) def GetPadding(self): """ Returns The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ return self.nb.GetPadding() def SetPadding(self, padding): """ Sets The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ self.nb.SetPadding(padding) def SetUseFocusIndicator(self, focus=True): """ Globally Enables/Disables Tab Focus Indicator. """ self.nb.SetUseFocusIndicator(focus) def GetUseFocusIndicator(self): """ Returns Globally Enable/Disable State For Tab Focus Indicator. """ return self.nb.GetUseFocusIndicator() def EnablePage(self, nPage, enable=True): """ Enable/Disable The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In EnablePage: (" + str(nPage) + ")" self.nb.EnablePage(nPage, enable) def IsPageEnabled(self, nPage): """ Returns Whether A Page Is Enabled Or Not. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In IsPageEnabled: (" + str(nPage) + ")" return self.nb.IsPageEnabled(nPage) def SetHighlightSelection(self, highlight=True): """ Globally Enables/Disables Tab Highlighting On Tab Selection. """ self.nb.SetHighlightSelection(highlight) def GetHighlightSelection(self): """ Returns Globally Enable/Disable State For Tab Highlighting On Tab Selection. """ return self.nb.GetHighlightSelection() def SetAnimationImages(self, nPage, imgarray): """ Sets An Animation List Associated To The Given Page nPage. @param nPage: The Given Page; @param imgarray: A List Of Image Indexes Of Images Inside The ImageList Associated To NotebookCtrl. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetAnimationImages: (" + str(nPage) + ")" if not imgarray: raise "\nERROR: Invalid Image Array In SetAnimationImages: (" + repr(imgarray) + ")" if min(imgarray) < 0: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Min(ImgArray) = " + \ str(min(imgarray)) + " < 0)" if max(imgarray) > self.GetImageList().GetImageCount() - 1: raise "\nERROR: Invalid Image Array In SetAnimationImages: (Max(ImgArray) = " + \ str(max(imgarray)) + " > " + str(self.GetImageList().GetImageCount()-1) + ")" self.nb.SetAnimationImages(nPage, imgarray) def GetAnimationImages(self, nPage): """ Returns The Animation Images List Associated To The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetAnimationImages: (" + str(nPage) + ")" return self.nb.GetAnimationImages(nPage) def StartAnimation(self, nPage, timer=500): """ Starts The Animation On The Given Page nPage, With Refreshing Time Rate "timer". """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StartAnimation: (" + str(nPage) + ")" self.nb.StartAnimation(nPage, timer) def StopAnimation(self, nPage): """ Stops The Animation On The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In StopAnimation: (" + str(nPage) + ")" self.nb.StopAnimation(nPage) def EnableDragAndDrop(self, enable=True): """ Globall Enables/Disables Tabs Drag And Drop. """ self.nb.EnableDragAndDrop(enable) def EnableHiding(self, enable=True): """ Globally Enables/Disables Hiding On Tabs In Runtime. """ self.nb.EnableHiding(enable) def SetDrawX(self, drawx=True, style=1, image1=None, image2=None): """ Globally Enables/Disables The Drawing Of A Closing "X" In The Tab. @param drawx: C{True} to enable drawing a closing "X"; C{False} to disable it @param style: the style of the X to draw when C{drawx} is C{True}; possible values are: - C{1}: Small "X" At The Top-Right Of The Tab; - C{2}: Bigger "X" In The Middle Vertical Of The Tab (Like Opera Notebook); - C{3}: Custom "X" Image Is Drawn On Tabs. @param image1: if C{style} is C{3}, the image to use when drawing the X on an unhighlighted tab @param image2: if C{style} is C{3}, the image to use when drawing the X on a highlighted tab """ self.nb.SetDrawX(drawx, style, image1, image2) def GetDrawX(self): """ Returns The Enable/Disable State Of Drawing Of A Small "X" At The Top-Right Of Every Page. """ return self.nb.GetDrawX() def SetImageToCloseButton(self, convert=True): """ Set Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ self.nb.SetImageToCloseButton(convert) def GetImageToCloseButton(self): """ Get Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ return self.nb._convertimage def HideOnSingleTab(self, hide=True): """ Hides The TabCtrl When There Is Only One Tab In NotebookCtrl. """ self.nb.HideOnSingleTab(hide) if self.GetPageCount() == 1: if hide: self._ShowTabCtrl(False) else: self._ShowTabCtrl(True) self.sizer.Layout() def SetPagePopupMenu(self, nPage, menu): """ Sets A Popup Menu Specific To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPagePopupMenu: (" + str(nPage) + ")" self.nb.SetPagePopupMenu(nPage, menu) def GetPagePopupMenu(self, nPage): """ Returns The Popup Menu Associated To A Single Tab. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPagePopupMenu: (" + str(nPage) + ")" return self.nb.GetPagePopupMenu(nPage) def SetPageToolTip(self, nPage, tooltip="", timer=500, winsize=400): """ Sets A ToolTip For The Given Page nPage. @param nPage: The Given Page; @param tooltip: The ToolTip String; @param timer: The Timer After Which The Tip Window Is Popped Up; @param winsize: The Maximum Width Of The Tip Window. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageToolTip: (" + str(nPage) + ")" self.nb.SetPageToolTip(nPage, tooltip, timer, winsize) def GetPageToolTip(self, nPage): """ Returns A Tuple With All Page ToolTip Parameters. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageToolTip: (" + str(nPage) + ")" return self.nb.GetPageToolTip(nPage) def EnableToolTip(self, show=True): """ Globally Enables/Disables Tab ToolTips. """ self.nb.EnableToolTip(show) def GetToolTipBackgroundColour(self): """ Returns The ToolTip Window Background Colour. """ return self.nb.GetToolTipBackgroundColour() def SetToolTipBackgroundColour(self, colour=None): """ Sets The ToolTip Window Background Colour. """ if colour is None: colour = wx.Colour(255, 255, 230) self.nb.SetToolTipBackgroundColour(colour) def EnableTabGradients(self, enable=True): """ Globally Enables/Disables Drawing Of Gradient Coloured Tabs For Each Tab. """ self.nb.EnableTabGradients(enable) def SetPageFirstGradientColour(self, nPage, colour=None): """ Sets The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageFirstGradientColour: (" + str(nPage) + ")" if colour is None: colour = wx.WHITE self.nb.SetPageFirstGradientColour(nPage, colour) def SetPageSecondGradientColour(self, nPage, colour=None): """ Sets The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageSecondGradientColour: (" + str(nPage) + ")" self.nb.SetPageSecondGradientColour(nPage, colour) def GetPageFirstGradientColour(self, nPage): """ Returns The Single Tab First Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageFirstGradientColour: (" + str(nPage) + ")" return self.nb.GetPageFirstGradientColour(nPage) def GetPageSecondGradientColour(self, nPage): """ Returns The Single Tab Second Gradient Colour. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageSecondGradientColour: (" + str(nPage) + ")" return self.nb.GetPageSecondGradientColour(nPage) def CancelTip(self): """ Destroys The Tip Window (Probably You Won't Need This One. """ self.nb.CancelTip() def AdvanceSelection(self, forward=True): """ Cycles Through The Tabs. The Call To This Function Generates The EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. """ self.nb.AdvanceSelection(forward) def SetDefaultPage(self, defaultpage=-1): """ Sets The Default Page That Will Be Selected When An Active And Selected Tab Is Made Inactive. """ if defaultpage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetDefaultPage: (" + str(defaultpage) + ")" self.nb.SetDefaultPage(defaultpage) def GetDefaultPage(self): """ Returns The Default Page. """ return self.nb.GetDefaultPage() def GetPageText(self, nPage): """ Returns The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageText: (" + str(nPage) + ")" return self.nb.GetPageText(nPage) def SetPageText(self, nPage, text): """ Sets The String For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageText: (" + str(nPage) + ")" self.nb.SetPageText(nPage, text) def GetPageImage(self, nPage): """ Returns The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageImage: (" + str(nPage) + ")" return self.nb.GetPageImage(nPage) def SetPageImage(self, nPage, img): """ Sets The Image Index For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageImage: (" + str(nPage) + ")" self.nb.SetPageImage(nPage, img) def SetPageTextFont(self, nPage, font=None): """ Sets The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self.nb.SetPageTextFont(nPage, font) def GetPageTextFont(self, nPage): """ Returns The Primary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextFont: (" + str(nPage) + ")" return self.nb.GetPageTextFont(nPage) def SetPageTextSecondaryFont(self, nPage, font=None): """ Sets The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextSecondaryFont: (" + str(nPage) + ")" if font is None: font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) self.nb.SetPageTextSecondaryFont(nPage, font) def GetPageTextSecondaryFont(self, nPage): """ Returns The Secondary Font For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextSecondaryFont: (" + str(nPage) + ")" return self.nb.GetPageTextSecondaryFont(nPage) def SetPageTextColour(self, nPage, colour=None): """ Sets The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageTextColour: (" + str(nPage) + ")" if colour is None: colour = wx.BLACK self.nb.SetPageTextColour(nPage, colour) def GetPageTextColour(self, nPage): """ Returns The Text Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageTextColour: (" + str(nPage) + ")" return self.nb.GetPageTextColour(nPage) def SetPageColour(self, nPage, colour=None): """ Sets The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In SetPageColour: (" + str(nPage) + ")" if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) self.nb.SetPageColour(nPage, colour) def GetPageColour(self, nPage): """ Returns The Tab Background Colour For The Given Page nPage. """ if nPage < 0 or nPage >= self.GetPageCount(): raise "\nERROR: Invalid Notebook Page In GetPageColour: (" + str(nPage) + ")" return self.nb.GetPageColour(nPage) def SetTabHeight(self, height=28): """ Sets The Tabs Height. """ if height <= 0: raise "\nERROR: Impossible To Set An Height <= 0. " self.nb.SetTabHeight(height) def SetControlBackgroundColour(self, colour=None): """ Sets The TabCtrl Background Colour (Behind The Tabs). """ if colour is None: colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) self.nb.SetBackgroundColour(colour) def ApplyTabTheme(self, theme=None): """ Apply A Particular Theme To Be Drawn On Tabs. """ if theme is None: theme = ThemeStyle() self.nb.ApplyTabTheme(theme) def SetSelectionColour(self, colour=None): """ Sets The Tab Selection Colour (Thin Line Above The Selected Tab). """ if colour is None: colour = wx.Colour(255, 180, 0) self.nb.SetSelectionColour(colour) def SetContourLineColour(self, colour=None): """ Sets The Contour Line Colour (Controur Line Around Tabs). """ self.nb.SetContourLineColour(colour) def Tile(self, show=True, orient=None): """ Shows Pages In Column/Row Mode (One Panel After The Other In Columns/Rows). """ if self._GetTabCtrlWindow().IsShown() == show and orient is None: return self.Freeze() if orient is not None and show: if orient == wx.VERTICAL: norient = wx.HORIZONTAL else: norient = wx.VERTICAL if orient is not None and show: origorient = self.bsizer.GetOrientation() if origorient != norient: for ii in xrange(self.GetPageCount()-1, -1, -1): self.bsizer.Detach(ii) self.sizer.Detach(self.bsizer) self.bsizer.Destroy() self.bsizer = wx.BoxSizer(norient) for ii in xrange(self.GetPageCount()): self.bsizer.Add(self._notebookpages[ii], 1, wx.EXPAND | wx.ALL, 2) if self._style & NC_TOP: self.sizer.Add(self.bsizer, 1, wx.EXPAND) else: self.sizer.Insert(0, self.bsizer, 1, wx.EXPAND) self.bsizer.Layout() self.sizer.Layout() selection = self.GetSelection() if show: self._ShowTabCtrl(False) if self._style & NC_TOP or self._style & NC_LEFT: if len(self.nb._selectedtabs) > 0: for ii in xrange(self.GetPageCount()): if ii in self.nb._selectedtabs: self.bsizer.Show(ii, True) else: self.bsizer.Show(ii, False) else: for ii in xrange(self.GetPageCount()): if self.IsPageEnabled(ii): if not self.nb._enablehiding or not self.nb._pages[ii]._ishidden: self.bsizer.Show(ii, True) else: self.bsizer.Show(ii, False) else: self.bsizer.Show(ii, False) else: if len(self.nb._selectedtabs) > 0: for ii in xrange(self.GetPageCount()): if ii in self.nb._selectedtabs: self.bsizer.Show(ii, True) else: for ii in xrange(self.GetPageCount()): if self.IsPageEnabled(ii): if not self.nb._enablehiding or not self.nb._pages[ii]._ishidden: self.bsizer.Show(ii, True) else: self.bsizer.Show(ii, False) else: self.bsizer.Show(ii, False) else: self._ShowTabCtrl(True) if self._style & NC_TOP or self._style & NC_LEFT: for ii in xrange(self.GetPageCount()): self.bsizer.Show(ii, False) else: for ii in xrange(self.GetPageCount()): self.bsizer.Show(ii, False) if selection < 0: self.bsizer.Layout() self.sizer.Layout() return else: self.bsizer.Show(selection, True) self.bsizer.Layout() self._showcolumns = show self.bsizer.Layout() self.sizer.Layout() self.Thaw() def ShowTabs(self, show=True): """ Shows/Hides Tabs On Request. """ if self._GetTabCtrlWindow().IsShown() == show: return if self.GetPageCount() == 0: return self.Freeze() self._ShowTabCtrl(show) self._showtabs = show self.sizer.Layout() self.Thaw() def GetIndex(self, page): """ Returns The Page Index (Position) Based On The NotebookCtrl Page Passed. """ if page in self._notebookpages: return self._notebookpages.index(page) return -1 def ReparentPage(self, nPage, newParent): """ Reparents The NotebookCtrl Page nPage To A New Parent. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In ReparentPage: (" + str(nPage) + ")" page = self.GetPage(nPage) page.Reparent(newParent) def ReparentToFrame(self, nPage, createNotebook=False): """ Reparents The NotebookCtrl Page nPage To A New Frame. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In ReparentToFrame: (" + str(nPage) + ")" self.Freeze() infos = self.GetPageInfo(nPage) panel = self.GetPage(nPage) text = infos["text"] oldparent = panel.GetParent() frame = NCFrame(None, -1, text, nb=self, infos=infos, panel=panel, oldparent=oldparent) if createNotebook: nb = NotebookCtrl(frame, -1, style=self._style, sizer=self._sizerstyle) nb.SetImageList(infos["imagelist"]) self.ReparentToNotebook(nPage, nb) else: self.ReparentPage(nPage, frame) self.nb.DeletePage(nPage, False) self.bsizer.Detach(nPage) self.bsizer.Layout() self.sizer.Layout() self._notebookpages.pop(nPage) self.AdvanceSelection() if self.GetPageCount() == 0: self._ShowTabCtrl(False) self.sizer.Layout() custom = self.GetCustomPage() if custom is not None: self.SetCustomPage(custom) self.Thaw() frame.Show() def ReparentToNotebook(self, nPage, notebook, newPage=None): """ Reparents The NotebookCtrl Page nPage To A New NotebookCtrl. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In ReparentToNotebook: (" + str(nPage) + ")" if newPage is not None and newPage >= notebook.GetPageCount(): raise "\nERROR: Invalid Notebook New Page In ReparentToNotebook: (" + str(nPage) + ")" self.Freeze() infos = self.GetPageInfo(nPage) panel = self.GetPage(nPage) self.ReparentPage(nPage, notebook) if newPage is None: notebook.AddPage(panel, infos["text"], False, infos["image"]) notebook.SetPageInfo(0, infos) for attr in attrs: setattr(notebook, attr, getattr(self.nb, attr)) self.nb.DeletePage(nPage, False) self.bsizer.Detach(nPage) self.bsizer.Layout() self.sizer.Layout() self._notebookpages.pop(nPage) self.AdvanceSelection() if self.GetPageCount() == 0: self._ShowTabCtrl(False) self.sizer.Layout() self.Thaw() def GetPageInfo(self, nPage): """ Returns All The Style Information For A Given Page. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In GetPageInfo: (" + str(nPage) + ")" text = self.GetPageText(nPage) image = self.GetPageImage(nPage) font1 = self.GetPageTextFont(nPage) font2 = self.GetPageTextSecondaryFont(nPage) fontcolour = self.GetPageTextColour(nPage) pagecolour = self.GetPageColour(nPage) enabled = self.IsPageEnabled(nPage) tooltip, ontime, winsize = self.GetPageToolTip(nPage) menu = self.GetPagePopupMenu(nPage) firstcol = self.GetPageFirstGradientColour(nPage) secondcol = self.GetPageSecondGradientColour(nPage) ishidden = self.nb._pages[nPage]._ishidden isanimated = 0 timer = None if self.nb._timers[nPage].IsRunning(): isanimated = 1 timer = self.nb._timers[nPage].GetInterval() self.StopAnimation(nPage) animatedimages = self.GetAnimationImages(nPage) infos = {"text": text, "image": image, "font1": font1, "font2": font2, "fontcolour": fontcolour, "pagecolour": pagecolour, "enabled": enabled, "tooltip": tooltip, "ontime": ontime, "winsize": winsize, "menu": menu, "isanimated": isanimated, "timer": timer, "animatedimages": animatedimages, "imagelist": self.nb._imglist, "firstcol": firstcol, "secondcol": secondcol, "ishidden": ishidden} return infos def SetPageInfo(self, nPage, infos): """ Sets All The Style Information For A Given Page. """ if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): raise "\nERROR: Invalid Notebook Page In SetPageInfo: (" + str(nPage) + ")" self.SetPageTextFont(nPage, infos["font1"]) self.SetPageTextSecondaryFont(nPage, infos["font2"]) self.SetPageTextColour(nPage, infos["fontcolour"]) self.SetPageColour(nPage, infos["pagecolour"]) self.EnablePage(nPage, infos["enabled"]) self.SetPageToolTip(nPage, infos["tooltip"], infos["ontime"], infos["winsize"]) self.SetPagePopupMenu(nPage, infos["menu"]) self.SetPageFirstGradientColour(nPage, infos["firstcol"]) self.SetPageSecondGradientColour(nPage, infos["secondcol"]) self.nb._pages[nPage]._ishidden = infos["ishidden"] if infos["isanimated"] and len(infos["animatedimages"]) > 1: self.SetAnimationImages(nPage, infos["animatedimages"]) self.StartAnimation(nPage, infos["timer"]) def SetCustomPage(self, panel): """ Sets A Custom Panel To Show When There Are No Pages Left In NotebookCtrl. """ self.Freeze() if panel is None: if self._custompanel is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) if self.GetPageCount() == 0: self._ShowTabCtrl(False) else: if self.GetPageCount() == 0: if self._custompanel is not None: self.bsizer.Detach(self._custompanel) self._custompanel.Show(False) self.bsizer.Add(panel, 1, wx.EXPAND | wx.ALL, 2) panel.Show(True) self._ShowTabCtrl(False) else: panel.Show(False) self._custompanel = panel self.bsizer.Layout() self.sizer.Layout() self.Thaw() def GetCustomPage(self): """ Gets A Custom Panel To Show When There Are No Pages Left In NotebookCtrl. """ return self._custompanel def HideTab(self, nPage, hide=True): """ Hides A Tab In The NotebookCtrl. """ self.nb.HideTab(nPage, hide) def HitTest(self, point, flags=0): """ Standard NotebookCtrl HitTest() Method. If Called With 2 Outputs, It Returns The Page Clicked (If Any) And One Of These Flags: NC_HITTEST_NOWHERE = 0 ==> Hit Not On Tab NC_HITTEST_ONICON = 1 ==> Hit On Icon NC_HITTEST_ONLABEL = 2 ==> Hit On Label NC_HITTEST_ONITEM = 4 ==> Hit Generic, On Item NC_HITTEST_ONX = 8 ==> Hit On Closing "X" On Every Page """ return self.nb.HitTest(point, flags) def _AddMargin(self, style, margin): if style & NC_TOP or style & NC_BOTTOM: self.tabsizer.Add((0, margin), 0) elif style & NC_LEFT or style & NC_RIGHT: self.tabsizer.Add((margin, 0), 0) def _GetTabCtrlWindow(self): if self._style & NC_TOP or self._style & NC_LEFT: return self.tabsizer.GetItem(1) else: return self.tabsizer.GetItem(0) def _ShowTabCtrl(self, show): if self._style & NC_TOP: self.sizer.Show(0, show) else: self.sizer.Show(1, show) # ---------------------------------------------------------------------------- # # Class TransientTipWindow # Auxiliary Help Class. Used To Build The Tip Window. # ---------------------------------------------------------------------------- # class _PopupWindow: def _Fill(self, tip, winsize): panel = wx.Panel(self, -1) colour = self.GetParent().GetToolTipBackgroundColour() panel.SetBackgroundColour(colour) # border from sides and top to text (in pixels) border = 5 # how much space between text lines textPadding = 2 max_len = len(tip) tw = winsize mylines = tip.split("\n") sts = wx.StaticText(panel, -1, "\n".join(mylines)) sx, sy = sts.GetBestSize() sts.SetPosition((2, 2)) panel.SetSize((sx+6, sy+6)) self.SetSize(panel.GetSize()) class TransientTipWindow(_PopupWindow, wx.PopupWindow): def __init__(self, parent, tip, winsize): wx.PopupWindow.__init__(self, parent, flags=wx.SIMPLE_BORDER) self._Fill(tip,winsize) def ProcessLeftDown(self, evt): return False def OnDismiss(self): return False class macPopupWindow(wx.Frame): def __init__(self, parent, flags): wx.Frame.__init__(self, parent, id=-1, style=flags|wx.FRAME_NO_TASKBAR|wx.STAY_ON_TOP) self._hideOnActivate = False #Get the parent frame: could be improved maybe? self._parentFrame = parent while True: parent = self._parentFrame.GetParent() if parent: self._parentFrame = parent else: break self.Bind(wx.EVT_ACTIVATE, self.OnActivate) def Show(self, show=True): wx.Frame.Show(self,show) if show: self._parentFrame.Raise() self._hideOnActivate = True def OnActivate(self, evt): """ Let The User Hide The Tooltip By Clicking On It. NotebookCtrl Will Destroy It Later. """ if self._hideOnActivate: wx.Frame.Show(self,False) class macTransientTipWindow(_PopupWindow, macPopupWindow): def __init__(self, parent, tip, winsize): macPopupWindow.__init__(self, parent, flags=wx.SIMPLE_BORDER) self._Fill(tip, winsize) class NCFrame(wx.Frame): def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, nb=None, panel=None, infos=None, oldparent=None): wx.Frame.__init__(self, parent, id, title, pos, size, style) self._infos = infos self._nb = nb self._panel = panel self._oldparent = oldparent self.Bind(wx.EVT_CLOSE, self.OnClose) def OnClose(self, event): try: infos = self._infos self._panel.Reparent(self._oldparent) self._nb.AddPage(self._panel, infos["text"], False, infos["image"]) id = self._nb.GetPageCount() - 1 self._nb.SetPageTextFont(id, infos["font1"]) self._nb.SetPageTextSecondaryFont(id, infos["font2"]) self._nb.SetPageTextColour(id, infos["fontcolour"]) self._nb.SetPageColour(id, infos["pagecolour"]) self._nb.EnablePage(id, infos["enabled"]) self._nb.SetPageToolTip(id, infos["tooltip"], infos["ontime"], infos["winsize"]) self._nb.SetPagePopupMenu(id, infos["menu"]) self._nb.SetPageFirstGradientColour(id, infos["firstcol"]) self._nb.SetPageSecondGradientColour(id, infos["secondcol"]) self._nb._pages[id]._ishidden = infos["ishidden"] if infos["isanimated"] and len(infos["animatedimages"]) > 1: self._nb.SetAnimationImages(id, infos["animatedimages"]) self._nb.StartAnimation(id, infos["timer"]) except: self.Destroy() event.Skip() return self.Destroy() event.Skip() class NotebookCtrlWindowHandler(xrc.XmlResourceHandler): """ Create L{NotebookCtrl} windows defined in Xrc resources. Below is an example of a resource definition:: <?xml version="1.0" encoding="ISO-8859-1"?> <resource> <object class="wxPanel" name="appPanel"> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>1</option> <flag>wxEXPAND</flag> <object class="NotebookCtrl" name="notebook"> <style>wxNO_BORDER | NC_RIGHT | NC_ROTATE | NC_EXPANDABLE </style> <focus>0</focus> <highlight>1</highlight> <tabstyle>NC_GRADIENT_HORIZONTAL | NC_GRADIENT_SELECTION</tabstyle> <color1>#DCDCDC</color1> <color2>#F5F5F5</color2> <selectedcolor1>#C4DADB</selectedcolor1> <selectedcolor2>#FFFFFF</selectedcolor2> <custompagecolor>#C0C0C0</custompagecolor> </object> </object> </object> </object> </resource> @undocumented: CanHandle, DoCreateResource, SetupWindow """ def __init__(self): """ Create a NotebookCtrlWindowHandler instance. """ xrc.XmlResourceHandler.__init__(self) # Specify the window styles recognized by objects of this type self.AddStyle("wxNO_BORDER", wx.NO_BORDER) self.AddStyle("wxTAB_TRAVERSAL", wx.TAB_TRAVERSAL) self.AddStyle("NC_TOP", NC_TOP) self.AddStyle("NC_BOTTOM", NC_BOTTOM) self.AddStyle("NC_LEFT", NC_LEFT) self.AddStyle("NC_RIGHT", NC_RIGHT) self.AddStyle("NC_FIXED_WIDTH", NC_FIXED_WIDTH) self.AddStyle("NC_ROTATE", NC_ROTATE) self.AddStyle("NC_EXPANDABLE", NC_EXPANDABLE) # More styles, used in the tabstyle parameter self.AddStyle("NC_AQUA_LIGHT", NC_AQUA_LIGHT) self.AddStyle("NC_AQUA_DARK", NC_AQUA_DARK) self.AddStyle("NC_AQUA", NC_AQUA) self.AddStyle("NC_METAL", NC_METAL) self.AddStyle("NC_SILVER", NC_SILVER) self.AddStyle("NC_KDE", NC_KDE) self.AddStyle("NC_GRADIENT_VERTICAL", NC_GRADIENT_VERTICAL) self.AddStyle("NC_GRADIENT_HORIZONTAL", NC_GRADIENT_HORIZONTAL) self.AddStyle("NC_GRADIENT_SELECTION", NC_GRADIENT_SELECTION) self.AddWindowStyles() def _CreateResourceInstance(self, parent, id, position, size, style, name): window = NotebookCtrl(parent, id, position, size=size, style=style, name=name) return window def _GetColorParamValue(self, paramName, defaultValue=wx.WHITE): paramValue = self.GetParamValue(paramName) if paramValue: return self.GetColour(paramName) else: return defaultValue def _GetCustomPage(self, window): customPage = wx.Window(window, -1, style = wx.STATIC_BORDER) customPage.SetBackgroundColour(self._GetColorParamValue('custompagecolor')) return customPage def _GetIntParamValue(self, paramName, defaultValue=0): paramValue = self.GetParamValue(paramName) if paramValue: return int(paramValue) else: return defaultValue def _GetTabTheme(self): tabstyle = self.GetStyle("tabstyle") if tabstyle: result = ThemeStyle() if tabstyle & NC_GRADIENT_VERTICAL or tabstyle & NC_GRADIENT_HORIZONTAL: result.EnableGradientStyle(True, tabstyle) result.SetFirstGradientColour(self._GetColorParamValue('color1')) result.SetSecondGradientColour(self._GetColorParamValue('color2')) result.SetFirstGradientColourSelected(self._GetColorParamValue('selectedcolor1')) result.SetSecondGradientColourSelected(self._GetColorParamValue('selectedcolor2')) elif tabstyle & NC_AQUA_LIGHT or tabstyle & NC_AQUA_DARK: result.EnableAquaTheme(True, tabstyle & NC_AQUA_LIGHT and 2 or 1) elif tabstyle & NC_METAL: result.EnableMetalTheme(True) elif tabstyle & NC_KDE: result.EnableKDETheme(True) elif tabstyle & NC_SILVER: result.EnableSilverTheme(True) else: result = GetDefaultTabStyle() return result # This method and the next one are required for XmlResourceHandlers def CanHandle(self, node): return self.IsOfClass(node, "NotebookCtrl") def DoCreateResource(self): # NOTE: wxWindows can be created in either a single-phase or # in a two-phase way. Single phase is what you normally do, # and two-phase creates the instnace first, and then later # creates the actual window when the Create method is called. # (In wxPython the first phase is done using the wxPre* # function, for example, wxPreFrame, wxPrePanel, etc.) # # wxXmlResource supports either method, a premade instance can # be created and populated by xrc using the appropriate # LoadOn* method (such as LoadOnPanel) or xrc can create the # instance too, using the Load* method. However this makes # the handlers a bit more complex. If you can be sure that a # particular class will never be loaded using a pre-existing # instance, then you can make the handle much simpler. I'll # show both methods below. # The simple method assumes that there is no existing # instance. Be sure of that with an assert. assert self.GetInstance() is None # Now create the object window = self._CreateResourceInstance(self.GetParentAsWindow(), self.GetID(), self.GetPosition(), self.GetSize(), self.GetStyle("style", NC_DEFAULT_STYLE), self.GetName()) # Set standard window attributes self.SetupWindow(window) # Create any child windows of this node self.CreateChildren(window) return window def SetupWindow(self, window): super(NotebookCtrlWindowHandler, self).SetupWindow(window) window.ApplyTabTheme(self._GetTabTheme()) window.SetHighlightSelection(self._GetIntParamValue("highlight", 0) != 0) window.SetUseFocusIndicator(self._GetIntParamValue("focus", 1) != 0) window.SetCustomPage(self._GetCustomPage(window))