"""
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
class SwitcherItem(object):
""" An object containing information about one item. """
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)
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
def SetTitle(self, title):
self._title = title
return self
def GetTitle(self):
return self._title
def SetName(self, name):
self._name = name
return self
def GetName(self):
return self._name
def SetDescription(self, descr):
self._description = descr
return self
def GetDescription(self):
return self._description
def SetId(self, id):
self._id = id
return self
def GetId(self):
return self._id
def SetIsGroup(self, isGroup):
self._isGroup = isGroup
return self
def GetIsGroup(self):
return self._isGroup
def BreakColumn(self, breakCol=True):
self._breakColumn = breakCol
return self
def GetBreakColumn(self):
return self._breakColumn
def SetRect(self, rect):
self._rect = rect
return self
def GetRect(self):
return self._rect
def SetTextColour(self, colour):
self._textColour = colour
return self
def GetTextColour(self):
return self._textColour
def SetFont(self, font):
self._font = font
return self
def GetFont(self):
return self._font
def SetBitmap(self, bitmap):
self._bitmap = bitmap
return self
def GetBitmap(self):
return self._bitmap
def SetRowPos(self, pos):
self._rowPos = pos
return self
def GetRowPos(self):
return self._rowPos
def SetColPos(self, pos):
self._colPos = pos
return self
def GetColPos(self):
return self._colPos
def SetWindow(self, win):
self._window = win
return self
def GetWindow(self):
return self._window
class SwitcherItems(object):
""" An object containing switcher items. """
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)
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
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]
def AddGroup(self, title, name, id=0, bitmap=wx.NullBitmap):
item = self.AddItem(title, name, id, bitmap)
item.SetIsGroup(True)
return item
def Clear(self):
self._items = []
def FindItemByName(self, name):
for i in xrange(len(self._items)):
if self._items[i].GetName() == name:
return i
return wx.NOT_FOUND
def FindItemById(self, id):
for i in xrange(len(self._items)):
if self._items[i].GetId() == id:
return i
return wx.NOT_FOUND
def SetSelection(self, sel):
self._selection = sel
def SetSelectionByName(self, name):
idx = self.FindItemByName(name)
if idx != wx.NOT_FOUND:
self.SetSelection(idx)
def GetSelection(self):
return self._selection
def GetItem(self, i):
return self._items[i]
def GetItemCount(self):
return len(self._items)
def SetRowCount(self, rows):
self._rowCount = rows
def GetRowCount(self):
return self._rowCount
def SetColumnCount(self, cols):
self._columnCount = cols
def GetColumnCount(self):
return self._columnCount
def SetBackgroundColour(self, colour):
self._backgroundColour = colour
def GetBackgroundColour(self):
return self._backgroundColour
def SetTextColour(self, colour):
self._textColour = colour
def GetTextColour(self):
return self._textColour
def SetSelectionColour(self, colour):
self._selectionColour = colour
def GetSelectionColour(self):
return self._selectionColour
def SetSelectionOutlineColour(self, colour):
self._selectionOutlineColour = colour
def GetSelectionOutlineColour(self):
return self._selectionOutlineColour
def SetItemFont(self, font):
self._itemFont = font
def GetItemFont(self):
return self._itemFont
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()
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
def GetIndexForFocus(self):
for i, item in enumerate(self._items):
if item.GetWindow():
if FindFocusDescendant(item.GetWindow()):
return i
return wx.NOT_FOUND
class MultiColumnListCtrl(wx.PyControl):
""" A control for displaying several columns (not scrollable). """
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()
def DoGetBestSize(self):
return self._overallSize
def OnEraseBackground(self, event):
pass
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)
def OnMouseEvent(self, event):
if event.LeftDown():
self.SetFocus()
def OnChar(self, event):
event.Skip()
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()
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()
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)
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)
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()
def SetItems(self, items):
self._items = items
def GetItems(self):
return self._items
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
def GetExtraNavigationKey(self):
return self._extraNavigationKey
def SetModifierKey(self, modifierKey):
"""
Set the modifier used to invoke the dialog, and therefore to test for
release.
"""
self._modifierKey = modifierKey
def GetModifierKey(self):
return self._modifierKey
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.
"""
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
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()
def GetSelection(self):
return self._listCtrl.GetItems().GetSelection()
def OnActivate(self, event):
if not event.GetActive():
if not self._closing:
self._closing = True
self.EndModal(wx.ID_CANCEL)
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)
def OnSelectItem(self, event):
self.ShowDescription(event.GetSelection())
# Convert a colour to a 6-digit hex string
def ColourToHexString(self, col):
hx = '%02x%02x%02x' % tuple([int(c) for c in col])
return hx
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)
def SetExtraNavigationKey(self, keyCode):
self._extraNavigationKey = keyCode
if self._listCtrl:
self._listCtrl.SetExtraNavigationKey(keyCode)
def GetExtraNavigationKey(self):
return self._extraNavigationKey
def SetModifierKey(self, modifierKey):
self._modifierKey = modifierKey
if self._listCtrl:
self._listCtrl.SetModifierKey(modifierKey)
def GetModifierKey(self):
return self._modifierKey
def SetBorderColour(self, colour):
self._borderColour = colour
|