#######################################################################
# File: PmwNoteBook.py
# Author: Joseph A. Saltiel - jsaltiel@lucent.com
# References: Pmw.0.4
# Modules: Tkinter, Pmw, string
# PmwNoteBook - This is a NoteBook Mega Widget made for Python.
# It is based on the framework and essentially is
# an extension of PMW (Python Mega Widgets). It
# allows the user to create a notebook, add and del
# pages. A page is a frame and the user can grab
# and put additional widgets on to it.
#
# Copyright (C) 1997 by Lucent Technologies, Inc. & Joseph Saltiel
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#######################################################################
import Tkinter
import Pmw
import string
##################################################################
# Class: NoteBook
# Description: This defines the notebook widget. This includes
# its subcomponents and attributes.
##################################################################
class NoteBookS(Pmw.MegaWidget):
def __init__(self, parent = None, **kw):
# Define the megawidget options.
INITOPT = Pmw.INITOPT
optiondefs = (
('tabColor', 'blue', None),
('canvasColor', 'white', None),
('activeColor', 'red', None),
('deactiveColor', 'grey', None),
('shadeColor', '#666666', None),
('textColor', 'black', None),
('textFont', '-*-helvetica-bold-r-normal--10-*-*-*-*-*', self._setFontLength),
('longX', 30, INITOPT),
('shortX', 7, INITOPT),
('longY', 35, INITOPT),
('shortY', 7, INITOPT),
('offsetY', 5, INITOPT),
('canvasHeight', 250, self._adjustHeight),
('canvasWidth', 400, self._adjustWidth),
('tabHeight', 40, INITOPT),
)
self.defineoptions(kw, optiondefs)
# Initialise the base class (after defining the options).
Pmw.MegaWidget.__init__(self, parent)
# Create the components.
interior = self.interior()
# Create the canvas widget.
self._mainCanvas = self.createcomponent('mainCanvas',
(), None,
Tkinter.Canvas, (interior,),
bg=self['canvasColor'], height=self['canvasHeight'],
width=self['canvasWidth'], highlightthickness=0,
bd=2, relief='raised')
self._mainCanvas.grid(sticky = 'news', ipadx=2, ipady=2)
# Create the tab canvas widget.
self._tabCanvas = self.createcomponent('tabCanvas',
(), None,
Tkinter.Canvas, (self._mainCanvas,),
bg=self['tabColor'], height=self['tabHeight'],
highlightthickness=0)
self._tabCanvas.grid(row=0, column=0, sticky = 'news')
# Create the container canvas widget.
self._containerCanvas = self.createcomponent('containerCanvas',
(), None,
Tkinter.Canvas, (self._mainCanvas,),
bg=self['activeColor'], highlightthickness=0,
height=self['canvasHeight'] - self['offsetY'] - self['longY'],
width=self['canvasWidth'])
self._containerCanvas.grid(row=1, column=0, sticky='news')
# Initialise instance variables.
self._tabOrder = []
self._pages = {}
self._containers = {}
self._tabNames = {}
self._shade = {}
self._activePage = None
self._numofPages = 0
self._fontLength = 10
self._offsetX = 10
self._lineBorder = self._tabCanvas.create_line(0, self['tabHeight']-1, self._tabCanvas.winfo_reqwidth(), self['tabHeight']-1, fill=self['shadeColor'])
self._mutex = 1
# Check keywords and initialise options.
self.initialiseoptions(NoteBookS)
#**********************************************************************
# CONFIGURATION METHODS
#**********************************************************************
##################################################################
# Method: _setFontLength
# Description: This sets the font length. The font length is based
# on the font type used. This determines how many
# characters may fit on a tab.
##################################################################
def _setFontLength(self):
try:
length = string.atoi(string.splitfields(self['textFont'], '-')[7])
self._fontLength = length
except:
message = 'Invalid Font specified. The 8th field, point size, must be specified'
raise ValueError, message
##################################################################
# Method: _tabSelect
# Description: When a tab is selected, we raise it and lower the
# the other tabs.
##################################################################
def _tabSelect(self, event=None):
if self._mutex:
for item in self._containers.keys():
self._containers[item].grid_forget()
for item in self._pages.keys():
if ((event==None) and (self._activePage != item)) or ((event) and (event.widget.gettags(self._pages[item])) == () and (event.widget.gettags(self._tabNames[item])) == ()):
self._tabCanvas.itemconfigure(self._pages[item], fill=self['deactiveColor'], outline=self['deactiveColor'])
self._tabCanvas.lower(self._pages[item])
else:
self.raisePage(item, select=None)
##################################################################
# Method: _adjustHeight
# Description: When the user changes the notebook height, we must make
# sure that information gets propageted to the proper components.
##################################################################
def _adjustHeight(self):
frameHeight = self['canvasHeight'] - self['offsetY'] - self['longY']
self._mainCanvas.configure(height=self['canvasHeight'])
self._mainCanvas.grid_rowconfigure(1, minsize=frameHeight)
self._containerCanvas.grid_rowconfigure(0, minsize=frameHeight)
##################################################################
# Method: _adjustWidth
# Description: When the user changes the notebook width, we must make
# sure that information gets propageted to the proper components.
##################################################################
def _adjustWidth(self):
self._mainCanvas.configure(width=self['canvasWidth'])
self._containerCanvas.grid_columnconfigure(0, minsize=self['canvasWidth'])
#**********************************************************************
# PRIVATE METHODS
#**********************************************************************
##################################################################
# Method: _getOffset
# Description: This determines where to draw a tab name on the tab
##################################################################
def _getOffset(self, name):
length = len(name)
if length > (self['longX'] / self._fontLength):
width = length * self._fontLength
else:
width = self['longX']
coords = (self._offsetX, self['longY']+self['offsetY'], self._offsetX, self['shortY']+self['offsetY'], self['shortX'] + self._offsetX, self['offsetY'], width + self._offsetX - self['shortX'], self['offsetY'], width+self._offsetX, self['shortY']+self['offsetY'], self._offsetX+width, self['offsetY']+self['longY'])
startX = self._offsetX+width/2
startY = self['offsetY']+self['longY']/2
self._offsetX = self._offsetX+width+4
return coords, startX, startY
##################################################################
# Method: _drawTab
# Description: This draws the tab on the tab Canvas
##################################################################
def _drawTab(self, name):
self._tabSelect()
coords, startX, startY = self._getOffset(name)
node = self._tabCanvas.create_polygon(coords, fill=self['activeColor'], outline=self['shadeColor'])
pageText = self._tabCanvas.create_text(startX, startY, text=name, fill=self['textColor'], font=self['textFont'])
self._lineBorder = self._tabCanvas.create_line(0, self['tabHeight']-1, self._tabCanvas.winfo_width(), self['tabHeight']-1, fill=self['shadeColor'])
self._tabCanvas.tag_bind(pageText, "", self._tabSelect)
self._tabCanvas.tag_bind(node, "", self._tabSelect)
self._pages[name] = node
self._tabNames[name] = pageText
#**********************************************************************
# PUBLIC METHODS
#**********************************************************************
##################################################################
# Method: addPage
# Description: The user calls this to add a page/tab
##################################################################
def addPage(self, name):
if self._tabNames.has_key(name):
message = 'Tab name already exists'
raise NameError, message
self._activePage = name
self._drawTab(name)
frame = Tkinter.Frame(self._containerCanvas, bg=self['activeColor'],
height=self['canvasHeight'] - self['offsetY'] - self['longY'])
frame.grid(row=0, column=0, sticky='news')
self._numofPages = self._numofPages + 1
self._tabOrder.append(name)
self._containers[name] = frame
##################################################################
# Method: delPage
# Description: The user calls this to delete a page/tab
##################################################################
def delPage (self, name):
if not(self._tabNames.has_key(name)):
message = 'That tab name does not exist'
raise KeyError, message
for item in self._tabOrder:
self._tabCanvas.delete(self._pages[item], self._tabNames[item])
self._tabCanvas.dtag(self._pages[item], self._tabNames[item])
self._tabOrder.remove(name)
self._containers[name].destroy()
del self._pages[name]
del self._tabNames[name]
del self._containers[name]
self._numofPages = self._numofPages - 1
self._offsetX = 10
for each in self._tabOrder:
self._drawTab(each)
if self._numofPages > 0:
self.raisePage(each)
##################################################################
# Method: getPage
# Description: Given a name, returns that frame(page) to the user
##################################################################
def getPage(self, name):
if self._containers.has_key(name):
return self._containers[name]
else:
message = 'That page does not exist'
raise KeyError, message
##################################################################
# Method: pages
# Description: Returns a list of frames(pages) on the current notebook
##################################################################
def pages(self):
lst = []
for item in self._containers.keys():
lst.append(self._containers[item])
return lst
##################################################################
# Method: raisePage
# Description: Raises the given tab name
##################################################################
def raisePage(self, name, select=1):
if select:
if not(self._pages.has_key(name)):
message = 'That page does not exist'
raise KeyError, message
self._tabSelect()
self._activePage = name
self._containers[name].grid(row=0, column=0, sticky='news')
self._tabCanvas.itemconfigure(self._pages[name], fill=self['activeColor'], outline=self['shadeColor'])
self._tabCanvas.lift(self._pages[name])
self._tabCanvas.lift(self._tabNames[name])
##################################################################
# Method: raised
# Description: Returns the name of the currently raised tab
##################################################################
def raised(self):
return self._activePage
##################################################################
# Method: pageNames
# Description: Returns a list of the all the page names
##################################################################
def pageNames(self):
return self._pages.keys()
##################################################################
# Method: unBind
# Description: Unbind the notebooks bindings
##################################################################
def unBind(self):
self._mutex = 0
##################################################################
# Method: reBind
# Description: Re bind the notebooks bindings
##################################################################
def reBind(self):
self._mutex = 1