X-Git-Url: http://www.iramuteq.org/git?a=blobdiff_plain;f=aui%2Faui_switcherdialog.py;fp=aui%2Faui_switcherdialog.py;h=552cb84717b687cb916a712d60c518a98f2773e5;hb=7fb5b2b86f6c9a0617208ee85211177c23d12f47;hp=0000000000000000000000000000000000000000;hpb=22f93a602f3584ddc6ba68114556212c90307a50;p=iramuteq diff --git a/aui/aui_switcherdialog.py b/aui/aui_switcherdialog.py new file mode 100644 index 0000000..552cb84 --- /dev/null +++ b/aui/aui_switcherdialog.py @@ -0,0 +1,1216 @@ +""" +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 = _("") + item.GetTitle() + _("") + + if item.GetDescription(): + html += _("

") + html += item.GetDescription() + + html += _("") + 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 + + \ No newline at end of file