diff --git a/direct/src/tkwidgets/AppShell.py b/direct/src/tkwidgets/AppShell.py new file mode 100644 index 0000000000..e3cdcf8072 --- /dev/null +++ b/direct/src/tkwidgets/AppShell.py @@ -0,0 +1,277 @@ +""" +AppShell provides a GUI application framework. +This is an adaption of AppShell.py found in Python and Tkinter Programming +by John E. Grayson which is a streamlined adaptation of GuiAppD.py, originally +created by Doug Hellmann (doughellmann@mindspring.com). +""" + +from PandaObject import * +from Tkinter import * +import Pmw +import sys, string +import ProgressBar + +class AppShell(Pmw.MegaToplevel, PandaObject): + appversion = '1.0' + appname = 'Generic Application Frame' + copyright = ('Copyright 2001 Walt Disney Imagineering.' + + ' All Rights Reserved') + contactname = 'Mark R. Mine' + contactphone = '(818) 544-2921' + contactemail = 'Mark.Mine@disney.com' + + frameWidth = 450 + frameHeight = 320 + padx = 5 + pady = 5 + usecommandarea = 0 + usestatusarea = 0 + balloonState = 'none' + + def __init__(self, parent = None, **kw): + optiondefs = ( + ('title', self.appname, None), + ('padx', 1, Pmw.INITOPT), + ('pady', 1, Pmw.INITOPT), + ('framewidth', self.frameWidth, Pmw.INITOPT), + ('frameheight', self.frameHeight, Pmw.INITOPT), + ('usecommandarea', self.usecommandarea, Pmw.INITOPT), + ('usestatusarea', self.usestatusarea, Pmw.INITOPT), + ) + self.defineoptions(kw, optiondefs) + # Initialize the base class + Pmw.MegaToplevel.__init__(self, parent) + # Set window size + self.geometry('%dx%d' % (self.frameWidth, self.frameHeight)) + # Get handle to the toplevels hull + self._hull = self.component('hull') + # Initialize the application + self.appInit() + # create the interface + self.__createInterface() + # Set focus to ourselves + self.focus_set() + # initialize our options + self.initialiseoptions(AppShell) + + def __createInterface(self): + self.__createBalloon() + self.__createMenuBar() + self.__createDataArea() + self.__createCommandArea() + self.__createMessageBar() + self.__createAboutBox() + # + # Create the parts of the interface + # which can be modified by subclasses + # + self.createMenuBar() + self.createInterface() + + def __createBalloon(self): + # Create the balloon help manager for the frame. + # Create the manager for the balloon help + self.__balloon = self.createcomponent('balloon', (), None, + Pmw.Balloon, (self._hull,)) + self.__balloon.configure(state = self.balloonState) + + def __createMenuBar(self): + self.menuFrame = Frame(self._hull) + self.menuBar = self.createcomponent('menubar', (), None, + Pmw.MenuBar, + (self.menuFrame,), + hull_relief=RAISED, + hull_borderwidth=1, + balloon=self.balloon()) + + self.menuBar.addmenu('Help', 'About %s' % self.appname, side = 'right') + self.menuBar.addmenu('File', 'File commands and Quit') + self.menuBar.pack(fill=X, side = LEFT) + self.menuFrame.pack(fill = X) + + def __createDataArea(self): + # Create data area where data entry widgets are placed. + self.dataArea = self.createcomponent('dataarea', + (), None, + Frame, (self._hull,), + relief=GROOVE, + bd=1) + self.dataArea.pack(side=TOP, fill=BOTH, expand=YES, + padx=self['padx'], pady=self['pady']) + + def __createCommandArea(self): + # Create a command area for application-wide buttons. + self.__commandFrame = self.createcomponent('commandframe', (), None, + Frame, + (self._hull,), + relief=SUNKEN, + bd=1) + self.__buttonBox = self.createcomponent('buttonbox', (), None, + Pmw.ButtonBox, + (self.__commandFrame,), + padx=0, pady=0) + self.__buttonBox.pack(side=TOP, expand=NO, fill=X) + if self['usecommandarea']: + self.__commandFrame.pack(side=TOP, + expand=NO, + fill=X, + padx=self['padx'], + pady=self['pady']) + + + def __createMessageBar(self): + # Create the message bar area for help and status messages. + frame = self.createcomponent('bottomtray', (), None, + Frame,(self._hull,), relief=SUNKEN) + self.__messageBar = self.createcomponent('messagebar', + (), None, + Pmw.MessageBar, + (frame,), + #entry_width = 40, + entry_relief=SUNKEN, + entry_bd=1, + labelpos=None) + self.__messageBar.pack(side=LEFT, expand=YES, fill=X) + + self.__progressBar = ProgressBar.ProgressBar( + frame, + fillColor='slateblue', + doLabel=1, + width=150) + self.__progressBar.frame.pack(side=LEFT, expand=NO, fill=NONE) + + self.updateProgress(0) + if self['usestatusarea']: + frame.pack(side=BOTTOM, expand=NO, fill=X) + + self.__balloon.configure(statuscommand = \ + self.__messageBar.helpmessage) + + def __createAboutBox(self): + Pmw.aboutversion(self.appversion) + Pmw.aboutcopyright(self.copyright) + Pmw.aboutcontact( + 'For more information, contact:\n %s\n Phone: %s\n Email: %s' %\ + (self.contactname, self.contactphone, + self.contactemail)) + self.about = Pmw.AboutDialog(self._hull, + applicationname=self.appname) + self.about.withdraw() + return None + + def toggleBalloon(self): + if self.toggleBalloonVar.get(): + self.__balloon.configure(state = 'both') + else: + self.__balloon.configure(state = 'status') + + def showAbout(self): + # Create the dialog to display about and contact information. + self.about.show() + self.about.focus_set() + + def quit(self): + self.destroy() + + ### USER METHODS ### + # To be overridden + def appInit(self): + # Called before interface is created (should be overridden). + pass + + def createInterface(self): + # Override this method to create the interface for the app. + pass + + def createMenuBar(self): + # Creates default menus. Can be overridden or simply augmented + # Using button Add below + self.menuBar.addmenuitem('Help', 'command', + 'Get information on application', + label='About...', command=self.showAbout) + self.toggleBalloonVar = IntVar() + if self.balloonState == 'none': + self.toggleBalloonVar.set(0) + else: + self.toggleBalloonVar.set(1) + self.menuBar.addmenuitem('Help', 'checkbutton', + 'Toggle balloon help', + label='Balloon help', + variable = self.toggleBalloonVar, + command=self.toggleBalloon) + + self.menuBar.addmenuitem('File', 'command', 'Quit this application', + label='Quit', + command=self.quit) + + # Utility functions + def buttonAdd(self, buttonName, helpMessage=None, + statusMessage=None, **kw): + # Add a button to the button box. + newBtn = self.__buttonBox.add(buttonName) + newBtn.configure(kw) + if helpMessage: + self.bind(newBtn, helpMessage, statusMessage) + return newBtn + + def alignbuttons(self): + """ Make all buttons wide as widest """ + self.__buttonBox.alignbuttons() + + def bind(self, child, balloonHelpMsg, statusHelpMsg=None): + # Bind a help message and/or status message to a widget. + self.__balloon.bind(child, balloonHelpMsg, statusHelpMsg) + + def updateProgress(self, newValue=0, newMax=0): + # Used to update progress bar + self.__progressBar.updateProgress(newValue, newMax) + + # Getters + def interior(self): + # Retrieve the interior site where widgets should go. + return self.dataArea + + def balloon(self): + # Retrieve the panel's balloon widget + return self.__balloon + + def buttonBox(self): + # Retrieve the button box. + return self.__buttonBox + + def messageBar(self): + # Retieve the message bar + return self.__messageBar + +class TestAppShell(AppShell): + # Override class variables here + appname = 'Test Application Shell' + usecommandarea = 1 + usestatusarea = 1 + + def __init__(self, parent = None, **kw): + # Call superclass initialization function + AppShell.__init__(self) + self.initialiseoptions(TestAppShell) + + def createButtons(self): + self.buttonAdd('Ok', + helpMessage='Exit', + statusMessage='Exit', + command=self.quit) + + def createMain(self): + self.label = self.createcomponent('label', (), None, + Label, + (self.interior(),), + text='Data Area') + self.label.pack() + self.bind(self.label, 'Space taker') + + def createInterface(self): + self.createButtons() + self.createMain() + +if __name__ == '__main__': + test = TestAppShell(balloon_state='none') + diff --git a/direct/src/tkwidgets/ProgressBar.py b/direct/src/tkwidgets/ProgressBar.py new file mode 100644 index 0000000000..b794ec0c7f --- /dev/null +++ b/direct/src/tkwidgets/ProgressBar.py @@ -0,0 +1,79 @@ +""" +A basic widget for showing the progress being made in a task. +""" +from Tkinter import * + +class ProgressBar: + def __init__(self, master=None, orientation="horizontal", + min=0, max=100, width=100, height=18, + doLabel=1, appearance="sunken", + fillColor="blue", background="gray", + labelColor="yellow", labelFont="Verdana", + labelText="", labelFormat="%d%%", + value=50, bd=2): + # preserve various values + self.master=master + self.orientation=orientation + self.min=min + self.max=max + self.width=width + self.height=height + self.doLabel=doLabel + self.fillColor=fillColor + self.labelFont= labelFont + self.labelColor=labelColor + self.background=background + self.labelText=labelText + self.labelFormat=labelFormat + self.value=value + self.frame=Frame(master, relief=appearance, bd=bd) + self.canvas=Canvas(self.frame, height=height, width=width, bd=0, + highlightthickness=0, background=background) + self.scale=self.canvas.create_rectangle(0, 0, width, height, + fill=fillColor) + self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2, + height / 2, text=labelText, + anchor="c", fill=labelColor, + font=self.labelFont) + self.update() + self.canvas.pack(side='top', fill='x', expand='no') + + def updateProgress(self, newValue, newMax=None): + if newMax: + self.max = newMax + self.value = newValue + self.update() + + def update(self): + # Trim the values to be between min and max + value=self.value + if value > self.max: + value = self.max + if value < self.min: + value = self.min + # Adjust the rectangle + if self.orientation == "horizontal": + self.canvas.coords(self.scale, 0, 0, + float(value) / self.max * self.width, self.height) + else: + self.canvas.coords(self.scale, 0, + self.height - (float(value) / self.max*self.height), + self.width, self.height) + # Now update the colors + self.canvas.itemconfig(self.scale, fill=self.fillColor) + self.canvas.itemconfig(self.label, fill=self.labelColor) + # And update the label + if self.doLabel: + if value: + if value >= 0: + pvalue = int((float(value) / float(self.max)) * 100.0) + else: + value = 0 + self.canvas.itemconfig(self.label, + text=self.labelFormat % value) + else: + self.canvas.itemconfig(self.label, text='') + else: + self.canvas.itemconfig(self.label, + text=self.labelFormat % self.labelText) + self.canvas.update_idletasks()