source: anuga_core/source/anuga/pmesh/AppShell.py @ 4522

Last change on this file since 4522 was 3492, checked in by duncan, 18 years ago

Cleaning things up

File size: 13.5 KB
Line 
1#! /usr/env/python
2
3"""
4AppShell provides a GUI application framework.
5
6This is a streamlined adaptation of GuiAppD.py, originally
7created by Doug Hellmann (doughellmann@mindspring.com).
8
9Pmw copyright
10
11Copyright 1997-1999 Telstra Corporation Limited,
12Australia Copyright 2000-2002 Really Good Software Pty Ltd, Australia
13
14Permission is hereby granted, free of charge, to any person obtaining
15a copy of this software and associated documentation files (the
16"Software"), to deal in the Software without restriction, including
17without limitation the rights to use, copy, modify, merge, publish,
18distribute, sublicense, and/or sell copies of the Software, and to
19permit persons to whom the Software is furnished to do so, subject to
20the following conditions:
21
22The above copyright notice and this permission notice shall be
23included in all copies or substantial portions of the Software.
24
25THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
33"""
34
35
36from Tkinter import *
37import Pmw
38import sys, string
39import ProgressBar
40
41class AppShell(Pmw.MegaWidget):       
42    appversion      = '1.0'
43    appname         = 'Generic Application Frame'
44    copyright       = 'Copyright YYYY Your Company. All Rights Reserved'
45    contactname     = 'Your Name'
46    contactphone    = '(999) 555-1212'
47    contactemail    = 'youremail@host.com'
48         
49    frameWidth      = 450
50    frameHeight     = 320
51    padx            = 5
52    pady            = 5
53    usecommandarea  = 0
54    balloonhelp     = 1
55   
56    busyCursor = 'watch'
57   
58    def __init__(self, **kw):
59        optiondefs = (
60            ('padx',           1,                   Pmw.INITOPT),
61            ('pady',           1,                   Pmw.INITOPT),
62            ('framewidth',     1,                   Pmw.INITOPT),
63            ('frameheight',    1,                   Pmw.INITOPT),
64            ('usecommandarea', self.usecommandarea, Pmw.INITOPT))
65        self.defineoptions(kw, optiondefs)
66       
67        self.root = Tk()
68        self.initializeTk(self.root)
69        Pmw.initialise(self.root)
70        self.root.title(self.appname)
71        self.root.geometry('%dx%d' % (self.frameWidth, self.frameHeight))
72
73        # Initialize the base class
74        Pmw.MegaWidget.__init__(self, parent=self.root)
75       
76        # initialize the application
77        self.appInit()
78       
79        # create the interface
80        self.__createInterface()
81       
82        # create a table to hold the cursors for
83        # widgets which get changed when we go busy
84        self.preBusyCursors = None
85       
86        # pack the container and set focus
87        # to ourselves
88        self._hull.pack(side=TOP, fill=BOTH, expand=YES)
89        self.focus_set()
90
91        # initialize our options
92        self.initialiseoptions(AppShell)
93       
94    def appInit(self):
95        # Called before interface is created (should be overridden).
96        pass
97       
98    def initializeTk(self, root):
99        # Initialize platform-specific options
100        if sys.platform == 'mac':
101            self.__initializeTk_mac(root)
102        elif sys.platform == 'win32':
103            self.__initializeTk_win32(root)
104        else:
105            self.__initializeTk_unix(root)
106
107    def __initializeTk_colors_common(self, root):
108        root.option_add('*background', 'grey')
109        root.option_add('*foreground', 'black')
110        root.option_add('*EntryField.Entry.background', 'white')
111        root.option_add('*Entry.background', 'white')       
112        root.option_add('*MessageBar.Entry.background', 'gray85')
113        root.option_add('*Listbox*background', 'white')
114        root.option_add('*Listbox*selectBackground', 'dark slate blue')
115        root.option_add('*Listbox*selectForeground', 'white')
116                       
117    def __initializeTk_win32(self, root):
118        self.__initializeTk_colors_common(root)
119        root.option_add('*Font', 'Verdana 10 bold')
120        root.option_add('*EntryField.Entry.Font', 'Courier 10')
121        root.option_add('*Listbox*Font', 'Courier 10')
122       
123    def __initializeTk_mac(self, root):
124        self.__initializeTk_colors_common(root)
125       
126    def __initializeTk_unix(self, root):
127        self.__initializeTk_colors_common(root)
128
129    def busyStart(self, newcursor=None):
130        if not newcursor:
131            newcursor = self.busyCursor
132        newPreBusyCursors = {}
133        for component in self.busyWidgets:
134            newPreBusyCursors[component] = component['cursor']
135            component.configure(cursor=newcursor)
136            component.update_idletasks()
137        self.preBusyCursors = (newPreBusyCursors, self.preBusyCursors)
138       
139    def busyEnd(self):
140        if not self.preBusyCursors:
141            return
142        oldPreBusyCursors = self.preBusyCursors[0]
143        self.preBusyCursors = self.preBusyCursors[1]
144        for component in self.busyWidgets:
145            try:
146                component.configure(cursor=oldPreBusyCursors[component])
147            except KeyError:
148                pass
149            component.update_idletasks()
150             
151    def __createAboutBox(self):
152        Pmw.aboutversion(self.appversion)
153        Pmw.aboutcopyright(self.copyright)
154        Pmw.aboutcontact(
155          'For more information, contact:\n %s\n Phone: %s\n Email: %s' %\
156                      (self.contactname, self.contactphone, 
157                       self.contactemail))
158        self.about = Pmw.AboutDialog(self._hull, 
159                                     applicationname=self.appname)
160        self.about.withdraw()
161        return None
162       
163    def showAbout(self):
164        # Create the dialog to display about and contact information.
165        self.about.show()
166        self.about.focus_set()
167       
168    def toggleBalloon(self):
169        if self.toggleBalloonVar.get():
170            self.__balloon.configure(state = 'both')
171        else:
172            self.__balloon.configure(state = 'status')
173
174    def __createMenuBar(self):
175        self.menuBar = self.createcomponent('menubar', (), None,
176                                            Pmw.MenuBar,
177                                            (self._hull,),
178                                            hull_relief=RAISED,
179                                            hull_borderwidth=1,
180                                            balloon=self.balloon())
181
182        self.menuBar.pack(fill=X)
183        self.menuBar.addmenu('Help', 'About %s' % self.appname, side='right')
184        self.menuBar.addmenu('File', 'File commands and Quit')
185                           
186    def createMenuBar(self):
187        self.menuBar.addmenuitem('Help', 'command',
188                                 'Get information on application', 
189                                 label='About...', command=self.showAbout)
190        self.toggleBalloonVar = IntVar()
191        self.toggleBalloonVar.set(1)
192        self.menuBar.addmenuitem('Help', 'checkbutton',
193                                 'Toggle balloon help',
194                                 label='Balloon help',
195                                 variable = self.toggleBalloonVar,
196                                 command=self.toggleBalloon)
197
198        self.menuBar.addmenuitem('File', 'command', 'Quit this application',
199                                label='Quit',
200                                command=self.quit)
201                                       
202    def __createBalloon(self):
203        # Create the balloon help manager for the frame.
204        # Create the manager for the balloon help
205        self.__balloon = self.createcomponent('balloon', (), None,
206                                              Pmw.Balloon, (self._hull,))
207
208    def balloon(self):
209        return self.__balloon
210
211    def __createDataArea(self):
212        # Create data area where data entry widgets are placed.
213        self.dataArea = self.createcomponent('dataarea',
214                                             (), None,
215                                             Frame, (self._hull,), 
216                                             relief=GROOVE, 
217                                             bd=1)
218        self.dataArea.pack(side=TOP, fill=BOTH, expand=YES,
219                           padx=self['padx'], pady=self['pady'])
220
221    def __createCommandArea(self):
222        # Create a command area for application-wide buttons.
223        self.__commandFrame = self.createcomponent('commandframe', (), None,
224                                                   Frame,
225                                                   (self._hull,),
226                                                   relief=SUNKEN,
227                                                   bd=1)
228        self.__buttonBox = self.createcomponent('buttonbox', (), None,
229                                                Pmw.ButtonBox,
230                                                (self.__commandFrame,),
231                                                padx=0, pady=0)
232        self.__buttonBox.pack(side=TOP, expand=NO, fill=X)
233        if self['usecommandarea']:
234            self.__commandFrame.pack(side=TOP, 
235                                     expand=NO, 
236                                     fill=X,
237                                     padx=self['padx'],
238                                     pady=self['pady'])
239
240
241    def __createMessageBar(self):
242        # Create the message bar area for help and status messages.
243        frame = self.createcomponent('bottomtray', (), None,
244                                     Frame,(self._hull,), relief=SUNKEN)
245        self.__messageBar = self.createcomponent('messagebar',
246                                                  (), None,
247                                                 Pmw.MessageBar, 
248                                                 (frame,),
249                                                 #entry_width = 40,
250                                                 entry_relief=SUNKEN,
251                                                 entry_bd=1,
252                                                 labelpos=None)
253        self.__messageBar.pack(side=LEFT, expand=YES, fill=X)
254
255        self.__progressBar = ProgressBar.ProgressBar(frame,
256                                                fillColor='slateblue',
257                                                doLabel=1,
258                                                width=150)
259        self.__progressBar.frame.pack(side=LEFT, expand=NO, fill=NONE)
260
261        self.updateProgress(0)
262        frame.pack(side=BOTTOM, expand=NO, fill=X)
263                   
264        self.__balloon.configure(statuscommand = \
265                                 self.__messageBar.helpmessage)
266
267    def messageBar(self):
268        return self.__messageBar
269
270    def updateProgress(self, newValue=0, newMax=0):
271        self.__progressBar.updateProgress(newValue, newMax)
272
273    def bind(self, child, balloonHelpMsg, statusHelpMsg=None):
274        # Bind a help message and/or status message to a widget.
275        self.__balloon.bind(child, balloonHelpMsg, statusHelpMsg)
276
277    def interior(self):
278        # Retrieve the interior site where widgets should go.
279        return self.dataArea
280
281    def buttonBox(self):
282        # Retrieve the button box.
283        return self.__buttonBox
284
285    def buttonAdd(self, buttonName, helpMessage=None,
286                  statusMessage=None, **kw):
287        # Add a button to the button box.
288        newBtn = self.__buttonBox.add(buttonName)
289        newBtn.configure(kw)
290        if helpMessage:
291             self.bind(newBtn, helpMessage, statusMessage)
292        return newBtn
293
294    def __createInterface(self):
295        self.__createBalloon()
296        self.__createMenuBar()
297        self.__createDataArea()
298        self.__createCommandArea()
299        self.__createMessageBar()
300        self.__createAboutBox()
301        #
302        # Create the parts of the interface
303        # which can be modified by subclasses
304        #
305        self.busyWidgets = ( self.root, )
306        self.createMenuBar()
307        self.createInterface()
308
309    def createInterface(self):
310        # Override this method to create the interface for the app.
311        pass
312       
313    def main(self):
314        # This method should be left intact!
315        self.pack()
316        self.mainloop()
317       
318    def run(self):
319        self.main()
320
321class TestAppShell(AppShell):
322        usecommandarea=1
323       
324        def createButtons(self):
325                self.buttonAdd('Ok',
326                        helpMessage='Exit',
327                        statusMessage='Exit',
328                        command=self.quit)
329       
330        def createMain(self):
331                self.label = self.createcomponent('label', (), None,
332                                        Label,
333                                        (self.interior(),),
334                                        text='Data Area')
335                self.label.pack()
336                self.bind(self.label, 'Space taker')
337               
338        def createInterface(self):
339                AppShell.createInterface(self)
340                self.createButtons()
341                self.createMain()
342       
343if __name__ == '__main__':
344        test = TestAppShell(balloon_state='both')
345        test.run()
Note: See TracBrowser for help on using the repository browser.