AGW Logo

Source code for aui.aui_switcherdialog

"""
Description
===========

The idea of `SwitcherDialog` is to make it easier to implement keyboard
navigation in AUI and other applications that have multiple panes and
tabs.

A key combination with a modifier (such as ``Ctrl`` + ``Tab``) shows the
dialog, and the user holds down the modifier whilst navigating with
``Tab`` and arrow keys before releasing the modifier to dismiss the dialog
and activate the selected pane.

The switcher dialog is a multi-column menu with no scrolling, implemented
by the `MultiColumnListCtrl` class. You can have headings for your items
for logical grouping, and you can force a column break if you need to.

The modifier used for invoking and dismissing the dialog can be customised,
as can the colours, number of rows, and the key used for cycling through
the items. So you can use different keys on different platforms if
required (especially since ``Ctrl`` + ``Tab`` is reserved on some platforms).

Items are shown as names and optional 16x16 images.


Base Functionalities
====================

To use the dialog, you set up the items in a `SwitcherItems` object,
before passing this to the `SwitcherDialog` instance.

Call L{SwitcherItems.AddItem} and optionally L{SwitcherItems.AddGroup} to add items and headings. These
functions take a label (to be displayed to the user), an identifying name,
an integer id, and a bitmap. The name and id are purely for application-defined
identification. You may also set a description to be displayed when each
item is selected; and you can set a window pointer for convenience when
activating the desired window after the dialog returns.

Have created the dialog, you call `ShowModal()`, and if the return value is
``wx.ID_OK``, retrieve the selection from the dialog and activate the pane.

The sample code below shows a generic method of finding panes and notebook
tabs within the current L{AuiManager}, and using the pane name or notebook
tab position to display the pane.

The only other code to add is a menu item with the desired accelerator,
whose modifier matches the one you pass to L{SwitcherDialog.SetModifierKey} 
(the default being ``wx.WXK_CONTROL``).


Usage
=====

Menu item::

    if wx.Platform == "__WXMAC__":
        switcherAccel = "Alt+Tab"
    elif wx.Platform == "__WXGTK__":
        switcherAccel = "Ctrl+/"
    else:
        switcherAccel = "Ctrl+Tab"

    view_menu.Append(ID_SwitchPane, _("S&witch Window...") + "\t" + switcherAccel)


Event handler::

    def OnSwitchPane(self, event):

        items = SwitcherItems()
        items.SetRowCount(12)

        # Add the main windows and toolbars, in two separate columns
        # We'll use the item 'id' to store the notebook selection, or -1 if not a page

        for k in xrange(2):
            if k == 0:
                items.AddGroup(_("Main Windows"), "mainwindows")
            else:
                items.AddGroup(_("Toolbars"), "toolbars").BreakColumn()

            for pane in self._mgr.GetAllPanes():
                name = pane.name
                caption = pane.caption

                toolbar = isinstance(info.window, wx.ToolBar) or isinstance(info.window, aui.AuiToolBar)
                if caption and (toolBar  and k == 1) or (not toolBar and k == 0):
                    items.AddItem(caption, name, -1).SetWindow(pane.window)

        # Now add the wxAuiNotebook pages

        items.AddGroup(_("Notebook Pages"), "pages").BreakColumn()

        for pane in self._mgr.GetAllPanes():
            nb = pane.window
            if isinstance(nb, aui.AuiNotebook):
                for j in xrange(nb.GetPageCount()):

                    name = nb.GetPageText(j)
                    win = nb.GetPage(j)

                    items.AddItem(name, name, j, nb.GetPageBitmap(j)).SetWindow(win)

        # Select the focused window

        idx = items.GetIndexForFocus()
        if idx != wx.NOT_FOUND:
            items.SetSelection(idx)

        if wx.Platform == "__WXMAC__":
            items.SetBackgroundColour(wx.WHITE)
        
        # Show the switcher dialog

        dlg = SwitcherDialog(items, wx.GetApp().GetTopWindow())

        # In GTK+ we can't use Ctrl+Tab; we use Ctrl+/ instead and tell the switcher
        # to treat / in the same was as tab (i.e. cycle through the names)

        if wx.Platform == "__WXGTK__":
            dlg.SetExtraNavigationKey(wxT('/'))

        if wx.Platform == "__WXMAC__":
            dlg.SetBackgroundColour(wx.WHITE)
            dlg.SetModifierKey(wx.WXK_ALT)

        ans = dlg.ShowModal()

        if ans == wx.ID_OK and dlg.GetSelection() != -1:
            item = items.GetItem(dlg.GetSelection())

            if item.GetId() == -1:
                info = self._mgr.GetPane(item.GetName())
                info.Show()
                self._mgr.Update()
                info.window.SetFocus()

            else:
                nb = item.GetWindow().GetParent()
                win = item.GetWindow();
                if isinstance(nb, aui.AuiNotebook):
                    nb.SetSelection(item.GetId())
                    win.SetFocus()


"""

import wx

import auibook
from aui_utilities import FindFocusDescendant
from aui_constants import SWITCHER_TEXT_MARGIN_X, SWITCHER_TEXT_MARGIN_Y


# Define a translation function
_ = wx.GetTranslation

    
[docs]class SwitcherItem(object): """ An object containing information about one item. """
[docs] def __init__(self, item=None): """ Default class constructor. """ self._id = 0 self._isGroup = False self._breakColumn = False self._rowPos = 0 self._colPos = 0 self._window = None self._description = "" self._textColour = wx.NullColour self._bitmap = wx.NullBitmap self._font = wx.NullFont if item: self.Copy(item)
[docs] def Copy(self, item): """ Copy operator between 2 L{SwitcherItem} instances. :param `item`: another instance of L{SwitcherItem}. """ self._id = item._id self._name = item._name self._title = item._title self._isGroup = item._isGroup self._breakColumn = item._breakColumn self._rect = item._rect self._font = item._font self._textColour = item._textColour self._bitmap = item._bitmap self._description = item._description self._rowPos = item._rowPos self._colPos = item._colPos self._window = item._window
[docs] def SetTitle(self, title): self._title = title return self
[docs] def GetTitle(self): return self._title
[docs] def SetName(self, name): self._name = name return self
[docs] def GetName(self): return self._name
[docs] def SetDescription(self, descr): self._description = descr return self
[docs] def GetDescription(self): return self._description
[docs] def SetId(self, id): self._id = id return self
[docs] def GetId(self): return self._id
[docs] def SetIsGroup(self, isGroup): self._isGroup = isGroup return self
[docs] def GetIsGroup(self): return self._isGroup
[docs] def BreakColumn(self, breakCol=True): self._breakColumn = breakCol return self
[docs] def GetBreakColumn(self): return self._breakColumn
[docs] def SetRect(self, rect): self._rect = rect return self
[docs] def GetRect(self): return self._rect
[docs] def SetTextColour(self, colour): self._textColour = colour return self
[docs] def GetTextColour(self): return self._textColour
[docs] def SetFont(self, font): self._font = font return self
[docs] def GetFont(self): return self._font
[docs] def SetBitmap(self, bitmap): self._bitmap = bitmap return self
[docs] def GetBitmap(self): return self._bitmap
[docs] def SetRowPos(self, pos): self._rowPos = pos return self
[docs] def GetRowPos(self): return self._rowPos
[docs] def SetColPos(self, pos): self._colPos = pos return self
[docs] def GetColPos(self): return self._colPos
[docs] def SetWindow(self, win): self._window = win return self
[docs] def GetWindow(self): return self._window
[docs]class SwitcherItems(object): """ An object containing switcher items. """
[docs] def __init__(self, items=None): """ Default class constructor. """ self._selection = -1 self._rowCount = 10 self._columnCount = 0 self._backgroundColour = wx.NullColour self._textColour = wx.NullColour self._selectionColour = wx.NullColour self._selectionOutlineColour = wx.NullColour self._itemFont = wx.NullFont self._items = [] if wx.Platform == "__WXMSW__": # If on Windows XP/Vista, use more appropriate colours self.SetSelectionOutlineColour(wx.Colour(49, 106, 197)) self.SetSelectionColour(wx.Colour(193, 210, 238)) if items: self.Copy(items)
[docs] def Copy(self, items): """ Copy operator between 2 L{SwitcherItems}. :param `items`: another instance of L{SwitcherItems}. """ self.Clear() for item in items._items: self._items.append(item) self._selection = items._selection self._rowCount = items._rowCount self._columnCount = items._columnCount self._backgroundColour = items._backgroundColour self._textColour = items._textColour self._selectionColour = items._selectionColour self._selectionOutlineColour = items._selectionOutlineColour self._itemFont = items._itemFont
[docs] def AddItem(self, titleOrItem, name=None, id=0, bitmap=wx.NullBitmap): if isinstance(titleOrItem, SwitcherItem): self._items.append(titleOrItem) return self._items[-1] item = SwitcherItem() item.SetTitle(titleOrItem) item.SetName(name) item.SetId(id) item.SetBitmap(bitmap) self._items.append(item) return self._items[-1]
[docs] def AddGroup(self, title, name, id=0, bitmap=wx.NullBitmap): item = self.AddItem(title, name, id, bitmap) item.SetIsGroup(True) return item
[docs] def Clear(self): self._items = []
[docs] def FindItemByName(self, name): for i in xrange(len(self._items)): if self._items[i].GetName() == name: return i return wx.NOT_FOUND
[docs] def FindItemById(self, id): for i in xrange(len(self._items)): if self._items[i].GetId() == id: return i return wx.NOT_FOUND
[docs] def SetSelection(self, sel): self._selection = sel
[docs] def SetSelectionByName(self, name): idx = self.FindItemByName(name) if idx != wx.NOT_FOUND: self.SetSelection(idx)
[docs] def GetSelection(self): return self._selection
[docs] def GetItem(self, i): return self._items[i]
[docs] def GetItemCount(self): return len(self._items)
[docs] def SetRowCount(self, rows): self._rowCount = rows
[docs] def GetRowCount(self): return self._rowCount
[docs] def SetColumnCount(self, cols): self._columnCount = cols
[docs] def GetColumnCount(self): return self._columnCount
[docs] def SetBackgroundColour(self, colour): self._backgroundColour = colour
[docs] def GetBackgroundColour(self): return self._backgroundColour
[docs] def SetTextColour(self, colour): self._textColour = colour
[docs] def GetTextColour(self): return self._textColour
[docs] def SetSelectionColour(self, colour): self._selectionColour = colour
[docs] def GetSelectionColour(self): return self._selectionColour
[docs] def SetSelectionOutlineColour(self, colour): self._selectionOutlineColour = colour
[docs] def GetSelectionOutlineColour(self): return self._selectionOutlineColour
[docs] def SetItemFont(self, font): self._itemFont = font
[docs] def GetItemFont(self): return self._itemFont
[docs] def PaintItems(self, dc, win): backgroundColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE) standardTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) selectionColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT) selectionOutlineColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) groupFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) groupFont.SetWeight(wx.BOLD) if self.GetBackgroundColour().IsOk(): backgroundColour = self.GetBackgroundColour() if self.GetTextColour().IsOk(): standardTextColour = self.GetTextColour() if self.GetSelectionColour().IsOk(): selectionColour = self.GetSelectionColour() if self.GetSelectionOutlineColour().IsOk(): selectionOutlineColour = self.GetSelectionOutlineColour() if self.GetItemFont().IsOk(): standardFont = self.GetItemFont() groupFont = wx.Font(standardFont.GetPointSize(), standardFont.GetFamily(), standardFont.GetStyle(), wx.BOLD, standardFont.GetUnderlined(), standardFont.GetFaceName()) textMarginX = SWITCHER_TEXT_MARGIN_X dc.SetLogicalFunction(wx.COPY) dc.SetBrush(wx.Brush(backgroundColour)) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangleRect(win.GetClientRect()) dc.SetBackgroundMode(wx.TRANSPARENT) for i in xrange(len(self._items)): item = self._items[i] if i == self._selection: dc.SetPen(wx.Pen(selectionOutlineColour)) dc.SetBrush(wx.Brush(selectionColour)) dc.DrawRectangleRect(item.GetRect()) clippingRect = wx.Rect(*item.GetRect()) clippingRect.Deflate(1, 1) dc.SetClippingRect(clippingRect) if item.GetTextColour().IsOk(): dc.SetTextForeground(item.GetTextColour()) else: dc.SetTextForeground(standardTextColour) if item.GetFont().IsOk(): dc.SetFont(item.GetFont()) else: if item.GetIsGroup(): dc.SetFont(groupFont) else: dc.SetFont(standardFont) w, h = dc.GetTextExtent(item.GetTitle()) x = item.GetRect().x x += textMarginX if not item.GetIsGroup(): if item.GetBitmap().IsOk() and item.GetBitmap().GetWidth() <= 16 \ and item.GetBitmap().GetHeight() <= 16: x -= textMarginX dc.DrawBitmap(item.GetBitmap(), x, item.GetRect().y + \ (item.GetRect().height - item.GetBitmap().GetHeight())/2, True) x += 16 + textMarginX #x += textMarginX y = item.GetRect().y + (item.GetRect().height - h)/2 dc.DrawText(item.GetTitle(), x, y) dc.DestroyClippingRegion()
[docs] def CalculateItemSize(self, dc): # Start off allowing for an icon sz = wx.Size(150, 16) standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) groupFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) groupFont.SetWeight(wx.BOLD) textMarginX = SWITCHER_TEXT_MARGIN_X textMarginY = SWITCHER_TEXT_MARGIN_Y maxWidth = 300 maxHeight = 40 if self.GetItemFont().IsOk(): standardFont = self.GetItemFont() for item in self._items: if item.GetFont().IsOk(): dc.SetFont(item.GetFont()) else: if item.GetIsGroup(): dc.SetFont(groupFont) else: dc.SetFont(standardFont) w, h = dc.GetTextExtent(item.GetTitle()) w += 16 + 2*textMarginX if w > sz.x: sz.x = min(w, maxWidth) if h > sz.y: sz.y = min(h, maxHeight) if sz == wx.Size(16, 16): sz = wx.Size(100, 25) else: sz.x += textMarginX*2 sz.y += textMarginY*2 return sz
[docs] def GetIndexForFocus(self): for i, item in enumerate(self._items): if item.GetWindow(): if FindFocusDescendant(item.GetWindow()): return i return wx.NOT_FOUND
[docs]class MultiColumnListCtrl(wx.PyControl): """ A control for displaying several columns (not scrollable). """
[docs] def __init__(self, parent, aui_manager, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name="MultiColumnListCtrl"): wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name) self._overallSize = wx.Size(200, 100) self._modifierKey = wx.WXK_CONTROL self._extraNavigationKey = 0 self._aui_manager = aui_manager self.SetInitialSize(size) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent) self.Bind(wx.EVT_CHAR, self.OnChar) self.Bind(wx.EVT_KEY_DOWN, self.OnKey) self.Bind(wx.EVT_KEY_UP, self.OnKey)
def __del__(self): self._aui_manager.HideHint()
[docs] def DoGetBestSize(self): return self._overallSize
[docs] def OnEraseBackground(self, event): pass
[docs] def OnPaint(self, event): dc = wx.AutoBufferedPaintDC(self) rect = self.GetClientRect() if self._items.GetColumnCount() == 0: self.CalculateLayout(dc) if self._items.GetColumnCount() == 0: return self._items.PaintItems(dc, self)
[docs] def OnMouseEvent(self, event): if event.LeftDown(): self.SetFocus()
[docs] def OnChar(self, event): event.Skip()
[docs] def OnKey(self, event): if event.GetEventType() == wx.wxEVT_KEY_UP: if event.GetKeyCode() == self.GetModifierKey(): topLevel = wx.GetTopLevelParent(self) closeEvent = wx.CloseEvent(wx.wxEVT_CLOSE_WINDOW, topLevel.GetId()) closeEvent.SetEventObject(topLevel) closeEvent.SetCanVeto(False) topLevel.GetEventHandler().ProcessEvent(closeEvent) return event.Skip() return keyCode = event.GetKeyCode() if keyCode in [wx.WXK_ESCAPE, wx.WXK_RETURN]: if keyCode == wx.WXK_ESCAPE: self._items.SetSelection(-1) topLevel = wx.GetTopLevelParent(self) closeEvent = wx.CloseEvent(wx.wxEVT_CLOSE_WINDOW, topLevel.GetId()) closeEvent.SetEventObject(topLevel) closeEvent.SetCanVeto(False) topLevel.GetEventHandler().ProcessEvent(closeEvent) return elif keyCode in [wx.WXK_TAB, self.GetExtraNavigationKey()]: if event.ShiftDown(): self._items.SetSelection(self._items.GetSelection() - 1) if self._items.GetSelection() < 0: self._items.SetSelection(self._items.GetItemCount() - 1) self.AdvanceToNextSelectableItem(-1) else: self._items.SetSelection(self._items.GetSelection() + 1) if self._items.GetSelection() >= self._items.GetItemCount(): self._items.SetSelection(0) self.AdvanceToNextSelectableItem(1) self.GenerateSelectionEvent() self.Refresh() elif keyCode in [wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN]: self._items.SetSelection(self._items.GetSelection() + 1) if self._items.GetSelection() >= self._items.GetItemCount(): self._items.SetSelection(0) self.AdvanceToNextSelectableItem(1) self.GenerateSelectionEvent() self.Refresh() elif keyCode in [wx.WXK_UP, wx.WXK_NUMPAD_UP]: self._items.SetSelection(self._items.GetSelection() - 1) if self._items.GetSelection() < 0: self._items.SetSelection(self._items.GetItemCount() - 1) self.AdvanceToNextSelectableItem(-1) self.GenerateSelectionEvent() self.Refresh() elif keyCode in [wx.WXK_HOME, wx.WXK_NUMPAD_HOME]: self._items.SetSelection(0) self.AdvanceToNextSelectableItem(1) self.GenerateSelectionEvent() self.Refresh() elif keyCode in [wx.WXK_END, wx.WXK_NUMPAD_END]: self._items.SetSelection(self._items.GetItemCount() - 1) self.AdvanceToNextSelectableItem(-1) self.GenerateSelectionEvent() self.Refresh() elif keyCode in [wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT]: item = self._items.GetItem(self._items.GetSelection()) row = item.GetRowPos() newCol = item.GetColPos() - 1 if newCol < 0: newCol = self._items.GetColumnCount() - 1 # Find the first item from the end whose row matches and whose column is equal or lower for i in xrange(self._items.GetItemCount()-1, -1, -1): item2 = self._items.GetItem(i) if item2.GetColPos() == newCol and item2.GetRowPos() <= row: self._items.SetSelection(i) break self.AdvanceToNextSelectableItem(-1) self.GenerateSelectionEvent() self.Refresh() elif keyCode in [wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT]: item = self._items.GetItem(self._items.GetSelection()) row = item.GetRowPos() newCol = item.GetColPos() + 1 if newCol >= self._items.GetColumnCount(): newCol = 0 # Find the first item from the end whose row matches and whose column is equal or lower for i in xrange(self._items.GetItemCount()-1, -1, -1): item2 = self._items.GetItem(i) if item2.GetColPos() == newCol and item2.GetRowPos() <= row: self._items.SetSelection(i) break self.AdvanceToNextSelectableItem(1) self.GenerateSelectionEvent() self.Refresh() else: event.Skip()
[docs] def AdvanceToNextSelectableItem(self, direction): if self._items.GetItemCount() < 2: return if self._items.GetSelection() == -1: self._items.SetSelection(0) oldSel = self._items.GetSelection() while 1: if self._items.GetItem(self._items.GetSelection()).GetIsGroup(): self._items.SetSelection(self._items.GetSelection() + direction) if self._items.GetSelection() == -1: self._items.SetSelection(self._items.GetItemCount()-1) elif self._items.GetSelection() == self._items.GetItemCount(): self._items.SetSelection(0) if self._items.GetSelection() == oldSel: break else: break self.SetTransparency() selection = self._items.GetItem(self._items.GetSelection()).GetWindow() pane = self._aui_manager.GetPane(selection) if not pane.IsOk(): if isinstance(selection.GetParent(), auibook.AuiNotebook): self.SetTransparency(selection) self._aui_manager.ShowHint(selection.GetScreenRect()) wx.CallAfter(self.SetFocus) self.SetFocus() return else: self._aui_manager.HideHint() return if not pane.IsShown(): self._aui_manager.HideHint() return self.SetTransparency(selection) self._aui_manager.ShowHint(selection.GetScreenRect()) # NOTE: this is odd but it is the only way for the focus to # work correctly on wxMac... wx.CallAfter(self.SetFocus) self.SetFocus()
[docs] def SetTransparency(self, selection=None): if not self.GetParent().CanSetTransparent(): return if selection is not None: intersects = False if selection.GetScreenRect().Intersects(self.GetParent().GetScreenRect()): intersects = True self.GetParent().SetTransparent(200) return self.GetParent().SetTransparent(255)
[docs] def GenerateSelectionEvent(self): event = wx.CommandEvent(wx.wxEVT_COMMAND_LISTBOX_SELECTED, self.GetId()) event.SetEventObject(self) event.SetInt(self._items.GetSelection()) self.GetEventHandler().ProcessEvent(event)
[docs] def CalculateLayout(self, dc=None): if dc is None: dc = wx.ClientDC(self) if self._items.GetSelection() == -1: self._items.SetSelection(0) columnCount = 1 # Spacing between edge of window or between columns xMargin = 4 yMargin = 4 # Inter-row spacing rowSpacing = 2 itemSize = self._items.CalculateItemSize(dc) self._overallSize = wx.Size(350, 200) currentRow = 0 x = xMargin y = yMargin breaking = False i = 0 while 1: oldOverallSize = self._overallSize item = self._items.GetItem(i) item.SetRect(wx.Rect(x, y, itemSize.x, itemSize.y)) item.SetColPos(columnCount-1) item.SetRowPos(currentRow) if item.GetRect().GetBottom() > self._overallSize.y: self._overallSize.y = item.GetRect().GetBottom() + yMargin if item.GetRect().GetRight() > self._overallSize.x: self._overallSize.x = item.GetRect().GetRight() + xMargin currentRow += 1 y += rowSpacing + itemSize.y stopBreaking = breaking if currentRow > self._items.GetRowCount() or (item.GetBreakColumn() and not breaking and currentRow != 1): currentRow = 0 columnCount += 1 x += xMargin + itemSize.x y = yMargin # Make sure we don't orphan a group if item.GetIsGroup() or (item.GetBreakColumn() and not breaking): self._overallSize = oldOverallSize if item.GetBreakColumn(): breaking = True # Repeat the last item, in the next column i -= 1 if stopBreaking: breaking = False i += 1 if i >= self._items.GetItemCount(): break self._items.SetColumnCount(columnCount) self.InvalidateBestSize()
[docs] def SetItems(self, items): self._items = items
[docs] def GetItems(self): return self._items
[docs] def SetExtraNavigationKey(self, keyCode): """ Set an extra key that can be used to cycle through items, in case not using the ``Ctrl`` + ``Tab`` combination. """ self._extraNavigationKey = keyCode
[docs] def GetExtraNavigationKey(self): return self._extraNavigationKey
[docs] def SetModifierKey(self, modifierKey): """ Set the modifier used to invoke the dialog, and therefore to test for release. """ self._modifierKey = modifierKey
[docs] def GetModifierKey(self): return self._modifierKey
[docs]class SwitcherDialog(wx.Dialog): """ SwitcherDialog shows a L{MultiColumnListCtrl} with a list of panes and tabs for the user to choose. ``Ctrl`` + ``Tab`` cycles through them. """
[docs] def __init__(self, items, parent, aui_manager, id=wx.ID_ANY, title=_("Pane Switcher"), pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.STAY_ON_TOP|wx.DIALOG_NO_PARENT|wx.BORDER_SIMPLE): """ Default class constructor. """ self._switcherBorderStyle = (style & wx.BORDER_MASK) if self._switcherBorderStyle == wx.BORDER_NONE: self._switcherBorderStyle = wx.BORDER_SIMPLE style &= wx.BORDER_MASK style |= wx.BORDER_NONE wx.Dialog.__init__(self, parent, id, title, pos, size, style) self._listCtrl = MultiColumnListCtrl(self, aui_manager, style=wx.WANTS_CHARS|wx.NO_BORDER) self._listCtrl.SetItems(items) self._listCtrl.CalculateLayout() self._descriptionCtrl = wx.html.HtmlWindow(self, size=(-1, 100), style=wx.BORDER_NONE) self._descriptionCtrl.SetBackgroundColour(self.GetBackgroundColour()) if wx.Platform == "__WXGTK__": fontSize = 11 self._descriptionCtrl.SetStandardFonts(fontSize) sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(sizer) sizer.Add(self._listCtrl, 1, wx.ALL|wx.EXPAND, 10) sizer.Add(self._descriptionCtrl, 0, wx.ALL|wx.EXPAND, 10) sizer.SetSizeHints(self) self._listCtrl.SetFocus() self.Centre(wx.BOTH) if self._listCtrl.GetItems().GetSelection() == -1: self._listCtrl.GetItems().SetSelection(0) self._listCtrl.AdvanceToNextSelectableItem(1) self.ShowDescription(self._listCtrl.GetItems().GetSelection()) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) self.Bind(wx.EVT_ACTIVATE, self.OnActivate) self.Bind(wx.EVT_LISTBOX, self.OnSelectItem) self.Bind(wx.EVT_PAINT, self.OnPaint) # Attributes self._closing = False if wx.Platform == "__WXMSW__": self._borderColour = wx.Colour(49, 106, 197) else: self._borderColour = wx.BLACK self._aui_manager = aui_manager
[docs] def OnCloseWindow(self, event): if self._closing: return if self.IsModal(): self._closing = True if self.GetSelection() == -1: self.EndModal(wx.ID_CANCEL) else: self.EndModal(wx.ID_OK) self._aui_manager.HideHint()
[docs] def GetSelection(self): return self._listCtrl.GetItems().GetSelection()
[docs] def OnActivate(self, event): if not event.GetActive(): if not self._closing: self._closing = True self.EndModal(wx.ID_CANCEL)
[docs] def OnPaint(self, event): dc = wx.PaintDC(self) if self._switcherBorderStyle == wx.BORDER_SIMPLE: dc.SetPen(wx.Pen(self._borderColour)) dc.SetBrush(wx.TRANSPARENT_BRUSH) rect = self.GetClientRect() dc.DrawRectangleRect(rect) # Draw border around the HTML control rect = wx.Rect(*self._descriptionCtrl.GetRect()) rect.Inflate(1, 1) dc.DrawRectangleRect(rect)
[docs] def OnSelectItem(self, event): self.ShowDescription(event.GetSelection()) # Convert a colour to a 6-digit hex string
[docs] def ColourToHexString(self, col): hx = '%02x%02x%02x' % tuple([int(c) for c in col]) return hx
[docs] def ShowDescription(self, i): item = self._listCtrl.GetItems().GetItem(i) colour = self._listCtrl.GetItems().GetBackgroundColour() if not colour.IsOk(): colour = self.GetBackgroundColour() backgroundColourHex = self.ColourToHexString(colour) html = _("<body bgcolor=\"#") + backgroundColourHex + _("\"><b>") + item.GetTitle() + _("</b>") if item.GetDescription(): html += _("<p>") html += item.GetDescription() html += _("</body>") self._descriptionCtrl.SetPage(html)
[docs] def SetExtraNavigationKey(self, keyCode): self._extraNavigationKey = keyCode if self._listCtrl: self._listCtrl.SetExtraNavigationKey(keyCode)
[docs] def GetExtraNavigationKey(self): return self._extraNavigationKey
[docs] def SetModifierKey(self, modifierKey): self._modifierKey = modifierKey if self._listCtrl: self._listCtrl.SetModifierKey(modifierKey)
[docs] def GetModifierKey(self): return self._modifierKey
[docs] def SetBorderColour(self, colour): self._borderColour = colour