text: ###############################################################################
  # Name: segmentbk.py                                                          #
  # Purpose: SegmentBook Implementation                                         #
  # Author: Cody Precord <cprecord@editra.org>                                  #
  # Copyright: (c) 2009 Cody Precord <staff@editra.org>                         #
  # 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 <cprecord@editra.org>"
  __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
  