PmwNoteBook.py :  » GUI » Pmw » Pmw.1.3.2 » src » Pmw » Pmw_1_3 » lib » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » GUI » Pmw 
Pmw » Pmw.1.3.2 » src » Pmw » Pmw_1_3 » lib » PmwNoteBook.py
import string
import types
import Tkinter
import Pmw

class NoteBook(Pmw.MegaArchetype):

    def __init__(self, parent = None, **kw):

  # Define the megawidget options.
  INITOPT = Pmw.INITOPT
        optiondefs = (
      ('hull_highlightthickness',  0,           None),
      ('hull_borderwidth',         0,           None),
            ('arrownavigation',          1,           INITOPT),
            ('borderwidth',              2,           INITOPT),
            ('createcommand',            None,        None),
            ('lowercommand',             None,        None),
            ('pagemargin',               4,           INITOPT),
            ('raisecommand',             None,        None),
      ('tabpos',                   'n',         INITOPT),
        )
  self.defineoptions(kw, optiondefs, dynamicGroups = ('Page', 'Tab'))

  # Initialise the base class (after defining the options).
  Pmw.MegaArchetype.__init__(self, parent, Tkinter.Canvas)

        self.bind('<Map>', self._handleMap)
        self.bind('<Configure>', self._handleConfigure)

        tabpos = self['tabpos']
  if tabpos is not None and tabpos != 'n':
            raise ValueError, \
                'bad tabpos option %s:  should be n or None' % repr(tabpos)
        self._withTabs = (tabpos is not None)
        self._pageMargin = self['pagemargin']
        self._borderWidth = self['borderwidth']

        # Use a dictionary as a set of bits indicating what needs to
        # be redisplayed the next time _layout() is called.  If
        # dictionary contains 'topPage' key, the value is the new top
        # page to be displayed.  None indicates that all pages have
        # been deleted and that _layout() should draw a border under where
        # the tabs should be.
        self._pending = {}
        self._pending['size'] = 1
        self._pending['borderColor'] = 1
        self._pending['topPage'] = None
        if self._withTabs:
            self._pending['tabs'] = 1

        self._canvasSize = None       # This gets set by <Configure> events

        # Set initial height of space for tabs
        if self._withTabs:
            self.tabBottom = 35
        else:
            self.tabBottom = 0

        self._lightBorderColor, self._darkBorderColor = \
                Pmw.Color.bordercolors(self, self['hull_background'])

  self._pageNames   = []        # List of page names

        # Map from page name to page info.  Each item is itself a
        # dictionary containing the following items:
        #   page           the Tkinter.Frame widget for the page
        #   created        set to true the first time the page is raised
        #   tabbutton      the Tkinter.Button widget for the button (if any)
        #   tabreqwidth    requested width of the tab
        #   tabreqheight   requested height of the tab
        #   tabitems       the canvas items for the button: the button
        #                  window item, the lightshadow and the darkshadow
        #   left           the left and right canvas coordinates of the tab
        #   right
  self._pageAttrs   = {}

        # Name of page currently on top (actually displayed, using
        # create_window, not pending).  Ignored if current top page
        # has been deleted or new top page is pending.  None indicates
        # no pages in notebook.
  self._topPageName = None

        # Canvas items used:
        #   Per tab: 
        #       top and left shadow
        #       right shadow
        #       button
        #   Per notebook: 
        #       page
        #       top page
        #       left shadow
        #       bottom and right shadow
        #       top (one or two items)

        # Canvas tags used:
        #   lighttag      - top and left shadows of tabs and page
        #   darktag       - bottom and right shadows of tabs and page
        #                   (if no tabs then these are reversed)
        #                   (used to color the borders by recolorborders)

        # Create page border shadows.
        if self._withTabs:
            self._pageLeftBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._lightBorderColor, tags = 'lighttag')
            self._pageBottomRightBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'darktag')
            self._pageTop1Border = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'lighttag')
            self._pageTop2Border = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'lighttag')
        else:
            self._pageLeftBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'darktag')
            self._pageBottomRightBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._lightBorderColor, tags = 'lighttag')
            self._pageTopBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'darktag')

  # Check keywords and initialise options.
  self.initialiseoptions()

    def insert(self, pageName, before = 0, **kw):
  if self._pageAttrs.has_key(pageName):
      msg = 'Page "%s" already exists.' % pageName
      raise ValueError, msg

        # Do this early to catch bad <before> spec before creating any items.
  beforeIndex = self.index(before, 1)

        pageOptions = {}
        if self._withTabs:
            # Default tab button options.
            tabOptions = {
                'text' : pageName,
                'borderwidth' : 0,
            }

        # Divide the keyword options into the 'page_' and 'tab_' options.
        for key in kw.keys():
            if key[:5] == 'page_':
                pageOptions[key[5:]] = kw[key]
                del kw[key]
            elif self._withTabs and key[:4] == 'tab_':
                tabOptions[key[4:]] = kw[key]
                del kw[key]
            else:
    raise KeyError, 'Unknown option "' + key + '"'

        # Create the frame to contain the page.
  page = apply(self.createcomponent, (pageName,
    (), 'Page',
    Tkinter.Frame, self._hull), pageOptions)

        attributes = {}
        attributes['page'] = page
        attributes['created'] = 0

        if self._withTabs:
            # Create the button for the tab.
            def raiseThisPage(self = self, pageName = pageName):
                self.selectpage(pageName)
            tabOptions['command'] = raiseThisPage
            tab = apply(self.createcomponent, (pageName + '-tab',
                    (), 'Tab',
                    Tkinter.Button, self._hull), tabOptions)

            if self['arrownavigation']:
                # Allow the use of the arrow keys for Tab navigation:
                def next(event, self = self, pageName = pageName):
                    self.nextpage(pageName)
                def prev(event, self = self, pageName = pageName):
                    self.previouspage(pageName)
                tab.bind('<Left>', prev)
                tab.bind('<Right>', next)

            attributes['tabbutton'] = tab
            attributes['tabreqwidth'] = tab.winfo_reqwidth()
            attributes['tabreqheight'] = tab.winfo_reqheight()

            # Create the canvas item to manage the tab's button and the items
            # for the tab's shadow.
            windowitem = self.create_window(0, 0, window = tab, anchor = 'nw')
            lightshadow = self.create_polygon(0, 0, 0, 0, 0, 0,
                tags = 'lighttag', fill = self._lightBorderColor)
            darkshadow = self.create_polygon(0, 0, 0, 0, 0, 0,
                tags = 'darktag', fill = self._darkBorderColor)
            attributes['tabitems'] = (windowitem, lightshadow, darkshadow)
            self._pending['tabs'] = 1

        self._pageAttrs[pageName] = attributes
  self._pageNames.insert(beforeIndex, pageName)

        # If this is the first page added, make it the new top page
        # and call the create and raise callbacks.
        if self.getcurselection() is None:
            self._pending['topPage'] = pageName
            self._raiseNewTop(pageName)

        self._layout()
        return page
      
    def add(self, pageName, **kw):
        return apply(self.insert, (pageName, len(self._pageNames)), kw)

    def delete(self, *pageNames):
        newTopPage = 0
        for page in pageNames:
            pageIndex = self.index(page)
            pageName = self._pageNames[pageIndex]
            pageInfo = self._pageAttrs[pageName]

            if self.getcurselection() == pageName:
                if len(self._pageNames) == 1:
                    newTopPage = 0
                    self._pending['topPage'] = None
                elif pageIndex == len(self._pageNames) - 1:
                    newTopPage = 1
                    self._pending['topPage'] = self._pageNames[pageIndex - 1]
                else:
                    newTopPage = 1
                    self._pending['topPage'] = self._pageNames[pageIndex + 1]

            if self._topPageName == pageName:
                self._hull.delete(self._topPageItem)
                self._topPageName = None
                                
            if self._withTabs:
                self.destroycomponent(pageName + '-tab')
                apply(self._hull.delete, pageInfo['tabitems'])
            self.destroycomponent(pageName)
            del self._pageAttrs[pageName]
            del self._pageNames[pageIndex]

        # If the old top page was deleted and there are still pages
        # left in the notebook, call the create and raise callbacks.
        if newTopPage:
            pageName = self._pending['topPage']
            self._raiseNewTop(pageName)

        if self._withTabs:
            self._pending['tabs'] = 1
        self._layout()

    def page(self, pageIndex):
        pageName = self._pageNames[self.index(pageIndex)]
  return self._pageAttrs[pageName]['page']

    def pagenames(self):
  return list(self._pageNames)

    def getcurselection(self):
        if self._pending.has_key('topPage'):
            return self._pending['topPage']
        else:
            return self._topPageName

    def tab(self, pageIndex):
        if self._withTabs:
            pageName = self._pageNames[self.index(pageIndex)]
            return self._pageAttrs[pageName]['tabbutton']
        else:
            return None

    def index(self, index, forInsert = 0):
  listLength = len(self._pageNames)
  if type(index) == types.IntType:
      if forInsert and index <= listLength:
    return index
      elif not forInsert and index < listLength:
    return index
      else:
    raise ValueError, 'index "%s" is out of range' % index
  elif index is Pmw.END:
      if forInsert:
    return listLength
      elif listLength > 0:
    return listLength - 1
      else:
    raise ValueError, 'NoteBook has no pages'
  elif index is Pmw.SELECT:
      if listLength == 0:
    raise ValueError, 'NoteBook has no pages'
            return self._pageNames.index(self.getcurselection())
  else:
            if index in self._pageNames:
                return self._pageNames.index(index)
      validValues = 'a name, a number, Pmw.END or Pmw.SELECT'
      raise ValueError, \
                'bad index "%s": must be %s' % (index, validValues)

    def selectpage(self, page):
        pageName = self._pageNames[self.index(page)]
        oldTopPage = self.getcurselection()
        if pageName != oldTopPage:
            self._pending['topPage'] = pageName
            if oldTopPage == self._topPageName:
                self._hull.delete(self._topPageItem)
            cmd = self['lowercommand']
            if cmd is not None:
                cmd(oldTopPage)
            self._raiseNewTop(pageName)

            self._layout()

        # Set focus to the tab of new top page:
        if self._withTabs and self['arrownavigation']:
            self._pageAttrs[pageName]['tabbutton'].focus_set()

    def previouspage(self, pageIndex = None):
        if pageIndex is None:
            curpage = self.index(Pmw.SELECT)
        else:
            curpage = self.index(pageIndex)
  if curpage > 0:
      self.selectpage(curpage - 1)

    def nextpage(self, pageIndex = None):
        if pageIndex is None:
            curpage = self.index(Pmw.SELECT)
        else:
            curpage = self.index(pageIndex)
  if curpage < len(self._pageNames) - 1:
      self.selectpage(curpage + 1)

    def setnaturalsize(self, pageNames = None):
        self.update_idletasks()
        maxPageWidth = 1
        maxPageHeight = 1
        if pageNames is None:
            pageNames = self.pagenames()
        for pageName in pageNames:
            pageInfo = self._pageAttrs[pageName]
            page = pageInfo['page']
            w = page.winfo_reqwidth()
            h = page.winfo_reqheight()
            if maxPageWidth < w:
                maxPageWidth = w
            if maxPageHeight < h:
                maxPageHeight = h
        pageBorder = self._borderWidth + self._pageMargin
        width = maxPageWidth + pageBorder * 2
        height = maxPageHeight + pageBorder * 2

        if self._withTabs:
            maxTabHeight = 0
            for pageInfo in self._pageAttrs.values():
                if maxTabHeight < pageInfo['tabreqheight']:
                    maxTabHeight = pageInfo['tabreqheight']
            height = height + maxTabHeight + self._borderWidth * 1.5

        # Note that, since the hull is a canvas, the width and height
        # options specify the geometry *inside* the borderwidth and
        # highlightthickness.
        self.configure(hull_width = width, hull_height = height)

    def recolorborders(self):
        self._pending['borderColor'] = 1
        self._layout()

    def _handleMap(self, event):
        self._layout()

    def _handleConfigure(self, event):
        self._canvasSize = (event.width, event.height)
        self._pending['size'] = 1
        self._layout()

    def _raiseNewTop(self, pageName):
        if not self._pageAttrs[pageName]['created']:
            self._pageAttrs[pageName]['created'] = 1
            cmd = self['createcommand']
            if cmd is not None:
                cmd(pageName)
        cmd = self['raisecommand']
        if cmd is not None:
            cmd(pageName)

    # This is the vertical layout of the notebook, from top (assuming
    # tabpos is 'n'):
    #     hull highlightthickness (top)
    #     hull borderwidth (top)
    #     borderwidth (top border of tabs)
    #     borderwidth * 0.5 (space for bevel)
    #     tab button (maximum of requested height of all tab buttons)
    #     borderwidth (border between tabs and page)
    #     pagemargin (top)
    #     the page itself
    #     pagemargin (bottom)
    #     borderwidth (border below page)
    #     hull borderwidth (bottom)
    #     hull highlightthickness (bottom)
    #
    # canvasBorder is sum of top two elements.
    # tabBottom is sum of top five elements.
    #
    # Horizontal layout (and also vertical layout when tabpos is None):
    #     hull highlightthickness
    #     hull borderwidth
    #     borderwidth
    #     pagemargin
    #     the page itself
    #     pagemargin
    #     borderwidth
    #     hull borderwidth
    #     hull highlightthickness
    #
    def _layout(self):
        if not self.winfo_ismapped() or self._canvasSize is None:
            # Don't layout if the window is not displayed, or we
            # haven't yet received a <Configure> event.
            return

        hullWidth, hullHeight = self._canvasSize
        borderWidth = self._borderWidth
        canvasBorder = string.atoi(self._hull['borderwidth']) + \
            string.atoi(self._hull['highlightthickness'])
        if not self._withTabs:
            self.tabBottom = canvasBorder
        oldTabBottom = self.tabBottom

        if self._pending.has_key('borderColor'):
            self._lightBorderColor, self._darkBorderColor = \
                    Pmw.Color.bordercolors(self, self['hull_background'])

        # Draw all the tabs.
        if self._withTabs and (self._pending.has_key('tabs') or
                self._pending.has_key('size')):
            # Find total requested width and maximum requested height
            # of tabs.
            sumTabReqWidth = 0
            maxTabHeight = 0
            for pageInfo in self._pageAttrs.values():
                sumTabReqWidth = sumTabReqWidth + pageInfo['tabreqwidth']
                if maxTabHeight < pageInfo['tabreqheight']:
                    maxTabHeight = pageInfo['tabreqheight']
            if maxTabHeight != 0:
                # Add the top tab border plus a bit for the angled corners
                self.tabBottom = canvasBorder + maxTabHeight + borderWidth * 1.5

            # Prepare for drawing the border around each tab button.
            tabTop = canvasBorder
            tabTop2 = tabTop + borderWidth
            tabTop3 = tabTop + borderWidth * 1.5
            tabBottom2 = self.tabBottom
            tabBottom = self.tabBottom + borderWidth

            numTabs = len(self._pageNames)
            availableWidth = hullWidth - 2 * canvasBorder - \
                numTabs * 2 * borderWidth
            x = canvasBorder
            cumTabReqWidth = 0
            cumTabWidth = 0

            # Position all the tabs.
            for pageName in self._pageNames:
                pageInfo = self._pageAttrs[pageName]
                (windowitem, lightshadow, darkshadow) = pageInfo['tabitems']
                if sumTabReqWidth <= availableWidth:
                    tabwidth = pageInfo['tabreqwidth']
                else:
                    # This ugly calculation ensures that, when the
                    # notebook is not wide enough for the requested
                    # widths of the tabs, the total width given to
                    # the tabs exactly equals the available width,
                    # without rounding errors.
                    cumTabReqWidth = cumTabReqWidth + pageInfo['tabreqwidth']
                    tmp = (2*cumTabReqWidth*availableWidth + sumTabReqWidth) \
                            / (2 * sumTabReqWidth)
                    tabwidth = tmp - cumTabWidth
                    cumTabWidth = tmp

                # Position the tab's button canvas item.
                self.coords(windowitem, x + borderWidth, tabTop3)
                self.itemconfigure(windowitem,
                    width = tabwidth, height = maxTabHeight)

                # Make a beautiful border around the tab.
                left = x
                left2 = left + borderWidth
                left3 = left + borderWidth * 1.5
                right = left + tabwidth + 2 * borderWidth
                right2 = left + tabwidth + borderWidth
                right3 = left + tabwidth + borderWidth * 0.5

                self.coords(lightshadow, 
                    left, tabBottom2, left, tabTop2, left2, tabTop,
                    right2, tabTop, right3, tabTop2, left3, tabTop2,
                    left2, tabTop3, left2, tabBottom,
                    )
                self.coords(darkshadow, 
                    right2, tabTop, right, tabTop2, right, tabBottom2,
                    right2, tabBottom, right2, tabTop3, right3, tabTop2,
                    )
                pageInfo['left'] = left
                pageInfo['right'] = right

                x = x + tabwidth + 2 * borderWidth

        # Redraw shadow under tabs so that it appears that tab for old
        # top page is lowered and that tab for new top page is raised.
        if self._withTabs and (self._pending.has_key('topPage') or
                self._pending.has_key('tabs') or self._pending.has_key('size')):

            if self.getcurselection() is None:
                # No pages, so draw line across top of page area.
                self.coords(self._pageTop1Border,
                    canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder - borderWidth,
                        self.tabBottom + borderWidth,
                    borderWidth + canvasBorder, self.tabBottom + borderWidth,
                    )

                # Ignore second top border.
                self.coords(self._pageTop2Border, 0, 0, 0, 0, 0, 0)
            else:
                # Draw two lines, one on each side of the tab for the
                # top page, so that the tab appears to be raised.
                pageInfo = self._pageAttrs[self.getcurselection()]
                left = pageInfo['left']
                right = pageInfo['right']
                self.coords(self._pageTop1Border,
                    canvasBorder, self.tabBottom,
                    left, self.tabBottom,
                    left + borderWidth, self.tabBottom + borderWidth,
                    canvasBorder + borderWidth, self.tabBottom + borderWidth,
                    )

                self.coords(self._pageTop2Border,
                    right, self.tabBottom,
                    hullWidth - canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder - borderWidth,
                        self.tabBottom + borderWidth,
                    right - borderWidth, self.tabBottom + borderWidth,
                    )

            # Prevent bottom of dark border of tabs appearing over
            # page top border.
            self.tag_raise(self._pageTop1Border)
            self.tag_raise(self._pageTop2Border)

        # Position the page border shadows.
        if self._pending.has_key('size') or oldTabBottom != self.tabBottom:

            self.coords(self._pageLeftBorder,
                canvasBorder, self.tabBottom,
                borderWidth + canvasBorder,
                    self.tabBottom + borderWidth,
                borderWidth + canvasBorder,
                    hullHeight - canvasBorder - borderWidth,
                canvasBorder, hullHeight - canvasBorder,
                )

            self.coords(self._pageBottomRightBorder,
                hullWidth - canvasBorder, self.tabBottom,
                hullWidth - canvasBorder, hullHeight - canvasBorder,
                canvasBorder, hullHeight - canvasBorder,
                borderWidth + canvasBorder,
                    hullHeight - canvasBorder - borderWidth,
                hullWidth - canvasBorder - borderWidth,
                    hullHeight - canvasBorder - borderWidth,
                hullWidth - canvasBorder - borderWidth,
                    self.tabBottom + borderWidth,
                )

            if not self._withTabs:
                self.coords(self._pageTopBorder,
                    canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder - borderWidth,
                        self.tabBottom + borderWidth,
                    borderWidth + canvasBorder, self.tabBottom + borderWidth,
                    )

        # Color borders.
        if self._pending.has_key('borderColor'):
            self.itemconfigure('lighttag', fill = self._lightBorderColor)
            self.itemconfigure('darktag', fill = self._darkBorderColor)

        newTopPage = self._pending.get('topPage')
        pageBorder = borderWidth + self._pageMargin

        # Raise new top page.
        if newTopPage is not None:
            self._topPageName = newTopPage
            self._topPageItem = self.create_window(
                pageBorder + canvasBorder, self.tabBottom + pageBorder,
                window = self._pageAttrs[newTopPage]['page'],
                anchor = 'nw',
                )

        # Change position of top page if tab height has changed.
        if self._topPageName is not None and oldTabBottom != self.tabBottom:
            self.coords(self._topPageItem,
                    pageBorder + canvasBorder, self.tabBottom + pageBorder)

        # Change size of top page if,
        #   1) there is a new top page.
        #   2) canvas size has changed, but not if there is no top
        #      page (eg:  initially or when all pages deleted).
        #   3) tab height has changed, due to difference in the height of a tab
        if (newTopPage is not None or \
                self._pending.has_key('size') and self._topPageName is not None
                or oldTabBottom != self.tabBottom):
            self.itemconfigure(self._topPageItem,
                width = hullWidth - 2 * canvasBorder - pageBorder * 2,
                height = hullHeight - 2 * canvasBorder - pageBorder * 2 -
                    (self.tabBottom - canvasBorder),
                )

        self._pending = {}

# Need to do forwarding to get the pack, grid, etc methods. 
# Unfortunately this means that all the other canvas methods are also
# forwarded.
Pmw.forwardmethods(NoteBook, Tkinter.Canvas, '_hull')
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.