############################################################################### # Name: segmentbk.py # # Purpose: SegmentBook Implementation # # Author: Cody Precord # # Copyright: (c) 2009 Cody Precord # # Licence: wxWindows Licence # ############################################################################### """ Editra Control Library: SegmentBook A L{SegmentBook} is a Toolbook like class derived from a ControlBox and SegmentBar. Allows for a multi page control with Icons w/ optional text as page buttons. +-----------------------------------------+ | @^@ *> | | <-> /|D | | frog bird | +-----------------------------------------+ | | | Main Page Area | | | | | | | | | | | | | | | | | +-----------------------------------------+ """ __author__ = "Cody Precord " __svnid__ = "$Id: segmentbk.py 69065 2011-09-11 19:18:25Z CJP $" __revision__ = "$Revision: 69065 $" __all__ = ['SegmentBook', 'SegmentBookEvent', 'SEGBOOK_STYLE_DEFAULT', 'SEGBOOK_STYLE_NO_DIVIDERS', 'SEGBOOK_STYLE_LABELS', 'SEGBOOK_STYLE_LEFT', 'SEGBOOK_STYLE_RIGHT', 'SEGBOOK_STYLE_TOP', 'SEGBOOK_STYLE_BOTTOM', 'SEGBOOK_NAME_STR', 'edEVT_SB_PAGE_CHANGING', 'EVT_SB_PAGE_CHANGING', 'edEVT_SB_PAGE_CHANGED', 'EVT_SB_PAGE_CHANGED', 'edEVT_SB_PAGE_CLOSED', 'EVT_SB_PAGE_CLOSED', 'edEVT_SB_PAGE_CONTEXT_MENU', 'EVT_SB_PAGE_CONTEXT_MENU', 'edEVT_SB_PAGE_CLOSING', 'EVT_SB_PAGE_CLOSING' ] #-----------------------------------------------------------------------------# # Imports import wx # Local Imports import ctrlbox from eclutil import Freezer #-----------------------------------------------------------------------------# # Events edEVT_SB_PAGE_CHANGING = wx.NewEventType() EVT_SB_PAGE_CHANGING = wx.PyEventBinder(edEVT_SB_PAGE_CHANGING, 1) edEVT_SB_PAGE_CHANGED = wx.NewEventType() EVT_SB_PAGE_CHANGED = wx.PyEventBinder(edEVT_SB_PAGE_CHANGED, 1) edEVT_SB_PAGE_CLOSING = wx.NewEventType() EVT_SB_PAGE_CLOSING = wx.PyEventBinder(edEVT_SB_PAGE_CLOSING, 1) edEVT_SB_PAGE_CLOSED = wx.NewEventType() EVT_SB_PAGE_CLOSED = wx.PyEventBinder(edEVT_SB_PAGE_CLOSED, 1) edEVT_SB_PAGE_CONTEXT_MENU = wx.NewEventType() EVT_SB_PAGE_CONTEXT_MENU = wx.PyEventBinder(edEVT_SB_PAGE_CONTEXT_MENU, 1) class SegmentBookEvent(wx.NotebookEvent): """SegmentBook event""" def __init__(self, etype=wx.wxEVT_NULL, id=-1, sel=-1, old_sel=-1): super(SegmentBookEvent, self).__init__(etype, id, sel, old_sel) #-----------------------------------------------------------------------------# # Global constants # Styles SEGBOOK_STYLE_NO_DIVIDERS = 1 # Don't put dividers between segments SEGBOOK_STYLE_LABELS = 2 # Use labels below the icons SEGBOOK_STYLE_TOP = 4 # Segments at top SEGBOOK_STYLE_BOTTOM = 8 # Segments at top SEGBOOK_STYLE_LEFT = 16 # Segments at top SEGBOOK_STYLE_RIGHT = 32 # Segments at top SEGBOOK_STYLE_DEFAULT = SEGBOOK_STYLE_TOP # Default Style # Misc SEGBOOK_NAME_STR = u"EditraSegmentBook" #-----------------------------------------------------------------------------# class SegmentBook(ctrlbox.ControlBox): """Notebook Class""" def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=SEGBOOK_STYLE_DEFAULT, name=SEGBOOK_NAME_STR): """Initialize the SegmentBook""" super(SegmentBook, self).__init__(parent, id, pos, size, wx.TAB_TRAVERSAL|wx.NO_BORDER, name) # Attributes self._pages = list() self._imglist = None self._use_pylist = False self._style = style # Setup bstyle = ctrlbox.CTRLBAR_STYLE_BORDER_BOTTOM # Disable gradient on GTK due to coloring issues and having # to deal with various themes. if wx.Platform != '__WXGTK__': bstyle |= ctrlbox.CTRLBAR_STYLE_GRADIENT if style & SEGBOOK_STYLE_NO_DIVIDERS: bstyle |= ctrlbox.CTRLBAR_STYLE_NO_DIVIDERS if style & SEGBOOK_STYLE_LABELS: bstyle |= ctrlbox.CTRLBAR_STYLE_LABELS if style & SEGBOOK_STYLE_LEFT or style & SEGBOOK_STYLE_RIGHT: bstyle |= ctrlbox.CTRLBAR_STYLE_VERTICAL self._segbar = ctrlbox.SegmentBar(self, style=bstyle) self.SetControlBar(self._segbar, self._GetSegBarPos()) # Event Handlers self.Bind(ctrlbox.EVT_SEGMENT_SELECTED, self._OnSegmentSel) self._segbar.Bind(wx.EVT_RIGHT_DOWN, self._OnRightDown) self._segbar.Bind(ctrlbox.EVT_SEGMENT_CLOSE, self._OnSegClose) def _GetSegBarPos(self): pos = wx.TOP if self._style & SEGBOOK_STYLE_LEFT: pos = wx.LEFT elif self._style & SEGBOOK_STYLE_RIGHT: pos = wx.RIGHT elif self._style & SEGBOOK_STYLE_BOTTOM: pos = wx.BOTTOM return pos def _DoPageChange(self, psel, csel): """Change the page and post events @param psel: previous selection (int) @param csel: current selection (int) """ # Post page changing event event = SegmentBookEvent(edEVT_SB_PAGE_CHANGING, self.GetId(), csel, psel) event.SetEventObject(self) handler = self.GetEventHandler() if not handler.ProcessEvent(event) or event.IsAllowed(): # Do the actual page change with Freezer(self) as _tmp: self.ChangePage(csel) # Post page changed event event.SetEventType(edEVT_SB_PAGE_CHANGED) handler.ProcessEvent(event) changed = True else: # Reset the segment selection self._segbar.SetSelection(max(psel, 0)) changed = False return changed def _OnRightDown(self, evt): """Handle right click events""" pos = evt.GetPosition() where, index = self._segbar.HitTest(pos) print where, index if where in (ctrlbox.SEGMENT_HT_SEG, ctrlbox.SEGMENT_HT_X_BTN): if where == ctrlbox.SEGMENT_HT_SEG: self._segbar.SetSelection(index) changed = self._DoPageChange(self.GetSelection(), index) if changed: # Send Context Menu Event event = SegmentBookEvent(edEVT_SB_PAGE_CONTEXT_MENU, self.GetId()) event.SetSelection(index) event.SetOldSelection(index) event.SetEventObject(self) self.GetEventHandler().ProcessEvent(event) else: # TODO: Handle other right clicks pass evt.Skip() def _OnSegClose(self, evt): """Handle clicks on segment close buttons""" index = evt.GetPreviousSelection() change = -1 segcnt = self._segbar.GetSegmentCount() - 1 if index == 0 and segcnt: change = 1 elif index > 0 and segcnt > 1: change = index - 1 if change != -1: self._DoPageChange(index, change) self._pages[index]['page'].Destroy() del self._pages[index] def _OnSegmentSel(self, evt): """Change the page in the book""" psel = evt.GetPreviousSelection() csel = evt.GetCurrentSelection() self._DoPageChange(psel, csel) def AddPage(self, page, text, select=False, img_id=-1): """Add a page to the notebook @param page: wxWindow object @param text: Page text @keyword select: should the page be selected @keyword img_id: Image to use """ page.Hide() self._pages.append(dict(page=page, img=img_id)) segbar = self.GetControlBar(self._GetSegBarPos()) if self._use_pylist: bmp = self._imglist[img_id] else: bmp = self._imglist.GetBitmap(img_id) segbar.AddSegment(wx.ID_ANY, bmp, text) idx = len(self._pages) - 1 if select or idx == 0: segbar.SetSelection(idx) self._DoPageChange(segbar.GetSelection(), idx) def ChangePage(self, index): """Change the page to the given index""" cpage = self._pages[index]['page'] page = self.ChangeWindow(cpage) if page is not None: page.Hide() cpage.Show() self.Layout() def DeleteAllPages(self): """Remove all pages from the control""" for page in reversed(range(len(self._pages))): self.DeletePage() def DeletePage(self, index): """Delete the page at the given index @param index: int """ cpage = self._segbar.GetSelection() self._segbar.RemoveSegment(index) npage = self._segbar.GetSelection() self._DoPageChange(cpage, npage) self._pages[index]['page'].Destroy() del self._pages[index] def CurrentPage(self): """Get the currently selected page @return: wxWindow or None """ idx = self._segbar.GetSelection() if idx != -1: return self._pages[idx]['page'] else: return None def GetImageList(self): """Get the notebooks image list @return: wxImageList or None """ return self._imglist def GetPage(self, index): """Get the page at the given index @param index: int """ return self._pages[index]['page'] def GetPageCount(self): """Get the number of pages in the book @return: int """ return len(self._pages) def GetPageImage(self, index): """Get the image index of the current page @param index: page index @return: int """ return self._pages[index]['img'] def SetPageCloseButton(self, index): """Set the property of a page @param index: Segment index """ if wx.Platform != '__WXMAC__': self._segbar.SetSegmentOption(index, ctrlbox.SEGBTN_OPT_CLOSEBTNR) else: self._segbar.SetSegmentOption(index, ctrlbox.SEGBTN_OPT_CLOSEBTNL) def GetPageText(self, index): """Get the text of the current page @param index: page index @return: string """ return self._segbar.GetSegmentLabel(index) def SetSegmentCanClose(self, index, can_close=True): """Add a close button to the given segment @param index: segment index @keyword can_close: Enable/Disable """ if not can_close: opt = ctrlbox.SEGBTN_OPT_NONE elif wx.Platform == '__WXMAC__': opt = ctrlbox.SEGBTN_OPT_CLOSEBTNL else: opt = ctrlbox.SEGBTN_OPT_CLOSEBTNR self._segbar.SetSegmentOption(index, opt) def GetSelection(self): """Get the current selection @return: int """ return self._segbar.GetSelection() def GetSegmentBar(self): """Get the segment bar used by this control @return: SegmentBar """ return self._segbar def HasMultiplePages(self): """Does the book have multiple pages @return: bool """ return bool(self.GetPageCount()) def HitTest(self, pt): """Find if/where the given point is in the window @param pt: wxPoint @return: where, index """ where, index = (SEGBOOK_NO_WHERE, -1) index = self._segbar.GetIndexFromPosition(pt) if index != wx.NOT_FOUND: where = SEGBOOK_ON_SEGMENT # TOOD check for clicks elsewhere on bar return where, index def InsertPage(self, index, page, text, select=False, image_id=-1): """Insert a page a the given index @param index: index to insert page at @param page: page to add to book @param text: page text @keyword select: bool @keyword image_id: image list index """ raise NotImplementedError def Refresh(self): """Refresh the segmentbar @todo: temporary HACK till rework of SegmentBar class image handling """ segbar = self.GetSegmentBar() for page in range(self.GetPageCount()): idx = self.GetPageImage(page) bmp = self._imglist[idx] segbar.SetSegmentImage(page, bmp) segbar.Refresh() super(SegmentBook, self).Refresh() def SetImageList(self, imglist): """Set the notebooks image list @param imglist: wxImageList """ self._imglist = imglist def SetPageImage(self, index, img_id): """Set the image to use on the given page @param index: page index @param img_id: image list index """ page = self._pages[index] page['img'] = img_id self._segbar.SetSegmentImage(self._imglst.GetBitmap(img_id)) self.Layout() def SetPageText(self, index, text): """Set the text to use on the given page @param index: page index @param text: string """ self._segbar.SetSegmentLabel(index, text) def SetSelection(self, index): """Set the selected page @param index: index of page to select """ csel = self._segbar.GetSelection() if csel != index: self._segbar.SetSelection(index) self._DoPageChange(csel, index) def SetUsePyImageList(self, use_pylist): """Set whether the control us using a regular python list for storing images or a wxImageList. @param use_pylist: bool """ self._use_pylist = use_pylist