]> SALOME platform Git repositories - modules/eficas.git/commitdiff
Salome HOME
*** empty log message ***
authoreficas <>
Tue, 17 May 2005 11:54:51 +0000 (11:54 +0000)
committereficas <>
Tue, 17 May 2005 11:54:51 +0000 (11:54 +0000)
253 files changed:
Accas/A_AU_PLUS_UN.py [new file with mode: 0644]
Accas/__init__.py
Aster/Cata/Macro/__init__.py
Aster/Cata/Macro/calc_fonction_ops.py [new file with mode: 0644]
Aster/Cata/Macro/calc_precont_ops.py
Aster/Cata/Macro/impr_fonction_ops.py
Aster/Cata/Macro/impr_table_ops.py
Aster/Cata/Macro/info_fonction_ops.py [new file with mode: 0644]
Aster/Cata/Macro/macr_ascouf_calc_ops.py
Aster/Cata/Macro/macr_ascouf_mail_ops.py
Aster/Cata/Macro/macr_aspic_calc_ops.py
Aster/Cata/Macro/macr_cabri_mail_ops.py
Aster/Cata/Macro/macr_fiab_impr_ops.py
Aster/Cata/Macro/macr_lign_coupe_ops.py
Aster/Cata/Macro/macr_recal_ops.py
Aster/Cata/Macro/macro_cara_poutre_ops.py [deleted file]
Aster/Cata/Macro/macro_matr_asse_ops.py
Aster/Cata/Macro/pre_gmsh_ops.py [deleted file]
Aster/Cata/Macro/reca_algo.py
Aster/Cata/Macro/recal.py
Pmw/Alpha_99_9_example/__init__.py [new file with mode: 0644]
Pmw/Alpha_99_9_example/lib/Pmw.def [new file with mode: 0644]
Pmw/Alpha_99_9_example/lib/PmwAlphaExample.py [new file with mode: 0644]
Pmw/Alpha_99_9_example/lib/__init__.py [new file with mode: 0644]
Pmw/Pmw_1_2/__init__.py [new file with mode: 0644]
Pmw/Pmw_1_2/bin/bundlepmw.py [new file with mode: 0755]
Pmw/Pmw_1_2/contrib/DirBrowser.py [new file with mode: 0644]
Pmw/Pmw_1_2/contrib/MCListbox.py [new file with mode: 0644]
Pmw/Pmw_1_2/contrib/PmwFileDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/contrib/PmwFullTimeCounter.py [new file with mode: 0644]
Pmw/Pmw_1_2/contrib/PmwVerticalGauge.py [new file with mode: 0644]
Pmw/Pmw_1_2/contrib/README [new file with mode: 0644]
Pmw/Pmw_1_2/contrib/TreeBrowser.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/AboutDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/All.py [new file with mode: 0755]
Pmw/Pmw_1_2/demos/Args.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Balloon.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/BltGraph.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/BltTabset.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ButtonBox.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Colors.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ComboBox.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ComboBoxDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ConfigClass.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Counter.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/CounterDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/DemoVersion.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Dialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/EntryField.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ErrorHandling.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ExampleDemo.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Grid.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Group.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/HistoryText.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/LabeledWidget.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/LogicalFont.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/MainMenuBar.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/MenuBar.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/MessageBar.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/MessageDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/MessageInfo.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/MultiLineLabel.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/NestedDialogs.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/NoteBook.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/NoteBook_2.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/NoteBook_3.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/OptionMenu.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/PanedWidget.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/PanedWidget_2.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/PromptDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/RadioSelect.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Resources.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Resources_Pmw.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ScrolledCanvas.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ScrolledField.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ScrolledFrame.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ScrolledListBox.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ScrolledText.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ScrolledText_2.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/SelectionDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/ShowBusy.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/SpecialCounter.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/SpecialEntry.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/Spectrum.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/SpeedTest.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/SubClassing.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/TextDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/TextDisplay.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/TimeCounter.py [new file with mode: 0644]
Pmw/Pmw_1_2/demos/WidgetDestroy.py [new file with mode: 0644]
Pmw/Pmw_1_2/doc/AboutDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/AboutDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Balloon.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Balloon.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Blt.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ButtonBox.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ButtonBox.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Color.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ComboBox.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ComboBox.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ComboBoxDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ComboBoxDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Counter.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Counter.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/CounterDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/CounterDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Dialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Dialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/EntryField.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/EntryField.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ExampleDemo.py [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Group.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/Group.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/HistoryText.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/HistoryText.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/LabeledWidget.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/LabeledWidget.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MainMenuBar.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MainMenuBar.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MegaArchetype.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MegaToplevel.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MegaWidget.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MenuBar.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MenuBar.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MessageBar.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MessageBar.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MessageDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/MessageDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/NoteBook.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/NoteBook.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/OptionMenu.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/OptionMenu.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/PanedWidget.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/PanedWidget.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/PmwFunctions.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/PromptDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/PromptDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/RadioSelect.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/RadioSelect.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledCanvas.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledCanvas.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledField.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledField.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledFrame.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledFrame.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledListBox.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledListBox.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledText.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledText.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/ScrolledText_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/doc/SelectionDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/SelectionDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/TextDialog.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/TextDialog.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/TimeCounter.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/TimeCounter.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/blue_line.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/blueball.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/bugs.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/changes.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/copyright.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/counter1.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/counter2.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/demosandtests.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/dynamicloader.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/example.py [new file with mode: 0644]
Pmw/Pmw_1_2/doc/example1.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/example2.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/exercises.py [new file with mode: 0644]
Pmw/Pmw_1_2/doc/features.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/halfblueball.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/howtobuild.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/howtouse.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/index.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/porting.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/refindex.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/scale1.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/scale2.gif [new file with mode: 0644]
Pmw/Pmw_1_2/doc/starting.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/todo.html [new file with mode: 0644]
Pmw/Pmw_1_2/doc/transdove.gif [new file with mode: 0644]
Pmw/Pmw_1_2/lib/Pmw.def [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwAboutDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwBalloon.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwBase.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwBlt.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwButtonBox.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwColor.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwComboBox.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwComboBoxDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwCounter.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwCounterDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwEntryField.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwGroup.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwHistoryText.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwLabeledWidget.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwLoader.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwLogicalFont.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwMainMenuBar.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwMenuBar.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwMessageBar.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwMessageDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwNoteBook.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwOptionMenu.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwPanedWidget.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwPromptDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwRadioSelect.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwScrolledCanvas.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwScrolledField.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwScrolledFrame.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwScrolledListBox.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwScrolledText.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwSelectionDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwTextDialog.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwTimeCounter.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/PmwTimeFuncs.py [new file with mode: 0644]
Pmw/Pmw_1_2/lib/__init__.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/AboutDialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/All.py [new file with mode: 0755]
Pmw/Pmw_1_2/tests/Blt_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ButtonBox_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/Colors_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ComboBox_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/CounterDialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/Counter_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/Dialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/EntryField_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/LabeledWidget_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ManualTests.py [new file with mode: 0755]
Pmw/Pmw_1_2/tests/MegaWidget_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/MessageDialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/NoteBook_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/OptionMenu_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/Options_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/PanedWidget_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/PmwBase_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/PromptDialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/RadioSelect_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ScrolledCanvas_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ScrolledField_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ScrolledFrame_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ScrolledListBox_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/ScrolledText_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/SelectionDialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/Test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/TestVersion.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/TextDialog_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/Tkinter_test.py [new file with mode: 0644]
Pmw/Pmw_1_2/tests/earthris.gif [new file with mode: 0644]
Pmw/Pmw_1_2/tests/flagup.bmp [new file with mode: 0644]
Pmw/README [new file with mode: 0644]
Pmw/__init__.py [new file with mode: 0644]

diff --git a/Accas/A_AU_PLUS_UN.py b/Accas/A_AU_PLUS_UN.py
new file mode 100644 (file)
index 0000000..e774270
--- /dev/null
@@ -0,0 +1,29 @@
+#@ MODIF A_AU_PLUS_UN Accas  DATE 28/01/2005   AUTEUR VABHHTS J.PELLET 
+# -*- coding: iso-8859-1 -*-
+#            CONFIGURATION MANAGEMENT OF EDF VERSION
+# ======================================================================
+# COPYRIGHT (C) 1991 - 2005  EDF R&D                  WWW.CODE-ASTER.ORG
+# 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 EDF R&D CODE_ASTER,         
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
+# ======================================================================
+
+from Noyau import N_REGLE
+from Validation import V_AU_PLUS_UN
+
+class AU_PLUS_UN(V_AU_PLUS_UN.AU_PLUS_UN,N_REGLE.REGLE):
+   """
+       La classe utilise l'initialiseur de REGLE. Il n'est pas
+       nécessaire d'expliciter son initialiseur car
+       V_AU_PLUS_UN.AU_PLUS_UN n'en a pas
+   """
index e8414f9cf5bdd49bd1033cd3f80e0a457b31447d..21636df6796a429378039f04bf8955aca6ac4a1d 100644 (file)
@@ -52,6 +52,7 @@ from A_MCSIMP import MCSIMP
 
 # Les règles
 from A_AU_MOINS_UN import AU_MOINS_UN
+from A_AU_PLUS_UN import AU_PLUS_UN
 from A_UN_PARMI import UN_PARMI
 from A_PRESENT_PRESENT import PRESENT_PRESENT
 from A_PRESENT_ABSENT import PRESENT_ABSENT
index 4aebb58b87c323b18cef5e3c2b8d4c14d8b7762a..a23fff6f13be6e83a6f6ed7376ec22d8af4c8e24 100644 (file)
@@ -19,3 +19,6 @@
 #                                                                       
 #                                                                       
 # ======================================================================
+print 80
+import traceback
+traceback.print_stack()
diff --git a/Aster/Cata/Macro/calc_fonction_ops.py b/Aster/Cata/Macro/calc_fonction_ops.py
new file mode 100644 (file)
index 0000000..8a2907b
--- /dev/null
@@ -0,0 +1,322 @@
+#@ MODIF calc_fonction_ops Macro  DATE 12/05/2005   AUTEUR DURAND C.DURAND 
+# -*- coding: iso-8859-1 -*-
+#            CONFIGURATION MANAGEMENT OF EDF VERSION
+# ======================================================================
+# COPYRIGHT (C) 1991 - 2005  EDF R&D                  WWW.CODE-ASTER.ORG
+# 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 EDF R&D CODE_ASTER,         
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
+# ======================================================================
+
+
+def tocomplex(arg):
+    if arg[0]=='RI' : return complex(arg[1],arg[2])
+    if arg[0]=='MP' : return complex(arg[1]*cos(arg[2]),arg[1]*sin(arg[2]))
+
+def calc_fonction_ops(self,FFT,DERIVE,INTEGRE,LISS_ENVELOP,
+                      SPEC_OSCI,ABS,COMB,COMB_C,COMPOSE,EXTRACTION,
+                      ENVELOPPE,ASSE,CORR_ACCE,PUISSANCE,INVERSE,
+                      NOM_PARA,NOM_RESU,INTERPOL,PROL_DROITE,
+                      PROL_GAUCHE,NOM_PARA_FONC,INTERPOL_FONC,PROL_DROITE_FONC,
+                      PROL_GAUCHE_FONC,**args):
+  """
+     Ecriture de la macro CALC_FONCTION
+  """
+  ier=0
+  import types
+  import string
+  import copy
+  from math import pi
+  from Utilitai.t_fonction import t_fonction,t_fonction_c,t_nappe
+  from Accas import _F
+  from Cata.cata import nappe_sdaster,fonction_sdaster,fonction_c
+  from Utilitai.Utmess import UTMESS
+  from Numeric import alltrue,less,array,reshape,cos,sin,exp,sqrt
+  from Numeric import choose,zeros,Float
+  import aster_fonctions
+
+  ### On importe les definitions des commandes a utiliser dans la macro
+  DEFI_FONCTION  = self.get_cmd('DEFI_FONCTION')
+  DEFI_NAPPE     = self.get_cmd('DEFI_NAPPE')
+  
+  ### Comptage commandes + déclaration concept sortant
+  self.set_icmd(1)
+  self.DeclareOut('C_out',self.sd)
+
+  ### type de traitement
+  ###
+  if (INTEGRE     != None):
+     __ff=INTEGRE['FONCTION'].convert()
+     if INTEGRE['METHODE']=='TRAPEZE' : __ex=__ff.trapeze(INTEGRE['COEF'])
+     if INTEGRE['METHODE']=='SIMPSON' : __ex=__ff.simpson(INTEGRE['COEF'])
+  ###
+  if (DERIVE      != None):
+     __ff=DERIVE['FONCTION'].convert()
+     __ex=__ff.derive()
+  ###
+  if (INVERSE     != None):
+     __ff=INVERSE['FONCTION'].convert()
+     __ex=__ff.inverse()
+  ###
+  if (ABS         != None): 
+     __ff=ABS['FONCTION'].convert()
+     __ex=__ff.abs()
+  ###
+  if (COMPOSE     != None): 
+     __ff=COMPOSE['FONC_RESU'].convert()
+     __fg=COMPOSE['FONC_PARA'].convert()
+     __ex=__ff[__fg]
+  ###
+  if (ASSE        != None):
+     __f0=ASSE['FONCTION'][0].convert()
+     __f1=ASSE['FONCTION'][1].convert()
+     __ex=__f0.cat(__f1,ASSE['SURCHARGE'])
+  ###
+  if (COMB        != None):
+     if args['LIST_PARA']!=None : vale_x=args['LIST_PARA'].Valeurs()
+     else               :
+        vale_x=[]
+        for mcfact in COMB :
+            vale_x=vale_x+mcfact['FONCTION'].Absc()
+     vale_x=dict([(i,0) for i in vale_x]).keys()
+     vale_x.sort()
+     list_fonc=[]  
+     if   isinstance(self.sd,nappe_sdaster):
+        for mcfact in COMB :
+           list_fonc.append(mcfact['FONCTION'].convert())
+        list_fonch=[]  
+        for f in list_fonc :
+            __ex=f
+            for g in list_fonc :
+               __ex=__ex.homo_support(g)
+            list_fonch.append(__ex)
+        list_fonc=list_fonch
+     elif isinstance(self.sd,fonction_sdaster):
+        for mcfact in COMB :
+           __ex=mcfact['FONCTION'].convert()
+           list_fonc.append(__ex.evalfonc(vale_x))
+
+     __ex=list_fonc[0]
+     __ex=__ex*COMB[0]['COEF']
+     i=1
+     for item in list_fonc[1:] :
+        item=item*COMB[i]['COEF']
+        __ex=__ex+item
+        i=i+1
+  ###
+  if (COMB_C    != None):
+     if args['LIST_PARA']!=None : vale_x=args['LIST_PARA'].Valeurs()
+     else               :
+        vale_x=[]
+        for mcfact in COMB_C :
+            vale_x=vale_x+mcfact['FONCTION'].Absc()
+     vale_x=dict([(i,0) for i in vale_x]).keys()
+     vale_x.sort()
+     list_fonc=[]  
+     if   isinstance(self.sd,nappe_sdaster):
+        for mcfact in COMB_C :
+           list_fonc.append(mcfact['FONCTION'].convert())
+        list_fonch=[]  
+        for f in list_fonc :
+            __ex=f
+            for g in list_fonc :
+               __ex=__ex.homo_support(g)
+            list_fonch.appen(__ex)
+        list_fonc=list_fonch
+     elif isinstance(self.sd,fonction_sdaster) or isinstance(self.sd,fonction_c):
+        for mcfact in COMB_C :
+           __ex=mcfact['FONCTION'].convert(arg='complex')
+           list_fonc.append(__ex.evalfonc(vale_x))
+
+     __ex=list_fonc[0]
+     if COMB_C[0]['COEF_R']!=None: __ex=__ex*complex(COMB_C[0]['COEF_R'])
+     if COMB_C[0]['COEF_C']!=None: __ex=__ex*tocomplex(COMB_C[0]['COEF_C'])
+     i=1
+     for item in list_fonc[1:] :
+        if COMB_C[i]['COEF_R']!=None: coef=complex(COMB_C[i]['COEF_R'])
+        if COMB_C[i]['COEF_C']!=None: coef=tocomplex(COMB_C[i]['COEF_C'])
+        item=item*coef
+        __ex=__ex+item
+        i=i+1
+  ###
+  if (PUISSANCE   != None): 
+     __ff=PUISSANCE['FONCTION'].convert()
+     __ex=__ff
+     for i in range(PUISSANCE['EXPOSANT']-1) : __ex=__ex*__ff
+  ###
+  if (EXTRACTION  != None):
+     if EXTRACTION['PARTIE']=='REEL'   : __ex=EXTRACTION['FONCTION'].convert(arg='real')
+     if EXTRACTION['PARTIE']=='IMAG'   : __ex=EXTRACTION['FONCTION'].convert(arg='imag')
+     if EXTRACTION['PARTIE']=='MODULE' : __ex=EXTRACTION['FONCTION'].convert(arg='modul')
+     if EXTRACTION['PARTIE']=='PHASE'  : __ex=EXTRACTION['FONCTION'].convert(arg='phase')
+  ###
+  if (ENVELOPPE   != None):
+     list_fonc=[]
+     if   isinstance(self.sd,nappe_sdaster):
+        for f in ENVELOPPE['FONCTION'] : list_fonc.append(f.convert())
+        list_fonch=[]  
+        for f in list_fonc :
+            __ff=f
+            for g in list_fonc :
+               __ff=__ff.homo_support(g)
+            list_fonch.append(__ff)
+        list_fonc=list_fonch
+        vale_para=list_fonc[0].vale_para
+        para     =list_fonc[0].para
+        l_fonc_f =[]
+        for i in range(len(vale_para)):
+            __ff=list_fonc[0].l_fonc[i]
+            if ENVELOPPE['CRITERE']=='SUP' :
+              for f in list_fonc[1:] : __ff=__ff.sup(f.l_fonc[i])
+            if ENVELOPPE['CRITERE']=='INF' :
+              for f in list_fonc[1:] : __ff=__ff.inf(f.l_fonc[i])
+            l_fonc_f.append(__ff)
+        __ex=t_nappe(vale_para,l_fonc_f,para)
+     elif isinstance(self.sd,fonction_sdaster):
+        for f in ENVELOPPE['FONCTION'] : list_fonc.append(f.convert())
+        __ex=list_fonc[0]
+        if ENVELOPPE['CRITERE']=='SUP' :
+           for f in list_fonc[1:] : __ex=__ex.sup(f)
+        if ENVELOPPE['CRITERE']=='INF' :
+           for f in list_fonc[1:] : __ex=__ex.inf(f)
+  ###
+  if (CORR_ACCE   != None):
+     __ex=CORR_ACCE['FONCTION'].convert()
+     para=copy.copy(__ex.para)
+     # suppression de la tendance de l accelero
+     __ex=__ex.suppr_tend()
+     # calcul de la vitesse
+     __ex=__ex.trapeze(0.)
+     # calcul de la tendance de la vitesse : y = a1*x +a0
+     __ex=__ex.suppr_tend()
+     if CORR_ACCE['CORR_DEPL']=='OUI':
+        # suppression de la tendance deplacement
+        # calcul du deplacement : integration
+        __ex=__ex.trapeze(0.)
+        # calcul de la tendance du déplacement : y = a1*x +a0
+        __ex=__ex.suppr_tend()
+        # regeneration de la vitesse : derivation
+        __ex=__ex.derive()
+     # regeneration de l accelero : derivation
+     __ex=__ex.derive()
+     __ex.para=para
+  ###
+  if (FFT         != None):
+     if isinstance(self.sd,fonction_c):
+        __ff=FFT['FONCTION'].convert()
+        __ex=__ff.fft(FFT['METHODE'])
+     if isinstance(self.sd,fonction_sdaster):
+        __ff=FFT['FONCTION'].convert(arg='complex')
+        __ex=__ff.fft(FFT['METHODE'],FFT['SYME'])
+  ###
+  if (SPEC_OSCI   != None):
+     if SPEC_OSCI['AMOR_REDUIT']==None :
+        l_amor=[0.02,0.05,0.1]
+        UTMESS('I','CALC_FONCTION',' : génération par défaut de 3 amortissements :'+str(l_amor))
+     else :
+        if type(SPEC_OSCI['AMOR_REDUIT']) not in (types.ListType,types.TupleType):
+               l_amor=[SPEC_OSCI['AMOR_REDUIT'],]
+        else : l_amor= SPEC_OSCI['AMOR_REDUIT']
+     if SPEC_OSCI['FREQ']==None and SPEC_OSCI['LIST_FREQ']==None:
+        l_freq=[]
+        for i in range(56) : l_freq.append( 0.2+0.050*i)
+        for i in range( 8) : l_freq.append( 3.0+0.075*i)
+        for i in range(14) : l_freq.append( 3.6+0.100*i)
+        for i in range(24) : l_freq.append( 5.0+0.125*i)
+        for i in range(28) : l_freq.append( 8.0+0.250*i)
+        for i in range( 6) : l_freq.append(15.0+0.500*i)
+        for i in range( 4) : l_freq.append(18.0+1.000*i)
+        for i in range(10) : l_freq.append(22.0+1.500*i)
+        texte=[]
+        for i in range(len(l_freq)/5) :
+            texte.append(' %f %f %f %f %f' %tuple(l_freq[i*5:i*5+5]))
+        UTMESS('I','CALC_FONCTION',' : génération par défaut de 150 fréquences :\n'+'\n'.join(texte))
+     elif SPEC_OSCI['LIST_FREQ']!=None:
+        l_freq=SPEC_OSCI['LIST_FREQ'].Valeurs()
+     elif SPEC_OSCI['FREQ']!=None:
+        if type(SPEC_OSCI['FREQ']) not in (types.ListType,types.TupleType):
+               l_freq=[SPEC_OSCI['FREQ'],]
+        else : l_freq= SPEC_OSCI['FREQ']
+     if abs(SPEC_OSCI['NORME'])<1.E-10 :
+        UTMESS('S','CALC_FONCTION',' : SPEC_OSCI, la norme ne peut etre nulle')
+     if SPEC_OSCI['NATURE_FONC']!='ACCE' :
+        UTMESS('S','CALC_FONCTION',' : SPEC_OSCI, le type de la fonction doit etre ACCE')
+     if SPEC_OSCI['METHODE']!='NIGAM' :
+        UTMESS('S','CALC_FONCTION',' : SPEC_OSCI, seule la méthode NIGAM est codée')
+     eps=1.e-6
+     for amor in l_amor :
+         if amor>(1-eps) :
+            UTMESS('S','CALC_FONCTION',' : SPEC_OSCI, la méthode choisie '\
+                   'suppose des amortissements sous-critiques, amor<1.')
+
+     __ff=SPEC_OSCI['FONCTION'].convert()
+     
+     # appel à SPEC_OSCI
+     spectr = aster_fonctions.SPEC_OSCI(__ff.vale_x, __ff.vale_y, l_freq, l_amor)
+
+     # construction de la nappe
+     vale_para = l_amor
+     para      = { 'INTERPOL'      : ['LIN','LOG'],
+                   'NOM_PARA_FONC' : 'FREQ',
+                   'NOM_PARA'      : 'AMOR',
+                   'PROL_DROITE'   : 'EXCLU',
+                   'PROL_GAUCHE'   : 'EXCLU',
+                   'NOM_RESU'      : SPEC_OSCI['NATURE'] }
+     para_fonc = { 'INTERPOL'      : ['LOG','LOG'],
+                   'NOM_PARA'      : 'FREQ',
+                   'PROL_DROITE'   : 'CONSTANT',
+                   'PROL_GAUCHE'   : 'EXCLU',
+                   'NOM_RESU'      : SPEC_OSCI['NATURE'] }
+     if   SPEC_OSCI['NATURE']=='DEPL' : ideb = 0
+     elif SPEC_OSCI['NATURE']=='VITE' : ideb = 1
+     else                             : ideb = 2
+     l_fonc = []
+     for iamor in range(len(l_amor)) :
+       l_fonc.append(t_fonction(l_freq,spectr[iamor,ideb,:]/SPEC_OSCI['NORME'],para_fonc))
+     __ex=t_nappe(vale_para,l_fonc,para)
+  ###
+  if (LISS_ENVELOP!= None): return
+
+  ### creation de la fonction produite par appel à DEFI_FONCTION
+  ### on récupère les paramètres issus du calcul de __ex
+  ### et on les surcharge par ceux imposés par l'utilisateur
+
+  if isinstance(__ex,t_fonction) or isinstance(__ex,t_fonction_c):
+     para=__ex.para
+     if NOM_PARA   !=None : para['NOM_PARA']   =NOM_PARA
+     if NOM_RESU   !=None : para['NOM_RESU']   =NOM_RESU
+     if PROL_DROITE!=None : para['PROL_DROITE']=PROL_DROITE
+     if PROL_GAUCHE!=None : para['PROL_GAUCHE']=PROL_GAUCHE
+     if INTERPOL   !=None : para['INTERPOL']   =INTERPOL
+     if   isinstance(__ex,t_fonction_c): para['VALE_C'] = __ex.tabul()
+     elif isinstance(__ex,t_fonction)  : para['VALE']   = __ex.tabul()
+     C_out=DEFI_FONCTION(**para)
+  elif isinstance(__ex,t_nappe):
+     def_fonc=[]
+     for f in __ex.l_fonc :
+       para=f.para
+       def_fonc.append(_F(VALE       =f.tabul(),
+                          INTERPOL   =f.para['INTERPOL'],
+                          PROL_DROITE=f.para['PROL_DROITE'],
+                          PROL_GAUCHE=f.para['PROL_GAUCHE'],)
+                       )
+     para=__ex.para
+     if NOM_PARA      !=None : para['NOM_PARA']   =NOM_PARA
+     if NOM_RESU      !=None : para['NOM_RESU']   =NOM_RESU
+     if PROL_DROITE   !=None : para['PROL_DROITE']=PROL_DROITE
+     if PROL_GAUCHE   !=None : para['PROL_GAUCHE']=PROL_GAUCHE
+     if NOM_PARA_FONC !=None : para['NOM_PARA_FONC']   =INTERPOL
+     if INTERPOL_FONC !=None : para['INTERPOL']   =INTERPOL
+     C_out=DEFI_NAPPE(PARA=__ex.vale_para.tolist(),DEFI_FONCTION=def_fonc,**para)
+  return ier
+
index b345ca866eab14fcddf90356c38845582b3ac81c..a012dfb5bb500367588be2bc9d677c08096082f5 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF calc_precont_ops Macro  DATE 22/11/2004   AUTEUR LEBOUVIE F.LEBOUVIER 
+#@ MODIF calc_precont_ops Macro  DATE 07/03/2005   AUTEUR DURAND C.DURAND 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -319,7 +319,7 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
   # 1.6 Blocage de tous les noeuds des cables actifs
   # --------------------------------------------------
   
-  __B_CA=AFFE_CHAR_MECA(MODELE=__M_CA,
+  _B_CA=AFFE_CHAR_MECA(MODELE=__M_CA,
                         DDL_IMPO= _F( GROUP_MA = __GROUP_MA_A,
                                       DX = 0.,
                                       DY = 0.,
@@ -328,11 +328,11 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
 
   # 1.7 Chargements concernant les cables
   # -------------------------------------
-  __C_CN=AFFE_CHAR_MECA(MODELE=__M_CA,**motscles)
-  __C_CA=AFFE_CHAR_MECA(MODELE=MODELE,**motscle2)
-  __C_CT=AFFE_CHAR_MECA(MODELE=MODELE,**motscle3)
+  _C_CN=AFFE_CHAR_MECA(MODELE=__M_CA,**motscles)
+  _C_CA=AFFE_CHAR_MECA(MODELE=MODELE,**motscle2)
+  _C_CT=AFFE_CHAR_MECA(MODELE=MODELE,**motscle3)
   if CABLE_BP_INACTIF:
-    __C_CI=AFFE_CHAR_MECA(MODELE=MODELE,**motscle6)
+    _C_CI=AFFE_CHAR_MECA(MODELE=MODELE,**motscle6)
 
 
 
@@ -343,7 +343,7 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
 
   #------------------------------------------------------------------- 
   # 2.1 Premiere etape : calcul sur le(s) cable(s) et 
-  #     recuperation des __F_CAs aux noeuds 
+  #     recuperation des _F_CAs aux noeuds 
   #     on travaile entre tmin et tmax
   #-------------------------------------------------------------------
 
@@ -351,8 +351,8 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
                          MODELE     = __M_CA,
                          CHAM_MATER = CHAM_MATER,
                          CARA_ELEM  = CARA_ELEM,
-                         EXCIT      =(_F(CHARGE = __B_CA),
-                                      _F(CHARGE = __C_CN),),
+                         EXCIT      =(_F(CHARGE = _B_CA),
+                                      _F(CHARGE = _C_CN),),
                          COMP_INCR  =_F( RELATION = 'ELAS',
                                          DEFORMATION = 'PETIT',
                                          TOUT = 'OUI'),
@@ -382,7 +382,7 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
                               CHAM_GD=__REA,
                               COEF_R = -1.), )
                   
-  __F_CA=AFFE_CHAR_MECA(MODELE=__M_CA,
+  _F_CA=AFFE_CHAR_MECA(MODELE=__M_CA,
                           VECT_ASSE = __REAC )      
   
   
@@ -400,12 +400,12 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
           if dExcit[-1][i]==None : del dExcit[-1][i]
 
   if CABLE_BP_INACTIF:
-    dExcit.append(_F(CHARGE=__C_CI),)
+    dExcit.append(_F(CHARGE=_C_CI),)
 
   # Creation du mots-cle EXCIT pour le STAT_NON_LINE
   dExcit1=copy.copy(dExcit)
-  dExcit1.append(_F(CHARGE=__C_CA),)
-  dExcit1.append(_F(CHARGE = __F_CA,
+  dExcit1.append(_F(CHARGE=_C_CA),)
+  dExcit1.append(_F(CHARGE = _F_CA,
                     FONC_MULT=__FCT ),)
 
   RES=STAT_NON_LINE( 
@@ -439,7 +439,7 @@ def calc_precont_ops(self,reuse,MODELE,CHAM_MATER,CARA_ELEM,EXCIT,
 
   # Creation du mots-cles EXCIT pour le STAT_NON_LINE
   dExcit2=copy.copy(dExcit)
-  dExcit2.append(_F(CHARGE=__C_CT,) )
+  dExcit2.append(_F(CHARGE=_C_CT,) )
    
   # Calcul sur un seul pas (de __TINT a __TMAX)
   RES=STAT_NON_LINE( reuse      = RES,
index 4f2ace216f636d3feefff01713ac1b2a26687bcb..1e9d6e49201d64514bea657ac57088995203de0a 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF impr_fonction_ops Macro  DATE 30/11/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF impr_fonction_ops Macro  DATE 11/05/2005   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -31,9 +31,10 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
    """
    macro='IMPR_FONCTION'
    import aster
-   from Accas import _F
-   from Utilitai import Graph
-   from Utilitai.Utmess import UTMESS
+   from Accas               import _F
+   from Utilitai            import Graph
+   from Utilitai.Utmess     import UTMESS
+   from Utilitai.UniteAster import UniteAster
    ier=0
    # La macro compte pour 1 dans la numerotation des commandes
    self.set_icmd(1)
@@ -42,21 +43,21 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
    # Le nom de la variable doit etre obligatoirement le nom de la commande
    CALC_FONC_INTERP = self.get_cmd('CALC_FONC_INTERP')
    DEFI_LIST_REEL   = self.get_cmd('DEFI_LIST_REEL')
-   DEFI_FICHIER     = self.get_cmd('DEFI_FICHIER')
    DETRUIRE         = self.get_cmd('DETRUIRE')
 
    #----------------------------------------------
    # 0. Traitement des arguments, initialisations
    # unité logique des fichiers réservés
    ul_reserve=(8,)
+   UL = UniteAster()
 
    # 0.1. Fichier
    nomfich=None
    if args['UNITE'] and args['UNITE']<>6:
-      nomfich='fort.'+str(args['UNITE'])
+      nomfich=UL.Nom(args['UNITE'])
       if INFO==2:
          print ' Nom du fichier :',nomfich
-   if nomfich and os.path.exists(nomfich):
+   if nomfich and os.path.exists(nomfich) and os.stat(nomfich).st_size<>0:
       if FORMAT=='XMGRACE':
          niv='A'
       else:
@@ -74,7 +75,8 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
    for Ci in COURBE:
       iocc+=1
       dC = Ci.cree_dict_valeurs(Ci.mc_liste)
-      if dC.has_key('LIST_PARA') and i0==0: i0=iocc
+      if dC.has_key('LIST_PARA') and dC['LIST_PARA']!=None and i0==0:
+         i0=iocc
       for mc in dC.keys():
          if dC[mc]==None: del dC[mc]
       Courbe.append(dC)
@@ -142,6 +144,7 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
          if typ=='nappe_sdaster':
             lpar,lval=obj.Valeurs()
             dico,ldicf=obj.Parametres()
+            Leg=dCi['LEGENDE']
             for i in range(len(lpar)):
                p=lpar[i]
                lx=lval[i][0]
@@ -169,12 +172,16 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
                   lx=lv2[0][0]
                   ly=lv2[0][1]
                # on stocke les données dans le Graph
+               nomresu=dic['NOM_RESU'].strip()+'_'+str(len(graph.Legendes))
                dicC={
                   'Val' : [lx,ly],
-                  'Lab' : [dic['NOM_PARA_FONC'],dic['NOM_RESU']]
+                  'Lab' : [dic['NOM_PARA_FONC'],nomresu]
                }
+               # ajoute la valeur du paramètre
+               dCi['LEGENDE'] = '%s %s=%g' % (Leg,dic['NOM_PARA'].strip(),p)
                Graph.AjoutParaCourbe(dicC, args=dCi)
                graph.AjoutCourbe(**dicC)
+               DETRUIRE(CONCEPT=_F(NOM=('li__','ftmp__'),),ALARME='NON',INFO=1)
          else:
             ftmp__=obj
             dpar=ftmp__.Parametres()
@@ -194,17 +201,19 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
             lx=lval[0]
             lr=lval[1]
             if typ=='fonction_c' and dCi.has_key('PARTIE'):
-               if dCi['PARTIE']=='COMPLEXE' : lr=lval[2]
+               if dCi['PARTIE']=='IMAG' : lr=lval[2]
             # on stocke les données dans le Graph
             if typ=='fonction_c' and not dCi.has_key('PARTIE'):
+               nomresu=dpar['NOM_RESU'].strip()+'_'+str(len(graph.Legendes))
                dicC={
                   'Val' : lval,
-                  'Lab' : [dpar['NOM_PARA'],dpar['NOM_RESU']+'_R',dpar['NOM_RESU']+'_I']
+                  'Lab' : [dpar['NOM_PARA'],nomresu+'_R',nomresu+'_I']
                }
             else:
+               nomresu=dpar['NOM_RESU'].strip()+'_'+str(len(graph.Legendes))
                dicC={
                   'Val' : [lx,lr],
-                  'Lab' : [dpar['NOM_PARA'],dpar['NOM_RESU']]
+                  'Lab' : [dpar['NOM_PARA'],nomresu]
                }
             Graph.AjoutParaCourbe(dicC, args=dCi)
             graph.AjoutCourbe(**dicC)
@@ -275,14 +284,18 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
          # on stocke les données dans le Graph
          # on imprime la liste des paramètres seulement si LIST_PARA
          if intloc:
+            nomresur=dpar['NOM_RESU'].strip()+'_'+str(len(graph.Legendes))
+            nomresu2=dpa2['NOM_RESU'].strip()+'_'+str(len(graph.Legendes)+1)
             dicC={
                'Val' : [lt,lx,ly],
-               'Lab' : [dpar['NOM_PARA'],dpar['NOM_RESU'],dpa2['NOM_RESU']]
+               'Lab' : [dpar['NOM_PARA'],nomresur,nomresu2]
             }
          else:
+            nomresur=dpar['NOM_RESU'].strip()+'_'+str(len(graph.Legendes))
+            nomresu2=dpa2['NOM_RESU'].strip()+'_'+str(len(graph.Legendes)+1)
             dicC={
                'Val' : [lx,ly],
-               'Lab' : [dpar['NOM_RESU'],dpa2['NOM_RESU']]
+               'Lab' : [nomresur,nomresu2]
             }
          Graph.AjoutParaCourbe(dicC, args=dCi)
          graph.AjoutCourbe(**dicC)
@@ -358,7 +371,7 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
    elif FORMAT=='AGRAF':
       nomdigr=None
       if args['UNITE_DIGR']<>6:
-         nomdigr='fort.'+str(args['UNITE_DIGR'])
+         nomdigr=UL.Nom(args['UNITE_DIGR'])
       kargs['FICHIER']=[nomfich, nomdigr]
       kargs['dform']={ 'formR' : '%12.5E' }
 
@@ -373,21 +386,15 @@ def impr_fonction_ops(self, FORMAT, COURBE, INFO, **args):
 
    # Traiter le cas des UL réservées
    if args['UNITE'] and args['UNITE'] in ul_reserve:
-      DEFI_FICHIER( ACTION='LIBERER', UNITE=args['UNITE'], )
+      UL.Etat(args['UNITE'], etat='F')
    if FORMAT=='AGRAF' and args['UNITE_DIGR']<>args['UNITE'] \
          and args['UNITE_DIGR'] in ul_reserve:
-      DEFI_FICHIER( ACTION='LIBERER', UNITE=args['UNITE_DIGR'], )
+      UL.Etat(args['UNITE_DIGR'], etat='F')
 
    # 2.4. On trace !
    graph.Trace(**kargs)
 
    # 99. Traiter le cas des UL réservées
-   if args['UNITE'] and args['UNITE'] in ul_reserve:
-      DEFI_FICHIER( ACTION='ASSOCIER', UNITE=args['UNITE'],
-            TYPE='ASCII', ACCES='APPEND' )
-   if FORMAT=='AGRAF' and args['UNITE_DIGR']<>args['UNITE'] \
-         and args['UNITE_DIGR'] in ul_reserve:
-      DEFI_FICHIER( ACTION='ASSOCIER', UNITE=args['UNITE_DIGR'],
-            TYPE='ASCII', ACCES='APPEND' )
+   UL.EtatInit()
 
    return ier
index ca1a492f970ddfbadbb53c72d785971c2f886aa7..74776f0bd78d390a5fd1f183763760e0c42b1146 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF impr_table_ops Macro  DATE 30/11/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF impr_table_ops Macro  DATE 11/05/2005   AUTEUR MCOURTOI M.COURTOIS 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -35,9 +35,10 @@ def impr_table_ops(self, FORMAT, TABLE, INFO, **args):
    """
    macro='IMPR_TABLE'
    import aster
-   from Accas import _F
-   from Cata.cata import table_jeveux
-   from Utilitai.Utmess import UTMESS
+   from Accas               import _F
+   from Cata.cata           import table_jeveux
+   from Utilitai.Utmess     import UTMESS
+   from Utilitai.UniteAster import UniteAster
    ier=0
    # La macro compte pour 1 dans la numerotation des commandes
    self.set_icmd(1)
@@ -45,19 +46,19 @@ def impr_table_ops(self, FORMAT, TABLE, INFO, **args):
    # On importe les definitions des commandes a utiliser dans la macro
    # Le nom de la variable doit etre obligatoirement le nom de la commande
    DETRUIRE         = self.get_cmd('DETRUIRE')
-   DEFI_FICHIER     = self.get_cmd('DEFI_FICHIER')
    RECU_FONCTION    = self.get_cmd('RECU_FONCTION')
 
    #----------------------------------------------
    # 0. Traitement des arguments, initialisations
    # unité logique des fichiers réservés
    ul_reserve=(8,)
+   UL = UniteAster()
 
    # 0.1. Fichier
    nomfich=None
    if args['UNITE'] and args['UNITE']<>6:
-      nomfich='fort.'+str(args['UNITE'])
-   if nomfich and os.path.exists(nomfich):
+      nomfich=UL.Nom(args['UNITE'])
+   if nomfich and os.path.exists(nomfich) and os.stat(nomfich).st_size<>0:
       if FORMAT=='XMGRACE':
          UTMESS('A',macro,'Le fichier '+nomfich+' existe déjà, on écrit ' \
                 'à la suite.')
@@ -111,7 +112,7 @@ def impr_table_ops(self, FORMAT, TABLE, INFO, **args):
 
    # 0.4.2. Traiter le cas des UL réservées
    if args['UNITE'] and args['UNITE'] in ul_reserve:
-      DEFI_FICHIER( ACTION='LIBERER', UNITE=args['UNITE'], )
+      UL.Etat(args['UNITE'], etat='F')
 
    #----------------------------------------------
    # Boucle sur les tables
@@ -205,9 +206,7 @@ def impr_table_ops(self, FORMAT, TABLE, INFO, **args):
             DETRUIRE(CONCEPT=_F(NOM=('__fonc',),), ALARME='NON', INFO=1,)
 
    # 99. Traiter le cas des UL réservées
-   if args['UNITE'] and args['UNITE'] in ul_reserve:
-      DEFI_FICHIER( ACTION='ASSOCIER', UNITE=args['UNITE'],
-            TYPE='ASCII', ACCES='APPEND' )
+   UL.EtatInit()
 
    return ier
 
diff --git a/Aster/Cata/Macro/info_fonction_ops.py b/Aster/Cata/Macro/info_fonction_ops.py
new file mode 100644 (file)
index 0000000..b728f6a
--- /dev/null
@@ -0,0 +1,252 @@
+#@ MODIF info_fonction_ops Macro  DATE 12/05/2005   AUTEUR DURAND C.DURAND 
+# -*- coding: iso-8859-1 -*-
+#            CONFIGURATION MANAGEMENT OF EDF VERSION
+# ======================================================================
+# COPYRIGHT (C) 1991 - 2005  EDF R&D                  WWW.CODE-ASTER.ORG
+# 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 EDF R&D CODE_ASTER,         
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
+# ======================================================================
+def info_fonction_ops(self,RMS,NOCI_SEISME,MAX,NORME,ECART_TYPE,**args):
+  """
+     Ecriture de la macro INFO_FONCTION
+  """
+  ier=0
+  import string
+  from Utilitai.t_fonction import t_fonction,t_fonction_c,t_nappe
+  import math
+  from Accas import _F
+  from Utilitai.Utmess import UTMESS
+
+  ### On importe les definitions des commandes a utiliser dans la macro
+  CREA_TABLE     = self.get_cmd('CREA_TABLE')
+  CALC_FONCTION  = self.get_cmd('CALC_FONCTION')
+  
+  ### Comptage commandes + déclaration concept sortant
+  self.set_icmd(1)
+  self.DeclareOut('C_out',self.sd)
+
+  ### type de traitement
+  
+  ###
+  if (MAX != None): 
+     __ff=MAX['FONCTION'].convert()
+     __ex=__ff.extreme()
+     n_mini=len(__ex['min'])
+     n_maxi=len(__ex['max'])
+     listeMCF=[_F(LISTE_K=[MAX['FONCTION'].nom]*(n_mini+n_maxi),PARA='FONCTION'), 
+               _F(LISTE_K=['MINI',]*n_mini+['MAXI',]*n_maxi,PARA='TYPE'),]
+     if isinstance(__ff,t_nappe) :
+        listeMCF=listeMCF+[\
+           _F(LISTE_R=[i[0] for i in __ex['min']]+[i[0] for i in __ex['max']],PARA=__ff.para['NOM_PARA']),\
+           _F(LISTE_R=[i[1] for i in __ex['min']]+[i[1] for i in __ex['max']],PARA=__ff.para['NOM_PARA_FONC']),\
+           _F(LISTE_R=[i[2] for i in __ex['min']]+[i[2] for i in __ex['max']],PARA=__ff.para['NOM_RESU'])]
+     else :
+        listeMCF=listeMCF+[\
+               _F(LISTE_R=[i[0] for i in __ex['min']]+[i[0] for i in __ex['max']],PARA=__ff.para['NOM_PARA']),\
+               _F(LISTE_R=[i[1] for i in __ex['min']]+[i[1] for i in __ex['max']],PARA=__ff.para['NOM_RESU'])]
+     C_out=CREA_TABLE(LISTE=listeMCF)
+
+  ###
+  if (ECART_TYPE  != None): 
+     __ff=ECART_TYPE['FONCTION'].convert()
+     if ECART_TYPE['INST_INIT']!=None : tini=ECART_TYPE['INST_INIT']
+     else                             : tini=__ff.vale_x[0]
+     if ECART_TYPE['INST_FIN' ]!=None : tfin=ECART_TYPE['INST_FIN' ]
+     else                             : tfin=__ff.vale_x[-1]
+     __ff=__ff.cut(tini,__ff.vale_x[-1],ECART_TYPE['PRECISION'],ECART_TYPE['CRITERE'])
+     __ff=__ff.cut(__ff.vale_x[0],tfin,ECART_TYPE['PRECISION'],ECART_TYPE['CRITERE'])
+     if ECART_TYPE['METHODE'  ]=='SIMPSON' : __ex=__ff.simpson(0.)
+     if ECART_TYPE['METHODE'  ]=='TRAPEZE' : __ex=__ff.trapeze(0.)
+     fmoy=__ex.vale_y[-1]/(__ff.vale_x[-1]-__ff.vale_x[0])
+     __ff=__ff+(-1*fmoy)
+     __ff=__ff*__ff
+     if ECART_TYPE['METHODE'  ]=='SIMPSON' : __ez=__ff.simpson(0.)
+     if ECART_TYPE['METHODE'  ]=='TRAPEZE' : __ez=__ff.trapeze(0.)
+     sigma=math.sqrt(__ez.vale_y[-1]/(__ff.vale_x[-1]-__ff.vale_x[0]))
+     C_out=CREA_TABLE(LISTE=(_F(LISTE_K=ECART_TYPE['FONCTION'].nom,PARA='FONCTION'),
+                             _F(LISTE_K=ECART_TYPE['METHODE']     ,PARA='METHODE'),
+                             _F(LISTE_R=fmoy                      ,PARA='MOYENNE'),
+                             _F(LISTE_R=sigma                     ,PARA='ECART_TYPE'),
+                             _F(LISTE_R=tini                      ,PARA='INST_INIT'),
+                             _F(LISTE_R=tfin                      ,PARA='INST_FIN'),)
+                     )
+
+  ###
+  if (RMS != None):
+     RMS  =list(RMS)
+     sigm =[]
+     tmpi =[]
+     tmpf =[]
+     nomf =[]
+     meth =[]
+     for i_rms in RMS :
+         __ff=i_rms['FONCTION'].convert()
+         if i_rms['INST_INIT']!=None : tini=i_rms['INST_INIT']
+         else                        : tini=__ff.vale_x[0]
+         if i_rms['INST_FIN' ]!=None : tfin=i_rms['INST_FIN' ]
+         else                        : tfin=__ff.vale_x[-1]
+         __ff=__ff.cut(tini,__ff.vale_x[-1],i_rms['PRECISION'],i_rms['CRITERE'])
+         __ff=__ff.cut(__ff.vale_x[0],tfin,i_rms['PRECISION'],i_rms['CRITERE'])
+         __ff=__ff*__ff
+         if i_rms['METHODE'  ]=='SIMPSON' : __ez=__ff.simpson(0.)
+         if i_rms['METHODE'  ]=='TRAPEZE' :
+            __ez=__ff.trapeze(0.)
+         sigm.append(math.sqrt(__ez.vale_y[-1]/(__ff.vale_x[-1]-__ff.vale_x[0])))
+         tmpi.append(tini)
+         tmpf.append(tfin)
+         nomf.append(i_rms['FONCTION'].nom)
+         meth.append(i_rms['METHODE'])
+     C_out=CREA_TABLE(LISTE=(_F(LISTE_K=nomf ,PARA='FONCTION'),
+                             _F(LISTE_K=meth ,PARA='METHODE'),
+                             _F(LISTE_R=tmpi ,PARA='INST_INIT'),
+                             _F(LISTE_R=tmpf ,PARA='INST_FIN'),
+                             _F(LISTE_R=sigm ,PARA='RMS'), )
+                     )
+
+  ###
+  if (NORME != None):
+     __ff=NORME['FONCTION'].convert()
+     norme=[]
+     for __fi in __ff.l_fonc :
+         norme.append(__fi.normel2())
+     nom=[NORME['FONCTION'].nom,]*len(norme)
+     C_out=CREA_TABLE(LISTE=(_F(LISTE_R=norme ,PARA='NORME'),
+                             _F(LISTE_K=nom   ,PARA='FONCTION'), )
+                     )
+
+  ###
+  if (NOCI_SEISME != None):
+     l_table=[]
+     if NOCI_SEISME['SPEC_OSCI'] !=None :
+        ### cas intensité spectrale d'une nappe de SRO
+        ### la seule option licite est INTE_SPEC
+        UTMESS('I','INFO_FONCTION',''' : intensite spectrale, avant de calculer l'\
+intensite spectrale, il est prudent de verifier la norme de la nappe sur laquelle \
+porte le calcul, ceci peut etre une source d erreurs.''')
+        amor=NOCI_SEISME['AMOR_REDUIT']
+        fini=NOCI_SEISME['FREQ_INIT'  ]
+        ffin=NOCI_SEISME['FREQ_FIN'   ]
+        __sp  =NOCI_SEISME['SPEC_OSCI'].convert()
+        vale_x=__sp.l_fonc[0].vale_x
+        vale_y=[__sp(amor,f) for f in vale_x]
+        para  =__sp.l_fonc[0].para
+        __srov=t_fonction(vale_x,vale_y,para)
+        if   NOCI_SEISME['NATURE']=='DEPL' : 
+             __srov.vale_y=(__srov.vale_y/__srov.vale_x)*2.*math.pi
+        elif NOCI_SEISME['NATURE']=='VITE' : 
+             __srov.vale_y=__srov.vale_y/__srov.vale_x/__srov.vale_x
+        elif NOCI_SEISME['NATURE']=='ACCE' : 
+             __srov.vale_y=__srov.vale_y/__srov.vale_x/__srov.vale_x
+             __srov.vale_y=__srov.vale_y/__srov.vale_x/2./math.pi
+        __srov=__srov.cut(fini,ffin,NOCI_SEISME['PRECISION'],NOCI_SEISME['CRITERE'])
+        insp=__srov.trapeze(0.).vale_y[-1]
+        l_table.append(_F(LISTE_R=fini ,PARA='FREQ_INIT'  ))
+        l_table.append(_F(LISTE_R=ffin ,PARA='FREQ_FIN'   ))
+        l_table.append(_F(LISTE_R=amor ,PARA='AMOR_REDUIT'))
+        l_table.append(_F(LISTE_R=insp ,PARA='INTE_SPECT' ))
+     if NOCI_SEISME['FONCTION'] !=None :
+        ### cas fonction
+        l_table.append(_F(LISTE_K=NOCI_SEISME['FONCTION'].nom,PARA='FONCTION'))
+        __ac=NOCI_SEISME['FONCTION'].convert()
+        option= NOCI_SEISME['OPTION']
+        if   NOCI_SEISME['INST_INIT']!=None : tdeb=NOCI_SEISME['INST_INIT']
+        else                                : tdeb=__ac.vale_x[0]
+        if   NOCI_SEISME['INST_FIN' ]!=None : tfin=NOCI_SEISME['INST_FIN' ]
+        else                                : tfin=__ac.vale_x[-1]
+        # calcul de la vitesse :
+        __vi=__ac.trapeze(NOCI_SEISME['COEF'])
+        # calcul du déplacement :
+        __de=__vi.trapeze(NOCI_SEISME['COEF'])
+        # calcul de |acceleration| :
+        __aa=__ac.abs()
+        # calcul de integrale(|acceleration|) :
+        ### on "coupe" la fonction entre tdeb et tfin
+        __ac=__ac.cut(tdeb,tfin,NOCI_SEISME['PRECISION'],NOCI_SEISME['CRITERE'])
+        __vi=__vi.cut(tdeb,tfin,NOCI_SEISME['PRECISION'],NOCI_SEISME['CRITERE'])
+        __de=__de.cut(tdeb,tfin,NOCI_SEISME['PRECISION'],NOCI_SEISME['CRITERE'])
+        __aa=__aa.cut(tdeb,tfin,NOCI_SEISME['PRECISION'],NOCI_SEISME['CRITERE'])
+        if   NOCI_SEISME['FREQ'     ]!=None : l_freq=NOCI_SEISME['FREQ']
+        elif NOCI_SEISME['LIST_FREQ']!=None : l_freq=NOCI_SEISME['LIST_FREQ'].Valeurs()
+        else                                :  
+           # fréquences par défaut
+           l_freq=[]
+           for i in range(56) : l_freq.append( 0.2+0.050*i)
+           for i in range( 8) : l_freq.append( 3.0+0.075*i)
+           for i in range(14) : l_freq.append( 3.6+0.100*i)
+           for i in range(24) : l_freq.append( 5.0+0.125*i)
+           for i in range(28) : l_freq.append( 8.0+0.250*i)
+           for i in range( 6) : l_freq.append(15.0+0.500*i)
+           for i in range( 4) : l_freq.append(18.0+1.000*i)
+           for i in range(10) : l_freq.append(22.0+1.500*i)
+        if option in('TOUT','MAXI','ACCE_SUR_VITE') : 
+           #   calcul du max des valeurs absolues
+           maxa_ac=__ac.abs().extreme()['max'][0][1]
+           maxa_vi=__vi.abs().extreme()['max'][0][1]
+           maxa_de=__de.abs().extreme()['max'][0][1]
+           l_table.append(_F(LISTE_R=maxa_ac,PARA='ACCE_MAX'))
+           l_table.append(_F(LISTE_R=maxa_vi,PARA='VITE_MAX'))
+           l_table.append(_F(LISTE_R=maxa_de,PARA='DEPL_MAX'))
+           l_table.append(_F(LISTE_R=maxa_ac/maxa_vi,PARA='ACCE_SUR_VITE'))
+        if option in('TOUT','INTE_ARIAS') : 
+           __a2=__ac*__ac
+           inte_arias=__a2.trapeze(0.).vale_y[-1]
+           inte_arias=inte_arias*math.pi/NOCI_SEISME['PESANTEUR']/2.
+           l_table.append(_F(LISTE_R=inte_arias,PARA='INTE_ARIAS'))
+        if option in('TOUT','POUV_DEST') : 
+           __v2=__vi*__vi
+           pouv_dest=__v2.trapeze(0.).vale_y[-1]
+           pouv_dest=pouv_dest*(math.pi)**3/NOCI_SEISME['PESANTEUR']/2.
+           l_table.append(_F(LISTE_R=pouv_dest,PARA='POUV_DEST'))
+        if option in('TOUT','VITE_ABSO_CUMU') : 
+           __vc=__aa.trapeze(0.)
+           vite_abso=__vc.vale_y[-1]
+           l_table.append(_F(LISTE_R=vite_abso,PARA='VITE_ABSO_CUMU'))
+        if option in('TOUT','INTE_SPEC') :
+           amor=NOCI_SEISME['AMOR_REDUIT']
+           fini=NOCI_SEISME['FREQ_INIT'  ]
+           ffin=NOCI_SEISME['FREQ_FIN'   ]
+           __so= CALC_FONCTION(SPEC_OSCI=_F(
+                                      NATURE     ='VITE',
+                                      NATURE_FONC='ACCE',
+                                      FONCTION   =NOCI_SEISME['FONCTION'],
+                                      METHODE    ='NIGAM',
+                                      NORME      =NOCI_SEISME['NORME'],
+                                      FREQ       =l_freq,
+                                      AMOR_REDUIT=(amor,)
+                                      ), )
+           __srov=__so.convert().l_fonc[0]
+           __srov=__srov.cut(fini,ffin,NOCI_SEISME['PRECISION'],NOCI_SEISME['CRITERE'])
+           __srov.vale_y=__srov.vale_y/__srov.vale_x/__srov.vale_x
+           insp=__srov.trapeze(0.).vale_y[-1]
+           l_table.append(_F(LISTE_R=fini ,PARA='FREQ_INIT'  ))
+           l_table.append(_F(LISTE_R=ffin ,PARA='FREQ_FIN'   ))
+           l_table.append(_F(LISTE_R=amor ,PARA='AMOR_REDUIT'))
+           l_table.append(_F(LISTE_R=insp ,PARA='INTE_SPECT' ))
+        if option in('TOUT','DUREE_PHAS_FORT') : 
+           __a2=__ac*__ac
+           __i2=__a2.trapeze(0.)
+           arias = __i2.vale_y[-1]*math.pi/NOCI_SEISME['PESANTEUR']/2.
+           valinf = arias * NOCI_SEISME['BORNE_INF']
+           valsup = arias * NOCI_SEISME['BORNE_SUP']
+           for i in range(len(__i2.vale_x)) :
+               ariask = __i2.vale_y[i]*math.pi/NOCI_SEISME['PESANTEUR']/2.
+               if ariask>=valinf : break
+           for j in range(len(__i2.vale_x)-1,-1,-1) :
+               ariask = __i2.vale_y[j]*math.pi/NOCI_SEISME['PESANTEUR']/2.
+               if ariask<=valsup : break
+           dphfor = __i2.vale_x[j] - __i2.vale_x[i]
+           l_table.append(_F(LISTE_R=dphfor,PARA='DUREE_PHAS_FORT'))
+     C_out=CREA_TABLE(LISTE=l_table)
+
+  return ier
index fda98363788ef788c682f6bf78d06ecc7aa68866..4c7c9b96e6b9725a9e87e22d52922804dae2db3c 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF macr_ascouf_calc_ops Macro  DATE 22/11/2004   AUTEUR LEBOUVIE F.LEBOUVIER 
+#@ MODIF macr_ascouf_calc_ops Macro  DATE 08/02/2005   AUTEUR CIBHHLV L.VIVAN 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -358,6 +358,7 @@ def macr_ascouf_calc_ops(self,TYPE_MAILLAGE,CL_BOL_P2_GV,MAILLAGE,MODELE,CHAM_MA
 #     l epaisseur
 #
       l_grno=MAILLAGE.LIST_GROUP_NO()
+      tabprl=[None]*4
       tablig=[None]*4
 #
 #     prelevements des ligaments circonferentiels et longitudinaux
@@ -370,15 +371,20 @@ def macr_ascouf_calc_ops(self,TYPE_MAILLAGE,CL_BOL_P2_GV,MAILLAGE,MODELE,CHAM_MA
         elif (tgrno[0][:4] in LIG) and (tgrno[0][4:6] not in ('GV','TU','MI')): lgrno.append(tgrno[0])
 #
       motscles={}
-      motscles['SEGMENT']=[]
-      for grno in lgrno : motscles['SEGMENT'].append(_F(INTITULE=grno,GROUP_NO=grno))
+      motscles['ACTION']=[]
+      for grno in lgrno : 
+         motscles['ACTION'].append(_F(RESULTAT=nomres,
+                                      NOM_CHAM='SIEF_ELNO_ELGA',
+                                      TOUT_CMP='OUI',
+                                      INTITULE=grno,
+                                      GROUP_NO=grno,
+                                      OPERATION='EXTRACTION',))
       motscles['TITRE']='TABLE DE POST-TRAITEMENT SECTION SOUS-EPAISSEUR'
+      tabprl[1]=POST_RELEVE_T(**motscles)
       tablig[1]=POST_RCCM(MATER          = rccmat,
-                          MAILLAGE       = MAILLAGE,
                           TYPE_RESU_MECA = 'EVOLUTION',
                           OPTION         = 'PM_PB',
-                          TRANSITOIRE=_F(RESULTAT=nomres,
-                                         NOM_CHAM='SIEF_ELNO_ELGA',),**motscles)
+                          TRANSITOIRE=_F(TABL_RESU_MECA = tabprl[1],),)
 #
       motscles={}
       motscles['ACTION']=[]
@@ -436,6 +442,7 @@ def macr_ascouf_calc_ops(self,TYPE_MAILLAGE,CL_BOL_P2_GV,MAILLAGE,MODELE,CHAM_MA
 #     les 8 ligaments sont tous les 45 degres
 #
       ACOUR = mc_IMPR_TABLE['ANGLE']*pi/180.0
+      secprl=[None]*3
       secrcm=[None]*3
       secinv=[None]*3
       secmoy=[None]*3
@@ -450,15 +457,21 @@ def macr_ascouf_calc_ops(self,TYPE_MAILLAGE,CL_BOL_P2_GV,MAILLAGE,MODELE,CHAM_MA
 #
 #        moyenne RCCM sur les sections MI,TU et GV
 #
-         motscles['SEGMENT']=[]
-         for j in range(8) : motscles['SEGMENT'].append(_F(INTITULE=LIG[j]+SECT[i],
-                                                           GROUP_NO=LIG[j]+SECT[i]))
-         secrcm[i] = POST_RCCM( MAILLAGE        = MAILLAGE ,
-                                MATER           = rccmat ,
-                                TYPE_RESU_MECA  = 'EVOLUTION' ,
-                                OPTION          = 'PM_PB' ,
-                                TRANSITOIRE     = _F(RESULTAT = nomres,NOM_CHAM='SIEF_ELNO_ELGA'),
-                                **motscles)
+         motscles={}
+         motscles['ACTION']=[]
+         for j in range(8) :
+            motscles['ACTION'].append(_F(RESULTAT=nomres,
+                                         NOM_CHAM='SIEF_ELNO_ELGA',
+                                         TOUT_CMP='OUI',
+                                         INTITULE=LIG[j]+SECT[i],
+                                         GROUP_NO=LIG[j]+SECT[i],
+                                         OPERATION='EXTRACTION',))
+         motscles['TITRE']='TABLE DE POST-TRAITEMENT MOYENNE RCCM SECTION '+SECT[i]
+         secprl[i]=POST_RELEVE_T(**motscles)
+         secrcm[i]=POST_RCCM(MATER          = rccmat,
+                             TYPE_RESU_MECA = 'EVOLUTION',
+                             OPTION         = 'PM_PB',
+                             TRANSITOIRE=_F(TABL_RESU_MECA = secprl[i],),)
 #
 #        invariants sur les sections MI,TU et GV
 #
index f7b95acf0ee074b3190ac775ecd1c0179f67a91d..fe02927abf74a0bfd4a6a7b974ce96c26c5999c2 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF macr_ascouf_mail_ops Macro  DATE 30/11/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF macr_ascouf_mail_ops Macro  DATE 09/05/2005   AUTEUR LEBOUVIE F.LEBOUVIER 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -2339,8 +2339,8 @@ def macr_ascouf_mail_ops(self,EXEC_MAILLAGE,TYPE_ELEM,COUDE,
 # coude fissure
 #
   if FISS_COUDE!=None:
-    if (RM/EP1)<5. or (RM/EP1)>12.:
-       print ' <MACR_ASCOUF_MAIL> valeur hors domaine de validite (5,12)'
+    if (RM/EP1)<5. or (RM/EP1)>50.:
+       print ' <MACR_ASCOUF_MAIL> valeur hors domaine de validite (5,50)'
        print ' <MACR_ASCOUF_MAIL> rapport RM/EP1 :',(RM/EP1)
        self.cr.fatal("<F> <MACR_ASCOUF_MAIL> erreur donnees ")
        ier = ier+1
index b6d91b36d21b049d23f658f8f5adc195382bee98..5426c3958b71597413f025effeac2e76efe90440 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF macr_aspic_calc_ops Macro  DATE 22/11/2004   AUTEUR LEBOUVIE F.LEBOUVIER 
+#@ MODIF macr_aspic_calc_ops Macro  DATE 08/02/2005   AUTEUR CIBHHLV L.VIVAN 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -427,18 +427,21 @@ def macr_aspic_calc_ops(self,TYPE_MAILLAGE,TUBULURE,MAILLAGE,MODELE,CHAM_MATER,C
         if i<10 : NUME = '0'+str(i)
         else    : NUME =     str(i)
         mcsimp={}
-        mcsimp['PRECISION']=55.E-1
-        mcsimp['GROUP_NO' ]='LD'+str(i)
+        mcsimp['INTITULE'   ]='LD'+str(i)
+        mcsimp['GROUP_NO'   ]='LD'+str(i)
+        mcsimp['RESULTAT'   ]=nomres
+        mcsimp['TOUT_ORDRE' ]='OUI'
+        mcsimp['NOM_CHAM'   ]='SIEF_ELNO_ELGA'
+        mcsimp['PRECISION'  ]=55.E-1
+        mcsimp['TOUT_CMP'   ]='OUI'
+        mcsimp['OPERATION'  ]='EXTRACTION'
         mcfact.append( _F(**mcsimp) )
-      __pmpbsd=POST_RCCM(MATER       = MRCCM,
-                         MAILLAGE    = MAILLAGE,
+      __prelsd=POST_RELEVE_T(ACTION=mcfact)
+      __pmpbsd=POST_RCCM(OPTION         = 'PM_PB',
                          TYPE_RESU_MECA = 'EVOLUTION',
-                         TYPE_RESU   = 'VALE_MAX',
-                         OPTION      = 'PM_PB',
-                         SEGMENT     = mcfact,
-                         TRANSITOIRE = _F(RESULTAT  =nomres,
-                                          NOM_CHAM  ='SIEF_ELNO_ELGA',
-                                          TOUT_ORDRE='OUI',),
+                         TYPE_RESU      = 'VALE_MAX',
+                         MATER          = MRCCM,
+                         TRANSITOIRE = _F(TABL_RESU_MECA = __prelsd,),
                          TITRE       = '-- TRAITEMENT DES AZIMUTS DROITS --',)
       IMPR_TABLE(TABLE = __pmpbsd, )
 #
@@ -514,18 +517,21 @@ def macr_aspic_calc_ops(self,TYPE_MAILLAGE,TUBULURE,MAILLAGE,MODELE,CHAM_MATER,C
         if i<10 : NUME = '0'+str(i)
         else    : NUME =     str(i)
         mcsimp={}
-        mcsimp['PRECISION']=55.E-1
-        mcsimp['GROUP_NO' ]='LI'+str(i)
+        mcsimp['INTITULE'   ]='LI'+str(i)
+        mcsimp['GROUP_NO'   ]='LI'+str(i)
+        mcsimp['RESULTAT'   ]=nomres
+        mcsimp['TOUT_ORDRE' ]='OUI'
+        mcsimp['NOM_CHAM'   ]='SIEF_ELNO_ELGA'
+        mcsimp['PRECISION'  ]=55.E-1
+        mcsimp['TOUT_CMP'   ]='OUI'
+        mcsimp['OPERATION'  ]='EXTRACTION'
         mcfact.append( _F(**mcsimp) )
-      __pmpbsi=POST_RCCM(MATER       = MRCCM,
-                         MAILLAGE    = MAILLAGE,
+      __prelsi=POST_RELEVE_T(ACTION=mcfact)
+      __pmpbsi=POST_RCCM(OPTION         = 'PM_PB',
                          TYPE_RESU_MECA = 'EVOLUTION',
-                         TYPE_RESU   = 'VALE_MAX',
-                         OPTION      = 'PM_PB',
-                         SEGMENT     = mcfact,
-                         TRANSITOIRE = _F(RESULTAT  =nomres,
-                                          NOM_CHAM  ='SIEF_ELNO_ELGA',
-                                          TOUT_ORDRE='OUI',),
+                         TYPE_RESU      = 'VALE_MAX',
+                         MATER          = MRCCM,
+                         TRANSITOIRE = _F(TABL_RESU_MECA = __prelsi,),
                          TITRE       = '-- TRAITEMENT DES AZIMUTS INCLINES --',)
       IMPR_TABLE(TABLE = __pmpbsi, )
 #
index d5ad388f8fd5212b1c6a63d81ead9cdb2147870c..92154545dc83412692f6eddba2ed122c8ba27925 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF macr_cabri_mail_ops Macro  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOI
+#@ MODIF macr_cabri_mail_ops Macro  DATE 07/02/2005   AUTEUR MABBAS M.ABBA
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -72,11 +72,11 @@ def macr_cabri_mail_ops(self,EXEC_MAILLAGE,RAFF_MAILLAGE,VERI_MAIL,GEOM_BRID,
    imp_formF = 1
   else:
    imp_formF = 0 
-  if IMPRESSION['FICHIER']!=None:
-   imp_fich = IMPRESSION['FICHIER']
-   imp_fichF = 1
-  else:
-   imp_fichF = 0 
+#  if IMPRESSION['FICHIER']!=None:
+#   imp_fich = IMPRESSION['FICHIER']
+#   imp_fichF = 1
+#  else:
+#   imp_fichF = 0 
  
   # Maillage  
   nrad = RAFF_MAILLAGE['NB_RADIAL']
@@ -141,8 +141,8 @@ def macr_cabri_mail_ops(self,EXEC_MAILLAGE,RAFF_MAILLAGE,VERI_MAIL,GEOM_BRID,
   nomres = LIRE_MAILLAGE(VERI_MAIL=_F(APLAT = ver_apla,
                                       VERIF = ver_veri ),)
                                       
-  if (imp_fichF == 1):  
-   print imp_fich
+#  if (imp_fichF == 1):  
+#   print imp_fich
   if (imp_formF == 1):  
    print imp_form
   if (imp_unitF == 1):  
index 3b338c7787f7a83bb4f0e67adda87004b54ff3a3..08ac8d107e50643307c146ce74840bf8a2085ee9 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF macr_fiab_impr_ops Macro  DATE 07/10/2004   AUTEUR GNICOLAS G.NICOLAS 
+#@ MODIF macr_fiab_impr_ops Macro  DATE 24/01/2005   AUTEUR DURAND C.DURAND 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -17,8 +17,6 @@
 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,         
 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
 # ======================================================================
-
-
 # RESPONSABLE GNICOLAS G.NICOLAS
 #
 def macr_fiab_impr_ops(self, INFO,
@@ -86,14 +84,16 @@ def macr_fiab_impr_ops(self, INFO,
 # 5. Ecritures des gradients
 #____________________________________________________________________
 #
-  for val in GRADIENTS :
+  if GRADIENTS is not None :
 #
-    IMPR_TABLE ( TABLE = val["TABLE"],
-                 SENSIBILITE = val["PARA_SENSI"],
-                 NOM_PARA = (val["NOM_PARA"]),
-                 UNITE = Unite_Fichier_ASTER_vers_FIABILITE,
-                 FORMAT_R = FORMAT_R,
-                 INFO = INFO )
+    for val in GRADIENTS :
+#
+      IMPR_TABLE ( TABLE = val["TABLE"],
+                   SENSIBILITE = val["PARA_SENSI"],
+                   NOM_PARA = (val["NOM_PARA"]),
+                   UNITE = Unite_Fichier_ASTER_vers_FIABILITE,
+                   FORMAT_R = FORMAT_R,
+                   INFO = INFO )
 #____________________________________________________________________
 #
 # 6. Libération du fichier d'échange
index 0d57da06df6424a033e91b9026305972fdd1fe9c..107ec4a2e19c9a3dc81361621f51cf30c59c0164 100644 (file)
@@ -1,21 +1,21 @@
-#@ MODIF macr_lign_coupe_ops Macro  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF macr_lign_coupe_ops Macro  DATE 14/02/2005   AUTEUR DURAND C.DURAND 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
-# 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 EDF R&D CODE_ASTER,         
-#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
+# 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 EDF R&D CODE_ASTER,
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
 # ======================================================================
 
 
 ########################################################################
 # script PYTHON de creation d un maillage de ligne de coupe
 
-def crea_mail_lig_coup(lignes):
+def crea_mail_lig_coup(dimension,lignes,groups):
 
   import os,sys,copy
 
-  try:
 # construction du maillage au format Aster des segments de lignes de coupe
 
-    nblig=len(lignes)
-    dimension=len(lignes[0][0])
+  nblig=len(lignes)
+  nbngr=len(groups)
 
-    resu='TITRE\n'
-    titre='Maillage ligne de coupe'+'\n'
-    resu=resu+'FINSF\n'
-    resu=resu+'COOR_'+str(dimension)+'D\n'
+  resu='TITRE\n'
+  titre='Maillage ligne de coupe'+'\n'
+  resu=resu+'FINSF\n'
+  resu=resu+'COOR_'+str(dimension)+'D\n'
 
 # creation des noeuds
-    nbno=0
-    for i in range(nblig):
-      pt1           = lignes[i][0]
-      pt2           = lignes[i][1]
-      nbp_lig_coupe = lignes[i][2]
-      for j in range(nbp_lig_coupe):
-        if dimension==2:
-          x=pt1[0]+j*(pt2[0]-pt1[0])/(nbp_lig_coupe-1)
-          y=pt1[1]+j*(pt2[1]-pt1[1])/(nbp_lig_coupe-1)
-          nbno=nbno+1
-          noeud='  N'+str(nbno)+'   '+str(x)+'    '+str(y)+'\n'
-          resu=resu+noeud
-        elif dimension==3:
-          x=pt1[0]+j*(pt2[0]-pt1[0])/(nbp_lig_coupe-1)
-          y=pt1[1]+j*(pt2[1]-pt1[1])/(nbp_lig_coupe-1)
-          z=pt1[2]+j*(pt2[2]-pt1[2])/(nbp_lig_coupe-1)
-          nbno=nbno+1
-          noeud='  N'+str(nbno)+'   '+str(x)+'    '+str(y)+'    '+str(z)+'\n'
-          resu=resu+noeud
-    resu=resu+'FINSF\n'
+  nbno=0
+  for i in range(nblig):
+    pt1           = lignes[i][0]
+    pt2           = lignes[i][1]
+    nbp_lig_coupe = lignes[i][2]
+    for j in range(nbp_lig_coupe):
+      if dimension==2:
+        x=pt1[0]+j*(pt2[0]-pt1[0])/(nbp_lig_coupe-1)
+        y=pt1[1]+j*(pt2[1]-pt1[1])/(nbp_lig_coupe-1)
+        nbno=nbno+1
+        noeud='  N'+str(nbno)+'   '+str(x)+'    '+str(y)+'\n'
+        resu=resu+noeud
+      elif dimension==3:
+        x=pt1[0]+j*(pt2[0]-pt1[0])/(nbp_lig_coupe-1)
+        y=pt1[1]+j*(pt2[1]-pt1[1])/(nbp_lig_coupe-1)
+        z=pt1[2]+j*(pt2[2]-pt1[2])/(nbp_lig_coupe-1)
+        nbno=nbno+1
+        noeud='  N'+str(nbno)+'   '+str(x)+'   '+str(y)+'   '+str(z)+'\n'
+        resu=resu+noeud
+  for i in range(nbngr):
+    for pt in groups[i][1:]:
+      if dimension==2:
+        nbno=nbno+1
+        noeud='  N'+str(nbno)+' '+str(pt[0])+'    '+str(pt[1])+'\n'
+        resu=resu+noeud
+      elif dimension==3:
+        nbno=nbno+1
+        noeud='  N'+str(nbno)+' '+str(pt[0])+'    '+str(pt[1])+'    '+str(pt[2])+'\n'
+        resu=resu+noeud
+  resu=resu+'FINSF\n'
 
 # creation des mailles
-    nbma=0
-    for i in range(nblig):
-      nbp_lig_coupe = lignes[i][2]
-      resu=resu+'SEG2\n'
-      for j in range(nbp_lig_coupe-1):
-          nbma=nbma+1
-          maille='  M'+str(nbma)+' N'+str(nbma+i)+' N'+str(nbma+1+i)+'\n'
-          resu=resu+maille
-      resu=resu+'FINSF\n'
+  nbma=0
+  for i in range(nblig):
+    nbp_lig_coupe = lignes[i][2]
+    resu=resu+'SEG2\n'
+    for j in range(nbp_lig_coupe-1):
+        nbma=nbma+1
+        maille='  M'+str(nbma)+' N'+str(nbma+i)+' N'+str(nbma+1+i)+'\n'
+        resu=resu+maille
+    resu=resu+'FINSF\n'
+  for i in range(nbngr):
+    resu=resu+'SEG2\n'
+    for pt in groups[i][1:-1]:
+        nbma=nbma+1
+        maille='  M'+str(nbma)+' N'+str(nbma+nblig+i)+' N'+str(nbma+nblig+1+i)+'\n'
+        resu=resu+maille
+    resu=resu+'FINSF\n'
 
 # creation des groupes de mailles (1 par ligne de coupe)
-    nbma=0
-    for i in range(nblig):
-      resu=resu+'GROUP_MA\n'
-      resu=resu+'  LICOU'+str(i+1)
-      nbp_lig_coupe = lignes[i][2]
-      for j in range(nbp_lig_coupe-1):
-          nbma=nbma+1
-          resu=resu+'  M'+str(nbma)+'\n'
-      resu=resu+'\n'
-      resu=resu+'FINSF\n'
-    resu=resu+'FIN\n'
-
-    return resu
-
-  except :
-    return 0
+  nbma=0
+  for i in range(nblig):
+    resu=resu+'GROUP_MA\n'
+    resu=resu+'  LICOU'+str(i+1)
+    nbp_lig_coupe = lignes[i][2]
+    for j in range(nbp_lig_coupe-1):
+        nbma=nbma+1
+        resu=resu+'  M'+str(nbma)+'\n'
+    resu=resu+'\n'
+    resu=resu+'FINSF\n'
+  for i in range(nbngr):
+    resu=resu+'GROUP_MA\n'
+    resu=resu+groups[i][0]
+    nbp_lig_coupe = len(groups[i])-1
+    for j in range(nbp_lig_coupe-1):
+        nbma=nbma+1
+        resu=resu+'  M'+str(nbma)+'\n'
+    resu=resu+'\n'
+    resu=resu+'FINSF\n'
+  resu=resu+'FIN\n'
+
+  return resu
+
 
 ########################################################################
-def macr_lign_coupe_ops(self,RESULTAT,UNITE_MAILLAGE,LIGN_COUPE,MODELE,
-                        NOM_CHAM,**args):
+def macr_lign_coupe_ops(self,RESULTAT,UNITE_MAILLAGE,LIGN_COUPE,NOM_CHAM,MODELE,**args):
   """
      Ecriture de la macro MACR_LIGN_COUPE
   """
-  import os
+  import os,string,types
   from Accas import _F
   from Noyau.N_utils import AsType
+  import aster
   ier=0
 
   # On importe les definitions des commandes a utiliser dans la macro
@@ -106,20 +129,57 @@ def macr_lign_coupe_ops(self,RESULTAT,UNITE_MAILLAGE,LIGN_COUPE,MODELE,
   AFFE_MODELE    =self.get_cmd('AFFE_MODELE')
   PROJ_CHAMP     =self.get_cmd('PROJ_CHAMP')
   POST_RELEVE_T  =self.get_cmd('POST_RELEVE_T')
+  CREA_TABLE     =self.get_cmd('CREA_TABLE')
 
   # La macro compte pour 1 dans la numerotation des commandes
   #self.icmd=1
   self.set_icmd(1)
+  
+  nomresu=RESULTAT.nom
+  l_modele=aster.getvectjev(nomresu.ljust(19)+'.MODL')
+  n_modele=string.strip(l_modele[0])
+  if n_modele=='' :
+     if MODELE==None:
+       ier=ier+1
+       self.cr.fatal("<F> <MACR_LIGN_COUPE> nom du modele absent dans le concept resultat "+nomresu)
+       return ier
+     else : n_modele=MODELE.nom
+  l_mailla=aster.getvectjev(n_modele.ljust(8)+'.MODELE    .NOMA')
+  n_mailla=string.strip(l_mailla[0])
+  dime=aster.getvectjev(n_mailla.ljust(8)+'.DIME')[5]
+  collgrno=aster.getcolljev(n_mailla.ljust(8)+'.GROUPENO')
 
   lignes=[]
+  groups=[]
+  minidim=dime
   for m in LIGN_COUPE :
-      lignes.append((m['COOR_ORIG'],m['COOR_EXTR'],m['NB_POINTS']))
+      if m['NB_POINTS'] !=None :
+         lignes.append((m['COOR_ORIG'],m['COOR_EXTR'],m['NB_POINTS']))
+         minidim=min(minidim,len(m['COOR_ORIG']),len(m['COOR_EXTR']))
+      elif m['GROUP_NO']!=None :
+        ngrno=m['GROUP_NO'].ljust(8).upper()
+        if ngrno not in collgrno.keys() :
+          ier=ier+1
+          self.cr.fatal("<F> <MACR_LIGN_COUPE> le group_no "+ngrno+" n est pas dans le maillage "+n_mailla)
+          return ier
+        grpn=collgrno[ngrno]
+        l_coor_group=[ngrno,]
+        for node in grpn:
+          l_coor_group.append(aster.getvectjev(n_mailla.ljust(8)+'.COORDO    .VALE',3*(node-1),3))
+        groups.append(l_coor_group)
+
+  if minidim!=dime:
+    ier=ier+1
+    self.cr.fatal("<F> <MACR_LIGN_COUPE> dimensions de maillage et de coordonnees incoherentes")
+    return ier
+
 
   # Création du maillage des NB_POINTS segments entre COOR_ORIG et COOR_EXTR
+  # ainsi que des segments reliant les noeuds issus des group_no demandés
   # par appel au script python crea_mail_lig_coup
   # le maillage est ensuite recopié dans l unité logique UNITE_MAILLAGE
 
-  resu_mail=crea_mail_lig_coup(lignes)
+  resu_mail=crea_mail_lig_coup(dime,lignes,groups)
   cur_dir=os.getcwd()
   nomFichierSortie   =cur_dir+'/fort.'+str(UNITE_MAILLAGE)
   fproc=open(nomFichierSortie,'w')
@@ -134,8 +194,11 @@ def macr_lign_coupe_ops(self,RESULTAT,UNITE_MAILLAGE,LIGN_COUPE,MODELE,
   iocc=1
   motscles['CREA_GROUP_NO']=[]
   for m in LIGN_COUPE :
-      motscles['CREA_GROUP_NO'].append(_F(GROUP_MA='LICOU'+str(iocc),) )
-      iocc=iocc+1
+      if m['NB_POINTS'] !=None :
+        motscles['CREA_GROUP_NO'].append(_F(GROUP_MA='LICOU'+str(iocc),) )
+        iocc=iocc+1
+      elif m['GROUP_NO']!=None :
+        motscles['CREA_GROUP_NO'].append(_F(GROUP_MA=m['GROUP_NO'].ljust(8).upper(),) )
   __macou=DEFI_GROUP( reuse =__macou , MAILLAGE=__macou , **motscles );
 
   if AsType(RESULTAT).__name__ in ('evol_elas','evol_noli') :
@@ -151,23 +214,52 @@ def macr_lign_coupe_ops(self,RESULTAT,UNITE_MAILLAGE,LIGN_COUPE,MODELE,
 
   __recou=PROJ_CHAMP(METHODE='ELEM',
                      RESULTAT=RESULTAT,
-                     MODELE_1=MODELE,
+                     MODELE_1=self.jdc.current_context[n_modele],
                      MODELE_2=__mocou,
+                     TYPE_CHAM='NOEU',
                      NOM_CHAM=NOM_CHAM,);
 
-  # Production d'une table par ligne de coupe
-  # Toutes les tables sont des concepts sortant de la macro définies
-  # dans chaque occurence du mcfact lign_coupe
+  # Production d'une table pour toutes les lignes de coupe
 
-  iocc=1
+  ioc2=0
+  mcACTION=[]
   for m in LIGN_COUPE :
-      self.DeclareOut('tt',m['TABLE'])
-      tt=POST_RELEVE_T(ACTION=_F(INTITULE  = 'lig.coupe'+str(iocc),
-                                 RESULTAT  = __recou,
-                                 GROUP_NO  = 'LICOU'+str(iocc),
-                                 NOM_CHAM  = NOM_CHAM,
-                                 TOUT_CMP  = 'OUI',
-                                 OPERATION = 'EXTRACTION', ),);
-      iocc=iocc+1
+      if m['NB_POINTS'] !=None :
+        ioc2=ioc2+1
+        groupe='LICOU'+str(ioc2)
+        if m['INTITULE'] !=None : intitl=m['INTITULE']
+        else                    : intitl='l.coupe'+str(ioc2)
+      elif m['GROUP_NO']!=None :
+        groupe=m['GROUP_NO'].ljust(8).upper()
+        if m['INTITULE'] !=None : intitl=m['INTITULE']
+        else                    : intitl=groupe
+      mcACTION.append( _F(INTITULE  = intitl,
+                          RESULTAT  = __recou,
+                          GROUP_NO  = groupe,
+                          NOM_CHAM  = NOM_CHAM,
+                          TOUT_CMP  = 'OUI',
+                          OPERATION = 'EXTRACTION', )           )
+
+  __tabitm=POST_RELEVE_T(ACTION=mcACTION,);
+
+  # on repasse par les tables python pour supprimer les paramètres inutiles
+  # NOEUD (car il est propre au maillage de la ligne) et RESU
+
+  self.DeclareOut('nomres',self.sd)
+  dictab=__tabitm.EXTR_TABLE()
+  listpara=dictab.para
+  listpara.remove('NOEUD')
+  listpara.remove('RESU')
+
+  coltab=[]
+  for key in listpara :
+      val=dictab[key].values()[key]
+      if   type(val[0])==types.IntType :
+         coltab.append(_F(PARA=key,LISTE_I=val))
+      elif type(val[0])==types.FloatType :
+         coltab.append(_F(PARA=key,LISTE_R=val))
+      elif type(val[0])==types.StringType :
+         coltab.append(_F(PARA=key,LISTE_K=val,TYPE_K='K16'))
+  nomres=CREA_TABLE(LISTE=coltab)
 
   return ier
index 308846a5dc39e848260474efc0584e8259e64799..17597e9045ca72bda20113bef5396f5087b2f865 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF macr_recal_ops Macro  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF macr_recal_ops Macro  DATE 14/03/2005   AUTEUR DURAND C.DURAND 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -45,7 +45,7 @@ def macr_recal_ops(self,UNITE_ESCL, RESU_EXP, POIDS, LIST_PARA, RESU_CALC,
    import Macro
    from Cata import cata
    from Cata.cata import DEFI_LIST_REEL
-   from Macro.recal import gestion,transforme_list_Num,EXTRACT,calcul_F,graphique
+   from Macro.recal import gestion,transforme_list_Num,calcul_F,graphique
    from Macro import reca_message
    from Macro import reca_algo
    from Macro import reca_interp
@@ -82,7 +82,6 @@ def macr_recal_ops(self,UNITE_ESCL, RESU_EXP, POIDS, LIST_PARA, RESU_CALC,
         if v.__class__.__name__ in ('OPER','MACRO'):
            self.current_context[k]= v
    self.current_context['_F']=cata.__dict__['_F']
-   self.g_context['EXTRACT']=EXTRACT
 
    #_____________________________________________
    #
diff --git a/Aster/Cata/Macro/macro_cara_poutre_ops.py b/Aster/Cata/Macro/macro_cara_poutre_ops.py
deleted file mode 100644 (file)
index a98d3d6..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-# -*- coding: utf-8 -*-
-#@ MODIF macro_cara_poutre_ops Macro  DATE 25/06/2002   AUTEUR JMBHH01 J.M.PROIX 
-#            CONFIGURATION MANAGEMENT OF EDF VERSION
-# ======================================================================
-# COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
-# 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 EDF R&D CODE_ASTER,         
-#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
-# ======================================================================
-# RESPONSABLE JMBHH01 J.M.PROIX
-def macro_cara_poutre_ops(self,UNITE_MAILLAGE,SYME_X,SYME_Y,GROUP_MA_BORD,
-                              GROUP_MA,ORIG_INER,NOEUD,GROUP_MA_INTE,
-                              LONGUEUR,MATERIAU,LIAISON,
-                              **args):
-  """
-     Ecriture de la macro MACRO_CARA_POUTRE
-  """
-  import types
-  from Accas import _F
-  ier=0
-  # On importe les definitions des commandes a utiliser dans la macro
-  # Le nom de la variable doit etre obligatoirement le nom de la commande
-  LIRE_MAILLAGE   =self.get_cmd('LIRE_MAILLAGE')
-  DEFI_GROUP      =self.get_cmd('DEFI_GROUP')
-  CREA_MAILLAGE   =self.get_cmd('CREA_MAILLAGE')
-  AFFE_MODELE     =self.get_cmd('AFFE_MODELE')
-  DEFI_MATERIAU   =self.get_cmd('DEFI_MATERIAU')
-  AFFE_MATERIAU   =self.get_cmd('AFFE_MATERIAU')
-  DEFI_FONCTION   =self.get_cmd('DEFI_FONCTION')
-  DEFI_CONSTANTE  =self.get_cmd('DEFI_CONSTANTE')
-  AFFE_CHAR_THER  =self.get_cmd('AFFE_CHAR_THER')
-  AFFE_CHAR_THER_F=self.get_cmd('AFFE_CHAR_THER_F')
-  THER_LINEAIRE   =self.get_cmd('THER_LINEAIRE')
-  CALC_VECT_ELEM  =self.get_cmd('CALC_VECT_ELEM')
-  CALC_MATR_ELEM  =self.get_cmd('CALC_MATR_ELEM')
-  NUME_DDL        =self.get_cmd('NUME_DDL')
-  ASSE_VECTEUR    =self.get_cmd('ASSE_VECTEUR')
-  POST_ELEM       =self.get_cmd('POST_ELEM')
-  # La macro compte pour 1 dans la numerotation des commandes
-  self.icmd=1
-
-  # Le concept sortant (de type tabl_cara_geom) est nommé 'nomres' dans 
-  # le contexte de la macro
-  
-  self.DeclareOut('nomres',self.sd)
-
-  if GROUP_MA_BORD and GROUP_MA:
-     if not LIAISON:
-        ier=ier+1
-        self.cr.fatal("Avec GROUP_MA, il faut obligatoirement preciser LIAISON, LONGUEUR ET MATERIAU")
-        return ier
-
-  __nomlma=LIRE_MAILLAGE(UNITE=UNITE_MAILLAGE,)
-
-  __nomamo=AFFE_MODELE(MAILLAGE=__nomlma,
-                       AFFE=_F(TOUT='OUI',
-                               PHENOMENE='MECANIQUE',
-                               MODELISATION='D_PLAN',),   )
-
-  __nomdma=DEFI_MATERIAU(ELAS=_F(E=1.0,NU=0.,RHO=1.0),)
-
-
-  __nomama=AFFE_MATERIAU(MAILLAGE=__nomlma,
-                         AFFE=_F(TOUT='OUI',
-                                 MATER=__nomdma,),  )
-
-# --- CALCUL DES CARACTERISTIQUES GEOMETRIQUES DE LA SECTION :
-#     ------------------------------------------------------
-
-  motsimps={}
-  if GROUP_MA  : motsimps['GROUP_MA']  = GROUP_MA
-  if SYME_X    : motsimps['SYME_X']    = SYME_X
-  if SYME_Y    : motsimps['SYME_Y']    = SYME_Y
-  motsimps['ORIG_INER'] = ORIG_INER
-  mfact=_F(TOUT='OUI',**motsimps)
-  nomres=POST_ELEM(MODELE=__nomamo,
-                   CHAM_MATER=__nomama,
-                   CARA_GEOM=mfact    )
-
-# nb  :  si GROUP_MA n existe pas : le mot clé est ignoré
-
-#
-#     ==================================================================
-# --- = CALCUL DE LA CONSTANTE DE TORSION SUR TOUT LE MAILLAGE         =
-# --- =     OU DU  CENTRE DE TORSION/CISAILLEMENT                      =
-# --- =        DES COEFFICIENTS DE CISAILLEMENT                        =
-# --- =     ET DE L INERTIE DE GAUCHISSEMENT                           =
-# --- = ON CREE UN MODELE PLAN 2D THERMIQUE REPRESENTANT LA SECTION    =
-# --- = DE LA POUTRE CAR ON A A RESOUDRE DES E.D.P. AVEC DES LAPLACIENS=
-#     ==================================================================
-
-  if GROUP_MA_BORD and not GROUP_MA:
-
-# --- TRANSFORMATION DES GROUP_MA EN GROUP_NO SUR-LESQUELS
-# --- ON POURRA APPLIQUER DES CONDITIONS DE TEMPERATURE IMPOSEE :
-#     ---------------------------------------------------------
-     motscles={}
-     if type(GROUP_MA_BORD)==types.StringType:
-        motscles['CREA_GROUP_NO']=_F(GROUP_MA=GROUP_MA_BORD,)
-     else:
-        motscles['CREA_GROUP_NO']=[]
-        for grma in GROUP_MA_BORD:
-           motscles['CREA_GROUP_NO'].append(_F(GROUP_MA=grma,))
-     __nomlma=DEFI_GROUP(reuse=__nomlma,
-                         MAILLAGE=__nomlma,
-                         **motscles)
-
-
-# --- CREATION D UN MAILLAGE IDENTIQUE AU PREMIER A CECI PRES
-# --- QUE LES COORDONNEES SONT EXPRIMEES DANS LE REPERE PRINCIPAL
-# --- D INERTIE DONT L ORIGINE EST LE CENTRE DE GRAVITE DE LA SECTION :
-#     ---------------------------------------------------------------
-
-     __nomapi=CREA_MAILLAGE(MAILLAGE=__nomlma,
-                            REPERE=_F(TABLE=nomres,
-                                      NOM_ORIG='CDG',  ),  )
-
-# --- AFFECTATION DU PHENOMENE 'THERMIQUE' AU MODELE EN VUE DE
-# --- LA CONSTRUCTION D UN OPERATEUR LAPLACIEN SUR CE MODELE :
-#     ------------------------------------------------------
-
-     __nomoth=AFFE_MODELE(MAILLAGE=__nomapi,
-                          AFFE=_F(TOUT='OUI',
-                                  PHENOMENE='THERMIQUE',
-                                  MODELISATION='PLAN',), )
-
-# --- POUR LA CONSTRUCTION DU LAPLACIEN, ON  DEFINIT UN
-# --- PSEUDO-MATERIAU DONT LES CARACTERISTIQUES THERMIQUES SONT :
-# --- LAMBDA = 1, RHO*CP = 0 :
-#     ----------------------
-
-     __nomath=DEFI_MATERIAU(THER=_F(LAMBDA=1.0,RHO_CP=0.,),)
-
-# --- DEFINITION D UN CHAM_MATER A PARTIR DU MATERIAU PRECEDENT :
-#     ---------------------------------------------------------
-
-     __chmath=AFFE_MATERIAU(MAILLAGE=__nomapi,
-                            AFFE=_F(TOUT='OUI',
-                                    MATER=__nomath,),   )
-
-#
-#     ------------------------------------------------------------
-# --- - CALCUL DE LA CONSTANTE DE TORSION PAR RESOLUTION         -
-# --- - D UN LAPLACIEN AVEC UN TERME SOURCE EGAL A -2            -
-# --- - L INCONNUE ETANT NULLE SUR LE CONTOUR DE LA SECTION :    -
-# --- -    LAPLACIEN(PHI) = -2 DANS LA SECTION                   -
-# --- -    PHI = 0 SUR LE CONTOUR :                              -
-#     ------------------------------------------------------------
-#
-# --- ON IMPOSE LA VALEUR 0 A L INCONNUE SCALAIRE SUR LE CONTOUR
-# --- DE LA SECTION
-# --- ET ON A UN TERME SOURCE EGAL A -2 DANS TOUTE LA SECTION :
-#     -------------------------------------------------------
-
-     motscles={}
-     if GROUP_MA_INTE:
-        motscles['LIAISON_UNIF']=_F(GROUP_MA=GROUP_MA_INTE,DDL='TEMP'),
-     __chart1=AFFE_CHAR_THER(MODELE=__nomoth,
-                             TEMP_IMPO   =_F(GROUP_NO=GROUP_MA_BORD,
-                                             TEMP=0. ),
-                             SOURCE      =_F(TOUT='OUI',
-                                             SOUR=2.0),
-                             **motscles  )
-
-# ---  POUR CHAQUE TROU DE LA SECTION :
-# ---  .ON A IMPOSE QUE PHI EST CONSTANT SUR LE CONTOUR INTERIEUR
-# ---   EN FAISANT LE LIAISON_UNIF DANS LE AFFE_CHAR_THER PRECEDENT
-# ---  .ON IMPOSE EN PLUS D(PHI)/DN = 2*AIRE(TROU)/L(TROU)
-# ---        OU D/DN DESIGNE LA DERIVEE PAR RAPPORT A LA
-# ---        NORMALE ET L DESIGNE LA LONGUEUR DU BORD DU TROU :
-#     -------------------------------------------------------
-
-     if GROUP_MA_INTE:
-        __tbaire=POST_ELEM(MODELE=__nomoth,
-                           AIRE_INTERNE=_F(GROUP_MA_BORD=GROUP_MA_INTE,),  )
-
-        motscles={}
-        motscles['FLUX_REP']=[]
-        if type(GROUP_MA_INTE)==types.StringType:
-           motscles['FLUX_REP']=_F(GROUP_MA=GROUP_MA_INTE,CARA_TORSION=__tbaire)
-        else:
-           motscles['FLUX_REP']=[]
-           for grma in GROUP_MA_INTE:
-              motscles['FLUX_REP'].append(_F(GROUP_MA=grma,CARA_TORSION=__tbaire),)
-        __chart2=AFFE_CHAR_THER(MODELE=__nomoth,**motscles)
-
-# --- RESOLUTION DE LAPLACIEN(PHI) = -2
-# --- AVEC PHI = 0 SUR LE CONTOUR :
-#     ----------------------------------------
-
-     motscles={}
-     motscles['EXCIT']=[_F(CHARGE=__chart1,),]
-     if GROUP_MA_INTE:
-        motscles['EXCIT'].append(_F(CHARGE=__chart2,))
-     __tempe1=THER_LINEAIRE(MODELE=__nomoth,
-                            CHAM_MATER=__chmath,
-                            SOLVEUR=_F(STOP_SINGULIER='NON',),
-                            **motscles   )
-
-#
-#     ----------------------------------------------
-# --- - CALCUL DU  CENTRE DE TORSION/CISAILLEMENT  -
-# --- - ET DES COEFFICIENTS DE CISAILLEMENT :      -
-#     ----------------------------------------------
-#
-# --- POUR LE CALCUL DES CONSTANTES DE CISAILLEMENT, ON VA DEFINIR
-# --- UN PREMIER TERME SOURCE, SECOND MEMBRE DE L EQUATION DE LAPLACE
-# --- PAR UNE FONCTION EGALE A Y :
-#     --------------------------
-
-     __fnsec1=DEFI_FONCTION(NOM_PARA='X',
-                            VALE=(0.,0.,10.,10.),
-                            PROL_DROITE='LINEAIRE',
-                            PROL_GAUCHE='LINEAIRE',
-                           )
-
-     __fnsec0=DEFI_CONSTANTE(VALE=0.,)
-
-# --- LE TERME SOURCE CONSTITUANT LE SECOND MEMBRE DE L EQUATION
-# --- DE LAPLACE EST PRIS EGAL A Y DANS TOUTE LA SECTION :
-#     --------------------------------------------------
-
-
-     motscles={}
-     if NOEUD:
-        motscles['TEMP_IMPO']=(_F(NOEUD=NOEUD,TEMP=__fnsec0))
-     __chart2=AFFE_CHAR_THER_F(MODELE=__nomoth,
-                               SOURCE=_F(TOUT='OUI',
-                                         SOUR=__fnsec1,),
-                               **motscles   )
-
-# --- RESOLUTION DE     LAPLACIEN(PHI) = -Y
-# ---              AVEC D(PHI)/D(N) = 0 SUR LE CONTOUR :
-#     ------------------------------------------------
-
-     __tempe2=THER_LINEAIRE(MODELE=__nomoth,
-                            CHAM_MATER=__chmath,
-                            EXCIT=_F(CHARGE=__chart2,), 
-                            SOLVEUR=_F(STOP_SINGULIER='NON',),
-                           )
-
-# --- POUR LE CALCUL DES CONSTANTES DE CISAILLEMENT, ON VA DEFINIR
-# --- UN PREMIER TERME SOURCE, SECOND MEMBRE DE L EQUATION DE LAPLACE
-# --- PAR UNE FONCTION EGALE A Z :
-#     --------------------------
-
-     __fnsec2=DEFI_FONCTION(NOM_PARA='Y',
-                            VALE=(0.,0.,10.,10.),
-                            PROL_DROITE='LINEAIRE',
-                            PROL_GAUCHE='LINEAIRE',
-                           )
-
-# --- LE TERME SOURCE CONSTITUANT LE SECOND MEMBRE DE L EQUATION
-# --- DE LAPLACE EST PRIS EGAL A Z DANS TOUTE LA SECTION :
-#     --------------------------------------------------
-
-     motscles={}
-     if NOEUD:
-        motscles['TEMP_IMPO']=_F(NOEUD=NOEUD,TEMP=__fnsec0)
-     __chart3=AFFE_CHAR_THER_F(MODELE=__nomoth,
-                               SOURCE=_F(TOUT='OUI',
-                                         SOUR=__fnsec2,),
-                               **motscles)
-
-# --- RESOLUTION DE     LAPLACIEN(PHI) = -Z
-# ---              AVEC D(PHI)/D(N) = 0 SUR LE CONTOUR :
-#     ------------------------------------------------
-
-     __tempe3=THER_LINEAIRE(MODELE=__nomoth,
-                            CHAM_MATER=__chmath,
-                            EXCIT=_F(CHARGE=__chart3,), 
-                            SOLVEUR=_F(STOP_SINGULIER='NON',),
-                           )
-
-# --- CALCUL DE LA CONSTANTE DE TORSION :
-#     ---------------------------------
-
-     motscles={}
-     if GROUP_MA_INTE:
-        motscles['CARA_POUTRE']=_F(CARA_GEOM=nomres,
-                                   LAPL_PHI=__tempe1,
-                                   TOUT='OUI',
-                                   OPTION='CARA_TORSION',
-                                   GROUP_MA_INTE=GROUP_MA_INTE,)
-     else:
-        motscles['CARA_POUTRE']=_F(CARA_GEOM=nomres,
-                                   LAPL_PHI=__tempe1,
-                                   TOUT='OUI',
-                                   OPTION='CARA_TORSION',      )
-     nomres=POST_ELEM(reuse=nomres,
-                      MODELE=__nomoth,
-                      CHAM_MATER=__chmath,
-                      **motscles  )
-
-# --- CALCUL DES COEFFICIENTS DE CISAILLEMENT ET DES COORDONNEES DU
-# --- CENTRE DE CISAILLEMENT/TORSION :
-#     ------------------------------
-
-     nomres=POST_ELEM(reuse=nomres,
-                      MODELE=__nomoth,
-                      CHAM_MATER=__chmath,
-                      CARA_POUTRE=_F(CARA_GEOM=nomres,
-                                     LAPL_PHI_Y=__tempe2,
-                                     LAPL_PHI_Z=__tempe3,
-                                     TOUT='OUI',
-                                     OPTION='CARA_CISAILLEMENT',),  )
-
-#
-#     ------------------------------------------------------------
-# --- - CALCUL DE L INERTIE DE GAUCHISSEMENT PAR RESOLUTION  DE  -
-# --- -    LAPLACIEN(OMEGA) = 0     DANS LA SECTION              -
-# --- -    AVEC D(OMEGA)/D(N) = Z*NY-Y*NZ   SUR LE               -
-# --- -    CONTOUR DE LA SECTION                                 -
-# --- -    NY ET NZ SONT LES COMPOSANTES DU VECTEUR N NORMAL     -
-# --- -    A CE CONTOUR                                          -
-# --- -    ET SOMME_S(OMEGA.DS) = 0                              -
-# --- -    OMEGA EST LA FONCTION DE GAUCHISSEMENT                -
-# --- -    L INERTIE DE GAUCHISSEMENT EST SOMME_S(OMEGA**2.DS)   -
-#     ------------------------------------------------------------
-#
-# --- CREATION D UN MAILLAGE DONT LES COORDONNEES SONT EXPRIMEES
-# --- DANS LE REPERE PRINCIPAL D INERTIE MAIS AVEC COMME ORIGINE
-# --- LE CENTRE DE TORSION DE LA SECTION, ON VA DONC UTILISER
-# --- LE MAILLAGE DE NOM NOMAPI DONT LES COORDONNEES SONT
-# --- EXPRIMEES DANS LE REPERE PRINCIPAL D'INERTIE, L'ORIGINE
-# --- ETANT LE CENTRE DE GRAVITE DE LA SECTION (QUI EST DONC
-# --- A CHANGER)  :
-#     ----------
-
-     __nomapt=CREA_MAILLAGE(MAILLAGE=__nomapi,
-                            REPERE=_F(TABLE=nomres,
-                                      NOM_ORIG='TORSION',)  )
-
-# --- AFFECTATION DU PHENOMENE 'THERMIQUE' AU MODELE EN VUE DE
-# --- LA CONSTRUCTION D UN OPERATEUR LAPLACIEN SUR CE MODELE :
-#     ------------------------------------------------------
-
-     __nomot2=AFFE_MODELE(MAILLAGE=__nomapt,
-                          AFFE=_F(TOUT='OUI',
-                                  PHENOMENE='THERMIQUE',
-                                  MODELISATION='PLAN', )  )
-
-# --- DEFINITION D UN CHAM_MATER A PARTIR DU MATERIAU PRECEDENT :
-#     ---------------------------------------------------------
-
-     __chmat2=AFFE_MATERIAU(MAILLAGE=__nomapt,
-                            AFFE=_F(TOUT='OUI',
-                                    MATER=__nomath, ), )
-
-# --- POUR LE CALCUL DE L INERTIE DE GAUCHISSEMENT, ON VA DEFINIR
-# --- LA COMPOSANTE SELON Y DU FLUX A IMPOSER SUR LE CONTOUR
-# --- PAR UNE FONCTION EGALE A -X :
-#     ---------------------------
-
-     __fnsec3=DEFI_FONCTION(NOM_PARA='X',
-                            VALE=(0.,0.,10.,-10.),
-                            PROL_DROITE='LINEAIRE',
-                            PROL_GAUCHE='LINEAIRE',
-                           )
-
-# --- POUR LE CALCUL DE L INERTIE DE GAUCHISSEMENT, ON VA DEFINIR
-# --- LA COMPOSANTE SELON X DU FLUX A IMPOSER SUR LE CONTOUR
-# --- PAR UNE FONCTION EGALE A Y :
-#     --------------------------
-
-     __fnsec4=DEFI_FONCTION(NOM_PARA='Y',
-                            VALE=(0.,0.,10.,10.),
-                            PROL_DROITE='LINEAIRE',
-                            PROL_GAUCHE='LINEAIRE',
-                           )
-
-# --- DANS LE BUT D IMPOSER LA RELATION LINEAIRE ENTRE DDLS
-# ---  SOMME_SECTION(OMEGA.DS) = 0 ( CETTE CONDITION
-# --- VENANT DE L EQUATION D EQUILIBRE SELON L AXE DE LA POUTRE
-# --- N = 0, N ETANT L EFFORT NORMAL)
-# --- ON CALCULE LE VECTEUR DE CHARGEMENT DU A UN TERME SOURCE EGAL
-# --- A 1., LES TERMES DE CE VECTEUR SONT EGAUX A
-# --- SOMME_SECTION(NI.DS) ET SONT DONC LES COEFFICIENTS DE
-# --- LA RELATION LINEAIRE A IMPOSER.
-# --- ON DEFINIT DONC UN CHARGEMENT DU A UN TERME SOURCE EGAL A 1 :
-#     -----------------------------------------------------------
-
-     __chart4=AFFE_CHAR_THER(MODELE=__nomot2,
-                             SOURCE=_F(TOUT='OUI',
-                                       SOUR=1.0),  )
-
-# --- ON CALCULE LE VECT_ELEM DU AU CHARGEMENT PRECEDENT
-# --- IL S AGIT DES VECTEURS ELEMENTAIRES DONT LE TERME
-# --- AU NOEUD COURANT I EST EGAL A SOMME_SECTION(NI.DS) :
-#     --------------------------------------------------
-
-     __vecel=CALC_VECT_ELEM(CHARGE=__chart4,
-                            OPTION='CHAR_THER'
-                            )
-
-# --- ON CALCULE LE MATR_ELEM DES MATRICES ELEMENTAIRES
-# --- DE CONDUCTIVITE UNIQUEMENT POUR GENERER LE NUME_DDL
-# --- SUR-LEQUEL S APPUIERA LE CHAMNO UTILISE POUR ECRIRE LA
-# --- RELATION LINEAIRE ENTRE DDLS :
-#     ----------------------------
-
-     __matel=CALC_MATR_ELEM(MODELE=__nomot2,
-                            CHAM_MATER=__chmat2,
-                            CHARGE=__chart4,
-                            OPTION='RIGI_THER',)
-
-# --- ON DEFINIT LE NUME_DDL ASSOCIE AU MATR_ELEM DEFINI
-# --- PRECEDEMMENT POUR CONSTRUIRE LE CHAMNO UTILISE POUR ECRIRE LA
-# --- RELATION LINEAIRE ENTRE DDLS :
-#     ----------------------------
-
-     __numddl=NUME_DDL(MATR_RIGI=__matel,
-                       METHODE='LDLT',    )
-
-# --- ON CONSTRUIT LE CHAMNO QUI VA ETRE UTILISE POUR ECRIRE LA
-# --- RELATION LINEAIRE ENTRE DDLS :
-#     ----------------------------
-
-     __chamno=ASSE_VECTEUR(VECT_ELEM=__vecel,
-                           NUME_DDL=__numddl,    )
-
-# --- ON IMPOSE LA RELATION LINEAIRE ENTRE DDLS
-# ---  SOMME_SECTION(OMEGA.DS) = 0 ( CETTE CONDITION
-# --- VENANT DE L EQUATION D EQUILIBRE SELON L AXE DE LA POUTRE
-# --- N = 0, N ETANT L EFFORT NORMAL)
-# --- POUR IMPOSER CETTE RELATION ON PASSE PAR LIAISON_CHAMNO,
-# --- LES TERMES DU CHAMNO (I.E. SOMME_SECTION(NI.DS))
-# --- SONT LES COEFFICIENTS DE LA RELATION LINEAIRE :
-#     ---------------------------------------------
-
-     __chart5=AFFE_CHAR_THER(MODELE=__nomot2,
-                             LIAISON_CHAMNO=_F(CHAM_NO=__chamno,
-                                               COEF_IMPO=0.),    )
-
-# --- LE CHARGEMENT EST UN FLUX REPARTI NORMAL AU CONTOUR
-# --- DONT LES COMPOSANTES SONT +Z (I.E. +Y) ET -Y (I.E. -X)
-# --- SELON LA DIRECTION NORMALE AU CONTOUR :
-#     -------------------------------------
-
-     __chart6=AFFE_CHAR_THER_F(MODELE=__nomot2,
-                               FLUX_REP=_F(GROUP_MA=GROUP_MA_BORD,
-                                           FLUX_X  =__fnsec4,
-                                           FLUX_Y  =__fnsec3,),    )
-
-# --- RESOLUTION DE     LAPLACIEN(OMEGA) = 0
-# --- AVEC D(OMEGA)/D(N) = Z*NY-Y*NZ   SUR LE CONTOUR DE LA SECTION
-# --- ET SOMME_SECTION(OMEGA.DS) = 0 ( CETTE CONDITION
-# --- VENANT DE L EQUATION D EQUILIBRE SELON L AXE DE LA POUTRE
-# --- N = 0, N ETANT L EFFORT NORMAL)  :
-#     -------------------------------
-
-     __tempe4=THER_LINEAIRE(MODELE=__nomot2,
-                            CHAM_MATER=__chmat2,
-                            EXCIT=(_F(CHARGE=__chart5,),
-                                   _F(CHARGE=__chart6,),),
-                            SOLVEUR=_F(METHODE='LDLT',
-                                       RENUM='SANS',
-                                       STOP_SINGULIER='NON',),   )
-    
-# --- CALCUL DE L INERTIE DE GAUCHISSEMENT :
-#     -------------------------------------
-
-     nomres=POST_ELEM(reuse=nomres,
-                      MODELE=__nomot2,
-                      CHAM_MATER=__chmat2,
-                      CARA_POUTRE=_F(CARA_GEOM=nomres,
-                                     LAPL_PHI=__tempe4,
-                                     TOUT='OUI',
-                                     OPTION='CARA_GAUCHI'),  )
-
-#
-#     ==================================================================
-# --- = CALCUL DE LA CONSTANTE DE TORSION SUR CHAQUE GROUPE            =
-# --- =     ET DU  CENTRE DE TORSION/CISAILLEMENT                      =
-# --- =        DES COEFFICIENTS DE CISAILLEMENT                        =
-#     ==================================================================
-#
-
-
-  if GROUP_MA_BORD and GROUP_MA:
-
-     if type(GROUP_MA_BORD)==types.StringType :
-        l_group_ma_bord=[GROUP_MA_BORD,]
-     else:
-        l_group_ma_bord= GROUP_MA_BORD
-     if type(GROUP_MA)==types.StringType :
-        l_group_ma=[GROUP_MA,]
-     else:
-        l_group_ma= GROUP_MA
-
-     if NOEUD:
-       if type(NOEUD)==types.StringType :
-          l_noeud=[NOEUD,]
-       else:
-          l_noeud= NOEUD
-
-     if len(l_group_ma)!=len(l_group_ma_bord):
-        ier=ier+1
-        self.cr.fatal("GROUP_MA et GROUP_MA_BORD incoherents")
-        return ier
-     if NOEUD and (len(l_group_ma)!=len(l_noeud)):
-        ier=ier+1
-        self.cr.fatal("GROUP_MA et NOEUD incoherents")
-        return ier
-
-     for i in range(0,len(l_group_ma_bord)):
-
-# --- TRANSFORMATION DES GROUP_MA EN GROUP_NO SUR-LESQUELS
-# --- ON POURRA APPLIQUER DES CONDITIONS DE TEMPERATURE IMPOSEE :
-#     ---------------------------------------------------------
-
-        __nomlma=DEFI_GROUP(reuse=__nomlma,
-                            MAILLAGE=__nomlma,
-                            CREA_GROUP_NO=_F(GROUP_MA=l_group_ma_bord[i],)  )
-
-
-# --- CREATION D UN MAILLAGE IDENTIQUE AU PREMIER A CECI PRES
-# --- QUE LES COORDONNEES SONT EXPRIMEES DANS LE REPERE PRINCIPAL
-# --- D INERTIE DONT L ORIGINE EST LE CENTRE DE GRAVITE DE LA SECTION :
-#     ---------------------------------------------------------------
-
-        __nomapi=CREA_MAILLAGE(MAILLAGE=__nomlma,
-                               REPERE=_F(TABLE=nomres,
-                                         NOM_ORIG='CDG',
-                                         GROUP_MA=l_group_ma[i],  ),  )
-
-# --- AFFECTATION DU PHENOMENE 'THERMIQUE' AU MODELE EN VUE DE
-# --- LA CONSTRUCTION D UN OPERATEUR LAPLACIEN SUR CE MODELE :
-#     ------------------------------------------------------
-
-        __nomoth=AFFE_MODELE(MAILLAGE=__nomapi,
-                             AFFE=_F(GROUP_MA=l_group_ma[i],
-                                     PHENOMENE='THERMIQUE',
-                                     MODELISATION='PLAN',  )  )
-
-# --- POUR LA CONSTRUCTION DU LAPLACIEN, ON  DEFINIT UN
-# --- PSEUDO-MATERIAU DONT LES CARACTERISTIQUES THERMIQUES SONT :
-# --- LAMBDA = 1, RHO*CP = 0 :
-#     ----------------------
-
-        __nomath=DEFI_MATERIAU(THER=_F(LAMBDA=1.0,
-                                       RHO_CP=0.0,  ),  )
-
-# --- DEFINITION D UN CHAM_MATER A PARTIR DU MATERIAU PRECEDENT :
-#     ---------------------------------------------------------
-
-        __chmath=AFFE_MATERIAU(MAILLAGE=__nomapi,
-                               AFFE=_F(TOUT='OUI',
-                                       MATER=__nomath ),  )
-
-#
-#     ------------------------------------------------------------
-# --- - CALCUL DE LA CONSTANTE DE TORSION PAR RESOLUTION         -
-# --- - D UN LAPLACIEN AVEC UN TERME SOURCE EGAL A -2            -
-# --- - L INCONNUE ETANT NULLE SUR LE CONTOUR DE LA SECTION :    -
-# --- -    LAPLACIEN(PHI) = -2 DANS LA SECTION                   -
-# --- -    PHI = 0 SUR LE CONTOUR :                              -
-#     ------------------------------------------------------------
-#
-# --- ON IMPOSE LA VALEUR 0 A L INCONNUE SCALAIRE SUR LE CONTOUR
-# --- DE LA SECTION
-# --- ET ON A UN TERME SOURCE EGAL A -2 DANS TOUTE LA SECTION :
-#     -------------------------------------------------------
-
-        __chart1=AFFE_CHAR_THER(MODELE=__nomoth,
-                                TEMP_IMPO=_F(GROUP_NO=l_group_ma_bord[i],
-                                             TEMP=0.0       ),
-                                SOURCE=_F(TOUT='OUI',
-                                          SOUR=2.0       )          )
-
-# --- RESOLUTION DE     LAPLACIEN(PHI) = -2
-# ---              AVEC PHI = 0 SUR LE CONTOUR :
-#     ----------------------------------------
-
-        __tempe1=THER_LINEAIRE(MODELE=__nomoth,
-                               CHAM_MATER=__chmath,
-                               EXCIT=_F(CHARGE=__chart1, ),
-                               SOLVEUR=_F(STOP_SINGULIER='NON',)    )
-
-#
-#     ----------------------------------------------
-# --- - CALCUL DU  CENTRE DE TORSION/CISAILLEMENT  -
-# --- - ET DES COEFFICIENTS DE CISAILLEMENT :      -
-#     ----------------------------------------------
-#
-# --- POUR LE CALCUL DES CONSTANTES DE CISAILLEMENT, ON VA DEFINIR
-# --- UN PREMIER TERME SOURCE, SECOND MEMBRE DE L EQUATION DE LAPLACE
-# --- PAR UNE FONCTION EGALE A Y :
-#     --------------------------
-
-        __fnsec1=DEFI_FONCTION(NOM_PARA='X',
-                               VALE=(0.,0.,10.,10.),
-                               PROL_DROITE='LINEAIRE',
-                               PROL_GAUCHE='LINEAIRE',        )
-
-        __fnsec0=DEFI_CONSTANTE(VALE=0.,)
-
-# --- LE TERME SOURCE CONSTITUANT LE SECOND MEMBRE DE L EQUATION
-# --- DE LAPLACE EST PRIS EGAL A Y DANS TOUTE LA SECTION :
-#     --------------------------------------------------
-
-        __chart2=AFFE_CHAR_THER_F(MODELE=__nomoth,
-                                  TEMP_IMPO=_F(NOEUD=l_noeud[i],
-                                               TEMP=__fnsec0),
-                                  SOURCE=_F(TOUT='OUI',
-                                            SOUR=__fnsec1)       )
-
-# --- RESOLUTION DE     LAPLACIEN(PHI) = -Y
-# ---              AVEC D(PHI)/D(N) = 0 SUR LE CONTOUR :
-#     ------------------------------------------------
-
-        __tempe2=THER_LINEAIRE(MODELE=__nomoth,
-                               CHAM_MATER=__chmath,
-                               EXCIT=_F(CHARGE=__chart2, ),
-                               SOLVEUR=_F(STOP_SINGULIER='NON',)         )
-
-# --- POUR LE CALCUL DES CONSTANTES DE CISAILLEMENT, ON VA DEFINIR
-# --- UN PREMIER TERME SOURCE, SECOND MEMBRE DE L EQUATION DE LAPLACE
-# --- PAR UNE FONCTION EGALE A Z :
-#     --------------------------
-
-        __fnsec2=DEFI_FONCTION(NOM_PARA='Y',
-                               VALE=(0.,0.,10.,10.),
-                               PROL_DROITE='LINEAIRE',
-                               PROL_GAUCHE='LINEAIRE',        )
-
-# --- LE TERME SOURCE CONSTITUANT LE SECOND MEMBRE DE L EQUATION
-# --- DE LAPLACE EST PRIS EGAL A Z DANS TOUTE LA SECTION :
-#     --------------------------------------------------
-
-        __chart3=AFFE_CHAR_THER_F(MODELE=__nomoth,
-                                  TEMP_IMPO=_F(NOEUD=l_noeud[i],
-                                               TEMP=__fnsec0),
-                                  SOURCE=_F(TOUT='OUI',
-                                            SOUR=__fnsec2)       )
-
-# --- RESOLUTION DE     LAPLACIEN(PHI) = -Z
-# ---              AVEC D(PHI)/D(N) = 0 SUR LE CONTOUR :
-#     ------------------------------------------------
-
-        __tempe3=THER_LINEAIRE(MODELE=__nomoth,
-                               CHAM_MATER=__chmath,
-                               EXCIT=_F(CHARGE=__chart3, ),
-                               SOLVEUR=_F(STOP_SINGULIER='NON',)         )
-
-# --- CALCUL DE LA CONSTANTE DE TORSION :
-#     ---------------------------------
-
-        nomres=POST_ELEM(reuse=nomres,
-                         MODELE=__nomoth,
-                         CHAM_MATER=__chmath,
-                         CARA_POUTRE=_F(CARA_GEOM=nomres,
-                                        LAPL_PHI=__tempe1,
-                                        GROUP_MA=l_group_ma[i],
-                                        OPTION='CARA_TORSION' ),     )
-
-# --- CALCUL DES COEFFICIENTS DE CISAILLEMENT ET DES COORDONNEES DU
-# --- CENTRE DE CISAILLEMENT/TORSION :
-#     ------------------------------
-
-        nomres=POST_ELEM(reuse=nomres,
-                         MODELE=__nomoth,
-                         CHAM_MATER=__chmath,
-                         CARA_POUTRE=_F(CARA_GEOM=nomres,
-                                        LAPL_PHI_Y=__tempe2,
-                                        LAPL_PHI_Z=__tempe3,
-                                        GROUP_MA=l_group_ma[i],
-                                        LONGUEUR=LONGUEUR,
-                                        MATERIAU=MATERIAU,
-                                        LIAISON =LIAISON,
-                                        OPTION='CARA_CISAILLEMENT' ),   )
-
-  return ier
-
index 5466b68530e9c089b06c8ac36ab4314465a2b7c4..4c7f99f1a176a859840cb11cdb8d7166ac68d892 100644 (file)
@@ -1,21 +1,21 @@
-#@ MODIF macro_matr_asse_ops Macro  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF macro_matr_asse_ops Macro  DATE 01/04/2005   AUTEUR VABHHTS J.PELLET 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
-# 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 EDF R&D CODE_ASTER,         
-#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
+# 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 EDF R&D CODE_ASTER,
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
 # ======================================================================
 
 
@@ -58,6 +58,15 @@ def macro_matr_asse_ops(self,MODELE,CHAM_MATER,CARA_ELEM,MATR_ASSE,
         ier=ier+1
         self.cr.fatal("<F> <MACRO_MATR_ASSE> Avec methode MULT_FRONT, RENUM doit etre MDA, MD ou RCMK.")
         return ier
+    elif methode=='MUMPS':
+      if SOLVEUR['RENUM']:
+         renum=SOLVEUR['RENUM']
+      else:
+         renum='SANS'
+      if renum not in ('SANS',):
+        ier=ier+1
+        self.cr.fatal("<F> <MACRO_MATR_ASSE> Avec methode MUMPS, RENUM doit etre SANS.")
+        return ier
     elif methode=='GCPC':
       if SOLVEUR['RENUM']:
          renum=SOLVEUR['RENUM']
@@ -81,7 +90,7 @@ def macro_matr_asse_ops(self,MODELE,CHAM_MATER,CARA_ELEM,MATR_ASSE,
   lrigel = 0
   lmasel = 0
 
-# decalage eventuel en premiere position dans la liste de l occurence de MATR_ASSE contenant 
+# decalage eventuel en premiere position dans la liste de l occurence de MATR_ASSE contenant
 # l option de rigidite
   try :
     for m in MATR_ASSE:
@@ -103,20 +112,6 @@ def macro_matr_asse_ops(self,MODELE,CHAM_MATER,CARA_ELEM,MATR_ASSE,
       self.cr.fatal("<F> <MACRO_MATR_ASSE> UNE DES OPTIONS DOIT ETRE RIGI_MECA OU RIGI_THER OU RIGI_ACOU OU RIGI_MECA_LAGR")
       return ier
 
-    if m['SIEF_ELGA']!=None and option!='RIGI_GEOM':
-      ier=ier+1
-      self.cr.fatal("<F> <MACRO_MATR_ASSE> SIEF_ELGA N EST ADMIS QU AVEC L OPTION RIGI_GEOM")
-      return ier
-
-    if m['MODE_FOURIER']!=None and option not in ('RIGI_MECA','RIGI_FLUI_STRU','RIGI_THER'):
-      ier=ier+1
-      self.cr.fatal("<F> <MACRO_MATR_ASSE> MODE_FOURIER N EST ADMIS QU AVEC UNE DES OPTIONS RIGI_MECA RIGI_FLUI_STRU RIGI_THER")
-      return ier
-
-    if (m['THETA']!=None or m['PROPAGATION']!=None) and option!='RIGI_MECA_LAGR':
-      ier=ier+1
-      self.cr.fatal("<F> <MACRO_MATR_ASSE> PROPAGATION ET,OU THETA NE SONT ADMIS QU AVEC L OPTION RIGI_MECA_LAGR")
-      return ier
 
     motscles={'OPTION':option}
     if option == 'AMOR_MECA':
@@ -134,11 +129,19 @@ def macro_matr_asse_ops(self,MODELE,CHAM_MATER,CARA_ELEM,MATR_ASSE,
     if CHAM_MATER != None: motscles['CHAM_MATER']  =CHAM_MATER
     if CARA_ELEM  != None: motscles['CARA_ELEM']   =CARA_ELEM
     if INST       != None: motscles['INST']        =INST
-    if m['SIEF_ELGA']   :  motscles['SIEF_ELGA']   =m['SIEF_ELGA']
-    if m['MODE_FOURIER']:  motscles['MODE_FOURIER']=m['MODE_FOURIER']
-    if m['THETA']       :  motscles['THETA']       =m['THETA']
-    if m['PROPAGATION'] :  motscles['PROPAGATION'] =m['PROPAGATION']
 
+    try : motscles['SIEF_ELGA']   =m['SIEF_ELGA']
+    except IndexError : pass
+
+    try : motscles['MODE_FOURIER']   =m['MODE_FOURIER']
+    except IndexError : pass
+
+    try : motscles['THETA']   =m['THETA']
+    except IndexError : pass
+
+    try : motscles['PROPAGATION']   =m['PROPAGATION']
+    except IndexError : pass
+    print motscles
     __a=CALC_MATR_ELEM(MODELE=MODELE,**motscles)
 
     if option == 'RIGI_MECA':
diff --git a/Aster/Cata/Macro/pre_gmsh_ops.py b/Aster/Cata/Macro/pre_gmsh_ops.py
deleted file mode 100644 (file)
index 8ff4170..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-#@ MODIF pre_gmsh_ops Macro  DATE 11/06/2002   AUTEUR DURAND C.DURAND 
-#            CONFIGURATION MANAGEMENT OF EDF VERSION
-# ======================================================================
-# COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
-# 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 EDF R&D CODE_ASTER,         
-#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
-# ======================================================================
-
-def pre_gmsh_ops(self,UNITE_MAILLAGE,UNITE_GMSH,MODI_QUAD,**args):
-  """
-     Ecriture de la macro PRE_GMSH
-  """
-  import os
-  from Macro.ajout_quad_gmsh import ajout_quad_gmsh
-  ier=0
-
-  PRE_GMSH_LECT =self.get_cmd('PRE_GMSH_LECT')
-
-  # La macro compte pour 1 dans la numerotation des commandes
-  self.icmd=1
-
-  if MODI_QUAD=='OUI':
-     cur_dir=os.getcwd()
-     unit  = str(UNITE_GMSH)
-     nomFichierGmsh = cur_dir+'/fort.'+unit
-     nomFichierMail = cur_dir+'/sortie'
-
-#    récupération du fichier .msh complet mis dans la string 'texte'
-
-     fproc=open(nomFichierGmsh,'r')
-     texte=fproc.read()
-     fproc.close()
-
-     resu=ajout_quad_gmsh(texte)
-     if not resu:
-        ier=ier+1
-        self.cr.fatal("Erreur dans la methode python de transformation mailles lineaires-quadratiques")
-        return ier
-
-     fsort=open(nomFichierMail,'w')
-     fsort.write(resu)
-     fsort.close()
-     os.system('cp '+nomFichierMail+' '+nomFichierGmsh)
-
-  PRE_GMSH_LECT(UNITE_MAILLAGE = UNITE_MAILLAGE,
-                UNITE_GMSH     = UNITE_GMSH     )
-
-  return ier
-
index 319d6d67952d36f46338e2188ab2ed7cfc77ae8b..65e02bd15a80f43d1f29bcd748cda08baec6a320 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF reca_algo Macro  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF reca_algo Macro  DATE 14/03/2005   AUTEUR DURAND C.DURAND 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -26,7 +26,6 @@ import copy,os
 import LinearAlgebra 
 from Cata.cata import INFO_EXEC_ASTER
 from Cata.cata import DETRUIRE
-from Macro.recal import EXTRACT
 from Accas import _F
 
 
index cb2d47789fdcd4fa24d0f908abad32f496186936..591614c84636251a5ca1ff82ab385fd1255b072d 100644 (file)
@@ -1,4 +1,4 @@
-#@ MODIF recal Macro  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOIS 
+#@ MODIF recal Macro  DATE 14/03/2005   AUTEUR DURAND C.DURAND 
 # -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
@@ -29,7 +29,6 @@ import Gnuplot
 import Cata
 from Cata.cata import INCLUDE,DETRUIRE
 from Accas import _F
-from Utilitai.extract import EXTRACT
 
 import os
 
@@ -151,13 +150,14 @@ def calcul_F(self,UL,para,val,reponses):
       
       Fichier_Resu.append(post_bloc)
       #--------------------------------------------------------------------------------
-      #on va ajouter la fonction EXTRACT 
+      #on va ajouter la fonction d'extraction du numarray de la table par la méthode Array 
       #et on stocke les réponses calculées dans la liste Lrep
       #qui va etre retournée par la fonction calcul_F
       self.g_context['Lrep'] = []
       Fichier_Resu.append('Lrep=[]'+'\n')
       for i in range(len(reponses)):
-         Fichier_Resu.append('F = EXTRACT('+str(reponses[i][0])+','+"'"+str(reponses[i][1])+"'"+','+"'"+str(reponses[i][2])+"'"+')'+'\n')
+         Fichier_Resu.append('t'+str(reponses[i][0])+'='+str(reponses[i][0])+'.EXTR_TABLE()'+'\n')
+         Fichier_Resu.append('F = '+'t'+str(reponses[i][0])+'.Array('+"'"+str(reponses[i][1])+"'"+','+"'"+str(reponses[i][2])+"'"+')'+'\n')
          Fichier_Resu.append('Lrep.append(F)'+'\n')
       
       #ouverture du fichier fort.3 et mise a jour de celui ci
diff --git a/Pmw/Alpha_99_9_example/__init__.py b/Pmw/Alpha_99_9_example/__init__.py
new file mode 100644 (file)
index 0000000..83d04e7
--- /dev/null
@@ -0,0 +1 @@
+# File to allow this directory to be treated as a python package.
diff --git a/Pmw/Alpha_99_9_example/lib/Pmw.def b/Pmw/Alpha_99_9_example/lib/Pmw.def
new file mode 100644 (file)
index 0000000..358a2b4
--- /dev/null
@@ -0,0 +1,9 @@
+# Widgets whose name is the same as its module.
+_widgets = ('AlphaExample',)
+
+# Widgets whose name is not the same as its module.
+_extraWidgets = {}
+
+_functions = {}
+
+_modules = ()
diff --git a/Pmw/Alpha_99_9_example/lib/PmwAlphaExample.py b/Pmw/Alpha_99_9_example/lib/PmwAlphaExample.py
new file mode 100644 (file)
index 0000000..5e4f88c
--- /dev/null
@@ -0,0 +1,24 @@
+import string
+import Pmw
+
+_default_text = "AlphaExample example alpha Pmw megawidget.\nPmw version: " + \
+    Pmw.version() + '\nPmw Alpha versions: ' + \
+    string.join(Pmw.version(alpha = 1), ' ')
+class AlphaExample(Pmw.MessageDialog):
+    # Dummy widget for illustrating use of Pmw alpha version directory
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('message_text', _default_text, None),
+       )
+       self.defineoptions(kw, optiondefs)
+       # Initialise the base class (after defining the options).
+       Pmw.MessageDialog.__init__(self, parent)
+       # Check keywords and initialise options.
+       self.initialiseoptions(AlphaExample)
diff --git a/Pmw/Alpha_99_9_example/lib/__init__.py b/Pmw/Alpha_99_9_example/lib/__init__.py
new file mode 100644 (file)
index 0000000..83d04e7
--- /dev/null
@@ -0,0 +1 @@
+# File to allow this directory to be treated as a python package.
diff --git a/Pmw/Pmw_1_2/__init__.py b/Pmw/Pmw_1_2/__init__.py
new file mode 100644 (file)
index 0000000..83d04e7
--- /dev/null
@@ -0,0 +1 @@
+# File to allow this directory to be treated as a python package.
diff --git a/Pmw/Pmw_1_2/bin/bundlepmw.py b/Pmw/Pmw_1_2/bin/bundlepmw.py
new file mode 100755 (executable)
index 0000000..fdb7dc0
--- /dev/null
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+
+# Helper script when freezing Pmw applications.  It concatenates all
+# Pmw megawidget files into a single file, 'Pmw.py', in the current
+# directory.  The script must be called with one argument, being the
+# path to the 'lib' directory of the required version of Pmw.
+# To freeze a Pmw application, you will also need to copy the
+# following files to the application directory before freezing:
+#
+#    PmwBlt.py PmwColor.py
+
+import os
+import regsub
+import string
+import sys
+
+# The order of these files is significant.  Files which reference
+# other files must appear later.  Files may be deleted if they are not
+# used.
+files = [
+    'Dialog', 'TimeFuncs', 'Balloon', 'ButtonBox', 'EntryField',
+    'Group', 'LabeledWidget', 'MainMenuBar', 'MenuBar', 'MessageBar',
+    'MessageDialog', 'NoteBook', 'OptionMenu', 'PanedWidget', 'PromptDialog',
+    'RadioSelect', 'ScrolledCanvas', 'ScrolledField', 'ScrolledFrame',
+    'ScrolledListBox', 'ScrolledText', 'HistoryText', 'SelectionDialog',
+    'TextDialog', 'TimeCounter', 'AboutDialog', 'ComboBox', 'ComboBoxDialog',
+    'Counter', 'CounterDialog',
+]
+
+# Set this to 0 if you do not use any of the Pmw.Color functions:
+needColor = 1
+
+# Set this to 0 if you do not use any of the Pmw.Blt functions:
+needBlt = 1
+
+def expandLinks(path):
+    if not os.path.isabs(path):
+       path = os.path.join(os.getcwd(), path)
+    while 1:
+       if not os.path.islink(path):
+           break
+       dir = os.path.dirname(path)
+       path = os.path.join(dir, os.readlink(path))
+
+    return path
+
+def mungeFile(file):
+    # Read the file and modify it so that it can be bundled with the
+    # other Pmw files.
+    file = 'Pmw' + file + '.py'
+    text = open(os.path.join(srcdir, file)).read()
+    text = regsub.gsub('import Pmw\>', '', text)
+    text = regsub.gsub('INITOPT = Pmw.INITOPT', '', text)
+    text = regsub.gsub('\<Pmw\.', '', text)
+    text = '\n' + ('#' * 70) + '\n' + '### File: ' + file + '\n' + text
+    return text
+
+# Work out which version is being bundled.
+file = sys.argv[0]
+file = os.path.normpath(file)
+file = expandLinks(file)
+
+dir = os.path.dirname(file)
+dir = expandLinks(dir)
+dir = os.path.dirname(dir)
+dir = expandLinks(dir)
+dir = os.path.basename(dir)
+
+version = string.replace(dir[4:], '_', '.')
+
+# Code to import the Color module.
+colorCode = """
+import PmwColor
+Color = PmwColor
+del PmwColor
+"""
+
+# Code to import the Blt module.
+bltCode = """
+import PmwBlt
+Blt = PmwBlt
+del PmwBlt
+"""
+
+# Code used when not linking with PmwBlt.py.
+ignoreBltCode = """
+_bltImported = 1
+_bltbusyOK = 0
+"""
+
+# Code to define the functions normally supplied by the dynamic loader.
+extraCode = """
+
+### Loader functions:
+
+_VERSION = '%s'
+
+def setversion(version):
+    if version != _VERSION:
+        raise ValueError, 'Dynamic versioning not available'
+
+def setalphaversions(*alpha_versions):
+    if alpha_versions != ():
+       raise ValueError, 'Dynamic versioning not available'
+
+def version(alpha = 0):
+    if alpha:
+        return ()
+    else:
+        return _VERSION
+
+def installedversions(alpha = 0):
+    if alpha:
+        return ()
+    else:
+        return (_VERSION,)
+
+"""
+
+if '-noblt' in sys.argv:
+    sys.argv.remove('-noblt')
+    needBlt = 0
+
+if '-nocolor' in sys.argv:
+    sys.argv.remove('-nocolor')
+    needColor = 0
+
+if len(sys.argv) != 2:
+    print 'usage: bundlepmw.py [-noblt] [-nocolor] /path/to/Pmw/Pmw_X_X_X/lib'
+    sys.exit()
+
+srcdir = sys.argv[1]
+
+if os.path.exists('Pmw.py'):
+    print 'Pmw.py already exists. Remove it and try again.'
+    sys.exit()
+    
+outfile = open('Pmw.py', 'w')
+
+if needColor:
+    outfile.write(colorCode)
+
+if needBlt:
+    outfile.write(bltCode)
+
+outfile.write(extraCode % version)
+
+# Specially handle PmwBase.py file:
+text = mungeFile('Base')
+text = regsub.gsub('import PmwLogicalFont', '', text)
+text = regsub.gsub('PmwLogicalFont._font_initialise', '_font_initialise', text)
+outfile.write(text)
+if not needBlt:
+    outfile.write(ignoreBltCode)
+
+files.append('LogicalFont')
+for file in files:
+    text = mungeFile(file)
+    outfile.write(text)
+
+print ''
+print '   Pmw.py has been created.'
+
+if needColor or needBlt:
+    print '   Before running freeze, also copy the following file(s):'
+    if needBlt:
+       print '   ' + os.path.join(srcdir, 'PmwBlt.py')
+    if needColor:
+       print '   ' + os.path.join(srcdir, 'PmwColor.py')
diff --git a/Pmw/Pmw_1_2/contrib/DirBrowser.py b/Pmw/Pmw_1_2/contrib/DirBrowser.py
new file mode 100644 (file)
index 0000000..8771215
--- /dev/null
@@ -0,0 +1,306 @@
+#
+#  FILE: DirBrowser.py
+#
+#  DESCRIPTION:
+#    This file provides a generic Directory browser selection widget.
+#
+#  AUTHOR:  MontaVista Software, Inc. <source@mvista.com>
+#
+#  Copyright 2001 MontaVista Software Inc.
+#
+#  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+#  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+#  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+#  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+#  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+#  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#  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 os
+import Tkinter
+import Pmw
+
+
+class DirBrowserDialog(Pmw.MegaToplevel):
+    def __init__(self, parent = None, **kw):
+        cwd = os.getcwd()
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+            ('path',               cwd,             None),
+            ('hidedotfiles',       1,               INITOPT),
+            ('label',              None,            INITOPT),
+           #('labelmargin',        0,               INITOPT),
+           #('labelpos',           None,            INITOPT),
+            ('borderx',    20,  INITOPT),
+            ('bordery',    20,  INITOPT),
+            )
+        
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+        Pmw.MegaToplevel.__init__(self, parent)
+
+        interior = self.interior()
+
+        self.childframe = self.createcomponent('childframe', (), None,
+                                               Tkinter.Frame,
+                                               (interior,),
+                                               borderwidth = 1,
+                                               relief = 'raised',
+                                              )
+        self.childframe.pack(expand = 1,
+                             fill = 'both',
+                             )
+
+        self.labelframe = self.createcomponent('labelframe', (), None,
+                                              Tkinter.Frame,
+                                              (self.childframe,),
+                                              borderwidth = 2,
+                                              relief = 'groove',
+                                              )
+        self.labelframe.pack(padx = 10, pady = 10, expand = 1, fill = 'both')
+        
+        if self['label']:
+            self.label = self.createcomponent('label', (), None,
+                                              Tkinter.Label,
+                                              (self.childframe,),
+                                              text = self['label'],
+                                              )
+            self.label.place(x = (10 + self['borderx']), y = 10, anchor = 'w')
+
+
+        self.workframe = self.createcomponent('workframe', (), None,
+                                              Tkinter.Frame,
+                                              (self.labelframe,),
+                                              #borderwidth = 2,
+                                              #relief = 'groove',
+                                              )
+        self.workframe.pack(padx = self['borderx'],
+                            pady = self['bordery'],
+                            expand = 1,
+                            fill = 'both',
+                            )
+
+        self.buttonframe = self.createcomponent('buttonframe', (), None,
+                                                Tkinter.Frame,
+                                                (interior,),
+                                                borderwidth = 1,
+                                                relief = 'raised',
+                                                )
+        self.buttonframe.pack(expand = 0,
+                              fill = 'x',
+                              )
+
+        self.optbox = self.createcomponent('optbox', (), None,
+                                           Pmw.OptionMenu,
+                                           (self.workframe,),
+                                           command = self.setpath,
+                                           )
+        self.optbox.bind('<Configure>', self._setMinimumSize)
+
+        self.listbox = self.createcomponent('listbox', (), None,
+                                            Pmw.ScrolledListBox,
+                                            (self.workframe,),
+                                            dblclickcommand = self._select,
+                                            )
+
+        path = self['path']
+        self.entry = self.createcomponent('entryfield', (), None,
+                                          Pmw.EntryField,
+                                          (self.workframe,),
+                                          value = path,
+                                          command = self.enteredpath,
+                                          labelpos = 'nw',
+                                          label_text = 'Current Path:',
+                                          )
+
+        #self.createlabel(self.workframe, childCols = 1, childRows = 3)
+
+        self.buttonbox = self.createcomponent('buttonbox', (), None,
+                                              Pmw.ButtonBox,
+                                              (self.buttonframe,),
+                                              )
+        self.buttonbox.add('OK', text = 'OK',
+                           command = self.okbutton)
+        self.buttonbox.add('Cancel', text = 'Cancel',
+                           command =  self.cancelbutton)
+        self.buttonbox.add('New Directory', text = 'New Directory',
+                           command =  self.newdirbutton)
+        
+        self.buttonbox.alignbuttons()
+        self.buttonbox.pack(expand = 1, fill = 'x')
+
+        self.optbox.grid(row = 2, column = 2, sticky = 'ew')
+        self.listbox.grid(row = 3, column = 2, sticky = 'news')
+        self.entry.grid(row = 5, column = 2, sticky = 'ew')
+        self.workframe.grid_rowconfigure(3, weight = 1)
+        self.workframe.grid_rowconfigure(4, minsize = 20)
+        self.workframe.grid_columnconfigure(2, weight = 1)
+
+
+        self.setpath(self['path'])
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def setpath(self, path):
+        path = os.path.abspath(os.path.expanduser(path))
+        
+        if os.path.isfile(path):
+            path = os.path.dirname(path)
+
+        dirlist = []
+        hidedotfiles = self['hidedotfiles']
+        try:
+            posix = (os.name == 'posix')
+            for entry in os.listdir(path):
+                entryPath = path + '/' + entry
+                if hidedotfiles and entry[0] == '.':
+                    # skip dot files if desired
+                    continue
+                if not os.path.isdir(entryPath):
+                    # skip files
+                    continue
+                if not os.access(entryPath, os.R_OK | os.X_OK):
+                    # skip directories we can't enter any way
+                    continue
+                dirlist.append(entry)
+
+        except:
+            self.entry.setentry(self['path'])
+            return
+
+        self.entry.setentry(path)
+        
+        self['path'] = path
+        
+        dirlist.sort()
+        if path != '/':
+            dirlist.insert(0, '..')
+
+        self.listbox.setlist(dirlist)
+        pathlist = []
+        while path != '/':
+            pathlist.append(path)
+            path = os.path.dirname(path)
+        pathlist.append('/')
+        self.optbox.setitems(pathlist, 0)
+
+    def _setMinimumSize(self, event):
+        # If the optionmenu changes width, make sure it does not
+        # shrink later.
+        owidth = self.optbox.winfo_width()
+        self.workframe.grid_columnconfigure(2, minsize = owidth)
+
+    def _select(self):
+        sel = self.listbox.getcurselection()
+        if self['path'] == '/':
+            self['path'] = ''
+        if len(sel) > 0:
+            if sel[0] == '..':
+                self.setpath(os.path.dirname(self['path']))
+            else:
+                self.setpath(self['path'] + '/' + sel[0])
+
+
+    def getcurpath(self):
+        return self['path']
+
+    def enteredpath(self):
+        self.setpath(self.entry.get())
+
+    def okbutton(self):
+        self.deactivate(self['path'])
+
+    def cancelbutton(self):
+        self.deactivate(None)
+
+    def newdirbutton(self):
+        CreateDirectoryPopup(self.interior(), self['path'])
+        self.setpath(self['path'])
+
+
+        
+class CreateDirectoryPopup:
+    def __init__(self, parent, path):
+        self.path = path
+        self.parent = parent
+        self.newdirpopup = Pmw.PromptDialog(parent,
+                                            buttons = ('OK', 'Cancel'),
+                                            defaultbutton = 'OK',
+                                            title = 'New Directory',
+                                            entryfield_labelpos = 'nw',
+                                            label_text = 'Enter new directory name for:\n%s'%self.path,
+                                            command = self._buttonpress
+                                            )
+
+        self.newdirpopup.activate()
+
+    def _buttonpress(self, button):
+        if button == 'OK':
+            newdirname = self.newdirpopup.get()
+            dirlist = os.listdir(self.path)
+            if newdirname in dirlist:
+                ErrorPopup(self.parent,
+                           'Error: "%s", already exists as a file or directory.'%newdirname)
+            else:
+                try:
+                    os.mkdir(self.path + '/' + newdirname)
+                except:
+                    ErrorPopup(self.parent,
+                               'Error: Could not create directory: "%s"'%newdirname)
+                else:
+                    self.newdirpopup.deactivate()
+        else:
+            self.newdirpopup.deactivate()
+            
+
+def ErrorPopup(parent, message):
+    error = Pmw.MessageDialog(parent, title = 'Error',
+                              message_text = message,
+                              defaultbutton = 0,
+                              )
+    error.activate()
+    
+if __name__ == '__main__':
+
+    rootWin = Tkinter.Tk()
+
+    Pmw.initialise()
+
+    rootWin.title('Directory Browser Dialog Demo')
+
+    def buildBrowser():
+        # Create the hierarchical directory browser widget
+        dirBrowserDialog = DirBrowserDialog(rootWin,
+                                            #labelpos = 'nw',
+                                            label = 'Select a directory',
+                                            title = 'Directory Selector',
+                                            #path = '~',
+                                            #hidedotfiles = 0,
+                                            )
+        dir = dirBrowserDialog.activate()
+        print 'Selected Directory:', dir
+
+    dirButton = Tkinter.Button(rootWin, text="Browser", command=buildBrowser)
+    dirButton.pack(side = 'left', padx = 10, pady = 10)
+
+    exitButton = Tkinter.Button(rootWin, text="Quit", command=rootWin.quit)
+    exitButton.pack(side = 'left', padx = 10, pady = 10)
+
+    rootWin.mainloop()
diff --git a/Pmw/Pmw_1_2/contrib/MCListbox.py b/Pmw/Pmw_1_2/contrib/MCListbox.py
new file mode 100644 (file)
index 0000000..166b8a0
--- /dev/null
@@ -0,0 +1,706 @@
+#
+#  FILE: MCListbox.py
+#
+#  DESCRIPTION:
+#    This file provides a generic Multi-Column Listbox widget.  It is derived
+#    from a heavily hacked version of Pmw.ScrolledFrame
+#
+#  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+#  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+#  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+#  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+#  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+#  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#  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 string
+import Tkinter
+import Pmw
+
+class MultiColumnListbox(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+        colors = Pmw.Color.getdefaultpalette(parent)
+
+        # Define the megawidget options.
+        INITOPT = Pmw.INITOPT
+        optiondefs = (
+            #('borderframe',      1,                          INITOPT),
+            ('horizflex',        'fixed',                    self._horizflex),
+            ('horizfraction',    0.05,                       INITOPT),
+            ('hscrollmode',      'dynamic',                  self._hscrollMode),
+            ('labelmargin',      0,                          INITOPT),
+            ('labelpos',         None,                       INITOPT),
+            ('scrollmargin',     2,                          INITOPT),
+            ('usehullsize',      0,                          INITOPT),
+            ('vertflex',         'fixed',                    self._vertflex),
+            ('vertfraction',     0.05,                       INITOPT),
+            ('vscrollmode',      'dynamic',                  self._vscrollMode),
+            ('labellist',        None,                       INITOPT),
+            ('selectbackground', colors['selectBackground'], INITOPT),
+            ('selectforeground', colors['selectForeground'], INITOPT),
+            ('background',       colors['background'],       INITOPT),
+            ('foreground',       colors['foreground'],       INITOPT),
+            ('command',          None,                       None),
+            ('dblclickcommand',  None,                       None),
+        )
+        self.defineoptions(kw, optiondefs)
+
+        # Initialise the base class (after defining the options).
+        Pmw.MegaWidget.__init__(self, parent)
+
+        self._numcolumns = len(self['labellist'])
+        self._columnlabels = self['labellist']
+        self._lineid = 0
+        self._numrows = 0
+        self._lineitemframes = []
+        self._lineitems = []
+        self._lineitemdata = {}
+        self._labelframe = {}
+        self._cursel = []
+        
+        # Create the components.
+        self.origInterior = Pmw.MegaWidget.interior(self)
+
+        if self['usehullsize']:
+            self.origInterior.grid_propagate(0)
+
+        # Create a frame widget to act as the border of the clipper. 
+        self._borderframe = self.createcomponent('borderframe',
+                                                 (), None,
+                                                 Tkinter.Frame,
+                                                 (self.origInterior,),
+                                                 relief = 'sunken',
+                                                 borderwidth = 2,
+                                                 )
+        self._borderframe.grid(row = 2, column = 2,
+                               rowspan = 2, sticky = 'news')
+
+        # Create the clipping windows.
+        self._hclipper = self.createcomponent('hclipper',
+                                              (), None,
+                                              Tkinter.Frame,
+                                              (self._borderframe,),
+                                              width = 400,
+                                              height = 300,
+                                              )
+        self._hclipper.pack(fill = 'both', expand = 1)
+
+        self._hsframe = self.createcomponent('hsframe', (), None,
+                                             Tkinter.Frame,
+                                             (self._hclipper,),
+                                             )
+                                             
+
+        self._vclipper = self.createcomponent('vclipper',
+                                              (), None,
+                                              Tkinter.Frame,
+                                              (self._hsframe,),
+                                              #width = 400,
+                                              #height = 300,
+                                              highlightthickness = 0,
+                                              borderwidth = 0,
+                                              )
+
+        self._vclipper.grid(row = 1, column = 0,
+                            columnspan = self._numcolumns,
+                            sticky = 'news')#, expand = 1)
+        self._hsframe.grid_rowconfigure(1, weight = 1)#, minsize = 300)
+        
+
+        gridcolumn = 0
+        for labeltext in self._columnlabels:
+            lframe = self.createcomponent(labeltext+'frame', (), None,
+                                          Tkinter.Frame,
+                                          (self._hsframe,),
+                                          borderwidth = 1,
+                                          relief = 'raised',
+                                          )
+            label = self.createcomponent(labeltext, (), None,
+                                         Tkinter.Label,
+                                         (lframe,),
+                                         text = labeltext,
+                                         )
+            label.pack(expand = 0, fill = 'y', side = 'left')
+            lframe.grid(row = 0, column = gridcolumn, sticky = 'ews')
+            self._labelframe[labeltext] = lframe
+            #lframe.update()
+            #print lframe.winfo_reqwidth()
+            self._hsframe.grid_columnconfigure(gridcolumn, weight = 1)
+            gridcolumn = gridcolumn + 1
+
+        lframe.update()
+        self._labelheight = lframe.winfo_reqheight()
+        self.origInterior.grid_rowconfigure(2, minsize = self._labelheight + 2)
+
+        self.origInterior.grid_rowconfigure(3, weight = 1, minsize = 0)
+        self.origInterior.grid_columnconfigure(2, weight = 1, minsize = 0)
+        
+        # Create the horizontal scrollbar
+        self._horizScrollbar = self.createcomponent('horizscrollbar',
+                                                    (), 'Scrollbar',
+                                                    Tkinter.Scrollbar,
+                                                    (self.origInterior,),
+                                                    orient='horizontal',
+                                                    command=self._xview
+                                                    )
+
+        # Create the vertical scrollbar
+        self._vertScrollbar = self.createcomponent('vertscrollbar',
+                                                   (), 'Scrollbar',
+                                                   Tkinter.Scrollbar,
+                                                   (self.origInterior,),
+                                                   #(self._hclipper,),
+                                                   orient='vertical',
+                                                   command=self._yview
+                                                   )
+
+        self.createlabel(self.origInterior, childCols = 3, childRows = 4)
+
+        # Initialise instance variables.
+        self._horizScrollbarOn = 0
+        self._vertScrollbarOn = 0
+        self.scrollTimer = None
+        self._scrollRecurse = 0
+        self._horizScrollbarNeeded = 0
+        self._vertScrollbarNeeded = 0
+        self.startX = 0
+        self.startY = 0
+        self._flexoptions = ('fixed', 'expand', 'shrink', 'elastic')
+
+        # Create a frame in the clipper to contain the widgets to be
+        # scrolled.
+        self._vsframe = self.createcomponent('vsframe',
+                                             (), None,
+                                             Tkinter.Frame,
+                                             (self._vclipper,),
+                                             #height = 300,
+                                             #borderwidth = 4,
+                                             #relief = 'groove',
+                                             )
+
+        # Whenever the clipping window or scrolled frame change size,
+        # update the scrollbars.
+        self._hsframe.bind('<Configure>', self._reposition)
+        self._vsframe.bind('<Configure>', self._reposition)
+        self._hclipper.bind('<Configure>', self._reposition)
+        self._vclipper.bind('<Configure>', self._reposition)
+
+        #elf._vsframe.bind('<Button-1>', self._vsframeselect)
+        
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def destroy(self):
+        if self.scrollTimer is not None:
+            self.after_cancel(self.scrollTimer)
+            self.scrollTimer = None
+        Pmw.MegaWidget.destroy(self)
+
+    # ======================================================================
+
+    # Public methods.
+
+    def interior(self):
+        return self._vsframe
+
+    # Set timer to call real reposition method, so that it is not
+    # called multiple times when many things are reconfigured at the
+    # same time.
+    def reposition(self):
+        if self.scrollTimer is None:
+            self.scrollTimer = self.after_idle(self._scrollBothNow)
+
+
+
+    def insertrow(self, index, rowdata):
+        #if len(rowdata) != self._numcolumns:
+        #    raise ValueError, 'Number of items in rowdata does not match number of columns.'
+        if index > self._numrows:
+            index = self._numrows
+
+        rowframes = {}
+        for columnlabel in self._columnlabels:
+            celldata = rowdata.get(columnlabel)
+            cellframe = self.createcomponent(('cellframeid.%d.%s'%(self._lineid,
+                                                                   columnlabel)),
+                                             (), ('Cellframerowid.%d'%self._lineid),
+                                             Tkinter.Frame,
+                                             (self._vsframe,),
+                                             background = self['background'],
+                                             #borderwidth = 1,
+                                             #relief = 'flat'
+                                             )
+
+            cellframe.bind('<Double-Button-1>', self._cellframedblclick)
+            cellframe.bind('<Button-1>', self._cellframeselect)
+                                             
+            if celldata:
+                cell = self.createcomponent(('cellid.%d.%s'%(self._lineid,
+                                                             columnlabel)),
+                                            (), ('Cellrowid.%d'%self._lineid),
+                                            Tkinter.Label,
+                                            (cellframe,),
+                                            background = self['background'],
+                                            foreground = self['foreground'],
+                                            text = celldata,
+                                            )
+
+                cell.bind('<Double-Button-1>', self._celldblclick)
+                cell.bind('<Button-1>', self._cellselect)
+
+                cell.pack(expand = 0, fill = 'y', side = 'left', padx = 1, pady = 1)
+            rowframes[columnlabel] = cellframe
+
+        self._lineitemdata[self._lineid] = rowdata
+        self._lineitems.insert(index, self._lineid)
+        self._lineitemframes.insert(index, rowframes)
+        self._numrows = self._numrows + 1
+        self._lineid = self._lineid + 1
+
+        self._placedata(index)
+
+    def _placedata(self, index = 0):
+        gridy = index
+        for rowframes in self._lineitemframes[index:]:
+            gridx = 0
+            for columnlabel in self._columnlabels:
+                rowframes[columnlabel].grid(row = gridy,
+                                           column = gridx,
+                                           sticky = 'news')
+                gridx = gridx + 1
+            gridy = gridy + 1
+                
+
+
+    def addrow(self, rowdata):
+        self.insertrow(self._numrows, rowdata)
+
+    def delrow(self, index):
+        rowframes = self._lineitemframes.pop(index)
+        for columnlabel in self._columnlabels:
+            rowframes[columnlabel].destroy()
+        self._placedata(index)
+        self._numrows = self._numrows - 1
+        del self._lineitems[index]
+        if index in self._cursel:
+            self._cursel.remove(index)
+        
+        
+    def curselection(self):
+        # Return a tuple of just one element as this will probably be the
+        # interface used in a future implementation when multiple rows can
+        # be selected at once.
+        return tuple(self._cursel)
+
+    def getcurselection(self):
+        # Return a tuple of just one row as this will probably be the
+        # interface used in a future implementation when multiple rows can
+        # be selected at once.
+        sellist = []
+        for sel in self._cursel:
+            sellist.append(self._lineitemdata[self._lineitems[sel]])
+        return tuple(sellist)
+
+    # ======================================================================
+
+    # Configuration methods.
+
+    def _hscrollMode(self):
+        # The horizontal scroll mode has been configured.
+
+        mode = self['hscrollmode']
+
+
+        if mode == 'static':
+            if not self._horizScrollbarOn:
+                self._toggleHorizScrollbar()
+        elif mode == 'dynamic':
+            if self._horizScrollbarNeeded != self._horizScrollbarOn:
+                self._toggleHorizScrollbar()
+        elif mode == 'none':
+            if self._horizScrollbarOn:
+                self._toggleHorizScrollbar()
+        else:
+            message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
+            raise ValueError, message
+
+    def _vscrollMode(self):
+        # The vertical scroll mode has been configured.
+
+        mode = self['vscrollmode']
+
+        if mode == 'static':
+            if not self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+        elif mode == 'dynamic':
+            if self._vertScrollbarNeeded != self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+        elif mode == 'none':
+            if self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+        else:
+            message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
+            raise ValueError, message
+
+    def _horizflex(self):
+        # The horizontal flex mode has been configured.
+
+        flex = self['horizflex']
+
+        if flex not in self._flexoptions:
+            message = 'bad horizflex option "%s": should be one of %s' % \
+                    mode, str(self._flexoptions)
+            raise ValueError, message
+
+        self.reposition()
+
+    def _vertflex(self):
+        # The vertical flex mode has been configured.
+
+        flex = self['vertflex']
+
+        if flex not in self._flexoptions:
+            message = 'bad vertflex option "%s": should be one of %s' % \
+                    mode, str(self._flexoptions)
+            raise ValueError, message
+
+        self.reposition()
+
+
+
+    # ======================================================================
+
+    # Private methods.
+
+    def _reposition(self, event):
+        gridx = 0
+        for col in self._columnlabels:
+            maxwidth = self._labelframe[col].winfo_reqwidth()
+            for row in self._lineitemframes:
+                cellwidth = row[col].winfo_reqwidth()
+                if cellwidth > maxwidth:
+                    maxwidth = cellwidth
+            self._hsframe.grid_columnconfigure(gridx, minsize = maxwidth)
+            gridwidth = self._hsframe.grid_bbox(column = gridx, row = 0)[2]
+            if self['horizflex'] in ('expand', 'elastic') and gridwidth > maxwidth:
+                maxwidth = gridwidth
+            self._vsframe.grid_columnconfigure(gridx, minsize = maxwidth)
+            gridx = gridx + 1
+            
+            
+
+        self._vclipper.configure(height = self._hclipper.winfo_height() - self._labelheight)
+        
+        self.reposition()
+
+    # Called when the user clicks in the horizontal scrollbar. 
+    # Calculates new position of frame then calls reposition() to
+    # update the frame and the scrollbar.
+    def _xview(self, mode, value, units = None):
+
+        if mode == 'moveto':
+            frameWidth = self._hsframe.winfo_reqwidth()
+            self.startX = string.atof(value) * float(frameWidth)
+        else:
+            clipperWidth = self._hclipper.winfo_width()
+            if units == 'units':
+                jump = int(clipperWidth * self['horizfraction'])
+            else:
+                jump = clipperWidth
+
+            if value == '1':
+                self.startX = self.startX + jump
+            else:
+                self.startX = self.startX - jump
+
+        self.reposition()
+
+    # Called when the user clicks in the vertical scrollbar. 
+    # Calculates new position of frame then calls reposition() to
+    # update the frame and the scrollbar.
+    def _yview(self, mode, value, units = None):
+
+        if mode == 'moveto':
+            frameHeight = self._vsframe.winfo_reqheight()
+            self.startY = string.atof(value) * float(frameHeight)
+        else:
+            clipperHeight = self._vclipper.winfo_height()
+            if units == 'units':
+                jump = int(clipperHeight * self['vertfraction'])
+            else:
+                jump = clipperHeight
+
+            if value == '1':
+                self.startY = self.startY + jump
+            else:
+                self.startY = self.startY - jump
+
+        self.reposition()
+
+    def _getxview(self):
+
+        # Horizontal dimension.
+        clipperWidth = self._hclipper.winfo_width()
+        frameWidth = self._hsframe.winfo_reqwidth()
+        if frameWidth <= clipperWidth:
+            # The scrolled frame is smaller than the clipping window.
+
+            self.startX = 0
+            endScrollX = 1.0
+
+            if self['horizflex'] in ('expand', 'elastic'):
+                relwidth = 1
+            else:
+                relwidth = ''
+        else:
+            # The scrolled frame is larger than the clipping window.
+
+            if self['horizflex'] in ('shrink', 'elastic'):
+                self.startX = 0
+                endScrollX = 1.0
+                relwidth = 1
+            else:
+                if self.startX + clipperWidth > frameWidth:
+                    self.startX = frameWidth - clipperWidth
+                    endScrollX = 1.0
+                else:
+                    if self.startX < 0:
+                        self.startX = 0
+                    endScrollX = (self.startX + clipperWidth) / float(frameWidth)
+                relwidth = ''
+
+        # Position frame relative to clipper.
+        self._hsframe.place(x = -self.startX, relwidth = relwidth)
+        return (self.startX / float(frameWidth), endScrollX)
+
+    def _getyview(self):
+
+        # Vertical dimension.
+        clipperHeight = self._vclipper.winfo_height()
+        frameHeight = self._vsframe.winfo_reqheight()
+        if frameHeight <= clipperHeight:
+            # The scrolled frame is smaller than the clipping window.
+
+            self.startY = 0
+            endScrollY = 1.0
+
+            if self['vertflex'] in ('expand', 'elastic'):
+                relheight = 1
+            else:
+                relheight = ''
+        else:
+            # The scrolled frame is larger than the clipping window.
+
+            if self['vertflex'] in ('shrink', 'elastic'):
+                self.startY = 0
+                endScrollY = 1.0
+                relheight = 1
+            else:
+                if self.startY + clipperHeight > frameHeight:
+                    self.startY = frameHeight - clipperHeight
+                    endScrollY = 1.0
+                else:
+                    if self.startY < 0:
+                        self.startY = 0
+                    endScrollY = (self.startY + clipperHeight) / float(frameHeight)
+                relheight = ''
+
+        # Position frame relative to clipper.
+        self._vsframe.place(y = -self.startY, relheight = relheight)
+        return (self.startY / float(frameHeight), endScrollY)
+
+    # According to the relative geometries of the frame and the
+    # clipper, reposition the frame within the clipper and reset the
+    # scrollbars.
+    def _scrollBothNow(self):
+        self.scrollTimer = None
+
+        # Call update_idletasks to make sure that the containing frame
+        # has been resized before we attempt to set the scrollbars. 
+        # Otherwise the scrollbars may be mapped/unmapped continuously.
+        self._scrollRecurse = self._scrollRecurse + 1
+        self.update_idletasks()
+        self._scrollRecurse = self._scrollRecurse - 1
+        if self._scrollRecurse != 0:
+            return
+
+        xview = self._getxview()
+        yview = self._getyview()
+        self._horizScrollbar.set(xview[0], xview[1])
+        self._vertScrollbar.set(yview[0], yview[1])
+
+        self._horizScrollbarNeeded = (xview != (0.0, 1.0))
+        self._vertScrollbarNeeded = (yview != (0.0, 1.0))
+
+        # If both horizontal and vertical scrollmodes are dynamic and
+        # currently only one scrollbar is mapped and both should be
+        # toggled, then unmap the mapped scrollbar.  This prevents a
+        # continuous mapping and unmapping of the scrollbars. 
+        if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
+                self._horizScrollbarNeeded != self._horizScrollbarOn and
+                self._vertScrollbarNeeded != self._vertScrollbarOn and
+                self._vertScrollbarOn != self._horizScrollbarOn):
+            if self._horizScrollbarOn:
+                self._toggleHorizScrollbar()
+            else:
+                self._toggleVertScrollbar()
+            return
+
+        if self['hscrollmode'] == 'dynamic':
+            if self._horizScrollbarNeeded != self._horizScrollbarOn:
+                self._toggleHorizScrollbar()
+
+        if self['vscrollmode'] == 'dynamic':
+            if self._vertScrollbarNeeded != self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+
+    def _toggleHorizScrollbar(self):
+
+        self._horizScrollbarOn = not self._horizScrollbarOn
+
+        interior = self.origInterior
+        if self._horizScrollbarOn:
+            self._horizScrollbar.grid(row = 5, column = 2, sticky = 'news')
+            interior.grid_rowconfigure(4, minsize = self['scrollmargin'])
+        else:
+            self._horizScrollbar.grid_forget()
+            interior.grid_rowconfigure(4, minsize = 0)
+
+    def _toggleVertScrollbar(self):
+
+        self._vertScrollbarOn = not self._vertScrollbarOn
+
+        interior = self.origInterior
+        if self._vertScrollbarOn:
+            self._vertScrollbar.grid(row = 3, column = 4, sticky = 'news')
+            interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
+        else:
+            self._vertScrollbar.grid_forget()
+            interior.grid_columnconfigure(3, minsize = 0)
+
+    # ======================================================================
+
+    # Selection methods.
+
+    #def _vsframeselect(self, event):
+    #    print 'vsframe event x: %d  y: %d'%(event.x, event.y)
+    #    col, row = self._vsframe.grid_location(event.x, event.y)
+    #    self._select(col, row)
+
+    def _cellframeselect(self, event):
+        #print 'cellframe event x: %d  y: %d'%(event.x, event.y)
+        x = event.widget.winfo_x()
+        y = event.widget.winfo_y()
+        #col, row = self._vsframe.grid_location(x + event.x, y + event.y)
+        self._select(x + event.x, y + event.y)#(col, row)
+
+    def _cellselect(self, event):
+        #print 'cell event x: %d  y: %d'%(event.x, event.y)
+        lx = event.widget.winfo_x()
+        ly = event.widget.winfo_y()
+        parent = event.widget.pack_info()['in']
+        fx = parent.winfo_x()
+        fy = parent.winfo_y()
+        #col, row = self._vsframe.grid_location(fx + lx + event.x, fy + ly + event.y)
+        self._select(fx + lx + event.x, fy + ly + event.y)#(col, row)
+
+    def _select(self, x, y):
+        col, row = self._vsframe.grid_location(x, y)
+        #print 'Clicked on col: %d  row: %d'%(col,row)
+        cfg = {}
+        lineid = self._lineitems[row]
+        cfg['Cellrowid.%d_foreground'%lineid] = self['selectforeground']
+        cfg['Cellrowid.%d_background'%lineid] = self['selectbackground']
+        cfg['Cellframerowid.%d_background'%lineid] = self['selectbackground']
+        #cfg['Cellframerowid%d_relief'%row] = 'raised'
+
+        if self._cursel != []:
+            cursel = self._cursel[0]
+            lineid = self._lineitems[cursel]
+            if cursel != None and cursel != row:
+                cfg['Cellrowid.%d_foreground'%lineid] = self['foreground']
+                cfg['Cellrowid.%d_background'%lineid] = self['background']
+                cfg['Cellframerowid.%d_background'%lineid] = self['background']
+                #cfg['Cellframerowid%d_relief'%cursel] = 'flat'
+            
+        apply(self.configure, (), cfg)
+        self._cursel = [row]
+
+        cmd = self['command']
+        if callable(cmd):
+            cmd()
+
+
+
+    def _cellframedblclick(self, event):
+        #print 'double click cell frame'
+        cmd = self['dblclickcommand']
+        if callable(cmd):
+            cmd()
+
+    def _celldblclick(self, event):
+        #print 'double click cell'
+        cmd = self['dblclickcommand']
+        if callable(cmd):
+            cmd()
+
+if __name__ == '__main__':
+
+    rootWin = Tkinter.Tk()
+
+    Pmw.initialise()
+
+    rootWin.title('MultiColumnListbox Demo')
+    rootWin.configure(width = 500, height = 300)
+    rootWin.update()
+
+    def dbl():
+        print listbox.getcurselection()
+
+    listbox = MultiColumnListbox(rootWin,
+                                           #usehullsize = 1,
+                                           labellist = ('Column 0',
+                                                        'Column 1',
+                                                        'Column 2',
+                                                        'Column 3',
+                                                        'Column 4',
+                                                        #'Column 5',
+                                                        #'Column 6',
+                                                        #'Column 7',
+                                                        #'Column 8',
+                                                        #'Column 9',
+                                                        ),
+                                           horizflex = 'expand',
+                                           #vertflex = 'elastic',
+                                           dblclickcommand = dbl,
+                                           )
+
+
+    #print 'start adding item'
+    for i in range(20):
+        r = {}
+        for j in range(5):
+            r[('Column %d'%j)] = 'Really long item name %d'%i
+        listbox.addrow(r)
+    #print 'items added'
+
+    listbox.pack(expand = 1, fill = 'both', padx = 10, pady = 10)
+
+
+    exitButton = Tkinter.Button(rootWin, text="Quit", command=rootWin.quit)
+    exitButton.pack(side = 'left', padx = 10, pady = 10)
+
+    rootWin.mainloop()
diff --git a/Pmw/Pmw_1_2/contrib/PmwFileDialog.py b/Pmw/Pmw_1_2/contrib/PmwFileDialog.py
new file mode 100644 (file)
index 0000000..dc7b461
--- /dev/null
@@ -0,0 +1,498 @@
+#
+__version__ = '$Id: PmwFileDialog.py,v 1.2 2002/08/23 15:03:35 gregm Exp $'
+#
+# Filename dialogs using Pmw
+#
+# (C) Rob W.W. Hooft, Nonius BV, 1998
+#
+# Modifications:
+#
+# J. Willem M. Nissink, Cambridge Crystallographic Data Centre, 8/2002
+#    Added optional information pane at top of dialog; if option
+#    'info' is specified, the text given will be shown (in blue).
+#    Modified example to show both file and directory-type dialog
+#
+# No Guarantees. Distribute Freely. 
+# Please send bug-fixes/patches/features to <r.hooft@euromail.com>
+#
+################################################################################
+import os,fnmatch,time
+import Tkinter,Pmw
+#Pmw.setversion("0.8.5")
+
+def _errorpop(master,text):
+    d=Pmw.MessageDialog(master,
+                        title="Error", 
+                        message_text=text,
+                        buttons=("OK",))
+    d.component('message').pack(ipadx=15,ipady=15)
+    d.activate()
+    d.destroy()
+    
+class PmwFileDialog(Pmw.Dialog):
+    """File Dialog using Pmw"""
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       optiondefs = (
+           ('filter',    '*',              self.newfilter),
+           ('directory', os.getcwd(),      self.newdir),
+           ('filename',  '',               self.newfilename),
+           ('historylen',10,               None),
+           ('command',   None,             None),
+            ('info',      None,             None),
+           )
+       self.defineoptions(kw, optiondefs)
+        # Initialise base class (after defining options).
+       Pmw.Dialog.__init__(self, parent)
+
+       self.withdraw()
+
+        # Create the components.
+       interior = self.interior()
+
+        if self['info'] is not None:
+            rowoffset=1
+            dn = self.infotxt()
+            dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
+        else:
+            rowoffset=0
+
+       dn = self.mkdn()
+       dn.grid(row=0+rowoffset,column=0,columnspan=2,padx=3,pady=3)
+       del dn
+
+       # Create the directory list component.
+       dnb = self.mkdnb()
+       dnb.grid(row=1+rowoffset,column=0,sticky='news',padx=3,pady=3)
+       del dnb
+
+       # Create the filename list component.
+       fnb = self.mkfnb()
+       fnb.grid(row=1+rowoffset,column=1,sticky='news',padx=3,pady=3)
+       del fnb
+
+       # Create the filter entry
+       ft = self.mkft()
+       ft.grid(row=2+rowoffset,column=0,columnspan=2,padx=3,pady=3)
+       del ft
+
+       # Create the filename entry
+       fn = self.mkfn()
+       fn.grid(row=3+rowoffset,column=0,columnspan=2,padx=3,pady=3)
+       fn.bind('<Return>',self.okbutton)
+       del fn
+
+       # Buttonbox already exists
+       bb=self.component('buttonbox')
+       bb.add('OK',command=self.okbutton)
+       bb.add('Cancel',command=self.cancelbutton)
+       del bb
+
+       Pmw.alignlabels([self.component('filename'),
+                        self.component('filter'),
+                        self.component('dirname')])
+
+    def infotxt(self):
+        """ Make information block component at the top """
+        return self.createcomponent(
+                'infobox',
+                (), None,
+                Tkinter.Label, (self.interior(),),
+                width=51,
+                relief='groove',
+                foreground='darkblue',
+                justify='left',
+                text=self['info']
+            )
+
+    def mkdn(self):
+        """Make directory name component"""
+        return self.createcomponent(
+           'dirname',
+           (), None,
+           Pmw.ComboBox, (self.interior(),),
+           entryfield_value=self['directory'],
+           entryfield_entry_width=40,
+            entryfield_validate=self.dirvalidate,
+           selectioncommand=self.setdir,
+           labelpos='w',
+           label_text='Directory:')
+
+    def mkdnb(self):
+        """Make directory name box"""
+        return self.createcomponent(
+           'dirnamebox',
+           (), None,
+           Pmw.ScrolledListBox, (self.interior(),),
+           label_text='directories',
+           labelpos='n',
+           hscrollmode='none',
+           dblclickcommand=self.selectdir)
+
+    def mkft(self):
+        """Make filter"""
+        return self.createcomponent(
+           'filter',
+           (), None,
+           Pmw.ComboBox, (self.interior(),),
+           entryfield_value=self['filter'],
+           entryfield_entry_width=40,
+           selectioncommand=self.setfilter,
+           labelpos='w',
+           label_text='Filter:')
+
+    def mkfnb(self):
+        """Make filename list box"""
+        return self.createcomponent(
+           'filenamebox',
+           (), None,
+           Pmw.ScrolledListBox, (self.interior(),),
+           label_text='files',
+           labelpos='n',
+           hscrollmode='none',
+           selectioncommand=self.singleselectfile,
+           dblclickcommand=self.selectfile)
+
+    def mkfn(self):
+        """Make file name entry"""
+        return self.createcomponent(
+           'filename',
+           (), None,
+           Pmw.ComboBox, (self.interior(),),
+           entryfield_value=self['filename'],
+           entryfield_entry_width=40,
+            entryfield_validate=self.filevalidate,
+           selectioncommand=self.setfilename,
+           labelpos='w',
+           label_text='Filename:')
+    
+    def dirvalidate(self,string):
+        if os.path.isdir(string):
+            return Pmw.OK
+        else:
+            return Pmw.PARTIAL
+        
+    def filevalidate(self,string):
+        if string=='':
+            return Pmw.PARTIAL
+        elif os.path.isfile(string):
+            return Pmw.OK
+        elif os.path.exists(string):
+            return Pmw.PARTIAL
+        else:
+            return Pmw.OK
+        
+    def okbutton(self):
+       """OK action: user thinks he has input valid data and wants to
+           proceed. This is also called by <Return> in the filename entry"""
+       fn=self.component('filename').get()
+       self.setfilename(fn)
+       if self.validate(fn):
+           self.canceled=0
+           self.deactivate()
+
+    def cancelbutton(self):
+       """Cancel the operation"""
+       self.canceled=1
+       self.deactivate()
+
+    def tidy(self,w,v):
+       """Insert text v into the entry and at the top of the list of 
+           the combobox w, remove duplicates"""
+       if not v:
+           return
+       entry=w.component('entry')
+       entry.delete(0,'end')
+       entry.insert(0,v)
+       list=w.component('scrolledlist')
+       list.insert(0,v)
+       index=1
+       while index<list.index('end'):
+           k=list.get(index)
+           if k==v or index>self['historylen']:
+               list.delete(index)
+           else:
+               index=index+1
+        w.checkentry()
+
+    def setfilename(self,value):
+       if not value:
+           return
+       value=os.path.join(self['directory'],value)
+       dir,fil=os.path.split(value)
+       self.configure(directory=dir,filename=value)
+        
+       c=self['command']
+       if callable(c):
+           c()
+
+    def newfilename(self):
+       """Make sure a newly set filename makes it into the combobox list"""
+       self.tidy(self.component('filename'),self['filename'])
+       
+    def setfilter(self,value):
+       self.configure(filter=value)
+
+    def newfilter(self):
+       """Make sure a newly set filter makes it into the combobox list"""
+       self.tidy(self.component('filter'),self['filter'])
+       self.fillit()
+
+    def setdir(self,value):
+       self.configure(directory=value)
+
+    def newdir(self):
+       """Make sure a newly set dirname makes it into the combobox list"""
+       self.tidy(self.component('dirname'),self['directory'])
+       self.fillit()
+
+    def singleselectfile(self):
+       """Single click in file listbox. Move file to "filename" combobox"""
+       cs=self.component('filenamebox').curselection()
+       if cs!=():
+           value=self.component('filenamebox').get(cs)
+            self.setfilename(value)
+
+    def selectfile(self):
+       """Take the selected file from the filename, normalize it, and OK"""
+        self.singleselectfile()
+       value=self.component('filename').get()
+        self.setfilename(value)
+        if value:
+           self.okbutton()
+
+    def selectdir(self):
+       """Take selected directory from the dirnamebox into the dirname"""
+       cs=self.component('dirnamebox').curselection()
+       if cs!=():
+           value=self.component('dirnamebox').get(cs)
+           dir=self['directory']
+           if not dir:
+               dir=os.getcwd()
+           if value:
+               if value=='..':
+                   dir=os.path.split(dir)[0]
+               else:
+                   dir=os.path.join(dir,value)
+           self.configure(directory=dir)
+           self.fillit()
+
+    def askfilename(self,directory=None,filter=None):
+       """The actual client function. Activates the dialog, and
+          returns only after a valid filename has been entered 
+           (return value is that filename) or when canceled (return 
+           value is None)"""
+       if directory!=None:
+           self.configure(directory=directory)
+       if filter!=None:
+           self.configure(filter=filter)
+       self.fillit()
+        self.canceled=1 # Needed for when user kills dialog window
+       self.activate()
+       if self.canceled:
+           return None
+       else:
+           return self.component('filename').get()
+
+    lastdir=""
+    lastfilter=None
+    lasttime=0
+    def fillit(self):
+       """Get the directory list and show it in the two listboxes"""
+        # Do not run unnecesarily
+        if self.lastdir==self['directory'] and self.lastfilter==self['filter'] and self.lasttime>os.stat(self.lastdir)[8]:
+            return
+        self.lastdir=self['directory']
+        self.lastfilter=self['filter']
+        self.lasttime=time.time()
+       dir=self['directory']
+       if not dir:
+           dir=os.getcwd()
+       dirs=['..']
+       files=[]
+        try:
+            fl=os.listdir(dir)
+            fl.sort()
+        except os.error,arg:
+            if arg[0] in (2,20):
+                return
+            raise
+       for f in fl:
+           if os.path.isdir(os.path.join(dir,f)):
+               dirs.append(f)
+           else:
+               filter=self['filter']
+               if not filter:
+                   filter='*'
+               if fnmatch.fnmatch(f,filter):
+                   files.append(f)
+       self.component('filenamebox').setlist(files)
+       self.component('dirnamebox').setlist(dirs)
+    
+    def validate(self,filename):
+       """Validation function. Should return 1 if the filename is valid, 
+           0 if invalid. May pop up dialogs to tell user why. Especially 
+           suited to subclasses: i.e. only return 1 if the file does/doesn't 
+           exist"""
+       return 1
+
+class PmwDirDialog(PmwFileDialog):
+    """Directory Dialog using Pmw"""
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       optiondefs = (
+           ('directory', os.getcwd(),      self.newdir),
+           ('historylen',10,               None),
+           ('command',   None,             None),
+           ('info',      None,             None),
+           )
+       self.defineoptions(kw, optiondefs)
+        # Initialise base class (after defining options).
+       Pmw.Dialog.__init__(self, parent)
+
+       self.withdraw()
+
+        # Create the components.
+       interior = self.interior()
+
+        if self['info'] is not None:
+            rowoffset=1
+            dn = self.infotxt()
+            dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
+        else:
+            rowoffset=0
+
+       dn = self.mkdn()
+       dn.grid(row=1+rowoffset,column=0,columnspan=2,padx=3,pady=3)
+       dn.bind('<Return>',self.okbutton)
+       del dn
+
+       # Create the directory list component.
+       dnb = self.mkdnb()
+       dnb.grid(row=0+rowoffset,column=0,columnspan=2,sticky='news',padx=3,pady=3)
+       del dnb
+
+       # Buttonbox already exists
+       bb=self.component('buttonbox')
+       bb.add('OK',command=self.okbutton)
+       bb.add('Cancel',command=self.cancelbutton)
+       del bb
+
+    lastdir=""
+    def fillit(self):
+       """Get the directory list and show it in the two listboxes"""
+        # Do not run unnecesarily
+        if self.lastdir==self['directory']:
+            return
+        self.lastdir=self['directory']
+       dir=self['directory']
+       if not dir:
+           dir=os.getcwd()
+       dirs=['..']
+        try:
+            fl=os.listdir(dir)
+            fl.sort()
+        except os.error,arg:
+            if arg[0] in (2,20):
+                return
+            raise
+       for f in fl:
+           if os.path.isdir(os.path.join(dir,f)):
+               dirs.append(f)
+       self.component('dirnamebox').setlist(dirs)
+
+    def okbutton(self):
+       """OK action: user thinks he has input valid data and wants to
+           proceed. This is also called by <Return> in the dirname entry"""
+       fn=self.component('dirname').get()
+       self.configure(directory=fn)
+       if self.validate(fn):
+           self.canceled=0
+           self.deactivate()
+    
+    def askfilename(self,directory=None):
+       """The actual client function. Activates the dialog, and
+          returns only after a valid filename has been entered 
+           (return value is that filename) or when canceled (return 
+           value is None)"""
+       if directory!=None:
+           self.configure(directory=directory)
+       self.fillit()
+       self.activate()
+       if self.canceled:
+           return None
+       else:
+           return self.component('dirname').get()
+
+    def dirvalidate(self,string):
+        if os.path.isdir(string):
+            return Pmw.OK
+        elif os.path.exists(string):
+            return Pmw.PARTIAL
+        else:
+            return Pmw.OK
+
+    def validate(self,filename):
+       """Validation function. Should return 1 if the filename is valid, 
+           0 if invalid. May pop up dialogs to tell user why. Especially 
+           suited to subclasses: i.e. only return 1 if the file does/doesn't 
+           exist"""
+        if filename=='':
+            _errorpop(self.interior(),"Empty filename")
+            return 0
+        if os.path.isdir(filename) or not os.path.exists(filename):
+            return 1
+        else:
+            _errorpop(self.interior(),"This is not a directory")
+            return 0
+
+class PmwExistingFileDialog(PmwFileDialog):
+    def filevalidate(self,string):
+        if os.path.isfile(string):
+            return Pmw.OK
+        else:
+            return Pmw.PARTIAL
+        
+    def validate(self,filename):
+        if os.path.isfile(filename):
+            return 1
+        elif os.path.exists(filename):
+            _errorpop(self.interior(),"This is not a plain file")
+            return 0
+        else:
+            _errorpop(self.interior(),"Please select an existing file")
+            return 0
+
+class PmwExistingDirDialog(PmwDirDialog):
+    def dirvalidate(self,string):
+        if os.path.isdir(string):
+            return Pmw.OK
+        else:
+            return Pmw.PARTIAL
+
+    def validate(self,filename):
+        if os.path.isdir(filename):
+            return 1
+        elif os.path.exists(filename):
+            _errorpop(self.interior(),"This is not a directory")
+            return 0
+        else:
+            _errorpop(self.interior(),"Please select an existing directory")
+    
+if __name__=="__main__":
+    root=Tkinter.Tk()
+    root.withdraw()
+    Pmw.initialise()
+
+    f0=PmwFileDialog(root)
+    f0.title('File name dialog')
+    n=f0.askfilename()
+    print '\nFilename : ',repr(n),'\n'
+
+    f1=PmwDirDialog(root,info='This is a directory dialog')
+    f1.title('Directory name dialog')
+    while 1:
+       n=f1.askfilename()
+       if n is None:
+           break
+       print "Dirname : ",repr(n)
diff --git a/Pmw/Pmw_1_2/contrib/PmwFullTimeCounter.py b/Pmw/Pmw_1_2/contrib/PmwFullTimeCounter.py
new file mode 100644 (file)
index 0000000..84e605a
--- /dev/null
@@ -0,0 +1,492 @@
+# Authors: Joe VanAndel, Greg McFarlane and Daniel Michelson
+
+import string
+import sys
+import time
+import Tkinter
+import Pmw
+
+class FullTimeCounter(Pmw.MegaWidget):
+    """Up-down counter
+
+    A TimeCounter is a single-line entry widget with Up and Down arrows
+    which increment and decrement the Time value in the entry.  
+    """
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('autorepeat',    1,    INITOPT),
+           ('buttonaspect',  1.0,  INITOPT),
+           ('initwait',      300,  INITOPT),
+           ('labelmargin',   0,    INITOPT),
+           ('labelpos',      None, INITOPT),
+           ('max',           '',   self._max),
+           ('min',           '',   self._min),
+           ('padx',          0,    INITOPT),
+           ('pady',          0,    INITOPT),
+           ('repeatrate',    50,   INITOPT),
+           ('value',         '',   INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       self.arrowDirection = {}
+       self._flag = 'stopped'
+       self._timerId = None
+
+       self._createComponents()
+
+       value = self['value']
+       if value is None or value == '':
+           now = time.time()
+           value = time.strftime('%Y:%m:%d:%H:%M',time.gmtime(now))
+       self._setTimeFromStr(value)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _createComponents(self):
+
+       # Create the components.
+       interior = self.interior()
+
+       # If there is no label, put the arrows and the entry directly
+       # into the interior, otherwise create a frame for them.  In
+       # either case the border around the arrows and the entry will
+       # be raised (but not around the label).
+       if self['labelpos'] is None:
+           frame = interior
+       else:
+           frame = self.createcomponent('frame',
+                   (), None,
+                   Tkinter.Frame, (interior,))
+           frame.grid(column=2, row=2, sticky='nsew')
+           interior.grid_columnconfigure(2, weight=1)
+           interior.grid_rowconfigure(2, weight=1)
+
+       frame.configure(relief = 'raised', borderwidth = 1)
+
+       # Create the down arrow buttons.
+
+       # Create the year down arrow.
+       self._downYearArrowBtn = self.createcomponent('downyeararrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downYearArrowBtn] = 0
+       self._downYearArrowBtn.grid(column = 0, row = 2)
+
+       # Create the month down arrow.
+       self._downMonthArrowBtn = self.createcomponent('downmontharrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downMonthArrowBtn] = 0
+       self._downMonthArrowBtn.grid(column = 1, row = 2)
+
+       # Create the day down arrow.
+       self._downDayArrowBtn = self.createcomponent('downdayarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downDayArrowBtn] = 0
+       self._downDayArrowBtn.grid(column = 2, row = 2)
+
+       # Create the hour down arrow.
+       self._downHourArrowBtn = self.createcomponent('downhourarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downHourArrowBtn] = 0
+       self._downHourArrowBtn.grid(column = 3, row = 2)
+
+       # Create the minute down arrow.
+       self._downMinuteArrowBtn = self.createcomponent('downminutearrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downMinuteArrowBtn] = 0
+       self._downMinuteArrowBtn.grid(column = 4, row = 2)
+
+       # Create the entry fields.
+
+       # Create the year entry field.
+       self._yearCounterEntry = self.createcomponent('yearentryfield',
+               (('yearentry', 'yearentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 4)
+       self._yearCounterEntry.grid(column = 0, row = 1, sticky = 'news')
+
+       # Create the month entry field.
+       self._monthCounterEntry = self.createcomponent('monthentryfield',
+               (('monthentry', 'monthentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._monthCounterEntry.grid(column = 1, row = 1, sticky = 'news')
+
+       # Create the day entry field.
+       self._dayCounterEntry = self.createcomponent('dayentryfield',
+               (('dayentry', 'dayentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._dayCounterEntry.grid(column = 2, row = 1, sticky = 'news')
+
+       # Create the hour entry field.
+       self._hourCounterEntry = self.createcomponent('hourentryfield',
+               (('hourentry', 'hourentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._hourCounterEntry.grid(column = 3, row = 1, sticky = 'news')
+
+       # Create the minute entry field.
+       self._minuteCounterEntry = self.createcomponent('minuteentryfield',
+               (('minuteentry', 'minuteentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._minuteCounterEntry.grid(column = 4, row = 1, sticky = 'news')
+
+       # Create the up arrow buttons.
+
+       # Create the year up arrow.
+       self._upYearArrowBtn = self.createcomponent('upyeararrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upYearArrowBtn] = 1
+       self._upYearArrowBtn.grid(column = 0, row = 0)
+
+       # Create the month up arrow.
+       self._upMonthArrowBtn = self.createcomponent('upmontharrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upMonthArrowBtn] = 1
+       self._upMonthArrowBtn.grid(column = 1, row = 0)
+
+       # Create the day up arrow.
+       self._upDayArrowBtn = self.createcomponent('updayarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upDayArrowBtn] = 1
+       self._upDayArrowBtn.grid(column = 2, row = 0)
+
+       # Create the hour up arrow.
+       self._upHourArrowBtn = self.createcomponent('uphourarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upHourArrowBtn] = 1
+       self._upHourArrowBtn.grid(column = 3, row = 0)
+
+       # Create the minute up arrow.
+       self._upMinuteArrowBtn = self.createcomponent('upminutearrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upMinuteArrowBtn] = 1
+       self._upMinuteArrowBtn.grid(column = 4, row = 0)
+
+       # Make it resize nicely.
+       padx = self['padx']
+       pady = self['pady']
+       for col in range(5): # YY, MM, DD, HH, mm
+           frame.grid_columnconfigure(col, weight = 1, pad = padx)
+       frame.grid_rowconfigure(0, pad = pady)
+       frame.grid_rowconfigure(2, pad = pady)
+
+       frame.grid_rowconfigure(1, weight = 1)
+
+       # Create the label.
+       self.createlabel(interior)
+
+       # Set bindings.
+
+       # Up year
+       self._upYearArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upYearArrowBtn: 
+               s._drawArrow(button, 1))
+       self._upYearArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upYearArrowBtn: 
+               s._countUp(button))
+       self._upYearArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upYearArrowBtn:
+               s._stopUpDown(button))
+
+       # Up month
+       self._upMonthArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upMonthArrowBtn: 
+               s._drawArrow(button, 1))
+       self._upMonthArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upMonthArrowBtn: 
+               s._countUp(button))
+       self._upMonthArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upMonthArrowBtn:
+               s._stopUpDown(button))
+
+       # Up day
+       self._upDayArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upDayArrowBtn: 
+               s._drawArrow(button, 1))
+       self._upDayArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upDayArrowBtn: 
+               s._countUp(button))
+       self._upDayArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upDayArrowBtn:
+               s._stopUpDown(button))
+
+       # Up hour
+       self._upHourArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upHourArrowBtn: 
+               s._drawArrow(button, 1))
+       self._upHourArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upHourArrowBtn: 
+               s._countUp(button))
+       self._upHourArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upHourArrowBtn:
+               s._stopUpDown(button))
+
+       # Up minute
+       self._upMinuteArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upMinuteArrowBtn: 
+               s._drawArrow(button, 1))
+       self._upMinuteArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upMinuteArrowBtn: 
+               s._countUp(button))
+       self._upMinuteArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upMinuteArrowBtn:
+               s._stopUpDown(button))
+
+
+       # Down year
+       self._downYearArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downYearArrowBtn: 
+               s._drawArrow(button, 0))
+       self._downYearArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downYearArrowBtn: 
+               s._countDown(button))
+       self._downYearArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downYearArrowBtn:
+               s._stopUpDown(button))
+
+       # Down month
+       self._downMonthArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downMonthArrowBtn: 
+               s._drawArrow(button, 0))
+       self._downMonthArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downMonthArrowBtn: 
+               s._countDown(button))
+       self._downMonthArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downMonthArrowBtn:
+               s._stopUpDown(button))
+
+       # Down day
+       self._downDayArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downDayArrowBtn: 
+               s._drawArrow(button, 0))
+       self._downDayArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downDayArrowBtn: 
+               s._countDown(button))
+       self._downDayArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downDayArrowBtn:
+               s._stopUpDown(button))
+
+       # Down hour
+       self._downHourArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downHourArrowBtn: 
+               s._drawArrow(button, 0))
+       self._downHourArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downHourArrowBtn: 
+               s._countDown(button))
+       self._downHourArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downHourArrowBtn:
+               s._stopUpDown(button))
+
+       # Down minute
+       self._downMinuteArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downMinuteArrowBtn: 
+               s._drawArrow(button, 0))
+       self._downMinuteArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downMinuteArrowBtn: s._countDown(button))
+       self._downMinuteArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downMinuteArrowBtn:
+               s._stopUpDown(button))
+
+
+       self._yearCounterEntry.bind('<Return>', self.invoke)
+       self._monthCounterEntry.bind('<Return>', self.invoke)
+       self._dayCounterEntry.bind('<Return>', self.invoke)
+       self._hourCounterEntry.bind('<Return>', self.invoke)
+       self._minuteCounterEntry.bind('<Return>', self.invoke)
+
+       self._yearCounterEntry.bind('<Configure>', self._resizeArrow)
+       self._monthCounterEntry.bind('<Configure>', self._resizeArrow)
+       self._dayCounterEntry.bind('<Configure>', self._resizeArrow)
+       self._hourCounterEntry.bind('<Configure>', self._resizeArrow)
+       self._minuteCounterEntry.bind('<Configure>', self._resizeArrow)
+
+    def _drawArrow(self, arrow, direction):
+       arrow.delete('arrow')
+
+       fg = self._yearCounterEntry.cget('entry_foreground')
+
+       bw = (string.atoi(arrow['borderwidth']) +
+               string.atoi(arrow['highlightthickness'])) / 2
+       h = string.atoi(arrow['height']) + 2 * bw
+       w =  string.atoi(arrow['width']) + 2 * bw
+
+       if direction == 0:
+            # down arrow
+            arrow.create_polygon(
+                0.25 * w + bw, 0.25 * h + bw,
+                0.50 * w + bw, 0.75 * h + bw,
+                0.75 * w + bw, 0.25 * h + bw,
+                fill=fg, tag='arrow')
+       else:
+            arrow.create_polygon(
+                0.25 * w + bw, 0.75 * h + bw,
+                0.50 * w + bw, 0.25 * h + bw,
+                0.75 * w + bw, 0.75 * h + bw,
+                fill=fg, tag='arrow')
+
+    def _resizeArrow(self, event = None):
+       for btn in (self._upYearArrowBtn, self._upMonthArrowBtn, 
+                   self._upDayArrowBtn, self._upHourArrowBtn, 
+                   self._upMinuteArrowBtn, self._downYearArrowBtn,
+                   self._downMonthArrowBtn, self._downDayArrowBtn,
+                   self._downHourArrowBtn, self._downMinuteArrowBtn):
+           bw = (string.atoi(btn['borderwidth']) + \
+                   string.atoi(btn['highlightthickness']))
+           newHeight = self._yearCounterEntry.winfo_reqheight() - 2 * bw
+           newWidth = newHeight * self['buttonaspect']
+           btn.configure(width=newWidth, height=newHeight)
+           self._drawArrow(btn, self.arrowDirection[btn])
+
+    def _min(self):
+       self._minVal = None
+
+    def _max(self):
+       self._maxVal = None
+
+    def _setTimeFromStr(self, str):
+        list = string.split(str, ':')
+       if len(list) != 5:
+           raise ValueError, 'invalid value: ' + str
+
+       self._year = string.atoi(list[0])
+       self._month = string.atoi(list[1])
+       self._day = string.atoi(list[2])
+       self._hour = string.atoi(list[3])
+       self._minute = string.atoi(list[4])
+
+       self._setHMS()
+
+    def getstring(self):
+       return '%04d:%02d:%02d:%02d:%02d' % (self._year, self._month, 
+                                            self._day, self._hour, 
+                                            self._minute)
+
+    def getint(self):
+       pass
+
+    def _countUp(self, button):
+       self._relief = self._upYearArrowBtn.cget('relief')
+       button.configure(relief='sunken')
+       if button == self._upYearArrowBtn: datetype = "year"
+       elif button == self._upMonthArrowBtn: datetype = "month"
+       elif button == self._upDayArrowBtn: datetype = "day"
+       elif button == self._upHourArrowBtn: datetype = "hour"
+       elif button == self._upMinuteArrowBtn: datetype = "minute"
+       self._count(1, datetype, 'start')
+
+    def _countDown(self, button):
+       self._relief = self._downYearArrowBtn.cget('relief')
+       button.configure(relief='sunken')
+       if button == self._downYearArrowBtn: datetype = "year"
+       elif button == self._downMonthArrowBtn: datetype = "month"
+       elif button == self._downDayArrowBtn: datetype = "day"
+       elif button == self._downHourArrowBtn: datetype = "hour"
+       elif button == self._downMinuteArrowBtn: datetype = "minute"
+       self._count(-1, datetype, 'start')
+
+    def _count(self, factor, datetype, newFlag=None):
+       if newFlag != 'force':
+         if newFlag is not None:
+           self._flag = newFlag
+
+         if self._flag == 'stopped':
+           return
+
+       if datetype == "year": self._year = self._year + factor
+       elif datetype == "month": self._month = self._month + factor
+       elif datetype == "day": self._day = self._day + factor
+       elif datetype == "hour": self._hour = self._hour + factor
+       elif datetype == "minute": self._minute = self._minute + factor
+       secs = time.mktime((self._year, self._month, self._day, self._hour, 
+                          self._minute, 0, 0, 0, -1))
+       tt = time.localtime(secs) # NOT gmtime!
+
+       self._year = tt[0]
+       self._month = tt[1]
+       self._day = tt[2]
+       self._hour = tt[3]
+       self._minute = tt[4]
+       self._setHMS()
+
+       if newFlag != 'force':
+         if self['autorepeat']:
+           if self._flag == 'start':
+             delay = self['initwait']
+             self._flag = 'running'
+           else:
+             delay = self['repeatrate']
+           self._timerId = self.after(
+               delay, lambda self=self, factor=factor, datetype=datetype: 
+                 self._count(factor, datetype, 'running'))
+
+    def _setHMS(self):
+        self._yearCounterEntry.setentry('%04d' % self._year)
+        self._monthCounterEntry.setentry('%02d' % self._month)
+        self._dayCounterEntry.setentry('%02d' % self._day)
+        self._hourCounterEntry.setentry('%02d' % self._hour)
+        self._minuteCounterEntry.setentry('%02d' % self._minute)
+
+    def _stopUpDown(self, button):
+        if self._timerId is not None:
+            self.after_cancel(self._timerId)
+           self._timerId = None
+        button.configure(relief=self._relief)
+        self._flag = 'stopped'
+
+    def invoke(self, event = None):
+        cmd = self['command']
+        if callable(cmd):
+           cmd()
+
+    def destroy(self):
+        if self._timerId is not None:
+            self.after_cancel(self._timerId)
+           self._timerId = None
+        Pmw.MegaWidget.destroy(self)
+
+if __name__=="__main__":
+
+    def showString():
+        stringVal = _time.getstring()
+        print stringVal
+
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title('FullTimeCounter')
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+
+    _time = FullTimeCounter(root,
+            labelpos = 'n',
+            label_text = 'YYYY:MM:DD:HH:mm')
+    _time.pack(fill = 'both', expand = 1, padx=10, pady=5)
+
+    button = Tkinter.Button(root, text = 'Show', command = showString)
+    button.pack()
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/contrib/PmwVerticalGauge.py b/Pmw/Pmw_1_2/contrib/PmwVerticalGauge.py
new file mode 100644 (file)
index 0000000..b413f93
--- /dev/null
@@ -0,0 +1,253 @@
+"""
+I needed a simple gauge, so I've made on with Pmw.
+It might be useful for others to use as a base to develop more comples
+gauges with.
+Is it worth cleaning up and submitting?
+cheers and thanks
+chris
+Dr. Chris Wright
+Intensive Care Unit
+Monash Medical Centre
+Clayton. VIC Australia
+"""
+
+import sys
+import Tkinter
+import Pmw
+import time
+
+
+if sys.platform == 'win32':
+    # MS-Windows specific fonts
+    label_font = "-family Ariel  -size 12"
+    value_font = "-family Ariel  -size 12"
+    small_font = "-family {MS Sans Serif} -size 9 -weight bold"
+    header_font = "-family {MS Sans Serif} -weight bold"
+else:
+    # X-Windows specific fonts
+    label_font = "-*-helvetica-*-r-*-*-*-160-*-*-*-*-*-*"
+    value_font = "-*-courier-*-r-*-*-*-160-*-*-*-*-*-*"
+    small_font = "-*-helvetica-*-r-*-*-*-130-*-*-*-*-*-*"
+    header_font = "-*-helvetica-bold-r-*-*-*-150-*-*-*-*-*-*"
+
+class VerticalGauge(Pmw.MegaWidget):
+    """Vertical gauge with actual and desired settings"""
+
+    def __init__(self, parent = None, **kw):
+       optiondefs = (
+           ('min', 0, None),
+           ('max', 100, None),
+           ('majortickinterval', 10, None),
+           ('minortickinterval', 5, None),
+           ('units', '', None),
+           ('bg', 'grey', self._backgroundSet),
+           ('actualvalue', 50, self._actualSet),
+           ('desiredvalue', 50, self._desiredSet),
+           ('actualcolour', 'yellow1', None),
+           ('desiredcolour', 'turquoise1', None),
+           ('label', 'Label', None),
+           )
+       self.defineoptions(kw, optiondefs)
+       Pmw.MegaWidget.__init__(self, parent)
+
+       interior = self.interior()
+       interior.grid_rowconfigure(1, weight = 1)
+       for r in range(3):
+           interior.grid_columnconfigure(r, weight = 1)
+
+       self.actuallabel = self.createcomponent('actualLabel',
+                                               (), None,
+                                               Tkinter.Label, (interior,),
+                                               text = '',
+                                               width = 3,
+                                               relief = 'sunken',
+                                               bd = 1,
+                                               fg = self['actualcolour'],
+                                               font = value_font)
+       self.actuallabel.grid(sticky = "nswe", row = 0, column = 0)
+
+       self.label = self.createcomponent('label',
+                                         (), None,
+                                         Tkinter.Label, (interior,),
+                                         text = self['label'],
+                                         relief = 'raised',
+                                         font = label_font,
+                                         fg = 'navy',
+                                         bd = 2)
+       self.label.grid(sticky = "nsew", row = 0, column = 1)
+
+       self.desiredlabel = self.createcomponent('desiredLabel',
+                                                (), None,
+                                                Tkinter.Label, (interior,),
+                                                text = '',
+                                                width = 3,
+                                                relief = 'sunken',
+                                                bd = 1,
+                                                fg = self['desiredcolour'],
+                                                font = value_font)
+       self.desiredlabel.grid(sticky = "nswe", row = 0, column = 2)
+
+       self.canvas = self.createcomponent('canvas',
+                                          (), None,
+                                          Tkinter.Canvas, (interior,),
+                                          width = 100,
+                                          height = 300,
+                                          bg = 'grey')
+                       
+       self.canvas.grid(sticky = "nsew", columnspan = 3, pady = 1)
+       self.canvas.bind("<Configure>", self._createGaugeAxes)
+       
+       self._createGaugeAxes()
+       
+       self.initialiseoptions()
+    
+    def _createGaugeAxes(self, event = None):
+       min = self['min']
+       max = self['max']
+       units = self['units']
+       majortickinterval = self['majortickinterval']
+
+       gauge_range = max - min
+
+       c = self.canvas
+       c.delete("all")
+       if event:
+           h, w = event.height, event.width
+       else:
+           h = int(c.configure("height")[4])
+           w = int(c.configure("width")[4])
+
+       self.lower = h - 15
+       self.upper = 15
+       self.middle = w / 2
+       c.create_line(self.middle, self.lower, self.middle, self.upper)
+       
+       majortickcount = int((max - min) / majortickinterval) 
+       self.axislength = self.lower - self.upper
+       self.majortickdistance = float(self.axislength) / majortickcount
+       self.majortickwidth = w / 5
+       labeloffset = (w / 4) + 10
+
+       for i in range(majortickcount + 1):
+           v = min + i * majortickinterval
+           d = self.lower - i * self.majortickdistance
+           c.create_line(self.middle, d, self.middle + self.majortickwidth, d)
+           c.create_text(self.middle + labeloffset, d, font = small_font, text = str(v))
+       
+       self._desiredSet(event)
+       self._actualSet(event)
+
+    def _backgroundSet(self):
+       self.canvas.configure(bg = self['bg'])
+               
+    def _desiredSet(self, event = None):
+       c = self.canvas
+       desired = self['desiredvalue']
+       desiredcolour = self['desiredcolour']
+
+       min = self['min']
+       max = self['max']
+       
+       if desired > max: desired = max
+       if desired < min: desired = min
+       gauge_range = max - min
+       
+       c = self.canvas
+       if event:
+           h, w = event.height, event.width
+       else:
+           h = int(c.configure("height")[4])
+           w = int(c.configure("width")[4])
+
+
+       desired_y = self.lower - (float(desired - min) / gauge_range) * self.axislength
+
+       try:
+           c.delete('desiredBar')
+       except:
+           pass
+
+       c.create_line(self.middle - self.majortickwidth, desired_y, 
+                     self.middle + self.majortickwidth, desired_y,
+                     fill = desiredcolour, stipple = 'gray50',
+                     width = 10, tag = 'desiredBar')
+       self.desiredlabel.configure(text = desired)
+
+    def setActual(self, value):
+       self.configure(actualvalue = value)
+
+    def getActual(self):
+       return self.cget('actualvalue')
+
+    def _actualSet(self, event = None):
+       c = self.canvas
+       actual = self['actualvalue']
+       actualcolour = self['actualcolour']
+
+       min = self['min']
+       max = self['max']
+       
+       if actual > max: actual = max
+       if actual < min: actual = min
+       gauge_range = max - min
+       
+       c = self.canvas
+       if event:
+           h, w = event.height, event.width
+       else:
+           h = int(c.configure("height")[4])
+           w = int(c.configure("width")[4])
+
+       actual_y = self.lower - (float(actual - min) / gauge_range) * self.axislength
+
+       try:
+           c.delete('actualPointer')
+       except:
+           pass
+       
+       triangle = ((self.middle, actual_y), 
+                   (self.middle - 1.4 * self.majortickwidth, actual_y - self.majortickwidth / 2),
+                   (self.middle - 1.4 * self.majortickwidth, actual_y + self.majortickwidth / 2))
+
+       c.create_polygon(triangle, fill = actualcolour, tag = 'actualPointer')
+       self.actuallabel.configure(text = actual)
+
+
+Pmw.forwardmethods(VerticalGauge, Tkinter.Canvas, 'canvas')
+
+if __name__ == '__main__':
+
+
+    # Initialise Tkinter and Pmw.
+    root = Pmw.initialise()
+    root.title('Pmw VerticalGauge demonstration')
+
+
+    def increase():
+       av = g1.getActual()
+       g1.setActual(av + 1)
+
+    def decrease():
+       av = g1.getActual()
+       g1.setActual(av - 1)
+
+    g1 = VerticalGauge(min = 0,
+                      max = 30, 
+                      actualvalue = 15,
+                      desiredvalue = 22,
+                      majortickinterval = 2,
+                      label = "Pms")
+    g1.grid(sticky = "nsew")
+    root.grid_rowconfigure(0, weight = 1)
+    root.grid_columnconfigure(0, weight = 1)
+    b1 = Tkinter.Button(text = "Increase", command = increase)
+    b1.grid()
+    b2 = Tkinter.Button(text = "Decrease", command = decrease)
+    b2.grid()
+
+    # Let's go.
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/contrib/README b/Pmw/Pmw_1_2/contrib/README
new file mode 100644 (file)
index 0000000..2662f77
--- /dev/null
@@ -0,0 +1,10 @@
+This directory contains contributed Pmw megawidgets.
+
+DirBrowser.py             directory selection dialog
+MCListbox.py              multi-column selectable listbox
+PmwFileDialog.py          file selection dialog
+PmwFullTimeCounter.py     time counter which includes year, month and day
+PmwVerticalGauge.py       a simple gauge indicating a value and a threshold
+TreeBrowser.py            generic hierarchical tree browser
+
+Each file can be executed and will display a demo of its megawidget.
diff --git a/Pmw/Pmw_1_2/contrib/TreeBrowser.py b/Pmw/Pmw_1_2/contrib/TreeBrowser.py
new file mode 100644 (file)
index 0000000..6d9fe89
--- /dev/null
@@ -0,0 +1,732 @@
+#
+#  FILE: TreeBrowser.py
+#
+#  DESCRIPTION:
+#    This file provides a generic hierarchical tree browser widget.
+#
+#  AUTHOR:  Steve Kinneberg <skinneberg@mvista.com>,
+#           MontaVista Software, Inc. <source@mvista.com>
+#
+#  Copyright 2001 MontaVista Software Inc.
+#
+#  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+#  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+#  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+#  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+#  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+#  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+#  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#  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 types
+import Tkinter
+import Pmw
+
+
+class _Branching:
+    def __init__(self):
+        # List of branch names
+        self._nodeNames = []
+
+        # Map from branch name to branch info
+        #   branch      Either _LeafNode or _BranchNode widget of the branch
+        #   nodetype    Either 'TreeNode' or 'LeafNode'
+        self._nodeAttrs = {}
+
+    def addbranch(self, branchName = None, **kw):
+        kw['indent'] = self['indent']
+        return apply(self._insertnode,
+                     ('tree', branchName, len(self._nodeNames),
+                      self._treeRoot),
+                     kw)
+
+    def addleaf(self, leafName = None, **kw):
+        return apply(self._insertnode,
+                     ('leaf', leafName, len(self._nodeNames),
+                      self._treeRoot),
+                     kw)
+
+    def insertbranch(self, branchName = None, before = 0, **kw):
+        kw['indent'] = self['indent']
+        return apply(self._insertnode,
+                     ('tree', branchName, before, self._treeRoot),
+                     kw)
+    
+    def insertleaf(self, leafName = None, before = 0, **kw):
+        return apply(self._insertnode,
+                     ('leaf', leafName, before, self._treeRoot),
+                     kw)
+
+    def _insertnode(self, type, nodeName, before, treeRoot, **kw):
+        if 'selectbackground' not in kw.keys():
+            kw['selectbackground'] = self['selectbackground']
+
+        if 'selectforeground' not in kw.keys():
+            kw['selectforeground'] = self['selectforeground']
+
+        if 'background' not in kw.keys():
+            kw['background'] = self['background']
+
+        if 'foreground' not in kw.keys():
+            kw['foreground'] = self['foreground']
+
+        if nodeName == None:
+            nodeName = self._nodeName + ".%d" % (len(self._nodeNames) + 1)
+        
+       if self._nodeAttrs.has_key(nodeName):
+           msg = 'Node "%s" already exists.' % nodeName
+           raise ValueError, msg
+
+        # Do this early to catch bad <before> spec before creating any items.
+       beforeIndex = self.index(before, 1)
+        attributes = {}
+
+        last = (beforeIndex == len(self._nodeNames))
+        if last and len(self._nodeNames) > 0:
+            # set the previous node to not last
+            self._nodeAttrs[self._nodeNames[-1]]['branch']._setlast(0)
+            
+        if(type == 'tree'):
+            node = apply(self.createcomponent, ('branch%d'%len(self._nodeNames),
+                                                (), None,
+                                                _BranchNode,
+                                                self._branchFrame,
+                                                nodeName,
+                                                treeRoot,
+                                                self,
+                                                last,
+                                                ), kw)
+            attributes['nodetype'] = 'TreeNode'
+        else:
+            node = apply(self.createcomponent, ('leaf%d'%len(self._nodeNames),
+                                                (), None,
+                                                _LeafNode,
+                                                self._branchFrame,
+                                                nodeName,
+                                                treeRoot,
+                                                self,
+                                                last,
+                                                ), kw)
+            attributes['nodetype'] = 'LeafNode'
+
+        if len(self._nodeNames) == beforeIndex:
+            node.pack(anchor='w')
+        else:
+            bname = self._nodeNames[beforeIndex]
+            battrs = self._nodeAttrs[bname]
+            node.pack(anchor='w', before=battrs['branch'])
+
+        attributes['branch'] = node
+
+        self._nodeAttrs[nodeName] = attributes
+        self._nodeNames.insert(beforeIndex, nodeName)
+        self._sizechange()
+        return node
+
+    def delete(self, *nodes):
+        curSel = self._treeRoot.curselection()[0]
+        for node in nodes:
+            index = self.index(node)
+            name = self._nodeNames.pop(index)
+            dnode = self._nodeAttrs[name]['branch']
+            del self._nodeAttrs[name]
+            if dnode == curSel:
+                self._treeRoot._unhightlightnode(dnode)
+            dnode.destroy()
+        self._sizechange()
+
+    def destroy(self):
+        for node in len(self._nodeNames):
+            self.delete(node)
+        Pmw.MegaWidget.destroy(self)
+
+    def index(self, index, forInsert = 0):
+        if isinstance(index, _LeafNode):
+            index = index._nodeName
+       listLength = len(self._nodeNames)
+       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 type(index) == types.StringType:
+            if index in self._nodeNames:
+                return self._nodeNames.index(index)
+            raise ValueError, 'bad branch or leaf name: %s' % index
+       elif index is Pmw.END:
+           if forInsert:
+               return listLength
+           elif listLength > 0:
+               return listLength - 1
+           else:
+               raise ValueError, 'TreeNode has no branches'
+       #elif index is Pmw.SELECT:
+       #    if listLength == 0:
+       #       raise ValueError, 'TreeNode has no branches'
+        #    return self._pageNames.index(self.getcurselection())
+       else:
+           validValues = 'a name, a number, Pmw.END, Pmw.SELECT, or a reference to a TreeBrowser Leaf or Branch'
+           raise ValueError, \
+                'bad index "%s": must be %s' % (index, validValues)
+
+    def getnodenames(self):
+        return self._nodeNames
+
+    def getnode(self, node):
+        nodeName = self._nodeNames[self.index(node)]
+        return self._nodeAttrs[nodeName]['branch']
+
+
+class _LeafNode(Pmw.MegaWidget):
+    
+    def __init__(self, parent, nodeName, treeRoot, parentnode, last = 1, **kw):
+        colors = Pmw.Color.getdefaultpalette(parent)
+        
+        self._nodeName = nodeName
+        self._treeRoot = treeRoot
+        self._parentNode = parentnode
+
+        self._last = last
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+            ('selectbackground', colors['selectBackground'], INITOPT),
+            ('selectforeground', colors['selectForeground'], INITOPT),
+            ('background',       colors['background'],       INITOPT),
+            ('foreground',       colors['foreground'],       INITOPT),
+            ('selectcommand',    None,                       None),
+            ('deselectcommand',  None,                       None),
+            ('labelpos',         'e',                        INITOPT),
+            ('labelmargin',      0,                          INITOPT),
+            ('label',            None,                       None),
+        )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+        # Create the components
+        interior = self._hull
+
+
+        labelpos = self['labelpos']
+
+        if self['label'] == None:
+            self._labelWidget = self.createcomponent('labelwidget',
+                                                     (), None,
+                                                     Pmw.LabeledWidget,
+                                                     (interior,),
+                                                     #background = self['background'],
+                                                     #foreground = self['foreground'],
+                                                     )
+        else:
+            self._labelWidget = self.createcomponent('labelwidget',
+                                                     (), None,
+                                                     Pmw.LabeledWidget,
+                                                     (interior,),
+                                                     label_background = self['background'],
+                                                     label_foreground = self['foreground'],
+                                                     labelpos = labelpos,
+                                                     labelmargin = self['labelmargin'],
+                                                     label_text = self['label'],
+                                                     )
+            self._labelWidget.component('label').bind('<ButtonRelease-1>',
+                                                      self._selectevent)
+
+        self._labelWidget.grid(column = 1, row = 0, sticky = 'w')
+
+        self._labelWidget.update()
+
+        self._labelheight = self._labelWidget.winfo_height()
+
+        self._lineCanvas = self.createcomponent('linecanvas',
+                                                (), None,
+                                                Tkinter.Canvas,
+                                                (interior,),
+                                                width = self._labelheight,
+                                                height = self._labelheight,
+                                                )
+        self._lineCanvas.grid( column = 0, row = 0, sticky = 'news')
+        self._lineCanvas.update()
+
+        cw = int(self._lineCanvas['width'])
+        ch = int(self._lineCanvas['height'])
+
+        self._lineCanvas.create_line(cw/2, ch/2, cw, ch/2, tag='hline')
+        if last:
+            self._lineCanvas.create_line(cw/2, 0, cw/2, ch/2, tag='vline')
+        else:
+            self._lineCanvas.create_line(cw/2, 0, cw/2, ch, tag='vline')
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+
+    def interior(self):
+        return self._labelWidget.interior()
+
+    def select(self):
+        self._highlight()
+
+    def getname(self):
+        return self._nodeName
+
+    def getlabel(self):
+        return self['label']
+    
+    def _selectevent(self, event):
+        self._highlight()
+
+    def _highlight(self):
+        self._treeRoot._highlightnode(self)
+        #self._subHull.configure(background = self._selectbg, relief = 'raised')
+        if self['label'] != None:
+            self._labelWidget.configure(label_background = self['selectbackground'])
+            self._labelWidget.configure(label_foreground = self['selectforeground'])
+        #self._viewButton.configure(background = self._selectbg)
+        cmd = self['selectcommand']
+        if callable(cmd):
+            cmd(self)
+
+    def _unhighlight(self):
+        #self._subHull.configure(background = self._bg, relief = 'flat')
+        if self['label'] != None:
+            self._labelWidget.configure(label_background = self['background'])
+            self._labelWidget.configure(label_foreground = self['foreground'])
+        #self._viewButton.configure(background = self._bg)
+        cmd = self['deselectcommand']
+        if callable(cmd):
+            cmd(self)
+
+    def _setlast(self, last):
+        self._last = last
+
+        cw = int(self._lineCanvas['width'])
+        ch = int(self._lineCanvas['height'])
+
+        if last:
+            self._lineCanvas.create_line(cw/2, 0, cw/2, ch/2, tag='vline')
+        else:
+            self._lineCanvas.create_line(cw/2, 0, cw/2, ch, tag='vline')
+        
+
+class _BranchNode(_LeafNode, _Branching): #Pmw.MegaWidget):
+
+    def __init__(self, parent, nodeName, treeRoot, parentnode, last = 1, **kw):
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+            ('view',            'collapsed', None),
+            ('expandcommand',   None,        None),
+            ('collapsecommand', None,        None),
+            ('indent',          0,           INITOPT)
+        )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+        apply(_LeafNode.__init__,
+              (self, parent, nodeName, treeRoot, parentnode, last),
+              kw)
+        _Branching.__init__(self)
+
+        # Create the components
+        interior = self._hull
+
+        # Create the expand/collapse button
+        self._viewButton = self.createcomponent('viewbutton', (), None,
+                                                Tkinter.Canvas,
+                                                (interior,),
+                                                background = self['background'],
+                                                width = self._labelheight - 4,
+                                                height = self._labelheight - 4,
+                                                borderwidth = 2,
+                                                relief = 'raised')
+
+        self._viewButton.grid(column = 0, row = 0, sticky='se')
+        self._viewButton.bind('<ButtonPress-1>', self._showbuttonpress)
+        self._viewButton.bind('<ButtonRelease-1>', self._toggleview)
+
+        # The label widget is already created by the base class, however
+        # we do need to make some slight modifications.
+        if self['label'] != None:
+            self._labelWidget.component('label').bind('<Double-1>',
+                                                      self._toggleview)
+        self._labelWidget.grid(column=1, row=0, columnspan = 3, sticky='sw')
+
+        # A line canvas is already created for us, we just need to make
+        # some slight modifications
+        self._lineCanvas.delete('hline')
+        self._lineCanvas.grid_forget()
+
+        
+        # Set the minsize of column 1 to control additional branch frame indentation
+        self.grid_columnconfigure(1, minsize = self['indent'])
+
+        # Create the branch frame that will contain all the branch/leaf nodes
+        self._branchFrame = self.createcomponent('frame', (), None,
+                                                 Tkinter.Frame, (interior,),
+                                                 #borderwidth=2,
+                                                 #relief='ridge',
+                                                 )
+        self.grid_columnconfigure(2,minsize=0, weight=1)
+        #self.grid_rowconfigure(0,minsize=0)
+
+        if(self['view'] == 'expanded'):
+            Pmw.drawarrow(self._viewButton,
+                          self['foreground'],
+                          'down', 'arrow')
+            self._branchFrame.grid(column = 2, row = 1, sticky='nw')
+            if not self._last:
+                self._branchFrame.update()
+                bh = self._branchFrame.winfo_height()
+                self._lineCanvas.configure(height = bh)
+                self._lineCanvas.grid(column = 0, row = 1, sticky='news')
+                cw = int(self._lineCanvas['width'])
+                ch = int(self._lineCanvas['height'])
+                #self._lineCanvas.create_line(cw/2, 1, cw/2, ch, tag = 'vline')
+                self._lineCanvas.coords('vline', cw/2, 1, cw/2, ch)
+        else:
+            Pmw.drawarrow(self._viewButton,
+                          self['foreground'],
+                          'right', 'arrow')
+            self._viewButton.configure(relief = 'raised')
+        
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+
+
+    def _showbuttonpress(self, event):
+        self._viewButton.configure(relief = 'sunken')
+        
+    def _toggleview(self, event):
+        self._viewButton.configure(relief = 'sunken')
+        self.select()
+        if(self['view'] == 'expanded'):
+            self.collapsetree()
+        else:
+            self.expandtree()
+        self._viewButton.configure(relief = 'raised')
+        
+    def expandtree(self):
+        if(self['view'] == 'collapsed'):
+            cmd = self['expandcommand']
+            if cmd is not None:
+                cmd(self)
+            self['view'] = 'expanded'
+            Pmw.drawarrow(self._viewButton,
+                          self['foreground'],
+                          'down', 'arrow')
+            self._branchFrame.grid(column = 2, row = 1, sticky='nw')
+            
+            if not self._last:
+                self._branchFrame.update()
+                bh = self._branchFrame.winfo_height()
+                self._lineCanvas.configure(height = bh)
+                self._lineCanvas.grid(column = 0, row = 1, sticky='news')
+                cw = int(self._lineCanvas['width'])
+                ch = int(self._lineCanvas['height'])
+                #self._lineCanvas.create_line( cw/2, 1, cw/2, ch, tag = 'vline')
+                self._lineCanvas.coords('vline', cw/2, 1, cw/2, ch)
+            self._parentNode._sizechange()
+        
+    def collapsetree(self):
+        if(self['view'] == 'expanded'):
+            cmd = self['collapsecommand']
+            if cmd is not None:
+                cmd(self)
+            self['view'] = 'collapsed'
+            Pmw.drawarrow(self._viewButton,
+                          self['foreground'],
+                          'right', 'arrow')
+            self._branchFrame.grid_forget()
+            if not self._last:
+                #self._lineCanvas.delete('vline')
+                self._lineCanvas.grid_forget()
+            self._parentNode._sizechange()
+
+    def _setlast(self, last):
+        self._last = last
+        if self['view'] == 'expanded':
+            self._branchFrame.update()
+            bh = self._branchFrame.winfo_height()
+            self._lineCanvas.configure(height = bh)
+            cw = int(self._lineCanvas['width'])
+            ch = int(self._lineCanvas['height'])
+            self._lineCanvas.delete('vline')
+            if not last:
+                self._lineCanvas.create_line(cw/2, 1, cw/2, ch, tag='vline')
+
+
+    def _sizechange(self):
+        if not self._last and self['view'] == 'expanded':
+            self._branchFrame.update()
+            bh = self._branchFrame.winfo_height()
+            self._lineCanvas.configure(height = bh)
+            if self._lineCanvas.coords('vline')[3] < bh:
+                cw = int(self._lineCanvas['width'])
+                ch = int(self._lineCanvas['height'])
+                #self._lineCanvas.delete('vline')
+                #self._lineCanvas.create_line(cw/2, 1, cw/2, ch, tag='vline')
+                self._lineCanvas.coords('vline', cw/2, 1, cw/2, ch)
+        self._parentNode._sizechange()
+
+class TreeBrowser(Pmw.MegaWidget, _Branching):
+
+    def __init__(self, parent = None, nodeName = '0', **kw):
+        colors = Pmw.Color.getdefaultpalette(parent)
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+            ('indent',           0,                          INITOPT),
+            ('selectbackground', colors['selectBackground'], INITOPT),
+            ('selectforeground', colors['selectForeground'], INITOPT),
+            ('background',       colors['background'],       INITOPT),
+            ('foreground',       colors['foreground'],       INITOPT),
+            #('selectrelief',     'raised',       INITOPT),
+        )
+        
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+        _Branching.__init__(self)
+
+        
+        # Create the components
+        interior = self._hull
+
+        browserFrame = self.createcomponent('frame', (), None,
+                                            Pmw.ScrolledFrame,
+                                            (interior,),
+                                            )
+        
+        browserFrame.pack(expand = 1, fill='both')
+
+        self._branchFrame = browserFrame.interior()
+
+        self._highlightedNode = None
+        self._treeRoot = self
+        self._nodeName = nodeName
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def _highlightnode(self, newNode):
+        if self._highlightedNode != newNode:
+            if self._highlightedNode != None:
+                self._highlightedNode._unhighlight()
+            self._highlightedNode = newNode
+
+    def _unhighlightnode(self):
+        if self._highlightedNode != None:
+            self._highlightedNode._unhighlight()
+            self._highlightedNode = None
+
+    def curselection(self):
+        retVal = None
+        if self._highlightedNode != None:
+            retVal = (self._highlightedNode,
+                      self._highlightedNode._nodeName,
+                      self._highlightedNode['label'])
+        return retVal
+
+    def getname(self):
+        return self._nodeName
+
+    # The top-level TreeBrowser widget only shows nodes in an expanded view
+    # but still provides collapsetree() and expandtree() methods so that users
+    # don't have to special case the top-level node
+
+    def collapsetree(self):
+        return
+
+    def expandtree(self):
+        return
+    
+    def _sizechange(self):
+        return
+
+if __name__ == '__main__':
+
+    rootWin = Tkinter.Tk()
+
+    Pmw.initialise()
+
+    rootWin.title('TreeBrowser Demo')
+
+    # Create the hierarchical tree browser widget
+    treeBrowser = TreeBrowser(rootWin,
+                                          #selectbackground = "darkgreen",
+                                          #selectforeground = 'lightgreen',
+                                          #background = 'green',
+                                          #indent = 10,
+                                          )
+
+
+    def printselected(node):
+        selection = treeBrowser.curselection()
+        if selection != None:
+            print "Selected node name:", selection[1], "   label:", selection[2]
+
+
+    def printdeselected(node):
+        selection = treeBrowser.curselection()
+        if selection != None:
+            print "Deselected node name:", selection[1], "   label:", selection[2]
+
+    def printexpanded(node):
+        print "Expanded node name:", node.getname(), "   label:", node.getlabel()
+
+    def printcollapsed(node):
+        print "Collapsed node name:", node.getname(), "   label:", node.getlabel()
+
+
+
+    for i in range(3):
+        # Add a tree node to the top level
+        treeNodeLevel1 = treeBrowser.addbranch(label = 'TreeNode %d'%i,
+                                               selectcommand = printselected,
+                                               deselectcommand = printdeselected,
+                                               expandcommand = printexpanded,
+                                               collapsecommand = printcollapsed,
+                                               )
+        for j in range(3):
+            # Add a tree node to the second level
+            treeNodeLevel2 = treeNodeLevel1.addbranch(label = 'TreeNode %d.%d'%(i,j),
+                                                      #selectforeground = 'yellow',
+                                                      selectcommand = printselected,
+                                                      deselectcommand = printdeselected,
+                                                      expandcommand = printexpanded,
+                                                      collapsecommand = printcollapsed,
+                                                      )
+            if i == 0 and j == 1:
+                dynamicTreeRootNode = treeNodeLevel1
+                dynamicTreePosNode = treeNodeLevel2
+                
+            for item in range((i+1)*(j+1)):
+                # Add a leaf node to the third level
+                leaf = treeNodeLevel2.addleaf(label = "Item %c"%(item+65),
+                                              #selectbackground = 'blue',
+                                              selectcommand = printselected,
+                                              deselectcommand = printdeselected)
+        for item in range(i+1):
+            # Add a leaf node to the top level
+            leaf = treeNodeLevel1.addleaf(label = "Item %c"%(item+65),
+                                          selectcommand = printselected,
+                                          deselectcommand = printdeselected)
+
+
+    treeNodeLevel1 = treeBrowser.addbranch(label = 'Check Button Label',
+                                           selectcommand = printselected,
+                                           deselectcommand = printdeselected,
+                                           expandcommand = printexpanded,
+                                           collapsecommand = printcollapsed,
+                                           )
+    checkButton = Tkinter.Checkbutton(treeNodeLevel1.interior(),
+                                      text = 'Da Check Button',
+                                      relief = 'ridge',
+                                      command = treeNodeLevel1.select)
+    checkButton.pack()
+
+    treeNodeLevel1.addleaf(label = 'Labeled Leaf',
+                           selectcommand = printselected,
+                           deselectcommand = printdeselected)
+    leaf = treeNodeLevel1.addleaf(label = 'Labeled Leaf w/ Checkbutton',
+                                  selectcommand = printselected,
+                                  deselectcommand = printdeselected)
+    checkButton = Tkinter.Checkbutton(leaf.interior(),
+                                      text = 'Da Check Button',
+                                      relief = 'ridge',
+                                      command = leaf.select)
+    checkButton.pack()
+
+
+    treeNodeLevel1 = treeBrowser.addbranch(selectcommand = printselected,
+                                           deselectcommand = printdeselected,
+                                           expandcommand = printexpanded,
+                                           collapsecommand = printcollapsed,
+                                           )
+    checkButton = Tkinter.Checkbutton(treeNodeLevel1.interior(),
+                                      text = 'Check Button with no label',
+                                      relief = 'ridge',
+                                      command = treeNodeLevel1.select)
+    checkButton.pack()
+
+    treeNodeLevel1 = treeBrowser.addbranch(label = 'Label',
+                                           selectcommand = printselected,
+                                           deselectcommand = printdeselected,
+                                           expandcommand = printexpanded,
+                                           collapsecommand = printcollapsed,
+                                           )
+
+    # setup dynamic tree node insertion and removal
+    class dynTree:
+        def __init__(self):
+            self.dyn = Tkinter.IntVar()
+            self.dtree = None
+
+            self.dLeaf = treeBrowser.addleaf(selectcommand = self.dynSelected,
+                                             deselectcommand = self.dynDeselected)
+            
+            self.dCheckButton = Tkinter.Checkbutton(self.dLeaf.interior(),
+                                                    text = 'Enable Dynamic Tree',
+                                                    variable = self.dyn,
+                                                    command = self.ChkBtnHandler)
+            self.dCheckButton.pack()
+
+            
+        def dynSelected(self, node):
+            self.dCheckButton.configure(background = self.dLeaf.configure('selectbackground')[4])
+            printselected(node)
+                
+        def dynDeselected(self, node):
+            self.dCheckButton.configure(background = self.dLeaf.configure('background')[4])
+            printdeselected(node)
+                    
+        def ChkBtnHandler(self):
+            self.dLeaf.select()
+            if self.dyn.get() == 1:
+                self.dtree = dynamicTreeRootNode.insertbranch(label = 'Dynamic Tree Node',
+                                                              selectcommand = printselected,
+                                                              deselectcommand = printdeselected,
+                                                              expandcommand = printexpanded,
+                                                              collapsecommand = printcollapsed,
+                                                              before = dynamicTreePosNode)
+                self.dtree.addleaf(label = 'Dynamic Leaf 1',
+                                   selectcommand = printselected,
+                                   deselectcommand = printdeselected)
+                self.dtree.addleaf(label = 'Dynamic Leaf 2',
+                                   selectcommand = printselected,
+                                   deselectcommand = printdeselected)
+            else:
+                if self.dtree != None:
+                    dynamicTreeRootNode.delete(self.dtree)
+                    self.dtree = None
+
+
+    foo = dynTree()
+
+
+    treeBrowser.pack(expand = 1, fill='both')
+
+    exitButton = Tkinter.Button(rootWin, text="Quit", command=rootWin.quit)
+    exitButton.pack()
+
+    rootWin.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/AboutDialog.py b/Pmw/Pmw_1_2/demos/AboutDialog.py
new file mode 100644 (file)
index 0000000..1760bef
--- /dev/null
@@ -0,0 +1,43 @@
+title = 'Pmw.AboutDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create dialog.
+       Pmw.aboutversion('9.9')
+       Pmw.aboutcopyright('Copyright My Company 1999\nAll rights reserved')
+       Pmw.aboutcontact(
+           'For information about this application contact:\n' +
+           '  My Help Desk\n' +
+           '  Phone: +61 2 9876 5432\n' +
+           '  email: help@my.company.com.au'
+       )
+       self.about = Pmw.AboutDialog(parent, applicationname = 'My Application')
+       self.about.withdraw()
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show about dialog',
+               command = self.execute)
+       w.pack(padx = 8, pady = 8)
+
+    def execute(self):
+       self.about.show()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/All.py b/Pmw/Pmw_1_2/demos/All.py
new file mode 100755 (executable)
index 0000000..f94955c
--- /dev/null
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+
+# ------------------------------------------------------------------
+# Display a splash screen as quickly as possible (before importing
+# modules and initialising Pmw).
+
+import Tkinter
+root = Tkinter.Tk(className = 'Demo')
+root.withdraw()
+
+splash = Tkinter.Toplevel()
+splash.withdraw()
+splash.title('Welcome to the Pmw demos')
+text = Tkinter.Label(splash,
+    font=('Helvetica', 16, 'bold'),
+    relief = 'raised',
+    borderwidth = 2,
+    padx=50, pady=50,
+    text =
+    'Welcome to the Pmw megawidgets demo.\n'
+    '\n'
+    'In a moment the main window will appear.\n'
+    'Please enjoy yourself while you wait.\n'
+    'You may be interested to know that splash screens\n'
+    '(as this window is called) were first devised to draw\n'
+    'attention away from the fact the certain applications\n'
+    'are slow to start. They are normally flashier and more\n'
+    'entertaining than this one. This is a budget model.'
+)
+text.pack(fill = 'both', expand = 1)
+splash.update_idletasks()
+
+width = splash.winfo_reqwidth()
+height = splash.winfo_reqheight()
+x = (root.winfo_screenwidth() - width) / 2 - root.winfo_vrootx()
+y = (root.winfo_screenheight() - height) / 3 - root.winfo_vrooty()
+if x < 0:
+    x = 0
+if y < 0:
+    y = 0
+geometry = '%dx%d+%d+%d' % (width, height, x, y)
+
+splash.geometry(geometry)
+splash.update_idletasks()
+splash.deiconify()
+root.update()
+
+# ------------------------------------------------------------------
+
+# Now crank up the application windows.
+
+import imp
+import os
+import re
+import string
+import sys
+import types
+import Tkinter
+import DemoVersion
+import Args
+
+# Find where the other scripts are, so they can be listed.
+if __name__ == '__main__':
+    script_name = sys.argv[0]
+else:
+    script_name = imp.find_module('DemoVersion')[1]
+
+script_name = os.path.normpath(script_name)
+script_name = DemoVersion.expandLinks(script_name)
+script_dir = os.path.dirname(script_name)
+script_dir = DemoVersion.expandLinks(script_dir)
+# Add the '../../..' directory to the path.
+package_dir = os.path.dirname(script_dir)
+package_dir = DemoVersion.expandLinks(package_dir)
+package_dir = os.path.dirname(package_dir)
+package_dir = DemoVersion.expandLinks(package_dir)
+package_dir = os.path.dirname(package_dir)
+package_dir = DemoVersion.expandLinks(package_dir)
+sys.path[:0] = [package_dir]
+
+# Import Pmw after modifying sys.path (it may not be in the default path).
+import Pmw
+DemoVersion.setPmwVersion()
+
+class Demo(Pmw.MegaWidget):
+
+    def __init__(self, parent=None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = ()
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+        Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the contents.
+       top = self.interior()
+
+       panes = Pmw.PanedWidget(top, orient = 'horizontal')
+       panes.pack(fill = 'both', expand = 1)
+
+       panes.add('widgetlist')
+       self._widgetlist = Pmw.ScrolledListBox(panes.pane('widgetlist'),
+               selectioncommand = Pmw.busycallback(self.startDemo),
+               label_text = 'Select a widget:',
+               labelpos = 'nw',
+               vscrollmode = 'dynamic',
+               hscrollmode = 'none',
+               listbox_exportselection = 0)
+       self._widgetlist.pack(fill = 'both', expand = 1, padx = 8)
+
+       panes.add('info')
+       self._status = Tkinter.Label(panes.pane('info'))
+       self._status.pack(padx = 8, anchor = 'w')
+
+       self._example = Tkinter.Frame(panes.pane('info'),
+               borderwidth = 2,
+               relief = 'sunken',
+               background = 'white')
+       self._example.pack(fill = 'both', expand = 1, padx = 8)
+
+       self.buttonBox = Pmw.ButtonBox(top)
+       self.buttonBox.pack(fill = 'x')
+
+       # Add the buttons and make them all the same width.
+       self._traceText = 'Trace tk calls'
+       self._stopTraceText = 'Stop trace'
+       self.buttonBox.add('Trace', text = self._traceText,
+               command = self.trace)
+       self.buttonBox.add('Code', text = 'Show code', command = self.showCode)
+       self.buttonBox.add('Exit', text = 'Exit', command = sys.exit)
+       self.buttonBox.alignbuttons()
+
+       # Create the window to display the python code.
+       self.codeWindow = Pmw.TextDialog(parent,
+           title = 'Python source',
+           buttons = ('Dismiss',),
+           scrolledtext_labelpos = 'n',
+           label_text = 'Source')
+       self.codeWindow.withdraw()
+       self.codeWindow.insert('end', '')
+
+       self.demoName = None
+       self._loadDemos()
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def startDemo(self):
+       # Import the selected module and create and instance of the module's
+       # Demo class.
+
+       sels = self._widgetlist.getcurselection()
+       if len(sels) == 0:
+           print 'No demonstrations to display'
+           return
+       demoName = sels[0]
+
+       # Ignore if this if it is a sub title.
+       if demoName[0] != ' ':
+           self._widgetlist.bell()
+           return
+
+       # Strip the leading two spaces.
+       demoName = demoName[2:]
+
+       # Ignore if this demo is already being shown.
+       if self.demoName == demoName:
+           return
+
+       self.demoName = demoName
+
+       self.showStatus('Loading ' + demoName)
+       # Busy cursor
+       self.update_idletasks()
+
+       for window in self._example.winfo_children():
+           window.destroy()
+
+       frame = Tkinter.Frame(self._example)
+       frame.pack(expand = 1)
+       exec 'import ' + demoName
+        # Need to keep a reference to the widget, so that variables, etc
+        # are not deleted.
+       self.widget = eval(demoName + '.Demo(frame)')
+       title = eval(demoName + '.title')
+       self.showStatus(title)
+
+       if self.codeWindow.state() == 'normal':
+           self.insertCode()
+
+    def showStatus(self, text):
+       self._status.configure(text = text)
+
+    def showCode(self):
+       if self.codeWindow.state() != 'normal':
+           if self.demoName is None:
+               print 'No demonstration selected'
+               return
+           self.insertCode()
+
+       self.codeWindow.show()
+
+    def insertCode(self):
+       self.codeWindow.clear()
+       fileName = os.path.join(script_dir, self.demoName + '.py')
+       self.codeWindow.importfile(fileName)
+       self.codeWindow.configure(label_text = self.demoName + ' source')
+
+    def trace(self):
+       text = self.buttonBox.component('Trace').cget('text')
+       if text == self._traceText:
+           self.buttonBox.configure(Trace_text = self._stopTraceText)
+           Pmw.tracetk(root, 1)
+           self.showStatus('Trace will appear on standard output')
+       else:
+           self.buttonBox.configure(Trace_text = self._traceText)
+           Pmw.tracetk(root, 0)
+           self.showStatus('Tk call tracing stopped')
+
+    def _loadDemos(self):
+       files = os.listdir(script_dir)
+       files.sort()
+       megawidgets = []
+       others = []
+       for file in files:
+           if re.search('.py$', file) is not None and \
+                   file not in ['All.py', 'DemoVersion.py', 'Args.py']:
+               demoName = file[:-3]
+               index = string.find(demoName, '_')
+               if index < 0:
+                   testattr = demoName
+               else:
+                   testattr = demoName[:index]
+               if hasattr(Pmw, testattr):
+                   megawidgets.append(demoName)
+               else:
+                   others.append(demoName)
+
+       self._widgetlist.insert('end', 'Megawidget demos:')
+       for name in megawidgets:
+           self._widgetlist.insert('end', '  ' + name)
+       self._widgetlist.insert('end', 'Other demos:')
+       for name in others:
+           self._widgetlist.insert('end', '  ' + name)
+       self._widgetlist.select_set(1)
+
+class StdOut:
+    def __init__(self, displayCommand):
+        self.displayCommand = displayCommand
+       self.text = '\n'
+
+    def write(self, text):
+       if self.text[-1] == '\n':
+           self.text = text
+       else:
+           self.text = self.text + text
+       if self.text[-1] == '\n':
+           text = self.text[:-1]
+       else:
+           text = self.text
+       self.displayCommand(text)
+
+if os.name == 'nt':
+    defaultFontSize = 16
+else:
+    defaultFontSize = 12
+
+commandLineArgSpecs = (
+    ('fontscheme', 0, 'scheme',  'fonts to use [eg pmw2] (Tk defaults)'),
+    ('fontsize',   0, 'num',     'size of fonts to use with fontscheme', defaultFontSize),
+    ('stdout',     0, Args.Bool, 'print messages rather than display in label'),
+)
+
+program = 'All.py'
+msg = Args.parseArgs(program, sys.argv, commandLineArgSpecs, 0)
+if msg is not None:
+    print msg 
+    sys.exit()
+
+size = Args.get('fontsize')
+fontScheme = Args.get('fontscheme')
+Pmw.initialise(root, size = size, fontScheme = fontScheme, useTkOptionDb = 1)
+
+root.title('Pmw ' + Pmw.version() + ' megawidget demonstration')
+if size < 18:
+    geometry = '800x550'
+else:
+    geometry = '1000x700'
+root.geometry(geometry)
+
+demo = Demo(root)
+demo.pack(fill = 'both', expand = 1)
+demo.focus()
+
+# Redirect standard output from demos to status line (unless -stdout
+# option given on command line).
+if not Args.get('stdout'):
+    sys.stdout = StdOut(demo.showStatus)
+
+# Start the first demo.
+demo.startDemo()
+
+# Get rid of the splash screen
+root.deiconify()
+root.update()
+splash.destroy()
+
+root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Args.py b/Pmw/Pmw_1_2/demos/Args.py
new file mode 100644 (file)
index 0000000..1bbedf9
--- /dev/null
@@ -0,0 +1,191 @@
+"""Handle command line arguments.
+
+This module contains functions to parse and access the arguments given
+to the program on the command line.
+"""
+
+import types
+import string
+import sys
+
+# Symbolic constants for the indexes into an argument specifier tuple.
+NAME        = 0
+MANDATORY   = 1
+TYPE        = 2
+HELP        = 3
+DEFAULT     = 4
+SPEC_LENGTH = 5
+
+Bool = []
+
+helpSpec = (
+  ('help',            0, Bool,   'print help and exit'),
+)
+
+def parseArgs(title, argv, argSpecs, filesOK):
+  """Parse and check command line arguments.
+
+  Scan the command line arguments in *argv* according to the argument
+  specifier *argSpecs*. Return **None** if there are no errors in
+  the arguments, otherwise return an error string describing the error.
+
+  This function must be called to initialise this module.
+
+  title    -- The name of the program. This is used when returning
+              error messages or help text.
+
+  argv     -- A sequence containing the arguments given to the program.
+              Normally **sys.argv**.
+
+  argSpecs -- A sequence of argument specifiers.  Each specifier describes
+              a valid command line argument and consists of 4 or 5 items:
+
+             - The argument name (without a leading minus sign **-**).
+
+             - A boolean value, true if the argument is mandatory.
+
+             - This should be **Args.Bool** if the argument has no option.
+               Otherwise it should be a string describing the option
+               required for this argument. This is used when printing help.
+
+             - A short string describing the argument.
+
+             - The default value of the argument.  This should only be used
+               for non-mandatory arguments expecting an option.
+             
+             For example:
+               (
+                 ('foreground', 0, 'colour',    'colour of text', 'black'),
+                 ('geometry',   0, 'spec',      'geometry of initial window'),
+                 ('server',     1, 'ompserver', 'ompserver to connect to'),
+                 ('silent',     0, Args.Bool,   'do not sound bell'),
+               )
+  """
+
+  global programName
+  global _fileList
+
+  errMsg = title + ' command line error: '
+  programName = argv[0];
+
+  argSpecs = helpSpec + argSpecs
+  argSpecDic = {}
+  for spec in argSpecs:
+    arg = spec[NAME]
+    argSpecDic[arg] = spec
+    if len(spec) >= SPEC_LENGTH:
+      set(arg, spec[DEFAULT])
+    elif spec[TYPE] is Bool:
+      set(arg, 0)
+    else:
+      set(arg, None)
+
+  knownKeys = argSpecDic.keys()
+
+  i = 1
+  _fileList = []
+  argc = len(argv)
+  while i < argc:
+    arg = argv[i]
+    key = arg[1:]
+    if key in knownKeys:
+      spec = argSpecDic[key]
+      if spec[TYPE] is Bool:
+       set(key, 1)
+      else:
+       i = i + 1
+       if i >= argc:
+         return errMsg + 'missing argument to \'' + arg + '\' option.'
+       value = argv[i]
+       if len(spec) >= SPEC_LENGTH:
+         try:
+             if type(spec[DEFAULT]) == types.IntType:
+                 typeStr = 'integer'
+                 value = string.atoi(value)
+             elif type(spec[DEFAULT]) == types.FloatType:
+                 typeStr = 'float'
+                 value = string.atof(value)
+         except:
+             sys.exc_traceback = None   # Clean up object references
+             return errMsg + 'cannot convert string \'' + value + \
+               '\' to ' + typeStr + ' for option \'-' + key + '\'.'
+       set(key, value)
+    else:
+      _fileList.append(arg)
+    i = i + 1
+
+  if get('help'):
+    return _helpString(title, argSpecs)
+
+  if not filesOK and len(_fileList) > 0:
+    if len(_fileList) == 1:
+      return errMsg + 'unknown option \'' + str(_fileList[0]) + '\'.'
+    else:
+      return errMsg + 'unknown options ' + str(_fileList) + '.'
+
+
+  _missing = []
+  for spec in argSpecs:
+    if spec[MANDATORY] and get(spec[NAME]) is None:
+      _missing.append(spec[NAME])
+  if len(_missing) == 1:
+    return errMsg + 'required argument \'-' + \
+      str(_missing[0]) + '\' is missing.'
+  elif len(_missing) > 1:
+    return errMsg + 'required arguments ' + \
+      str(map(lambda s: '-' + s, _missing)) + ' are missing.'
+
+  return None
+
+def fileList():
+  return _fileList
+
+def _helpString(title, argSpecs):
+  max = 0
+  for spec in argSpecs:
+    if spec[TYPE] is Bool:
+      width = len(spec[NAME]) + 1
+    else:
+      width = len(spec[NAME]) + 4 + len(spec[TYPE])
+    if width > max:
+      max = width
+
+  rtn = title + ' command line arguments:'
+  format = '\n  %-' + str(max) + 's %s'
+  for mandatory in (1, 0):
+    needHeader = 1
+    for spec in argSpecs:
+      if mandatory and spec[MANDATORY] or not mandatory and not spec[MANDATORY]:
+       if needHeader:
+         if mandatory:
+           rtn = rtn + '\n Mandatory arguments:'
+         else:
+           rtn = rtn + '\n Optional arguments (defaults in parentheses):'
+         needHeader = 0
+       if spec[TYPE] is Bool:
+         arg = '-%s' % spec[NAME]
+       else:
+         arg = '-%s <%s>' % (spec[NAME], spec[TYPE])
+       if len(spec) >= SPEC_LENGTH:
+         if type(spec[DEFAULT]) == types.StringType:
+             definition = spec[HELP] + ' (' + spec[DEFAULT] + ')'
+         else:
+             definition = spec[HELP] + ' (' + str(spec[DEFAULT]) + ')'
+       else:
+         definition = spec[HELP]
+       rtn = rtn + format % (arg, definition)
+
+  return rtn
+
+def exists(key):
+    return configDict.has_key(key)
+
+def get(key):
+    return configDict[key]
+
+def set(key, value):
+    global configDict
+
+    configDict[key] = value
+
+configDict = {}
diff --git a/Pmw/Pmw_1_2/demos/Balloon.py b/Pmw/Pmw_1_2/demos/Balloon.py
new file mode 100644 (file)
index 0000000..71788f6
--- /dev/null
@@ -0,0 +1,185 @@
+title = 'Pmw.Balloon demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the Balloon.
+       self.balloon = Pmw.Balloon(parent)
+
+       # Create some widgets and megawidgets with balloon help.
+       frame = Tkinter.Frame(parent)
+       frame.pack(padx = 10, pady = 5)
+       field = Pmw.EntryField(frame,
+               labelpos = 'nw',
+               label_text = 'Command:')
+       field.setentry('mycommand -name foo')
+       field.pack(side = 'left', padx = 10)
+       self.balloon.bind(field, 'Command to\nstart/stop',
+               'Enter the shell command to control')
+
+       start = Tkinter.Button(frame, text='Start')
+       start.pack(side='left', padx = 10)
+       self.balloon.bind(start, 'Start the command')
+
+       stop = Tkinter.Button(frame, text='Stop')
+       stop.pack(side='left', padx = 10)
+       self.balloon.bind(stop, 'Stop the command')
+
+       self.suicide = Tkinter.Button(frame, text='Kill me soon!',
+            command = self.killButton)
+       self.suicide.pack(side='left', padx = 10)
+       self.balloon.bind(self.suicide, 'Watch this button disappear!')
+
+       scrolledCanvas = Pmw.ScrolledCanvas(parent,
+               canvas_width = 300,
+               canvas_height = 115,
+       )
+       scrolledCanvas.pack()
+        canvas = scrolledCanvas.component('canvas')
+        self.canvas = canvas
+
+       # Create some canvas items and individual help.
+       item = canvas.create_arc(5, 5, 35, 35, fill = 'red', extent = 315)
+       self.balloon.tagbind(canvas, item, 'This is help for\nan arc item')
+       item = canvas.create_bitmap(20, 150, bitmap = 'question')
+       self.balloon.tagbind(canvas, item, 'This is help for\na bitmap')
+       item = canvas.create_line(50, 60, 70, 80, 85, 20, width = 5)
+       self.balloon.tagbind(canvas, item, 'This is help for\na line item')
+       item = canvas.create_text(10, 90, text = 'Canvas items with balloons',
+                anchor = 'nw', font = field.cget('entry_font'))
+       self.balloon.tagbind(canvas, item, 'This is help for\na text item')
+
+       # Create two canvas items which have the same tag and which use
+       # the same help.
+       canvas.create_rectangle(100, 10, 170, 50, fill = 'aliceblue',
+               tags = 'TAG1')
+       self.bluecircle = canvas.create_oval(110, 30, 160, 80, fill = 'blue',
+               tags = 'TAG1')
+       self.balloon.tagbind(canvas, 'TAG1',
+               'This is help for the two blue items' + '\n' * 10 +
+                    'It is very, very big.',
+                'This is help for the two blue items')
+       item = canvas.create_text(180, 10, text = 'Delete',
+                anchor = 'nw', font = field.cget('entry_font'))
+       self.balloon.tagbind(canvas, item,
+                'After 2 seconds,\ndelete the blue circle')
+       canvas.tag_bind(item, '<ButtonPress>', self._canvasButtonpress)
+       scrolledCanvas.resizescrollregion()
+
+       scrolledText = Pmw.ScrolledText(parent,
+               text_width = 32,
+               text_height = 4,
+                text_wrap = 'none',
+        )
+       scrolledText.pack(pady = 5)
+        text = scrolledText.component('text')
+        self.text = text
+
+       text.insert('end',
+               'This is a text widget with ', '',
+               ' balloon', 'TAG1',
+               '\nhelp. Find the ', '',
+               ' text ', 'TAG1',
+               ' tagged with', '',
+               ' help.', 'TAG2',
+               '\n', '',
+                'Remove tag 1.', 'TAG3',
+                '\nAnother line.\nAnd another', '',
+       )
+       text.tag_configure('TAG1', borderwidth = 2, relief = 'sunken')
+       text.tag_configure('TAG3', borderwidth = 2, relief = 'raised')
+
+       self.balloon.tagbind(text, 'TAG1',
+               'There is one secret\nballoon help.\nCan you find it?')
+       self.balloon.tagbind(text, 'TAG2',
+               'Well done!\nYou found it!')
+       self.balloon.tagbind(text, 'TAG3',
+               'After 2 seconds\ndelete the tag')
+       text.tag_bind('TAG3', '<ButtonPress>', self._textButtonpress)
+
+       frame = Tkinter.Frame(parent)
+       frame.pack(padx = 10)
+       self.toggleBalloonVar = Tkinter.IntVar()
+       self.toggleBalloonVar.set(1)
+       toggle = Tkinter.Checkbutton(frame,
+               variable = self.toggleBalloonVar,
+               text = 'Balloon help', command = self.toggle)
+       toggle.pack(side = 'left', padx = 10)
+       self.balloon.bind(toggle, 'Toggle balloon help\non and off')
+
+       self.toggleStatusVar = Tkinter.IntVar()
+       self.toggleStatusVar.set(1)
+       toggle = Tkinter.Checkbutton(frame,
+               variable = self.toggleStatusVar,
+               text = 'Status help', command = self.toggle)
+       toggle.pack(side = 'left', padx = 10)
+       self.balloon.bind(toggle,
+                'Toggle status help on and off, on and off' + '\n' * 10 +
+                    'It is very, very big, too.',
+                'Toggle status help on and off')
+
+       # Create and pack the MessageBar.
+       messageBar = Pmw.MessageBar(parent,
+               entry_width = 40,
+               entry_relief='groove',
+               labelpos = 'w',
+               label_text = 'Status:')
+       messageBar.pack(fill = 'x', expand = 1, padx = 10, pady = 5)
+
+       # Configure the balloon to display its status messages in the
+       # message bar.
+       self.balloon.configure(statuscommand = messageBar.helpmessage)
+
+    def toggle(self):
+       if self.toggleBalloonVar.get():
+           if self.toggleStatusVar.get():
+               self.balloon.configure(state = 'both')
+           else:
+               self.balloon.configure(state = 'balloon')
+       else:
+           if self.toggleStatusVar.get():
+               self.balloon.configure(state = 'status')
+           else:
+               self.balloon.configure(state = 'none')
+
+    def killButton(self):
+        # Test for old bug when destroying widgets 1) while the
+        # balloon was up and 2) during the initwait period.
+        print 'Destroying button in 2 seconds'
+        self.suicide.after(2000, self.suicide.destroy)
+
+    def _canvasButtonpress(self, event):
+        print 'Destroying blue circle in 2 seconds'
+       self.canvas.after(2000, self.deleteBlueCircle)
+
+    def deleteBlueCircle(self):
+        self.balloon.tagunbind(self.canvas, self.bluecircle)
+        self.canvas.delete(self.bluecircle)
+
+    def _textButtonpress(self, event):
+        print 'Deleting the text tag in 2 seconds'
+       self.text.after(2000, self.deleteTextTag)
+
+    def deleteTextTag(self):
+       self.balloon.tagunbind(self.text, 'TAG1')
+        self.text.tag_delete('TAG1')
+
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root, 12, fontScheme = 'default')
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/BltGraph.py b/Pmw/Pmw_1_2/demos/BltGraph.py
new file mode 100644 (file)
index 0000000..a71c5c3
--- /dev/null
@@ -0,0 +1,241 @@
+title = 'Blt Graph demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+# Simple random number generator.
+rand = 12345
+def random():
+    global rand
+    rand = (rand * 125) % 2796203
+    return rand
+
+class GraphDemo(Pmw.MegaToplevel):
+
+    def __init__(self, parent=None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = (
+           ('size',      10,   Pmw.INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaToplevel.__init__(self, parent)
+
+       # Create the graph.
+       self.createWidgets()
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def createWidgets(self):
+       # Create vectors for use as x and y data points.
+       self._numElements = 7
+       self._vectorSize = self['size']
+       self._vector_x = Pmw.Blt.Vector()
+       self._vector_y = []
+       for y in range(self._numElements):
+           self._vector_y.append(Pmw.Blt.Vector())
+       for index in range(self._vectorSize):
+           self._vector_x.append(index)
+           for y in range(self._numElements):
+               self._vector_y[y].append(random() % 100)
+
+       interior = self.interior()
+
+        controlFrame = Tkinter.Frame(interior)
+       controlFrame.pack(side = 'bottom', fill = 'x', expand = 0)
+
+        # Create an option menu for the kind of elements to create.
+       elementtype = Pmw.OptionMenu(controlFrame,
+               labelpos = 'nw',
+               label_text = 'Element type',
+               items = ['bars', 'lines', 'mixed', 'none'],
+               command = self._setelementtype,
+               menubutton_width = 8,
+       )
+       elementtype.pack(side = 'left')
+
+        # Create an option menu for the barmode option.
+       barmode = Pmw.OptionMenu(controlFrame,
+               labelpos = 'nw',
+               label_text = 'Bar mode',
+               items = ['normal', 'stacked', 'aligned', 'overlap'],
+               command = self._setbarmode,
+               menubutton_width = 8,
+       )
+       barmode.pack(side = 'left')
+
+        # Create an option menu for the smooth option.
+       self.smooth = Pmw.OptionMenu(controlFrame,
+               labelpos = 'nw',
+               label_text = 'Smooth',
+               items = ['linear', 'step', 'natural', 'quadratic'],
+               command = self._setsmooth,
+               menubutton_width = 9,
+       )
+       self.smooth.pack(side = 'left')
+
+        # Create an option menu to reverse sort the elements.
+       sortelements = Pmw.OptionMenu(controlFrame,
+               labelpos = 'nw',
+               label_text = 'Order',
+               items = ['normal', 'reverse'],
+               command = self._setsortelements,
+               menubutton_width = 8,
+       )
+       sortelements.pack(side = 'left')
+
+        # Create an option menu for the bufferelements option.
+       bufferelements = Pmw.OptionMenu(controlFrame,
+               labelpos = 'nw',
+               label_text = 'Buffering',
+               items = ['buffered', 'unbuffered'],
+               command = self._setbufferelements,
+               menubutton_width = 10,
+       )
+       bufferelements.pack(side = 'left')
+
+       # Create a button to add a point to the vector.
+       addpoint = Tkinter.Button(controlFrame, text = 'Add point', 
+               command = Pmw.busycallback(self._addpoint))
+       addpoint.pack(side = 'left', fill = 'x', expand = 0)
+
+       # Create a button to close the window
+       close = Tkinter.Button(controlFrame, text = 'Close', 
+               command = Pmw.busycallback(self.destroy))
+       close.pack(side = 'left', fill = 'x', expand = 0)
+
+       # Create the graph and its elements.
+       self._graph = Pmw.Blt.Graph(interior)
+       self._graph.pack(expand = 1, fill = 'both')
+       self._graph.yaxis_configure(command=self.yaxisCommand)
+       elementtype.invoke('mixed')
+       bufferelements.invoke('buffered')
+
+    def yaxisCommand(self, graph, value):
+        try:
+            num = string.atoi(value)
+            return '%d      %3d' % (num * 3, num)
+        except ValueError:
+            num = string.atof(value)
+            return '%g      %3g' % (num * 3, num)
+
+    def _setelementtype(self, type):
+        elements = self._graph.element_names()
+       apply(self._graph.element_delete, elements)
+
+        if type == 'none':
+            return
+
+       colorList = Pmw.Color.spectrum(self._numElements)
+       for elem in range(self._numElements):
+           if elem == 0:
+               hue = None
+           else:
+               hue = (elem + 1.0) / self._numElements * 6.28318
+           foreground = colorList[elem]
+           background = Pmw.Color.changebrightness(self, foreground, 0.8)
+           if type == 'mixed':
+               if elem < self._numElements / 2:
+                   bar = 0
+               else:
+                   bar = 1
+           elif type == 'bars':
+               bar = 1
+           else:
+               bar = 0
+           if bar:
+               self._graph.bar_create(
+                   'var' + str(elem),
+                   xdata=self._vector_x,
+                   ydata=self._vector_y[elem],
+                   foreground = foreground,
+                   background = background)
+           else:
+               self._graph.line_create(
+                   'var' + str(elem),
+                   linewidth = 4,
+                   xdata=self._vector_x,
+                   ydata=self._vector_y[elem],
+                    smooth = self.smooth.getcurselection(),
+                   color = foreground)
+
+    def _setbarmode(self, tag):
+        self._graph.configure(barmode = tag)
+
+    def _setsmooth(self, tag):
+       for element in self._graph.element_show():
+            if self._graph.element_type(element) == 'line':
+                self._graph.element_configure(element, smooth = tag)
+
+    def _setbufferelements(self, tag):
+        self._graph.configure(bufferelements = (tag == 'buffered'))
+
+    def _setsortelements(self, tag):
+       element_list = list(self._graph.element_show())
+        if len(element_list) > 1:
+            if (tag == 'normal') == (element_list[-1] != 'var0'):
+                element_list.reverse()
+                self._graph.element_show(element_list)
+
+    def _addpoint(self):
+       self._vector_x.append(self._vectorSize)
+       for y in range(self._numElements):
+           self._vector_y[y].append(random() % 100)
+       self._vectorSize = self._vectorSize + 1
+
+class Demo:
+    def __init__(self, parent):
+       if not Pmw.Blt.haveblt(parent):
+           message = 'Sorry\nThe BLT package has not been\n' + \
+                   'installed on this system.\n' + \
+                   'Please install it and try again.'
+           w = Tkinter.Label(parent, text = message)
+           w.pack(padx = 8, pady = 8)
+           return
+
+       message = 'This is a simple demonstration of the\n' + \
+               'BLT graph widget.\n' + \
+               'Select the number of points to display and\n' + \
+               'click on the button to display the graph.'
+       w = Tkinter.Label(parent, text = message)
+       w.pack(padx = 8, pady = 8)
+
+       # Create combobox to select number of points to display.
+       self.combo = Pmw.ComboBox(parent,
+               scrolledlist_items = ('10', '25', '50', '100', '300'),
+               entryfield_value = '10')
+       self.combo.pack(padx = 8, pady = 8)
+
+       # Create button to start blt graph.
+       start = Tkinter.Button(parent,
+               text = 'Show BLT graph',
+               command = Pmw.busycallback(self.showGraphDemo))
+       start.pack(padx = 8, pady = 8)
+
+       self.parent = parent
+
+    def showGraphDemo(self):
+       size = string.atoi(self.combo.get())
+       demo = GraphDemo(self.parent, size = size)
+        demo.focus()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/BltTabset.py b/Pmw/Pmw_1_2/demos/BltTabset.py
new file mode 100644 (file)
index 0000000..b6cf589
--- /dev/null
@@ -0,0 +1,101 @@
+title = 'Blt Tabset demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       if not Pmw.Blt.haveblt(parent):
+           message = 'Sorry\nThe BLT package has not been\n' + \
+                   'installed on this system.\n' + \
+                   'Please install it and try again.'
+           w = Tkinter.Label(parent, text = message)
+           w.pack(padx = 8, pady = 8)
+           return
+
+        self.tabset = Pmw.Blt.Tabset(parent,
+            borderwidth = 0,
+            highlightthickness = 0,
+            selectpad = 0,
+            tiers = 2,
+        )
+        background = self.tabset.cget('background')
+        self.tabset.configure(selectbackground = background,
+                tabbackground = background, activebackground = background)
+
+        configurePanel = Tkinter.Frame(self.tabset)
+        sideMenu = Pmw.OptionMenu (configurePanel,
+                labelpos = 'w',
+                label_text = 'Side:',
+                items = ('top', 'bottom', 'left', 'right'),
+                menubutton_width = 10,
+                command = self.changeSide,
+        )
+        sideMenu.pack(anchor = 'w', padx = 10, pady = 10)
+
+        rotateMenu = Pmw.ComboBox(configurePanel,
+                labelpos = 'w',
+                label_text = 'Text rotation:',
+                entryfield_validate = 'integer',
+                entry_width = 8,
+                selectioncommand = self.rotateText,
+                scrolledlist_items = (0, 45, 90, 135, 180, 225, 270, 315),
+        )
+        rotateMenu.pack(side = 'left', padx = 10, pady = 10)
+
+        rotateMenu.selectitem(0)
+        self.rotateText('0')
+
+        self.appearancePanel = Tkinter.Label(self.tabset)
+        helpersPanel = Tkinter.Button(self.tabset,
+                text = 'This is a lot\nof help!')
+
+        self.tabset.insert('end',
+                'Appearance', 'Configure', 'Helpers', 'Images')
+
+        self.tabset.tab_configure('Appearance',
+                command = self.appearance_cb, fill = 'both')
+        self.tabset.tab_configure('Configure', window = configurePanel)
+        self.tabset.tab_configure('Images',
+                command = self.images_cb, fill = 'both')
+        self.tabset.tab_configure('Helpers',
+                window = helpersPanel, padx = 100, pady = 150)
+
+        self.tabset.invoke(1)
+        self.tabset.pack(fill = 'both', expand = 1, padx = 5, pady = 5)
+        self.tabset.focus()
+
+    def appearance_cb(self):
+        self.appearancePanel.configure(
+                text = 'Don\'t judge a book\nby it\'s cover.')
+        self.tabset.tab_configure('Appearance', window = self.appearancePanel)
+
+    def images_cb(self):
+        self.appearancePanel.configure(text = 'Beauty is only\nskin deep.')
+        self.tabset.tab_configure('Images', window = self.appearancePanel)
+
+    def changeSide(self, side):
+        self.tabset.configure(side = side)
+
+    def rotateText(self, angle):
+        if Pmw.integervalidator(angle) == Pmw.OK:
+            self.tabset.configure(rotate = angle)
+        else:
+            self.tabset.bell()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ButtonBox.py b/Pmw/Pmw_1_2/demos/ButtonBox.py
new file mode 100644 (file)
index 0000000..984ff36
--- /dev/null
@@ -0,0 +1,56 @@
+title = 'Pmw.ButtonBox demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the ButtonBox.
+       self.buttonBox = Pmw.ButtonBox(parent,
+               labelpos = 'nw',
+               label_text = 'ButtonBox:',
+                frame_borderwidth = 2,
+                frame_relief = 'groove')
+       self.buttonBox.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+
+       # Add some buttons to the ButtonBox.
+       self.buttonBox.add('OK', command = self.ok)
+       self.buttonBox.add('Apply', command = self.apply)
+       self.buttonBox.add('Cancel', command = self.cancel)
+
+       # Set the default button (the one executed when <Return> is hit).
+       self.buttonBox.setdefault('OK')
+       parent.bind('<Return>', self._processReturnKey)
+       parent.focus_set()
+
+       # Make all the buttons the same width.
+       self.buttonBox.alignbuttons()
+
+    def _processReturnKey(self, event):
+       self.buttonBox.invoke()
+
+    def ok(self):
+       print 'You clicked on OK'
+
+    def apply(self):
+       print 'You clicked on Apply'
+
+    def cancel(self):
+       print 'You clicked on Cancel'
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Colors.py b/Pmw/Pmw_1_2/demos/Colors.py
new file mode 100644 (file)
index 0000000..b6e0a5b
--- /dev/null
@@ -0,0 +1,50 @@
+title = 'Colorscheme demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       frame = Tkinter.Frame(parent)
+       frame.pack(fill = 'both', expand = 1)
+
+       defaultPalette = Pmw.Color.getdefaultpalette(parent)
+
+       colors = ('red', 'green', 'blue')
+       items = ('Testing', 'More testing', 'a test', 'foo', 'blah')
+       for count in range(len(colors)):
+           color = colors[count]
+           normalcolor = Pmw.Color.changebrightness(parent, color, 0.85)
+           Pmw.Color.setscheme(parent, normalcolor)
+           combo = Pmw.ComboBox(frame,
+                   scrolledlist_items = items,
+                   entryfield_value = items[0])
+           combo.grid(sticky='nsew', row = count, column = 0)
+
+           normalcolor = Pmw.Color.changebrightness(parent, color, 0.35)
+           Pmw.Color.setscheme(parent, normalcolor, foreground = 'white')
+           combo = Pmw.ComboBox(frame,
+                   scrolledlist_items = items,
+                   entryfield_value = items[0])
+           combo.grid(sticky='nsew', row = count, column = 1)
+
+       apply(Pmw.Color.setscheme, (parent,), defaultPalette)
+       #normalcolor = Pmw.Color.changebrightness(parent, 'red', 0.85)
+       #Pmw.Color.setscheme(parent, normalcolor)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ComboBox.py b/Pmw/Pmw_1_2/demos/ComboBox.py
new file mode 100644 (file)
index 0000000..461fc80
--- /dev/null
@@ -0,0 +1,76 @@
+title = 'Pmw.ComboBox demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+        parent.configure(background = 'white')
+
+        # Create and pack the widget to be configured.
+       self.target = Tkinter.Label(parent,
+               relief = 'sunken',
+                padx = 20,
+                pady = 20,
+        )
+       self.target.pack(fill = 'x', padx = 8, pady = 8)
+
+       # Create and pack the simple ComboBox.
+        words = ('Monti', 'Python', 'ik', 'den', 'Holie', 'Grailen', '(Bok)')
+       simple = Pmw.ComboBox(parent,
+                label_text = 'Simple ComboBox:',
+               labelpos = 'nw',
+                selectioncommand = self.changeText,
+               scrolledlist_items = words,
+                dropdown = 0,
+        )
+       simple.pack(side = 'left', fill = 'both',
+                expand = 1, padx = 8, pady = 8)
+
+       # Display the first text.
+       first = words[0]
+       simple.selectitem(first)
+       self.changeText(first)
+
+       # Create and pack the dropdown ComboBox.
+        colours = ('cornsilk1', 'snow1', 'seashell1', 'antiquewhite1',
+                'bisque1', 'peachpuff1', 'navajowhite1', 'lemonchiffon1',
+                'ivory1', 'honeydew1', 'lavenderblush1', 'mistyrose1')
+       dropdown = Pmw.ComboBox(parent,
+                label_text = 'Dropdown ComboBox:',
+               labelpos = 'nw',
+                selectioncommand = self.changeColour,
+               scrolledlist_items = colours,
+        )
+       dropdown.pack(side = 'left', anchor = 'n',
+                fill = 'x', expand = 1, padx = 8, pady = 8)
+
+       # Display the first colour.
+       first = colours[0]
+       dropdown.selectitem(first)
+       self.changeColour(first)
+
+    def changeColour(self, colour):
+       print 'Colour: ' + colour
+       self.target.configure(background = colour)
+
+    def changeText(self, text):
+       print 'Text: ' + text
+       self.target.configure(text = text)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ComboBoxDialog.py b/Pmw/Pmw_1_2/demos/ComboBoxDialog.py
new file mode 100644 (file)
index 0000000..c0e3ded
--- /dev/null
@@ -0,0 +1,44 @@
+title = 'Pmw.ComboBoxDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the dialog.
+       self.dialog = Pmw.ComboBoxDialog(parent,
+           title = 'My ComboBoxDialog',
+           buttons = ('OK', 'Cancel'),
+           defaultbutton = 'OK',
+           combobox_labelpos = 'n',
+           label_text = 'What do you think of Pmw?',
+           scrolledlist_items = ('Cool man', 'Cool', 'Good', 'Bad', 'Gross'))
+       self.dialog.withdraw()
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent,
+               text = 'Show combo box dialog',
+               command = self.doit)
+       w.pack(padx = 8, pady = 8)
+
+    def doit(self):
+        result = self.dialog.activate()
+       print 'You clicked on', result, self.dialog.get()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
+
diff --git a/Pmw/Pmw_1_2/demos/ConfigClass.py b/Pmw/Pmw_1_2/demos/ConfigClass.py
new file mode 100644 (file)
index 0000000..b4d2b7f
--- /dev/null
@@ -0,0 +1,76 @@
+title = 'Component python class configuration demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class MyButton(Tkinter.Button):
+    # This is just an ordinary button with special colors.
+
+    def __init__(self, master=None, cnf={}, **kw):
+       self.__toggle = 0
+       kw['background'] = 'green'
+       kw['activebackground'] = 'red'
+       apply(Tkinter.Button.__init__, (self, master, cnf), kw)
+
+class Demo:
+    def __init__(self, parent):
+
+       # Create a title label:
+       label = Tkinter.Label(parent,
+               text = 'EntryFields with label components of specified type:')
+       label.pack(fill='x', expand=1, padx=10, pady=5)
+
+       # Create and pack some EntryFields.
+       entries = []
+       entry = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Label'
+       )
+       entry.pack(fill='x', expand=1, padx=10, pady=5)
+       entries.append(entry)
+
+       entry = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_pyclass = Tkinter.Button,
+               label_text = 'Button'
+       )
+       entry.pack(fill='x', expand=1, padx=10, pady=5)
+       entries.append(entry)
+
+       entry = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_pyclass = MyButton,
+               label_text = 'Special button'
+       )
+       entry.pack(fill='x', expand=1, padx=10, pady=5)
+       entries.append(entry)
+
+       Pmw.alignlabels(entries)
+
+       # Create and pack a ButtonBox.
+       buttonBox = Pmw.ButtonBox(parent,
+               labelpos = 'nw',
+               label_text = 'ButtonBox:')
+       buttonBox.pack(fill = 'both', expand = 1, padx=10, pady=5)
+
+       # Add some buttons to the ButtonBox.
+       buttonBox.add('with a')
+       buttonBox.add('special', pyclass = MyButton)
+       buttonBox.add('button')
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Counter.py b/Pmw/Pmw_1_2/demos/Counter.py
new file mode 100644 (file)
index 0000000..856b4df
--- /dev/null
@@ -0,0 +1,121 @@
+title = 'Pmw.Counter demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import time
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Need to use long ints here because on the Macintosh the maximum size
+       # of an integer is smaller than the value returned by time.time().
+       now = (long(time.time()) / 300) * 300
+
+       # Create the Counters.
+       self._date = Pmw.Counter(parent,
+               labelpos = 'w',
+               label_text = 'Date (4-digit year):',
+               entryfield_value =
+                        time.strftime('%d/%m/%Y', time.localtime(now)),
+               entryfield_command = self.execute,
+               entryfield_validate = {'validator' : 'date', 'format' : 'dmy'},
+               datatype = {'counter' : 'date', 'format' : 'dmy', 'yyyy' : 1})
+
+       self._isodate = Pmw.Counter(parent,
+               labelpos = 'w',
+               label_text = 'ISO-Date (4-digit year):',
+               entryfield_value =
+                       time.strftime('%Y-%m-%d', time.localtime(now)),
+               entryfield_command = self.execute,
+               entryfield_validate = {'validator' : 'date', 'format' : 'ymd',
+                        'separator' : '-' },
+               datatype = {'counter' : 'date', 'format' : 'ymd', 'yyyy' : 1,
+                        'separator' : '-' })
+
+       self._time = Pmw.Counter(parent,
+               labelpos = 'w',
+               label_text = 'Time:',
+               entryfield_value =
+                        time.strftime('%H:%M:%S', time.localtime(now)),
+               entryfield_validate = {'validator' : 'time',
+                       'min' : '00:00:00', 'max' : '23:59:59',
+                       'minstrict' : 0, 'maxstrict' : 0},
+               datatype = {'counter' : 'time', 'time24' : 1},
+               increment=5*60)
+       self._real = Pmw.Counter(parent,
+               labelpos = 'w',
+               label_text = 'Real (with comma)\nand extra\nlabel lines:',
+                label_justify = 'left',
+               entryfield_value = '1,5',
+               datatype = {'counter' : 'real', 'separator' : ','},
+               entryfield_validate = {'validator' : 'real',
+                       'min' : '-2,0', 'max' : '5,0',
+                       'separator' : ','},
+               increment = 0.1)
+       self._custom = Pmw.Counter(parent,
+               labelpos = 'w',
+               label_text = 'Custom:',
+               entryfield_value = specialword[:4],
+               datatype = _custom_counter,
+               entryfield_validate = _custom_validate)
+       self._int = Pmw.Counter(parent,
+               labelpos = 'w',
+               label_text = 'Vertical integer:',
+               orient = 'vertical',
+               entry_width = 2,
+               entryfield_value = 50,
+               entryfield_validate = {'validator' : 'integer',
+                       'min' : 0, 'max' : 99}
+       )
+
+       counters = (self._date, self._isodate, self._time, self._real,
+                self._custom)
+       Pmw.alignlabels(counters)
+
+       # Pack them all.
+       for counter in counters:
+           counter.pack(fill='both', expand=1, padx=10, pady=5)
+       self._int.pack(padx=10, pady=5)
+
+    def execute(self):
+       print 'Return pressed, value is', self._date.get()
+
+specialword = 'Monti Python ik den Holie Grailen (Bok)'
+
+def _custom_validate(text):
+    if string.find(specialword, text) == 0:
+       return 1
+    else:
+       return -1
+
+def _custom_counter(text, factor, increment):
+    # increment is ignored here.
+    if string.find(specialword, text) == 0:
+       length = len(text)
+       if factor == 1:
+           if length >= len(specialword):
+               raise ValueError, 'maximum length reached'
+           return specialword[:length + 1]
+       else:
+           if length == 0:
+               raise ValueError, 'empty string'
+           return specialword[:length - 1]
+    else:
+       raise ValueError, 'bad string ' + text
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/CounterDialog.py b/Pmw/Pmw_1_2/demos/CounterDialog.py
new file mode 100644 (file)
index 0000000..808c3bf
--- /dev/null
@@ -0,0 +1,60 @@
+title = 'Pmw.CounterDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the dialog to prompt for the number of times to ring the bell.
+       self.dialog = Pmw.CounterDialog(parent,
+           label_text = 'Enter the number of times to\n' + \
+                   'sound the bell (1 to 5)\n',
+           counter_labelpos = 'n',
+           entryfield_value = 2,
+           counter_datatype = 'numeric',
+           entryfield_validate =
+               {'validator' : 'numeric', 'min' : 1, 'max' : 5},
+           buttons = ('OK', 'Cancel'),
+           defaultbutton = 'OK',
+           title = 'Bell ringing',
+           command = self.execute)
+       self.dialog.withdraw()
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show counter dialog',
+               command = self.dialog.activate)
+       w.pack(padx = 8, pady = 8)
+
+    def execute(self, result):
+       if result is None or result == 'Cancel':
+           print 'Bell ringing cancelled'
+           self.dialog.deactivate()
+       else:
+           count = self.dialog.get()
+           if not self.dialog.valid():
+               print 'Invalid entry: "' + count + '"'
+           else:
+               print 'Ringing the bell ' + count + ' times'
+               for num in range(string.atoi(count)):
+                   if num != 0:
+                       self.dialog.after(200)
+                   self.dialog.bell()
+               self.dialog.deactivate()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/DemoVersion.py b/Pmw/Pmw_1_2/demos/DemoVersion.py
new file mode 100644 (file)
index 0000000..477a9f9
--- /dev/null
@@ -0,0 +1,36 @@
+# Set the version of Pmw to use for the demonstrations based on the
+# directory name.
+
+import imp
+import os
+import string
+
+def expandLinks(path):
+    if not os.path.isabs(path):
+       path = os.path.join(os.getcwd(), path)
+    while 1:
+       if not os.path.islink(path):
+           break
+       dir = os.path.dirname(path)
+       path = os.path.join(dir, os.readlink(path))
+
+    return path
+
+def setPmwVersion():
+    file = imp.find_module(__name__)[1]
+    file = os.path.normpath(file)
+    file = expandLinks(file)
+
+    dir = os.path.dirname(file)
+    dir = expandLinks(dir)
+    dir = os.path.dirname(dir)
+    dir = expandLinks(dir)
+    dir = os.path.basename(dir)
+
+    version = string.replace(dir[4:], '_', '.')
+    import Pmw
+    if version in Pmw.installedversions():
+       Pmw.setversion(version)
+    else:
+       print 'No such Pmw version', `version` + '.',
+       print 'Using default version', `Pmw.version()`
diff --git a/Pmw/Pmw_1_2/demos/Dialog.py b/Pmw/Pmw_1_2/demos/Dialog.py
new file mode 100644 (file)
index 0000000..3be3fdb
--- /dev/null
@@ -0,0 +1,89 @@
+title = 'Pmw.Dialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create two buttons to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show application modal dialog',
+               command = self.showAppModal)
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text = 'Show global modal dialog',
+               command = self.showGlobalModal)
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text = 'Show dialog with "no grab"',
+               command = self.showDialogNoGrab)
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text =
+                    'Show toplevel window which\n' +
+                    'will not get a busy cursor',
+               command = self.showExcludedWindow)
+       w.pack(padx = 8, pady = 8)
+
+       # Create the dialog.
+       self.dialog = Pmw.Dialog(parent,
+           buttons = ('OK', 'Apply', 'Cancel', 'Help'),
+           defaultbutton = 'OK',
+           title = 'My dialog',
+           command = self.execute)
+       self.dialog.withdraw()
+
+       # Add some contents to the dialog.
+       w = Tkinter.Label(self.dialog.interior(),
+           text = 'Pmw Dialog\n(put your widgets here)',
+           background = 'black',
+           foreground = 'white',
+           pady = 20)
+       w.pack(expand = 1, fill = 'both', padx = 4, pady = 4)
+
+       # Create the window excluded from showbusycursor.
+       self.excluded = Pmw.MessageDialog(parent,
+           title = 'I still work',
+           message_text =
+                'This window will not get\n' +
+                'a busy cursor when modal dialogs\n' +
+                'are activated.  In addition,\n' +
+                'you can still interact with\n' +
+                'this window when a "no grab"\n' +
+                'modal dialog is displayed.')
+       self.excluded.withdraw()
+        Pmw.setbusycursorattributes(self.excluded.component('hull'),
+            exclude = 1)
+
+    def showAppModal(self):
+        self.dialog.activate(geometry = 'centerscreenalways')
+
+    def showGlobalModal(self):
+        self.dialog.activate(globalMode = 1)
+
+    def showDialogNoGrab(self):
+        self.dialog.activate(globalMode = 'nograb')
+
+    def showExcludedWindow(self):
+        self.excluded.show()
+
+    def execute(self, result):
+       print 'You clicked on', result
+       if result not in ('Apply', 'Help'):
+           self.dialog.deactivate(result)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/EntryField.py b/Pmw/Pmw_1_2/demos/EntryField.py
new file mode 100644 (file)
index 0000000..6916381
--- /dev/null
@@ -0,0 +1,98 @@
+title = 'Pmw.EntryField demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import time
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the EntryFields.
+       self._any = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Any:',
+               validate = None,
+               command = self.execute)
+       self._real = Pmw.EntryField(parent,
+               labelpos = 'w',
+               value = '55.5',
+               label_text = 'Real (10.0 to 99.0):',
+               validate = {'validator' : 'real',
+                       'min' : 10, 'max' : 99, 'minstrict' : 0},
+               modifiedcommand = self.changed)
+       self._odd = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Odd length:',
+               validate = self.custom_validate,
+               value = 'ABC')
+       self._date = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Date (in 2000):',
+               value = '2000/2/29',
+               validate = {'validator' : 'date',
+                       'min' : '2000/1/1', 'max' : '2000/12/31',
+                       'minstrict' : 0, 'maxstrict' : 0,
+                       'format' : 'ymd'},
+               )
+       now = time.localtime(time.time())
+       self._date2 = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Date (d.m.y):',
+               value = '%d.%d.%d' % (now[2], now[1], now[0]),
+               validate = {'validator' : 'date',
+                       'format' : 'dmy', 'separator' : '.'},
+               )
+       self._time = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Time (24hr clock):',
+               value = '8:00:00',
+               validate = {'validator' : 'time',
+                       'min' : '00:00:00', 'max' : '23:59:59',
+                       'minstrict' : 0, 'maxstrict' : 0},
+               )
+       self._comma = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Real (with comma):',
+               value = '123,456',
+               validate = {'validator' : 'real', 'separator' : ','},
+               )
+
+       entries = (self._any, self._real, self._odd, self._date, self._date2,
+               self._time, self._comma)
+
+       for entry in entries:
+           entry.pack(fill='x', expand=1, padx=10, pady=5)
+       Pmw.alignlabels(entries)
+
+       self._any.component('entry').focus_set()
+
+    def changed(self):
+       print 'Text changed, value is', self._real.getvalue()
+
+    def execute(self):
+       print 'Return pressed, value is', self._any.getvalue()
+
+    # This implements a custom validation routine.  It simply checks
+    # if the string is of odd length.
+    def custom_validate(self, text):
+       print 'text:', text
+       if len(text) % 2 == 0:
+         return -1
+       else:
+         return 1
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ErrorHandling.py b/Pmw/Pmw_1_2/demos/ErrorHandling.py
new file mode 100644 (file)
index 0000000..41fd10f
--- /dev/null
@@ -0,0 +1,42 @@
+title = 'Pmw error handling demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create two buttons to generate errors.
+       w = Tkinter.Button(parent, text = 'Click here to generate\n' +
+               'an error in a command callback.', command = self.execute)
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text = 'Click here to generate\n' +
+               'an error in a callback called\nfrom an event binding.')
+       w.pack(padx = 8, pady = 8)
+       w.bind('<ButtonRelease-1>', self.execute)
+       w.bind('<Key-space>', self.execute)
+
+    def execute(self, event = None):
+       self._error()
+
+    def _error(self):
+       # Divide by zero
+       1/0
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ExampleDemo.py b/Pmw/Pmw_1_2/demos/ExampleDemo.py
new file mode 100644 (file)
index 0000000..f7ec1e7
--- /dev/null
@@ -0,0 +1,33 @@
+title = 'Pmw.EXAMPLE demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+       # Create and pack the EXAMPLEs.
+       self.widget1 = Pmw.Counter(parent)
+       self.widget1.setentry('1')
+       self.widget1.pack()
+
+       self.widget2 = Pmw.Counter(parent, increment = 10)
+       self.widget2.setentry('100')
+       self.widget2.pack()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Grid.py b/Pmw/Pmw_1_2/demos/Grid.py
new file mode 100644 (file)
index 0000000..051863e
--- /dev/null
@@ -0,0 +1,44 @@
+title = 'Grid geometry manager demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       frame = Tkinter.Frame(parent)
+       frame.pack(fill = 'both', expand = 1)
+
+       button = {}
+       for num in range(0, 10):
+           button[num] = Tkinter.Button(frame, text = 'Button ' + str(num))
+
+       button[0].grid(column=0, row=0, rowspan=2, sticky='nsew')
+       button[1].grid(column=1, row=0, columnspan=3, sticky='nsew')
+       button[2].grid(column=1, row=1, rowspan=2, sticky='nsew')
+       button[3].grid(column=2, row=1)
+       button[4].grid(column=3, row=1)
+       button[5].grid(column=0, row=2)
+       button[6].grid(column=0, row=3, columnspan=2, sticky='nsew')
+       button[7].grid(column=2, row=2, columnspan=2, rowspan=2, sticky='nsew')
+       button[8].grid(column=0, row=4)
+       button[9].grid(column=3, row=4, sticky='e')
+
+       frame.grid_rowconfigure(3, weight=1)
+       frame.grid_columnconfigure(3, weight=1)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Group.py b/Pmw/Pmw_1_2/demos/Group.py
new file mode 100644 (file)
index 0000000..b1c4ed5
--- /dev/null
@@ -0,0 +1,93 @@
+title = 'Pmw.Group demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+        # Create and pack the Groups.
+       w = Pmw.Group(parent, tag_text='label')
+       w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+       cw = Tkinter.Label(w.interior(),
+               text = 'A group with the\ndefault Label tag')
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+       w = Pmw.Group(parent, tag_pyclass = None)
+       w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+       cw = Tkinter.Label(w.interior(), text = 'A group\nwithout a tag')
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+       radiogroups = []
+       self.var = Tkinter.IntVar()
+       self.var.set(0)
+       radioframe = Tkinter.Frame(parent)
+       w = Pmw.Group(radioframe,
+               tag_pyclass = Tkinter.Radiobutton,
+               tag_text='radiobutton 1',
+               tag_value = 0,
+               tag_variable = self.var)
+       w.pack(fill = 'both', expand = 1, side='left')
+       cw = Tkinter.Frame(w.interior(),width=200,height=20)
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+       radiogroups.append(w)
+
+       w = Pmw.Group(radioframe,
+               tag_pyclass = Tkinter.Radiobutton,
+               tag_text='radiobutton 2',
+               tag_font = Pmw.logicalfont('Helvetica', 4),
+               tag_value = 1,
+               tag_variable = self.var)
+       w.pack(fill = 'both', expand = 1, side='left')
+       cw = Tkinter.Frame(w.interior(),width=200,height=20)
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+       radiogroups.append(w)
+       radioframe.pack(padx = 6, pady = 6, expand='yes', fill='both')
+       Pmw.aligngrouptags(radiogroups)
+
+       w = Pmw.Group(parent,
+               tag_pyclass = Tkinter.Checkbutton,
+               tag_text='checkbutton',
+               tag_foreground='blue')
+       w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+       cw = Tkinter.Frame(w.interior(),width=150,height=20)
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+       w = Pmw.Group(parent,
+               tag_pyclass = Tkinter.Button,
+               tag_text='Tkinter.Button')
+        w.configure(tag_command = w.toggle)
+       w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+       cw = Tkinter.Label(w.interior(),
+               background = 'aliceblue',
+               text = 'A group with\na Button tag!?'
+       )
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+       w = Pmw.Group(parent,
+               tag_pyclass = Tkinter.Button,
+               tag_text='Show/Hide')
+        w.configure(tag_command = w.toggle)
+       w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+       cw = Tkinter.Label(w.interior(),
+               background = 'aliceblue',
+               text = 'Now you see me.\nNow you don\'t.'
+       )
+       cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/HistoryText.py b/Pmw/Pmw_1_2/demos/HistoryText.py
new file mode 100644 (file)
index 0000000..5a7b2eb
--- /dev/null
@@ -0,0 +1,102 @@
+title = 'Pmw.HistoryText demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the PanedWidget to hold the query and result
+        # windows.
+        # !! panedwidget should automatically size to requested size
+        panedWidget = Pmw.PanedWidget(parent,
+                orient = 'vertical',
+                hull_height = 400,
+                hull_width = 550)
+        panedWidget.add('query', min = 0.05, size = 0.2)
+        panedWidget.add('buttons', min = 0.1, max = 0.1)
+        panedWidget.add('results', min = 0.05)
+        panedWidget.pack(fill = 'both', expand = 1)
+
+       # Create and pack the HistoryText.
+        self.historyText = Pmw.HistoryText(panedWidget.pane('query'),
+                text_wrap = 'none',
+                text_width = 60,
+                text_height = 10,
+                historycommand = self.statechange,
+        )
+        self.historyText.pack(fill = 'both', expand = 1)
+        self.historyText.component('text').focus()
+
+        buttonList = (
+            [20, None],
+            ['Clear', self.clear],
+            ['Undo', self.historyText.undo],
+            ['Redo', self.historyText.redo],
+            [20, None],
+            ['Prev', self.historyText.prev],
+            ['Next', self.historyText.next],
+            [30, None],
+            ['Execute', Pmw.busycallback(self.executeQuery)],
+        )
+        self.buttonDict = {}
+
+        buttonFrame = panedWidget.pane('buttons')
+        for text, cmd in buttonList:
+            if type(text) == type(69):
+                frame = Tkinter.Frame(buttonFrame, width = text)
+                frame.pack(side = 'left')
+            else:
+                button = Tkinter.Button(buttonFrame, text = text, command = cmd)
+                button.pack(side = 'left')
+                self.buttonDict[text] = button
+
+        for text in ('Prev', 'Next'):
+            self.buttonDict[text].configure(state = 'disabled')
+
+        self.results = Pmw.ScrolledText(panedWidget.pane('results'), text_wrap = 'none')
+        self.results.pack(fill = 'both', expand = 1)
+
+    def statechange(self, prevstate, nextstate):
+        self.buttonDict['Prev'].configure(state = prevstate)
+        self.buttonDict['Next'].configure(state = nextstate)
+
+    def clear(self):
+        self.historyText.delete('1.0', 'end')
+
+    def addnewlines(self, text):
+        if len(text) == 1:
+            text = text + '\n'
+        if text[-1] != '\n':
+            text = text + '\n'
+        if text[-2] != '\n':
+            text = text + '\n'
+        return text
+
+    def executeQuery(self):
+        sql = self.historyText.get()
+        self.results.insert('end', 'Query:\n' + self.addnewlines(sql))
+        self.results.see('end')
+        self.results.update_idletasks()
+        self.historyText.addhistory()
+        results = 'Results:\nfoo'
+        if len(results) > 0:
+            self.results.insert('end', self.addnewlines(results))
+        self.results.see('end')
+
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/LabeledWidget.py b/Pmw/Pmw_1_2/demos/LabeledWidget.py
new file mode 100644 (file)
index 0000000..8a98c59
--- /dev/null
@@ -0,0 +1,46 @@
+title = 'Pmw.LabeledWidget demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+       # Create a frame to put the LabeledWidgets into
+       frame = Tkinter.Frame(parent, background = 'grey90')
+       frame.pack(fill = 'both', expand = 1)
+
+       # Create and pack the LabeledWidgets.
+       column = 0
+       row = 0
+       for pos in ('n', 'nw', 'wn', 'w'):
+           lw = Pmw.LabeledWidget(frame,
+                   labelpos = pos,
+                   label_text = pos + ' label')
+           lw.component('hull').configure(relief='sunken', borderwidth=2)
+           lw.grid(column=column, row=row, padx=10, pady=10)
+           cw = Tkinter.Button(lw.interior(), text='child\nsite')
+           cw.pack(padx=10, pady=10, expand='yes', fill='both')
+
+           # Get ready for next grid position.
+           column = column + 1
+           if column == 2:
+             column = 0
+             row = row + 1
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    widget = Demo(root)
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack()
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/LogicalFont.py b/Pmw/Pmw_1_2/demos/LogicalFont.py
new file mode 100644 (file)
index 0000000..6185469
--- /dev/null
@@ -0,0 +1,84 @@
+title = 'Pmw LogicalFont demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+
+    # The fonts to demonstrate.
+    fontList = (
+      (('Times', 0), {}),
+      (('Helvetica', 0), {}),
+      (('Typewriter', 0), {}),
+      (('Fixed', 0), {}),
+      (('Courier', 0), {}),
+      (('Helvetica', 2), {'slant' : 'italic'}),
+      (('Helvetica', 0), {'size' : 18}),
+      (('Helvetica', 0), {'weight' : 'bold'}),
+      (('Helvetica', 12), {'weight' : 'bold', 'slant' : 'italic'}),
+      (('Typewriter', 0), {'size' : 8, 'weight' : 'bold'}),
+      (('Fixed', 0), {'size' : 8, 'weight' : 'bold'}),
+      (('Times', 0), {'size' : 24, 'weight' : 'bold', 'slant' : 'italic'}),
+      (('Typewriter', 0), {'width' : 'condensed'}),
+      (('Typewriter', -1), {'width' : 'condensed'}),
+      (('Fixed', 0), {'width' : 'condensed'}),
+      (('Fixed', -1), {'width' : 'condensed'}),
+      (('Helvetica', 0), {'weight' : 'bogus'}),
+    )
+
+    fontText = []
+
+    def __init__(self, parent):
+
+       self.parent = parent
+
+       # Create the text to display to the user to represent each font.
+       if Demo.fontText == []:
+           for args, dict in Demo.fontList:
+               text = args[0]
+               if args[1] != 0:
+                   text = text + ' ' + str(args[1])
+               for name, value in dict.items():
+                   text = text + ' ' + name + ': ' + str(value)
+               Demo.fontText.append(text)
+
+       # Create a listbox to contain the font selections.
+       self.box = Pmw.ScrolledListBox(parent, listbox_selectmode='single', 
+               listbox_width = 35,
+               listbox_height = 10,
+               items=Demo.fontText,
+               label_text='Font', labelpos='nw', 
+               selectioncommand=self.selectionCommand)
+       self.box.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+
+       # Create a label to display the selected font.
+       self.target = Tkinter.Label(parent,
+               text = 'The quick brown fox jumps\nover the lazy dog',
+               relief = 'sunken', padx = 10, pady = 10)
+       self.target.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+
+    def selectionCommand(self):
+       sel = self.box.curselection()
+       if len(sel) > 0:
+           args, dict = Demo.fontList[string.atoi(sel[0])]
+           font = apply(Pmw.logicalfont, args, dict)
+            self.target.configure(font = font)
+            print font
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/MainMenuBar.py b/Pmw/Pmw_1_2/demos/MainMenuBar.py
new file mode 100644 (file)
index 0000000..682d36e
--- /dev/null
@@ -0,0 +1,176 @@
+title = 'Pmw.MainMenuBar demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create button to launch the toplevel with main menubar.
+       w = Tkinter.Button(parent, text = 'Show Pmw.MainMenuBar demo',
+               command = lambda parent=parent: MainMenuBarToplevel(parent))
+       w.pack(padx = 8, pady = 8)
+
+class MainMenuBarToplevel:
+    def __init__(self, parent):
+        # Create the toplevel to contain the main menubar.
+        megaToplevel = Pmw.MegaToplevel(parent, title = title)
+       toplevel = megaToplevel.interior()
+
+       # Create the Balloon for this toplevel.
+       self.balloon = Pmw.Balloon(toplevel)
+
+       # Create and install the MenuBar.
+       menuBar = Pmw.MainMenuBar(toplevel,
+                balloon = self.balloon)
+        toplevel.configure(menu = menuBar)
+       self.menuBar = menuBar
+
+       # Add some buttons to the MainMenuBar.
+       menuBar.addmenu('File', 'Close this window or exit')
+       menuBar.addmenuitem('File', 'command', 'Close this window',
+               command = PrintOne('Action: close'),
+               label = 'Close')
+       menuBar.addmenuitem('File', 'separator')
+       menuBar.addmenuitem('File', 'command', 'Exit the application',
+               command = PrintOne('Action: exit'),
+               label = 'Exit')
+
+       menuBar.addmenu('Edit', 'Cut, copy or paste')
+       menuBar.addmenuitem('Edit', 'command', 'Delete the current selection',
+               command = PrintOne('Action: delete'),
+               label = 'Delete')
+
+       menuBar.addmenu('Options', 'Set user preferences')
+       menuBar.addmenuitem('Options', 'command', 'Set general preferences',
+               command = PrintOne('Action: general options'),
+               label = 'General...')
+
+       # Create a checkbutton menu item.
+        self.toggleVar = Tkinter.IntVar()
+       # Initialise the checkbutton to 1:
+        self.toggleVar.set(1)
+        menuBar.addmenuitem('Options', 'checkbutton', 'Toggle me on/off',
+                label = 'Toggle',
+                command = self._toggleMe,
+                variable = self.toggleVar)
+        self._toggleMe()
+
+       menuBar.addcascademenu('Options', 'Size',
+               'Set some other preferences', traverseSpec = 'z', tearoff = 1)
+       for size in ('tiny', 'small', 'average', 'big', 'huge'):
+           menuBar.addmenuitem('Size', 'command', 'Set size to ' + size,
+                    command = PrintOne('Action: size ' + size),
+                   label = size)
+
+       menuBar.addmenu('Help', 'User manuals', name = 'help')
+       menuBar.addmenuitem('Help', 'command', 'About this application',
+               command = PrintOne('Action: about'),
+               label = 'About...')
+
+       # Create and pack the main part of the window.
+       self.mainPart = Tkinter.Label(toplevel,
+               text = 'This is the\nmain part of\nthe window',
+               background = 'black',
+               foreground = 'white',
+               padx = 30,
+               pady = 30)
+       self.mainPart.pack(fill = 'both', expand = 1)
+
+       # Create and pack the MessageBar.
+       self.messageBar = Pmw.MessageBar(toplevel,
+               entry_width = 40,
+               entry_relief='groove',
+               labelpos = 'w',
+               label_text = 'Status:')
+       self.messageBar.pack(fill = 'x', padx = 10, pady = 10)
+       self.messageBar.message('state',
+            'Balloon/status help not working properly - Tk menubar bug')
+
+       buttonBox = Pmw.ButtonBox(toplevel)
+       buttonBox.pack(fill = 'x')
+       buttonBox.add('Disable\nall', command = menuBar.disableall)
+       buttonBox.add('Enable\nall', command = menuBar.enableall)
+       buttonBox.add('Create\nmenu', command = self.add)
+       buttonBox.add('Delete\nmenu', command = self.delete)
+       buttonBox.add('Create\nitem', command = self.additem)
+       buttonBox.add('Delete\nitem', command = self.deleteitem)
+
+       # Configure the balloon to displays its status messages in the
+       # message bar.
+       self.balloon.configure(statuscommand = self.messageBar.helpmessage)
+
+       self.testMenuList = []
+
+    def _toggleMe(self):
+        print 'Toggle value:', self.toggleVar.get()
+
+    def add(self):
+       if len(self.testMenuList) == 0:
+           num = 0
+       else:
+           num = self.testMenuList[-1]
+       num = num + 1
+       name = 'Menu%d' % num
+       self.testMenuList.append(num)
+
+       self.menuBar.addmenu(name, 'This is ' + name)
+
+    def delete(self):
+       if len(self.testMenuList) == 0:
+           self.menuBar.bell()
+       else:
+           num = self.testMenuList[0]
+           name = 'Menu%d' % num
+           del self.testMenuList[0]
+           self.menuBar.deletemenu(name)
+
+    def additem(self):
+       if len(self.testMenuList) == 0:
+           self.menuBar.bell()
+       else:
+           num = self.testMenuList[-1]
+           menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName)
+            if menu.index('end') is None:
+                label = 'item X'
+            else:
+                label = menu.entrycget('end', 'label') + 'X'
+            self.menuBar.addmenuitem(menuName, 'command', 'Help for ' + label,
+                    command = PrintOne('Action: ' + menuName + ': ' + label),
+                    label = label)
+            
+    def deleteitem(self):
+       if len(self.testMenuList) == 0:
+           self.menuBar.bell()
+       else:
+           num = self.testMenuList[-1]
+           menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName)
+            if menu.index('end') is None:
+                self.menuBar.bell()
+            else:
+                self.menuBar.deletemenuitems(menuName, 0)
+            
+class PrintOne:
+    def __init__(self, text):
+        self.text = text
+
+    def __call__(self):
+        print self.text
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/MenuBar.py b/Pmw/Pmw_1_2/demos/MenuBar.py
new file mode 100644 (file)
index 0000000..8e22e53
--- /dev/null
@@ -0,0 +1,166 @@
+title = 'Pmw.MenuBar demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the Balloon.
+       self.balloon = Pmw.Balloon(parent)
+
+       # Create and pack the MenuBar.
+       menuBar = Pmw.MenuBar(parent,
+               hull_relief = 'raised',
+               hull_borderwidth = 1,
+               balloon = self.balloon)
+       menuBar.pack(fill = 'x')
+       self.menuBar = menuBar
+
+       # Add some buttons to the MenuBar.
+       menuBar.addmenu('File', 'Close this window or exit')
+       menuBar.addmenuitem('File', 'command', 'Close this window',
+               command = PrintOne('Action: close'),
+               label = 'Close')
+       menuBar.addmenuitem('File', 'separator')
+       menuBar.addmenuitem('File', 'command', 'Exit the application',
+               command = PrintOne('Action: exit'),
+               label = 'Exit')
+
+       menuBar.addmenu('Edit', 'Cut, copy or paste')
+       menuBar.addmenuitem('Edit', 'command', 'Delete the current selection',
+               command = PrintOne('Action: delete'),
+               label = 'Delete')
+
+       menuBar.addmenu('Options', 'Set user preferences')
+       menuBar.addmenuitem('Options', 'command', 'Set general preferences',
+               command = PrintOne('Action: general options'),
+               label = 'General...')
+
+       # Create a checkbutton menu item.
+        self.toggleVar = Tkinter.IntVar()
+       # Initialise the checkbutton to 1:
+        self.toggleVar.set(1)
+        menuBar.addmenuitem('Options', 'checkbutton', 'Toggle me on/off',
+                label = 'Toggle',
+                command = self._toggleMe,
+                variable = self.toggleVar)
+        self._toggleMe()
+
+       menuBar.addcascademenu('Options', 'Size',
+               'Set some other preferences', traverseSpec = 'z', tearoff = 1)
+       for size in ('tiny', 'small', 'average', 'big', 'huge'):
+           menuBar.addmenuitem('Size', 'command', 'Set size to ' + size,
+                    command = PrintOne('Action: size ' + size),
+                   label = size)
+
+       menuBar.addmenu('Help', 'User manuals', side = 'right')
+       menuBar.addmenuitem('Help', 'command', 'About this application',
+               command = PrintOne('Action: about'),
+               label = 'About...')
+
+       # Create and pack the main part of the window.
+       self.mainPart = Tkinter.Label(parent,
+               text = 'This is the\nmain part of\nthe window',
+               background = 'black',
+               foreground = 'white',
+               padx = 30,
+               pady = 30)
+       self.mainPart.pack(fill = 'both', expand = 1)
+
+       # Create and pack the MessageBar.
+       self.messageBar = Pmw.MessageBar(parent,
+               entry_width = 40,
+               entry_relief='groove',
+               labelpos = 'w',
+               label_text = 'Status:')
+       self.messageBar.pack(fill = 'x', padx = 10, pady = 10)
+       self.messageBar.message('state', 'OK')
+
+       buttonBox = Pmw.ButtonBox(parent)
+       buttonBox.pack(fill = 'x')
+       buttonBox.add('Disable\nall', command = menuBar.disableall)
+       buttonBox.add('Enable\nall', command = menuBar.enableall)
+       buttonBox.add('Create\nmenu', command = self.add)
+       buttonBox.add('Delete\nmenu', command = self.delete)
+       buttonBox.add('Create\nitem', command = self.additem)
+       buttonBox.add('Delete\nitem', command = self.deleteitem)
+
+       # Configure the balloon to displays its status messages in the
+       # message bar.
+       self.balloon.configure(statuscommand = self.messageBar.helpmessage)
+
+       self.testMenuList = []
+
+    def _toggleMe(self):
+        print 'Toggle value:', self.toggleVar.get()
+
+    def add(self):
+       if len(self.testMenuList) == 0:
+           num = 0
+       else:
+           num = self.testMenuList[-1]
+       num = num + 1
+       name = 'Menu%d' % num
+       self.testMenuList.append(num)
+
+       self.menuBar.addmenu(name, 'This is ' + name)
+
+    def delete(self):
+       if len(self.testMenuList) == 0:
+           self.menuBar.bell()
+       else:
+           num = self.testMenuList[0]
+           name = 'Menu%d' % num
+           del self.testMenuList[0]
+           self.menuBar.deletemenu(name)
+
+    def additem(self):
+       if len(self.testMenuList) == 0:
+           self.menuBar.bell()
+       else:
+           num = self.testMenuList[-1]
+           menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName + '-menu')
+            if menu.index('end') is None:
+                label = 'item X'
+            else:
+                label = menu.entrycget('end', 'label') + 'X'
+            self.menuBar.addmenuitem(menuName, 'command', 'Help for ' + label,
+                    command = PrintOne('Action: ' + menuName + ': ' + label),
+                    label = label)
+            
+    def deleteitem(self):
+       if len(self.testMenuList) == 0:
+           self.menuBar.bell()
+       else:
+           num = self.testMenuList[-1]
+           menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName + '-menu')
+            if menu.index('end') is None:
+                self.menuBar.bell()
+            else:
+                self.menuBar.deletemenuitems(menuName, 0)
+            
+class PrintOne:
+    def __init__(self, text):
+        self.text = text
+
+    def __call__(self):
+        print self.text
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/MessageBar.py b/Pmw/Pmw_1_2/demos/MessageBar.py
new file mode 100644 (file)
index 0000000..8cec7dd
--- /dev/null
@@ -0,0 +1,85 @@
+title = 'Pmw.MessageBar demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the MessageBar.
+       self._messagebar = Pmw.MessageBar(parent,
+               entry_width = 40,
+               entry_relief='groove',
+               labelpos = 'w',
+               label_text = 'Status:')
+       self._messagebar.pack(side = 'bottom', fill = 'x',
+               expand = 1, padx = 10, pady = 10)
+
+       # Create and pack the ScrolledListBox to change the MessageBar.
+       self.box = Pmw.ScrolledListBox(parent,
+               listbox_selectmode='single',
+               items=('state', 'help', 'userevent', 'systemevent',
+                       'usererror', 'systemerror', 'busy',),
+               label_text='Message type',
+               labelpos='n',
+               selectioncommand=self.selectionCommand)
+       self.box.pack(fill = 'both', expand = 'yes', padx = 10, pady = 10)
+
+       self._index = 0
+       self._stateCounter = 0
+
+    def selectionCommand(self):
+       sels = self.box.getcurselection()
+       if len(sels) > 0:
+           self._index = self._index + 1
+           messagetype = sels[0]
+           if messagetype == 'state':
+               self._stateCounter = (self._stateCounter + 1) % 3
+               text = stateMessages[self._stateCounter]
+               if text != '':
+                   text = text + ' (' + messagetype + ')'
+               self._messagebar.message('state', text)
+           else:
+               text = messages[messagetype]
+               text = text + ' (' + messagetype + ')'
+               self._messagebar.message(messagetype, text)
+               if messagetype == 'busy':
+                   Pmw.showbusycursor()
+                   self.box.after(2000)
+                   Pmw.hidebusycursor()
+                   self._messagebar.resetmessages('busy')
+                   text = 'All files successfully removed'
+                   text = text + ' (userevent)'
+                   self._messagebar.message('userevent', text)
+
+
+messages = {
+    'help': 'Save current file',
+    'userevent': 'Saving file "foo"',
+    'busy': 'Busy deleting all files from file system ...',
+    'systemevent': 'File "foo" saved',
+    'usererror': 'Invalid file name "foo/bar"',
+    'systemerror': 'Failed to save file: file system full',
+}
+
+stateMessages = {
+    0: '',
+    1: 'Database is down',
+    2: 'Waiting for reply from database',
+}
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/MessageDialog.py b/Pmw/Pmw_1_2/demos/MessageDialog.py
new file mode 100644 (file)
index 0000000..09c8c98
--- /dev/null
@@ -0,0 +1,102 @@
+title = 'Pmw.MessageDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       self.parent = parent
+
+       # Create dialog 1.
+       self.dialog1 = Pmw.MessageDialog(parent,
+           title = 'Simple message dialog',
+           defaultbutton = 0,
+           message_text = 'A simple message dialog\nwith no callback.')
+       self.dialog1.iconname('Simple message dialog')
+       self.dialog1.withdraw()
+
+       # Create dialog 2.
+       self.dialog2 = Pmw.MessageDialog(parent,
+           title = 'Bell ringing dialog',
+           message_text = 'This message dialog\nwill ring the bell ' +
+               'when\nyou click on the buttons.',
+           iconpos = 'w',
+           icon_bitmap = 'error',
+           command = self.execute2,
+           buttons = ('One', 'Two', 'Three', 'Close'))
+       self.dialog2.iconname('Bell ringing dialog')
+       self.dialog2.withdraw()
+
+       # Create dialog 3.
+       self.dialog3 = Pmw.MessageDialog(parent,
+           title = 'Vertical button dialog',
+           message_text = 'This message dialog\nhas the buttons on the\n' +
+               'right hand side.',
+           buttonboxpos = 'e',
+           iconpos = 'n',
+           icon_bitmap = 'warning',
+           buttons = ('Goodbye', 'Au revoir', 'Sayonara', 'Close'),
+           defaultbutton = 'Close')
+       self.dialog3.iconname('Vertical button dialog')
+       self.dialog3.withdraw()
+
+       # Create some buttons to launch the dialogs.
+       w = Tkinter.Button(parent, text = 'Simple dialog',
+               command = lambda self = self:
+                       self.dialog1.activate(geometry = 'first+100+100'))
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text = 'Bell ringing dialog',
+               command = self.dialog2.activate)
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text = 'Vertical buttons',
+               command = self.dialog3.activate)
+       w.pack(padx = 8, pady = 8)
+
+       w = Tkinter.Button(parent, text = 'On the fly dialog',
+               command = self._createOnTheFly)
+       w.pack(padx = 8, pady = 8)
+
+    def execute2(self, result):
+       print 'You clicked on', result
+       if result is None:
+           self.dialog2.deactivate(result)
+       elif result == 'Close':
+           self.dialog2.deactivate(result)
+       else:
+           for count in range({'One': 1, 'Two': 2, 'Three': 3}[result]):
+               if count != 0:
+                   self.dialog2.after(200)
+               self.dialog2.bell()
+
+    def _createOnTheFly(self):
+       dialog = Pmw.MessageDialog(self.parent,
+           title = 'On the fly dialog',
+           defaultbutton = 0,
+           buttons = ('OK', 'Apply', 'Cancel', 'Help'),
+           message_text = 'This dialog was created when you clicked ' +
+               'on the button.')
+       dialog.iconname('Simple message dialog')
+       result = dialog.activate()
+
+       print 'You selected', result
+
+
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/MessageInfo.py b/Pmw/Pmw_1_2/demos/MessageInfo.py
new file mode 100644 (file)
index 0000000..1c2fac4
--- /dev/null
@@ -0,0 +1,108 @@
+title = 'Pmw toplevel megawidget demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class MessageInfo(Pmw.MegaToplevel):
+
+    # Demo Pmw toplevel megawidget.
+
+    def __init__(self, parent=None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = ()
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaToplevel.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       self._dismiss = self.createcomponent('dismiss',
+               (), None,
+               Tkinter.Button, (interior,),
+               text = 'Dismiss',
+               command = self.goodbye)
+       self._dismiss.pack(side = 'bottom', pady = 4)
+
+       self._separator = self.createcomponent('separator',
+               (), None,
+               Tkinter.Frame, (interior,),
+               height = 2,
+               borderwidth = 1,
+               relief = 'sunken')
+       self._separator.pack(side = 'bottom', fill = 'x', pady = 4)
+
+       self._icon = self.createcomponent('icon',
+               (), None,
+               Tkinter.Label, (interior,))
+       self._icon.pack(side = 'left', padx = 8, pady = 8)
+
+       self._infoFrame = self.createcomponent('infoframe',
+               (), None,
+               Tkinter.Frame, (interior,))
+       self._infoFrame.pack(
+               side = 'left',
+               fill = 'both',
+               expand = 1,
+               padx = 4,
+               pady = 4)
+
+       self._message = self.createcomponent('message',
+               (), None,
+               Tkinter.Label, (interior,))
+       self._message.pack(expand = 1, fill = 'both', padx = 10, pady = 10)
+
+       self.bind('<Return>', self.goodbye)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def goodbye(self, event = None):
+       self.destroy()
+
+class Demo:
+    def __init__(self, parent):
+       # Create button to launch the megawidget.
+       self.button = Tkinter.Button(parent,
+               command = self.showMessageInfo,
+               text = 'Show toplevel megawidget')
+       self.button.pack(padx = 8, pady = 8)
+
+       self.count = 0
+       self.parent = parent
+
+    def showMessageInfo(self):
+       bitmaps = ('warning', 'hourglass', 'error', 'info',
+               'gray25', 'gray50', 'question', 'questhead')
+       bitmap = bitmaps[self.count % len(bitmaps)]
+
+       message = 'This is a demonstration of\na megawidget.\n' + \
+               'It contains a configurable\nmessage area and bitmap.\n' + \
+               'This instance is displaying\nthe "' + bitmap + '" bitmap.'
+
+       # Make the toplevel window a child of this window, so that it
+       # is destroyed when the demo is destroyed.
+       MessageInfo(self.parent, message_text = message, icon_bitmap = bitmap)
+
+       self.count = self.count + 1
+       if self.count == 1:
+           self.button.configure(text = 'Show another\ntoplevel megawidget')
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/MultiLineLabel.py b/Pmw/Pmw_1_2/demos/MultiLineLabel.py
new file mode 100644 (file)
index 0000000..b08b4c1
--- /dev/null
@@ -0,0 +1,73 @@
+title = 'Multi-line label demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+        frame = Tkinter.Frame(parent, background = '#eeeeee')
+        frame.pack(fill = 'both', expand = 1, padx = 5, pady = 5)
+
+        stickys = ('n', 's', 'e', 'w', 'ns', 'ew', 'ne', 'nw', 'se', 'sw',
+                'nsw', 'nse', 'new', 'sew', 'nsew',)
+
+        widgets = []
+        row = 0
+        column = 0
+
+        # Choose one megawidget class to demonstrate:
+        cls = Pmw.EntryField
+        # cls = Pmw.Counter
+        # cls = Pmw.ComboBox
+        # cls = Pmw.LabeledWidget
+        # cls = Pmw.MessageBar
+
+        for sticky in stickys:
+            dict = {}
+            dict['sticky'] = sticky
+            dict['labelpos'] = 'w'
+            dict['label_text'] = '1\n' + sticky + ':\n3'
+            if cls == Pmw.EntryField:
+                dict['value'] = sticky
+                dict['entry_width'] = 6
+            if cls == Pmw.Counter or cls == Pmw.ComboBox:
+                dict['entryfield_value'] = sticky
+                dict['entry_width'] = 6
+            widget = apply(cls, (frame,), dict)
+            if cls == Pmw.LabeledWidget:
+                f = Tkinter.Button(widget.interior(), text = sticky)
+                f.pack(fill = 'both', expand = 1)
+            if cls == Pmw.MessageBar:
+               widget.message('state', sticky)
+           widget.grid(column=column, row=row, sticky='ew', padx = 10, pady = 5)
+           frame.grid_columnconfigure(column, weight=1)
+           frame.grid_rowconfigure(row, weight=1)
+
+            widgets.append(widget)
+
+            if row < 4:
+                row = row + 1
+            else:
+                row = 0
+                column = column + 1
+
+        Pmw.alignlabels(widgets, sticky = 'e')
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/NestedDialogs.py b/Pmw/Pmw_1_2/demos/NestedDialogs.py
new file mode 100644 (file)
index 0000000..e8199a3
--- /dev/null
@@ -0,0 +1,71 @@
+title = 'Modal dialog nesting demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show first dialog',
+               command = self.showFirstDialog)
+       w.pack(padx = 8, pady = 8)
+
+        self.timerId = None
+
+       self.dialog1 = Pmw.MessageDialog(parent,
+               message_text = 'This is the first modal dialog.\n' +
+                       'You can see how dialogs nest by\n' +
+                       'clicking on the "Next" button.',
+               title = 'Dialog 1',
+               buttons = ('Next', 'Cancel'),
+               defaultbutton = 'Next',
+               command = self.next_dialog)
+       self.dialog1.withdraw()
+
+       self.dialog2 = Pmw.Dialog(self.dialog1.interior(),
+               title = 'Dialog 2',
+               buttons = ('Cancel',),
+               deactivatecommand = self.cancelTimer,
+               defaultbutton = 'Cancel')
+       self.dialog2.withdraw()
+       w = Tkinter.Label(self.dialog2.interior(),
+           text = 'This is the second modal dialog.\n' +
+               'It will automatically disappear shortly')
+       w.pack(padx = 10, pady = 10)
+
+    def showFirstDialog(self):
+       self.dialog1.activate()
+
+    def cancelTimer(self):
+        if self.timerId is not None:
+            self.dialog2.after_cancel(self.timerId)
+            self.timerId = None
+
+    def deactivateSecond(self):
+        self.timerId = None
+       self.dialog2.deactivate()
+
+    def next_dialog(self, result):
+       if result != 'Next':
+           self.dialog1.deactivate()
+           return
+
+       self.timerId = self.dialog2.after(3000, self.deactivateSecond)
+       self.dialog2.activate()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/NoteBook.py b/Pmw/Pmw_1_2/demos/NoteBook.py
new file mode 100644 (file)
index 0000000..20815a5
--- /dev/null
@@ -0,0 +1,52 @@
+title = 'Pmw.NoteBook demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the NoteBook.
+        notebook = Pmw.NoteBook(parent)
+        notebook.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+
+        # Add the "Appearance" page to the notebook.
+        page = notebook.add('Appearance')
+        notebook.tab('Appearance').focus_set()
+
+        # Create the "Toolbar" contents of the page.
+        group = Pmw.Group(page, tag_text = 'Toolbar')
+        group.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+        b1 = Tkinter.Checkbutton(group.interior(), text = 'Show toolbar')
+        b1.grid(row = 0, column = 0)
+        b2 = Tkinter.Checkbutton(group.interior(), text = 'Toolbar tips')
+        b2.grid(row = 0, column = 1)
+
+        # Create the "Startup" contents of the page.
+        group = Pmw.Group(page, tag_text = 'Startup')
+        group.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+        home = Pmw.EntryField(group.interior(), labelpos = 'w',
+            label_text = 'Home page location:')
+        home.pack(fill = 'x', padx = 20, pady = 10)
+
+        # Add two more empty pages.
+        page = notebook.add('Helpers')
+        page = notebook.add('Images')
+
+        notebook.setnaturalsize()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    widget = Demo(root)
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack()
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/NoteBook_2.py b/Pmw/Pmw_1_2/demos/NoteBook_2.py
new file mode 100644 (file)
index 0000000..f42037a
--- /dev/null
@@ -0,0 +1,224 @@
+title = 'Pmw.NoteBook demonstration (more complex)'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent, withTabs = 1):
+
+        # Repeat random number sequence for each run.
+        self.rand = 12345
+
+        # Default demo is to display a tabbed notebook.
+        self.withTabs = withTabs
+
+        # Create a frame to put everything in
+        self.mainframe = Tkinter.Frame(parent)
+        self.mainframe.pack(fill = 'both', expand = 1)
+
+        # Find current default colors
+        button = Tkinter.Button()
+        defaultbg = button.cget('background')
+        defaultfg = button.cget('foreground')
+        button.destroy()
+
+        # Create the list of colors to cycle through
+       self.colorList = []
+        self.colorList.append((defaultbg, defaultfg))
+        self.colorIndex = 0
+       for color in Pmw.Color.spectrum(6, 1.5, 1.0, 1.0, 1):
+            bg = Pmw.Color.changebrightness(self.mainframe, color, 0.85)
+            self.colorList.append((bg, 'black'))
+            bg = Pmw.Color.changebrightness(self.mainframe, color, 0.55)
+            self.colorList.append((bg, 'white'))
+
+        # Set the color to the current default
+        Pmw.Color.changecolor(self.mainframe, defaultbg, foreground = defaultfg)
+        defaultPalette = Pmw.Color.getdefaultpalette(self.mainframe)
+        Pmw.Color.setscheme(self.mainframe, defaultbg, foreground = defaultfg)
+
+        # Create the notebook, but don't pack it yet.
+        if self.withTabs:
+            tabpos = 'n'
+        else:
+            tabpos = None
+        self.notebook = Pmw.NoteBook(self.mainframe,
+                tabpos = tabpos,
+                createcommand = PrintOne('Create'),
+                lowercommand = PrintOne('Lower'),
+                raisecommand = PrintOne('Raise'),
+                hull_width = 300,
+                hull_height = 200,
+                )
+
+        # Create a buttonbox to configure the notebook and pack it first.
+        buttonbox = Pmw.ButtonBox(self.mainframe)
+        buttonbox.pack(side = 'bottom', fill = 'x')
+
+        # Add some buttons to the buttonbox to configure the notebook.
+        buttonbox.add('Insert\npage', command = self.insertpage)
+        buttonbox.add('Delete\npage', command = self.deletepage)
+        buttonbox.add('Add\nbutton', command = self.addbutton)
+        buttonbox.add('Change\ncolor', command = self.changecolor)
+        buttonbox.add('Natural\nsize', command =
+                self.notebook.setnaturalsize)
+
+        if not self.withTabs:
+            # Create the selection widget to select the page in the notebook.
+            self.optionmenu = Pmw.OptionMenu(self.mainframe,
+                    menubutton_width = 10,
+                    command = self.notebook.selectpage
+            )
+            self.optionmenu.pack(side = 'left', padx = 10)
+
+        # Pack the notebook last so that the buttonbox does not disappear
+        # when the window is made smaller.
+        self.notebook.pack(fill = 'both', expand = 1, padx = 5, pady = 5)
+
+        # Populate some pages of the notebook.
+        page = self.notebook.add('tmp')
+        self.notebook.delete('tmp')
+        page = self.notebook.add('Appearance')
+        if self.withTabs:
+            self.notebook.tab('Appearance').focus_set()
+        button = Tkinter.Button(page,
+            text = 'Welcome\nto\nthe\nAppearance\npage')
+        button.pack(expand = 1)
+        page = self.notebook.add('Fonts')
+        button = Tkinter.Button(page,
+            text = 'This is a very very very very wide Fonts page')
+        button.pack(expand = 1)
+        page = self.notebook.insert('Applications', before = 'Fonts')
+        button = Tkinter.Button(page, text = 'This is the Applications page')
+        button.pack(expand = 1)
+
+        # Initialise the first page and the initial colour.
+        if not self.withTabs:
+            self.optionmenu.setitems(self.notebook.pagenames())
+        apply(Pmw.Color.setscheme, (self.mainframe,), defaultPalette)
+        self.pageCounter = 0
+
+    def insertpage(self):
+        # Create a page at a random position
+
+        defaultPalette = Pmw.Color.getdefaultpalette(self.mainframe)
+        bg, fg = self.colorList[self.colorIndex]
+        Pmw.Color.setscheme(self.mainframe, bg, foreground = fg)
+
+        self.pageCounter = self.pageCounter + 1
+        before = self.randomchoice(self.notebook.pagenames() + [Pmw.END])
+        pageName = 'page%d' % self.pageCounter
+        if self.pageCounter % 5 == 0:
+            tab_text = pageName + '\nline two'
+        else:
+            tab_text = pageName
+        classes = (None, Tkinter.Button, Tkinter.Label, Tkinter.Checkbutton)
+        cls = self.randomchoice((None,) + classes)
+        if cls is None:
+            print 'Adding', pageName, 'as a frame with a button'
+            if self.withTabs:
+                page = self.notebook.insert(pageName, before, tab_text = tab_text)
+            else:
+                page = self.notebook.insert(pageName, before)
+            button = Tkinter.Button(page,
+                    text = 'This is button %d' % self.pageCounter)
+            button.pack(expand = 1)
+        else:
+            print 'Adding', pageName, 'using', cls
+            if self.withTabs:
+                page = self.notebook.insert(pageName, before,
+                        tab_text = tab_text,
+                        page_pyclass = cls,
+                        page_text = 'This is a page using\na %s' % str(cls)
+                        )
+            else:
+                page = self.notebook.insert(pageName, before,
+                        page_pyclass = cls,
+                        page_text = 'This is a page using\na %s' % str(cls)
+                        )
+        if not self.withTabs:
+            self.optionmenu.setitems(
+                self.notebook.pagenames(), self.notebook.getcurselection())
+
+        apply(Pmw.Color.setscheme, (self.mainframe,), defaultPalette)
+
+    def addbutton(self):
+        # Add a button to a random page.
+
+        defaultPalette = Pmw.Color.getdefaultpalette(self.mainframe)
+        bg, fg = self.colorList[self.colorIndex]
+        Pmw.Color.setscheme(self.mainframe, bg, foreground = fg)
+
+        framePages = []
+        for pageName in self.notebook.pagenames():
+            page = self.notebook.page(pageName)
+            if page.__class__ == Tkinter.Frame:
+                framePages.append(pageName)
+
+        if len(framePages) == 0:
+            self.notebook.bell()
+            return
+
+        pageName = self.randomchoice(framePages)
+        print 'Adding extra button to', pageName
+        page = self.notebook.page(pageName)
+        button = Tkinter.Button(page, text = 'This is an extra button')
+        button.pack(expand = 1)
+
+        apply(Pmw.Color.setscheme, (self.mainframe,), defaultPalette)
+
+    def deletepage(self):
+        # Delete a random page
+
+        pageNames = self.notebook.pagenames()
+        if len(pageNames) == 0:
+            self.notebook.bell()
+            return
+
+        pageName = self.randomchoice(pageNames)
+        print 'Deleting', pageName
+        self.notebook.delete(pageName)
+        if not self.withTabs:
+            self.optionmenu.setitems(
+                self.notebook.pagenames(), self.notebook.getcurselection())
+
+    def changecolor(self):
+        self.colorIndex = self.colorIndex + 1
+        if self.colorIndex == len(self.colorList):
+            self.colorIndex = 0
+
+        bg, fg = self.colorList[self.colorIndex]
+        print 'Changing color to', bg
+        Pmw.Color.changecolor(self.mainframe, bg, foreground = fg)
+        self.notebook.recolorborders()
+
+    # Simple random number generator.
+    def randomchoice(self, selection):
+        num = len(selection)
+        self.rand = (self.rand * 125) % 2796203
+        index = self.rand % num
+        return selection[index]
+
+class PrintOne:
+    def __init__(self, text):
+        self.text = text
+
+    def __call__(self, text):
+        print self.text, text
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    widget = Demo(root)
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack()
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/NoteBook_3.py b/Pmw/Pmw_1_2/demos/NoteBook_3.py
new file mode 100644 (file)
index 0000000..8106c5a
--- /dev/null
@@ -0,0 +1,26 @@
+title = 'Pmw.NoteBook demonstration (with no tabs)'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+# Reuse the NoteBook with tabs demo.
+import NoteBook_2
+
+class Demo(NoteBook_2.Demo):
+    def __init__(self, parent):
+        NoteBook_2.Demo.__init__(self, parent, withTabs = 0)
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    widget = Demo(root)
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack()
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/OptionMenu.py b/Pmw/Pmw_1_2/demos/OptionMenu.py
new file mode 100644 (file)
index 0000000..11d7a88
--- /dev/null
@@ -0,0 +1,66 @@
+title = 'Pmw.OptionMenu demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the OptionMenu megawidgets.
+       # The first one has a textvariable.
+       self.var = Tkinter.StringVar()
+       self.var.set('steamed')
+       self.method_menu = Pmw.OptionMenu(parent,
+               labelpos = 'w',
+               label_text = 'Choose method:',
+               menubutton_textvariable = self.var,
+               items = ['baked', 'steamed', 'stir fried', 'boiled', 'raw'],
+               menubutton_width = 10,
+       )
+       self.method_menu.pack(anchor = 'w', padx = 10, pady = 10)
+
+       self.vege_menu = Pmw.OptionMenu (parent,
+               labelpos = 'w',
+               label_text = 'Choose vegetable:',
+               items = ('broccoli', 'peas', 'carrots', 'pumpkin'),
+               menubutton_width = 10,
+               command = self._printOrder,
+       )
+       self.vege_menu.pack(anchor = 'w', padx = 10, pady = 10)
+
+       self.direction_menu = Pmw.OptionMenu (parent,
+               labelpos = 'w',
+               label_text = 'Menu direction:',
+               items = ('flush', 'above', 'below', 'left', 'right'),
+               menubutton_width = 10,
+               command = self._changeDirection,
+       )
+       self.direction_menu.pack(anchor = 'w', padx = 10, pady = 10)
+
+       menus = (self.method_menu, self.vege_menu, self.direction_menu)
+       Pmw.alignlabels(menus)
+
+    def _printOrder(self, vege):
+       # Can use 'self.var.get()' instead of 'getcurselection()'.
+       print 'You have chosen %s %s.' % \
+            (self.method_menu.getcurselection(), vege)
+
+    def _changeDirection(self, direction):
+       for menu in (self.method_menu, self.vege_menu, self.direction_menu):
+           menu.configure(menubutton_direction = direction)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/PanedWidget.py b/Pmw/Pmw_1_2/demos/PanedWidget.py
new file mode 100644 (file)
index 0000000..e8bdb22
--- /dev/null
@@ -0,0 +1,103 @@
+title = 'Pmw.PanedWidget demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+       # Create a main PanedWidget with a few panes.
+       self.pw = Pmw.PanedWidget(parent,
+                orient='vertical',
+                hull_borderwidth = 1,
+                hull_relief = 'sunken',
+                hull_width=300,
+                hull_height=400)
+       for self.numPanes in range(4):
+           if self.numPanes == 1:
+               name = 'Fixed size'
+               pane = self.pw.add(name, min = .1, max = .1)
+           else:
+               name = 'Pane ' + str(self.numPanes)
+               pane = self.pw.add(name, min = .1, size = .25)
+           label = Tkinter.Label(pane, text = name)
+           label.pack(side = 'left', expand = 1)
+           button = Tkinter.Button(pane, text = 'Delete',
+                    command = lambda s=self, n=name: s.deletePane(n))
+           button.pack(side = 'left', expand = 1)
+            # TODO: add buttons to invoke self.moveOneUp and self.moveOneUp.
+
+       self.pw.pack(expand = 1, fill='both')
+
+        buttonBox = Pmw.ButtonBox(parent)
+        buttonBox.pack(fill = 'x')
+        buttonBox.add('Add pane', command = self.addPane)   
+        buttonBox.add('Move pane', command = self.move)   
+        self.moveSrc = 0
+        self.moveNewPos = 1
+        self.moveBack = 0
+
+    def move(self):
+        numPanes = len(self.pw.panes())
+        if numPanes == 0:
+            print 'No panes to move!'
+            return
+
+        if self.moveSrc >= numPanes:
+            self.moveSrc = numPanes - 1
+        if self.moveNewPos >= numPanes:
+            self.moveNewPos = numPanes - 1
+        print 'Moving pane', self.moveSrc, 'to new position', self.moveNewPos
+        self.pw.move(self.moveSrc, self.moveNewPos)
+
+        self.moveSrc, self.moveNewPos = self.moveNewPos, self.moveSrc
+        if self.moveBack:
+            if self.moveNewPos == numPanes - 1:
+                self.moveNewPos = 0
+                if self.moveSrc == numPanes - 1:
+                    self.moveSrc = 0
+                else:
+                    self.moveSrc = self.moveSrc + 1
+            else:
+                self.moveNewPos = self.moveNewPos + 1
+        self.moveBack = not self.moveBack
+
+    def addPane(self):
+        self.numPanes = self.numPanes + 1
+        name = 'Pane ' + str(self.numPanes)
+        print 'Adding', name
+        pane = self.pw.add(name, min = .1, size = .25)
+        label = Tkinter.Label(pane, text = name)
+        label.pack(side = 'left', expand = 1)
+        button = Tkinter.Button(pane, text = 'Delete',
+                command = lambda s=self, n=name: s.deletePane(n))
+        button.pack(side = 'left', expand = 1)
+       self.pw.updatelayout()
+
+    def deletePane(self, name):
+        print 'Deleting', name
+        self.pw.delete(name)
+       self.pw.updatelayout()
+
+    def moveOneUp(self, name):
+        self.pw.move(name, name, -1)
+
+    def moveOneDown(self, name):
+        self.pw.move(name, name, 1)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/PanedWidget_2.py b/Pmw/Pmw_1_2/demos/PanedWidget_2.py
new file mode 100644 (file)
index 0000000..334bced
--- /dev/null
@@ -0,0 +1,65 @@
+title = 'Pmw.PanedWidget demonstration (pane factory)'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       self.paneCount = 0
+
+       # Create a "pane factory".
+       label = Tkinter.Label(parent,
+               pady = 10,
+               text = 'Below is a simple "pane factory".\n' +
+                       'Drag the handle on the left\nto create new panes.')
+       label.pack()
+       self.factory = Pmw.PanedWidget(parent,
+               orient='horizontal',
+               command = self.resize,
+               hull_borderwidth = 1,
+               hull_relief = 'raised',
+               hull_width=300, hull_height=200
+                )
+       self.factory.add('starter', size = 0.0)
+       self.factory.add('main')
+       button = Tkinter.Button(self.factory.pane('main'),
+               text = 'Pane\n0')
+       button.pack(expand = 1)
+       self.factory.pack(expand = 1, fill = 'both')
+
+    def resize(self, list):
+       # Remove any panes less than 2 pixel wide.
+       for i in range(len(list) - 1, 0, -1):
+           if list[i] < 2:
+               self.factory.delete(i)
+
+       # If the user has dragged the left hand handle, create a new pane.
+       if list[0] > 1:
+           self.paneCount = self.paneCount + 1
+
+           # Add a button to the new pane.
+           name = self.factory.panes()[0]
+           text = 'Pane\n' + str(self.paneCount)
+           button = Tkinter.Button(self.factory.pane(name), text = text)
+           button.pack(expand = 1)
+
+           # Create a new starter pane.
+           name = 'Pane ' + str(self.paneCount)
+           self.factory.insert(name, size=0.0)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/PromptDialog.py b/Pmw/Pmw_1_2/demos/PromptDialog.py
new file mode 100644 (file)
index 0000000..40f50f7
--- /dev/null
@@ -0,0 +1,62 @@
+title = 'Pmw.PromptDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+# This may demonstrate a bug in Tk.  Click on Cancel in the confirm
+# dialog and then click on OK in the password dialog.  Under Solaris
+# 2.5 and python 1.5, the Cancel button in the confirm dialog is still
+# displayed active, that is, it has a lighter background.
+
+class Demo:
+    def __init__(self, parent):
+       # Create the dialog to prompt for the password.
+       self.dialog = Pmw.PromptDialog(parent,
+           title = 'Password',
+           label_text = 'Password:',
+           entryfield_labelpos = 'n',
+           entry_show = '*',
+           defaultbutton = 0,
+           buttons = ('OK', 'Cancel'),
+           command = self.execute)
+       self.dialog.withdraw()
+
+       # Create the confirmation dialog.
+       self.confirm = Pmw.MessageDialog(
+           title = 'Are you sure?',
+           message_text = 'Are you really sure?',
+           defaultbutton = 0,
+           buttons = ('OK', 'Cancel'))
+       self.confirm.withdraw()
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show prompt dialog',
+               command = self.dialog.activate)
+       w.pack(padx = 8, pady = 8)
+
+    def execute(self, result):
+       if result is None or result == 'Cancel':
+           print 'Password prompt cancelled'
+           self.dialog.deactivate(result)
+       else:
+           result = self.confirm.activate()
+           if result == 'OK':
+               print 'Password entered ' + self.dialog.get()
+               self.dialog.deactivate()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/RadioSelect.py b/Pmw/Pmw_1_2/demos/RadioSelect.py
new file mode 100644 (file)
index 0000000..fb549b7
--- /dev/null
@@ -0,0 +1,116 @@
+title = 'Pmw.RadioSelect demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack a horizontal RadioSelect widget.
+       horiz = Pmw.RadioSelect(parent,
+               labelpos = 'w',
+               command = self.callback,
+               label_text = 'Horizontal',
+               frame_borderwidth = 2,
+               frame_relief = 'ridge'
+       )
+       horiz.pack(fill = 'x', padx = 10, pady = 10)
+
+       # Add some buttons to the horizontal RadioSelect.
+       for text in ('Fruit', 'Vegetables', 'Cereals', 'Legumes'):
+           horiz.add(text)
+       horiz.invoke('Cereals')
+
+       # Create and pack a multiple selection RadioSelect widget.
+       self.multiple = Pmw.RadioSelect(parent,
+               labelpos = 'w',
+               command = self.multcallback,
+               label_text = 'Multiple\nselection',
+               frame_borderwidth = 2,
+               frame_relief = 'ridge',
+               selectmode = 'multiple',
+       )
+       self.multiple.pack(fill = 'x', padx = 10)
+
+       # Add some buttons to the multiple selection RadioSelect.
+       for text in ('Apricots', 'Eggplant', 'Rice', 'Lentils'):
+           self.multiple.add(text)
+       self.multiple.invoke('Rice')
+
+       # Create and pack a vertical RadioSelect widget, with checkbuttons.
+       self.checkbuttons = Pmw.RadioSelect(parent,
+               buttontype = 'checkbutton',
+               orient = 'vertical',
+               labelpos = 'w',
+               command = self.checkbuttoncallback,
+               label_text = 'Vertical,\nusing\ncheckbuttons',
+               hull_borderwidth = 2,
+               hull_relief = 'ridge',
+       )
+       self.checkbuttons.pack(side = 'left', expand = 1, padx = 10, pady = 10)
+
+       # Add some buttons to the checkbutton RadioSelect.
+       for text in ('Male', 'Female'):
+           self.checkbuttons.add(text)
+       self.checkbuttons.invoke('Male')
+       self.checkbuttons.invoke('Female')
+
+       # Create and pack a RadioSelect widget, with radiobuttons.
+       radiobuttons = Pmw.RadioSelect(parent,
+               buttontype = 'radiobutton',
+               orient = 'vertical',
+               labelpos = 'w',
+               command = self.callback,
+               label_text = 'Vertical,\nusing\nradiobuttons',
+               hull_borderwidth = 2,
+               hull_relief = 'ridge',
+       )
+       radiobuttons.pack(side = 'left', expand = 1, padx = 10, pady = 10)
+
+       # Add some buttons to the radiobutton RadioSelect.
+       for text in ('Male', 'Female', 'Both', 'Neither'):
+           radiobuttons.add(text)
+       radiobuttons.invoke('Both')
+
+    def callback(self, tag):
+       # This is called whenever the user clicks on a button
+       # in a single select RadioSelect widget.
+       print 'Button', tag, 'was pressed.'
+
+    def multcallback(self, tag, state):
+       # This is called whenever the user clicks on a button
+       # in the multiple select RadioSelect widget.
+        if state:
+           action = 'pressed.'
+        else:
+           action = 'released.'
+
+        print 'Button', tag, 'was', action, \
+               'Selection:', self.multiple.getcurselection()
+           
+    def checkbuttoncallback(self, tag, state):
+       # This is called whenever the user clicks on a button
+       # in the checkbutton RadioSelect widget.
+        if state:
+           action = 'pressed.'
+        else:
+           action = 'released.'
+
+        print 'Button', tag, 'was', action, \
+               'Selection:', self.checkbuttons.getcurselection()
+           
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Resources.py b/Pmw/Pmw_1_2/demos/Resources.py
new file mode 100644 (file)
index 0000000..2168b4a
--- /dev/null
@@ -0,0 +1,74 @@
+title = 'Using Tk option database to configure Tk widgets'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+info = """
+  The Tk widgets contained in this
+  simple megawidget have been
+  configured using the Tk option
+  database.
+      *DemoClass*Listbox.cursor is 'heart'
+      *DemoClass*Entry.cursor is 'hand1'
+      *DemoClass*background is 'pink'
+      *DemoClass*highlightBackground is 'green'
+      *DemoClass*foreground is 'blue'
+"""
+
+class DemoClass(Pmw.MegaWidget):
+
+    # Demo Pmw megawidget.
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = ()
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       interior = self.interior()
+       listbox = Tkinter.Listbox(interior, height = 12, width = 40)
+       listbox.pack(fill='both', expand='yes')
+       for line in string.split(info, '\n'):
+           listbox.insert('end', line)
+
+       entry = Tkinter.Entry(interior)
+       entry.pack(fill='y')
+       entry.insert(0, 'Hello, World!')
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+class Demo:
+    def __init__(self, parent):
+
+       # Test Tk option database settings.
+       parent.option_add('*DemoClass*Listbox.cursor', 'heart')
+       parent.option_add('*DemoClass*Entry.cursor', 'hand1')
+       parent.option_add('*DemoClass*background', 'pink')
+       parent.option_add('*DemoClass*highlightBackground', 'green')
+       parent.option_add('*DemoClass*foreground', 'blue')
+
+       # Create and pack the megawidget.
+       demo = DemoClass(parent)
+       demo.pack(fill = 'both', expand = 1)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Resources_Pmw.py b/Pmw/Pmw_1_2/demos/Resources_Pmw.py
new file mode 100644 (file)
index 0000000..a1f2f99
--- /dev/null
@@ -0,0 +1,110 @@
+title = 'Using Tk option database to configure Pmw megawidgets'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       self.parent = parent
+
+       header = Tkinter.Label(parent, text = 'Select some Tk option ' +
+               'database values from\nthe lists, then click ' +
+               '\'Create dialog\' to create\na MessageDialog with ' +
+               'these values as defaults.')
+       header.pack(padx = 10, pady = 10)
+
+       # Create and pack the ComboBoxes to select options.
+       buttons = (
+           "('OK',)",
+           "('Read', 'Write')",
+           "('OK', 'Cancel')",
+           "('OK', 'Apply', 'Cancel', 'Help')",
+       )
+
+        if Tkinter.TkVersion >= 8.4:
+          disabledState = 'readonly'
+        else:
+          disabledState = 'disabled'
+
+       self._buttons = Pmw.ComboBox(parent, label_text = 'buttons:',
+               labelpos = 'w',
+               entry_state = disabledState,
+               scrolledlist_items = buttons)
+       self._buttons.pack(fill = 'x', expand = 1, padx = 8, pady = 8)
+       self._buttons.selectitem(3)
+
+       buttonboxpos = ('n', 's', 'e', 'w',)
+       self._buttonboxpos = Pmw.ComboBox(parent, label_text = 'buttonboxpos:',
+               labelpos = 'w',
+               entry_state = disabledState,
+               scrolledlist_items = buttonboxpos)
+       self._buttonboxpos.pack(fill = 'x', expand = 1, padx = 8, pady = 8)
+       self._buttonboxpos.selectitem(2)
+
+       pad = ('0', '8', '20', '50',)
+       self._pad = Pmw.ComboBox(parent, label_text = 'padx, pady:',
+               labelpos = 'w',
+               entry_state = disabledState,
+               scrolledlist_items = pad)
+       self._pad.pack(fill = 'x', expand = 1, padx = 8, pady = 8)
+       self._pad.selectitem(1)
+
+       Pmw.alignlabels((self._buttons, self._buttonboxpos, self._pad))
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Create dialog',
+               command = self._createDialog)
+       w.pack(padx = 8, pady = 8)
+
+       self.dialog = None
+
+    def _createDialog(self):
+
+       # Set the option database.
+       buttons = self._buttons.get()
+       buttonboxpos = self._buttonboxpos.get()
+       pad = self._pad.get()
+       self.parent.option_add('*MessageDialog.buttons', buttons)
+       self.parent.option_add('*MessageDialog.buttonboxpos', buttonboxpos)
+       self.parent.option_add('*ButtonBox.padx', pad)
+       self.parent.option_add('*ButtonBox.pady', pad)
+
+       # Create the dialog.
+       if self.dialog is not None:
+           self.dialog.destroy()
+
+       text = ('This dialog was created by setting the Tk ' +
+               'option database:\n\n  *MessageDialog.buttons: ' + buttons +
+               '\n  *MessageDialog.buttonboxpos: ' + buttonboxpos +
+               '\n  *ButtonBox.padx: ' + pad +
+               '\n  *ButtonBox.pady: ' + pad)
+       self.dialog = Pmw.MessageDialog(self.parent,
+           defaultbutton = 0,
+           title = 'Pmw option database demonstration',
+           message_justify = 'left',
+           message_text = text)
+       self.dialog.iconname('Test dialog')
+
+       # Return the defaults to normal, otherwise all other demos
+       # will be affected.
+       self.parent.option_add('*MessageDialog.buttons', "('OK',)")
+       self.parent.option_add('*MessageDialog.buttonboxpos', 's')
+       self.parent.option_add('*ButtonBox.padx', 8)
+       self.parent.option_add('*ButtonBox.pady', 8)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root, useTkOptionDb = 1)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ScrolledCanvas.py b/Pmw/Pmw_1_2/demos/ScrolledCanvas.py
new file mode 100644 (file)
index 0000000..28933ec
--- /dev/null
@@ -0,0 +1,124 @@
+title = 'Pmw.ScrolledCanvas demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the ScrolledCanvas.
+       self.sc = Pmw.ScrolledCanvas(parent,
+               borderframe = 1,
+               labelpos = 'n',
+               label_text = 'ScrolledCanvas',
+               usehullsize = 1,
+               hull_width = 400,
+               hull_height = 300,
+       )
+
+       # Create a group widget to contain the scrollmode options.
+       w = Pmw.Group(parent, tag_text='Scroll mode')
+       w.pack(side = 'bottom', padx = 5, pady = 5)
+
+       hmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Horizontal:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.sethscrollmode,
+               menubutton_width = 8,
+       )
+       hmode.pack(side = 'left', padx = 5, pady = 5)
+       hmode.invoke('dynamic')
+
+       vmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Vertical:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.setvscrollmode,
+               menubutton_width = 8,
+       )
+       vmode.pack(side = 'left', padx = 5, pady = 5)
+       vmode.invoke('dynamic')
+
+       buttonBox = Pmw.ButtonBox(parent)
+       buttonBox.pack(side = 'bottom')
+       buttonBox.add('yview', text = 'Show\nyview', command = self.showYView)
+       buttonBox.add('scroll', text = 'Page\ndown', command = self.pageDown)
+       buttonBox.add('center', text = 'Center', command = self.centerPage)
+
+       # Pack this last so that the buttons do not get shrunk when
+       # the window is resized.
+       self.sc.pack(padx = 5, pady = 5, fill = 'both', expand = 1)
+
+       self.sc.component('canvas').bind('<1>', self.addcircle)
+
+        testEntry = Tkinter.Entry(parent)
+       self.sc.create_line(20, 20, 100, 100)
+       self.sc.create_oval(100, 100, 200, 200, fill = 'green')
+       self.sc.create_text(100, 20, anchor = 'nw',
+               text = 'Click in the canvas\nto draw ovals',
+                font = testEntry.cget('font'))
+       button = Tkinter.Button(self.sc.interior(),
+               text = 'Hello,\nWorld!\nThis\nis\na\nbutton.')
+       self.sc.create_window(200, 200,
+                anchor='nw',
+               window = button)
+
+       # Set the scroll region of the canvas to include all the items
+       # just created.
+       self.sc.resizescrollregion()
+
+       self.colours = ('red', 'green', 'blue', 'yellow', 'cyan', 'magenta',
+               'black', 'white')
+       self.oval_count = 0
+        self.rand = 12345
+
+    def sethscrollmode(self, tag):
+       self.sc.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+       self.sc.configure(vscrollmode = tag)
+
+    def addcircle(self, event):
+       x = self.sc.canvasx(event.x)
+       y = self.sc.canvasy(event.y)
+       width = 10 + self.random() % 100
+       height = 10 + self.random() % 100
+       self.sc.create_oval(
+           x - width, y - height, x + width, y + height,
+           fill = self.colours[self.oval_count])
+       self.oval_count = (self.oval_count + 1) % len(self.colours)
+       self.sc.resizescrollregion()
+
+    # Simple random number generator.
+    def random(self):
+        self.rand = (self.rand * 125) % 2796203
+        return self.rand
+
+    def showYView(self):
+        print self.sc.yview()
+
+    def pageDown(self):
+        self.sc.yview('scroll', 1, 'page')
+
+    def centerPage(self):
+        top, bottom = self.sc.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.sc.yview('moveto', middle)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ScrolledField.py b/Pmw/Pmw_1_2/demos/ScrolledField.py
new file mode 100644 (file)
index 0000000..b3a268d
--- /dev/null
@@ -0,0 +1,51 @@
+title = 'Pmw.ScrolledField demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the ScrolledField.
+       self._field = Pmw.ScrolledField(parent, entry_width = 30,
+               entry_relief='groove', labelpos = 'n',
+               label_text = 'Scroll the field using the\nmiddle mouse button')
+       self._field.pack(fill = 'x', expand = 1, padx = 10, pady = 10)
+
+       # Create and pack a button to change the ScrolledField.
+       self._button = Tkinter.Button(parent, text = 'Change field',
+               command = self.execute)
+       self._button.pack(padx = 10, pady = 10)
+
+       self._index = 0
+       self.execute()
+
+    def execute(self):
+       self._field.configure(text = lines[self._index % len(lines)])
+       self._index = self._index + 1
+
+lines = (
+  'Alice was beginning to get very tired of sitting by her sister',
+  'on the bank, and of having nothing to do:  once or twice she had',
+  'peeped into the book her sister was reading, but it had no',
+  'pictures or conversations in it, "and what is the use of a book,"',
+  'thought Alice "without pictures or conversation?"',
+  'Alice\'s Adventures in Wonderland',
+  'Lewis Carroll',
+)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ScrolledFrame.py b/Pmw/Pmw_1_2/demos/ScrolledFrame.py
new file mode 100644 (file)
index 0000000..06880df
--- /dev/null
@@ -0,0 +1,157 @@
+title = 'Pmw.ScrolledFrame demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the ScrolledFrame.
+       self.sf = Pmw.ScrolledFrame(parent,
+               labelpos = 'n', label_text = 'ScrolledFrame',
+               usehullsize = 1,
+               hull_width = 400,
+               hull_height = 220,
+       )
+
+       # Create a group widget to contain the flex options.
+       w = Pmw.Group(parent, tag_text='Flex')
+       w.pack(side = 'bottom', padx = 5, pady = 3)
+
+       hflex = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Horizontal:',
+               items = ['fixed', 'expand', 'shrink', 'elastic'],
+               command = self.sethflex,
+               menubutton_width = 8,
+       )
+       hflex.pack(side = 'left', padx = 5, pady = 3)
+       hflex.invoke('fixed')
+
+       vflex = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Vertical:',
+               items = ['fixed', 'expand', 'shrink', 'elastic'],
+               command = self.setvflex,
+               menubutton_width = 8,
+       )
+       vflex.pack(side = 'left', padx = 5, pady = 3)
+       vflex.invoke('fixed')
+
+       # Create a group widget to contain the scrollmode options.
+       w = Pmw.Group(parent, tag_text='Scroll mode')
+       w.pack(side = 'bottom', padx = 5, pady = 0)
+
+       hmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Horizontal:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.sethscrollmode,
+               menubutton_width = 8,
+       )
+       hmode.pack(side = 'left', padx = 5, pady = 3)
+       hmode.invoke('dynamic')
+
+       vmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Vertical:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.setvscrollmode,
+               menubutton_width = 8,
+       )
+       vmode.pack(side = 'left', padx = 5, pady = 3)
+       vmode.invoke('dynamic')
+
+        self.radio = Pmw.RadioSelect(parent, selectmode = 'multiple',
+            command = self.radioSelected)
+        self.radio.add('center', text = 'Keep centered vertically')
+        self.radio.pack(side = 'bottom')
+
+        buttonBox = Pmw.ButtonBox(parent)
+       buttonBox.pack(side = 'bottom')
+       buttonBox.add('add', text = 'Add a button', command = self.addButton)
+       buttonBox.add('yview', text = 'Show yview', command = self.showYView)
+       buttonBox.add('scroll', text = 'Page down', command = self.pageDown)
+
+       # Pack this last so that the buttons do not get shrunk when
+       # the window is resized.
+       self.sf.pack(padx = 5, pady = 3, fill = 'both', expand = 1)
+
+       self.frame = self.sf.interior()
+
+       self.row = 0
+       self.col = 0
+
+        for count in range(15):
+            self.addButton()
+
+    def sethscrollmode(self, tag):
+       self.sf.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+       self.sf.configure(vscrollmode = tag)
+
+    def sethflex(self, tag):
+       self.sf.configure(horizflex = tag)
+
+    def setvflex(self, tag):
+       self.sf.configure(vertflex = tag)
+
+    def addButton(self):
+       button = Tkinter.Button(self.frame,
+           text = '(%d,%d)' % (self.col, self.row))
+       button.grid(row = self.row, column = self.col, sticky = 'nsew')
+
+       self.frame.grid_rowconfigure(self.row, weight = 1)
+       self.frame.grid_columnconfigure(self.col, weight = 1)
+       if self.sf.cget('horizflex') == 'expand' or \
+                self.sf.cget('vertflex') == 'expand':
+            self.sf.reposition()
+
+        if 'center' in self.radio.getcurselection():
+            self.sf.update_idletasks()
+            self.centerPage()
+
+       if self.col == self.row:
+           self.col = 0
+           self.row = self.row + 1
+       else:
+           self.col = self.col + 1
+
+    def showYView(self):
+        print self.sf.yview()
+
+    def pageDown(self):
+        self.sf.yview('scroll', 1, 'page')
+
+    def radioSelected(self, name, state):
+        if state:
+            self.centerPage()
+
+    def centerPage(self):
+        # Example of how to use the yview() method of Pmw.ScrolledFrame.
+        top, bottom = self.sf.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.sf.yview('moveto', middle)
+
+######################################################################
+# Create demo in root window for testing.
+if __name__ == '__main__': 
+    import os
+    if os.name == 'nt':
+        size = 16
+    else:
+        size = 12
+    root = Tkinter.Tk()
+    Pmw.initialise(root, size = size, fontScheme = 'pmw2')
+    root.title(title)
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop() 
diff --git a/Pmw/Pmw_1_2/demos/ScrolledListBox.py b/Pmw/Pmw_1_2/demos/ScrolledListBox.py
new file mode 100644 (file)
index 0000000..f2f7d9d
--- /dev/null
@@ -0,0 +1,118 @@
+title = 'Pmw.ScrolledListBox demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the ScrolledListBox.
+       self.box = Pmw.ScrolledListBox(parent,
+               items=('Sydney', 'Melbourne', 'Brisbane'),
+               labelpos='nw',
+               label_text='Cities',
+               listbox_height = 6,
+               selectioncommand=self.selectionCommand,
+               dblclickcommand=self.defCmd,
+               usehullsize = 1,
+               hull_width = 200,
+               hull_height = 200,
+       )
+
+       # Create a group widget to contain the scrollmode options.
+       w = Pmw.Group(parent, tag_text='Scroll mode')
+       w.pack(side = 'bottom', padx = 5, pady = 5)
+
+       hmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Horizontal:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.sethscrollmode,
+               menubutton_width = 8,
+       )
+       hmode.pack(side = 'top', padx = 5, pady = 5)
+       hmode.invoke('dynamic')
+
+       vmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Vertical:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.setvscrollmode,
+               menubutton_width = 8,
+       )
+       vmode.pack(side = 'top', padx = 5, pady = 5)
+       vmode.invoke('dynamic')
+
+       buttonBox = Pmw.ButtonBox(parent)
+       buttonBox.pack(side = 'bottom')
+       buttonBox.add('yview', text = 'Show\nyview', command = self.showYView)
+       buttonBox.add('scroll', text = 'Page\ndown', command = self.pageDown)
+       buttonBox.add('center', text = 'Center', command = self.centerPage)
+
+       # Pack this last so that the buttons do not get shrunk when
+       # the window is resized.
+       self.box.pack(fill = 'both', expand = 1, padx = 5, pady = 5)
+
+        # Do this after packing the scrolled list box, so that the
+        # window does not resize as soon as it appears (because
+        # alignlabels has to do an update_idletasks).
+       Pmw.alignlabels((hmode, vmode))
+
+       # Add some more entries to the listbox.
+       items = ('Andamooka', 'Coober Pedy', 'Innamincka', 'Oodnadatta')
+       self.box.setlist(items)
+       self.box.insert(2, 'Wagga Wagga', 'Perth', 'London')
+       self.box.insert('end', 'Darwin', 'Auckland', 'New York')
+       index = list(self.box.get(0, 'end')).index('London')
+       self.box.delete(index)
+       self.box.delete(7, 8)
+       self.box.insert('end', 'Bulli', 'Alice Springs', 'Woy Woy')
+       self.box.insert('end', 'Wallumburrawang', 'Willandra Billabong')
+
+    def sethscrollmode(self, tag):
+       self.box.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+       self.box.configure(vscrollmode = tag)
+
+    def selectionCommand(self):
+       sels = self.box.getcurselection()
+       if len(sels) == 0:
+           print 'No selection'
+       else:
+           print 'Selection:', sels[0]
+
+    def defCmd(self):
+       sels = self.box.getcurselection()
+       if len(sels) == 0:
+           print 'No selection for double click'
+       else:
+           print 'Double click:', sels[0]
+
+    def showYView(self):
+        print self.box.yview()
+
+    def pageDown(self):
+        self.box.yview('scroll', 1, 'page')
+
+    def centerPage(self):
+        top, bottom = self.box.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.box.yview('moveto', middle)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ScrolledText.py b/Pmw/Pmw_1_2/demos/ScrolledText.py
new file mode 100644 (file)
index 0000000..aae02ea
--- /dev/null
@@ -0,0 +1,99 @@
+title = 'Pmw.ScrolledText demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import os
+import math
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+       # Create the ScrolledText with headers.
+        fixedFont = Pmw.logicalfont('Fixed')
+       self.st = Pmw.ScrolledText(parent,
+               # borderframe = 1,
+               labelpos = 'n',
+               label_text='ScrolledText with headers',
+                columnheader = 1,
+                rowheader = 1,
+                rowcolumnheader = 1,
+               usehullsize = 1,
+               hull_width = 400,
+               hull_height = 300,
+               text_wrap='none',
+                text_font = fixedFont,
+                Header_font = fixedFont,
+                Header_foreground = 'blue',
+                rowheader_width = 3,
+                rowcolumnheader_width = 3,
+               text_padx = 4,
+               text_pady = 4,
+               Header_padx = 4,
+               rowheader_pady = 4,
+       )
+
+       self.st.pack(padx = 5, pady = 5, fill = 'both', expand = 1)
+
+        funcs = 'atan cos cosh exp log log10 sin sinh sqrt tan tanh'
+        funcs = string.split(funcs)
+
+        # Create the header for the row headers
+        self.st.component('rowcolumnheader').insert('end', 'x')
+
+        # Create the column headers
+        headerLine = ''
+        for column in range(len(funcs)):
+            headerLine = headerLine + ('%-7s   ' % (funcs[column],))
+        headerLine = headerLine[:-3]
+        self.st.component('columnheader').insert('0.0', headerLine)
+
+        self.st.tag_configure('yellow', background = 'yellow')
+
+        # Create the data rows and the row headers
+        numRows = 50
+        tagList = []
+        for row in range(1, numRows):
+            dataLine = ''
+            x = row / 5.0
+            for column in range(len(funcs)):
+                value = eval('math.' + funcs[column] + '(' + str(x) + ')')
+                data = str(value)[:7]
+                if value < 0:
+                    tag1 = '%d.%d' % (row, len(dataLine))
+                    tag2 = '%d.%d' % (row, len(dataLine) + len(data))
+                    tagList.append(tag1)
+                    tagList.append(tag2)
+                data = '%-7s' % (data,)
+                dataLine = dataLine + data + '   '
+            dataLine = dataLine[:-3]
+            header = '%.1f' % (x,)
+            if row < numRows - 1:
+                dataLine = dataLine + '\n'
+                header = header + '\n'
+            self.st.insert('end', dataLine)
+            self.st.component('rowheader').insert('end', header)
+        apply(self.st.tag_add, ('yellow',) + tuple(tagList))
+
+        # Prevent users' modifying text and headers
+        self.st.configure(
+            text_state = 'disabled',
+            Header_state = 'disabled',
+        )
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ScrolledText_2.py b/Pmw/Pmw_1_2/demos/ScrolledText_2.py
new file mode 100644 (file)
index 0000000..cffb733
--- /dev/null
@@ -0,0 +1,99 @@
+title = 'Pmw.ScrolledText demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import os
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the ScrolledText.
+       self.st = Pmw.ScrolledText(parent,
+               borderframe = 1,
+               labelpos = 'n',
+               label_text='ScrolledText.py',
+               usehullsize = 1,
+               hull_width = 400,
+               hull_height = 300,
+               text_padx = 10,
+               text_pady = 10,
+               text_wrap='none'
+       )
+
+       # Create a group widget to contain the scrollmode options.
+       w = Pmw.Group(parent, tag_text='Scroll mode')
+       w.pack(side = 'bottom', padx = 5, pady = 5)
+
+       hmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Horizontal:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.sethscrollmode,
+               menubutton_width = 8,
+       )
+       hmode.pack(side = 'left', padx = 5, pady = 5)
+       hmode.invoke('dynamic')
+
+       vmode = Pmw.OptionMenu(w.interior(),
+               labelpos = 'w',
+               label_text = 'Vertical:',
+               items = ['none', 'static', 'dynamic'],
+               command = self.setvscrollmode,
+               menubutton_width = 8,
+       )
+       vmode.pack(side = 'left', padx = 5, pady = 5)
+       vmode.invoke('dynamic')
+
+       buttonBox = Pmw.ButtonBox(parent)
+       buttonBox.pack(side = 'bottom')
+       buttonBox.add('yview', text = 'Show\nyview', command = self.showYView)
+       buttonBox.add('scroll', text = 'Page\ndown', command = self.pageDown)
+       buttonBox.add('center', text = 'Center', command = self.centerPage)
+
+       # Pack this last so that the buttons do not get shrunk when
+       # the window is resized.
+       self.st.pack(padx = 5, pady = 5, fill = 'both', expand = 1)
+
+       # Read this file into the text widget.
+       head, tail = os.path.split(sys.argv[0])
+       self.st.importfile(os.path.join(head,'ScrolledText.py'))
+
+       self.st.insert('end', '\nThis demonstrates how to\n' +
+           'add a window to a text widget:  ')
+       counter = Pmw.Counter(self.st.component('text'),
+           entryfield_value = 9999)
+       self.st.window_create('end', window = counter)
+
+    def sethscrollmode(self, tag):
+       self.st.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+       self.st.configure(vscrollmode = tag)
+
+    def showYView(self):
+        print self.st.yview()
+
+    def pageDown(self):
+        self.st.yview('scroll', 1, 'page')
+
+    def centerPage(self):
+        top, bottom = self.st.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.st.yview('moveto', middle)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/SelectionDialog.py b/Pmw/Pmw_1_2/demos/SelectionDialog.py
new file mode 100644 (file)
index 0000000..12fea94
--- /dev/null
@@ -0,0 +1,47 @@
+title = 'Pmw.SelectionDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the dialog.
+       self.dialog = Pmw.SelectionDialog(parent,
+           title = 'My SelectionDialog',
+           buttons = ('OK', 'Cancel'),
+           defaultbutton = 'OK',
+           scrolledlist_labelpos = 'n',
+           label_text = 'What do you think of Pmw?',
+           scrolledlist_items = ('Cool man', 'Cool', 'Good', 'Bad', 'Gross'),
+           command = self.execute)
+       self.dialog.withdraw()
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show selection dialog',
+               command = self.dialog.activate)
+       w.pack(padx = 8, pady = 8)
+
+    def execute(self, result):
+       sels = self.dialog.getcurselection()
+       if len(sels) == 0:
+           print 'You clicked on', result, '(no selection)'
+       else:
+           print 'You clicked on', result, sels[0]
+       self.dialog.deactivate(result)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/ShowBusy.py b/Pmw/Pmw_1_2/demos/ShowBusy.py
new file mode 100644 (file)
index 0000000..831b7a5
--- /dev/null
@@ -0,0 +1,48 @@
+title = 'Blt busy cursor demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       self.parent = parent
+
+       if Pmw.Blt.havebltbusy(parent):
+           text = 'Click here to show the\nbusy cursor for one second.'
+       else:
+           text = 'Sorry\n' \
+               'Either the BLT package has not\n' \
+               'been installed on this system or\n' \
+               'it does not support the busy command.\n' \
+               'Clicking on this button will pause\n' \
+               'for one second but will not display\n' \
+               'the busy cursor.'
+
+       button = Tkinter.Button(parent,
+               text = text,
+               command = Pmw.busycallback(self.sleep, parent.update))
+       button.pack(padx = 10, pady = 10)
+
+       entry = Tkinter.Entry(parent, width = 30)
+       entry.insert('end', 'Try to enter some text while busy.')
+       entry.pack(padx = 10, pady = 10)
+
+    def sleep(self):
+        self.parent.after(1000)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/SpecialCounter.py b/Pmw/Pmw_1_2/demos/SpecialCounter.py
new file mode 100644 (file)
index 0000000..a76645a
--- /dev/null
@@ -0,0 +1,68 @@
+title = 'Subclassing Pmw.Counter'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import time
+import types
+import Tkinter
+import Pmw
+
+class LabeledDateCounter(Pmw.Counter):
+
+    def __init__(self, parent=None , **kw):
+
+       # Need to use long ints here because on the Macintosh the maximum size
+       # of an integer is smaller than the value returned by time.time().
+       now = (long(time.time()) / 300) * 300
+        text = time.strftime('%y/%m/%d', time.localtime(now))
+
+        kw['datatype'] = 'date'
+        kw['entryfield_validate'] = 'date'
+        kw['entryfield_value'] = text
+        kw['labelpos'] = 'w'
+
+       apply(Pmw.Counter.__init__, (self, parent), kw)
+
+class LabeledRealCounter(Pmw.Counter):
+
+    def __init__(self, parent=None , **kw):
+
+        # Define the validate option dictionary.
+        validate = {'validator' : 'real', 'min' : 0.0, 'max' : 100.0}
+
+        kw['datatype'] = 'real'
+        kw['entryfield_validate'] = validate
+        kw['entryfield_value'] = 50.0
+        kw['labelpos'] = 'w'
+
+       apply(Pmw.Counter.__init__, (self, parent), kw)
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack some LabeledDateCounters and LabeledRealCounter.
+       self._date1 = LabeledDateCounter(parent, label_text = 'Date:')
+       self._date2 = LabeledDateCounter(parent, label_text = 'Another Date:')
+       self._real1 = LabeledRealCounter(parent, label_text = 'Real:')
+       self._real2 = LabeledRealCounter(parent, label_text = 'Another Real:')
+
+       counters = (self._date1, self._date2, self._real1, self._real2)
+
+       for counter in counters:
+           counter.pack(fill='x', expand=1, padx=10, pady=5)
+       Pmw.alignlabels(counters)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/SpecialEntry.py b/Pmw/Pmw_1_2/demos/SpecialEntry.py
new file mode 100644 (file)
index 0000000..270780b
--- /dev/null
@@ -0,0 +1,170 @@
+title = 'Subclassing Pmw.EntryField'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import time
+import types
+import Tkinter
+import Pmw
+
+class SpecialEntry(Pmw.EntryField):
+
+    def __init__(self, parent=None , **kw):
+
+        kw['extravalidators'] = _myValidators
+       apply(Pmw.EntryField.__init__, (self, parent), kw)
+       self._converter = None
+
+    def setentry(self, text):
+       # Override Pmw.EntryField.setentry to pass string through
+       # the appropriate converter.
+
+       val = self['validate']
+       if type(val) == types.DictionaryType:
+           val = val['validator']
+       if _converters.has_key(val):
+           text = _converters[val](text, output = 0)
+       Pmw.EntryField.setentry(self, text)
+
+    def getentry(self):
+       text = self.get()
+       val = self['validate']
+       if type(val) == types.DictionaryType:
+           val = val['validator']
+       if _converters.has_key(val):
+           return _converters[val](text, output = 1)
+       else:
+           return text
+
+def _date(text):
+    return Pmw.datevalidator(text, 'dmy', '.')
+
+def _real(text):
+    return Pmw.realvalidator(text, ',')
+
+def _dateconv(text, output = 0):
+    # On output, convert from dd.mm.yy to mm-dd-yy.  On input, convert
+    # mm-dd-yy to dd.mm.yy and also from +NN+ or -NN- to date NN days
+    # before or after today.
+
+    if len(text) == 0:
+       return ''
+    if output:
+       try:
+           d = string.split(text, '.')
+           return d[1] + '-' + d[0] + '-' + d[2]
+       except:
+           return text
+    else:
+       if text[-1] == '+' or text[-1] == '-':
+           text = text[:-1]
+       if text[0] == '+' or text[0] == '-':
+            secondsAhead = string.atoi(text) * 3600 * 24
+           return time.strftime('%d.%m.%Y',
+                    time.localtime(time.time() + secondsAhead))
+       try:
+           d = string.split(text,'-')
+           return d[1] + '.' + d[0] + '.' + d[2]
+       except:
+           return text
+
+def _realconv(text, output = 0):
+    # Convert between DD.DD and DD,DD.
+
+    if output:
+       index = string.find(text, ',')
+       if index >= 0:
+           return text[:index] + '.' + text[index + 1:]
+       else:
+           return text
+    else:
+       index = string.find(text, '.')
+       if index >= 0:
+           return text[:index] + ',' + text[index + 1:]
+       else:
+           return text
+
+
+_converters = {
+    'real' : _realconv,
+    'float8' : _realconv,
+    'date' : _dateconv
+}
+
+_myValidators = {
+    'date' : (_date, lambda s: Pmw.datestringtojdn(s, 'dmy', '.')),
+    'real' : (_real, lambda s: string.atof(_realconv(s, 1))),
+    'int4' : ('numeric', 'numeric'),
+    'oid' : ('int4', 'int4'),
+    'float8' : ('real', 'real'),
+    'varchar' : ('alphanumeric', 'alphanumeric'),
+    'text' : ('alphanumeric', 'alphanumeric'),
+}
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the SpecialEntry megawidgets.
+       self._any = SpecialEntry(parent,
+               labelpos = 'w',
+               label_text = 'Text (max 10 chars):',
+               validate = {'validator' : 'text', 'max' : 10},
+               command = self.execute)
+       self._any.setentry('abc')
+       self._int = SpecialEntry(parent,
+               labelpos = 'w',
+               label_text = 'Int4:',
+               validate = 'int4')
+       self._int.setentry(1)
+       self._real = SpecialEntry(parent,
+               labelpos = 'w',
+               label_text = 'Real (max 2,5e+9):',
+               validate = {'validator' : 'real', 'max' : +2.5e+9},
+               )
+       self._real.setentry('+2.5e+6')
+       self._date = SpecialEntry(parent,
+               labelpos = 'w',
+               label_text = 'Date (dd.mm.yy):',
+               validate = 'date',
+               modifiedcommand = self.changed
+               )
+        # Set entry to one week from now, using special intput format.
+       self._date.setentry('+7+')
+
+       entries = (self._any, self._int, self._real, self._date)
+
+       for entry in entries:
+           entry.pack(fill='x', expand=1, padx=10, pady=5)
+       Pmw.alignlabels(entries)
+
+       self._any.component('entry').focus_set()
+
+    def changed(self):
+       print 'Text changed, converted value is', self._date.getentry()
+
+    def execute(self):
+       print 'Return pressed, value is', self._any.get()
+
+    # This implements a custom validation routine.  It simply checks
+    # if the string is of odd length.
+    def custom_validate(self, text):
+       print 'text:', text
+       if len(text) % 2 == 0:
+         return -1
+       else:
+         return 1
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/Spectrum.py b/Pmw/Pmw_1_2/demos/Spectrum.py
new file mode 100644 (file)
index 0000000..cfef979
--- /dev/null
@@ -0,0 +1,166 @@
+title = 'Color spectrum demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       parent = Tkinter.Frame(parent)
+       parent.pack(padx=10, pady=10, fill='both', expand=1)
+       self.width = 350
+       self.height = 250
+       self.canvas = Tkinter.Canvas(parent,
+               width = self.width, height = self.height)
+       self.canvas.grid(row = 0, column = 0, columnspan = 2, sticky = 'news')
+
+       self.numColors = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Number of colors:',
+               entry_width = 5,
+               validate = 'numeric',
+               command = Pmw.busycallback(self.execute))
+       self.numColors.grid(row = 1, column = 0, sticky = 'ew')
+
+       self.correction = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Correction:',
+               validate = 'real',
+               entry_width = 5,
+               command = Pmw.busycallback(self.execute))
+       self.correction.grid(row = 1, column = 1, sticky = 'ew')
+
+       self.saturation = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Saturation:',
+               validate = 'real',
+               entry_width = 5,
+               command = Pmw.busycallback(self.execute))
+       self.saturation.grid(row = 2, column = 0, sticky = 'ew')
+
+       self.intensity = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Intensity:',
+               validate = 'real',
+               entry_width = 5,
+               command = Pmw.busycallback(self.execute))
+       self.intensity.grid(row = 2, column = 1, sticky = 'ew')
+
+       self.extraOrange = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Emphasize orange (0 or 1):',
+               validate = {'validator' : 'numeric', 'min' : 0, 'max' : 1},
+               entry_width = 5,
+               command = Pmw.busycallback(self.execute))
+       self.extraOrange.grid(row = 3, column = 0, sticky = 'ew')
+
+       self.text = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Text:',
+               entry_width = 20,
+               command = Pmw.busycallback(self.execute))
+       self.text.grid(row = 4, column = 0, sticky = 'ew')
+
+       self.brightness = Pmw.EntryField(parent,
+               labelpos = 'w',
+               label_text = 'Brightness:',
+               validate = 'real',
+               entry_width = 5,
+               command = Pmw.busycallback(self.execute))
+       self.brightness.grid(row = 3, column = 1, sticky = 'ew')
+
+       self.radiobuttons = Pmw.RadioSelect(parent,
+               command = Pmw.busycallback(self.radio_cb),
+       )
+        self.radiobuttons.grid(row = 4, column = 1)
+        self.radiobuttons.add('Use saturation\nand intensity')
+        self.radiobuttons.add('Use\nbrightness')
+
+       parent.grid_columnconfigure(0, weight = 1)
+       parent.grid_columnconfigure(1, weight = 1)
+       parent.grid_rowconfigure(0, weight = 1)
+
+       Pmw.alignlabels((self.numColors, self.saturation, self.extraOrange))
+       Pmw.alignlabels((self.correction, self.intensity, self.brightness))
+
+       # Set initial values for all entries.
+       self.numColors.setentry('64')
+       self.correction.setentry('1.0')
+       self.saturation.setentry('1.0')
+       self.intensity.setentry('1.0')
+       self.extraOrange.setentry('1')
+       self.brightness.setentry('0.7')
+       self.text.setentry('This is a test')
+       self.radiobuttons.invoke('Use saturation\nand intensity')
+
+       self.execute()
+
+    def radio_cb(self, value):
+       self.execute()
+
+    def execute(self):
+       try:
+           numColors = string.atoi(self.numColors.get())
+           correction = string.atof(self.correction.get())
+           saturation = string.atof(self.saturation.get())
+           intensity = string.atof(self.intensity.get())
+           extraOrange = string.atof(self.extraOrange.get())
+           brightness = string.atof(self.brightness.get())
+       except ValueError:
+           self.numColors.bell()
+           return
+
+       if numColors <= 0:
+           self.numColors.bell()
+           return
+
+        self.canvas.delete('all')
+
+       colorList = Pmw.Color.spectrum(
+               numColors, correction, saturation, intensity, extraOrange)
+       extent = 360.0 / numColors
+
+        useBrightness = \
+                (self.radiobuttons.getcurselection() == 'Use\nbrightness')
+
+       if numColors == 1:
+           # Special case circle, since create_arc does not work when
+           # extent is 360.
+           background = colorList[0]
+            if useBrightness:
+                background = Pmw.Color.changebrightness(
+                        self.canvas, background, brightness)
+           self.canvas.create_oval(10, 10, self.width - 10, self.height - 10,
+               fill = background, outline = background)
+
+       for index in range(numColors):
+           start = index * extent - extent / 2
+           background = colorList[index]
+            if useBrightness:
+                background = Pmw.Color.changebrightness(
+                        self.canvas, background, brightness)
+           self.canvas.create_arc(10, 10, self.width - 10, self.height - 10,
+               start = start, extent = extent,
+               fill = background, outline = background)
+
+        text = self.text.get()
+        self.canvas.create_text(self.width / 2, self.height / 3, text = text)
+        self.canvas.create_text(self.width / 2, self.height / 2, text = text)
+        self.canvas.create_text(self.width / 2, 2 * self.height / 3, text = text)
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/SpeedTest.py b/Pmw/Pmw_1_2/demos/SpeedTest.py
new file mode 100644 (file)
index 0000000..589486b
--- /dev/null
@@ -0,0 +1,60 @@
+title = 'Test of the speed of creating Pmw megawidgets'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import time
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       self.parent = parent
+
+       message = 'This is a test of the time\n' + \
+               'it takes to create 20 Pmw\nEntryField megawidgets.\n' + \
+               'Click on the button to create them.'
+       w = Tkinter.Label(parent, text = message)
+       w.pack(padx = 8, pady = 8)
+
+       # Create button to run speed test.
+       w = Tkinter.Button(parent,
+               text = 'Create 20 EntryFields',
+               command = self.createEntries)
+       w.pack(padx = 8, pady = 8)
+
+    def createEntries(self):
+      entryTop = Tkinter.Toplevel(self.parent)
+
+      startClock = time.clock()
+      fields = []
+      for num in range(20):
+       field = Pmw.EntryField(entryTop,
+               labelpos = 'w',
+               label_text='*' + ('*' * num),
+               hull_background = 'lightsteelblue',
+               label_background = 'lightsteelblue',
+               hull_highlightbackground = 'lightsteelblue',
+               label_highlightbackground = 'lightsteelblue',
+               entry_highlightbackground = 'lightsteelblue',
+               entry_background = 'aliceblue')
+       field.pack()
+       fields.append(field)
+
+      Pmw.alignlabels(fields)
+      print 'Time to create 20 EntryFields:', \
+             time.clock() - startClock, 'seconds'
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/SubClassing.py b/Pmw/Pmw_1_2/demos/SubClassing.py
new file mode 100644 (file)
index 0000000..f538b59
--- /dev/null
@@ -0,0 +1,128 @@
+title = 'More examples of subclassing'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class ExtraMethods(Pmw.EntryField):
+
+    # How to subclass a Pmw megawidget when you only want to add or
+    # override methods.
+
+    def doubletext(self):
+       self.setvalue(self.getvalue() + ' ' + self.getvalue())
+
+class OverrideInit(Pmw.EntryField):
+
+    # How to subclass a Pmw megawidget when you want to define
+    # a new __init__ method.
+
+    def __init__(self, textToAdd, parent = None, **kw):
+        self._textToAdd = textToAdd
+       apply(Pmw.EntryField.__init__, (self, parent), kw)
+
+    def addtext(self):
+       self.setvalue(self.getvalue() + ' ' + self._textToAdd)
+
+class DefaultOptions(Pmw.EntryField):
+
+    # How to subclass a Pmw megawidget when you only want to set
+    # existing options to new default values.
+
+    def __init__(self, parent = None, **kw):
+        kw['label_foreground'] = 'blue'
+        kw['entry_background'] = 'white'
+       apply(Pmw.EntryField.__init__, (self, parent), kw)
+
+class NewOptions(Pmw.EntryField):
+
+    # How to subclass a Pmw megawidget when you want to add new options.
+
+    def __init__(self, parent=None , **kw):
+
+       # Define the megawidget options.
+       optiondefs = (
+            ('backgrounds',              None,     self._backgrounds),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.EntryField.__init__(self, parent)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _backgrounds(self):
+       background = self['backgrounds']
+        Pmw.Color.changecolor(self.component('hull'), background)
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the megawidgets.
+       self._extraMethod = ExtraMethods(parent,
+               labelpos = 'w',
+               label_text = 'Sub class with extra method:',
+                value = 'Hello'
+        )
+       self._overrideInit = OverrideInit('Again', parent,
+               labelpos = 'w',
+               label_text = 'Sub class with new __init__ method:',
+                value = 'Hello'
+        )
+       self._defaultOptions = DefaultOptions(parent,
+               labelpos = 'w',
+               label_text = 'Sub class with new default options:',
+                value = 'Hello'
+        )
+
+       self._newOptions = NewOptions(parent,
+               labelpos = 'w',
+               label_text = 'Sub class with new option:',
+                value = 'Hello',
+                backgrounds = 'white',
+        )
+
+       entries = (self._extraMethod, self._overrideInit,
+                self._defaultOptions, self._newOptions)
+
+       for entry in entries:
+           entry.pack(fill='x', expand=1, padx=10, pady=5)
+       Pmw.alignlabels(entries)
+
+        bb = Pmw.ButtonBox(parent)
+        bb.add('Double text', command = self._doubleText)
+        bb.pack()
+        bb.add('Add text', command = self._addText)
+        bb.pack()
+        bb.add('White', command = self._changeColorWhite)
+        bb.pack()
+        bb.add('Green', command = self._changeColorGreen)
+        bb.pack()
+
+    def _doubleText(self):
+        self._extraMethod.doubletext()
+
+    def _addText(self):
+        self._overrideInit.addtext()
+
+    def _changeColorWhite(self):
+        self._newOptions.configure(backgrounds = 'white')
+
+    def _changeColorGreen(self):
+        self._newOptions.configure(backgrounds = 'green')
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/TextDialog.py b/Pmw/Pmw_1_2/demos/TextDialog.py
new file mode 100644 (file)
index 0000000..adec821
--- /dev/null
@@ -0,0 +1,75 @@
+title = 'Pmw.TextDialog demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create the dialog.
+       dialog = Pmw.TextDialog(parent, scrolledtext_labelpos = 'n',
+               title = 'My TextDialog',
+               defaultbutton = 0,
+               label_text = 'Lawyer jokes')
+       dialog.withdraw()
+       dialog.insert('end', jokes)
+       dialog.configure(text_state = 'disabled')
+
+       # Create button to launch the dialog.
+       w = Tkinter.Button(parent, text = 'Show text dialog',
+               command = dialog.activate)
+       w.pack(padx = 8, pady = 8)
+
+jokes = """
+Q: What do you call 5000 dead lawyers at the bottom of the ocean?
+A: A good start!
+
+Q: How can you tell when a lawyer is lying?
+A: His lips are moving.
+
+Q: Why won't sharks attack lawyers?
+A: Professional courtesy.
+
+Q: What do have when a lawyer is buried up to his neck in sand?
+A: Not enough sand.
+
+Q: How do you get a lawyer out of a tree?
+A: Cut the rope.
+
+Q: What is the definition of a shame (as in "that's a shame")?
+A: When a bus load of lawyers goes off a cliff.
+
+Q: What is the definition of a "crying shame"?
+A: There was an empty seat.
+
+Q: What do you get when you cross the Godfather with a lawyer?
+A: An offer you can't understand.
+
+Q. What do lawyers use as contraceptives?
+A. Their personalities.
+
+Q. What's brown and black and looks good on a lawyer?
+A. A doberman.
+
+Q. Why are lawyers buried 12 feet underground?
+A. Deep down their good.
+
+Q. What's the difference between a catfish and a lawyer?
+A. One's a slimy scum-sucking scavenger, the other is just a fish.
+
+"""
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/TextDisplay.py b/Pmw/Pmw_1_2/demos/TextDisplay.py
new file mode 100644 (file)
index 0000000..0eadf52
--- /dev/null
@@ -0,0 +1,78 @@
+title = 'Demonstration of how to create a megawidget'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class TextDisplay(Pmw.MegaWidget):
+
+    # Demo Pmw megawidget.
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = ()
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       self._text = self.createcomponent('text',
+               (), None,
+               Tkinter.Text, (interior,), state = 'disabled')
+       self._text.pack(side='left', fill='both', expand='yes')
+
+       self._scrollbar = self.createcomponent('scrollbar',
+               (), None,
+               Tkinter.Scrollbar, (interior,), command = self._text.yview)
+       self._scrollbar.pack(side='right', fill='y')
+       self._text.configure(yscrollcommand = self._scrollbar.set)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def display(self, info):
+       self._text.configure(state = 'normal')
+       self._text.delete('1.0', 'end')
+       self._text.insert('1.0', info)
+       self._text.configure(state = 'disabled')
+
+    def append(self, info):
+       self._text.configure(state = 'normal')
+       self._text.insert('end', info)
+       self._text.configure(state = 'disabled')
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack the megawidget.
+       text = TextDisplay(parent,
+               text_background = 'aliceblue',
+               text_width = 40,
+               text_height = 10,
+               text_wrap = 'none',
+       )
+       text.pack(fill = 'both', expand = 1)
+       text.display('This is an example of a simple Pmw megawidget.\n\n' +
+               'Public attributes of the Tkinter module:\n\n')
+       for name in dir(Tkinter):
+           if name[0] != '_':
+               text.append('    ' + name + '\n')
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/TimeCounter.py b/Pmw/Pmw_1_2/demos/TimeCounter.py
new file mode 100644 (file)
index 0000000..7be1eb3
--- /dev/null
@@ -0,0 +1,40 @@
+title = 'Pmw.TimeCounter demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import string
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       self._time = Pmw.TimeCounter(parent,
+               labelpos = 'w',
+               label_text = 'HH:MM:SS',
+               min = '00:00:00',
+               max = '23:59:59')
+       self._time.pack(padx=10, pady=5)
+
+       button = Tkinter.Button(parent, text = 'Show', command = self.show)
+       button.pack()
+
+    def show(self):
+       stringVal = self._time.getstring()
+       intVal =  self._time.getint()
+       print stringVal + '  (' + str(intVal) + ')'
+
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/demos/WidgetDestroy.py b/Pmw/Pmw_1_2/demos/WidgetDestroy.py
new file mode 100644 (file)
index 0000000..a62fa28
--- /dev/null
@@ -0,0 +1,36 @@
+title = 'Demonstration of Pmw megawidget destruction'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+       # Create and pack an EntryField.
+       self.entryfield = Pmw.EntryField(parent,
+           command = self.execute,
+            value = 'Press <Return> to destroy me',
+           entry_width = 30)
+       self.entryfield.pack(fill='x', expand=1, padx=10, pady=5)
+
+       self.entryfield.component('entry').focus_set()
+
+    def execute(self):
+       print 'Return pressed, destroying EntryField.'
+       self.entryfield.destroy()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/doc/AboutDialog.gif b/Pmw/Pmw_1_2/doc/AboutDialog.gif
new file mode 100644 (file)
index 0000000..2d60dc5
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/AboutDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/AboutDialog.html b/Pmw/Pmw_1_2/doc/AboutDialog.html
new file mode 100644 (file)
index 0000000..8f487d5
--- /dev/null
@@ -0,0 +1,286 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.AboutDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.AboutDialog</h1>
+    
+<center><IMG SRC=AboutDialog.gif ALT="" WIDTH=378 HEIGHT=284></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.AboutDialog() - 
+    window to display version and contact information
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MessageDialog.html">Pmw.MessageDialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    An about dialog is a dialog window which displays information
+    about the application, such as name, version, copyright and
+    contact details.</p>
+
+<p>    The text of the message is constructed from the application name
+    (given by the <strong>applicationname</strong> option) followed by the values
+    supplied in the most recent calls to <code>Pmw.aboutversion()</code>,
+    <code>Pmw.aboutcopyright()</code> and <code>Pmw.aboutcontact()</code> functions.</p>
+
+<p>    The icon of the message defaults to <strong>'info'</strong>, but may be changed
+    using the <strong>icon_bitmap</strong> component option.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.applicationname></a>
+<dl><dt> <strong>applicationname
+</strong></dt><dd>
+Initialisation option. The name of application, to be dispayed in the dialog body and in
+    the window title if the <strong>title</strong> option is not given. The default is <strong>''</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the text message and icon. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the text message and icon. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('Close',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.iconmargin></a>
+<dl><dt> <strong>iconmargin
+</strong></dt><dd>
+Initialisation option. The padding between the text message and icon. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.iconpos></a>
+<dl><dt> <strong>iconpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the text message to place the icon. 
+    Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'w'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.icon></a>
+<dl><dt> <strong>icon
+</strong></dt><dd>
+If the <strong>iconpos</strong> option is not <strong>None</strong>, this component is created
+    to contain the icon label for the dialog.  To display a bitmap as
+    an icon, set the <strong>icon_bitmap</strong> component option to any of the
+    forms acceptable to Tk, such as <strong>'warning'</strong> or <strong>'error'</strong>. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.message></a>
+<dl><dt> <strong>message
+</strong></dt><dd>
+The label to contain the text message for the dialog.  To set
+    the text, use the <strong>message_text</strong> component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+This megawidget has no methods of its own.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MessageDialog.html#methods">Pmw.MessageDialog</a></strong>.
+<p></p>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create dialog.
+        Pmw.aboutversion('9.9')
+        Pmw.aboutcopyright('Copyright My Company 1999\nAll rights reserved')
+        Pmw.aboutcontact(
+            'For information about this application contact:\n' +
+            '  My Help Desk\n' +
+            '  Phone: +61 2 9876 5432\n' +
+            '  email: help@my.company.com.au'
+        )
+        self.about = Pmw.AboutDialog(parent, applicationname = 'My Application')
+        self.about.withdraw()
+
+        # Create button to launch the dialog.
+        w = Tkinter.Button(parent, text = 'Show about dialog',
+                command = self.execute)
+        w.pack(padx = 8, pady = 8)
+
+    def execute(self):
+        self.about.show()
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/Balloon.gif b/Pmw/Pmw_1_2/doc/Balloon.gif
new file mode 100644 (file)
index 0000000..e8bc9b8
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/Balloon.gif differ
diff --git a/Pmw/Pmw_1_2/doc/Balloon.html b/Pmw/Pmw_1_2/doc/Balloon.html
new file mode 100644 (file)
index 0000000..012f9c3
--- /dev/null
@@ -0,0 +1,429 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.Balloon reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.Balloon</h1>
+    
+<center><IMG SRC=Balloon.gif ALT="" WIDTH=428 HEIGHT=189></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.Balloon() - 
+    display "tool tips" for a number of widgets
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaToplevel.html">Pmw.MegaToplevel</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A balloon megawidget can be used to give short help messages to
+    the user when they place the mouse over a button or other widget
+    for a short time.  It can also be used to display help messages
+    for canvas or text items.</p>
+
+<p>    One balloon megawidget can be used to display help for many
+    widgets or items.  For each widget or item that requires balloon
+    help, the <code>bind()</code> or <code>bindtag()</code> method is used to specify the
+    help text that should be displayed.</p>
+
+<p>    The help message is displayed in a popup balloon window when the
+    mouse remains over the widget or item for a short time.  The popup
+    balloon is withdrawn when the mouse leaves the widget or item, or
+    any mouse buttons are pressed.</p>
+
+<p>    The position of the popup balloon is configurable and may appear
+    either relative to the widget or item or relative to the position
+    of the mouse.</p>
+
+<p>    The popup balloon is displayed without any window manager
+    decorations.</p>
+
+<p>    The megawidget can cooperate with a <a href="MessageBar.html">Pmw.MessageBar</a> to display a
+    single-line help message as well as the balloon help.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.initwait></a>
+<dl><dt> <strong>initwait
+</strong></dt><dd>
+The number of milliseconds delay between when the mouse enters a
+    widget or item and when the popup balloon window should be
+    displayed. The default is <strong>500</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.relmouse></a>
+<dl><dt> <strong>relmouse
+</strong></dt><dd>
+This may be one of <strong>'both'</strong>, <strong>'x'</strong>, <strong>'y'</strong> or <strong>'none'</strong> and
+    indicates that the top left corner of the popup balloon window
+    should be placed relative to the current position of the mouse
+    rather than relative to the bottom left corner of the widget or
+    item (the default).  The positioning may be set for the horizontal
+    (x) and vertical (y) axes independently. The default is <strong>'none'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.state></a>
+<dl><dt> <strong>state
+</strong></dt><dd>
+This may be one of <strong>'both'</strong>, <strong>'balloon'</strong>, <strong>'status'</strong> or <strong>'none'</strong>
+    and indicates whether the help message should be displayed in the
+    popup balloon window, in an associated messagebar (via the
+    <strong>statuscommand</strong> option), or both. The default is <strong>'both'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.statuscommand></a>
+<dl><dt> <strong>statuscommand
+</strong></dt><dd>
+This specifies a function to call when the mouse enters a widget
+    or item bound to this balloon megawidget.  To configure a
+    <a href="MessageBar.html">Pmw.MessageBar</a> to display help, set this option to the <code>helpmessage</code>
+    method of the messagebar. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.xoffset></a>
+<dl><dt> <strong>xoffset
+</strong></dt><dd>
+This specifies the horizontal offset of the position of the left
+    side of the popup balloon window relative the point determined by
+    the <strong>relmouse</strong> option. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.yoffset></a>
+<dl><dt> <strong>yoffset
+</strong></dt><dd>
+This specifies the vertical offset of the position of the top of
+    the popup balloon window relative the point determined by the
+    <strong>relmouse</strong> option. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+This component displays the text of the help message in the popup
+    balloon window.  By default it is created with a <strong>'lightyellow'</strong>
+    background, a <strong>'black'</strong> foreground and is <strong>'left'</strong> justified. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaToplevel.html#methods">Pmw.MegaToplevel</a></strong>.
+<p></p>
+<a name=method.bind></a>
+<dl><dt> <strong>bind</strong>(<em>widget</em>, <em>balloonHelp</em>, <em>statusHelp</em> = <strong>None</strong>)</dt><dd>
+Create bindings for <em>widget</em> so that balloon help and/or status
+    help is displayed when the mouse enters the widget.  The balloon
+    help message is given by <em>balloonHelp</em> and the status help message
+    is given by <em>statusHelp</em>.  If <em>balloonHelp</em> is <strong>None</strong>, no balloon
+    is displayed.  If <em>statusHelp</em> is not set, it defaults to
+    <em>balloonHelp</em>.  Any previous bindings for this widget are removed.</p>
+
+
+</dd></dl>
+<a name=method.clearstatus></a>
+<dl><dt> <strong>clearstatus</strong>()</dt><dd>
+Clear the text in the associated messagebar by passing <strong>None</strong> to
+    the <strong>statuscommand</strong> function.</p>
+
+
+</dd></dl>
+<a name=method.showstatus></a>
+<dl><dt> <strong>showstatus</strong>(<em>statusHelp</em>)</dt><dd>
+Set the text in the associated messagebar by passing <em>statusHelp</em>
+    to the <strong>statuscommand</strong> function.</p>
+
+
+</dd></dl>
+<a name=method.tagbind></a>
+<dl><dt> <strong>tagbind</strong>(<em>widget</em>, <em>tagOrItem</em>, <em>balloonHelp</em>, <em>statusHelp</em> = <strong>None</strong>)</dt><dd>
+Create bindings for the tag or item specified by <em>tagOrItem</em> in
+    the text or canvas <em>widget</em> so that balloon help and/or status
+    help is displayed when the mouse enters the tag or item.  The
+    balloon help message is given by <em>balloonHelp</em> and the status help
+    message is given by <em>statusHelp</em>.  If <em>balloonHelp</em> is <strong>None</strong>, no
+    balloon is displayed.  If <em>statusHelp</em> is not set, it defaults to
+    <em>balloonHelp</em>.  Any previous bindings for this tag or item are
+    removed.</p>
+
+
+</dd></dl>
+<a name=method.tagunbind></a>
+<dl><dt> <strong>tagunbind</strong>(<em>widget</em>, <em>tagOrItem</em>)</dt><dd>
+Remove the balloon help bindings from the tag or item specified by
+    <em>tagOrItem</em> in the text or canvas <em>widget</em>.</p>
+<p>    Note that <code>tagunbind()</code> must be called when deleting a canvas
+    item, so that the popup balloon window can be withdrawn if it was
+    triggered by the item.  (Unfortunately this can not be automated
+    as is done for widgets since Tk does not support <code>&lt;Destroy&gt;</code>
+    bindings on canvas items, so there is no way that Pmw.Balloon can
+    be notified of the deletion of an item.)</p>
+
+
+
+</dd></dl>
+<a name=method.unbind></a>
+<dl><dt> <strong>unbind</strong>(<em>widget</em>)</dt><dd>
+Remove the balloon help bindings from <em>widget</em>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the Balloon.
+        self.balloon = Pmw.Balloon(parent)
+
+        # Create some widgets and megawidgets with balloon help.
+        frame = Tkinter.Frame(parent)
+        frame.pack(padx = 10, pady = 5)
+        field = Pmw.EntryField(frame,
+                labelpos = 'nw',
+                label_text = 'Command:')
+        field.setentry('mycommand -name foo')
+        field.pack(side = 'left', padx = 10)
+        self.balloon.bind(field, 'Command to\nstart/stop',
+                'Enter the shell command to control')
+
+        start = Tkinter.Button(frame, text='Start')
+        start.pack(side='left', padx = 10)
+        self.balloon.bind(start, 'Start the command')
+
+        stop = Tkinter.Button(frame, text='Stop')
+        stop.pack(side='left', padx = 10)
+        self.balloon.bind(stop, 'Stop the command')
+
+        self.suicide = Tkinter.Button(frame, text='Kill me soon!',
+            command = self.killButton)
+        self.suicide.pack(side='left', padx = 10)
+        self.balloon.bind(self.suicide, 'Watch this button disappear!')
+
+        scrolledCanvas = Pmw.ScrolledCanvas(parent,
+                canvas_width = 300,
+                canvas_height = 115,
+        )
+        scrolledCanvas.pack()
+        canvas = scrolledCanvas.component('canvas')
+        self.canvas = canvas
+
+        # Create some canvas items and individual help.
+        item = canvas.create_arc(5, 5, 35, 35, fill = 'red', extent = 315)
+        self.balloon.tagbind(canvas, item, 'This is help for\nan arc item')
+        item = canvas.create_bitmap(20, 150, bitmap = 'question')
+        self.balloon.tagbind(canvas, item, 'This is help for\na bitmap')
+        item = canvas.create_line(50, 60, 70, 80, 85, 20, width = 5)
+        self.balloon.tagbind(canvas, item, 'This is help for\na line item')
+        item = canvas.create_text(10, 90, text = 'Canvas items with balloons',
+                anchor = 'nw', font = field.cget('entry_font'))
+        self.balloon.tagbind(canvas, item, 'This is help for\na text item')
+
+        # Create two canvas items which have the same tag and which use
+        # the same help.
+        canvas.create_rectangle(100, 10, 170, 50, fill = 'aliceblue',
+                tags = 'TAG1')
+        self.bluecircle = canvas.create_oval(110, 30, 160, 80, fill = 'blue',
+                tags = 'TAG1')
+        self.balloon.tagbind(canvas, 'TAG1',
+                'This is help for the two blue items' + '\n' * 10 +
+                    'It is very, very big.',
+                'This is help for the two blue items')
+        item = canvas.create_text(180, 10, text = 'Delete',
+                anchor = 'nw', font = field.cget('entry_font'))
+        self.balloon.tagbind(canvas, item,
+                'After 2 seconds,\ndelete the blue circle')
+        canvas.tag_bind(item, '&lt;ButtonPress&gt;', self._canvasButtonpress)
+        scrolledCanvas.resizescrollregion()
+
+        scrolledText = Pmw.ScrolledText(parent,
+                text_width = 32,
+                text_height = 4,
+                text_wrap = 'none',
+        )
+        scrolledText.pack(pady = 5)
+        text = scrolledText.component('text')
+        self.text = text
+
+        text.insert('end',
+                'This is a text widget with ', '',
+                ' balloon', 'TAG1',
+                '\nhelp. Find the ', '',
+                ' text ', 'TAG1',
+                ' tagged with', '',
+                ' help.', 'TAG2',
+                '\n', '',
+                'Remove tag 1.', 'TAG3',
+                '\nAnother line.\nAnd another', '',
+        )
+        text.tag_configure('TAG1', borderwidth = 2, relief = 'sunken')
+        text.tag_configure('TAG3', borderwidth = 2, relief = 'raised')
+
+        self.balloon.tagbind(text, 'TAG1',
+                'There is one secret\nballoon help.\nCan you find it?')
+        self.balloon.tagbind(text, 'TAG2',
+                'Well done!\nYou found it!')
+        self.balloon.tagbind(text, 'TAG3',
+                'After 2 seconds\ndelete the tag')
+        text.tag_bind('TAG3', '&lt;ButtonPress&gt;', self._textButtonpress)
+
+        frame = Tkinter.Frame(parent)
+        frame.pack(padx = 10)
+        self.toggleBalloonVar = Tkinter.IntVar()
+        self.toggleBalloonVar.set(1)
+        toggle = Tkinter.Checkbutton(frame,
+                variable = self.toggleBalloonVar,
+                text = 'Balloon help', command = self.toggle)
+        toggle.pack(side = 'left', padx = 10)
+        self.balloon.bind(toggle, 'Toggle balloon help\non and off')
+
+        self.toggleStatusVar = Tkinter.IntVar()
+        self.toggleStatusVar.set(1)
+        toggle = Tkinter.Checkbutton(frame,
+                variable = self.toggleStatusVar,
+                text = 'Status help', command = self.toggle)
+        toggle.pack(side = 'left', padx = 10)
+        self.balloon.bind(toggle,
+                'Toggle status help on and off, on and off' + '\n' * 10 +
+                    'It is very, very big, too.',
+                'Toggle status help on and off')
+
+        # Create and pack the MessageBar.
+        messageBar = Pmw.MessageBar(parent,
+                entry_width = 40,
+                entry_relief='groove',
+                labelpos = 'w',
+                label_text = 'Status:')
+        messageBar.pack(fill = 'x', expand = 1, padx = 10, pady = 5)
+
+        # Configure the balloon to display its status messages in the
+        # message bar.
+        self.balloon.configure(statuscommand = messageBar.helpmessage)
+
+    def toggle(self):
+        if self.toggleBalloonVar.get():
+            if self.toggleStatusVar.get():
+                self.balloon.configure(state = 'both')
+            else:
+                self.balloon.configure(state = 'balloon')
+        else:
+            if self.toggleStatusVar.get():
+                self.balloon.configure(state = 'status')
+            else:
+                self.balloon.configure(state = 'none')
+
+    def killButton(self):
+        # Test for old bug when destroying widgets 1) while the
+        # balloon was up and 2) during the initwait period.
+        print 'Destroying button in 2 seconds'
+        self.suicide.after(2000, self.suicide.destroy)
+
+    def _canvasButtonpress(self, event):
+        print 'Destroying blue circle in 2 seconds'
+        self.canvas.after(2000, self.deleteBlueCircle)
+
+    def deleteBlueCircle(self):
+        self.balloon.tagunbind(self.canvas, self.bluecircle)
+        self.canvas.delete(self.bluecircle)
+
+    def _textButtonpress(self, event):
+        print 'Deleting the text tag in 2 seconds'
+        self.text.after(2000, self.deleteTextTag)
+
+    def deleteTextTag(self):
+        self.balloon.tagunbind(self.text, 'TAG1')
+        self.text.tag_delete('TAG1')
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 20 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/Blt.html b/Pmw/Pmw_1_2/doc/Blt.html
new file mode 100644 (file)
index 0000000..9986984
--- /dev/null
@@ -0,0 +1,135 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.Blt reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.Blt</h1>
+    
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.Blt - 
+    interface to some BLT widgets and commands</p>
+<p></p>
+
+
+
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This module contains function interfaces to the BLT <code>busy</code> command
+    as well as the classes <strong>Pmw.Blt.Vector</strong>, <strong>Pmw.Blt.Graph</strong>,
+    <strong>Pmw.Blt.Stripchart</strong> and <strong>Pmw.Blt.Tabset</strong>, which are interfaces to
+    the vector, graph, stripchart and tabset commands of version 2.4
+    of the <strong>BLT</strong> extension to Tk.  The interfaces are complete except
+    for <strong>Pmw.Blt.Vector</strong> where several creation options, methods and
+    operations have not been implemented.</p>
+
+<p>    The blt graph and barchart widgets are essentially the same and so
+    only the graph widget has been ported.  The <code>element_create()</code>
+    method is not implememted for <strong>Pmw.Blt.Graph</strong>, so instead:</p>
+<ul><li><p>to create a <em>line</em> element, use the <code>line_create()</code> method and</p>
+
+</li>
+<li><p>to create a <em>bar</em> element, use the <code>bar_create()</code> method.</p>
+
+</li></ul>
+
+<p>    To operate on elements, use the <code>element_*()</code> methods, such as
+    <code>element_bind()</code>, <code>element_activate()</code>, etc.</p>
+
+<p>    <strong>Note:</strong> Full documentation of Pmw.Blt.Graph is available in
+    <a href="http://www.ifi.uio.no/~hpl/Pmw.Blt/doc/">A User's Guide to Pmw.Blt</a>
+    written by Bjørn Ove Thue and Hans Petter Langtangen.
+    You can also download 
+    <a href="http://www.ifi.uio.no/~hpl/Pmw.Blt/Pmw.Blt.doc.tar.gz">the full HTML document</a>
+    of the guide for local viewing.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Functions</h3></dt><dd>
+The following functions are available.<p></p>
+<dl>
+<dt> <strong>Pmw.Blt.busy_forget</strong>(<em>window</em>)</dt><dd>
+
+    Interface to the BLT <code>busy forget</code> command.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Blt.busy_hold</strong>(<em>window</em>, <em>cursor</em> = <strong>None</strong>)</dt><dd>
+
+    Interface to the BLT <code>busy hold</code> command.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Blt.busy_release</strong>(<em>window</em>)</dt><dd>
+
+    Interface to the BLT <code>busy release</code> command.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Blt.haveblt</strong>(<em>window</em>)</dt><dd>
+
+    Return true if any commands in the BLT extension are available.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Blt.havebltbusy</strong>(<em>window</em>)</dt><dd>
+
+    Return true if the BLT <strong>busy</strong> command is available.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Blt.vector_expr</strong>(<em>expression</em>)</dt><dd>
+
+    Interface to the BLT <code>vector expr</code> command.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Blt.vector_names</strong>(<em>pattern</em> = <strong>None</strong>)</dt><dd>
+
+    Interface to the BLT <code>vector names</code> command.</p>
+
+<p></p>
+
+
+</dd>
+</dl>
+</dd></dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 25 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ButtonBox.gif b/Pmw/Pmw_1_2/doc/ButtonBox.gif
new file mode 100644 (file)
index 0000000..402b6b0
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ButtonBox.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ButtonBox.html b/Pmw/Pmw_1_2/doc/ButtonBox.html
new file mode 100644 (file)
index 0000000..2075f42
--- /dev/null
@@ -0,0 +1,306 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ButtonBox reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ButtonBox</h1>
+    
+<center><IMG SRC=ButtonBox.gif ALT="" WIDTH=297 HEIGHT=65></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ButtonBox() - 
+    manager megawidget for buttons
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A button box is a container megawidget which manages a number of
+    buttons.  One of these buttons may be specified as the default and
+    it will be displayed with the platform specific appearance for a
+    default button.  The buttons may be laid out either horizontally
+    or vertically.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.orient></a>
+<dl><dt> <strong>orient
+</strong></dt><dd>
+Initialisation option. Specifies the orientation of the button box.  This may be
+    <strong>'horizontal'</strong> or <strong>'vertical'</strong>. The default is <strong>'horizontal'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.padx></a>
+<dl><dt> <strong>padx
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave between each button in the x
+    direction and also between the buttons and the outer edge of the 
+    button box. The default is <strong>3</strong>.</p>
+
+
+</dd></dl>
+<a name=option.pady></a>
+<dl><dt> <strong>pady
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave between each button in the y
+    direction and also between the buttons and the outer edge of the
+    button box. The default is <strong>3</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.frame></a>
+<dl><dt> <strong>frame
+</strong></dt><dd>
+If the <strong>label</strong> component has been created (that is, the <strong>labelpos</strong>
+    option is not <strong>None</strong>), the <strong>frame</strong> component is created to act as
+    the container of the buttons created by the <code>add()</code> and
+    <code>insert()</code> methods.  If there is no <strong>label</strong> component, then no
+    <strong>frame</strong> component is created and the <strong>hull</strong> component acts as the
+    container. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Dynamic components</h3></dt><dd>
+<p>
+        Button components are created dynamically by the <code>add()</code> and
+        <code>insert()</code> methods.  By default, the buttons are of type
+        Tkinter.Button and are created with a component group of
+        <strong>Button</strong>.</p>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.add></a>
+<dl><dt> <strong>add</strong>(<em>componentName</em>, **<em>kw</em>)</dt><dd>
+Add a button to the end of the button box as a component named
+    <em>componentName</em>.  Any keyword arguments present will be passed to the
+    constructor when creating the button.  If the <strong>text</strong> keyword
+    argument is not given, the <strong>text</strong> option of the button defaults to
+    <em>componentName</em>.  The method returns the component widget.</p>
+
+
+</dd></dl>
+<a name=method.alignbuttons></a>
+<dl><dt> <strong>alignbuttons</strong>(<em>when</em> = <strong>'later'</strong>)</dt><dd>
+Set the widths of all the buttons to be the same as the width of
+    the widest button.  If <em>when</em> is <strong>'later'</strong>, this will occur when the
+    interpreter next becomes idle, otherwise the resizing will occur
+    immediately.</p>
+
+
+</dd></dl>
+<a name=method.button></a>
+<dl><dt> <strong>button</strong>(<em>buttonIndex</em>)</dt><dd>
+Return the button specified by <em>buttonIndex</em>, which may have any
+    of the forms accepted by the <code>index()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.delete></a>
+<dl><dt> <strong>delete</strong>(<em>index</em>)</dt><dd>
+Delete the button given by <em>index</em> from the button box.  <em>index</em>
+    may have any of the forms accepted by the <code>index()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.index></a>
+<dl><dt> <strong>index</strong>(<em>index</em>, <em>forInsert</em> = <strong>0</strong>)</dt><dd>
+Return the numerical index of the button corresponding to <em>index</em>. 
+    This may be specified in any of the following forms:</p>
+<dl><dt><em>name</em></dt><dd>Specifies the button named <em>name</em>.<p></p>
+
+</dd>
+<dt><em>number</em></dt><dd>Specifies the button numerically, where <strong>0</strong> corresponds to
+         the left (or top) button.<p></p>
+
+</dd>
+<dt><strong>Pmw.END</strong></dt><dd>Specifies the right (or bottom) button.<p></p>
+
+</dd>
+<dt><strong>Pmw.DEFAULT</strong></dt><dd>Specifies the current default button.<p></p>
+
+</dd></dl>
+<p>    If <em>forInsert</em> is true, <strong>Pmw.END</strong> returns the number of buttons rather
+    than the index of the last button.</p>
+
+
+
+</dd></dl>
+<a name=method.insert></a>
+<dl><dt> <strong>insert</strong>(<em>componentName</em>, <em>beforeComponent</em> = <strong>0</strong>, **<em>kw</em>)</dt><dd>
+Add a button to the button box as a component named
+    <em>componentName</em>.  The button is added just before the button
+    specified by <em>beforeComponent</em>, which may have any of the forms
+    accepted by the <code>index()</code> method.  Any keyword arguments present
+    will be passed to the constructor when creating the button.  If
+    the <strong>text</strong> keyword argument is not given, the <strong>text</strong> option of the
+    button defaults to <em>componentName</em>.  To add a button to the end of
+    the button box, use <code>add()</code>.  The method returns the component
+    widget.</p>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>(<em>index</em> = <strong>Pmw.DEFAULT</strong>, <em>noFlash</em> = <strong>0</strong>)</dt><dd>
+Invoke the callback command associated with the button specified
+    by <em>index</em> and return the value returned by the callback.
+    Unless <em>noFlash</em> is true, flash the button to
+    indicate to the user that something happened.
+    <em>index</em> may have any of the forms accepted by the <code>index()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.numbuttons></a>
+<dl><dt> <strong>numbuttons</strong>()</dt><dd>
+Return the number of buttons in the button box.</p>
+
+
+</dd></dl>
+<a name=method.setdefault></a>
+<dl><dt> <strong>setdefault</strong>(<em>index</em>)</dt><dd>
+Set the default button to the button given by <em>index</em>.  This
+    causes the specified button to be displayed with the platform
+    specific appearance for a default button.  If <em>index</em> is <strong>None</strong>,
+    there will be no default button.  <em>index</em> may have any of the
+    forms accepted by the <code>index()</code> method.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the ButtonBox.
+        self.buttonBox = Pmw.ButtonBox(parent,
+                labelpos = 'nw',
+                label_text = 'ButtonBox:',
+                frame_borderwidth = 2,
+                frame_relief = 'groove')
+        self.buttonBox.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+
+        # Add some buttons to the ButtonBox.
+        self.buttonBox.add('OK', command = self.ok)
+        self.buttonBox.add('Apply', command = self.apply)
+        self.buttonBox.add('Cancel', command = self.cancel)
+
+        # Set the default button (the one executed when &lt;Return&gt; is hit).
+        self.buttonBox.setdefault('OK')
+        parent.bind('&lt;Return&gt;', self._processReturnKey)
+        parent.focus_set()
+
+        # Make all the buttons the same width.
+        self.buttonBox.alignbuttons()
+
+    def _processReturnKey(self, event):
+        self.buttonBox.invoke()
+
+    def ok(self):
+        print 'You clicked on OK'
+
+    def apply(self):
+        print 'You clicked on Apply'
+
+    def cancel(self):
+        print 'You clicked on Cancel'
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 24 May 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/Color.html b/Pmw/Pmw_1_2/doc/Color.html
new file mode 100644 (file)
index 0000000..e004f85
--- /dev/null
@@ -0,0 +1,326 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.Color reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.Color</h1>
+    
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.Color - 
+    contains functions for handling colors and color schemes</p>
+<p></p>
+
+
+
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This module is a set of functions for manipulating colors and for
+    modifying the color scheme of an application or a widget.  Many of
+    the functions in this module take or return colors.  These values
+    may represent colors in the following ways:</p>
+<dl><dt><strong>name</strong></dt><dd>a standard color name, eg <code>'orange'</code> or <code>'#ffa500'</code><p></p>
+
+</dd>
+<dt><strong>rgb</strong></dt><dd>a 3-element sequence of red, green and blue intensities
+        each between 0.0 (dark) and 1.0 (light), eg <code>[1.0, 0.6, 0.0]</code>.<p></p>
+
+</dd>
+<dt><strong>hsi</strong></dt><dd>a 3-element sequence (<em>hue</em>, <em>saturation</em>,
+        <em>intensity</em>).  The value of <em>hue</em> is between 0.0 and <strong>2pi</strong>
+        (6.28318) giving a range of colors covering, in order, red,
+        orange, yellow green, cyan, blue, magenta and back to red. 
+        The value of <em>saturation</em> is between 0.0 (grey) and 1.0
+        (brilliant) and the value of <em>intensity</em> is between 0.0 (dark)
+        and 1.0 (bright).<p></p>
+
+</dd></dl>
+
+<p>    As used in these functions, the <strong>brightness</strong> of a color is the
+    perceived grey level of the color as registered by the human eye. 
+    For example, even though the colors red, blue and yellow have the
+    same intensity (1.0), they have different brightnesses, 0.299,
+    0.114 and 0.886 respectively, reflecting the different way these
+    colors appear to the eye.  The brightness of a color is a value
+    between 0.0 (dark) and 1.0 (bright).</p>
+
+<p>    A <strong>color scheme</strong> is a set of colors defined for each of the
+    default color options in the Tk option database.  Color schemes
+    can be used in two ways.  Firstly, using <code>Pmw.Color.setscheme()</code>,
+    the Tk option database can be set to the values in the color
+    scheme.  This will not have any effect on currently existing
+    widgets, but any new widgets created after setting the options
+    will have these colors as their defaults.  Secondly, using
+    <code>Pmw.Color.changecolor()</code> the color scheme can be used to change
+    the colors of a widget and all its child widgets.</p>
+
+<p>    A color scheme is specified by defining one or more color options
+    (one of the defined options must be <code>background</code>).  Not all
+    options need be specified - if any options are not defined, they
+    are calculated from the other colors.  These are the options used
+    by a color scheme, together with their values if not specified:</p>
+<dl><dd><pre> background:            (must be specified)
+ foreground:            black
+ activeForeground:      same as foreground
+ insertBackground:      same as foreground
+ selectForeground:      same as foreground
+ highlightColor:        same as foreground
+ disabledForeground:    between fg and bg but closer to bg
+ highlightBackground:   same as background
+ activeBackground:      a little lighter that bg
+ selectBackground:      a little darker that bg
+ troughColor:           a little darker that bg
+ selectColor:           yellow</pre></dd></dl>
+
+
+<p>    There are many functions in this module.  As well as
+    <code>Pmw.Color.setscheme()</code> and <code>Pmw.Color.changecolor()</code>, some of the
+    most useful are <code>Pmw.Color.spectrum()</code>,
+    <code>Pmw.Color.changebrightness()</code> and
+    <code>Pmw.Color.getdefaultpalette()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Functions</h3></dt><dd>
+The following functions are available.<p></p>
+<dl>
+<dt> <strong>Pmw.Color.average</strong>(<em>rgb1</em>, <em>rgb2</em>, <em>fraction</em>)</dt><dd>
+
+    Return an <strong>rgb</strong> color <em>fraction</em> of the way "between" the colors
+    <em>rgb1</em> and <em>rgb2</em>, where <em>fraction</em> must be between <strong>0.0</strong> and
+    <strong>1.0</strong>.  If <em>fraction</em> is close to <strong>0.0</strong>, then the color returned
+    will be close to <em>rgb1</em>.  If it is close to <strong>1.0</strong>, then the color
+    returned will be close to <em>rgb2</em>.  If it is near <strong>0.5</strong>, then the
+    color returned will be half way between the two colors.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.bhi2saturation</strong>(<em>brightness</em>, <em>hue</em>, <em>intensity</em>)</dt><dd>
+
+    Return the saturation of the color represented by <em>brightness</em>,
+    <em>hue</em> and <em>intensity</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.bordercolors</strong>(<em>root</em>, <em>colorName</em>)</dt><dd>
+
+    Return a tuple <code>(light, dark)</code> of color names that can be used as
+    the light and dark border shadows on a widget where the background
+    is <em>colorName</em>.  This is the same method that Tk uses for shadows
+    when drawing reliefs on widget borders.  The <em>root</em> argument is
+    only used to query Tk for the <strong>rgb</strong> values of <em>colorName</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.changebrightness</strong>(<em>root</em>, <em>colorName</em>, <em>brightness</em>)</dt><dd>
+
+    Find the hue of the color <em>colorName</em> and return a color of this
+    hue with the required <em>brightness</em>.  If <em>brightness</em> is <strong>None</strong>,
+    return the name of color with the given hue and with saturation
+    and intensity both <strong>1.0</strong>.  The <em>root</em> argument is only used to
+    query Tk for the <strong>rgb</strong> values of <em>colorName</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.changecolor</strong>(<em>widget</em>, <em>background</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+
+    Change the color of <em>widget</em> and all its child widgets according
+    to the color scheme specified by the other arguments.  This is done
+    by modifying all of the color options of existing widgets that
+    have the default value.  The color options are the lower case
+    versions of those described in the <strong>color scheme</strong> section.  Any
+    options which are different to the previous color scheme (or the
+    defaults, if this is the first call) are not changed.</p>
+
+<p>    For example to change a widget to have a red color scheme with a
+    white foreground:</p>
+
+<dl><dd><pre> Pmw.Color.changecolor(widget,
+     background = 'red3', foreground = 'white')</pre></dd></dl>
+
+<p>    The colors of widgets created after this call will not be
+    affected.</p>
+
+<p>    Note that <em>widget</em> must be a Tk widget or toplevel.  To change the
+    color of a Pmw megawidget, use it's <strong>hull</strong> component.  For example:</p>
+
+<dl><dd><pre> widget = megawidget.component('hull')
+ Pmw.Color.changecolor(widget, background = 'red3')</pre></dd></dl>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.correct</strong>(<em>rgb</em>, <em>correction</em>)</dt><dd>
+
+    Return the "corrected" value of <em>rgb</em>.  This can be used to
+    correct for dull monitors.  If <em>correction</em> is less than <strong>1.0</strong>,
+    the color is dulled.  If <em>correction</em> is greater than <strong>1.0</strong>, the
+    color is brightened.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.getdefaultpalette</strong>(<em>root</em>)</dt><dd>
+
+    Return a dictionary of the default values of the color options
+    described in the <strong>color scheme</strong> section.</p>
+
+<p>    To do this, a few widgets are created as children of <em>root</em>, their
+    defaults are queried, and then the widgets are destroyed.  (Tk
+    supplies no other way to get widget default values.)</p>
+
+<p>    Note that <em>root</em> must be a Tk widget or toplevel.  To use a Pmw
+    megawidget as the root, use it's <strong>hull</strong> component.  For example:</p>
+
+<dl><dd><pre> root = megawidget.component('hull')
+ Pmw.Color.getdefaultpalette(root)</pre></dd></dl>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.hsi2rgb</strong>(<em>hue</em>, <em>saturation</em>, <em>intensity</em>)</dt><dd>
+
+    Return the <strong>rgb</strong> representation of the color represented by <em>hue</em>,
+    <em>saturation</em> and <em>intensity</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.hue2name</strong>(<em>hue</em>, <em>brightness</em> = <strong>None</strong>)</dt><dd>
+
+    Return the name of the color with the specified <em>hue</em> and
+    <em>brightness</em>.  If <em>hue</em> is <strong>None</strong>, return a grey of the requested
+    brightness.  Otherwise, the value of <em>hue</em> should be as described
+    above.  If <em>brightness</em> is <strong>None</strong>, return the name of color with
+    the given hue and with saturation and intensity both <strong>1.0</strong>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.name2rgb</strong>(<em>root</em>, <em>colorName</em>, <em>asInt</em> = <strong>0</strong>)</dt><dd>
+
+    Return <em>colorName</em> as an <strong>rgb</strong> value.  If <em>asInt</em> is true, then
+    the elements of the return sequence are in the range <strong>0</strong> to
+    <strong>65535</strong> rather than <strong>0.0</strong> to <strong>1.0</strong>.  The <em>root</em> argument is only
+    used to query Tk for the <strong>rgb</strong> values of <em>colorName</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.rgb2brightness</strong>(<em>rgb</em>)</dt><dd>
+
+    Return the brightness of the color represented by <em>rgb</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.rgb2hsi</strong>(<em>rgb</em>)</dt><dd>
+
+    Return a tuple (<em>hue</em>, <em>saturation</em>, <em>intensity</em>) corresponding to
+    the color specified by the <em>rgb</em> sequence.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.rgb2name</strong>(<em>rgb</em>)</dt><dd>
+
+    Return the name of the color represented by <em>rgb</em> as a string of
+    the form <code>'#RRGGBB'</code> suitable for use with Tk color functions.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.setscheme</strong>(<em>root</em>, <em>background</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+
+    Set the color scheme for the application by setting default colors
+    (in the Tk option database of the root window of <em>root</em>) according
+    to the color scheme specified by the other arguments.  This will
+    affect the initial colours of all widgets created after the call
+    to this function.</p>
+
+<p>    For example to initialise an application to have a red color
+    scheme with a white foreground:</p>
+
+<dl><dd><pre> Pmw.Color.setscheme(root,
+     background = 'red3', foreground = 'white')</pre></dd></dl>
+
+<p>    This function does not modify the colors of already existing
+    widgets.  Use <strong>Pmw.Color.changecolor()</strong> to do this.</p>
+
+<p>    Note that <em>root</em> must be a Tk widget or toplevel.  To use the Tk
+    option database of the root window of a Pmw megawidget, use the
+    megawidget's <strong>hull</strong> component.  For example:</p>
+
+<dl><dd><pre> root = megawidget.component('hull')
+ Pmw.Color.setscheme(root, background = 'red3')</pre></dd></dl>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.Color.spectrum</strong>(<em>numColors</em>, <em>correction</em> = <strong>1.0</strong>, <em>saturation</em> = <strong>1.0</strong>, <em>intensity</em> = <strong>1.0</strong>, <em>extraOrange</em> = <strong>1</strong>, <em>returnHues</em> = <strong>0</strong>)</dt><dd>
+
+    Return a list of <em>numColors</em> different colors making up a
+    <em>spectrum</em>.  If <em>extraOrange</em> is false, the colors are evenly
+    spaced by hue from one end of the spectrum (red) to the other
+    (magenta).  If <em>extraOrange</em> is true, the hues are not quite
+    evenly spaced - the hues around orange are emphasised, thus
+    preventing the spectrum from appearing to have to many <em>cool</em>
+    hues. </p>
+
+<p>    If <em>returnHues</em> is false, the return values are the names of the
+    colors represented by the hues together with <em>saturation</em> and
+    <em>intensity</em> and corrected by <em>correction</em>.</p>
+
+<p>    If <em>returnHues</em> is true, the return values are hues.</p>
+
+<p></p>
+
+
+</dd>
+</dl>
+</dd></dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 25 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ComboBox.gif b/Pmw/Pmw_1_2/doc/ComboBox.gif
new file mode 100644 (file)
index 0000000..31fee77
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ComboBox.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ComboBox.html b/Pmw/Pmw_1_2/doc/ComboBox.html
new file mode 100644 (file)
index 0000000..0be8d68
--- /dev/null
@@ -0,0 +1,363 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ComboBox reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ComboBox</h1>
+    
+<center><IMG SRC=ComboBox.gif ALT="" WIDTH=376 HEIGHT=246></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ComboBox() - 
+    dropdown or simple combination box
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A combobox contains an entry field and an associated scrolled
+    listbox.  When an item in the listbox is selected, it is displayed
+    in the entry field.  Optionally, the user may also edit the entry
+    field directly.</p>
+
+<p>    For a simple combobox, the scrolled listbox is displayed beneath
+    the entry field.  For a dropdown combobox (the default), the
+    scrolled listbox is displayed in a window which pops up beneath
+    the entry field when the user clicks on an arrow button on the
+    right of the entry field.  Either style allows an optional label.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.autoclear></a>
+<dl><dt> <strong>autoclear
+</strong></dt><dd>
+Initialisation option. If both <strong>autoclear</strong> and <strong>history</strong> are true, clear the entry field
+    whenever <strong>&lt;Return&gt;</strong> is pressed, after adding the value to the
+    history list. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonaspect></a>
+<dl><dt> <strong>buttonaspect
+</strong></dt><dd>
+Initialisation option. The width of the arrow button as a proportion of the height.  The
+    height of the arrow button is set to the height of the entry
+    widget. The default is <strong>1.0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.dropdown></a>
+<dl><dt> <strong>dropdown
+</strong></dt><dd>
+Initialisation option. Specifies whether the combobox should be dropdown or simple. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.fliparrow></a>
+<dl><dt> <strong>fliparrow
+</strong></dt><dd>
+Initialisation option. If true, the arrow button is draw upside down when the listbox is
+    being displayed.  Used only in dropdown megawidgets. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.history></a>
+<dl><dt> <strong>history
+</strong></dt><dd>
+Initialisation option. When <strong>&lt;Return&gt;</strong> is pressed in the entry field, the current value
+    of the entry field is appended to the listbox if <strong>history</strong> is
+    true. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.listheight></a>
+<dl><dt> <strong>listheight
+</strong></dt><dd>
+Initialisation option. The height, in pixels, of the dropdown listbox. The default is <strong>200</strong>.</p>
+
+
+</dd></dl>
+<a name=option.selectioncommand></a>
+<dl><dt> <strong>selectioncommand
+</strong></dt><dd>
+The function to call when an item is selected.
+    If this function takes a long time to run, and you want the entry
+    field to be updated quickly, call <code>update_idletasks()</code> at the
+    beginning of the function.  Alternatively, wrap the function using
+    <code>Pmw.busycallback()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'ew'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.unique></a>
+<dl><dt> <strong>unique
+</strong></dt><dd>
+Initialisation option. If both <strong>unique</strong> and <strong>history</strong> are true, the current value of the
+    entry field is not added to the listbox if it is already in the
+    list. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.arrowbutton></a>
+<dl><dt> <strong>arrowbutton
+</strong></dt><dd>
+In a dropdown combobox, the button to popup the listbox. By default, this component is a Tkinter.Canvas.</p>
+
+
+</dd></dl>
+<a name=component.entryfield></a>
+<dl><dt> <strong>entryfield
+</strong></dt><dd>
+The entry field where the current selection is displayed. By default, this component is a <a href="EntryField.html">Pmw.EntryField</a>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.popup></a>
+<dl><dt> <strong>popup
+</strong></dt><dd>
+In a dropdown combobox, the dropdown window. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.scrolledlist></a>
+<dl><dt> <strong>scrolledlist
+</strong></dt><dd>
+The scrolled listbox which displays the items to select. By default, this component is a <a href="ScrolledListBox.html">Pmw.ScrolledListBox</a>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+Alias for <strong>entryfield_entry</strong>.
+</dd></dl>
+<dl><dt> <strong>listbox
+</strong></dt><dd>
+Alias for <strong>scrolledlist_listbox</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the following classes
+are forwarded by this megawidget.
+Methods from <strong><a href="ScrolledListBox.html#methods">Pmw.ScrolledListBox</a></strong>
+are forwarded to the
+<strong>scrolledlist</strong> component.
+Methods from <strong><a href="EntryField.html#methods">Pmw.EntryField</a></strong>
+are forwarded to the
+<strong>entryfield</strong> component.
+Forwarded methods are searched in the order given.
+<p></p>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(<em>index</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>scrolledlist</strong>
+    component's <code>bbox()</code> method.  Without this explicit forwarding,
+    the <code>bbox()</code> method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would
+    be invoked, which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+<a name=method.clear></a>
+<dl><dt> <strong>clear</strong>()</dt><dd>
+Delete all items from the scrolled listbox and delete all text
+    from the entry widget.</p>
+
+
+</dd></dl>
+<a name=method.get></a>
+<dl><dt> <strong>get</strong>(<em>first</em> = <strong>None</strong>, <em>last</em> = <strong>None</strong>)</dt><dd>
+This is the same as the <code>get()</code> method of the <strong>scrolledlist</strong>
+    component, except that if <em>first</em> is <strong>None</strong> then
+    the value of the entry field is returned.</p>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>()</dt><dd>
+If a dropdown combobox, display the dropdown listbox.  In a simple
+    combobox, select the currently selected item in the listbox,
+    call the <strong>selectioncommand</strong> and return the result.</p>
+
+
+</dd></dl>
+<a name=method.selectitem></a>
+<dl><dt> <strong>selectitem</strong>(<em>index</em>, <em>setentry</em> = <strong>1</strong>)</dt><dd>
+Select the item in the listbox specified by <em>index</em> which may be
+    either one of the items in the listbox or the integer index of one
+    of the items in the listbox.</p>
+<p>    If <em>setentry</em> is true, also set the entry field to the selected
+    item.</p>
+
+
+
+</dd></dl>
+<a name=method.size></a>
+<dl><dt> <strong>size</strong>()</dt><dd>
+This method is explicitly forwarded to the <strong>scrolledlist</strong>
+    component's <code>size()</code> method.  Without this explicit forwarding,
+    the <code>size()</code> method (aliased to <code>grid_size()</code>) of the <strong>hull</strong> would
+    be invoked, which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        parent.configure(background = 'white')
+
+        # Create and pack the widget to be configured.
+        self.target = Tkinter.Label(parent,
+                relief = 'sunken',
+                padx = 20,
+                pady = 20,
+        )
+        self.target.pack(fill = 'x', padx = 8, pady = 8)
+
+        # Create and pack the simple ComboBox.
+        words = ('Monti', 'Python', 'ik', 'den', 'Holie', 'Grailen', '(Bok)')
+        simple = Pmw.ComboBox(parent,
+                label_text = 'Simple ComboBox:',
+                labelpos = 'nw',
+                selectioncommand = self.changeText,
+                scrolledlist_items = words,
+                dropdown = 0,
+        )
+        simple.pack(side = 'left', fill = 'both',
+                expand = 1, padx = 8, pady = 8)
+
+        # Display the first text.
+        first = words[0]
+        simple.selectitem(first)
+        self.changeText(first)
+
+        # Create and pack the dropdown ComboBox.
+        colours = ('cornsilk1', 'snow1', 'seashell1', 'antiquewhite1',
+                'bisque1', 'peachpuff1', 'navajowhite1', 'lemonchiffon1',
+                'ivory1', 'honeydew1', 'lavenderblush1', 'mistyrose1')
+        dropdown = Pmw.ComboBox(parent,
+                label_text = 'Dropdown ComboBox:',
+                labelpos = 'nw',
+                selectioncommand = self.changeColour,
+                scrolledlist_items = colours,
+        )
+        dropdown.pack(side = 'left', anchor = 'n',
+                fill = 'x', expand = 1, padx = 8, pady = 8)
+
+        # Display the first colour.
+        first = colours[0]
+        dropdown.selectitem(first)
+        self.changeColour(first)
+
+    def changeColour(self, colour):
+        print 'Colour: ' + colour
+        self.target.configure(background = colour)
+
+    def changeText(self, text):
+        print 'Text: ' + text
+        self.target.configure(text = text)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 1 November 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ComboBoxDialog.gif b/Pmw/Pmw_1_2/doc/ComboBoxDialog.gif
new file mode 100644 (file)
index 0000000..011fde5
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ComboBoxDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ComboBoxDialog.html b/Pmw/Pmw_1_2/doc/ComboBoxDialog.html
new file mode 100644 (file)
index 0000000..e139f11
--- /dev/null
@@ -0,0 +1,286 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ComboBoxDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ComboBoxDialog</h1>
+    
+<center><IMG SRC=ComboBoxDialog.gif ALT="" WIDTH=218 HEIGHT=236></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ComboBoxDialog() - 
+    selection dialog displaying a list and an entry field
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="Dialog.html">Pmw.Dialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A combobox dialog is a dialog window which displays a list and
+    an entry field which can be used to prompt the user for a value.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the combobox. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the combobox. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.combobox></a>
+<dl><dt> <strong>combobox
+</strong></dt><dd>
+The combobox for the user to enter a value.  By default it is
+    created using the option <code>dropdown = 0</code>. By default, this component is a <a href="ComboBox.html">Pmw.ComboBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+Alias for <strong>combobox_entry</strong>.
+</dd></dl>
+<dl><dt> <strong>label
+</strong></dt><dd>
+Alias for <strong>combobox_label</strong>.
+</dd></dl>
+<dl><dt> <strong>listbox
+</strong></dt><dd>
+Alias for <strong>combobox_listbox</strong>.
+</dd></dl>
+<dl><dt> <strong>scrolledlist
+</strong></dt><dd>
+Alias for <strong>combobox_scrolledlist</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="Dialog.html#methods">Pmw.Dialog</a></strong>.
+In addition, methods from the
+<strong><a href="ComboBox.html#methods">Pmw.ComboBox</a></strong> class
+are forwarded by this megawidget to the
+<strong>combobox</strong> component.
+<p></p>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(<em>index</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>combobox</strong> component's
+    <code>bbox()</code> method.  Without this explicit forwarding, the <code>bbox()</code>
+    method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+<a name=method.size></a>
+<dl><dt> <strong>size</strong>()</dt><dd>
+This method is explicitly forwarded to the <strong>combobox</strong> component's
+    <code>size()</code> method.  Without this explicit forwarding, the <code>size()</code>
+    method (aliased to <code>grid_size()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the dialog.
+        self.dialog = Pmw.ComboBoxDialog(parent,
+            title = 'My ComboBoxDialog',
+            buttons = ('OK', 'Cancel'),
+            defaultbutton = 'OK',
+            combobox_labelpos = 'n',
+            label_text = 'What do you think of Pmw?',
+            scrolledlist_items = ('Cool man', 'Cool', 'Good', 'Bad', 'Gross'))
+        self.dialog.withdraw()
+
+        # Create button to launch the dialog.
+        w = Tkinter.Button(parent,
+                text = 'Show combo box dialog',
+                command = self.doit)
+        w.pack(padx = 8, pady = 8)
+
+    def doit(self):
+        result = self.dialog.activate()
+        print 'You clicked on', result, self.dialog.get()
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/Counter.gif b/Pmw/Pmw_1_2/doc/Counter.gif
new file mode 100644 (file)
index 0000000..20c3322
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/Counter.gif differ
diff --git a/Pmw/Pmw_1_2/doc/Counter.html b/Pmw/Pmw_1_2/doc/Counter.html
new file mode 100644 (file)
index 0000000..a52595e
--- /dev/null
@@ -0,0 +1,455 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.Counter reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.Counter</h1>
+    
+<center><IMG SRC=Counter.gif ALT="" WIDTH=400 HEIGHT=110></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.Counter() - 
+    entry field with up and down arrow buttons
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A counter contains an entry field and two arrow buttons to
+    increment and decrement the value in the entry field.  Standard
+    counting types include numbers, times and dates.  A user defined
+    counting function may also be supplied for specialised counting. 
+    Counting can be used in combination with the entry field's
+    validation.  The components may be laid out horizontally or
+    vertically.</p>
+
+<p>    Each time an arrow button is pressed the value displayed in the
+    entry field is incremented or decremented by the value of the
+    <strong>increment</strong> option.  If the new value is invalid (according to the
+    entry field's <strong>validate</strong> option, perhaps due to exceeding minimum
+    or maximum limits), the old value is restored.</p>
+
+<p>    When an arrow button is pressed and the value displayed is not an
+    exact multiple of the <strong>increment</strong>, it is "truncated" up or down to
+    the nearest increment.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.autorepeat></a>
+<dl><dt> <strong>autorepeat
+</strong></dt><dd>
+If true, the counter will continue to count up or down while an
+    arrow button is held pressed down. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonaspect></a>
+<dl><dt> <strong>buttonaspect
+</strong></dt><dd>
+Initialisation option. Specifies the width of the arrow buttons as a proportion of their
+    height.  Values less than <strong>1.0</strong> will produce thin arrow buttons. 
+    Values greater than <strong>1.0</strong> will produce fat arrow buttons. The default is <strong>1.0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.datatype></a>
+<dl><dt> <strong>datatype
+</strong></dt><dd>
+Specifies how the counter should count up and down.</p>
+<p>    The most general way to specify the <strong>datatype</strong> option is as a
+    dictionary.  The kind of counting is specified by the <strong>'counter'</strong>
+    dictionary field, which may be either a function or the name of
+    one of the standard counters described below.  If the dictionary
+    does not have a <strong>'counter'</strong> field, the field defaults to
+    <strong>'numeric'</strong>.</p>
+
+<p>    Any other fields in the dictionary are passed on to the <em>counter</em>
+    function as keyword arguments.</p>
+
+<p>    If <strong>datatype</strong> is not a dictionary, then it is equivalent to
+    specifying it as a dictionary with a single <strong>'counter'</strong> field. 
+    For example, <code>datatype = 'real'</code> is equivalent to
+    <code>datatype = {'counter' : 'real'}</code>.</p>
+
+<p>    The standard counters are:</p>
+
+<dl><dt><strong>'numeric'</strong></dt><dd>An integer number, as accepted by <code>string.atol()</code>.<p></p>
+
+</dd>
+<dt><strong>'integer'</strong></dt><dd>Same as <strong>'numeric'</strong>.<p></p>
+
+</dd>
+<dt><strong>'real'</strong></dt><dd>A real number, as accepted by <code>string.atof()</code>.  This
+        counter accepts a <strong>'separator'</strong> argument, which specifies
+        the character used to represent the decimal point.  The
+        default <strong>'separator'</strong> is <strong>'.'</strong>.<p></p>
+
+</dd>
+<dt><strong>'time'</strong></dt><dd>A time specification, as accepted by
+        <code>Pmw.timestringtoseconds()</code>.  This counter accepts a
+        <strong>'separator'</strong> argument, which specifies the character used to
+        separate the time fields.  The default separator is <strong>':'</strong>. 
+        This counter also accepts a <strong>'time24'</strong> argument.  If this is
+        true, the time value is converted to a value between
+        <strong>'00:00:00'</strong> and <strong>'23:59:59'</strong>.  The default is false.<p></p>
+
+</dd>
+<dt><strong>'date'</strong></dt><dd>A date specification, as accepted by
+        <code>Pmw.datestringtojdn()</code>.  This counter accepts a <strong>'separator'</strong>
+        argument, which specifies the character used to separate the
+        three date fields.  The default is <strong>'/'</strong>.  This counter also
+        accepts a <strong>'format'</strong> argument, which is passed to
+        <code>Pmw.datestringtojdn()</code> to specify the desired ordering of the
+        fields.  The default is <strong>'ymd'</strong>.
+        This counter also accepts a <strong>'yyyy'</strong> argument.  If this is
+        false, the year field will be displayed as the year within the
+        century, otherwise it will be fully displayed.  In both cases
+        it will be displayed with at least 2 digits, using leading
+        zeroes.  The default is false.<p></p>
+
+</dd></dl>
+<p>    If the <strong>'counter'</strong> dictionary field is a function, then it will be
+    called whenever the counter is to be incremented or decremented. 
+    The function is called with at least three arguments, the first
+    three being (<em>text</em>, <em>factor</em>, <em>increment</em>), where <em>text</em> is the
+    current contents of the entry field, <em>factor</em> is <strong>1</strong> when
+    incrementing or <strong>-1</strong> when decrementing, and <em>increment</em> is the
+    value of the <strong>increment</strong> megawidget option.</p>
+
+<p>    The other arguments are keyword arguments made up of the fields of
+    the <strong>datatype</strong> dictionary (excluding the <strong>'counter'</strong> field).</p>
+
+<p>    The <em>counter</em> function should return a string representing the
+    incremented or decremented value.  It should raise a
+    <strong>ValueError</strong> exception if the <em>text</em> is invalid.  In this case the
+    bell is rung and the entry text is not changed.</p>
+
+<p>    The default for <strong>datatype</strong> is <strong>numeric</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.increment></a>
+<dl><dt> <strong>increment
+</strong></dt><dd>
+Specifies how many units should be added or subtracted when the
+    counter is incremented or decremented.  If the currently displayed
+    value is not a multiple of <strong>increment</strong>, the value is changed to
+    the next multiple greater or less than the current value.</p>
+<p>    For the number datatypes, the value of <strong>increment</strong> is a number. 
+    For the <strong>'time'</strong> datatype, the value is in seconds.  For the
+    <strong>'date'</strong> datatype, the value is in days. The default is <strong>1</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.initwait></a>
+<dl><dt> <strong>initwait
+</strong></dt><dd>
+Specifies the initial delay (in milliseconds) before a depressed
+    arrow button automatically starts to repeat counting. The default is <strong>300</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.orient></a>
+<dl><dt> <strong>orient
+</strong></dt><dd>
+Initialisation option. Specifies whether the arrow buttons should appear to the left and
+    right of the entry field (<strong>'horizontal'</strong>) or above and below
+    (<strong>'vertical'</strong>). The default is <strong>'horizontal'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.padx></a>
+<dl><dt> <strong>padx
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave around the arrow buttons in
+    the x direction. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.pady></a>
+<dl><dt> <strong>pady
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave around the arrow buttons in
+    the y direction. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.repeatrate></a>
+<dl><dt> <strong>repeatrate
+</strong></dt><dd>
+Specifies the delay (in milliseconds) between automatic counts
+    while an arrow button is held pressed down. The default is <strong>50</strong>.</p>
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'ew'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.downarrow></a>
+<dl><dt> <strong>downarrow
+</strong></dt><dd>
+The arrow button used for decrementing the counter.  Depending on
+    the value of <strong>orient</strong>, it will appear on the left or below the
+    entry field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+<a name=component.entryfield></a>
+<dl><dt> <strong>entryfield
+</strong></dt><dd>
+The entry field widget where the text is entered, displayed and
+    validated. By default, this component is a <a href="EntryField.html">Pmw.EntryField</a>.</p>
+
+
+</dd></dl>
+<a name=component.frame></a>
+<dl><dt> <strong>frame
+</strong></dt><dd>
+If the <strong>label</strong> component has been created (that is, the <strong>labelpos</strong>
+    option is not <strong>None</strong>), the <strong>frame</strong> component is created to act as
+    the container of the entry field and arrow buttons.  If there is
+    no <strong>label</strong> component, then no <strong>frame</strong> component is created and the
+    <strong>hull</strong> component acts as the container.  In either case the border
+    around the container of the entry field and arrow buttons will be
+    raised (but not around the label). By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.uparrow></a>
+<dl><dt> <strong>uparrow
+</strong></dt><dd>
+The arrow button used for incrementing the counter.  Depending on
+    the value of <strong>orient</strong>, it will appear on the right or above the
+    entry field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+Alias for <strong>entryfield_entry</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong><a href="EntryField.html#methods">Pmw.EntryField</a></strong> class
+are forwarded by this megawidget to the
+<strong>entryfield</strong> component.
+<p></p>
+<a name=method.decrement></a>
+<dl><dt> <strong>decrement</strong>()</dt><dd>
+Decrement the counter once, as if the down arrow had been pressed.</p>
+
+
+</dd></dl>
+<a name=method.increment></a>
+<dl><dt> <strong>increment</strong>()</dt><dd>
+Increment the counter once, as if the up arrow had been pressed.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Need to use long ints here because on the Macintosh the maximum size
+        # of an integer is smaller than the value returned by time.time().
+        now = (long(time.time()) / 300) * 300
+
+        # Create the Counters.
+        self._date = Pmw.Counter(parent,
+                labelpos = 'w',
+                label_text = 'Date (4-digit year):',
+                entryfield_value =
+                        time.strftime('%d/%m/%Y', time.localtime(now)),
+                entryfield_command = self.execute,
+                entryfield_validate = {'validator' : 'date', 'format' : 'dmy'},
+                datatype = {'counter' : 'date', 'format' : 'dmy', 'yyyy' : 1})
+
+        self._isodate = Pmw.Counter(parent,
+                labelpos = 'w',
+                label_text = 'ISO-Date (4-digit year):',
+                entryfield_value =
+                        time.strftime('%Y-%m-%d', time.localtime(now)),
+                entryfield_command = self.execute,
+                entryfield_validate = {'validator' : 'date', 'format' : 'ymd',
+                        'separator' : '-' },
+                datatype = {'counter' : 'date', 'format' : 'ymd', 'yyyy' : 1,
+                        'separator' : '-' })
+
+        self._time = Pmw.Counter(parent,
+                labelpos = 'w',
+                label_text = 'Time:',
+                entryfield_value =
+                        time.strftime('%H:%M:%S', time.localtime(now)),
+                entryfield_validate = {'validator' : 'time',
+                        'min' : '00:00:00', 'max' : '23:59:59',
+                        'minstrict' : 0, 'maxstrict' : 0},
+                datatype = {'counter' : 'time', 'time24' : 1},
+                increment=5*60)
+        self._real = Pmw.Counter(parent,
+                labelpos = 'w',
+                label_text = 'Real (with comma)\nand extra\nlabel lines:',
+                label_justify = 'left',
+                entryfield_value = '1,5',
+                datatype = {'counter' : 'real', 'separator' : ','},
+                entryfield_validate = {'validator' : 'real',
+                        'min' : '-2,0', 'max' : '5,0',
+                        'separator' : ','},
+                increment = 0.1)
+        self._custom = Pmw.Counter(parent,
+                labelpos = 'w',
+                label_text = 'Custom:',
+                entryfield_value = specialword[:4],
+                datatype = _custom_counter,
+                entryfield_validate = _custom_validate)
+        self._int = Pmw.Counter(parent,
+                labelpos = 'w',
+                label_text = 'Vertical integer:',
+                orient = 'vertical',
+                entry_width = 2,
+                entryfield_value = 50,
+                entryfield_validate = {'validator' : 'integer',
+                        'min' : 0, 'max' : 99}
+        )
+
+        counters = (self._date, self._isodate, self._time, self._real,
+                self._custom)
+        Pmw.alignlabels(counters)
+
+        # Pack them all.
+        for counter in counters:
+            counter.pack(fill='both', expand=1, padx=10, pady=5)
+        self._int.pack(padx=10, pady=5)
+
+    def execute(self):
+        print 'Return pressed, value is', self._date.get()
+
+specialword = 'Monti Python ik den Holie Grailen (Bok)'
+
+def _custom_validate(text):
+    if string.find(specialword, text) == 0:
+        return 1
+    else:
+        return -1
+
+def _custom_counter(text, factor, increment):
+    # increment is ignored here.
+    if string.find(specialword, text) == 0:
+        length = len(text)
+        if factor == 1:
+            if length &gt;= len(specialword):
+                raise ValueError, 'maximum length reached'
+            return specialword[:length + 1]
+        else:
+            if length == 0:
+                raise ValueError, 'empty string'
+            return specialword[:length - 1]
+    else:
+        raise ValueError, 'bad string ' + text
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 24 May 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/CounterDialog.gif b/Pmw/Pmw_1_2/doc/CounterDialog.gif
new file mode 100644 (file)
index 0000000..dd83342
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/CounterDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/CounterDialog.html b/Pmw/Pmw_1_2/doc/CounterDialog.html
new file mode 100644 (file)
index 0000000..ec8ed83
--- /dev/null
@@ -0,0 +1,299 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.CounterDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.CounterDialog</h1>
+    
+<center><IMG SRC=CounterDialog.gif ALT="" WIDTH=268 HEIGHT=198></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.CounterDialog() - 
+    selection dialog displaying a counter
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="Dialog.html">Pmw.Dialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A counter dialog is a dialog window which displays a counter
+    which can be used to prompt the user for a value.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the counter. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the counter. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.counter></a>
+<dl><dt> <strong>counter
+</strong></dt><dd>
+The counter for the user to enter a value. By default, this component is a <a href="Counter.html">Pmw.Counter</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+Alias for <strong>counter_entryfield_entry</strong>.
+</dd></dl>
+<dl><dt> <strong>entryfield
+</strong></dt><dd>
+Alias for <strong>counter_entryfield</strong>.
+</dd></dl>
+<dl><dt> <strong>label
+</strong></dt><dd>
+Alias for <strong>counter_label</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="Dialog.html#methods">Pmw.Dialog</a></strong>.
+In addition, methods from the
+<strong><a href="Counter.html#methods">Pmw.Counter</a></strong> class
+are forwarded by this megawidget to the
+<strong>counter</strong> component.
+<p></p>
+<a name=method.deleteentry></a>
+<dl><dt> <strong>deleteentry</strong>(<em>first</em>, <em>last</em> = <strong>None</strong>)</dt><dd>
+Delete text from the counter's entry widget.  An alias for
+    <code>component('entry').delete()</code>.</p>
+
+
+</dd></dl>
+<a name=method.indexentry></a>
+<dl><dt> <strong>indexentry</strong>(<em>index</em>)</dt><dd>
+An alias for <code>component('entry').index()</code>.</p>
+
+
+</dd></dl>
+<a name=method.insertentry></a>
+<dl><dt> <strong>insertentry</strong>(<em>index</em>, <em>text</em>)</dt><dd>
+Insert text into the counter's entry widget.  An alias for
+    <code>component('entry').insert()</code>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the dialog to prompt for the number of times to ring the bell.
+        self.dialog = Pmw.CounterDialog(parent,
+            label_text = 'Enter the number of times to\n' + \
+                    'sound the bell (1 to 5)\n',
+            counter_labelpos = 'n',
+            entryfield_value = 2,
+            counter_datatype = 'numeric',
+            entryfield_validate =
+                {'validator' : 'numeric', 'min' : 1, 'max' : 5},
+            buttons = ('OK', 'Cancel'),
+            defaultbutton = 'OK',
+            title = 'Bell ringing',
+            command = self.execute)
+        self.dialog.withdraw()
+
+        # Create button to launch the dialog.
+        w = Tkinter.Button(parent, text = 'Show counter dialog',
+                command = self.dialog.activate)
+        w.pack(padx = 8, pady = 8)
+
+    def execute(self, result):
+        if result is None or result == 'Cancel':
+            print 'Bell ringing cancelled'
+            self.dialog.deactivate()
+        else:
+            count = self.dialog.get()
+            if not self.dialog.valid():
+                print 'Invalid entry: "' + count + '"'
+            else:
+                print 'Ringing the bell ' + count + ' times'
+                for num in range(string.atoi(count)):
+                    if num != 0:
+                        self.dialog.after(200)
+                    self.dialog.bell()
+                self.dialog.deactivate()
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/Dialog.gif b/Pmw/Pmw_1_2/doc/Dialog.gif
new file mode 100644 (file)
index 0000000..3483457
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/Dialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/Dialog.html b/Pmw/Pmw_1_2/doc/Dialog.html
new file mode 100644 (file)
index 0000000..1e3c888
--- /dev/null
@@ -0,0 +1,286 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.Dialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.Dialog</h1>
+    
+<center><IMG SRC=Dialog.gif ALT="" WIDTH=374 HEIGHT=162></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.Dialog() - 
+    toplevel window with button box
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaToplevel.html">Pmw.MegaToplevel</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A dialog is a toplevel window composed of a button box and a child
+    site area.  The child site area can be used to specialise the
+    megawidget by creating other widgets within it.  This can be done
+    by using this class directly or by deriving from it.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaToplevel.html#methods">Pmw.MegaToplevel</a></strong>.
+<p></p>
+<a name=method.interior></a>
+<dl><dt> <strong>interior</strong>()</dt><dd>
+Return the child site for the dialog.  This is the same as
+    <code>component('dialogchildsite')</code>.</p>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>(<em>index</em> = <strong>Pmw.DEFAULT</strong>)</dt><dd>
+Invoke the command specified by the <strong>command</strong> option as if the
+    button specified by <em>index</em> had been pressed and return the
+    result.  <em>index</em> may have any of the forms accepted by the
+    <a href="ButtonBox.html">Pmw.ButtonBox</a> <code>index()</code> method.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create two buttons to launch the dialog.
+        w = Tkinter.Button(parent, text = 'Show application modal dialog',
+                command = self.showAppModal)
+        w.pack(padx = 8, pady = 8)
+
+        w = Tkinter.Button(parent, text = 'Show global modal dialog',
+                command = self.showGlobalModal)
+        w.pack(padx = 8, pady = 8)
+
+        w = Tkinter.Button(parent, text = 'Show dialog with "no grab"',
+                command = self.showDialogNoGrab)
+        w.pack(padx = 8, pady = 8)
+
+        w = Tkinter.Button(parent, text =
+                    'Show toplevel window which\n' +
+                    'will not get a busy cursor',
+                command = self.showExcludedWindow)
+        w.pack(padx = 8, pady = 8)
+
+        # Create the dialog.
+        self.dialog = Pmw.Dialog(parent,
+            buttons = ('OK', 'Apply', 'Cancel', 'Help'),
+            defaultbutton = 'OK',
+            title = 'My dialog',
+            command = self.execute)
+        self.dialog.withdraw()
+
+        # Add some contents to the dialog.
+        w = Tkinter.Label(self.dialog.interior(),
+            text = 'Pmw Dialog\n(put your widgets here)',
+            background = 'black',
+            foreground = 'white',
+            pady = 20)
+        w.pack(expand = 1, fill = 'both', padx = 4, pady = 4)
+
+        # Create the window excluded from showbusycursor.
+        self.excluded = Pmw.MessageDialog(parent,
+            title = 'I still work',
+            message_text =
+                'This window will not get\n' +
+                'a busy cursor when modal dialogs\n' +
+                'are activated.  In addition,\n' +
+                'you can still interact with\n' +
+                'this window when a "no grab"\n' +
+                'modal dialog is displayed.')
+        self.excluded.withdraw()
+        Pmw.setbusycursorattributes(self.excluded.component('hull'),
+            exclude = 1)
+
+    def showAppModal(self):
+        self.dialog.activate(geometry = 'centerscreenalways')
+
+    def showGlobalModal(self):
+        self.dialog.activate(globalMode = 1)
+
+    def showDialogNoGrab(self):
+        self.dialog.activate(globalMode = 'nograb')
+
+    def showExcludedWindow(self):
+        self.excluded.show()
+
+    def execute(self, result):
+        print 'You clicked on', result
+        if result not in ('Apply', 'Help'):
+            self.dialog.deactivate(result)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/EntryField.gif b/Pmw/Pmw_1_2/doc/EntryField.gif
new file mode 100644 (file)
index 0000000..d9eeb8b
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/EntryField.gif differ
diff --git a/Pmw/Pmw_1_2/doc/EntryField.html b/Pmw/Pmw_1_2/doc/EntryField.html
new file mode 100644 (file)
index 0000000..5417f14
--- /dev/null
@@ -0,0 +1,545 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.EntryField reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.EntryField</h1>
+    
+<center><IMG SRC=EntryField.gif ALT="" WIDTH=313 HEIGHT=177></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.EntryField() - 
+    entry widget with validation
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    An entry field contains an entry widget with optional validation of
+    various kinds.  Built-in validation may be used, such as
+    <strong>integer</strong>, <strong>real</strong>, <strong>time</strong> or <strong>date</strong>, or an external validation
+    function may be supplied.  If valid text is entered, it will be
+    displayed with the normal background.  If invalid text is entered,
+    it is not displayed and the previously displayed text is restored. 
+    If partially valid text is entered, it will be displayed with a
+    background color to indicate it is in error.  An example of
+    partially valid <strong>real</strong> text is <strong>'-.'</strong>, which may be the first two
+    charactes of the valid string <strong>'-.5'</strong>.  Some validators, such as
+    <strong>date</strong>, have a relaxed interpretation of partial validity, which
+    allows the user flexibility in how they enter the text.</p>
+
+<p>    Validation is performed <em>early</em>, at each keystroke or other event
+    which modifies the text.  However, if partially valid text is
+    permitted, the validity of the entered text can be checked just
+    before it is to be used, which is a form of <em>late</em> validation.</p>
+
+<p>    Minimum and maximum values may be specified.  Some validators also
+    accept other specifications, such as date and time formats and
+    separators.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Validation function return values</h3></dt><dd>
+<p>
+        Validation is performed by a function which takes as its first
+        argument the entered text and returns one of three standard
+        values, indicating whether the text is valid:</p>
+
+<dl><dt><strong>Pmw.OK</strong></dt><dd>The text is valid.<p></p>
+
+</dd>
+<dt><strong>Pmw.ERROR</strong></dt><dd>The text is invalid and is not acceptable for
+            display.  In this case the entry will be restored to its
+            previous value.<p></p>
+
+</dd>
+<dt><strong>Pmw.PARTIAL</strong></dt><dd>The text is partially valid and is acceptable
+            for display.  In this case the text will be displayed
+            using the <strong>errorbackground</strong> color.<p></p>
+<p>        </p>
+
+
+</dd></dl>
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+This specifies a function to call whenever the <strong>&lt;Return&gt;</strong> key is
+    pressed or <code>invoke()</code> is called. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.errorbackground></a>
+<dl><dt> <strong>errorbackground
+</strong></dt><dd>
+Specifies the background color to use when displaying invalid or
+    partially valid text. The default is <strong>'pink'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.extravalidators></a>
+<dl><dt> <strong>extravalidators
+</strong></dt><dd>
+This is a dictionary of extra validators.  The keys are the names
+    of validators which may be used in a future call to the
+    <strong>validate</strong> option.  Each value in the dictionary is a tuple of
+    (<em>validate_function</em>, <em>stringtovalue_function</em>).</p>
+<p>    The <em>validate_function</em> is used to implement the validation and
+    the <em>stringtovalue_function</em> is used to convert the entry input
+    into a value which can be compared with the minimum and maximum
+    limits.  These functions are as described for the <strong>validate</strong>
+    option.</p>
+
+<p>    If either of these is not given as a function, it is assumed to be
+    the name of one of the other extra validators or one of the
+    standard validators.  The alias search is performed when the
+    <strong>validate</strong> option is configured, not when the <strong>extravalidators</strong>
+    option is configured or when the <strong>validate</strong> function is called.</p>
+
+<p>    If the name of one of the extra validators is the same as one of
+    the standard validators, the extra validator takes precedence. The default is <strong>{}</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.invalidcommand></a>
+<dl><dt> <strong>invalidcommand
+</strong></dt><dd>
+This is executed when invalid text is entered and the text is
+    restored to its previous value (that is, when the <strong>validate</strong>
+    function returns <strong>Pmw.ERROR</strong>).  It is also called if an attempt is
+    made to set invalid text in a call to <code>setentry()</code>.  The default
+    is <strong>self.bell</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.modifiedcommand></a>
+<dl><dt> <strong>modifiedcommand
+</strong></dt><dd>
+This is called whenever the text of the entry has been changed
+    due to user action or by a call to <code>setentry()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'ew'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.validate></a>
+<dl><dt> <strong>validate
+</strong></dt><dd>
+Specifies what kind of validation should be performed on the entry
+    input text.</p>
+<p>    The most general way to specify the <strong>validate</strong> option is as a
+    dictionary.  The kind of validation is specified by the
+    <strong>'validator'</strong> dictionary field, which may be the name of one of
+    the standard validators described below, the name of a validator
+    supplied by the <strong>extravalidators</strong> option, a function or <strong>None</strong>. 
+    The default is <strong>None</strong>.</p>
+
+<p>    Any other dictionary fields specify other restrictions on the
+    entered values.  For all validators, the following fields may be
+    specified:</p>
+
+<dl><dt><strong>'min'</strong></dt><dd>Specifies the minimum acceptable value, or <strong>None</strong> if no
+        minimum checking should be performed.  The default is <strong>None</strong>.<p></p>
+
+</dd>
+<dt><strong>'max'</strong></dt><dd>Specifies the maximum acceptable value, or <strong>None</strong> if no
+        maximum checking should be performed.  The default is <strong>None</strong>.<p></p>
+
+</dd>
+<dt><strong>'minstrict'</strong></dt><dd>If true, then minimum checking is strictly enforced. 
+        Otherwise, the entry input may be less than <strong>min</strong>, but will be
+        displayed using the <strong>errorbackground</strong> color.  The default is true.<p></p>
+
+</dd>
+<dt><strong>'maxstrict'</strong></dt><dd>If true, then maximum checking is strictly enforced. 
+        Otherwise, the entry input may be more than <strong>max</strong>, but will be
+        displayed using the <strong>errorbackground</strong> color.  The default is true.<p></p>
+
+</dd></dl>
+<p>    If the dictionary contains a <strong>'stringtovalue'</strong> field, it overrides
+    the normal <em>stringtovalue</em> function for the validator.  The
+    <em>stringtovalue</em> function is described below.</p>
+
+<p>    Other fields in the dictionary (apart from the core fields
+    mentioned above) are passed on to the <em>validator</em> and
+    <em>stringtovalue</em> functions as keyword arguments.</p>
+
+<p>    If <strong>validate</strong> is not a dictionary, then it is equivalent to
+    specifying it as a dictionary with a single <strong>'validator'</strong> field. 
+    For example, <code>validate = 'real'</code> is equivalent to /validate =
+    {'validator' : 'real'}/ and specifies real numbers without any
+    minimum or maximum limits and using <strong>'.'</strong> as the decimal point
+    character.</p>
+
+<p>    The standard validators accepted in the <strong>'validator'</strong> field are:</p>
+
+<dl><dt><strong>'numeric'</strong></dt><dd>An integer greater than or equal to 0.  Digits
+        only. No sign.<p></p>
+
+</dd>
+<dt><strong>'integer'</strong></dt><dd>Any integer (negative, 0 or positive) as accepted
+        by <code>string.atol()</code>.<p></p>
+
+</dd>
+<dt><strong>'hexadecimal'</strong></dt><dd>Hex number (with optional leading <strong>'0x'</strong>), as accepted
+        by <code>string.atol(text, 16)</code>.<p></p>
+
+</dd>
+<dt><strong>'real'</strong></dt><dd>A number, with or without a decimal point and optional
+        exponent (e or E), as accepted by <code>string.atof()</code>.  This
+        validator accepts a <strong>'separator'</strong> argument, which specifies
+        the character used to represent the decimal point.  The
+        default <strong>'separator'</strong> is <strong>'.'</strong>.<p></p>
+
+</dd>
+<dt><strong>'alphabetic'</strong></dt><dd>Consisting of the letters <strong>'a-z'</strong> and <strong>'A-Z'</strong>.
+        In this case, <strong>'min'</strong> and <strong>'max'</strong> specify limits on the length
+        of the text.<p></p>
+
+</dd>
+<dt><strong>'alphanumeric'</strong></dt><dd>Consisting of the letters <strong>'a-z'</strong>, <strong>'A-Z'</strong> and <strong>'0-9'</strong>.
+        In this case, <strong>'min'</strong> and <strong>'max'</strong> specify limits on the length
+        of the text.<p></p>
+
+</dd>
+<dt><strong>'time'</strong></dt><dd>Hours, minutes and seconds, in the format
+        <strong>'HH:MM:SS'</strong>, as accepted by <code>Pmw.timestringtoseconds()</code>. 
+        This validator accepts a <strong>'separator'</strong> argument, which
+        specifies the character used to separate the three fields. 
+        The default separator is <strong>':'</strong>.  The time may be negative.<p></p>
+
+</dd>
+<dt><strong>'date'</strong></dt><dd>Day, month and year, as accepted by
+        <code>Pmw.datestringtojdn()</code>.  This validator accepts a
+        <strong>'separator'</strong> argument, which specifies the character used to
+        separate the three fields.  The default is <strong>':'</strong>.  This
+        validator also accepts a <strong>'format'</strong> argument, which is passed to
+        <code>Pmw.datestringtojdn()</code> to specify the desired ordering of the
+        fields.  The default is <strong>'ymd'</strong>.<p></p>
+
+</dd></dl>
+<p>    If <strong>'validator'</strong> is a function, then it will be called whenever
+    the contents of the entry may have changed due to user action or
+    by a call to <code>setentry()</code>.  The function is called with at least
+    one argument, the first one being the new text as modified by the
+    user or <code>setentry()</code>.  The other arguments are keyword arguments
+    made up of the non-core fields of the <strong>validate</strong> dictionary.</p>
+
+<p>    The <em>validator</em> function should return <strong>Pmw.OK</strong>, <strong>Pmw.ERROR</strong> or
+    <strong>Pmw.PARTIAL</strong> as described above.  It should not perform minimum
+    and maximum checking.  This is done after the call, if it returns
+    <strong>Pmw.OK</strong>.</p>
+
+<p>    The <strong>'stringtovalue'</strong> field in the dictionary may be specified as
+    the name of one of the standard validators, the name of a
+    validator supplied by the <strong>extravalidators</strong> option, a function or
+    <strong>None</strong>.</p>
+
+<p>    The <em>stringtovalue</em> function is used to convert the entry input
+    into a value which can then be compared with any minimum or
+    maximum values specified for the validator.  If the <strong>'min'</strong> or
+    <strong>'max'</strong> fields are specified as strings, they are converted using
+    the <em>stringtovalue</em> function.  The <em>stringtovalue</em> function is
+    called with the same arguments as the <em>validator</em> function.  The
+    <em>stringtovalue</em> function for the standard number validators
+    convert the string to a number.  Those for the standard alpha
+    validators return the length of the string.  Those for the
+    standard <strong>'time'</strong> and <strong>'date'</strong> validators return the number of
+    seconds and the Julian Day Number, respectively.  See
+    <code>Pmw.stringtoreal()</code>, <code>Pmw.timestringtoseconds()</code> and
+    <code>Pmw.datestringtojdn()</code>.</p>
+
+<p>    If the validator has been specified as a function and no
+    <strong>'stringtovalue'</strong> field is given, then it defaults to the standard
+    python <code>len()</code> function.</p>
+
+<p>    If <strong>'validator'</strong> is <strong>None</strong>, no validation is performed.  However,
+    minimum and maximum checking may be performed, according to the
+    <em>stringtovalue</em> function.  For example, to limit the entry text to
+    a maximum of five characters:</p>
+
+<dl><dd><pre> Pmw.EntryField(validate = {'max' : 5})</pre></dd></dl>
+
+<p>    The validator functions for each of the standard validators can
+    be accessed as:</p>
+<dl><dd><pre> Pmw.numericvalidator
+ Pmw.integervalidator
+ Pmw.hexadecimalvalidator
+ Pmw.realvalidator
+ Pmw.alphabeticvalidator
+ Pmw.alphanumericvalidator
+ Pmw.timevalidator
+ Pmw.datevalidator</pre></dd></dl>
+
+
+<p>    Whenever the <strong>validate</strong> option is configured, the text currently
+    displayed in the entry widget is revalidated.  If it is not valid,
+    the <strong>errorbackground</strong> color is set and the <strong>invalidcommand</strong>
+    function is called.  However, the displayed text is not modified.</p>
+
+<p>    The default for <strong>validate</strong> is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.value></a>
+<dl><dt> <strong>value
+</strong></dt><dd>
+Initialisation option. Specifies the initial contents of the entry.
+    If this text is invalid, it will be displayed with the
+    <strong>errorbackground</strong> color and the <strong>invalidcommand</strong> function will be called. 
+    If both <strong>value</strong> and <strong>entry_textvariable</strong> options are specified in
+    the constructor, <strong>value</strong> will take precedence. The default is <strong>''</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.entry></a>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+The widget where the user may enter text.  Long text may be
+    scrolled horizontally by dragging with the middle mouse button. By default, this component is a Tkinter.Entry.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Entry</strong> class
+are forwarded by this megawidget to the
+<strong>entry</strong> component.
+<p></p>
+<a name=method.checkentry></a>
+<dl><dt> <strong>checkentry</strong>()</dt><dd>
+Check the validity of the current contents of the entry widget
+    and return the result.
+    If the text is not valid, set the background to <strong>errorbackground</strong> and
+    call the <strong>invalidcommand</strong> function.  If there is a variable
+    specified by the <strong>entry_textvariable</strong> option, this method should be
+    called after the <code>set()</code> method of the variable is called.  If this
+    is not done in this case, the entry widget background will not be
+    set correctly.</p>
+
+
+</dd></dl>
+<a name=method.clear></a>
+<dl><dt> <strong>clear</strong>()</dt><dd>
+Remove all text from the entry widget.  Equivalent to <code>setentry('')</code>.</p>
+
+
+</dd></dl>
+<a name=method.getvalue></a>
+<dl><dt> <strong>getvalue</strong>()</dt><dd>
+Return the text displayed by the entry.</p>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>()</dt><dd>
+Invoke the command specified by the <strong>command</strong> option as if the
+    <strong>&lt;Return&gt;</strong> key had been pressed and return the result.</p>
+
+
+</dd></dl>
+<a name=method.setentry></a>
+<dl><dt> <strong>setentry</strong>(<em>text</em>)</dt><dd>
+Same as <code>setvalue()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.setvalue></a>
+<dl><dt> <strong>setvalue</strong>(<em>text</em>)</dt><dd>
+Set the contents of the entry widget to <em>text</em> and carry out
+    validation as if the text had been entered by the user.  If the
+    text is invalid, the entry widget will not be changed and the
+    <strong>invalidcommand</strong> function will be called.  Return the validity
+    of <em>text</em>.</p>
+
+
+</dd></dl>
+<a name=method.valid></a>
+<dl><dt> <strong>valid</strong>()</dt><dd>
+Return true if the contents of the entry widget are valid.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the EntryFields.
+        self._any = Pmw.EntryField(parent,
+                labelpos = 'w',
+                label_text = 'Any:',
+                validate = None,
+                command = self.execute)
+        self._real = Pmw.EntryField(parent,
+                labelpos = 'w',
+                value = '55.5',
+                label_text = 'Real (10.0 to 99.0):',
+                validate = {'validator' : 'real',
+                        'min' : 10, 'max' : 99, 'minstrict' : 0},
+                modifiedcommand = self.changed)
+        self._odd = Pmw.EntryField(parent,
+                labelpos = 'w',
+                label_text = 'Odd length:',
+                validate = self.custom_validate,
+                value = 'ABC')
+        self._date = Pmw.EntryField(parent,
+                labelpos = 'w',
+                label_text = 'Date (in 2000):',
+                value = '2000/2/29',
+                validate = {'validator' : 'date',
+                        'min' : '2000/1/1', 'max' : '2000/12/31',
+                        'minstrict' : 0, 'maxstrict' : 0,
+                        'format' : 'ymd'},
+                )
+        now = time.localtime(time.time())
+        self._date2 = Pmw.EntryField(parent,
+                labelpos = 'w',
+                label_text = 'Date (d.m.y):',
+                value = '%d.%d.%d' % (now[2], now[1], now[0]),
+                validate = {'validator' : 'date',
+                        'format' : 'dmy', 'separator' : '.'},
+                )
+        self._time = Pmw.EntryField(parent,
+                labelpos = 'w',
+                label_text = 'Time (24hr clock):',
+                value = '8:00:00',
+                validate = {'validator' : 'time',
+                        'min' : '00:00:00', 'max' : '23:59:59',
+                        'minstrict' : 0, 'maxstrict' : 0},
+                )
+        self._comma = Pmw.EntryField(parent,
+                labelpos = 'w',
+                label_text = 'Real (with comma):',
+                value = '123,456',
+                validate = {'validator' : 'real', 'separator' : ','},
+                )
+
+        entries = (self._any, self._real, self._odd, self._date, self._date2,
+                self._time, self._comma)
+
+        for entry in entries:
+            entry.pack(fill='x', expand=1, padx=10, pady=5)
+        Pmw.alignlabels(entries)
+
+        self._any.component('entry').focus_set()
+
+    def changed(self):
+        print 'Text changed, value is', self._real.getvalue()
+
+    def execute(self):
+        print 'Return pressed, value is', self._any.getvalue()
+
+    # This implements a custom validation routine.  It simply checks
+    # if the string is of odd length.
+    def custom_validate(self, text):
+        print 'text:', text
+        if len(text) % 2 == 0:
+          return -1
+        else:
+          return 1
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 22 May 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ExampleDemo.py b/Pmw/Pmw_1_2/doc/ExampleDemo.py
new file mode 100644 (file)
index 0000000..f7ec1e7
--- /dev/null
@@ -0,0 +1,33 @@
+title = 'Pmw.EXAMPLE demonstration'
+
+# Import Pmw from this directory tree.
+import sys
+sys.path[:0] = ['../../..']
+
+import Tkinter
+import Pmw
+
+class Demo:
+    def __init__(self, parent):
+
+       # Create and pack the EXAMPLEs.
+       self.widget1 = Pmw.Counter(parent)
+       self.widget1.setentry('1')
+       self.widget1.pack()
+
+       self.widget2 = Pmw.Counter(parent, increment = 10)
+       self.widget2.setentry('100')
+       self.widget2.pack()
+
+######################################################################
+
+# Create demo in root window for testing.
+if __name__ == '__main__':
+    root = Tkinter.Tk()
+    Pmw.initialise(root)
+    root.title(title)
+
+    exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+    exitButton.pack(side = 'bottom')
+    widget = Demo(root)
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/doc/Group.gif b/Pmw/Pmw_1_2/doc/Group.gif
new file mode 100644 (file)
index 0000000..9c4d8d5
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/Group.gif differ
diff --git a/Pmw/Pmw_1_2/doc/Group.html b/Pmw/Pmw_1_2/doc/Group.html
new file mode 100644 (file)
index 0000000..b961a1f
--- /dev/null
@@ -0,0 +1,226 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.Group reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.Group</h1>
+    
+<center><IMG SRC=Group.gif ALT="" WIDTH=428 HEIGHT=209></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.Group() - 
+    frame with ring border and tag
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This megawidget consists of an interior frame with an exterior
+    ring border and an identifying tag displayed over the top edge of
+    the ring.  The programmer can create other widgets within the
+    interior frame.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.collapsedsize></a>
+<dl><dt> <strong>collapsedsize
+</strong></dt><dd>
+Initialisation option. The distance from the bottom of the tag to the bottom of the ring
+    when the groupchildsite is collapsed. The default is <strong>6</strong>.</p>
+
+
+</dd></dl>
+<a name=option.tagindent></a>
+<dl><dt> <strong>tagindent
+</strong></dt><dd>
+Initialisation option. The distance from the left edge of the ring to the left side of
+    the tag component. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.groupchildsite></a>
+<dl><dt> <strong>groupchildsite
+</strong></dt><dd>
+The frame which can contain other widgets to be grouped. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.ring></a>
+<dl><dt> <strong>ring
+</strong></dt><dd>
+This component acts as the enclosing ring around the
+    <strong>groupchildsite</strong>.  The default <strong>borderwidth</strong> is <strong>2</strong> and the
+    default <strong>relief</strong> is <strong>'groove'</strong>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.tag></a>
+<dl><dt> <strong>tag
+</strong></dt><dd>
+The identifying tag displayed over the top edge of the enclosing
+    ring.  If the pyclass for this component is <strong>None</strong>, (ie: 
+    <code>tag_pyclass = None</code>, then no tag component is created. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.collapse></a>
+<dl><dt> <strong>collapse</strong>()</dt><dd>
+Do not display the groupchildsite component.</p>
+
+
+</dd></dl>
+<a name=method.expand></a>
+<dl><dt> <strong>expand</strong>()</dt><dd>
+Display the groupchildsite component.</p>
+
+
+</dd></dl>
+<a name=method.interior></a>
+<dl><dt> <strong>interior</strong>()</dt><dd>
+Return the frame within which the programmer may create widgets. 
+    This is the same as <code>component('groupchildsite')</code>.</p>
+
+
+</dd></dl>
+<a name=method.toggle></a>
+<dl><dt> <strong>toggle</strong>()</dt><dd>
+Display the groupchildsite component if it is currently hidden and
+    hide it if it is currently displayed.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+
+        # Create and pack the Groups.
+        w = Pmw.Group(parent, tag_text='label')
+        w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+        cw = Tkinter.Label(w.interior(),
+                text = 'A group with the\ndefault Label tag')
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+        w = Pmw.Group(parent, tag_pyclass = None)
+        w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+        cw = Tkinter.Label(w.interior(), text = 'A group\nwithout a tag')
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+        radiogroups = []
+        self.var = Tkinter.IntVar()
+        self.var.set(0)
+        radioframe = Tkinter.Frame(parent)
+        w = Pmw.Group(radioframe,
+                tag_pyclass = Tkinter.Radiobutton,
+                tag_text='radiobutton 1',
+                tag_value = 0,
+                tag_variable = self.var)
+        w.pack(fill = 'both', expand = 1, side='left')
+        cw = Tkinter.Frame(w.interior(),width=200,height=20)
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+        radiogroups.append(w)
+
+        w = Pmw.Group(radioframe,
+                tag_pyclass = Tkinter.Radiobutton,
+                tag_text='radiobutton 2',
+                tag_font = Pmw.logicalfont('Helvetica', 4),
+                tag_value = 1,
+                tag_variable = self.var)
+        w.pack(fill = 'both', expand = 1, side='left')
+        cw = Tkinter.Frame(w.interior(),width=200,height=20)
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+        radiogroups.append(w)
+        radioframe.pack(padx = 6, pady = 6, expand='yes', fill='both')
+        Pmw.aligngrouptags(radiogroups)
+
+        w = Pmw.Group(parent,
+                tag_pyclass = Tkinter.Checkbutton,
+                tag_text='checkbutton',
+                tag_foreground='blue')
+        w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+        cw = Tkinter.Frame(w.interior(),width=150,height=20)
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+        w = Pmw.Group(parent,
+                tag_pyclass = Tkinter.Button,
+                tag_text='Tkinter.Button')
+        w.configure(tag_command = w.toggle)
+        w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+        cw = Tkinter.Label(w.interior(),
+                background = 'aliceblue',
+                text = 'A group with\na Button tag!?'
+        )
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+        w = Pmw.Group(parent,
+                tag_pyclass = Tkinter.Button,
+                tag_text='Show/Hide')
+        w.configure(tag_command = w.toggle)
+        w.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+        cw = Tkinter.Label(w.interior(),
+                background = 'aliceblue',
+                text = 'Now you see me.\nNow you don\'t.'
+        )
+        cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 15 November 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/HistoryText.gif b/Pmw/Pmw_1_2/doc/HistoryText.gif
new file mode 100644 (file)
index 0000000..5ee3ae3
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/HistoryText.gif differ
diff --git a/Pmw/Pmw_1_2/doc/HistoryText.html b/Pmw/Pmw_1_2/doc/HistoryText.html
new file mode 100644 (file)
index 0000000..c42dad6
--- /dev/null
@@ -0,0 +1,427 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.HistoryText reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.HistoryText</h1>
+    
+<center><IMG SRC=HistoryText.gif ALT="" WIDTH=551 HEIGHT=142></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.HistoryText() - 
+    text widget with a course-grained form of history
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="ScrolledText.html">Pmw.ScrolledText</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A history text is a scrolled text widget with added functionality
+    to maintain a history of each screen and allow editing of prior
+    screens.  Here, <em>screen</em> refers to the entire contents of the text
+    widget.  This widget does not support a fine-grained history of
+    every change made to the text.</p>
+
+<p>    Together with a few buttons and a scrolled text to display the
+    results, a history text can be used as the query-entry part of a
+    simple interactive text-based database query system.  When the
+    user enters and executes a query, the query (the entire contents
+    of the text widget) is added to the history list.  The user may
+    view previous queries and either execute them again or modify them
+    and execute the new query.  If a previously executed query is
+    modified, the user may undo or redo all changes made to the query
+    <em>before the query is executed</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+Initialisation option. If true, the <strong>borderframe</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.columnheader></a>
+<dl><dt> <strong>columnheader
+</strong></dt><dd>
+Initialisation option. If true, the <strong>columnheader</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.compressany></a>
+<dl><dt> <strong>compressany
+</strong></dt><dd>
+See <code>addhistory()</code>. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.compresstail></a>
+<dl><dt> <strong>compresstail
+</strong></dt><dd>
+See <code>addhistory()</code>. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.historycommand></a>
+<dl><dt> <strong>historycommand
+</strong></dt><dd>
+This is a callback to indicate whether the currently displayed
+    entry in the history list has a previous or next entry.  The
+    callback is given two arguments, <em>prevstate</em> and <em>nextstate</em>.  If
+    the currently displayed entry is first in the history list, then
+    <em>prevstate</em> is <strong>'disabled'</strong>, otherwise it is <strong>'normal'</strong>.  If the
+    currently displayed entry is last in the history list, then
+    <em>nextstate</em> is <strong>'disabled'</strong>, otherwise it is <strong>'normal'</strong>.  These
+    values can be used, for example, to modify the state of <strong>Next</strong> and
+    <strong>Previous</strong> buttons that call the <code>next()</code> and <code>prev()</code> methods. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.hscrollmode></a>
+<dl><dt> <strong>hscrollmode
+</strong></dt><dd>
+The horizontal scroll mode.  If <strong>'none'</strong>, the horizontal scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.rowcolumnheader></a>
+<dl><dt> <strong>rowcolumnheader
+</strong></dt><dd>
+Initialisation option. If true, the <strong>rowcolumnheader</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.rowheader></a>
+<dl><dt> <strong>rowheader
+</strong></dt><dd>
+Initialisation option. If true, the <strong>rowheader</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.scrollmargin></a>
+<dl><dt> <strong>scrollmargin
+</strong></dt><dd>
+Initialisation option. The distance between the scrollbars and the text widget. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+<a name=option.usehullsize></a>
+<dl><dt> <strong>usehullsize
+</strong></dt><dd>
+Initialisation option. If true, the size of the megawidget is determined solely by the
+    width and height options of the <strong>hull</strong> component.</p>
+<p>    Otherwise, the size of the megawidget is determined by the width
+    and height of the <strong>text</strong> component, along with the size and/or
+    existence of the other components, such as the label, the
+    scrollbars and the scrollmargin option.  All these affect the
+    overall size of the megawidget. The default is <strong>0</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.vscrollmode></a>
+<dl><dt> <strong>vscrollmode
+</strong></dt><dd>
+The vertical scroll mode.  If <strong>'none'</strong>, the vertical scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+A frame widget which snuggly fits around the text widget, to give
+    the appearance of a text border.  It is created with a border so
+    that the text widget, which is created without a border, looks
+    like it has a border. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.columnheader></a>
+<dl><dt> <strong>columnheader
+</strong></dt><dd>
+A text widget with a default height of 1 displayed above the main
+    text widget and which scrolls horizontally in sync with the
+    horizontal scrolling of the main text widget. By default, this component is a Tkinter.Text. Its component group is <strong>Header</strong>.</p>
+
+
+</dd></dl>
+<a name=component.horizscrollbar></a>
+<dl><dt> <strong>horizscrollbar
+</strong></dt><dd>
+The horizontal scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.rowcolumnheader></a>
+<dl><dt> <strong>rowcolumnheader
+</strong></dt><dd>
+A text widget displayed to the top left of the main text widget,
+    above the row header and to the left of the column header if they
+    exist.  The widget is not scrolled  automatically. By default, this component is a Tkinter.Text. Its component group is <strong>Header</strong>.</p>
+
+
+</dd></dl>
+<a name=component.rowheader></a>
+<dl><dt> <strong>rowheader
+</strong></dt><dd>
+A text widget displayed to the left of the main text widget and
+    which scrolls vertically in sync with the vertical scrolling of
+    the main text widget. By default, this component is a Tkinter.Text. Its component group is <strong>Header</strong>.</p>
+
+
+</dd></dl>
+<a name=component.text></a>
+<dl><dt> <strong>text
+</strong></dt><dd>
+The text widget which is scrolled by the scrollbars.  If the
+    <strong>borderframe</strong> option is true, this is created with a borderwidth
+    of <strong>0</strong> to overcome a known problem with text widgets:  if a widget
+    inside a text widget extends across one of the edges of the text
+    widget, then the widget obscures the border of the text widget. 
+    Therefore, if the text widget has no border, then this overlapping
+    does not occur. By default, this component is a Tkinter.Text.</p>
+
+
+</dd></dl>
+<a name=component.vertscrollbar></a>
+<dl><dt> <strong>vertscrollbar
+</strong></dt><dd>
+The vertical scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="ScrolledText.html#methods">Pmw.ScrolledText</a></strong>.
+<p></p>
+<a name=method.addhistory></a>
+<dl><dt> <strong>addhistory</strong>()</dt><dd>
+Append the currently displayed text to the history list.</p>
+<p>    If <strong>compressany</strong> is true, a new entry will be added to the history
+    list only if the currently displayed entry has changed.</p>
+
+<p>    If <strong>compresstail</strong> is true, a new entry will be added to the
+    history list only if the currently displayed entry has changed
+    <em>or</em> if it is not the last entry in the history list.</p>
+
+
+
+</dd></dl>
+<a name=method.gethistory></a>
+<dl><dt> <strong>gethistory</strong>()</dt><dd>
+Return the history list.  Each entry in the list is a 3-tuple. 
+    The first item in a history entry is the original text as added by
+    <code>addhistory()</code>.  The second item is the edited text (if the user
+    has modified the entry but <code>addhistory()</code> has not yet been called
+    on the text).  The third item specifies whether the entry should
+    currently display the original or modified text.</p>
+
+
+</dd></dl>
+<a name=method.next></a>
+<dl><dt> <strong>next</strong>()</dt><dd>
+Display the next screen in the history list.</p>
+
+
+</dd></dl>
+<a name=method.prev></a>
+<dl><dt> <strong>prev</strong>()</dt><dd>
+Display the previous screen in the history list.</p>
+
+
+</dd></dl>
+<a name=method.redo></a>
+<dl><dt> <strong>redo</strong>()</dt><dd>
+Reverse the effect of <code>undo()</code>.</p>
+
+
+</dd></dl>
+<a name=method.undo></a>
+<dl><dt> <strong>undo</strong>()</dt><dd>
+Undo all changes made since this entry was added to the history
+    list.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the PanedWidget to hold the query and result
+        # windows.
+        # !! panedwidget should automatically size to requested size
+        panedWidget = Pmw.PanedWidget(parent,
+                orient = 'vertical',
+                hull_height = 400,
+                hull_width = 550)
+        panedWidget.add('query', min = 0.05, size = 0.2)
+        panedWidget.add('buttons', min = 0.1, max = 0.1)
+        panedWidget.add('results', min = 0.05)
+        panedWidget.pack(fill = 'both', expand = 1)
+
+        # Create and pack the HistoryText.
+        self.historyText = Pmw.HistoryText(panedWidget.pane('query'),
+                text_wrap = 'none',
+                text_width = 60,
+                text_height = 10,
+                historycommand = self.statechange,
+        )
+        self.historyText.pack(fill = 'both', expand = 1)
+        self.historyText.component('text').focus()
+
+        buttonList = (
+            [20, None],
+            ['Clear', self.clear],
+            ['Undo', self.historyText.undo],
+            ['Redo', self.historyText.redo],
+            [20, None],
+            ['Prev', self.historyText.prev],
+            ['Next', self.historyText.next],
+            [30, None],
+            ['Execute', Pmw.busycallback(self.executeQuery)],
+        )
+        self.buttonDict = {}
+
+        buttonFrame = panedWidget.pane('buttons')
+        for text, cmd in buttonList:
+            if type(text) == type(69):
+                frame = Tkinter.Frame(buttonFrame, width = text)
+                frame.pack(side = 'left')
+            else:
+                button = Tkinter.Button(buttonFrame, text = text, command = cmd)
+                button.pack(side = 'left')
+                self.buttonDict[text] = button
+
+        for text in ('Prev', 'Next'):
+            self.buttonDict[text].configure(state = 'disabled')
+
+        self.results = Pmw.ScrolledText(panedWidget.pane('results'), text_wrap = 'none')
+        self.results.pack(fill = 'both', expand = 1)
+
+    def statechange(self, prevstate, nextstate):
+        self.buttonDict['Prev'].configure(state = prevstate)
+        self.buttonDict['Next'].configure(state = nextstate)
+
+    def clear(self):
+        self.historyText.delete('1.0', 'end')
+
+    def addnewlines(self, text):
+        if len(text) == 1:
+            text = text + '\n'
+        if text[-1] != '\n':
+            text = text + '\n'
+        if text[-2] != '\n':
+            text = text + '\n'
+        return text
+
+    def executeQuery(self):
+        sql = self.historyText.get()
+        self.results.insert('end', 'Query:\n' + self.addnewlines(sql))
+        self.results.see('end')
+        self.results.update_idletasks()
+        self.historyText.addhistory()
+        results = 'Results:\nfoo'
+        if len(results) &gt; 0:
+            self.results.insert('end', self.addnewlines(results))
+        self.results.see('end')
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 20 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/LabeledWidget.gif b/Pmw/Pmw_1_2/doc/LabeledWidget.gif
new file mode 100644 (file)
index 0000000..dfa6154
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/LabeledWidget.gif differ
diff --git a/Pmw/Pmw_1_2/doc/LabeledWidget.html b/Pmw/Pmw_1_2/doc/LabeledWidget.html
new file mode 100644 (file)
index 0000000..726ba08
--- /dev/null
@@ -0,0 +1,170 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.LabeledWidget reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.LabeledWidget</h1>
+    
+<center><IMG SRC=LabeledWidget.gif ALT="" WIDTH=163 HEIGHT=116></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.LabeledWidget() - 
+    frame with label
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This megawidget consists of an interior frame with an associated
+    label which can be positioned on any side of the frame.  The
+    programmer can create other widgets within the interior frame.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'nsew'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.labelchildsite></a>
+<dl><dt> <strong>labelchildsite
+</strong></dt><dd>
+The frame which can contain other widgets to be labelled. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.interior></a>
+<dl><dt> <strong>interior</strong>()</dt><dd>
+Return the frame within which the programmer may create widgets. 
+    This is the same as <code>component('labelchildsite')</code>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+
+        # Create a frame to put the LabeledWidgets into
+        frame = Tkinter.Frame(parent, background = 'grey90')
+        frame.pack(fill = 'both', expand = 1)
+
+        # Create and pack the LabeledWidgets.
+        column = 0
+        row = 0
+        for pos in ('n', 'nw', 'wn', 'w'):
+            lw = Pmw.LabeledWidget(frame,
+                    labelpos = pos,
+                    label_text = pos + ' label')
+            lw.component('hull').configure(relief='sunken', borderwidth=2)
+            lw.grid(column=column, row=row, padx=10, pady=10)
+            cw = Tkinter.Button(lw.interior(), text='child\nsite')
+            cw.pack(padx=10, pady=10, expand='yes', fill='both')
+
+            # Get ready for next grid position.
+            column = column + 1
+            if column == 2:
+              column = 0
+              row = row + 1
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 8 November 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MainMenuBar.gif b/Pmw/Pmw_1_2/doc/MainMenuBar.gif
new file mode 100644 (file)
index 0000000..aa7a7bf
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/MainMenuBar.gif differ
diff --git a/Pmw/Pmw_1_2/doc/MainMenuBar.html b/Pmw/Pmw_1_2/doc/MainMenuBar.html
new file mode 100644 (file)
index 0000000..4f0fea8
--- /dev/null
@@ -0,0 +1,421 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MainMenuBar reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MainMenuBar</h1>
+    
+<center><IMG SRC=MainMenuBar.gif ALT="" WIDTH=474 HEIGHT=29></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MainMenuBar() - 
+    manager for toplevel native menus
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaArchetype.html">Pmw.MegaArchetype</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This class is a wrapper for the Tkinter.Menu class.  It should be
+    used as the main menu of toplevel windows. The class is similar
+    to <a href="MenuBar.html">Pmw.MenuBar</a>, but should be used when native menus are required.
+    See the Tkinter.Menu documentation for full details.</p>
+
+<p>    This class should be created as the child of a Tkinter.Toplevel
+    and should then be specified as the menu associated with the
+    toplevel, using the toplevel's <code>configure()</code> method.  For example:</p>
+<dl><dd><pre> # Create a Pmw.MegaToplevel.
+ megaToplevel = Pmw.MegaToplevel()
+ # Get the Tkinter.Toplevel from Pmw.MegaToplevel.
+ toplevel = megaToplevel.interior()
+ # Create the menu bar for the toplevel.
+ menuBar = Pmw.MainMenuBar(toplevel)
+ # Configure the toplevel to use the menuBar.
+ toplevel.configure(menu = menuBar)</pre></dd></dl>
+
+
+<p>    There are methods to add menus, both as toplevel menus and
+    sub-menus, and for adding menu items to the menus.  Each menu item
+    may have help text to be displayed by a <a href="Balloon.html">Pmw.Balloon</a>.  Each menu and
+    cascaded menu (sub-menu) is referenced by name which is supplied
+    on creation.</p>
+
+<p>    This megawidget is derived from <a href="MegaArchetype.html">Pmw.MegaArchetype</a> (not <a href="MegaWidget.html">Pmw.MegaWidget</a>
+    like most other megawidgets), with the hull class being
+    Tkinter.Menu.</p>
+
+<p>    (Note that due to bugs in Tk's menubar functionality, balloon help
+    has not been implemented and status help does not work properly.)</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.balloon></a>
+<dl><dt> <strong>balloon
+</strong></dt><dd>
+Specifies a <a href="Balloon.html">Pmw.Balloon</a> to display the help text for menu items.  If
+    <strong>None</strong>, no help is displayed.  If the balloon has an associated
+    <a href="MessageBar.html">Pmw.MessageBar</a>, the help text will also be displayed there.</p>
+<p>    Due to a bug in some versions of Tk (8.0 and possible others),
+    help text will not be displayed by the balloon.  However, help
+    text will be displayed in the balloon's associated messagebar. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.hotkeys></a>
+<dl><dt> <strong>hotkeys
+</strong></dt><dd>
+Initialisation option. If true, keyboard accelerators will be assigned to each menu item. 
+    Keyboard accelerators can be used to access the menus without
+    using the mouse.  The accelerator character is always one of the
+    alphanumeric characters in the text label of the menu item and is
+    indicated by an underline.</p>
+<p>    To select a menu, simultaneously press the <strong>&lt;Alt&gt;</strong> key and the
+    accelerator character indicated on a toplevel menu item.  The
+    arrows keys can then be used to select other menus and menu items. 
+    To invoke a menu item, press <strong>&lt;Return&gt;</strong> or press the accelerator
+    character indicated on the menu item.</p>
+
+<p>    Each accelerator character will be assigned automatically unless
+    <em>traverseSpec</em> is supplied to the <code>addmenu()</code>, <code>addmenuitem()</code> or
+    <code>addcascademenu()</code> methods.  The automatically selected
+    accelerator character for a menu item is the first character in
+    the label text that has not already been used as an accelerator in
+    the menu containing the menu item.</p>
+
+<p>    If <em>traverseSpec</em> is given, it must be either an integer or a
+    character.  If an integer, it specifies the index of the character
+    in the label text to use as the accelerator character.  If a
+    character, it specifies the character to use as the accelerator
+    character. The default is <strong>1</strong>.</p>
+
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+The toplevel menu widget. By default, this component is a Tkinter.Menu.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Dynamic components</h3></dt><dd>
+<p>
+        Menu components are created dynamically by the <code>addmenu()</code> and
+        <code>addcascademenu()</code> methods.  By default, these are of type
+        Tkinter.Menu and are created with a component group of <strong>Menu</strong>.</p>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaArchetype.html#methods">Pmw.MegaArchetype</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Menu</strong> class
+are forwarded by this megawidget to the
+<strong>hull</strong> component.
+<p></p>
+<a name=method.addcascademenu></a>
+<dl><dt> <strong>addcascademenu</strong>(<em>parentMenuName</em>, <em>menuName</em>, <em>statusHelp</em> = <strong>''</strong>, <em>traverseSpec</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Add a cascade menu (sub-menu) to the menu <em>parentMenuName</em>.  The
+    <em>menuName</em> argument must not be the same as any menu already
+    created using the <code>addmenu()</code> or <code>addcascademenu()</code> methods.</p>
+<p>    A menu item in the parent menu is created (with the
+    <code>add_cascade()</code> method of the parent menu) using all keyword
+    arguments except <strong>tearoff</strong> and <strong>name</strong>.</p>
+
+<p>    If the <strong>label</strong> keyword argument is not given, the <strong>label</strong> option
+    of the menu item defaults to <em>menuName</em>.  If the <strong>underline</strong>
+    keyword argument is not given (and the <strong>hotkeys</strong> megawidget option
+    is true) the <strong>underline</strong> option is determined as described under
+    <strong>hotkeys</strong> and is used to specify the keyboard accelerator.</p>
+
+<p>    The <em>statusHelp</em> argument is used as the help string for the menu
+    item.  This is displayed using the <code>showstatus()</code> method of the
+    balloon.</p>
+
+<p>    The <strong>tearoff</strong> and <strong>name</strong> keyword arguments, if present, are passed
+    to the constructor of the menu.  See Tkinter.Menu for details of
+    these options.  The menu is created as a component named
+    <em>menuName</em>.</p>
+
+
+
+</dd></dl>
+<a name=method.addmenu></a>
+<dl><dt> <strong>addmenu</strong>(<em>menuName</em>, <em>balloonHelp</em>, <em>statusHelp</em> = <strong>None</strong>, <em>traverseSpec</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Add a cascade menu to the toplevel menu.  The <em>menuName</em> argument
+    must not be the same as any menu already created using the
+    <code>addmenu()</code> or <code>addcascademenu()</code> methods.</p>
+<p>    A menu item in the toplevel menu is created (with the
+    <code>add_cascade()</code> method) using all keyword arguments except
+    <strong>tearoff</strong> and <strong>name</strong>.</p>
+
+<p>    If the <strong>label</strong> keyword argument is not given, the <strong>label</strong> option
+    of the menu button defaults to <em>menuName</em>.  If the <strong>underline</strong>
+    keyword argument is not given (and the <strong>hotkeys</strong> megawidget option
+    is true) the <strong>underline</strong> option is determined as described under
+    <strong>hotkeys</strong> and is used to specify the keyboard accelerator.</p>
+
+<p>    The <em>statusHelp</em> argument is used as the help string for the menu
+    item.  This is displayed using the <code>showstatus()</code> method of the
+    balloon.  Currently <em>balloonHelp</em> is not used, due to a bug in Tk
+    version 8.0.</p>
+
+<p>    The <strong>tearoff</strong> and <strong>name</strong> keyword arguments, if present, are passed
+    to the constructor of the menu.  See Tkinter.Menu for details of
+    these options.  The menu is created as a component named
+    <em>menuName</em>.</p>
+
+
+
+</dd></dl>
+<a name=method.addmenuitem></a>
+<dl><dt> <strong>addmenuitem</strong>(<em>menuName</em>, <em>itemType</em>, <em>statusHelp</em> = <strong>''</strong>, <em>traverseSpec</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Add a menu item to the menu <em>menuName</em>.  The kind of menu item is
+    given by <em>itemType</em> and may be one of <strong>command</strong>, <strong>separator</strong>,
+    <strong>checkbutton</strong>, <strong>radiobutton</strong> or <strong>cascade</strong> (although cascade menus
+    are better added using the <code>addcascademenu()</code> method).  Any
+    keyword arguments present will be passed to the menu when creating
+    the menu item.  See Tkinter.Menu for the valid options for each
+    item type.  In addition, a keyboard accelerator may be
+    automatically given to the item, as described under <strong>hotkeys</strong>. </p>
+<p>    When the mouse is moved over the menu item, the <em>helpString</em> will
+    be displayed by the <strong>balloon</strong>'s <strong>statuscommand</strong>.</p>
+
+
+
+</dd></dl>
+<a name=method.deletemenu></a>
+<dl><dt> <strong>deletemenu</strong>(<em>menuName</em>)</dt><dd>
+Delete the menu <em>menuName</em> and all its items.  The menu may either
+    be a toplevel menu or a cascade menu.</p>
+
+
+</dd></dl>
+<a name=method.deletemenuitems></a>
+<dl><dt> <strong>deletemenuitems</strong>(<em>menuName</em>, <em>start</em>, <em>end</em> = <strong>None</strong>)</dt><dd>
+Delete menu items from the menu <em>menuName</em>.  If <em>end</em> is not
+    given, the <em>start</em> item is deleted.  Otherwise all items from
+    <em>start</em> to <em>end</em> are deleted.</p>
+
+
+</dd></dl>
+<a name=method.disableall></a>
+<dl><dt> <strong>disableall</strong>()</dt><dd>
+Disable all toplevel menus.</p>
+
+
+</dd></dl>
+<a name=method.enableall></a>
+<dl><dt> <strong>enableall</strong>()</dt><dd>
+Enable all toplevel menus.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create button to launch the toplevel with main menubar.
+        w = Tkinter.Button(parent, text = 'Show Pmw.MainMenuBar demo',
+                command = lambda parent=parent: MainMenuBarToplevel(parent))
+        w.pack(padx = 8, pady = 8)
+
+class MainMenuBarToplevel:
+    def __init__(self, parent):
+        # Create the toplevel to contain the main menubar.
+        megaToplevel = Pmw.MegaToplevel(parent, title = title)
+        toplevel = megaToplevel.interior()
+
+        # Create the Balloon for this toplevel.
+        self.balloon = Pmw.Balloon(toplevel)
+
+        # Create and install the MenuBar.
+        menuBar = Pmw.MainMenuBar(toplevel,
+                balloon = self.balloon)
+        toplevel.configure(menu = menuBar)
+        self.menuBar = menuBar
+
+        # Add some buttons to the MainMenuBar.
+        menuBar.addmenu('File', 'Close this window or exit')
+        menuBar.addmenuitem('File', 'command', 'Close this window',
+                command = PrintOne('Action: close'),
+                label = 'Close')
+        menuBar.addmenuitem('File', 'separator')
+        menuBar.addmenuitem('File', 'command', 'Exit the application',
+                command = PrintOne('Action: exit'),
+                label = 'Exit')
+
+        menuBar.addmenu('Edit', 'Cut, copy or paste')
+        menuBar.addmenuitem('Edit', 'command', 'Delete the current selection',
+                command = PrintOne('Action: delete'),
+                label = 'Delete')
+
+        menuBar.addmenu('Options', 'Set user preferences')
+        menuBar.addmenuitem('Options', 'command', 'Set general preferences',
+                command = PrintOne('Action: general options'),
+                label = 'General...')
+
+        # Create a checkbutton menu item.
+        self.toggleVar = Tkinter.IntVar()
+        # Initialise the checkbutton to 1:
+        self.toggleVar.set(1)
+        menuBar.addmenuitem('Options', 'checkbutton', 'Toggle me on/off',
+                label = 'Toggle',
+                command = self._toggleMe,
+                variable = self.toggleVar)
+        self._toggleMe()
+
+        menuBar.addcascademenu('Options', 'Size',
+                'Set some other preferences', traverseSpec = 'z', tearoff = 1)
+        for size in ('tiny', 'small', 'average', 'big', 'huge'):
+            menuBar.addmenuitem('Size', 'command', 'Set size to ' + size,
+                    command = PrintOne('Action: size ' + size),
+                    label = size)
+
+        menuBar.addmenu('Help', 'User manuals', name = 'help')
+        menuBar.addmenuitem('Help', 'command', 'About this application',
+                command = PrintOne('Action: about'),
+                label = 'About...')
+
+        # Create and pack the main part of the window.
+        self.mainPart = Tkinter.Label(toplevel,
+                text = 'This is the\nmain part of\nthe window',
+                background = 'black',
+                foreground = 'white',
+                padx = 30,
+                pady = 30)
+        self.mainPart.pack(fill = 'both', expand = 1)
+
+        # Create and pack the MessageBar.
+        self.messageBar = Pmw.MessageBar(toplevel,
+                entry_width = 40,
+                entry_relief='groove',
+                labelpos = 'w',
+                label_text = 'Status:')
+        self.messageBar.pack(fill = 'x', padx = 10, pady = 10)
+        self.messageBar.message('state',
+            'Balloon/status help not working properly - Tk menubar bug')
+
+        buttonBox = Pmw.ButtonBox(toplevel)
+        buttonBox.pack(fill = 'x')
+        buttonBox.add('Disable\nall', command = menuBar.disableall)
+        buttonBox.add('Enable\nall', command = menuBar.enableall)
+        buttonBox.add('Create\nmenu', command = self.add)
+        buttonBox.add('Delete\nmenu', command = self.delete)
+        buttonBox.add('Create\nitem', command = self.additem)
+        buttonBox.add('Delete\nitem', command = self.deleteitem)
+
+        # Configure the balloon to displays its status messages in the
+        # message bar.
+        self.balloon.configure(statuscommand = self.messageBar.helpmessage)
+
+        self.testMenuList = []
+
+    def _toggleMe(self):
+        print 'Toggle value:', self.toggleVar.get()
+
+    def add(self):
+        if len(self.testMenuList) == 0:
+            num = 0
+        else:
+            num = self.testMenuList[-1]
+        num = num + 1
+        name = 'Menu%d' % num
+        self.testMenuList.append(num)
+
+        self.menuBar.addmenu(name, 'This is ' + name)
+
+    def delete(self):
+        if len(self.testMenuList) == 0:
+            self.menuBar.bell()
+        else:
+            num = self.testMenuList[0]
+            name = 'Menu%d' % num
+            del self.testMenuList[0]
+            self.menuBar.deletemenu(name)
+
+    def additem(self):
+        if len(self.testMenuList) == 0:
+            self.menuBar.bell()
+        else:
+            num = self.testMenuList[-1]
+            menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName)
+            if menu.index('end') is None:
+                label = 'item X'
+            else:
+                label = menu.entrycget('end', 'label') + 'X'
+            self.menuBar.addmenuitem(menuName, 'command', 'Help for ' + label,
+                    command = PrintOne('Action: ' + menuName + ': ' + label),
+                    label = label)
+            
+    def deleteitem(self):
+        if len(self.testMenuList) == 0:
+            self.menuBar.bell()
+        else:
+            num = self.testMenuList[-1]
+            menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName)
+            if menu.index('end') is None:
+                self.menuBar.bell()
+            else:
+                self.menuBar.deletemenuitems(menuName, 0)
+            
+class PrintOne:
+    def __init__(self, text):
+        self.text = text
+
+    def __call__(self):
+        print self.text
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 22 April 2000
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MegaArchetype.html b/Pmw/Pmw_1_2/doc/MegaArchetype.html
new file mode 100644 (file)
index 0000000..03f6266
--- /dev/null
@@ -0,0 +1,459 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MegaArchetype reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MegaArchetype</h1>
+    
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MegaArchetype() - 
+    abstract base class for all Pmw megawidgets
+</p>
+
+
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This class is the basis for all Pmw megawidgets.  It provides
+    methods to manage options and component widgets.</p>
+
+<p>    This class is normally used as a base class for other classes.  If
+    the <em>hullClass</em> argument is specified, such as in the <a href="MegaWidget.html">Pmw.MegaWidget</a>
+    and <a href="MegaToplevel.html">Pmw.MegaToplevel</a> classes, a container widget is created to act
+    as the parent of all other component widgets.  Classes derived
+    from these sub classes create other component widgets and options
+    to implement megawidgets that can be used in applications. </p>
+
+<p>    If no <em>hullClass</em> argument is given to the constructor, no
+    container widget is created and only the option configuration
+    functionality is available.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+<p>
+        A megawidget is generally made up of other widgets packed
+        within the megawidget's containing widget.  These sub-widgets
+        are called the <em>components</em> of the megawidget and are given
+        logical names for easy reference.  The component mechanism
+        allows the user of a megawidget to gain controlled access to
+        some of the internals of the megawidget, for example to call a
+        method of a component or to set a component's configuration
+        options.</p>
+
+<p>        <strong>Sub components:</strong> If a component is itself a megawidget containing
+        sub-components, then these sub-components can be referred to
+        using the notation <em>component_subcomponent</em>.  For example,
+        <a href="ComboBox.html">Pmw.ComboBox</a> has a component named <strong>entryfield</strong> which is an
+        instance of <a href="EntryField.html">Pmw.EntryField</a>, which itself has a Tkinter.Entry
+        component named <strong>entry</strong>.  In the context of the combobox, this
+        entry widget can be referred to as <strong>entryfield_entry</strong>.</p>
+
+<p>        <strong>Component aliases:</strong> Because the sub-component notation may
+        make component names inconveniently long, components and
+        sub-components can be aliased to simpler names.  For example,
+        the <strong>entryfield_entry</strong> sub-component of <a href="ComboBox.html">Pmw.ComboBox</a> is aliased
+        to simply <strong>entry</strong>.  If there is no conflict in component
+        names, sub-component names are usually aliased to the name of
+        the "leaf" component.</p>
+
+<p>        <strong>Component groups:</strong> Similar components of a megawidget can be
+        given a <em>group</em> name, which allows all components of a group
+        to be referenced using the one group name.  For example, the
+        two arrow components of <a href="Counter.html">Pmw.Counter</a> have a group name of <strong>Arrow</strong>. 
+        Also, megawidgets that can create an unlimited number of
+        similar components, such as <a href="ButtonBox.html">Pmw.ButtonBox</a>, create each of these
+        components with the same group name.  By convention, group
+        names begin with a capital letter.</p>
+<p>        </p>
+
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+<p>
+        A megawidget defines options which allow the megawidget user
+        to modify the appearance and behaviour of the megawidget. 
+        Using the same technique as Tkinter widgets, the values of
+        megawidget options may be set in calls to the constructor and
+        to <code>configure()</code> and the values may be queried by calls to
+        <code>cget()</code> and <code>configure()</code>.  Like Tkinter widgets, megawidget
+        options are initialised with default values.  Also, if the
+        <em>useTkOptionDb</em> option to <code>Pmw.initialise()</code> has been set,
+        then the Tk option database will be queried to get the initial
+        values.  Strings found in the option database are converted
+        to python objects (integer, float, tuple, dictionary, etc)
+        using a restricted <code>eval()</code> call.  Anything that is not accepted by
+        <code>eval()</code> is treated as a string.</p>
+
+<p>        <strong>Inherited options:</strong> As well as the options defined in a class,
+        a derived class inherits all options of its base classes.  The
+        default value of an option defined by a base class may be
+        modified by the derived class.</p>
+
+<p>        <strong>Initialisation options:</strong> Some megawidget options can only be
+        set in the call to the constructor.  These are called
+        <em>initialisation options</em>.  Unlike normal configuration
+        options, they cannot be set by calling the <code>configure()</code>
+        method.</p>
+
+<p>        <strong>Component options:</strong> Options of the components of a megawidget
+        can be referred to using the notation <em>component_option</em>. 
+        Like the megawidget options, component options can be used in
+        calls to the constructor and to the <code>cget()</code> and <code>configure()</code>
+        methods.  For example, the <strong>state</strong> option of the Tkinter.Text
+        <strong>text</strong> component of <a href="ScrolledText.html">Pmw.ScrolledText</a> may be set by calling</p>
+<dl><dd><pre> widget.configure(text_state = 'disabled')</pre></dd></dl>
+
+
+<p>        Sub-components, component aliases and component groups may
+        also be combined with options.  For example, the <strong>state</strong>
+        option of the <strong>entryfield_entry</strong> component of <a href="ComboBox.html">Pmw.ComboBox</a>
+        may be set by calling</p>
+<dl><dd><pre> combobox.configure(entryfield_entry_state = 'normal')</pre></dd></dl>
+
+
+<p>        Since it has an alias, it is more convenient to use the
+        equivalent form</p>
+<dl><dd><pre> combobox.configure(entry_state = 'normal')</pre></dd></dl>
+
+
+<p>        Also, the background color of both arrows of <a href="Counter.html">Pmw.Counter</a>
+        can be set using the <strong>Arrow</strong> component group.</p>
+<dl><dd><pre> counter.configure(Arrow_background = 'aliceblue')</pre></dd></dl>
+
+
+<p>    </p>
+
+
+</dd>
+<dt> <h3>The pyclass component option</h3></dt><dd>
+<p>
+        The <strong>pyclass</strong> component option is a special notation that can
+        be used to specify a non-default python class for a component. 
+        This can only be used when the component is being constructed. 
+        For a component created during the construction of its parent
+        megawidget, this option must be given to the constructor in
+        the form <em>component_pyclass</em>.  For example, to change the
+        python class of the <strong>text</strong> sub-component of <a href="TextDialog.html">Pmw.TextDialog</a>
+        to a class <strong>FontText.Text</strong></p>
+<dl><dd><pre> dialog = Pmw.TextDialog(text_pyclass = FontText.Text)</pre></dd></dl>
+
+
+<p>        For components created after the construction of the parent
+        megawidget, the <strong>pyclass</strong> option must be passed into the
+        method which constructs the component.  For example, to set
+        the python class of a button in <a href="ButtonBox.html">Pmw.ButtonBox</a> to a class
+        <strong>MyButton</strong>:</p>
+<dl><dd><pre> buttonBox.add('special', pyclass = MyButton)</pre></dd></dl>
+
+
+<p>        The new python class of the component must support all methods
+        and options that are used by the megawidget when operating on
+        the component.  The exact interface required for each
+        component is not documented.  You will have to examine the Pmw
+        source code.  However, any class derived from the default
+        class of a component can be used as the new class of the
+        component, as long as all of the original methods and options
+        are still supported.  For example, any class derived from
+        <strong>Tkinter.Text</strong> can be used as the class of the <strong>text</strong>
+        sub-component of <a href="TextDialog.html">Pmw.TextDialog</a>. </p>
+
+<p>        The <strong>pyclass</strong> component option should not be confused with the
+        <strong>class</strong> option that some of the Tk widgets support.  The
+        <strong>class</strong> option sets the Tk option database class for the
+        widget and is used by Tk to query the database for the default
+        values of the widget's other options.  The name <strong>pyclass</strong> was
+        chosen so that it did not conflict with any known Tk options.</p>
+
+<p>    </p>
+
+
+</dd>
+<dt> <h3>Construction</h3></dt><dd>
+<p>
+        The constructors of classes derived from this class all accept
+        the same arguments:  one positional argument and any number of
+        keyword arguments.  The positional argument defaults to <strong>None</strong>
+        (meaning the root window) and specifies the widget to use as
+        the parent when creating the 
+        megawidget's <strong>hull</strong> component.  The keyword arguments define
+        initial values for options.  The format for the constructors
+        of derived classes is:</p>
+
+<dl><dd><pre>   def __init__(self, parent = None, **kw):</pre></dd></dl>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+<a name=method.addoptions></a>
+<dl><dt> <strong>addoptions</strong>(<em>optionDefs</em>)</dt><dd>
+Add additional options for this megawidget.  The <em>optionDefs</em>
+    argument is treated in the same way as for the <code>defineoptions()</code>
+    method.</p>
+<p>    This method is for use by derived classes.  It is only used if a
+    megawidget should conditionally define some options, perhaps
+    depending on the value of other options.  Usually, megawidgets
+    unconditionally define all their options in the call to
+    <code>defineoptions()</code> and do not need to use <code>addoptions()</code>.  This
+    method must be called after the call to <code>defineoptions()</code> and
+    before the call to <code>initialiseoptions()</code>.</p>
+
+
+
+</dd></dl>
+<a name=method.cget></a>
+<dl><dt> <strong>cget</strong>(<em>option</em>)</dt><dd>
+Return the current value of <em>option</em> (which should be in the
+    format described in the <strong>Options</strong> section).  This method is also
+    available using object subscripting, for example
+    <code>myWidget['font']</code>.  Unlike Tkinter's cget(), which always returns
+    a string, this method returns the same value and type as used when
+    the option was set (except where <em>option</em> is a component option
+    and the component is a Tkinter widget, in which case it returns
+    the string returned by Tcl/Tk).</p>
+
+
+</dd></dl>
+<a name=method.component></a>
+<dl><dt> <strong>component</strong>(<em>name</em>)</dt><dd>
+Return the component widget whose name is <em>name</em>.  This
+    allows the user of a megawidget to access and configure component
+    widgets directly.</p>
+
+
+</dd></dl>
+<a name=method.componentaliases></a>
+<dl><dt> <strong>componentaliases</strong>()</dt><dd>
+Return the list of aliases for components.  Each item in the list
+    is a tuple whose first item is the name of the alias and whose
+    second item is the name of the component or sub-component it
+    refers to.</p>
+
+
+</dd></dl>
+<a name=method.componentgroup></a>
+<dl><dt> <strong>componentgroup</strong>(<em>name</em>)</dt><dd>
+Return the group of the component whose name is <em>name</em> or <strong>None</strong>
+    if it does not have a group.</p>
+
+
+</dd></dl>
+<a name=method.components></a>
+<dl><dt> <strong>components</strong>()</dt><dd>
+Return a sorted list of names of the components of this
+    megawidget.</p>
+
+
+</dd></dl>
+<a name=method.configure></a>
+<dl><dt> <strong>configure</strong>(<em>option</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Query or configure the megawidget options.</p>
+<p>    If no arguments are given, return a tuple consisting of all
+    megawidget options and values, each as a 5-element tuple
+    (<em>name</em>, <em>resourceName</em>, <em>resourceClass</em>, <em>default</em>, <em>value</em>).
+    This is in the same format as the value returned by the standard
+    Tkinter <code>configure()</code> method, except that the resource name is
+    always the same as the option name and the resource class is the
+    option name with the first letter capitalised.</p>
+
+<p>    If one argument is given, return the 5 element tuple for <em>option</em>.</p>
+
+<p>    Otherwise, set the configuration options specified by the keyword
+    arguments.  Each key should be in the format described in the
+    <strong>Options</strong> section.</p>
+
+
+
+</dd></dl>
+<a name=method.createcomponent></a>
+<dl><dt> <strong>createcomponent</strong>(<em>componentName</em>, <em>componentAliases</em>, <em>componentGroup</em>, <em>widgetClass</em>, *<em>widgetArgs</em>, **<em>kw</em>)</dt><dd>
+Create a component widget by calling <em>widgetClass</em> with the
+    arguments given by <em>widgetArgs</em> and any keyword arguments.  The
+    <em>componentName</em> argument is the name by which the component will
+    be known and must not contain the underscore, <strong>'_'</strong>, character. 
+    The <em>componentGroup</em> argument specifies the group of the
+    component.  The <em>componentAliases</em> argument is a sequence of
+    2-element tuples, whose first item is an alias name and whose
+    second item is the name of the component or sub-component it is to
+    refer to.</p>
+<p>    If this method is called during megawidget construction, any
+    component options supplied to the megawidget constructor which
+    refer to this component (by <em>componentName</em> or <em>componentGroup</em>)
+    are added to the <em>kw</em> dictionary before calling <em>widgetClass</em>.  If
+    the dictionary contains a <strong>'pyclass'</strong> key, then this item is
+    removed from the dictionary and the value is used instead of
+    <em>widgetClass</em>.  For more details see <strong>The pyclass component option</strong>
+    section.</p>
+
+<p>    This method may be called by derived classes during or after
+    megawidget construction.  It returns the instance of the class
+    created.</p>
+
+
+
+</dd></dl>
+<a name=method.createlabel></a>
+<dl><dt> <strong>createlabel</strong>(<em>parent</em>, <em>childCols</em> = <strong>1</strong>, <em>childRows</em> = <strong>1</strong>)</dt><dd>
+Create a <strong>Tkinter.Label</strong> component named <strong>'label'</strong> in the <em>parent</em>
+    widget.  This is a convenience method used by several megawidgets
+    that require an optional label.  The widget must have options
+    named <strong>labelpos</strong> and <strong>labelmargin</strong>.  If <strong>labelpos</strong> is <strong>None</strong>, no
+    label is created.  Otherwise, a label is created and positioned
+    according to the value of <strong>labelpos</strong> and <strong>labelmargin</strong>.  The label
+    is added to the parent using the <code>grid()</code> method, with <em>childCols</em>
+    and <em>childRows</em> indicating how many rows and columns the label
+    should span.  Note that all other child widgets of the parent
+    <em>must</em> be added to the parent using the <code>grid()</code> method.  The
+    <code>createlabel()</code> method may be called by derived classes during
+    megawidget construction.</p>
+
+
+</dd></dl>
+<a name=method.defineoptions></a>
+<dl><dt> <strong>defineoptions</strong>(<em>keywords</em>, <em>optionDefs</em>, <em>dynamicGroups</em> = <strong>()</strong>)</dt><dd>
+Create options for this megawidget.  The <em>optionDefs</em> argument
+    defines the options.  It is a sequence of 3-element tuples,
+    (<em>name</em>, <em>default</em>, <em>callback</em>), where <em>name</em> is the name of the
+    option, <em>default</em> is its default value and <em>callback</em> is the
+    function to call when the value of the option is set by a call to
+    <code>configure()</code>.  The <em>keywords</em> argument should be the keyword
+    arguments passed in to the constructor of the megawidget.  The user
+    may override the default value of an option by supplying a keyword
+    argument to the constructor.</p>
+<p>    If any option created by a base class is also defined by
+    <em>optionDefs</em>, then the derived class's default value will take
+    precedence over the base class's.  If the <em>callback</em> field is not
+    <strong>None</strong>, then this will also override the callback set by the base
+    class.</p>
+
+<p>    If <em>callback</em> is <strong>Pmw.INITOPT</strong>, then the option is an
+    <em>initialisation option</em>.</p>
+
+<p>    The <em>dynamicGroups</em> argument contains a list of the groups of the
+    components created dynamically by this megawidget.  If a group is
+    included in this list, then it not an error if a keyword argument
+    for the group is given to the constructor or to <code>configure()</code>,
+    even when no components with this group have been created.</p>
+
+<p>    If <code>defineoptions()</code> is called, it must be called once in the
+    megawidget constructor before the call to the constructor of the
+    base class and there must be a matching call to
+    <code>initialiseoptions()</code> at the end of the constructor.</p>
+
+
+
+</dd></dl>
+<a name=method.destroy></a>
+<dl><dt> <strong>destroy</strong>()</dt><dd>
+Destroy the <strong>hull</strong> component widget, if it exists, including all
+    of its children.</p>
+
+
+</dd></dl>
+<a name=method.destroycomponent></a>
+<dl><dt> <strong>destroycomponent</strong>(<em>name</em>)</dt><dd>
+Remove the megawidget component called <em>name</em>.  This method may be
+    called by derived classes to destroy a megawidget component.  It
+    destroys the component widget and then removes all record of the
+    component from the megawidget.</p>
+
+
+</dd></dl>
+<a name=method.hulldestroyed></a>
+<dl><dt> <strong>hulldestroyed</strong>()</dt><dd>
+Return true if the Tk widget corresponding to the <strong>hull</strong> component
+    has been destroyed.</p>
+
+
+</dd></dl>
+<a name=method.initialiseoptions></a>
+<dl><dt> <strong>initialiseoptions</strong>(<em>dummy</em> = <strong>None</strong>)</dt><dd>
+Check keyword arguments and call option callback functions.  This
+    method must be called, at the end of a megawidget constructor, if
+    and only if <code>defineoptions()</code> was also called in the constructor. 
+    The <em>dummy</em> argument is not required, but is retained for
+    backwards compatibility.</p>
+<p>    It checks that all keyword arguments given to the constructor have
+    been used.  If not, it raises an error indicating which arguments
+    were unused.  A keyword is defined to be used if, during the
+    construction of a megawidget, it is defined in a call to
+    <code>defineoptions()</code> or <code>addoptions()</code> (by the megawidget or one of
+    its base classes), or it references, by name, a component of the
+    megawidget, or it references, by group, at least one component. 
+    It also calls the configuration callback function for all options
+    that have a callback.</p>
+
+<p>    This method is only effective when called by the constructor of
+    the <em>leaf</em> class, that is, the class in the class hierarchy which
+    first called <code>defineoptions()</code>.  For all other classes in the
+    class hierarchy (base classes), the method returns immediately.</p>
+
+
+
+</dd></dl>
+<a name=method.interior></a>
+<dl><dt> <strong>interior</strong>()</dt><dd>
+Return the widget framing the interior space in which any children
+    of this megawidget should be created.  By default, this returns
+    the <strong>hull</strong> component widget, if one was created, or <strong>None</strong>
+    otherwise.  A subclass should use the widget returned by
+    <code>interior()</code> as the parent of any components or sub-widgets it
+    creates.  Megawidgets which can be further subclassed, such as
+    <a href="Dialog.html">Pmw.Dialog</a>, should redefine this method to return the widget in
+    which subclasses should create children.  The overall containing
+    widget is always available as the <strong>hull</strong> component.</p>
+
+
+</dd></dl>
+<a name=method.isinitoption></a>
+<dl><dt> <strong>isinitoption</strong>(<em>option</em>)</dt><dd>
+If <em>option</em> is an initialisation option, return true.  Otherwise,
+    return false (the option is a configuration option).  The <em>option</em>
+    argument must be an option of this megawidget, not an option of a
+    component.  Otherwise an exception is raised.</p>
+
+
+</dd></dl>
+<a name=method.options></a>
+<dl><dt> <strong>options</strong>()</dt><dd>
+Return a sorted list of this megawidget's options.  Each item in
+    the list is a 3-element tuple, (<em>option</em>, <em>default</em>, <em>isinit</em>),
+    where <em>option</em> is the name of the option, <em>default</em> is its default
+    value and <em>isinit</em> is true if the option is an initialisation
+    option.</p>
+
+
+</dd></dl>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 22 May 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MegaToplevel.html b/Pmw/Pmw_1_2/doc/MegaToplevel.html
new file mode 100644 (file)
index 0000000..53c1fe0
--- /dev/null
@@ -0,0 +1,267 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MegaToplevel reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MegaToplevel</h1>
+    
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MegaToplevel() - 
+    base class for megawidgets within a toplevel
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaArchetype.html">Pmw.MegaArchetype</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This class creates a megawidget contained within a toplevel
+    window.  It may be used directly to create a toplevel megawidget
+    or it may be used as a base class for more specialised toplevel
+    megawidgets, such as <a href="Dialog.html">Pmw.Dialog</a>.  It creates a Tkinter.Toplevel
+    component, named <strong>hull</strong>, to act as the container of the megawidget. 
+    The window class name for the <strong>hull</strong> widget is set to the
+    most-specific class name for the megawidget.  Derived classes
+    specialise this class by creating other widget components as
+    children of the <strong>hull</strong> widget.</p>
+
+<p>    The megawidget may be used as either a normal toplevel window or
+    as a modal dialog.  Use <code>show()</code> and <code>withdraw()</code> for normal use
+    and <code>activate()</code> and <code>deactivate()</code> for modal dialog use.  If the
+    window is deleted by the window manager while being shown
+    normally, the default behaviour is to destroy the window.  If the
+    window is deleted by the window manager while the window is active
+    (ie:  when used as a modal dialog), the window is deactivated. 
+    Use the <code>userdeletefunc()</code> and <code>usermodaldeletefunc()</code> methods to
+    override these behaviours.  Do not call <code>protocol()</code> to set the
+    <strong>WM_DELETE_WINDOW</strong> window manager protocol directly if you want to
+    use this window as a modal dialog.</p>
+
+<p>    The currently active windows form a stack with the most recently
+    activated window at the top of the stack.  All mouse and
+    keyboard events are sent to this top window.  When it
+    deactivates, the next window in the stack will start to receive
+    events.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaArchetype.html#methods">Pmw.MegaArchetype</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Toplevel</strong> class
+are forwarded by this megawidget to the
+<strong>hull</strong> component.
+<p></p>
+<a name=method.activate></a>
+<dl><dt> <strong>activate</strong>(<em>globalMode</em> = <strong>0</strong>, <em>geometry</em> = <strong>'centerscreenfirst'</strong>)</dt><dd>
+Display the window as a modal dialog.  This means that all mouse
+    and keyboard events go to this window and no other windows can
+    receive any events.  If you do not want to restrict mouse and
+    keyboard events to this window, use the <code>show()</code> method instead.</p>
+<p>    If the BLT extension to Tk is present, a busy cursor will be
+    displayed on other toplevel windows, using <code>Pmw.showbusycursor()</code>.</p>
+
+<p>    The <code>activate()</code> method does not return until the <code>deactivate()</code>
+    method is called, when the window is withdrawn, the grab released
+    and the result returned.</p>
+
+<p>    If <em>globalMode</em> is false, the window will grab control of the
+    pointer and keyboard, preventing any events from being delivered
+    to any other toplevel windows within the application.  If
+    <em>globalMode</em> is true, the grab will prevent events from being
+    delivered to any other toplevel windows regardless of application. 
+    Global grabs should be used sparingly, if at all.</p>
+
+<p>    If <em>globalMode</em> is <strong>'nograb'</strong>, then no grab is performed.  If BLT
+    is present, this will allow mouse and keyboard events to be
+    received by other windows whose <strong>exclude</strong> busycursor attribute has
+    been set to true by a call to <code>Pmw.setbusycursorattributes()</code>. 
+    Note that if <strong>'nograb'</strong> is used and BLT is not present, then <em>all</em>
+    other windows will receive mouse and keyboard events.  This is
+    because, in plain Tk, there is no way to specify that two windows
+    (only) receive events.  If your application may be used without
+    BLT, then do not use <strong>'nograb'</strong>.</p>
+
+<p>    When the window is displayed, it is positioned on the screen
+    according to <em>geometry</em> which may be one of:</p>
+
+<dl><dt><strong>centerscreenfirst</strong></dt><dd>The window will be centered the first time it is activated. 
+        On subsequent activations it will be positioned in the same
+        position as the last time it was displayed, even if it has
+        been moved by the user.<p></p>
+
+</dd>
+<dt><strong>centerscreenalways</strong></dt><dd>The window will be be centered on the screen (halfway across
+        and one third down).<p></p>
+
+</dd>
+<dt><strong>first</strong> + <em>spec</em></dt><dd>It is assumed that the rest of the argument (after <strong>'first'</strong>)
+        is a standard geometry specification.  The window will be
+        positioned using this specification the first time it is
+        activated.  On subsequent activations it will be positioned in
+        the same position as the last time it was displayed, even if
+        it has been moved by the user.  For example,
+        <code>geometry = first+100+100</code> will initially display the window
+        at position (100,100).  Other calls to <code>activate()</code> will not
+        change the previous position of the window.<p></p>
+
+</dd>
+<dt><em>spec</em></dt><dd>This is a standard geometry specification.  The window will be
+        be positioned using this specification.<p></p>
+
+</dd></dl>
+<p>    If the <strong>BLT</strong> Tcl extension library is present, a <strong>clock</strong> cursor
+    will be displayed until the window is deactivated.</p>
+
+<p>    If the <strong>activatecommand</strong> option is callable, it is called just
+    before the window begins to wait for the result.</p>
+
+<p>    If the <strong>master</strong> option is not <strong>None</strong>, the window will become a
+    transient window of <strong>master</strong>, which should be a toplevel window. 
+    If <strong>master</strong> has the special value of <strong>'parent'</strong>, the master is the
+    toplevel window of the window's parent.</p>
+
+
+
+</dd></dl>
+<a name=method.active></a>
+<dl><dt> <strong>active</strong>()</dt><dd>
+Return true if the megawidget is currently active (that is,
+    <code>activate()</code> is currently waiting for a result to be passed to it
+    by a call to <code>deactivate()</code>).</p>
+
+
+</dd></dl>
+<a name=method.deactivate></a>
+<dl><dt> <strong>deactivate</strong>(<em>result</em> = <strong>None</strong>)</dt><dd>
+This should be called while a call to <code>activate()</code> is waiting.  It
+    will withdraw the window, release the grab and cause the
+    <code>activate()</code> call to return with the value of <em>result</em>.</p>
+<p>    If the <strong>deactivatecommand</strong> option is callable, it is called just
+    before the <code>deactivate()</code> method returns.</p>
+
+
+
+</dd></dl>
+<a name=method.destroy></a>
+<dl><dt> <strong>destroy</strong>()</dt><dd>
+Destroy the <strong>hull</strong> component widget, including all of its
+    children.  If the megawidget is currently active, deactivate it.</p>
+
+
+</dd></dl>
+<a name=method.show></a>
+<dl><dt> <strong>show</strong>(<em>master</em> = <strong>None</strong>)</dt><dd>
+Make the window visible.  This raises or deiconifies the toplevel
+    window.  If the window has previously been shown it will remain in
+    the same position.  This means that calling <code>withdraw()</code> then
+    <code>show()</code> will not move the window, whereas calling <code>withdraw()</code>
+    then <code>deiconify()</code> may change the window's position.  (This may
+    depend on the behaviour of the window manager.)</p>
+
+
+</dd></dl>
+<a name=method.userdeletefunc></a>
+<dl><dt> <strong>userdeletefunc</strong>(<em>func</em> = <strong>None</strong>)</dt><dd>
+If <em>func</em> is <strong>None</strong>, return the function that will be called
+    when the window is deleted by the window manager while being
+    displayed normally.  If <em>func</em> is not <strong>None</strong>, set this function to
+    <em>func</em>.  By default, the function is <code>self.destroy</code>.</p>
+
+
+</dd></dl>
+<a name=method.usermodaldeletefunc></a>
+<dl><dt> <strong>usermodaldeletefunc</strong>(<em>func</em> = <strong>None</strong>)</dt><dd>
+If <em>func</em> is <strong>None</strong>, return the function that will be called
+    when the window is deleted by the window manager while it is
+    active (ie:  when being used as a modal dialog).  If <em>func</em> is not
+    <strong>None</strong>, set this function to <em>func</em>.  By default, the function is
+    <code>self.deactivate</code>.</p>
+
+
+</dd></dl>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 22 May 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MegaWidget.html b/Pmw/Pmw_1_2/doc/MegaWidget.html
new file mode 100644 (file)
index 0000000..d18698b
--- /dev/null
@@ -0,0 +1,83 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MegaWidget reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MegaWidget</h1>
+    
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MegaWidget() - 
+    base class for megawidgets within a frame
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaArchetype.html">Pmw.MegaArchetype</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    This class creates a megawidget contained within a Tkinter.Frame
+    window.  The class acts as the base class for megawidgets that are
+    not contained in their own toplevel window, such as <a href="ButtonBox.html">Pmw.ButtonBox</a> and
+    <a href="ComboBox.html">Pmw.ComboBox</a>.  It creates a Tkinter.Frame component, named <strong>hull</strong>,
+    to act as the container of the megawidget.  The window class name
+    for the <strong>hull</strong> widget is set to the most-specific class name for
+    the megawidget.  Derived classes specialise this class by
+    creating other widget components as children of the <strong>hull</strong> widget.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+This megawidget has no methods of its own.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaArchetype.html#methods">Pmw.MegaArchetype</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Frame</strong> class
+are forwarded by this megawidget to the
+<strong>hull</strong> component.
+<p></p>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 22 May 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MenuBar.gif b/Pmw/Pmw_1_2/doc/MenuBar.gif
new file mode 100644 (file)
index 0000000..aa7a7bf
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/MenuBar.gif differ
diff --git a/Pmw/Pmw_1_2/doc/MenuBar.html b/Pmw/Pmw_1_2/doc/MenuBar.html
new file mode 100644 (file)
index 0000000..e2c04a6
--- /dev/null
@@ -0,0 +1,399 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MenuBar reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MenuBar</h1>
+    
+<center><IMG SRC=MenuBar.gif ALT="" WIDTH=474 HEIGHT=29></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MenuBar() - 
+    manager megawidget for menu buttons and menus
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A menu bar is a container megawidget which manages a number of
+    menu buttons and dropdown menus.  There
+    are methods to add menu buttons and menus to the menu bar and for
+    adding menu items to the menus.  Menu buttons may be added to the
+    left or right of the megawidget.  Each menu button and menu item may
+    have help text to be displayed by a <a href="Balloon.html">Pmw.Balloon</a>.  Each menu
+    and cascaded menu (sub-menu) is referenced by name which is
+    supplied on creation.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.balloon></a>
+<dl><dt> <strong>balloon
+</strong></dt><dd>
+Specifies a <a href="Balloon.html">Pmw.Balloon</a> to display the help text for menu
+    buttons and menu items.  If <strong>None</strong>, no help is displayed.  If the
+    balloon has an associated <a href="MessageBar.html">Pmw.MessageBar</a>, the help text will also be
+    displayed there. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.hotkeys></a>
+<dl><dt> <strong>hotkeys
+</strong></dt><dd>
+Initialisation option. If true, keyboard accelerators will be assigned to each menu
+    button and menu item.  Keyboard accelerators can be used to access
+    the menus without using the mouse.  The accelerator character is
+    always one of the alphanumeric characters in the text label of the
+    menu or menu item and is indicated by an underline.</p>
+<p>    To select a menu, simultaneously press the <strong>&lt;Alt&gt;</strong> key and the
+    accelerator character indicated on a menu button.  The arrows keys
+    can then be used to select other menus and menu items.  To invoke a
+    menu item, press <strong>&lt;Return&gt;</strong> or press the accelerator character
+    indicated on the menu item.</p>
+
+<p>    Each accelerator character will be assigned automatically unless
+    <em>traverseSpec</em> is supplied to the <code>addmenu()</code>, <code>addmenuitem()</code> or
+    <code>addcascademenu()</code> methods.  The automatically selected
+    accelerator character for a menu button (or menu item) is the
+    first character in the label text that has not already been used
+    as an accelerator for a menu button (or in the menu containing the
+    menu item).</p>
+
+<p>    If <em>traverseSpec</em> is given, it must be either an integer or a
+    character.  If an integer, it specifies the index of the character
+    in the label text to use as the accelerator character.  If a
+    character, it specifies the character to use as the accelerator
+    character. The default is <strong>1</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.padx></a>
+<dl><dt> <strong>padx
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave between each menu button in
+    the x direction and also between the menu buttons and the outer
+    edge of the menu bar. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Dynamic components</h3></dt><dd>
+<p>
+        Menu button components are created dynamically by the
+        <code>addmenu()</code> method.  By default, these are of type
+        Tkinter.Menubutton and are created with a component group of
+        <strong>Button</strong>.</p>
+
+<p>        Menu components are created dynamically by the <code>addmenu()</code> and
+        <code>addcascademenu()</code> methods.  By default, these are of type
+        Tkinter.Menu and are created with a component group of <strong>Menu</strong>.</p>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.addcascademenu></a>
+<dl><dt> <strong>addcascademenu</strong>(<em>parentMenuName</em>, <em>menuName</em>, <em>statusHelp</em> = <strong>''</strong>, <em>traverseSpec</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Add a cascade menu (sub-menu) to the menu <em>parentMenuName</em>.  The
+    <em>menuName</em> argument must not be the same as any menu already
+    created using the <code>addmenu()</code> or <code>addcascademenu()</code> methods.</p>
+<p>    A menu item in the parent menu is created (with the
+    <code>add_cascade()</code> method of the parent menu) using all keyword
+    arguments except <strong>tearoff</strong>.</p>
+
+<p>    If the <strong>label</strong> keyword argument is not given, the <strong>label</strong> option
+    of the menu item defaults to <em>menuName</em>.  If the <strong>underline</strong>
+    keyword argument is not given (and the <strong>hotkeys</strong> megawidget option
+    is true) the <strong>underline</strong> option is determined as described under
+    <strong>hotkeys</strong> and is used to specify the keyboard accelerator.</p>
+
+<p>    The <em>statusHelp</em> argument is used as the help string for the menu
+    item.  This is displayed using the <code>showstatus()</code> method of the
+    balloon.</p>
+
+<p>    The <strong>tearoff</strong> keyword argument, if present, is passed to the
+    constructor of the menu.  The menu is created as a component named
+    <em>menuName</em>-<strong>menu</strong>.</p>
+
+
+
+</dd></dl>
+<a name=method.addmenu></a>
+<dl><dt> <strong>addmenu</strong>(<em>menuName</em>, <em>balloonHelp</em>, <em>statusHelp</em> = <strong>None</strong>, <em>side</em> = <strong>'left'</strong>, <em>traverseSpec</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Add a menu button and its associated menu to the menu bar.  The
+    <em>menuName</em> argument must not be the same as any menu already
+    created using the <code>addmenu()</code> or <code>addcascademenu()</code> methods.</p>
+<p>    Any keyword arguments present (except <strong>tearoff</strong>) will be passed to
+    the constructor of the menu button.  If the <strong>text</strong> keyword
+    argument is not given, the <strong>text</strong> option of the menu button
+    defaults to <em>menuName</em>.  If the <strong>underline</strong> keyword argument is
+    not given (and the <strong>hotkeys</strong> megawidget option is true) the
+    <strong>underline</strong> option is determined as described under <strong>hotkeys</strong> and
+    is used to specify the keyboard accelerator.  Each menu button is
+    packed into the menu bar using the given <em>side</em>, which should be
+    either <strong>left</strong> or <strong>right</strong>.  The menu button is created as a
+    component named <em>menuName</em>-<strong>button</strong>.</p>
+
+<p>    If the <strong>balloon</strong> option has been defined, <em>balloonHelp</em> and
+    <em>statusHelp</em> are passed to the balloon as the help strings for the
+    menu button.  See the <code>bind()</code> method of <a href="Balloon.html">Pmw.Balloon</a> for how these
+    strings may be displayed.</p>
+
+<p>    The <strong>tearoff</strong> keyword argument, if present, is passed to the
+    constructor of the menu.  The menu is created as a component named
+    <em>menuName</em>-<strong>menu</strong>.</p>
+
+
+
+</dd></dl>
+<a name=method.addmenuitem></a>
+<dl><dt> <strong>addmenuitem</strong>(<em>menuName</em>, <em>itemType</em>, <em>statusHelp</em> = <strong>''</strong>, <em>traverseSpec</em> = <strong>None</strong>, **<em>kw</em>)</dt><dd>
+Add a menu item to the menu <em>menuName</em>.  The kind of menu item is
+    given by <em>itemType</em> and may be one of <strong>command</strong>, <strong>separator</strong>,
+    <strong>checkbutton</strong>, <strong>radiobutton</strong> or <strong>cascade</strong> (although cascade menus
+    are better added using the <code>addcascademenu()</code> method).  Any
+    keyword arguments present will be passed to the menu when creating
+    the menu item.  See Tkinter.Menu for the valid options for each
+    item type.  In addition, a keyboard accelerator may be
+    automatically given to the item, as described under <strong>hotkeys</strong>. </p>
+<p>    When the mouse is moved over the menu item, the <em>helpString</em> will
+    be displayed by the <strong>balloon</strong>'s <strong>statuscommand</strong>.</p>
+
+
+
+</dd></dl>
+<a name=method.deletemenu></a>
+<dl><dt> <strong>deletemenu</strong>(<em>menuName</em>)</dt><dd>
+Delete the menu <em>menuName</em> and all its items.  The menu may either
+    be a toplevel menu (in which case the corresponding menu button is
+    also deleted) or a cascade menu.</p>
+
+
+</dd></dl>
+<a name=method.deletemenuitems></a>
+<dl><dt> <strong>deletemenuitems</strong>(<em>menuName</em>, <em>start</em>, <em>end</em> = <strong>None</strong>)</dt><dd>
+Delete menu items from the menu <em>menuName</em>.  If <em>end</em> is not
+    given, the <em>start</em> item is deleted.  Otherwise all items from
+    <em>start</em> to <em>end</em> are deleted.</p>
+
+
+</dd></dl>
+<a name=method.disableall></a>
+<dl><dt> <strong>disableall</strong>()</dt><dd>
+Disable all toplevel menus.</p>
+
+
+</dd></dl>
+<a name=method.enableall></a>
+<dl><dt> <strong>enableall</strong>()</dt><dd>
+Enable all toplevel menus.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the Balloon.
+        self.balloon = Pmw.Balloon(parent)
+
+        # Create and pack the MenuBar.
+        menuBar = Pmw.MenuBar(parent,
+                hull_relief = 'raised',
+                hull_borderwidth = 1,
+                balloon = self.balloon)
+        menuBar.pack(fill = 'x')
+        self.menuBar = menuBar
+
+        # Add some buttons to the MenuBar.
+        menuBar.addmenu('File', 'Close this window or exit')
+        menuBar.addmenuitem('File', 'command', 'Close this window',
+                command = PrintOne('Action: close'),
+                label = 'Close')
+        menuBar.addmenuitem('File', 'separator')
+        menuBar.addmenuitem('File', 'command', 'Exit the application',
+                command = PrintOne('Action: exit'),
+                label = 'Exit')
+
+        menuBar.addmenu('Edit', 'Cut, copy or paste')
+        menuBar.addmenuitem('Edit', 'command', 'Delete the current selection',
+                command = PrintOne('Action: delete'),
+                label = 'Delete')
+
+        menuBar.addmenu('Options', 'Set user preferences')
+        menuBar.addmenuitem('Options', 'command', 'Set general preferences',
+                command = PrintOne('Action: general options'),
+                label = 'General...')
+
+        # Create a checkbutton menu item.
+        self.toggleVar = Tkinter.IntVar()
+        # Initialise the checkbutton to 1:
+        self.toggleVar.set(1)
+        menuBar.addmenuitem('Options', 'checkbutton', 'Toggle me on/off',
+                label = 'Toggle',
+                command = self._toggleMe,
+                variable = self.toggleVar)
+        self._toggleMe()
+
+        menuBar.addcascademenu('Options', 'Size',
+                'Set some other preferences', traverseSpec = 'z', tearoff = 1)
+        for size in ('tiny', 'small', 'average', 'big', 'huge'):
+            menuBar.addmenuitem('Size', 'command', 'Set size to ' + size,
+                    command = PrintOne('Action: size ' + size),
+                    label = size)
+
+        menuBar.addmenu('Help', 'User manuals', side = 'right')
+        menuBar.addmenuitem('Help', 'command', 'About this application',
+                command = PrintOne('Action: about'),
+                label = 'About...')
+
+        # Create and pack the main part of the window.
+        self.mainPart = Tkinter.Label(parent,
+                text = 'This is the\nmain part of\nthe window',
+                background = 'black',
+                foreground = 'white',
+                padx = 30,
+                pady = 30)
+        self.mainPart.pack(fill = 'both', expand = 1)
+
+        # Create and pack the MessageBar.
+        self.messageBar = Pmw.MessageBar(parent,
+                entry_width = 40,
+                entry_relief='groove',
+                labelpos = 'w',
+                label_text = 'Status:')
+        self.messageBar.pack(fill = 'x', padx = 10, pady = 10)
+        self.messageBar.message('state', 'OK')
+
+        buttonBox = Pmw.ButtonBox(parent)
+        buttonBox.pack(fill = 'x')
+        buttonBox.add('Disable\nall', command = menuBar.disableall)
+        buttonBox.add('Enable\nall', command = menuBar.enableall)
+        buttonBox.add('Create\nmenu', command = self.add)
+        buttonBox.add('Delete\nmenu', command = self.delete)
+        buttonBox.add('Create\nitem', command = self.additem)
+        buttonBox.add('Delete\nitem', command = self.deleteitem)
+
+        # Configure the balloon to displays its status messages in the
+        # message bar.
+        self.balloon.configure(statuscommand = self.messageBar.helpmessage)
+
+        self.testMenuList = []
+
+    def _toggleMe(self):
+        print 'Toggle value:', self.toggleVar.get()
+
+    def add(self):
+        if len(self.testMenuList) == 0:
+            num = 0
+        else:
+            num = self.testMenuList[-1]
+        num = num + 1
+        name = 'Menu%d' % num
+        self.testMenuList.append(num)
+
+        self.menuBar.addmenu(name, 'This is ' + name)
+
+    def delete(self):
+        if len(self.testMenuList) == 0:
+            self.menuBar.bell()
+        else:
+            num = self.testMenuList[0]
+            name = 'Menu%d' % num
+            del self.testMenuList[0]
+            self.menuBar.deletemenu(name)
+
+    def additem(self):
+        if len(self.testMenuList) == 0:
+            self.menuBar.bell()
+        else:
+            num = self.testMenuList[-1]
+            menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName + '-menu')
+            if menu.index('end') is None:
+                label = 'item X'
+            else:
+                label = menu.entrycget('end', 'label') + 'X'
+            self.menuBar.addmenuitem(menuName, 'command', 'Help for ' + label,
+                    command = PrintOne('Action: ' + menuName + ': ' + label),
+                    label = label)
+            
+    def deleteitem(self):
+        if len(self.testMenuList) == 0:
+            self.menuBar.bell()
+        else:
+            num = self.testMenuList[-1]
+            menuName = 'Menu%d' % num
+            menu = self.menuBar.component(menuName + '-menu')
+            if menu.index('end') is None:
+                self.menuBar.bell()
+            else:
+                self.menuBar.deletemenuitems(menuName, 0)
+            
+class PrintOne:
+    def __init__(self, text):
+        self.text = text
+
+    def __call__(self):
+        print self.text
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 22 April 2000
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MessageBar.gif b/Pmw/Pmw_1_2/doc/MessageBar.gif
new file mode 100644 (file)
index 0000000..0dc4446
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/MessageBar.gif differ
diff --git a/Pmw/Pmw_1_2/doc/MessageBar.html b/Pmw/Pmw_1_2/doc/MessageBar.html
new file mode 100644 (file)
index 0000000..69be04e
--- /dev/null
@@ -0,0 +1,302 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MessageBar reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MessageBar</h1>
+    
+<center><IMG SRC=MessageBar.gif ALT="" WIDTH=398 HEIGHT=44></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MessageBar() - 
+    information line for displaying short messages
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A message bar contains a single-line message display area.  Messages
+    of several different types may displayed.  Messages are cleared
+    after a period defined for each message type.  Each message type
+    has a priority so that if the application attempts to display more
+    than one message at a time, the message with the highest priority
+    will be displayed.  Messages may be accompanied by a number of
+    audible bells.</p>
+
+<p>    This megawidget can be used for both interactive help messages
+    (when the mouse enters certain widgets) and also for other general
+    messages.</p>
+
+<p>    To perform the help function it can cooperate with the <a href="Balloon.html">Pmw.Balloon</a>
+    megawidget so that the programmer (or user) can choose either
+    balloon help, message bar help, both or neither.</p>
+
+<p>    This megawidget supports a configurable number of message types. 
+    The default types include <strong>'state'</strong>, <strong>'help'</strong>, <strong>'usererror'</strong> and
+    <strong>'systemerror'</strong>.  The difference between these are the length of
+    time they are displayed, the number of bells that are rung and the
+    priority of the message.  For example, the <strong>'help'</strong> message type
+    is lower in priority than the <strong>'usererror'</strong>, so that error
+    messages will always be displayed in preference to help messages
+    regardless of the order the messages are created.  The <strong>'state'</strong>
+    message type is lowest in priority but has no timeout, so it
+    should contain messages describing the current state of the
+    application, such as <em>Waiting for database connection</em> or 'Waiting
+    for file to be unlocked'.  Generally this should be set to the
+    empty string when the application is running normally.  By default
+    the help messages (with message type <strong>'help'</strong>) time out after 5
+    seconds, so that if the cursor happens to be left over a widget,
+    the application state will be redisplayed after a short time.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.messagetypes></a>
+<dl><dt> <strong>messagetypes
+</strong></dt><dd>
+Initialisation option. This defines what message types are supported by the message bar
+    and the characteristics of those message types.  It is a
+    dictionary where the key is a string specifying a message type and
+    the value is a tuple of four integers, (<em>priority</em>, <em>showtime</em>,
+    <em>bells</em>, <em>logmessage</em>), where <em>priority</em> is the rank of the
+    message type, <em>showtime</em> is the number of seconds to display
+    messages of this message type, <em>bells</em> is the number of audible
+    bells to ring and <em>logmessage</em> is a boolean
+    specifying whether this message should be logged for retrieval
+    later.  Messages with a higher priority are displayed in
+    preference to those with lower priority.  If a high priority
+    message times out (because it has been displayed for <em>showtime</em>
+    seconds), then a lower priority message may be displayed.  A
+    <em>showtime</em> of <strong>0</strong> means that the message will never time out and
+    is useful for displaying messages describing the current state of
+    the application as opposed to messages describing events.  Logging
+    is not currently implemented.  The default is</p>
+<dl><dd><pre> {
+     'systemerror'  : (5, 10, 2, 1),
+     'usererror'    : (4, 5, 1, 0),
+     'busy'         : (3, 0, 0, 0),
+     'systemevent'  : (2, 5, 0, 0),
+     'userevent'    : (2, 5, 0, 0),
+     'help'         : (1, 5, 0, 0),
+     'state'        : (0, 0, 0, 0),
+ }</pre></dd></dl>
+
+
+
+</dd></dl>
+<a name=option.silent></a>
+<dl><dt> <strong>silent
+</strong></dt><dd>
+If true, no audible bells will sound, regardless of the value for
+    <em>bells</em> defined in the <strong>messagetypes</strong> option. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'ew'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.entry></a>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+The widget where the messages are displayed.  Long messages may be
+    scrolled horizontally by dragging with the middle mouse button. By default, this component is a Tkinter.Entry.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Entry</strong> class
+are forwarded by this megawidget to the
+<strong>entry</strong> component.
+<p></p>
+<a name=method.helpmessage></a>
+<dl><dt> <strong>helpmessage</strong>(<em>text</em>)</dt><dd>
+A convenience method to display <em>text</em> in the message bar
+    according to the characteristics defined by the <strong>help</strong> message type.
+    Equivalent to <code>message('help', text)</code>.</p>
+
+
+</dd></dl>
+<a name=method.message></a>
+<dl><dt> <strong>message</strong>(<em>type</em>, <em>text</em>)</dt><dd>
+Display <em>text</em> in the message bar according to the characteristics
+    defined by the <em>type</em> message type, as discussed under
+    <strong>messagetypes</strong>.</p>
+
+
+</dd></dl>
+<a name=method.resetmessages></a>
+<dl><dt> <strong>resetmessages</strong>(<em>type</em>)</dt><dd>
+Clear the <em>type</em> message and all message types with a lower
+    priority, except permanent messages, such as <strong>state</strong>.  This is
+    useful to clear the <strong>busy</strong> message and any outstanding event and
+    help messages.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the MessageBar.
+        self._messagebar = Pmw.MessageBar(parent,
+                entry_width = 40,
+                entry_relief='groove',
+                labelpos = 'w',
+                label_text = 'Status:')
+        self._messagebar.pack(side = 'bottom', fill = 'x',
+                expand = 1, padx = 10, pady = 10)
+
+        # Create and pack the ScrolledListBox to change the MessageBar.
+        self.box = Pmw.ScrolledListBox(parent,
+                listbox_selectmode='single',
+                items=('state', 'help', 'userevent', 'systemevent',
+                        'usererror', 'systemerror', 'busy',),
+                label_text='Message type',
+                labelpos='n',
+                selectioncommand=self.selectionCommand)
+        self.box.pack(fill = 'both', expand = 'yes', padx = 10, pady = 10)
+
+        self._index = 0
+        self._stateCounter = 0
+
+    def selectionCommand(self):
+        sels = self.box.getcurselection()
+        if len(sels) &gt; 0:
+            self._index = self._index + 1
+            messagetype = sels[0]
+            if messagetype == 'state':
+                self._stateCounter = (self._stateCounter + 1) % 3
+                text = stateMessages[self._stateCounter]
+                if text != '':
+                    text = text + ' (' + messagetype + ')'
+                self._messagebar.message('state', text)
+            else:
+                text = messages[messagetype]
+                text = text + ' (' + messagetype + ')'
+                self._messagebar.message(messagetype, text)
+                if messagetype == 'busy':
+                    Pmw.showbusycursor()
+                    self.box.after(2000)
+                    Pmw.hidebusycursor()
+                    self._messagebar.resetmessages('busy')
+                    text = 'All files successfully removed'
+                    text = text + ' (userevent)'
+                    self._messagebar.message('userevent', text)
+
+
+messages = {
+    'help': 'Save current file',
+    'userevent': 'Saving file "foo"',
+    'busy': 'Busy deleting all files from file system ...',
+    'systemevent': 'File "foo" saved',
+    'usererror': 'Invalid file name "foo/bar"',
+    'systemerror': 'Failed to save file: file system full',
+}
+
+stateMessages = {
+    0: '',
+    1: 'Database is down',
+    2: 'Waiting for reply from database',
+}
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/MessageDialog.gif b/Pmw/Pmw_1_2/doc/MessageDialog.gif
new file mode 100644 (file)
index 0000000..f6ac164
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/MessageDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/MessageDialog.html b/Pmw/Pmw_1_2/doc/MessageDialog.html
new file mode 100644 (file)
index 0000000..f3e3588
--- /dev/null
@@ -0,0 +1,326 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.MessageDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.MessageDialog</h1>
+    
+<center><IMG SRC=MessageDialog.gif ALT="" WIDTH=309 HEIGHT=220></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.MessageDialog() - 
+    a dialog displaying a text message and an icon
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="Dialog.html">Pmw.Dialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A message dialog is a dialog window which displays a simple
+    message to the user along with one or more buttons to press.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the text message and icon. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the text message and icon. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.iconmargin></a>
+<dl><dt> <strong>iconmargin
+</strong></dt><dd>
+Initialisation option. The padding between the text message and icon. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.iconpos></a>
+<dl><dt> <strong>iconpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the text message to place the icon. 
+    Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.icon></a>
+<dl><dt> <strong>icon
+</strong></dt><dd>
+If the <strong>iconpos</strong> option is not <strong>None</strong>, this component is created
+    to contain the icon label for the dialog.  To display a bitmap as
+    an icon, set the <strong>icon_bitmap</strong> component option to any of the
+    forms acceptable to Tk, such as <strong>'warning'</strong> or <strong>'error'</strong>. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.message></a>
+<dl><dt> <strong>message
+</strong></dt><dd>
+The label to contain the text message for the dialog.  To set
+    the text, use the <strong>message_text</strong> component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+This megawidget has no methods of its own.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="Dialog.html#methods">Pmw.Dialog</a></strong>.
+<p></p>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        self.parent = parent
+
+        # Create dialog 1.
+        self.dialog1 = Pmw.MessageDialog(parent,
+            title = 'Simple message dialog',
+            defaultbutton = 0,
+            message_text = 'A simple message dialog\nwith no callback.')
+        self.dialog1.iconname('Simple message dialog')
+        self.dialog1.withdraw()
+
+        # Create dialog 2.
+        self.dialog2 = Pmw.MessageDialog(parent,
+            title = 'Bell ringing dialog',
+            message_text = 'This message dialog\nwill ring the bell ' +
+                'when\nyou click on the buttons.',
+            iconpos = 'w',
+            icon_bitmap = 'error',
+            command = self.execute2,
+            buttons = ('One', 'Two', 'Three', 'Close'))
+        self.dialog2.iconname('Bell ringing dialog')
+        self.dialog2.withdraw()
+
+        # Create dialog 3.
+        self.dialog3 = Pmw.MessageDialog(parent,
+            title = 'Vertical button dialog',
+            message_text = 'This message dialog\nhas the buttons on the\n' +
+                'right hand side.',
+            buttonboxpos = 'e',
+            iconpos = 'n',
+            icon_bitmap = 'warning',
+            buttons = ('Goodbye', 'Au revoir', 'Sayonara', 'Close'),
+            defaultbutton = 'Close')
+        self.dialog3.iconname('Vertical button dialog')
+        self.dialog3.withdraw()
+
+        # Create some buttons to launch the dialogs.
+        w = Tkinter.Button(parent, text = 'Simple dialog',
+                command = lambda self = self:
+                        self.dialog1.activate(geometry = 'first+100+100'))
+        w.pack(padx = 8, pady = 8)
+
+        w = Tkinter.Button(parent, text = 'Bell ringing dialog',
+                command = self.dialog2.activate)
+        w.pack(padx = 8, pady = 8)
+
+        w = Tkinter.Button(parent, text = 'Vertical buttons',
+                command = self.dialog3.activate)
+        w.pack(padx = 8, pady = 8)
+
+        w = Tkinter.Button(parent, text = 'On the fly dialog',
+                command = self._createOnTheFly)
+        w.pack(padx = 8, pady = 8)
+
+    def execute2(self, result):
+        print 'You clicked on', result
+        if result is None:
+            self.dialog2.deactivate(result)
+        elif result == 'Close':
+            self.dialog2.deactivate(result)
+        else:
+            for count in range({'One': 1, 'Two': 2, 'Three': 3}[result]):
+                if count != 0:
+                    self.dialog2.after(200)
+                self.dialog2.bell()
+
+    def _createOnTheFly(self):
+        dialog = Pmw.MessageDialog(self.parent,
+            title = 'On the fly dialog',
+            defaultbutton = 0,
+            buttons = ('OK', 'Apply', 'Cancel', 'Help'),
+            message_text = 'This dialog was created when you clicked ' +
+                'on the button.')
+        dialog.iconname('Simple message dialog')
+        result = dialog.activate()
+
+        print 'You selected', result
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/NoteBook.gif b/Pmw/Pmw_1_2/doc/NoteBook.gif
new file mode 100644 (file)
index 0000000..206a88d
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/NoteBook.gif differ
diff --git a/Pmw/Pmw_1_2/doc/NoteBook.html b/Pmw/Pmw_1_2/doc/NoteBook.html
new file mode 100644 (file)
index 0000000..38601f7
--- /dev/null
@@ -0,0 +1,344 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.NoteBook reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.NoteBook</h1>
+    
+<center><IMG SRC=NoteBook.gif ALT="" WIDTH=400 HEIGHT=219></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.NoteBook() - 
+    a set of tabbed pages
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaArchetype.html">Pmw.MegaArchetype</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A notebook contains a set of tabbed pages.  At any one time only
+    one of these pages (the <em>selected</em> page) is visible, with the
+    other pages being hidden "beneath" it.  Another page in the
+    notebook may be displayed by clicking on the tab attached to the
+    page.  The tabs are displayed along the top edge.</p>
+
+<p>    Optionally, the notebook may be displayed without tabs.  In this
+    case, another selection widget, such as <a href="OptionMenu.html">Pmw.OptionMenu</a>, may be used
+    to select the pages.</p>
+
+<p>    This megawidget is derived from <a href="MegaArchetype.html">Pmw.MegaArchetype</a> (not <a href="MegaWidget.html">Pmw.MegaWidget</a>
+    like most other megawidgets), with the hull class being
+    Tkinter.Canvas.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.arrownavigation></a>
+<dl><dt> <strong>arrownavigation
+</strong></dt><dd>
+Initialisation option. If true and a tab button has the keyboard focus, then the Left and
+    Right arrow keys can be used to select the page before or after
+    the tab button with the focus. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderwidth></a>
+<dl><dt> <strong>borderwidth
+</strong></dt><dd>
+Initialisation option. The width of the border drawn around each tab and around the
+    selected page. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+<a name=option.createcommand></a>
+<dl><dt> <strong>createcommand
+</strong></dt><dd>
+Specifies a function to call when a page is selected for the first
+    time.  The function is called with a single argument, which is the
+    name of the selected page, and is called before the <strong>raisecommand</strong>
+    function.  This allows the creation of the page contents to be
+    deferred until the page is first displayed. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.lowercommand></a>
+<dl><dt> <strong>lowercommand
+</strong></dt><dd>
+Specifies a function to call when the selected page is replaced
+    with a new selected page.  The function is called with a single
+    argument, which is the name of the previously selected page, and
+    is called before the <strong>createcommand</strong> or <strong>raisecommand</strong> functions. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.pagemargin></a>
+<dl><dt> <strong>pagemargin
+</strong></dt><dd>
+Initialisation option. The margin (in pixels) around the selected page inside the
+    notebook's page border. The default is <strong>4</strong>.</p>
+
+
+</dd></dl>
+<a name=option.raisecommand></a>
+<dl><dt> <strong>raisecommand
+</strong></dt><dd>
+Specifies a function to call when a new page is selected.  The
+    function is called with a single argument, which is the name of
+    the selected page. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.tabpos></a>
+<dl><dt> <strong>tabpos
+</strong></dt><dd>
+Initialisation option. Specifies the location of the tabs.  If <strong>'n'</strong>, tabs are created
+    for each page and positioned at the top of the notebook.  If
+    <strong>None</strong>, no tabs are created, in which case another selection
+    widget can be used to select pages by calling the <code>selectpage()</code>
+    method. The default is <strong>'n'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the megawidget.  The contents of the
+    megawidget are created as canvas items and positioned in the
+    hull using the canvas coordinate system. By default, this component is a Tkinter.Canvas.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Dynamic components</h3></dt><dd>
+<p>
+        Page and tab components are created dynamically by the <code>add()</code>
+        and <code>insert()</code> methods.  By default, the pages are of type
+        Tkinter.Frame and are created with a component group of <strong>Page</strong>
+        and the tabs are of type Tkinter.Button and are created with a
+        component group of <strong>Tab</strong>.</p>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaArchetype.html#methods">Pmw.MegaArchetype</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Canvas</strong> class
+are forwarded by this megawidget to the
+<strong>hull</strong> component.
+<p></p>
+<a name=method.add></a>
+<dl><dt> <strong>add</strong>(<em>pageName</em>, **<em>kw</em>)</dt><dd>
+Add a page at the end of the notebook. See the <code>insert()</code> method
+    for full details.</p>
+
+
+</dd></dl>
+<a name=method.delete></a>
+<dl><dt> <strong>delete</strong>(*<em>pageNames</em>)</dt><dd>
+Delete the pages given by <em>pageNames</em> from the notebook.  Each of
+    the <em>pageNames</em> may have any of the forms accepted by the
+    <code>index()</code> method.</p>
+<p>    If the currently selected page is deleted, then the next page, in
+    index order, is selected.  If the <strong>end</strong> page is deleted, then the
+    previous page is selected.</p>
+
+
+
+</dd></dl>
+<a name=method.getcurselection></a>
+<dl><dt> <strong>getcurselection</strong>()</dt><dd>
+Return the name of the currently selected page.</p>
+
+
+</dd></dl>
+<a name=method.index></a>
+<dl><dt> <strong>index</strong>(<em>index</em>, <em>forInsert</em> = <strong>0</strong>)</dt><dd>
+Return the numerical index of the page corresponding to <em>index</em>. 
+    This may be specified in any of the following forms:</p>
+<dl><dt><em>name</em></dt><dd>Specifies the page labelled <em>name</em>.<p></p>
+
+</dd>
+<dt><em>number</em></dt><dd>Specifies the page numerically, where <strong>0</strong> corresponds to
+         the first page.<p></p>
+
+</dd>
+<dt><strong>Pmw.END</strong></dt><dd>Specifies the last page.<p></p>
+
+</dd>
+<dt><strong>Pmw.SELECT</strong></dt><dd>Specifies the currently selected page.<p></p>
+
+</dd></dl>
+<p>    If <em>forInsert</em> is true, <strong>Pmw.END</strong> returns the number of pages
+    rather than the index of the last page.</p>
+
+
+
+</dd></dl>
+<a name=method.insert></a>
+<dl><dt> <strong>insert</strong>(<em>pageName</em>, <em>before</em> = <strong>0</strong>, **<em>kw</em>)</dt><dd>
+Add a page to the notebook as a component named <em>pageName</em>.  The
+    page is added just before the page specified by <em>before</em>, which
+    may have any of the forms accepted by the <code>index()</code> method.  If
+    <strong>tabpos</strong> is not <strong>None</strong>, also create a tab as a component named
+    <em>pageName</em>-<strong>tab</strong>.  Keyword arguments prefixed with <strong>page_</strong> or
+    <strong>tab_</strong> are passed to the respective constructors when creating the
+    page or tab.  If the <strong>tab_text</strong> keyword argument is not given, the
+    <strong>text</strong> option of the tab defaults to <em>pageName</em>.  If a page is
+    inserted into an empty notebook, the page is selected.  To add a
+    page to the end of the notebook, use <code>add()</code>.  The method returns
+    the <em>pageName</em> component widget.</p>
+
+
+</dd></dl>
+<a name=method.nextpage></a>
+<dl><dt> <strong>nextpage</strong>(<em>pageIndex</em> = <strong>None</strong>)</dt><dd>
+If <em>pageIndex</em> is <strong>None</strong>, then select the page after the
+    currently selected page.  Otherwise select the page after
+    <em>pageIndex</em>, which may have any of the forms accepted by the
+    <code>index()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.page></a>
+<dl><dt> <strong>page</strong>(<em>pageIndex</em>)</dt><dd>
+Return the frame component widget of the page <em>pageIndex</em>, where
+    <em>pageIndex</em> may have any of the forms accepted by the <code>index()</code>
+    method.</p>
+
+
+</dd></dl>
+<a name=method.pagenames></a>
+<dl><dt> <strong>pagenames</strong>()</dt><dd>
+Return a list of the names of the pages, in display order.</p>
+
+
+</dd></dl>
+<a name=method.previouspage></a>
+<dl><dt> <strong>previouspage</strong>(<em>pageIndex</em> = <strong>None</strong>)</dt><dd>
+If <em>pageIndex</em> is <strong>None</strong>, then select the page before the
+    currently selected page.  Otherwise select the page before
+    <em>pageIndex</em>, which may have any of the forms accepted by the
+    <code>index()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.recolorborders></a>
+<dl><dt> <strong>recolorborders</strong>()</dt><dd>
+Change the color of the page and tab borders.  This method is
+    required because the borders are created as canvas polygons and
+    hence do not respond to normal color changing techniques, such as
+    <code>Pmw.Color.changecolor()</code>.</p>
+
+
+</dd></dl>
+<a name=method.selectpage></a>
+<dl><dt> <strong>selectpage</strong>(<em>page</em>)</dt><dd>
+Select <em>page</em> to be the currently selected page.  The page will be
+    raised and the previous selected page will be lowered.</p>
+
+
+</dd></dl>
+<a name=method.setnaturalsize></a>
+<dl><dt> <strong>setnaturalsize</strong>(<em>pageNames</em> = <strong>None</strong>)</dt><dd>
+Set the width and height of the notebook to be the maximum
+    requested width and height of the pages specified by <em>pageNames</em>.
+    If <em>pageNames</em> is <strong>None</strong>, the size of all pages are used to
+    determine the size of the notebook.  Otherwise, <em>pageNames</em> must
+    be a list of page names whose sizes are to be used to determine
+    the size of the notebook.  This method should be called after all
+    pages and their contents have been created.  It calls
+    <code>update_idletasks()</code> so that the width and height of the pages can
+    be determined.  This may cause the notebook to flash onto the
+    screen at the default size before resizing to the natural size.</p>
+
+
+</dd></dl>
+<a name=method.tab></a>
+<dl><dt> <strong>tab</strong>(<em>pageIndex</em>)</dt><dd>
+Return the tab component widget of the page <em>pageIndex</em>, where
+    <em>pageIndex</em> may have any of the forms accepted by the <code>index()</code>
+    method.  If <strong>tabpos</strong> is <strong>None</strong>, return <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the NoteBook.
+        notebook = Pmw.NoteBook(parent)
+        notebook.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+
+        # Add the "Appearance" page to the notebook.
+        page = notebook.add('Appearance')
+        notebook.tab('Appearance').focus_set()
+
+        # Create the "Toolbar" contents of the page.
+        group = Pmw.Group(page, tag_text = 'Toolbar')
+        group.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+        b1 = Tkinter.Checkbutton(group.interior(), text = 'Show toolbar')
+        b1.grid(row = 0, column = 0)
+        b2 = Tkinter.Checkbutton(group.interior(), text = 'Toolbar tips')
+        b2.grid(row = 0, column = 1)
+
+        # Create the "Startup" contents of the page.
+        group = Pmw.Group(page, tag_text = 'Startup')
+        group.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
+        home = Pmw.EntryField(group.interior(), labelpos = 'w',
+            label_text = 'Home page location:')
+        home.pack(fill = 'x', padx = 20, pady = 10)
+
+        # Add two more empty pages.
+        page = notebook.add('Helpers')
+        page = notebook.add('Images')
+
+        notebook.setnaturalsize()
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 30 October 1999
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/OptionMenu.gif b/Pmw/Pmw_1_2/doc/OptionMenu.gif
new file mode 100644 (file)
index 0000000..a36b151
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/OptionMenu.gif differ
diff --git a/Pmw/Pmw_1_2/doc/OptionMenu.html b/Pmw/Pmw_1_2/doc/OptionMenu.html
new file mode 100644 (file)
index 0000000..e1e0a6b
--- /dev/null
@@ -0,0 +1,289 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.OptionMenu reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.OptionMenu</h1>
+    
+<center><IMG SRC=OptionMenu.gif ALT="" WIDTH=298 HEIGHT=170></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.OptionMenu() - 
+    single item selection megawidget
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    An option menu consists of a menu button
+    and an associated menu which pops up when the button is pressed. 
+    The text displayed in the menu button is updated whenever an item
+    is selected in the menu.  The currently selected value can be
+    retrieved from the megawidget.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a menu item is selected or
+    the <code>invoke()</code> method is called.  The function is called with the
+    currently selected value as its single argument. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.initialitem></a>
+<dl><dt> <strong>initialitem
+</strong></dt><dd>
+Initialisation option. Specifies the initial selected value.  This option is treated in
+    the same way as the <em>index</em> argument of the <code>setitems()</code> method. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.items></a>
+<dl><dt> <strong>items
+</strong></dt><dd>
+Initialisation option. A sequence of strings containing the initial items to be displayed
+    in the <strong>menu</strong> component. The default is <strong>()</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'ew'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.menu></a>
+<dl><dt> <strong>menu
+</strong></dt><dd>
+The popup menu displayed when the <strong>menubutton</strong> is pressed. By default, this component is a Tkinter.Menu.</p>
+
+
+</dd></dl>
+<a name=component.menubutton></a>
+<dl><dt> <strong>menubutton
+</strong></dt><dd>
+The menu button displaying the currently selected value. By default, this component is a Tkinter.Menubutton.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.getcurselection></a>
+<dl><dt> <strong>getcurselection</strong>()</dt><dd>
+Same as <code>getvalue()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.getvalue></a>
+<dl><dt> <strong>getvalue</strong>()</dt><dd>
+Return the currently selected value.</p>
+
+
+</dd></dl>
+<a name=method.index></a>
+<dl><dt> <strong>index</strong>(<em>index</em>)</dt><dd>
+Return the numerical index of the menu item corresponding to
+    <em>index</em>.  This may be specified in any of the following forms:</p>
+<dl><dt><em>name</em></dt><dd>Specifies the menu item labelled <em>name</em>.<p></p>
+
+</dd>
+<dt><em>number</em></dt><dd>Specifies the menu item numerically, where <strong>0</strong> corresponds to
+         the first menu item.<p></p>
+
+</dd>
+<dt><strong>Pmw.END</strong></dt><dd>Specifies the last menu item.<p></p>
+
+</dd>
+<dt><strong>Pmw.SELECT</strong></dt><dd>Specifies the currently selected menu item.<p></p>
+
+</dd></dl>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>(<em>index</em> = <strong>Pmw.SELECT</strong>)</dt><dd>
+Calling this method is the same as selecting the menu item
+    specified by <em>index</em>:  the text displayed by the
+    <strong>menubutton</strong> component is updated and the function specified by
+    the <strong>command</strong> option is called.  <em>index</em> may have any of the
+    forms accepted by the <code>index()</code> method.  The value returned by
+    <strong>command</strong> is returned.</p>
+
+
+</dd></dl>
+<a name=method.setitems></a>
+<dl><dt> <strong>setitems</strong>(<em>items</em>, <em>index</em> = <strong>None</strong>)</dt><dd>
+Replace all the items in the <strong>menu</strong> component with those specified
+    by <em>items</em>, which must be a sequence of strings.</p>
+<p>    If <em>index</em> is not <strong>None</strong>, set the selected value to <em>index</em>, which
+    may have any of the forms accepted by the <code>index()</code> method.</p>
+
+<p>    If <em>index</em> is <strong>None</strong> and the <strong>textvariable</strong> option of the
+    <strong>menubutton</strong> component is the empty string, then if
+    the previous selected value is one of the <em>items</em>, then do not
+    change the selection.  If the previous selected value is no longer
+    in <em>items</em>, then set the selected value to the first value in
+    <em>items</em>.  If <em>items</em> is empty, set the selected value to the empty
+    string.</p>
+
+<p>    If <em>index</em> is <strong>None</strong> and the <strong>textvariable</strong> option of the
+    <strong>menubutton</strong> component is not the empty string, then do not set
+    the selected value.  This assumes that the variable is already (or
+    will be) set to the desired value.</p>
+
+
+
+</dd></dl>
+<a name=method.setvalue></a>
+<dl><dt> <strong>setvalue</strong>(<em>text</em>)</dt><dd>
+Set the text displayed by the <strong>menubutton</strong> component to <em>text</em>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the OptionMenu megawidgets.
+        # The first one has a textvariable.
+        self.var = Tkinter.StringVar()
+        self.var.set('steamed')
+        self.method_menu = Pmw.OptionMenu(parent,
+                labelpos = 'w',
+                label_text = 'Choose method:',
+                menubutton_textvariable = self.var,
+                items = ['baked', 'steamed', 'stir fried', 'boiled', 'raw'],
+                menubutton_width = 10,
+        )
+        self.method_menu.pack(anchor = 'w', padx = 10, pady = 10)
+
+        self.vege_menu = Pmw.OptionMenu (parent,
+                labelpos = 'w',
+                label_text = 'Choose vegetable:',
+                items = ('broccoli', 'peas', 'carrots', 'pumpkin'),
+                menubutton_width = 10,
+                command = self._printOrder,
+        )
+        self.vege_menu.pack(anchor = 'w', padx = 10, pady = 10)
+
+        self.direction_menu = Pmw.OptionMenu (parent,
+                labelpos = 'w',
+                label_text = 'Menu direction:',
+                items = ('flush', 'above', 'below', 'left', 'right'),
+                menubutton_width = 10,
+                command = self._changeDirection,
+        )
+        self.direction_menu.pack(anchor = 'w', padx = 10, pady = 10)
+
+        menus = (self.method_menu, self.vege_menu, self.direction_menu)
+        Pmw.alignlabels(menus)
+
+    def _printOrder(self, vege):
+        # Can use 'self.var.get()' instead of 'getcurselection()'.
+        print 'You have chosen %s %s.' % \
+            (self.method_menu.getcurselection(), vege)
+
+    def _changeDirection(self, direction):
+        for menu in (self.method_menu, self.vege_menu, self.direction_menu):
+            menu.configure(menubutton_direction = direction)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 23 October 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/PanedWidget.gif b/Pmw/Pmw_1_2/doc/PanedWidget.gif
new file mode 100644 (file)
index 0000000..eecbbf2
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/PanedWidget.gif differ
diff --git a/Pmw/Pmw_1_2/doc/PanedWidget.html b/Pmw/Pmw_1_2/doc/PanedWidget.html
new file mode 100644 (file)
index 0000000..bcbb663
--- /dev/null
@@ -0,0 +1,345 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.PanedWidget reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.PanedWidget</h1>
+    
+<center><IMG SRC=PanedWidget.gif ALT="" WIDTH=400 HEIGHT=128></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.PanedWidget() - 
+    frame subdivided into several resizable panes
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A paned widget is a container megawidget which manages a number of
+    resizable frames, known as panes.  Each pane may act as the container for
+    other widgets.  The user may interactively resize the panes by
+    dragging a small rectangle (the handle) or the line between the
+    panes (the separator).  The panes may be arranged horizontally or
+    vertically.  Each pane may have maximum and minimum limits of its
+    size.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to be called whenever the size of any of the
+    panes changes.  The function is called with a single argument,
+    being a list of the sizes of the panes, in order.  For <strong>vertical</strong>
+    orientation, the size is the height of the panes.  For
+    <strong>horizontal</strong> orientation, the size is the width of the panes. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.handlesize></a>
+<dl><dt> <strong>handlesize
+</strong></dt><dd>
+Initialisation option. Specifies the size in pixels of the square handle which appears on
+    the lines separating the panes. The default is <strong>8</strong>.</p>
+
+
+</dd></dl>
+<a name=option.orient></a>
+<dl><dt> <strong>orient
+</strong></dt><dd>
+Initialisation option. Specifies the orientation of the paned widget.  This may be
+    <strong>'horizontal'</strong> or <strong>'vertical'</strong>.  If <strong>'vertical'</strong>, the panes are
+    stacked above and below each other, otherwise the panes are laid
+    out side by side. The default is <strong>'vertical'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorrelief></a>
+<dl><dt> <strong>separatorrelief
+</strong></dt><dd>
+Initialisation option. Specifies the relief of the lines separating the panes. The default is <strong>'sunken'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorthickness></a>
+<dl><dt> <strong>separatorthickness
+</strong></dt><dd>
+Initialisation option. Specifies the thickness of the lines separating the panes. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Pane options</h3></dt><dd>
+<p>
+        Each pane has the following options.  These may be set when
+        creating or configuring a pane.  The value of each option may
+        be an integer, which specifies a pane size in pixels, or a
+        real number between 0.0 and 1.0, which specifies a pane size
+        proportional to the size of the entire paned widget.</p>
+
+<dl><dt><strong>size</strong></dt><dd>Specifies the initial size of the pane.  The default is <strong>0</strong>.<p></p>
+
+</dd>
+<dt><strong>min</strong></dt><dd>Specifies the minimum size of the pane.  The default is <strong>0</strong>.<p></p>
+
+</dd>
+<dt><strong>max</strong></dt><dd>Specifies the maximum size of the pane.  The default is a
+            very large number.<p></p>
+<p>        </p>
+
+
+</dd></dl>
+
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Dynamic components</h3></dt><dd>
+<p>
+        Frame, separator and handle components are created dynamically
+        by the <code>add()</code> and <code>insert()</code> methods.  The components are of type
+        Tkinter.Frame and are created with component groups of
+        <strong>Frame</strong>, <strong>Separator</strong> and <strong>Handle</strong> respectively.</p>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.add></a>
+<dl><dt> <strong>add</strong>(<em>name</em>, **<em>kw</em>)</dt><dd>
+Add a pane to the end of the paned widget as a component named
+    <em>name</em>.  This is equivalent to calling <code>insert()</code> with <em>before</em>
+    set to the current number of panes.  The method returns the <em>name</em>
+    component widget.</p>
+
+
+</dd></dl>
+<a name=method.configurepane></a>
+<dl><dt> <strong>configurepane</strong>(<em>name</em>, **<em>kw</em>)</dt><dd>
+Configure the pane specified by <em>name</em>, where <em>name</em> is either an
+    integer, specifying the index of the pane, or a string, specifying
+    the name of the pane.  The keyword arguments specify the new
+    values for the options for the pane.  These options are described
+    in the <strong>Pane options</strong> section.</p>
+
+
+</dd></dl>
+<a name=method.delete></a>
+<dl><dt> <strong>delete</strong>(<em>name</em>)</dt><dd>
+Delete the pane specified by <em>name</em>, where <em>name</em> is either an
+    integer, specifying the index of the pane, or a string, specifying
+    the name of the pane.</p>
+<p>    If the pane deleted was not the only pane in the paned widget,
+    also delete the separator and handle components named
+    <strong>separator</strong>-<em>n</em> and <strong>handle</strong>-<em>n</em>, where <em>n</em> is the number of
+    panes remaining.</p>
+
+
+
+</dd></dl>
+<a name=method.insert></a>
+<dl><dt> <strong>insert</strong>(<em>name</em>, <em>before</em> = <strong>0</strong>, **<em>kw</em>)</dt><dd>
+Add a pane to the paned widget as a component named <em>name</em>.  The
+    pane is added just before the pane specified by <em>before</em>, where
+    <em>before</em> may be either an integer, specifying the index of the
+    pane, or a string, specifying the name of the pane.  The keyword
+    arguments specify the initial values for the options for the new
+    pane.  These options are described in the <strong>Pane options</strong> section. 
+    To add a pane to the end of the paned widget, use <code>add()</code>.</p>
+<p>    The new pane is created as a Tkinter.Frame component named <em>name</em>. 
+    If this is not the only pane, a separator and handle are also
+    created as components named <strong>separator</strong>-<em>n</em> and <strong>handle</strong>-<em>n</em>,
+    where <em>n</em> is one less than the number of panes.  The method
+    returns the <em>name</em> component widget.</p>
+
+
+
+</dd></dl>
+<a name=method.move></a>
+<dl><dt> <strong>move</strong>(<em>name</em>, <em>newPos</em>, <em>newPosOffset</em> = <strong>0</strong>)</dt><dd>
+Move the pane specified by <em>name</em> to the new position specified by
+    <em>newPos</em>.  The first two arguments may be either an integer,
+    specifying the index of the pane, or a string, specifying the name
+    of the pane.  If <em>newPosOffset</em> is specified, it is added to the
+    <em>newPos</em> index.  For example, to move a horizontal pane one pane
+    to the left, specify the name or index of the pane for both <em>name</em>
+    and <em>newPos</em> and specify <strong>-1</strong> for <em>newPosOffset</em>.</p>
+
+
+</dd></dl>
+<a name=method.pane></a>
+<dl><dt> <strong>pane</strong>(<em>name</em>)</dt><dd>
+Return the Tkinter.Frame pane widget for the pane specified by
+    <em>name</em>, where <em>name</em> is either an integer, specifying the index of
+    the pane, or a string, specifying the name of the pane.</p>
+
+
+</dd></dl>
+<a name=method.panes></a>
+<dl><dt> <strong>panes</strong>()</dt><dd>
+Return a list of the names of the panes, in display order.</p>
+
+
+</dd></dl>
+<a name=method.setnaturalsize></a>
+<dl><dt> <strong>setnaturalsize</strong>()</dt><dd>
+If oriented horizontally, set the width of the paned widget to the
+    sum of the requested widths of all panes and set the height to the
+    maximum requested height of all panes.</p>
+<p>    If oriented vertically, set the height of the paned widget to the
+    sum of the requested heights of all panes and set the width to the
+    maximum requested width of all panes.</p>
+
+
+
+</dd></dl>
+<a name=method.updatelayout></a>
+<dl><dt> <strong>updatelayout</strong>()</dt><dd>
+Recalculate size and position of panes.  This method must be
+    called after adding or deleting one or more panes.  However it
+    does not need to be called when panes are first added to a newly
+    created paned widget, before it has been displayed.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+
+        # Create a main PanedWidget with a few panes.
+        self.pw = Pmw.PanedWidget(parent,
+                orient='vertical',
+                hull_borderwidth = 1,
+                hull_relief = 'sunken',
+                hull_width=300,
+                hull_height=400)
+        for self.numPanes in range(4):
+            if self.numPanes == 1:
+                name = 'Fixed size'
+                pane = self.pw.add(name, min = .1, max = .1)
+            else:
+                name = 'Pane ' + str(self.numPanes)
+                pane = self.pw.add(name, min = .1, size = .25)
+            label = Tkinter.Label(pane, text = name)
+            label.pack(side = 'left', expand = 1)
+            button = Tkinter.Button(pane, text = 'Delete',
+                    command = lambda s=self, n=name: s.deletePane(n))
+            button.pack(side = 'left', expand = 1)
+            # TODO: add buttons to invoke self.moveOneUp and self.moveOneUp.
+
+        self.pw.pack(expand = 1, fill='both')
+
+        buttonBox = Pmw.ButtonBox(parent)
+        buttonBox.pack(fill = 'x')
+        buttonBox.add('Add pane', command = self.addPane)   
+        buttonBox.add('Move pane', command = self.move)   
+        self.moveSrc = 0
+        self.moveNewPos = 1
+        self.moveBack = 0
+
+    def move(self):
+        numPanes = len(self.pw.panes())
+        if numPanes == 0:
+            print 'No panes to move!'
+            return
+
+        if self.moveSrc &gt;= numPanes:
+            self.moveSrc = numPanes - 1
+        if self.moveNewPos &gt;= numPanes:
+            self.moveNewPos = numPanes - 1
+        print 'Moving pane', self.moveSrc, 'to new position', self.moveNewPos
+        self.pw.move(self.moveSrc, self.moveNewPos)
+
+        self.moveSrc, self.moveNewPos = self.moveNewPos, self.moveSrc
+        if self.moveBack:
+            if self.moveNewPos == numPanes - 1:
+                self.moveNewPos = 0
+                if self.moveSrc == numPanes - 1:
+                    self.moveSrc = 0
+                else:
+                    self.moveSrc = self.moveSrc + 1
+            else:
+                self.moveNewPos = self.moveNewPos + 1
+        self.moveBack = not self.moveBack
+
+    def addPane(self):
+        self.numPanes = self.numPanes + 1
+        name = 'Pane ' + str(self.numPanes)
+        print 'Adding', name
+        pane = self.pw.add(name, min = .1, size = .25)
+        label = Tkinter.Label(pane, text = name)
+        label.pack(side = 'left', expand = 1)
+        button = Tkinter.Button(pane, text = 'Delete',
+                command = lambda s=self, n=name: s.deletePane(n))
+        button.pack(side = 'left', expand = 1)
+        self.pw.updatelayout()
+
+    def deletePane(self, name):
+        print 'Deleting', name
+        self.pw.delete(name)
+        self.pw.updatelayout()
+
+    def moveOneUp(self, name):
+        self.pw.move(name, name, -1)
+
+    def moveOneDown(self, name):
+        self.pw.move(name, name, 1)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 14 April 2001
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/PmwFunctions.html b/Pmw/Pmw_1_2/doc/PmwFunctions.html
new file mode 100644 (file)
index 0000000..af22de8
--- /dev/null
@@ -0,0 +1,766 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw functions reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw functions</h1>
+    
+<dl>
+<dt> <strong>Pmw.aboutcontact</strong>(<em>value</em>)</dt><dd>
+<p>
+    The value passed to this function is used to construct the text
+    displayed by <a href="AboutDialog.html">Pmw.AboutDialog</a> megawidgets created subsequently.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.aboutcopyright</strong>(<em>value</em>)</dt><dd>
+<p>
+    The value passed to this function is used to construct the text
+    displayed by <a href="AboutDialog.html">Pmw.AboutDialog</a> megawidgets created subsequently.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.aboutversion</strong>(<em>value</em>)</dt><dd>
+<p>
+    The value passed to this function is used to construct the text
+    displayed by <a href="AboutDialog.html">Pmw.AboutDialog</a> megawidgets created subsequently.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.aligngrouptags</strong>(<em>groups</em>)</dt><dd>
+<p>
+    This function takes a sequence of <a href="Group.html">Pmw.Group</a>s and adjusts the
+    vertical position of the tags in each group so that they all have
+    the height of the tallest tag.  This can be used when groups are
+    positioned side-by-side but the natural height of the tags are
+    different because, for example, different fonts with different
+    sizes are used.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.alignlabels</strong>(<em>widgets</em>, <em>sticky</em> = <strong>None</strong>)</dt><dd>
+<p>
+    Adjust the size of the labels of all the <em>widgets</em> to be equal, so
+    that the body of each widget lines up vertically.  This assumes
+    that each widget is a megawidget with a <strong>label</strong> component in
+    column 0 (ie, the <strong>labelpos</strong> option was set to <strong>'w'</strong>, <strong>'wn'</strong> or
+    <strong>'ws'</strong>).  If <em>sticky</em> is set to a combination of <strong>'n'</strong>, <strong>'s'</strong>,
+    <strong>'e'</strong> and <strong>'w'</strong>, the label will be positioned within its cell
+    accordingly.  For example to make labels right justified, set
+    <em>sticky</em> to <strong>'e'</strong>, <strong>'ne'</strong> or <strong>'se'</strong>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.alphabeticvalidator</strong>(<em>text</em>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>alphabetic</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.alphanumericvalidator</strong>(<em>text</em>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>alphanumeric</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.busycallback</strong>(<em>command</em>, <em>updateFunction</em> = <strong>None</strong>)</dt><dd>
+<p>
+    Create a wrapper function which displays a busy cursor while
+    executing <em>command</em> and return the wrapper.  When the wrapper
+    function is called, it first calls <code>Pmw.showbusycursor()</code>, then
+    the <em>command</em> (passing any arguments to it), then <code>Pmw.hidebusycursor()</code>.
+    The return value of <em>command</em> is returned from the wrapper.</p>
+
+<p>    If <em>updateFunction</em> is specified, it is called just before the
+    call to <code>Pmw.hidebusycursor()</code>.  This is intended to be the
+    Tkinter <code>update()</code> method, in which case it will clear any events
+    that may have occurred while <em>command</em> was executing.  An example
+    of this usage is in the <code>ShowBusy</code> demonstration:  run the
+    demonstration, click on the entry widget then click on the button
+    and type some characters while the busy cursor is displayed.  No
+    characters should appear in the entry widget.</p>
+
+<p>    Note that the Tkinter <code>update()</code> method should only be called when
+    it is known that it can be safely called.  One case where a
+    problem has been found is when a filehandler has been created (on
+    a non-blocking Oracle database connection), but the filehandler
+    does not read from the connection.  The connection is read (by a
+    call to the Oracle fetch function <em>ofen</em>) in a loop which also
+    contains a call to <code>_tkinter.dooneevent()</code>.  If <code>update()</code> is
+    called from <code>dooneevent()</code> and there is data to be read on the
+    connection, then the filehandler will be called continuously, thus
+    hanging the application.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.clearbusycursor</strong>()</dt><dd>
+<p>
+    Unconditionally remove the event block and busy cursor from all
+    windows.  This undoes all outstanding calls to
+    <code>Pmw.showbusycursor()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.datestringtojdn</strong>(<em>text</em>, <em>format</em> = <strong>'ymd'</strong>, <em>separator</em> = <strong>'/'</strong>)</dt><dd>
+<p>
+    Return the Julian Day Number corresponding to the date in <em>text</em>.
+    A Julian Day Number is defined as the number of days since 1 Jan 4713
+    BC.  The date must be specified as three integers separated by the
+    <em>separator</em> character.  The integers must be in the order specified by
+    <em>format</em>, which must be a combination of <strong>'d'</strong>, <strong>'m'</strong> and <strong>'y'</strong> in
+    any order.  These give the order of the day, month and year
+    fields.  Examples of valid input are:</p>
+<dl><dd><pre> 'dmy':  31/01/99  31/1/1999  31/1/99
+ 'mdy':  01/31/99  1/31/1999  1/31/99
+ 'ymd':  99/01/31  1999/1/31  99/1/31</pre></dd></dl>
+
+
+<p>    If the application's 
+    <em>pivot</em> year (default 50) is not <strong>None</strong> and the year specified
+    in <em>text</em> has only one or two digits, then the year is
+    converted to a four digit year.  If it is less than or equal to
+    the pivot year, then it is incremented by the application's
+    <em>century</em> value (default 2000).  If it is more than the pivot year
+    then it is incremented by the <em>century</em> value less 100.</p>
+
+<p>    The function <code>Pmw.setyearpivot()</code> can be used to change the
+    default values for the application's
+    <em>pivot</em> and <em>century</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.datevalidator</strong>(<em>text</em>, <em>format</em> = <strong>'ymd'</strong>, <em>separator</em> = <strong>'/'</strong>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>date</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.displayerror</strong>(<em>text</em>)</dt><dd>
+<p>
+    This is a general purpose method for displaying background errors
+    to the user.  The errors would normally be programming errors and
+    may be caused by errors in Tk callbacks or functions called by other
+    asynchronous events.</p>
+
+<p>    If the global error report file (set by calling
+    <code>Pmw.reporterrorstofile()</code>) is <strong>None</strong>, the error message `text` is
+    written to standard error and also shown in a text window.  If
+    <code>displayerror</code> is called while previous error messages are being
+    displayed, the window is raised and the new error is queued.  The
+    queued errors may be viewed by the user or ignored by dismissing
+    the window.</p>
+
+<p>    If the global error report file is not <strong>None</strong>, `text` is written
+    to the file.  <em>file</em> may be any object with a <code>write()</code> method,
+    such as <code>sys.stderr</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.drawarrow</strong>(<em>canvas</em>, <em>color</em>, <em>direction</em>, <em>tag</em>, <em>baseOffset</em> = <strong>0.25</strong>, <em>edgeOffset</em> = <strong>0.15</strong>)</dt><dd>
+<p>
+    Draw a triangle in the Tkinter.Canvas <em>canvas</em> in the given
+    <em>color</em>.  The value of <em>direction</em> may be <strong>'up'</strong>, <strong>'down'</strong>,
+    <strong>'left'</strong> or <strong>'right'</strong> and specifies which direction the arrow
+    should point.  The values of <em>baseOffset</em> and <em>edgeOffset</em> specify
+    how far from the edges of the canvas the points of the triangles
+    are as a fraction of the size of the canvas.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.forwardmethods</strong>(<em>fromClass</em>, <em>toClass</em>, <em>toPart</em>, <em>exclude</em> = <strong>()</strong>)</dt><dd>
+<p>
+    Forward methods from one class to another.</p>
+
+<p>    This function adds methods to the class <em>fromClass</em>.  The names of
+    the methods added are the names of the methods of the class
+    <em>toClass</em> (and its base classes) except those which are already
+    defined by <em>fromClass</em> or are found in the <em>exclude</em> list. 
+    Special methods with one or more leading or trailing underscores
+    are also excluded.</p>
+
+<p>    When one of the added methods is called, the method of the same
+    name is called on an instance defined by <em>toPart</em> and the return
+    value passed back.  If <em>toPart</em> is a string, then it specifies the
+    name of an attribute (<em>not</em> a component) of the <em>fromClass</em>
+    object.  The class of this attribute should be <em>toClass</em>.  If
+    <em>toPart</em> is not a string, it must be a function taking a
+    <em>fromClass</em> object and returning a <em>toClass</em> object.</p>
+
+<p>    This function must be called outside of and after the definition
+    of <em>fromClass</em>.</p>
+
+<p>    For example:</p>
+
+<dl><dd><pre>class MyClass:
+    def __init__(self):
+        ...
+        self.__target = TargetClass()
+        ...
+
+    def foo(self):
+        pass
+
+    def findtarget(self):
+        return self.__target
+
+Pmw.forwardmethods(MyClass, TargetClass, '__target',
+    ['dangerous1', 'dangerous2'])
+
+# ...or...
+
+Pmw.forwardmethods(MyClass, TargetClass,
+    MyClass.findtarget, ['dangerous1', 'dangerous2'])</pre></dd></dl>
+
+<p>    In both cases, all <code>TargetClass</code> methods will be forwarded from
+    <code>MyClass</code> except for <code>dangerous1</code>, <code>dangerous2</code>, special methods like
+    <code>__str__</code>, and pre-existing methods like <code>foo</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.grabstacktopwindow</strong>()</dt><dd>
+<p>
+    Return the window at the top of the grab stack (the window
+    currently with the grab) or <strong>None</strong> if the grab stack is empty (no
+    window has the grab).  See also <code>pushgrab()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.hexadecimalvalidator</strong>(<em>text</em>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>hexadecimal</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.hidebusycursor</strong>(<em>forceFocusRestore</em> = <strong>0</strong>)</dt><dd>
+<p>
+    Undo one call to <code>Pmw.showbusycursor()</code>.  If there are no
+    outstanding calls to <code>Pmw.showbusycursor()</code>, remove the event
+    block and busy cursor.</p>
+
+<p>    If the focus window has not been changed since the corresponding
+    call to <code>Pmw.showbusycursor()</code>, or if <em>forceFocusRestore</em> is true,
+    then the focus is restored to that saved by <code>Pmw.showbusycursor()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.initialise</strong>(<em>root</em> = <strong>None</strong>, <em>size</em> = <strong>None</strong>, <em>fontScheme</em> = <strong>None</strong>, <em>useTkOptionDb</em> = <strong>0</strong>, <em>noBltBusy</em> = <strong>0</strong>, <em>disableKeyboardWhileBusy</em> = <strong>None</strong>)</dt><dd>
+<p>
+    Initialise Pmw.  This performs several functions:</p>
+<ul><li><p>Set up a trap in the Tkinter Toplevel constructor so that a
+          list of Toplevels can be maintained.  A list of all Toplevel
+          windows needs to be kept so that <code>Pmw.showbusycursor()</code> can
+          create busy cursors for them.</p>
+
+</li>
+<li><p>Set up a trap in the Tkinter Toplevel and Frame destructors
+          so that Pmw is notified when these widgets are destroyed. 
+          This allows Pmw to destroy megawidgets when their hull
+          widget is destroyed and to prune the list of Toplevels.</p>
+
+</li>
+<li><p>Modify Tkinter's CallWrapper class to improve the display of
+          errors which occur in callbacks.  If an error occurs, the
+          new CallWrapper class calls <code>Pmw.clearbusycursor()</code> to
+          remove any outstanding busy cursors and calls
+          <code>Pmw.displayerror()</code> to display the error.</p>
+
+</li>
+<li><p>Using the window given by <em>root</em>, set the <strong>WM_DELETE_WINDOW</strong>
+          root window protocol to destroy the root window.  This means
+          that the root window is destroyed if the window manager
+          deletes it.  This is only done if the protocol has not been
+          set before the call to <code>Pmw.initialise()</code>.  This protocol is
+          required if there is a modal dialog displayed and the window
+          manager deletes the root window.  Otherwise the application
+          will not exit, even though there are no windows.</p>
+
+</li>
+<li><p>Set the base font size for the application to <em>size</em>.  This
+          is used by <code>Pmw.logicalfont()</code> as the default point size for
+          fonts.  If this is not given, the default is <strong>14</strong>, except
+          under NT where it is <strong>16</strong>.  These are reasonable default
+          sizes for most screens, but for unusually high or low screen
+          resolutions, an appropriate size should be supplied.  Note
+          that Tk's definition of <em>point size</em>, is somewhat
+          idiosyncratic.</p>
+
+</li>
+<li><p>Set the Tk option database for <em>root</em> according to
+          <em>fontScheme</em>.  This changes the default fonts set by Tk. 
+          <em>fontScheme</em> may be one of</p>
+<dl><dt><strong>None</strong> </dt><dd>Do not change the Tk defaults.<p></p>
+
+</dd>
+<dt><strong>'pmw1'</strong> </dt><dd>If running under posix (Unix), set the default font to
+                be Helvetica with bold italic menus, italic scales and
+                a special balloon font 6 points smaller than the base
+                font size and with the <strong>'pixel'</strong> field set to <strong>'12'</strong>.
+                For other operating systems (such as NT or Macintosh),
+                simply set the default font to be Helvetica.  All
+                fonts are as returned by calls to <code>Pmw.logicalfont()</code>.<p></p>
+
+</dd>
+<dt><strong>'pmw2'</strong> </dt><dd>This is the same as <strong>'pmw1'</strong> except that under posix
+                the balloon font is 2 points smaller than the base
+                font size and the <strong>'pixel'</strong> field is not set.<p></p>
+
+</dd>
+<dt><strong>'default'</strong> </dt><dd>This sets the default fonts using the Tk font naming
+                convention, rather than that returned by
+                <code>Pmw.logicalfont()</code>.  The default font is bold
+                Helvetica.  The font for entry widgets is Helvetica. 
+                The font for text widgets is Courier The size of all
+                fonts is the application base font size as described
+                above.<p></p>
+
+</dd></dl>
+
+</li>
+<li><p>If <em>root</em> is <strong>None</strong>, use the Tkinter default root window as the
+          root, if it has been created, or create a new Tk root window.
+          The <code>initialise()</code> method returns this <em>root</em>.</p>
+
+</li>
+<li><p>If <em>useTkOptionDb</em> is true, then, when a megawidget is
+          created, the Tk option database will be queried to get the
+          initial values of the options which have not been set in
+          the call to the constructor.  The resource name used in the
+          query is the same as the option name and the resource class
+          is the option name with the first letter capitalised.  If
+          <em>useTkOptionDb</em> is false, then options for newly created
+          megawidgets will be initialised to default values.</p>
+
+</li>
+<li><p>If <em>noBltBusy</em> is true, then <code>Pmw.showbusycursor()</code> will not
+          display a busy cursor, even if the BLT busy command is
+          present.</p>
+
+</li>
+<li><p>If <em>disableKeyboardWhileBusy</em> is false, then do not disable
+          keyboard input while displaying the busy cursor.  Normally,
+          Pmw ignores keyboard input while displaying the busy cursor
+          by setting the focus for each toplevel window to the Blt
+          busy window.  However, under NT, this may cause the toplevel
+          windows to be raised.  If this is not acceptable, programs
+          running on NT can request show/hidebusycursor to not ignore
+          keyboard input by setting <em>disableKeyboardWhileBusy</em> to true
+          in <code>Pmw.initialise()</code>.</p>
+
+</li></ul>
+
+<p>    It is not absolutely necessary to call this function to be able to use
+    Pmw.  However, some functionality will be lost.  Most importantly,
+    Pmw megawidgets will not be notified when their hull widget is
+    destroyed.  This may prevent the megawidget from cleaning up
+    timers which will try to access the widget, hence causing a
+    background error to occur.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.installedversions</strong>(<em>alpha</em> = <strong>0</strong>)</dt><dd>
+<p>
+    If <em>alpha</em> is false, return the list of base versions of Pmw
+    that are currently installed and available for use.  If <em>alpha</em> is
+    true, return the list of alpha versions.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.integervalidator</strong>(<em>text</em>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>integer</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.jdntoymd</strong>(<em>jdn</em>, <em>julian</em> = <strong>-1</strong>, <em>papal</em> = <strong>1</strong>)</dt><dd>
+<p>
+    Return the year, month and day of the Julian Day Number <em>jdn</em>.  If
+    <em>julian</em> is <strong>1</strong>, then the date returned will be in the Julian
+    calendar.  If <em>julian</em> is <strong>0</strong>, then the date returned will be in
+    the modern calendar.  If <em>julian</em> is <strong>-1</strong>, then which calendar to
+    use will be automatically determined by the value of <em>jdn</em> and
+    <em>papal</em>.  If <em>papal</em> is true, then the date set by Pope Gregory
+    XIII's decree (4 October 1582) will be used as the last day to use
+    the Julian calendar.  If <em>papal</em> is false, then the last day to
+    use the Julian calendar will be according to British-American
+    usage (2 September 1752).</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.logicalfont</strong>(<em>name</em> = <strong>'Helvetica'</strong>, <em>sizeIncr</em> = <strong>0</strong>, **<em>kw</em>)</dt><dd>
+<p>
+    Return the full name of a Tk font, being a hyphen-separated list
+    of font properties.  The <em>logical</em> name of the font is given by
+    <em>name</em> and may be one of <strong>'Helvetica'</strong>, <strong>'Times'</strong>, <strong>'Fixed'</strong>,
+    <strong>'Courier'</strong> or <strong>'Typewriter'</strong>.  Pmw uses this name to define the
+    default values of many of the font properties.  The size of the
+    font is the base font size for the application specified in the
+    call to <code>Pmw.initialise()</code> increased or decreased by the value of
+    <em>sizeIncr</em>.  The other properties of the font may be specified by
+    other named arguments.  These may be <strong>'registry'</strong>, <strong>'foundry'</strong>,
+    <strong>'family'</strong>, <strong>'weight'</strong>, <strong>'slant'</strong>, <strong>'width'</strong>, <strong>'style'</strong>,
+    <strong>'pixel'</strong>, <strong>'size'</strong>, <strong>'xres'</strong>, <strong>'yres'</strong>, <strong>'spacing'</strong>,
+    <strong>'avgwidth'</strong>, <strong>'charset'</strong> and <strong>'encoding'</strong>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.logicalfontnames</strong>()</dt><dd>
+<p>
+    Return the list of known logical font names that can be given
+    to <code>Pmw.logicalfont()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.numericvalidator</strong>(<em>text</em>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>numeric</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.popgrab</strong>(<em>window</em>)</dt><dd>
+<p>
+    Remove <em>window</em> from the grab stack.  If there are not more
+    windows in the grab stack, release the grab.  Otherwise set the
+    grab and the focus to the next window in the grab stack.  See also
+    <code>pushgrab()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.pushgrab</strong>(<em>grabWindow</em>, <em>globalMode</em>, <em>deactivateFunction</em>)</dt><dd>
+<p>
+    The grab functions (<code>pushgrab()</code>, <code>popgrab()</code>, <code>releasegrabs()</code>
+    and <code>grabstacktopwindow()</code>) are an interface to the Tk <strong>grab</strong>
+    command which implements simple pointer and keyboard grabs.  When
+    a grab is set for a particular window, Tk restricts all pointer
+    events to the grab window and its descendants in Tk's window
+    hierarchy.  The functions are used by the <code>activate()</code> and
+    <code>deactivate()</code> methods to implement modal dialogs.</p>
+
+<p>    Pmw maintains a stack of grabbed windows, where the window on the
+    top of the stack is the window currently with the grab.  The grab
+    stack allows nested modal dialogs, where one modal dialog can be
+    activated while another modal dialog is activated.  When the
+    second dialog is deactivated, the first dialog becomes active
+    again.</p>
+
+<p>    Use <code>pushgrab()</code> to add <em>grabWindow</em> to the grab stack.  This
+    releases the grab by the window currently on top of the stack (if
+    there is one) and gives the grab and focus to the <em>grabWindow</em>. 
+    If <em>globalMode</em> is true, perform a global grab, otherwise perform
+    a local grab.  The value of <em>deactivateFunction</em> specifies a
+    function to call (usually grabWindow.deactivate) if popgrab() is
+    called (usually from a deactivate() method) on a window which is
+    not at the top of the stack (that is, does not have the grab or
+    focus).  For example, if a modal dialog is deleted by the window
+    manager or deactivated by a timer.  In this case, all dialogs
+    above and including this one are deactivated, starting at the top
+    of the stack.</p>
+
+<p>    For more information, see the Tk grab manual page.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.realvalidator</strong>(<em>text</em>, <em>separator</em> = <strong>'.'</strong>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>real</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.releasegrabs</strong>()</dt><dd>
+<p>
+    Release grab and clear the grab stack.  This should normally not
+    be used, use <code>popgrab()</code> instead.  See also <code>pushgrab()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.reporterrorstofile</strong>(<em>file</em> = <strong>None</strong>)</dt><dd>
+<p>
+    Sets the global error report file, which is initially <strong>None</strong>.  See
+    <code>Pmw.displayerror()</code></p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.setalphaversions</strong>(*<em>alpha_versions</em>)</dt><dd>
+<p>
+    Set the list of alpha versions of Pmw to use for this session to
+    the arguments.  When searching for Pmw classes and functions,
+    these alpha versions will be searched, in the order given, before
+    the base version.  This must be called before any other Pmw class
+    or function, except functions setting or querying versions.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.setbusycursorattributes</strong>(<em>window</em>, **<em>kw</em>)</dt><dd>
+<p>
+    Use the keyword arguments to set attributes controlling the effect
+    on <em>window</em> (which must be a <strong>Tkinter.Toplevel</strong>) of future calls
+    to <code>Pmw.showbusycursor()</code>.  The attributes are:</p>
+
+<dl><dt><strong>exclude</strong></dt><dd>a boolean value which specifies whether the window
+    will be affected by calls to <code>Pmw.showbusycursor()</code>.  If a window
+    is excluded, then the cursor will not be changed to a busy cursor
+    and events will still be delivered to the window.  By default,
+    windows are affected by calls to <code>Pmw.showbusycursor()</code>.<p></p>
+
+</dd>
+<dt><strong>cursorName</strong></dt><dd>the name of the cursor to use when displaying the
+    busy cursor.  If <strong>None</strong>, then the default cursor is used.<p></p>
+
+</dd></dl>
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.setgeometryanddeiconify</strong>(<em>window</em>, <em>geom</em>)</dt><dd>
+<p>
+    Deiconify and raise the toplevel <em>window</em> and set its position and
+    size according to <em>geom</em>.  This overcomes some problems with the
+    window flashing under X and correctly positions the window under
+    NT (caused by Tk bugs).</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.setversion</strong>(<em>version</em>)</dt><dd>
+<p>
+    Set the version of Pmw to use for this session to <em>version</em>.  If
+    <code>Pmw.setversion()</code> is not called, the latest installed version of
+    Pmw will be used.  This must be called before any other Pmw class
+    or function, except functions setting or querying versions.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.setyearpivot</strong>(<em>pivot</em>, <em>century</em> = <strong>None</strong>)</dt><dd>
+<p>
+    Set the pivot year and century for the application's date
+    processing.  These values are used in the <code>datestringtojdn()</code>
+    method, which is used by <a href="Counter.html">Pmw.Counter</a> and <a href="EntryField.html">Pmw.EntryField</a>
+    and derived classes.  The initial values of <em>pivot</em> and <em>century</em>
+    are <strong>50</strong> and <strong>2000</strong> repectively.  Return a tuple containing the
+    old values of <em>pivot</em> and <em>century</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.showbusycursor</strong>()</dt><dd>
+<p>
+    Block events to and display a busy cursor over all windows in this
+    application that are in the state <strong>'normal'</strong> or <strong>'iconic'</strong>, except
+    those windows whose <strong>exclude</strong> busycursor attribute has been set to
+    true by a call to <code>Pmw.setbusycursorattributes()</code>.</p>
+
+<p>    If a window and its contents have just been created,
+    <code>update_idletasks()</code> may have to be called before
+    <code>Pmw.showbusycursor()</code> so that the window is mapped to the screen. 
+    Windows created or deiconified after calling
+    <code>Pmw.showbusycursor()</code> will not be blocked.</p>
+
+<p>    To unblock events and remove the busy cursor, use
+    <code>Pmw.hidebusycursor()</code>.  Nested calls to <code>Pmw.showbusycursor()</code>
+    may be made.  In this case, a matching number of calls to
+    <code>Pmw.hidebusycursor()</code> must be made before the event block and
+    busy cursor are removed.</p>
+
+<p>    If the BLT extension to Tk is not present, this function has no
+    effect other than to save the value of the current focus window,
+    to be later restored by <code>Pmw.hidebusycursor()</code>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.stringtoreal</strong>(<em>text</em>, <em>separator</em> = <strong>'.'</strong>)</dt><dd>
+<p>
+    Return the real number represented by <em>text</em>.  This is similar to
+    <code>string.atof()</code> except that the character representing the decimal
+    point in <em>text</em> is given by <em>separator</em>.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.timestringtoseconds</strong>(<em>text</em>, <em>separator</em> = <strong>':'</strong>)</dt><dd>
+<p>
+    Return the number of seconds corresponding to the time in <em>text</em>. 
+    The time must be specified as three integers separated by the
+    <em>separator</em> character and must be in the order hours, minutes and
+    seconds.  The first number may be negative, indicating a negative
+    time.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.timevalidator</strong>(<em>text</em>, <em>separator</em> = <strong>':'</strong>)</dt><dd>
+<p>
+    Validator function for <a href="EntryField.html">Pmw.EntryField</a> <strong>time</strong> standard validator.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.tracetk</strong>(<em>root</em> = <strong>None</strong>, <em>on</em> = <strong>1</strong>, <em>withStackTrace</em> = <strong>0</strong>, <em>file</em> = <strong>None</strong>)</dt><dd>
+<p>
+    Print debugging trace of calls to, and callbacks from, the Tk
+    interpreter associated with the <em>root</em> window .  If <em>root</em> is
+    <strong>None</strong>, use the Tkinter default root.  If <em>on</em> is true, start
+    tracing, otherwise stop tracing.  If <em>withStackTrace</em> is true,
+    print a python function call stacktrace after the trace for each
+    call to Tk.  If <em>file</em> is <strong>None</strong>, print to standard error,
+    otherwise print to the file given by <em>file</em>.</p>
+
+<p>    For each call to Tk, the Tk command and its options are printed as
+    a python tuple, followed by the return value of the command (if
+    not the empty string).  For example:</p>
+
+<dl><dd><pre>python executed:
+  button = Tkinter.Button()
+  button.configure(text = 'Hi')
+
+tracetk output:
+  CALL  TK&gt; 1:  ('button', '.3662448') -&gt; '.3662448'
+  CALL  TK&gt; 1:  ('.3662448', 'configure', '-text', 'Hi')</pre></dd></dl>
+
+<p>    Some calls from python to Tk (such as <strong>update</strong>, <strong>tkwait</strong>,
+    <strong>invoke</strong>, etc) result in the execution of callbacks from Tk to
+    python.  These python callbacks can then recursively call into Tk. 
+    When displayed by <strong>tracetk()</strong>, these recursive calls are indented
+    proportionally to the depth of recursion.  The depth is also
+    printed as a leading number.  The return value of a call to Tk
+    which generated recursive calls is printed on a separate line at
+    the end of the recursion.  For example:</p>
+
+<dl><dd><pre>python executed:
+  def callback():
+      button.configure(text = 'Bye')
+      return 'Got me!'
+  button = Tkinter.Button()
+  button.configure(command = callback)
+  button.invoke()</pre></dd></dl>
+
+<dl><dd><pre>tracetk output:
+  CALL  TK&gt; 1:  ('button', '.3587144') -&gt; '.3587144'
+  CALL  TK&gt; 1:  ('.3587144', 'configure', '-command', '3638368callback')
+  CALL  TK&gt; 1:  ('.3587144', 'invoke')
+  CALLBACK&gt; 2:    callback()
+  CALL  TK&gt; 2:    ('.3587144', 'configure', '-text', 'Bye')
+  CALL RTN&gt; 1:  -&gt; 'Got me!'</pre></dd></dl>
+
+<p>    <strong>Pmw.initialise()</strong> must be called before <strong>tracetk()</strong> so that hooks
+    are put into the Tkinter CallWrapper class to trace callbacks from
+    Tk to python and also to handle recursive calls correctly.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.version</strong>(<em>alpha</em> = <strong>0</strong>)</dt><dd>
+<p>
+    If <em>alpha</em> is false, return the base version of Pmw being used
+    for this session.  If <code>Pmw.setversion()</code> has not been called, this
+    will be the latest installed version of Pmw.  If <em>alpha</em> is true,
+    return the list of alpha versions of Pmw being used for this
+    session, in search order.  If <code>Pmw.setalphaversions()</code> has not
+    been called, this will be the empty list.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <strong>Pmw.ymdtojdn</strong>(<em>year</em>, <em>month</em>, <em>day</em>, <em>julian</em> = <strong>-1</strong>, <em>papal</em> = <strong>1</strong>)</dt><dd>
+<p>
+    Return the Julian Day Number corresponding to <em>year</em>, <em>month</em> and
+    <em>day</em>.  See <code>jdntoymd()</code> for description of other arguments)</p>
+
+<p></p>
+
+
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/PromptDialog.gif b/Pmw/Pmw_1_2/doc/PromptDialog.gif
new file mode 100644 (file)
index 0000000..b82205c
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/PromptDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/PromptDialog.html b/Pmw/Pmw_1_2/doc/PromptDialog.html
new file mode 100644 (file)
index 0000000..f04b350
--- /dev/null
@@ -0,0 +1,293 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.PromptDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.PromptDialog</h1>
+    
+<center><IMG SRC=PromptDialog.gif ALT="" WIDTH=218 HEIGHT=164></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.PromptDialog() - 
+    selection dialog displaying an entry field
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="Dialog.html">Pmw.Dialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    The prompt dialog is a dialog window which displays an entry field
+    which can be used to prompt the user for a value.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the entry field. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the entry field. The default is <strong>20</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.entryfield></a>
+<dl><dt> <strong>entryfield
+</strong></dt><dd>
+The entry field for the user to enter a value. By default, this component is a <a href="EntryField.html">Pmw.EntryField</a>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+Alias for <strong>entryfield_entry</strong>.
+</dd></dl>
+<dl><dt> <strong>label
+</strong></dt><dd>
+Alias for <strong>entryfield_label</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="Dialog.html#methods">Pmw.Dialog</a></strong>.
+In addition, methods from the
+<strong><a href="EntryField.html#methods">Pmw.EntryField</a></strong> class
+are forwarded by this megawidget to the
+<strong>entryfield</strong> component.
+<p></p>
+<a name=method.deleteentry></a>
+<dl><dt> <strong>deleteentry</strong>(<em>first</em>, <em>last</em> = <strong>None</strong>)</dt><dd>
+Delete text from the entry field's entry widget.  An alias for
+    <code>component('entry').delete()</code>.</p>
+
+
+</dd></dl>
+<a name=method.indexentry></a>
+<dl><dt> <strong>indexentry</strong>(<em>index</em>)</dt><dd>
+An alias for <code>component('entry').index()</code>.</p>
+
+
+</dd></dl>
+<a name=method.insertentry></a>
+<dl><dt> <strong>insertentry</strong>(<em>index</em>, <em>text</em>)</dt><dd>
+Insert text into the entry field's entry widget.  An alias for
+    <code>component('entry').insert()</code>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the dialog to prompt for the password.
+        self.dialog = Pmw.PromptDialog(parent,
+            title = 'Password',
+            label_text = 'Password:',
+            entryfield_labelpos = 'n',
+            entry_show = '*',
+            defaultbutton = 0,
+            buttons = ('OK', 'Cancel'),
+            command = self.execute)
+        self.dialog.withdraw()
+
+        # Create the confirmation dialog.
+        self.confirm = Pmw.MessageDialog(
+            title = 'Are you sure?',
+            message_text = 'Are you really sure?',
+            defaultbutton = 0,
+            buttons = ('OK', 'Cancel'))
+        self.confirm.withdraw()
+
+        # Create button to launch the dialog.
+        w = Tkinter.Button(parent, text = 'Show prompt dialog',
+                command = self.dialog.activate)
+        w.pack(padx = 8, pady = 8)
+
+    def execute(self, result):
+        if result is None or result == 'Cancel':
+            print 'Password prompt cancelled'
+            self.dialog.deactivate(result)
+        else:
+            result = self.confirm.activate()
+            if result == 'OK':
+                print 'Password entered ' + self.dialog.get()
+                self.dialog.deactivate()
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/RadioSelect.gif b/Pmw/Pmw_1_2/doc/RadioSelect.gif
new file mode 100644 (file)
index 0000000..026a139
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/RadioSelect.gif differ
diff --git a/Pmw/Pmw_1_2/doc/RadioSelect.html b/Pmw/Pmw_1_2/doc/RadioSelect.html
new file mode 100644 (file)
index 0000000..bdf871c
--- /dev/null
@@ -0,0 +1,405 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.RadioSelect reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.RadioSelect</h1>
+    
+<center><IMG SRC=RadioSelect.gif ALT="" WIDTH=466 HEIGHT=272></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.RadioSelect() - 
+    a set of buttons, some of which may be selected
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A radio select is a container megawidget which manages a number of
+    buttons.  The buttons may be laid out either horizontally or
+    vertically.  In single selection mode, only one button may be
+    selected at any one time.  In multiple selection mode, several
+    buttons may be selected at the same time and clicking on a
+    selected button will deselect it. </p>
+
+<p>    The buttons displayed can be either standard buttons, radio
+    buttons or check buttons.  When selected, standard buttons are
+    displayed sunken and radio and check buttons are displayed with
+    the appropriate indicator color and relief.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.buttontype></a>
+<dl><dt> <strong>buttontype
+</strong></dt><dd>
+Initialisation option. Specifies the default type of buttons created by the <code>add()</code>
+    method.  If <strong>'button'</strong>, the default type is Tkinter.Button.  If
+    <strong>'radiobutton'</strong>, the default type is Tkinter.Radiobutton.  If
+    <strong>'checkbutton'</strong>, the default type is Tkinter.Checkbutton.</p>
+<p>    If <strong>'radiobutton'</strong>, single selection mode is automatically set. 
+    If <strong>'checkbutton'</strong>, multiple selection mode is automatically set. The default is <strong>'button'</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call when one of the buttons is clicked on
+    or when <code>invoke()</code> is called.</p>
+<p>    In single selection mode, the function is called with a single
+    argument, which is the name of the selected button.</p>
+
+<p>    In multiple selection mode, the function is called with the first
+    argument being the name of the button and the second argument
+    being true if the button is now selected or false if it is now
+    deselected. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.orient></a>
+<dl><dt> <strong>orient
+</strong></dt><dd>
+Initialisation option. Specifies the direction in which the buttons are laid out.  This
+    may be <strong>'horizontal'</strong> or <strong>'vertical'</strong>. The default is <strong>'horizontal'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.padx></a>
+<dl><dt> <strong>padx
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave between each button in the x
+    direction and also between the buttons and the outer edge of the
+    radio select. The default is <strong>5</strong>.</p>
+
+
+</dd></dl>
+<a name=option.pady></a>
+<dl><dt> <strong>pady
+</strong></dt><dd>
+Initialisation option. Specifies a padding distance to leave between each button in the y
+    direction and also between the buttons and the outer edge of the
+    radio select. The default is <strong>5</strong>.</p>
+
+
+</dd></dl>
+<a name=option.selectmode></a>
+<dl><dt> <strong>selectmode
+</strong></dt><dd>
+Initialisation option. Specifies the selection mode:  whether a single button or multiple
+    buttons can be selected at one time.  If <strong>'single'</strong>, clicking on
+    an unselected button selects it and deselects all other buttons. 
+    If <strong>'multiple'</strong>, clicking on an unselected button selects it and
+    clicking on a selected button deselects it.  This option is
+    ignored if <strong>buttontype</strong> is <strong>'radiobutton'</strong> or <strong>'checkbutton'</strong>. The default is <strong>'single'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.frame></a>
+<dl><dt> <strong>frame
+</strong></dt><dd>
+If the <strong>label</strong> component has been created (that is, the <strong>labelpos</strong>
+    option is not <strong>None</strong>), the <strong>frame</strong> component is created to act as
+    the container of the buttons created by the <code>add()</code> method.  If
+    there is no <strong>label</strong> component, then no <strong>frame</strong> component is
+    created and the <strong>hull</strong> component acts as the container. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Dynamic components</h3></dt><dd>
+<p>
+        Button components are created dynamically by the <code>add()</code>
+        method.  The default type of the buttons depends on the value
+        of the <strong>buttontype</strong> option.</p>
+
+<p>        Button components are created with a component group of <strong>Button</strong>.</p>
+<p>        </p>
+
+
+
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.add></a>
+<dl><dt> <strong>add</strong>(<em>componentName</em>, **<em>kw</em>)</dt><dd>
+Add a button to the end of the radio select as a component
+    named <em>componentName</em>.  with a default type as specified by
+    <strong>buttontype</strong>.  Any keyword arguments present (except <strong>command</strong>)
+    will be passed to the constructor when creating the button.  If
+    the <strong>text</strong> keyword argument is not given, the <strong>text</strong> option of the
+    button defaults to <em>componentName</em>.  The method returns the
+    component widget.</p>
+
+
+</dd></dl>
+<a name=method.button></a>
+<dl><dt> <strong>button</strong>(<em>buttonIndex</em>)</dt><dd>
+Return the button specified by <em>buttonIndex</em>, which may have any
+    of the forms accepted by the <code>index()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.deleteall></a>
+<dl><dt> <strong>deleteall</strong>()</dt><dd>
+Delete all buttons and clear the current selection.</p>
+
+
+</dd></dl>
+<a name=method.getcurselection></a>
+<dl><dt> <strong>getcurselection</strong>()</dt><dd>
+Same as <code>getvalue()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.getvalue></a>
+<dl><dt> <strong>getvalue</strong>()</dt><dd>
+In single selection mode, return the name of the currently
+    selected button, or <strong>None</strong> if no buttons have been selected yet.</p>
+<p>    In multiple selection mode, return a list of the names of the
+    currently selected buttons.</p>
+
+
+
+</dd></dl>
+<a name=method.index></a>
+<dl><dt> <strong>index</strong>(<em>index</em>)</dt><dd>
+Return the numerical index of the button corresponding to <em>index</em>. 
+    This may be specified in any of the following forms:</p>
+<dl><dt><em>name</em></dt><dd>Specifies the button named <em>name</em>.<p></p>
+
+</dd>
+<dt><em>number</em></dt><dd>Specifies the button numerically, where <strong>0</strong> corresponds to
+         the left (or top) button.<p></p>
+
+</dd>
+<dt><strong>Pmw.END</strong></dt><dd>Specifies the right (or bottom) button.<p></p>
+
+</dd></dl>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>(<em>index</em>)</dt><dd>
+Calling this method is the same as clicking on the button
+    specified by <em>index</em>:  the buttons are displayed selected or
+    deselected according to the selection mode and <strong>command</strong> is
+    called.  <em>index</em> may have any of the forms accepted by the
+    <code>index()</code> method.  The value returned by <strong>command</strong> is returned.</p>
+
+
+</dd></dl>
+<a name=method.numbuttons></a>
+<dl><dt> <strong>numbuttons</strong>()</dt><dd>
+Return the number of buttons in the radio select.</p>
+
+
+</dd></dl>
+<a name=method.setvalue></a>
+<dl><dt> <strong>setvalue</strong>(<em>textOrList</em>)</dt><dd>
+Set the current selection for the radio select to <em>textOrList</em>,
+    but do not invoke <strong>command</strong>.</p>
+<p>    In single selection mode, select only the button specified by the
+    string <em>textOrList</em>.</p>
+
+<p>    In multiple selection mode, select only the buttons specified by
+    the list <em>textOrList</em>.</p>
+
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack a horizontal RadioSelect widget.
+        horiz = Pmw.RadioSelect(parent,
+                labelpos = 'w',
+                command = self.callback,
+                label_text = 'Horizontal',
+                frame_borderwidth = 2,
+                frame_relief = 'ridge'
+        )
+        horiz.pack(fill = 'x', padx = 10, pady = 10)
+
+        # Add some buttons to the horizontal RadioSelect.
+        for text in ('Fruit', 'Vegetables', 'Cereals', 'Legumes'):
+            horiz.add(text)
+        horiz.invoke('Cereals')
+
+        # Create and pack a multiple selection RadioSelect widget.
+        self.multiple = Pmw.RadioSelect(parent,
+                labelpos = 'w',
+                command = self.multcallback,
+                label_text = 'Multiple\nselection',
+                frame_borderwidth = 2,
+                frame_relief = 'ridge',
+                selectmode = 'multiple',
+        )
+        self.multiple.pack(fill = 'x', padx = 10)
+
+        # Add some buttons to the multiple selection RadioSelect.
+        for text in ('Apricots', 'Eggplant', 'Rice', 'Lentils'):
+            self.multiple.add(text)
+        self.multiple.invoke('Rice')
+
+        # Create and pack a vertical RadioSelect widget, with checkbuttons.
+        self.checkbuttons = Pmw.RadioSelect(parent,
+                buttontype = 'checkbutton',
+                orient = 'vertical',
+                labelpos = 'w',
+                command = self.checkbuttoncallback,
+                label_text = 'Vertical,\nusing\ncheckbuttons',
+                hull_borderwidth = 2,
+                hull_relief = 'ridge',
+        )
+        self.checkbuttons.pack(side = 'left', expand = 1, padx = 10, pady = 10)
+
+        # Add some buttons to the checkbutton RadioSelect.
+        for text in ('Male', 'Female'):
+            self.checkbuttons.add(text)
+        self.checkbuttons.invoke('Male')
+        self.checkbuttons.invoke('Female')
+
+        # Create and pack a RadioSelect widget, with radiobuttons.
+        radiobuttons = Pmw.RadioSelect(parent,
+                buttontype = 'radiobutton',
+                orient = 'vertical',
+                labelpos = 'w',
+                command = self.callback,
+                label_text = 'Vertical,\nusing\nradiobuttons',
+                hull_borderwidth = 2,
+                hull_relief = 'ridge',
+        )
+        radiobuttons.pack(side = 'left', expand = 1, padx = 10, pady = 10)
+
+        # Add some buttons to the radiobutton RadioSelect.
+        for text in ('Male', 'Female', 'Both', 'Neither'):
+            radiobuttons.add(text)
+        radiobuttons.invoke('Both')
+
+    def callback(self, tag):
+        # This is called whenever the user clicks on a button
+        # in a single select RadioSelect widget.
+        print 'Button', tag, 'was pressed.'
+
+    def multcallback(self, tag, state):
+        # This is called whenever the user clicks on a button
+        # in the multiple select RadioSelect widget.
+        if state:
+           action = 'pressed.'
+        else:
+           action = 'released.'
+
+        print 'Button', tag, 'was', action, \
+                'Selection:', self.multiple.getcurselection()
+           
+    def checkbuttoncallback(self, tag, state):
+        # This is called whenever the user clicks on a button
+        # in the checkbutton RadioSelect widget.
+        if state:
+           action = 'pressed.'
+        else:
+           action = 'released.'
+
+        print 'Button', tag, 'was', action, \
+                'Selection:', self.checkbuttons.getcurselection()
+           
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 6 June 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ScrolledCanvas.gif b/Pmw/Pmw_1_2/doc/ScrolledCanvas.gif
new file mode 100644 (file)
index 0000000..da7941a
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ScrolledCanvas.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ScrolledCanvas.html b/Pmw/Pmw_1_2/doc/ScrolledCanvas.html
new file mode 100644 (file)
index 0000000..f3ebd21
--- /dev/null
@@ -0,0 +1,352 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ScrolledCanvas reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ScrolledCanvas</h1>
+    
+<center><IMG SRC=ScrolledCanvas.gif ALT="" WIDTH=382 HEIGHT=240></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ScrolledCanvas() - 
+    canvas with optional scrollbars
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A scrolled canvas consists of a standard canvas widget with optional
+    scrollbars which can be used to scroll the canvas.  The scrollbars
+    can be <em>dynamic</em>, which means that a scrollbar will only be
+    displayed if it is necessary, that is, if the scrollregion of the
+    canvas is larger than the canvas.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+Initialisation option. If true, the <strong>borderframe</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.canvasmargin></a>
+<dl><dt> <strong>canvasmargin
+</strong></dt><dd>
+Initialisation option. The margin around the items in the canvas.  Used by the
+    <strong>resizescrollregion()</strong> method. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.hscrollmode></a>
+<dl><dt> <strong>hscrollmode
+</strong></dt><dd>
+The horizontal scroll mode.  If <strong>'none'</strong>, the horizontal scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.scrollmargin></a>
+<dl><dt> <strong>scrollmargin
+</strong></dt><dd>
+Initialisation option. The distance between the scrollbars and the enclosing canvas
+    widget. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+<a name=option.usehullsize></a>
+<dl><dt> <strong>usehullsize
+</strong></dt><dd>
+Initialisation option. If true, the size of the megawidget is determined solely by the
+    width and height options of the <strong>hull</strong> component.</p>
+<p>    Otherwise, the size of the megawidget is determined by the width
+    and height of the <strong>canvas</strong> component, along with the size and/or
+    existence of the other components, such as the label, the
+    scrollbars and the scrollmargin option.  All these affect the
+    overall size of the megawidget. The default is <strong>0</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.vscrollmode></a>
+<dl><dt> <strong>vscrollmode
+</strong></dt><dd>
+The vertical scroll mode.  If <strong>'none'</strong>, the vertical scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+A frame widget which snuggly fits around the canvas, to give the
+    appearance of a canvas border.  It is created with a border so
+    that the canvas, which is created without a border, looks like it
+    has a border. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.canvas></a>
+<dl><dt> <strong>canvas
+</strong></dt><dd>
+The canvas widget which is scrolled by the scrollbars.  If the
+    <strong>borderframe</strong> option is true, this is created with a borderwidth
+    of <strong>0</strong> to overcome a known problem with canvas widgets:  if a
+    widget inside a canvas extends across one of the edges of the
+    canvas, then the widget obscures the border of the canvas. 
+    Therefore, if the canvas has no border, then this overlapping does
+    not occur. By default, this component is a Tkinter.Canvas.</p>
+
+
+</dd></dl>
+<a name=component.horizscrollbar></a>
+<dl><dt> <strong>horizscrollbar
+</strong></dt><dd>
+The horizontal scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.vertscrollbar></a>
+<dl><dt> <strong>vertscrollbar
+</strong></dt><dd>
+The vertical scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Canvas</strong> class
+are forwarded by this megawidget to the
+<strong>canvas</strong> component.
+<p></p>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(*<em>args</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>canvas</strong> component's
+    <code>bbox()</code> method.  Without this explicit forwarding, the <code>bbox()</code>
+    method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+<a name=method.interior></a>
+<dl><dt> <strong>interior</strong>()</dt><dd>
+Return the canvas widget within which the programmer should create
+    graphical items and child widgets.  This is the same as
+    <code>component('canvas')</code>.</p>
+
+
+</dd></dl>
+<a name=method.resizescrollregion></a>
+<dl><dt> <strong>resizescrollregion</strong>()</dt><dd>
+Resize the scrollregion of the <strong>canvas</strong> component to be the
+    bounding box covering all the items in the canvas plus a margin on
+    all sides, as specified by the <strong>canvasmargin</strong> option.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the ScrolledCanvas.
+        self.sc = Pmw.ScrolledCanvas(parent,
+                borderframe = 1,
+                labelpos = 'n',
+                label_text = 'ScrolledCanvas',
+                usehullsize = 1,
+                hull_width = 400,
+                hull_height = 300,
+        )
+
+        # Create a group widget to contain the scrollmode options.
+        w = Pmw.Group(parent, tag_text='Scroll mode')
+        w.pack(side = 'bottom', padx = 5, pady = 5)
+
+        hmode = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Horizontal:',
+                items = ['none', 'static', 'dynamic'],
+                command = self.sethscrollmode,
+                menubutton_width = 8,
+        )
+        hmode.pack(side = 'left', padx = 5, pady = 5)
+        hmode.invoke('dynamic')
+
+        vmode = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Vertical:',
+                items = ['none', 'static', 'dynamic'],
+                command = self.setvscrollmode,
+                menubutton_width = 8,
+        )
+        vmode.pack(side = 'left', padx = 5, pady = 5)
+        vmode.invoke('dynamic')
+
+        buttonBox = Pmw.ButtonBox(parent)
+        buttonBox.pack(side = 'bottom')
+        buttonBox.add('yview', text = 'Show\nyview', command = self.showYView)
+        buttonBox.add('scroll', text = 'Page\ndown', command = self.pageDown)
+        buttonBox.add('center', text = 'Center', command = self.centerPage)
+
+        # Pack this last so that the buttons do not get shrunk when
+        # the window is resized.
+        self.sc.pack(padx = 5, pady = 5, fill = 'both', expand = 1)
+
+        self.sc.component('canvas').bind('&lt;1&gt;', self.addcircle)
+
+        testEntry = Tkinter.Entry(parent)
+        self.sc.create_line(20, 20, 100, 100)
+        self.sc.create_oval(100, 100, 200, 200, fill = 'green')
+        self.sc.create_text(100, 20, anchor = 'nw',
+                text = 'Click in the canvas\nto draw ovals',
+                font = testEntry.cget('font'))
+        button = Tkinter.Button(self.sc.interior(),
+                text = 'Hello,\nWorld!\nThis\nis\na\nbutton.')
+        self.sc.create_window(200, 200,
+                anchor='nw',
+                window = button)
+
+        # Set the scroll region of the canvas to include all the items
+        # just created.
+        self.sc.resizescrollregion()
+
+        self.colours = ('red', 'green', 'blue', 'yellow', 'cyan', 'magenta',
+                'black', 'white')
+        self.oval_count = 0
+        self.rand = 12345
+
+    def sethscrollmode(self, tag):
+        self.sc.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+        self.sc.configure(vscrollmode = tag)
+
+    def addcircle(self, event):
+        x = self.sc.canvasx(event.x)
+        y = self.sc.canvasy(event.y)
+        width = 10 + self.random() % 100
+        height = 10 + self.random() % 100
+        self.sc.create_oval(
+            x - width, y - height, x + width, y + height,
+            fill = self.colours[self.oval_count])
+        self.oval_count = (self.oval_count + 1) % len(self.colours)
+        self.sc.resizescrollregion()
+
+    # Simple random number generator.
+    def random(self):
+        self.rand = (self.rand * 125) % 2796203
+        return self.rand
+
+    def showYView(self):
+        print self.sc.yview()
+
+    def pageDown(self):
+        self.sc.yview('scroll', 1, 'page')
+
+    def centerPage(self):
+        top, bottom = self.sc.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.sc.yview('moveto', middle)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 20 September 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ScrolledField.gif b/Pmw/Pmw_1_2/doc/ScrolledField.gif
new file mode 100644 (file)
index 0000000..d1942e3
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ScrolledField.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ScrolledField.html b/Pmw/Pmw_1_2/doc/ScrolledField.html
new file mode 100644 (file)
index 0000000..4c28cbc
--- /dev/null
@@ -0,0 +1,187 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ScrolledField reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ScrolledField</h1>
+    
+<center><IMG SRC=ScrolledField.gif ALT="" WIDTH=268 HEIGHT=37></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ScrolledField() - 
+    single line scrollable output field
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A scrolled field displays a single line of text.  If the text is
+    too wide to display in the megawidget it can be scrolled to the
+    left and right by the user by dragging with the middle mouse
+    button.  The text is also selectable by clicking or dragging with
+    the left mouse button.</p>
+
+<p>    It can be used instead of a Tkinter.Label widget when displaying
+    text of unknown width such as application status messages.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.sticky></a>
+<dl><dt> <strong>sticky
+</strong></dt><dd>
+Initialisation option.  The default is <strong>'ew'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.text></a>
+<dl><dt> <strong>text
+</strong></dt><dd>
+Specifies the text to display in the scrolled field. The default is <strong>''</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.entry></a>
+<dl><dt> <strong>entry
+</strong></dt><dd>
+This is used to display the text and allows the user to scroll and
+    select the text.  The <strong>state</strong> of this component is set to
+    <strong>'readonly'</strong> (or <strong>'disabled'</strong> in earlier versions of Tcl/Tk which do
+    not support  <strong>'readonly'</strong>), so that the user is unable to modify the text. By default, this component is a Tkinter.Entry.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+This megawidget has no methods of its own.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Entry</strong> class
+are forwarded by this megawidget to the
+<strong>entry</strong> component.
+<p></p>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create and pack the ScrolledField.
+        self._field = Pmw.ScrolledField(parent, entry_width = 30,
+                entry_relief='groove', labelpos = 'n',
+                label_text = 'Scroll the field using the\nmiddle mouse button')
+        self._field.pack(fill = 'x', expand = 1, padx = 10, pady = 10)
+
+        # Create and pack a button to change the ScrolledField.
+        self._button = Tkinter.Button(parent, text = 'Change field',
+                command = self.execute)
+        self._button.pack(padx = 10, pady = 10)
+
+        self._index = 0
+        self.execute()
+
+    def execute(self):
+        self._field.configure(text = lines[self._index % len(lines)])
+        self._index = self._index + 1
+
+lines = (
+  'Alice was beginning to get very tired of sitting by her sister',
+  'on the bank, and of having nothing to do:  once or twice she had',
+  'peeped into the book her sister was reading, but it had no',
+  'pictures or conversations in it, "and what is the use of a book,"',
+  'thought Alice "without pictures or conversation?"',
+  'Alice\'s Adventures in Wonderland',
+  'Lewis Carroll',
+)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 23 August 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ScrolledFrame.gif b/Pmw/Pmw_1_2/doc/ScrolledFrame.gif
new file mode 100644 (file)
index 0000000..089a201
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ScrolledFrame.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ScrolledFrame.html b/Pmw/Pmw_1_2/doc/ScrolledFrame.html
new file mode 100644 (file)
index 0000000..5cfe3b3
--- /dev/null
@@ -0,0 +1,479 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ScrolledFrame reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ScrolledFrame</h1>
+    
+<center><IMG SRC=ScrolledFrame.gif ALT="" WIDTH=404 HEIGHT=174></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ScrolledFrame() - 
+    frame with optional scrollbars
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A scrolled frame consists of a scrollable interior frame within a
+    clipping frame.  The programmer can create other widgets within
+    the interior frame.  If the frame becomes larger than the
+    surrounding clipping frame, the user can position the frame using
+    the horizontal and vertical scrollbars.</p>
+
+<p>    The scrollbars can be <em>dynamic</em>, which means that a scrollbar will
+    only be displayed if it is necessary.  That is, if the frame is
+    smaller than the surrounding clipping frame, the scrollbar will be
+    hidden.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+Initialisation option. If true, the <strong>borderframe</strong> component will be created. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.horizflex></a>
+<dl><dt> <strong>horizflex
+</strong></dt><dd>
+Specifies how the width of the scrollable interior frame should be
+    resized relative to the clipping frame.</p>
+<p>    If <strong>'fixed'</strong>, the interior frame is set to the <em>natural</em> width, as
+    requested by the child widgets of the frame.  If <strong>'expand'</strong> and
+    the requested width of the interior frame is less than the width
+    of the clipping frame, the interior frame expands to fill the
+    clipping frame.  If <strong>'shrink'</strong> and the requested width of the
+    interior frame is more than the width of the clipping frame, the
+    interior frame shrinks to the width of the clipping frame.  If
+    <strong>'elastic'</strong>, the width of the interior frame is always set to the
+    width of the clipping frame. The default is <strong>'fixed'</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.horizfraction></a>
+<dl><dt> <strong>horizfraction
+</strong></dt><dd>
+Initialisation option. The fraction of the width of the clipper frame to scroll the
+    interior frame when the user clicks on the horizontal scrollbar
+    arrows. The default is <strong>0.05</strong>.</p>
+
+
+</dd></dl>
+<a name=option.hscrollmode></a>
+<dl><dt> <strong>hscrollmode
+</strong></dt><dd>
+The horizontal scroll mode.  If <strong>'none'</strong>, the horizontal scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.scrollmargin></a>
+<dl><dt> <strong>scrollmargin
+</strong></dt><dd>
+Initialisation option. The distance between the scrollbars and the clipping frame. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+<a name=option.usehullsize></a>
+<dl><dt> <strong>usehullsize
+</strong></dt><dd>
+Initialisation option. If true, the size of the megawidget is determined solely by the
+    width and height options of the <strong>hull</strong> component.</p>
+<p>    Otherwise, the size of the megawidget is determined by the width
+    and height of the <strong>clipper</strong> component, along with the size and/or
+    existence of the other components, such as the label, the
+    scrollbars and the scrollmargin option.  All these affect the
+    overall size of the megawidget. The default is <strong>0</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.vertflex></a>
+<dl><dt> <strong>vertflex
+</strong></dt><dd>
+Specifies how the height of the scrollable interior frame should
+    be resized relative to the clipping frame.</p>
+<p>    If <strong>'fixed'</strong>, the interior frame is set to the <em>natural</em> height,
+    as requested by the child widgets of the frame.  If <strong>'expand'</strong> and
+    the requested height of the interior frame is less than the height
+    of the clipping frame, the interior frame expands to fill the
+    clipping frame.  If <strong>'shrink'</strong> and the requested height of the
+    interior frame is more than the height of the clipping frame, the
+    interior frame shrinks to the height of the clipping frame.  If
+    <strong>'elastic'</strong>, the height of the interior frame is always set to the
+    height of the clipping frame. The default is <strong>'fixed'</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.vertfraction></a>
+<dl><dt> <strong>vertfraction
+</strong></dt><dd>
+Initialisation option. The fraction of the height of the clipper frame to scroll the
+    interior frame when the user clicks on the vertical scrollbar
+    arrows. The default is <strong>0.05</strong>.</p>
+
+
+</dd></dl>
+<a name=option.vscrollmode></a>
+<dl><dt> <strong>vscrollmode
+</strong></dt><dd>
+The vertical scroll mode.  If <strong>'none'</strong>, the vertical scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+A frame widget which snuggly fits around the clipper, to give the
+    appearance of a border.  It is created with a border so that the
+    clipper, which is created without a border, looks like it has a
+    border. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.clipper></a>
+<dl><dt> <strong>clipper
+</strong></dt><dd>
+The frame which is used to provide a clipped view of the <strong>frame</strong>
+    component.  If the <strong>borderframe</strong> option is true, this is created
+    with a borderwidth of <strong>0</strong> to overcome a known problem with using
+    <code>place</code> to position widgets:  if a widget (in this case the
+    <strong>frame</strong> component) is <code>placed</code> inside a frame (in this case the
+    <strong>clipper</strong> component) and it extends across one of the edges of the
+    frame, then the widget obscures the border of the frame. 
+    Therefore, if the clipper has no border, then this overlapping
+    does not occur. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.frame></a>
+<dl><dt> <strong>frame
+</strong></dt><dd>
+The frame within the clipper to contain the widgets to be scrolled. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.horizscrollbar></a>
+<dl><dt> <strong>horizscrollbar
+</strong></dt><dd>
+The horizontal scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.vertscrollbar></a>
+<dl><dt> <strong>vertscrollbar
+</strong></dt><dd>
+The vertical scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.interior></a>
+<dl><dt> <strong>interior</strong>()</dt><dd>
+Return the frame within which the programmer may create widgets to
+    be scrolled.  This is the same as <code>component('frame')</code>.</p>
+
+
+</dd></dl>
+<a name=method.reposition></a>
+<dl><dt> <strong>reposition</strong>()</dt><dd>
+Update the position of the <strong>frame</strong> component in the <strong>clipper</strong> and
+    update the scrollbars.</p>
+<p>    Usually, this method does not need to be called explicitly, since
+    the position of the <strong>frame</strong> component and the scrollbars are
+    automatically updated whenever the size of the <strong>frame</strong> or
+    <strong>clipper</strong> components change or the user clicks in the scrollbars. 
+    However, if <strong>horizflex</strong> or <strong>vertflex</strong> is <strong>'expand'</strong>, the
+    megawidget cannot detect when the requested size of the <strong>frame</strong>
+    increases to greater than the size of the <strong>clipper</strong>.  Therefore,
+    this method should be called when a new widget is added to the
+    <strong>frame</strong> (or a widget is increased in size) <em>after</em> the initial
+    megawidget construction.</p>
+
+
+
+</dd></dl>
+<a name=method.xview></a>
+<dl><dt> <strong>xview</strong>(<em>mode</em> = <strong>None</strong>, <em>value</em> = <strong>None</strong>, <em>units</em> = <strong>None</strong>)</dt><dd>
+Query or change the horizontal position of the scrollable interior
+    frame.  If <em>mode</em> is <strong>None</strong>, return a tuple of two numbers, each
+    between 0.0 and 1.0.  The first is the position of the left edge
+    of the visible region of the contents of the scrolled frame,
+    expressed as a fraction of the total width of the contents.  The
+    second is the position of the right edge of the visible region.</p>
+<p>    If <em>mode</em> == <strong>'moveto'</strong>, adjust the view of the interior so that
+    the fraction <em>value</em> of the total width of the contents is
+    off-screen to the left.  The <em>value</em> must be between <em>0.0</em> and
+    <em>1.0</em>.</p>
+
+<p>    If <em>mode</em> == <strong>'scroll'</strong>, adjust the view of the interior left or
+    right by a fixed amount.  If <em>what</em> is <strong>'units'</strong>, move the view in
+    units of <strong>horizfraction</strong>.  If <em>what</em> is <em>pages</em>, move the view in
+    units of the width of the scrolled frame.  If <em>value</em> is positive,
+    move to the right, otherwise move to the left.</p>
+
+
+
+</dd></dl>
+<a name=method.yview></a>
+<dl><dt> <strong>yview</strong>(<em>mode</em> = <strong>None</strong>, <em>value</em> = <strong>None</strong>, <em>units</em> = <strong>None</strong>)</dt><dd>
+Query or change the vertical position of the scrollable interior
+    frame.  If <em>mode</em> is <strong>None</strong>, return a tuple of two numbers, each
+    between 0.0 and 1.0.  The first is the position of the top edge
+    of the visible region of the contents of the scrolled frame,
+    expressed as a fraction of the total height of the contents.  The
+    second is the position of the bottom edge of the visible region.</p>
+<p>    If <em>mode</em> == <strong>'moveto'</strong>, adjust the view of the interior so that
+    the fraction <em>value</em> of the total height of the contents is
+    off-screen to the top.  The <em>value</em> must be between <em>0.0</em> and
+    <em>1.0</em>.</p>
+
+<p>    If <em>mode</em> == <strong>'scroll'</strong>, adjust the view of the interior up or
+    down by a fixed amount.  If <em>what</em> is <strong>'units'</strong>, move the view in
+    units of <strong>vertfraction</strong>.  If <em>what</em> is <em>pages</em>, move the view in
+    units of the height of the scrolled frame.  If <em>value</em> is
+    positive, move to down, otherwise move up.</p>
+
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the ScrolledFrame.
+        self.sf = Pmw.ScrolledFrame(parent,
+                labelpos = 'n', label_text = 'ScrolledFrame',
+                usehullsize = 1,
+                hull_width = 400,
+                hull_height = 220,
+        )
+
+        # Create a group widget to contain the flex options.
+        w = Pmw.Group(parent, tag_text='Flex')
+        w.pack(side = 'bottom', padx = 5, pady = 3)
+
+        hflex = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Horizontal:',
+                items = ['fixed', 'expand', 'shrink', 'elastic'],
+                command = self.sethflex,
+                menubutton_width = 8,
+        )
+        hflex.pack(side = 'left', padx = 5, pady = 3)
+        hflex.invoke('fixed')
+
+        vflex = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Vertical:',
+                items = ['fixed', 'expand', 'shrink', 'elastic'],
+                command = self.setvflex,
+                menubutton_width = 8,
+        )
+        vflex.pack(side = 'left', padx = 5, pady = 3)
+        vflex.invoke('fixed')
+
+        # Create a group widget to contain the scrollmode options.
+        w = Pmw.Group(parent, tag_text='Scroll mode')
+        w.pack(side = 'bottom', padx = 5, pady = 0)
+
+        hmode = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Horizontal:',
+                items = ['none', 'static', 'dynamic'],
+                command = self.sethscrollmode,
+                menubutton_width = 8,
+        )
+        hmode.pack(side = 'left', padx = 5, pady = 3)
+        hmode.invoke('dynamic')
+
+        vmode = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Vertical:',
+                items = ['none', 'static', 'dynamic'],
+                command = self.setvscrollmode,
+                menubutton_width = 8,
+        )
+        vmode.pack(side = 'left', padx = 5, pady = 3)
+        vmode.invoke('dynamic')
+
+        self.radio = Pmw.RadioSelect(parent, selectmode = 'multiple',
+            command = self.radioSelected)
+        self.radio.add('center', text = 'Keep centered vertically')
+        self.radio.pack(side = 'bottom')
+
+        buttonBox = Pmw.ButtonBox(parent)
+        buttonBox.pack(side = 'bottom')
+        buttonBox.add('add', text = 'Add a button', command = self.addButton)
+        buttonBox.add('yview', text = 'Show yview', command = self.showYView)
+        buttonBox.add('scroll', text = 'Page down', command = self.pageDown)
+
+        # Pack this last so that the buttons do not get shrunk when
+        # the window is resized.
+        self.sf.pack(padx = 5, pady = 3, fill = 'both', expand = 1)
+
+        self.frame = self.sf.interior()
+
+        self.row = 0
+        self.col = 0
+
+        for count in range(15):
+            self.addButton()
+
+    def sethscrollmode(self, tag):
+        self.sf.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+        self.sf.configure(vscrollmode = tag)
+
+    def sethflex(self, tag):
+        self.sf.configure(horizflex = tag)
+
+    def setvflex(self, tag):
+        self.sf.configure(vertflex = tag)
+
+    def addButton(self):
+        button = Tkinter.Button(self.frame,
+            text = '(%d,%d)' % (self.col, self.row))
+        button.grid(row = self.row, column = self.col, sticky = 'nsew')
+
+        self.frame.grid_rowconfigure(self.row, weight = 1)
+        self.frame.grid_columnconfigure(self.col, weight = 1)
+        if self.sf.cget('horizflex') == 'expand' or \
+                self.sf.cget('vertflex') == 'expand':
+            self.sf.reposition()
+
+        if 'center' in self.radio.getcurselection():
+            self.sf.update_idletasks()
+            self.centerPage()
+
+        if self.col == self.row:
+            self.col = 0
+            self.row = self.row + 1
+        else:
+            self.col = self.col + 1
+
+    def showYView(self):
+        print self.sf.yview()
+
+    def pageDown(self):
+        self.sf.yview('scroll', 1, 'page')
+
+    def radioSelected(self, name, state):
+        if state:
+            self.centerPage()
+
+    def centerPage(self):
+        # Example of how to use the yview() method of Pmw.ScrolledFrame.
+        top, bottom = self.sf.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.sf.yview('moveto', middle)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 February 2001
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ScrolledListBox.gif b/Pmw/Pmw_1_2/doc/ScrolledListBox.gif
new file mode 100644 (file)
index 0000000..9a59561
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ScrolledListBox.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ScrolledListBox.html b/Pmw/Pmw_1_2/doc/ScrolledListBox.html
new file mode 100644 (file)
index 0000000..0c12d76
--- /dev/null
@@ -0,0 +1,379 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ScrolledListBox reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ScrolledListBox</h1>
+    
+<center><IMG SRC=ScrolledListBox.gif ALT="" WIDTH=210 HEIGHT=168></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ScrolledListBox() - 
+    listbox with optional scrollbars
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A scrolled listbox consists of a standard listbox widget with optional
+    scrollbars which can be used to scroll the listbox.  The
+    scrollbars can be <em>dynamic</em>, which means that a scrollbar will
+    only be displayed if it is necessary.  That is, if the listbox
+    does not contain enough entries, the vertical scrollbar will be
+    automatically hidden and if the entries are not wide enough, the
+    horizontal scrollbar will be automatically hidden.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.dblclickcommand></a>
+<dl><dt> <strong>dblclickcommand
+</strong></dt><dd>
+This specifies a function to call when mouse button 1 is double
+    clicked over an entry in the <strong>listbox</strong> component. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.hscrollmode></a>
+<dl><dt> <strong>hscrollmode
+</strong></dt><dd>
+The horizontal scroll mode.  If <strong>'none'</strong>, the horizontal scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.items></a>
+<dl><dt> <strong>items
+</strong></dt><dd>
+Initialisation option. A tuple containing the initial items to be displayed by the
+    <strong>listbox</strong> component. The default is <strong>()</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.scrollmargin></a>
+<dl><dt> <strong>scrollmargin
+</strong></dt><dd>
+Initialisation option. The distance between the scrollbars and the listbox widget. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+<a name=option.selectioncommand></a>
+<dl><dt> <strong>selectioncommand
+</strong></dt><dd>
+This specifies a function to call when mouse button 1 is single
+    clicked over an entry in the <strong>listbox</strong> component or if the <strong>&lt;Space&gt;</strong>
+    or <strong>&lt;Return&gt;</strong> key is hit while the <strong>listbox</strong> has focus. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.usehullsize></a>
+<dl><dt> <strong>usehullsize
+</strong></dt><dd>
+Initialisation option. If true, the size of the megawidget is determined solely by the
+    width and height options of the <strong>hull</strong> component.</p>
+<p>    Otherwise, the size of the megawidget is determined by the width
+    and height of the <strong>listbox</strong> component, along with the size and/or
+    existence of the other components, such as the label, the
+    scrollbars and the scrollmargin option.  All these affect the
+    overall size of the megawidget. The default is <strong>0</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.vscrollmode></a>
+<dl><dt> <strong>vscrollmode
+</strong></dt><dd>
+The vertical scroll mode.  If <strong>'none'</strong>, the vertical scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.horizscrollbar></a>
+<dl><dt> <strong>horizscrollbar
+</strong></dt><dd>
+The horizontal scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.listbox></a>
+<dl><dt> <strong>listbox
+</strong></dt><dd>
+The listbox widget which is scrolled by the scrollbars. By default, this component is a Tkinter.Listbox.</p>
+
+
+</dd></dl>
+<a name=component.vertscrollbar></a>
+<dl><dt> <strong>vertscrollbar
+</strong></dt><dd>
+The vertical scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Listbox</strong> class
+are forwarded by this megawidget to the
+<strong>listbox</strong> component.
+<p></p>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(<em>index</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>listbox</strong> component's
+    <code>bbox()</code> method.  Without this explicit forwarding, the <code>bbox()</code>
+    method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+<a name=method.clear></a>
+<dl><dt> <strong>clear</strong>()</dt><dd>
+Delete all items from the scrolled listbox.  Equivalent to
+    <code>setlist(())</code>.</p>
+
+
+</dd></dl>
+<a name=method.get></a>
+<dl><dt> <strong>get</strong>(<em>first</em> = <strong>None</strong>, <em>last</em> = <strong>None</strong>)</dt><dd>
+This is the same as the <code>get()</code> method of the <strong>listbox</strong> component,
+    except that if <em>first</em> is <strong>None</strong> all list
+    elements are returned.</p>
+
+
+</dd></dl>
+<a name=method.getcurselection></a>
+<dl><dt> <strong>getcurselection</strong>()</dt><dd>
+Same as <code>getvalue()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.getvalue></a>
+<dl><dt> <strong>getvalue</strong>()</dt><dd>
+Return a list of the currently selected items of the listbox.</p>
+
+
+</dd></dl>
+<a name=method.setlist></a>
+<dl><dt> <strong>setlist</strong>(<em>items</em>)</dt><dd>
+Replace all the items of the <strong>listbox</strong> component with those
+    specified by the <em>items</em> sequence.</p>
+
+
+</dd></dl>
+<a name=method.setvalue></a>
+<dl><dt> <strong>setvalue</strong>(<em>textOrList</em>)</dt><dd>
+Set the current selection for the scrolled list to <em>textOrList</em>.</p>
+<p>    If <em>textOrList</em> is a string, select only the list item specified.</p>
+
+<p>    Otherwise, select only the list items specified by <em>textOrList</em>,
+    which must be a sequence of strings.</p>
+
+
+
+</dd></dl>
+<a name=method.size></a>
+<dl><dt> <strong>size</strong>()</dt><dd>
+This method is explicitly forwarded to the <strong>listbox</strong> component's
+    <code>size()</code> method.  Without this explicit forwarding, the <code>size()</code>
+    method (aliased to <code>grid_size()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the ScrolledListBox.
+        self.box = Pmw.ScrolledListBox(parent,
+                items=('Sydney', 'Melbourne', 'Brisbane'),
+                labelpos='nw',
+                label_text='Cities',
+                listbox_height = 6,
+                selectioncommand=self.selectionCommand,
+                dblclickcommand=self.defCmd,
+                usehullsize = 1,
+                hull_width = 200,
+                hull_height = 200,
+        )
+
+        # Create a group widget to contain the scrollmode options.
+        w = Pmw.Group(parent, tag_text='Scroll mode')
+        w.pack(side = 'bottom', padx = 5, pady = 5)
+
+        hmode = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Horizontal:',
+                items = ['none', 'static', 'dynamic'],
+                command = self.sethscrollmode,
+                menubutton_width = 8,
+        )
+        hmode.pack(side = 'top', padx = 5, pady = 5)
+        hmode.invoke('dynamic')
+
+        vmode = Pmw.OptionMenu(w.interior(),
+                labelpos = 'w',
+                label_text = 'Vertical:',
+                items = ['none', 'static', 'dynamic'],
+                command = self.setvscrollmode,
+                menubutton_width = 8,
+        )
+        vmode.pack(side = 'top', padx = 5, pady = 5)
+        vmode.invoke('dynamic')
+
+        buttonBox = Pmw.ButtonBox(parent)
+        buttonBox.pack(side = 'bottom')
+        buttonBox.add('yview', text = 'Show\nyview', command = self.showYView)
+        buttonBox.add('scroll', text = 'Page\ndown', command = self.pageDown)
+        buttonBox.add('center', text = 'Center', command = self.centerPage)
+
+        # Pack this last so that the buttons do not get shrunk when
+        # the window is resized.
+        self.box.pack(fill = 'both', expand = 1, padx = 5, pady = 5)
+
+        # Do this after packing the scrolled list box, so that the
+        # window does not resize as soon as it appears (because
+        # alignlabels has to do an update_idletasks).
+        Pmw.alignlabels((hmode, vmode))
+
+        # Add some more entries to the listbox.
+        items = ('Andamooka', 'Coober Pedy', 'Innamincka', 'Oodnadatta')
+        self.box.setlist(items)
+        self.box.insert(2, 'Wagga Wagga', 'Perth', 'London')
+        self.box.insert('end', 'Darwin', 'Auckland', 'New York')
+        index = list(self.box.get(0, 'end')).index('London')
+        self.box.delete(index)
+        self.box.delete(7, 8)
+        self.box.insert('end', 'Bulli', 'Alice Springs', 'Woy Woy')
+        self.box.insert('end', 'Wallumburrawang', 'Willandra Billabong')
+
+    def sethscrollmode(self, tag):
+        self.box.configure(hscrollmode = tag)
+
+    def setvscrollmode(self, tag):
+        self.box.configure(vscrollmode = tag)
+
+    def selectionCommand(self):
+        sels = self.box.getcurselection()
+        if len(sels) == 0:
+            print 'No selection'
+        else:
+            print 'Selection:', sels[0]
+
+    def defCmd(self):
+        sels = self.box.getcurselection()
+        if len(sels) == 0:
+            print 'No selection for double click'
+        else:
+            print 'Double click:', sels[0]
+
+    def showYView(self):
+        print self.box.yview()
+
+    def pageDown(self):
+        self.box.yview('scroll', 1, 'page')
+
+    def centerPage(self):
+        top, bottom = self.box.yview()
+        size = bottom - top
+        middle = 0.5 - size / 2
+        self.box.yview('moveto', middle)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 30 August 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ScrolledText.gif b/Pmw/Pmw_1_2/doc/ScrolledText.gif
new file mode 100644 (file)
index 0000000..b766c95
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/ScrolledText.gif differ
diff --git a/Pmw/Pmw_1_2/doc/ScrolledText.html b/Pmw/Pmw_1_2/doc/ScrolledText.html
new file mode 100644 (file)
index 0000000..1acbccc
--- /dev/null
@@ -0,0 +1,409 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.ScrolledText reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.ScrolledText</h1>
+    
+<center><IMG SRC=ScrolledText.gif ALT="" WIDTH=409 HEIGHT=310></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.ScrolledText() - 
+    text widget with optional scrollbars
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A scrolled text consists of a standard text widget with optional
+    scrollbars which can be used to scroll the text.  The
+    scrollbars can be <em>dynamic</em>, which means that a scrollbar will
+    only be displayed if it is necessary.  That is, if the text widget
+    does not contain enough text (either horizontally or vertically),
+    the scrollbar will be automatically hidden.  If it is displayed,
+    the horizontal scrollbar is under the text widget.  Similarly, if
+    it is displayed, the vertical scrollbar is to the right of the
+    text widget.</p>
+
+<p>    Row and column headers may also be displayed, which scroll in sync
+    with the text widget and may be useful when displaying tabular
+    data.  To assist in ensuring that columns line up when using a
+    column header, a fixed width font should be used.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+Initialisation option. If true, the <strong>borderframe</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.columnheader></a>
+<dl><dt> <strong>columnheader
+</strong></dt><dd>
+Initialisation option. If true, the <strong>columnheader</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.hscrollmode></a>
+<dl><dt> <strong>hscrollmode
+</strong></dt><dd>
+The horizontal scroll mode.  If <strong>'none'</strong>, the horizontal scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.rowcolumnheader></a>
+<dl><dt> <strong>rowcolumnheader
+</strong></dt><dd>
+Initialisation option. If true, the <strong>rowcolumnheader</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.rowheader></a>
+<dl><dt> <strong>rowheader
+</strong></dt><dd>
+Initialisation option. If true, the <strong>rowheader</strong> component will be created. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.scrollmargin></a>
+<dl><dt> <strong>scrollmargin
+</strong></dt><dd>
+Initialisation option. The distance between the scrollbars and the text widget. The default is <strong>2</strong>.</p>
+
+
+</dd></dl>
+<a name=option.usehullsize></a>
+<dl><dt> <strong>usehullsize
+</strong></dt><dd>
+Initialisation option. If true, the size of the megawidget is determined solely by the
+    width and height options of the <strong>hull</strong> component.</p>
+<p>    Otherwise, the size of the megawidget is determined by the width
+    and height of the <strong>text</strong> component, along with the size and/or
+    existence of the other components, such as the label, the
+    scrollbars and the scrollmargin option.  All these affect the
+    overall size of the megawidget. The default is <strong>0</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.vscrollmode></a>
+<dl><dt> <strong>vscrollmode
+</strong></dt><dd>
+The vertical scroll mode.  If <strong>'none'</strong>, the vertical scrollbar
+    will never be displayed.  If <strong>'static'</strong>, the scrollbar will always
+    be displayed.  If <strong>'dynamic'</strong>, the scrollbar will be displayed
+    only if necessary. The default is <strong>'dynamic'</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.borderframe></a>
+<dl><dt> <strong>borderframe
+</strong></dt><dd>
+A frame widget which snuggly fits around the text widget, to give
+    the appearance of a text border.  It is created with a border so
+    that the text widget, which is created without a border, looks
+    like it has a border. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.columnheader></a>
+<dl><dt> <strong>columnheader
+</strong></dt><dd>
+A text widget with a default height of 1 displayed above the main
+    text widget and which scrolls horizontally in sync with the
+    horizontal scrolling of the main text widget. By default, this component is a Tkinter.Text. Its component group is <strong>Header</strong>.</p>
+
+
+</dd></dl>
+<a name=component.horizscrollbar></a>
+<dl><dt> <strong>horizscrollbar
+</strong></dt><dd>
+The horizontal scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.rowcolumnheader></a>
+<dl><dt> <strong>rowcolumnheader
+</strong></dt><dd>
+A text widget displayed to the top left of the main text widget,
+    above the row header and to the left of the column header if they
+    exist.  The widget is not scrolled  automatically. By default, this component is a Tkinter.Text. Its component group is <strong>Header</strong>.</p>
+
+
+</dd></dl>
+<a name=component.rowheader></a>
+<dl><dt> <strong>rowheader
+</strong></dt><dd>
+A text widget displayed to the left of the main text widget and
+    which scrolls vertically in sync with the vertical scrolling of
+    the main text widget. By default, this component is a Tkinter.Text. Its component group is <strong>Header</strong>.</p>
+
+
+</dd></dl>
+<a name=component.text></a>
+<dl><dt> <strong>text
+</strong></dt><dd>
+The text widget which is scrolled by the scrollbars.  If the
+    <strong>borderframe</strong> option is true, this is created with a borderwidth
+    of <strong>0</strong> to overcome a known problem with text widgets:  if a widget
+    inside a text widget extends across one of the edges of the text
+    widget, then the widget obscures the border of the text widget. 
+    Therefore, if the text widget has no border, then this overlapping
+    does not occur. By default, this component is a Tkinter.Text.</p>
+
+
+</dd></dl>
+<a name=component.vertscrollbar></a>
+<dl><dt> <strong>vertscrollbar
+</strong></dt><dd>
+The vertical scrollbar. By default, this component is a Tkinter.Scrollbar. Its component group is <strong>Scrollbar</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+In addition, methods from the
+<strong>Tkinter.Text</strong> class
+are forwarded by this megawidget to the
+<strong>text</strong> component.
+<p></p>
+<a name=method.appendtext></a>
+<dl><dt> <strong>appendtext</strong>(<em>text</em>)</dt><dd>
+Add <em>text</em> to the end of the <strong>text</strong> component.  Scroll to the
+    bottom of the text, but only if it was already visible before the
+    new text was added.</p>
+
+
+</dd></dl>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(<em>index</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>text</strong> component's
+    <code>bbox()</code> method.  Without this explicit forwarding, the <code>bbox()</code>
+    method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+<a name=method.clear></a>
+<dl><dt> <strong>clear</strong>()</dt><dd>
+Delete all text from the <strong>text</strong> component.</p>
+
+
+</dd></dl>
+<a name=method.exportfile></a>
+<dl><dt> <strong>exportfile</strong>(<em>fileName</em>)</dt><dd>
+Write the contents of the <strong>text</strong> component to the file <em>fileName</em>.</p>
+
+
+</dd></dl>
+<a name=method.get></a>
+<dl><dt> <strong>get</strong>(<em>first</em> = <strong>None</strong>, <em>last</em> = <strong>None</strong>)</dt><dd>
+This is the same as the <code>get()</code> method of the <strong>text</strong> component,
+    except that if <em>first</em> is <strong>None</strong> the entire
+    contents of the text widget are returned.</p>
+
+
+</dd></dl>
+<a name=method.getvalue></a>
+<dl><dt> <strong>getvalue</strong>()</dt><dd>
+Return the entire contents of the text widget.</p>
+
+
+</dd></dl>
+<a name=method.importfile></a>
+<dl><dt> <strong>importfile</strong>(<em>fileName</em>, <em>where</em> = <strong>'end'</strong>)</dt><dd>
+Read the contents of the file <em>fileName</em> and insert into the
+    <strong>text</strong> component at the position given by <em>where</em>.</p>
+
+
+</dd></dl>
+<a name=method.settext></a>
+<dl><dt> <strong>settext</strong>(<em>text</em>)</dt><dd>
+Same as <code>setvalue()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.setvalue></a>
+<dl><dt> <strong>setvalue</strong>(<em>text</em>)</dt><dd>
+Replace the entire contents of the <strong>text</strong> component with <em>text</em>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+
+        # Create the ScrolledText with headers.
+        fixedFont = Pmw.logicalfont('Fixed')
+        self.st = Pmw.ScrolledText(parent,
+                # borderframe = 1,
+                labelpos = 'n',
+                label_text='ScrolledText with headers',
+                columnheader = 1,
+                rowheader = 1,
+                rowcolumnheader = 1,
+                usehullsize = 1,
+                hull_width = 400,
+                hull_height = 300,
+                text_wrap='none',
+                text_font = fixedFont,
+                Header_font = fixedFont,
+                Header_foreground = 'blue',
+                rowheader_width = 3,
+                rowcolumnheader_width = 3,
+                text_padx = 4,
+                text_pady = 4,
+                Header_padx = 4,
+                rowheader_pady = 4,
+        )
+
+        self.st.pack(padx = 5, pady = 5, fill = 'both', expand = 1)
+
+        funcs = 'atan cos cosh exp log log10 sin sinh sqrt tan tanh'
+        funcs = string.split(funcs)
+
+        # Create the header for the row headers
+        self.st.component('rowcolumnheader').insert('end', 'x')
+
+        # Create the column headers
+        headerLine = ''
+        for column in range(len(funcs)):
+            headerLine = headerLine + ('%-7s   ' % (funcs[column],))
+        headerLine = headerLine[:-3]
+        self.st.component('columnheader').insert('0.0', headerLine)
+
+        self.st.tag_configure('yellow', background = 'yellow')
+
+        # Create the data rows and the row headers
+        numRows = 50
+        tagList = []
+        for row in range(1, numRows):
+            dataLine = ''
+            x = row / 5.0
+            for column in range(len(funcs)):
+                value = eval('math.' + funcs[column] + '(' + str(x) + ')')
+                data = str(value)[:7]
+                if value &lt; 0:
+                    tag1 = '%d.%d' % (row, len(dataLine))
+                    tag2 = '%d.%d' % (row, len(dataLine) + len(data))
+                    tagList.append(tag1)
+                    tagList.append(tag2)
+                data = '%-7s' % (data,)
+                dataLine = dataLine + data + '   '
+            dataLine = dataLine[:-3]
+            header = '%.1f' % (x,)
+            if row &lt; numRows - 1:
+                dataLine = dataLine + '\n'
+                header = header + '\n'
+            self.st.insert('end', dataLine)
+            self.st.component('rowheader').insert('end', header)
+        apply(self.st.tag_add, ('yellow',) + tuple(tagList))
+
+        # Prevent users' modifying text and headers
+        self.st.configure(
+            text_state = 'disabled',
+            Header_state = 'disabled',
+        )
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 30 August 1998
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/ScrolledText_test.py b/Pmw/Pmw_1_2/doc/ScrolledText_test.py
new file mode 100644 (file)
index 0000000..53a5ab4
--- /dev/null
@@ -0,0 +1,116 @@
+# Based on iwidgets2.2.0/tests/scrolledtext.test code.   
+
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ScrolledText
+
+def _testYView(doBottom):
+    w = Test.currentWidget()
+    top, bottom = w.yview()
+    if type(top) != type(0.0) or type(bottom) != type(0.0):
+        return 'bad type ' + str(top) + ' ' + str(bottom)
+    if doBottom:
+        if bottom != 1.0:
+            return 'bottom is ' + str(bottom)
+    else:
+        if top != 0.0:
+            return 'top is ' + str(top)
+
+kw_1 = {'labelpos': 'n', 'label_text': 'ScrolledText'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 10),
+  (c.importfile, 'ScrolledText_test.py'),
+  ('hull_background', 'aliceblue'),
+  ('text_borderwidth', 3),
+  ('Scrollbar_borderwidth', 3),
+  ('hull_cursor', 'gumby'),
+  ('text_exportselection', 0),
+  ('text_exportselection', 1),
+  ('text_foreground', 'Black'),
+  ('text_height', 10),
+  ('text_width', 20),
+  ('text_insertbackground', 'Black'),
+  ('text_insertborderwidth', 1),
+  ('text_insertofftime', 200),
+  ('text_insertontime', 500),
+  ('text_insertwidth', 3),
+  ('label_text', 'Label'),
+  ('text_relief', 'raised'),
+  ('text_relief', 'sunken'),
+  ('Scrollbar_repeatdelay', 200),
+  ('Scrollbar_repeatinterval', 105),
+  ('vscrollmode', 'none'),
+  ('vscrollmode', 'static'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'none'),
+  ('hscrollmode', 'static'),
+  ('hscrollmode', 'dynamic'),
+  ('Scrollbar_width', 20),
+  ('text_selectborderwidth', 2),
+  ('text_state', 'disabled'),
+  ('text_state', 'normal'),
+  ('text_background', 'GhostWhite'),
+  ('text_wrap', 'char'),
+  ('text_wrap', 'none'),
+  ('vscrollmode', 'bogus', 'ValueError: bad vscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  ('hscrollmode', 'bogus', 'ValueError: bad hscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  (c.cget, 'vscrollmode', 'bogus'),
+  (c.cget, 'hscrollmode', 'bogus'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'dynamic'),
+  (c.insert, ('end', 'Hello there\n')),
+  (_testYView, 0),
+  (c.yview, ('moveto', 0.02)),
+  (c.yview, ('moveto', 0.04)),
+  (c.yview, ('moveto', 0.06)),
+  (c.yview, ('moveto', 0.08)),
+  (c.yview, ('moveto', 0.10)),
+  (c.yview, ('moveto', 0.12)),
+  (c.yview, ('moveto', 0.14)),
+  (c.yview, ('moveto', 0.16)),
+  (c.yview, ('moveto', 0.18)),
+  (c.yview, ('moveto', 0.20)),
+  (c.yview, ('moveto', 0.22)),
+  (c.yview, ('moveto', 0.24)),
+  (c.yview, ('moveto', 0.26)),
+  (c.yview, ('moveto', 0.28)),
+  (c.yview, ('moveto', 0.98)),
+  (_testYView, 1),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -50, 'page')),
+  (_testYView, 0),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 50, 'page')),
+  (_testYView, 1),
+  (c.clear, ()),
+  (c.get, (), '\n'),
+)
+
+kw_2 = {
+  'hscrollmode' : 'dynamic',
+  'label_text' : 'Label',
+  'labelpos' : 'n',
+  'scrollmargin': 20,
+}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (c.importfile, 'ScrolledText_test.py'),
+  ('text_relief', 'raised'),
+  ('text_relief', 'sunken'),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((Pmw.ScrolledText, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/doc/SelectionDialog.gif b/Pmw/Pmw_1_2/doc/SelectionDialog.gif
new file mode 100644 (file)
index 0000000..1d6f3dd
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/SelectionDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/SelectionDialog.html b/Pmw/Pmw_1_2/doc/SelectionDialog.html
new file mode 100644 (file)
index 0000000..c470823
--- /dev/null
@@ -0,0 +1,281 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.SelectionDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.SelectionDialog</h1>
+    
+<center><IMG SRC=SelectionDialog.gif ALT="" WIDTH=206 HEIGHT=278></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.SelectionDialog() - 
+    selection dialog displaying a scrolled list
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="Dialog.html">Pmw.Dialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    The selection dialog is a dialog window which displays a scrolled
+    list which can be used to prompt the user for a value.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the scrolled list. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the scrolled list. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.scrolledlist></a>
+<dl><dt> <strong>scrolledlist
+</strong></dt><dd>
+The scrolled list for the user to enter a value. By default, this component is a <a href="ScrolledListBox.html">Pmw.ScrolledListBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>label
+</strong></dt><dd>
+Alias for <strong>scrolledlist_label</strong>.
+</dd></dl>
+<dl><dt> <strong>listbox
+</strong></dt><dd>
+Alias for <strong>scrolledlist_listbox</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="Dialog.html#methods">Pmw.Dialog</a></strong>.
+In addition, methods from the
+<strong><a href="ScrolledListBox.html#methods">Pmw.ScrolledListBox</a></strong> class
+are forwarded by this megawidget to the
+<strong>scrolledlist</strong> component.
+<p></p>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(<em>index</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>listbox</strong> component's
+    <code>bbox()</code> method.  Without this explicit forwarding, the <code>bbox()</code>
+    method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+<a name=method.size></a>
+<dl><dt> <strong>size</strong>()</dt><dd>
+This method is explicitly forwarded to the <strong>listbox</strong> component's
+    <code>size()</code> method.  Without this explicit forwarding, the <code>size()</code>
+    method (aliased to <code>grid_size()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the dialog.
+        self.dialog = Pmw.SelectionDialog(parent,
+            title = 'My SelectionDialog',
+            buttons = ('OK', 'Cancel'),
+            defaultbutton = 'OK',
+            scrolledlist_labelpos = 'n',
+            label_text = 'What do you think of Pmw?',
+            scrolledlist_items = ('Cool man', 'Cool', 'Good', 'Bad', 'Gross'),
+            command = self.execute)
+        self.dialog.withdraw()
+
+        # Create button to launch the dialog.
+        w = Tkinter.Button(parent, text = 'Show selection dialog',
+                command = self.dialog.activate)
+        w.pack(padx = 8, pady = 8)
+
+    def execute(self, result):
+        sels = self.dialog.getcurselection()
+        if len(sels) == 0:
+            print 'You clicked on', result, '(no selection)'
+        else:
+            print 'You clicked on', result, sels[0]
+        self.dialog.deactivate(result)
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/TextDialog.gif b/Pmw/Pmw_1_2/doc/TextDialog.gif
new file mode 100644 (file)
index 0000000..4438828
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/TextDialog.gif differ
diff --git a/Pmw/Pmw_1_2/doc/TextDialog.html b/Pmw/Pmw_1_2/doc/TextDialog.html
new file mode 100644 (file)
index 0000000..3f4995f
--- /dev/null
@@ -0,0 +1,301 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.TextDialog reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.TextDialog</h1>
+    
+<center><IMG SRC=TextDialog.gif ALT="" WIDTH=362 HEIGHT=287></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.TextDialog() - 
+    a dialog displaying a scrolled text
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="Dialog.html">Pmw.Dialog</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A text dialog is a dialog window which displays a text message to
+    the user along with one or more buttons to press.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.activatecommand></a>
+<dl><dt> <strong>activatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    activated by a call to <code>activate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.borderx></a>
+<dl><dt> <strong>borderx
+</strong></dt><dd>
+Initialisation option. The padding to the left and right of the scrolled text. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+<a name=option.bordery></a>
+<dl><dt> <strong>bordery
+</strong></dt><dd>
+Initialisation option. The padding above and below the scrolled text. The default is <strong>10</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonboxpos></a>
+<dl><dt> <strong>buttonboxpos
+</strong></dt><dd>
+Initialisation option. Specifies on which side of the dialog window to place the button
+    box.  Must be one of <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> or <strong>'w'</strong>. The default is <strong>'s'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttons></a>
+<dl><dt> <strong>buttons
+</strong></dt><dd>
+This must be a tuple or a list and specifies the names on the
+    buttons in the button box. The default is <strong>('OK',)</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+Specifies a function to call whenever a button in the button box
+    is invoked or the window is deleted by the window manager.  The
+    function is called with a single argument, which is the name of
+    the button which was invoked, or <strong>None</strong> if the window was deleted
+    by the window manager.</p>
+<p>    If the value of <strong>command</strong> is not callable, the default behaviour
+    is to deactivate the window if it is active, or withdraw the
+    window if it is not active.  If it is deactivated, <code>deactivate()</code>
+    is called with the button name or <strong>None</strong> as described above. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.deactivatecommand></a>
+<dl><dt> <strong>deactivatecommand
+</strong></dt><dd>
+If this is callable, it will be called whenever the megawidget is
+    deactivated by a call to <code>deactivate()</code>. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.defaultbutton></a>
+<dl><dt> <strong>defaultbutton
+</strong></dt><dd>
+Specifies the default button in the button box.  If the <strong>&lt;Return&gt;</strong>
+    key is hit when the dialog has focus, the default button will be
+    invoked.  If <strong>defaultbutton</strong> is <strong>None</strong>, there will be no default
+    button and hitting the <strong>&lt;Return&gt;</strong> key will have no effect. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.master></a>
+<dl><dt> <strong>master
+</strong></dt><dd>
+This is used by the <code>activate()</code> method to control whether the
+    window is made <em>transient</em> during modal dialogs.  See the
+    <code>activate()</code> method. The default is <strong>'parent'</strong>.</p>
+
+
+</dd></dl>
+<a name=option.separatorwidth></a>
+<dl><dt> <strong>separatorwidth
+</strong></dt><dd>
+Initialisation option. If this is greater than <strong>0</strong>, a separator line with the specified
+    width will be created between the button box and the child site,
+    as a component named <strong>separator</strong>.  Since the default border of the
+    button box and child site is <strong>raised</strong>, this option does not
+    usually need to be set for there to be a visual separation between
+    the button box and child site. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.title></a>
+<dl><dt> <strong>title
+</strong></dt><dd>
+This is the title that the window manager displays in the title
+    bar of the window. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.buttonbox></a>
+<dl><dt> <strong>buttonbox
+</strong></dt><dd>
+This is the button box containing the buttons for the dialog.  By
+    default it is created with the options
+    <code>(hull_borderwidth = 1, hull_relief = 'raised')</code>. By default, this component is a <a href="ButtonBox.html">Pmw.ButtonBox</a>.</p>
+
+
+</dd></dl>
+<a name=component.dialogchildsite></a>
+<dl><dt> <strong>dialogchildsite
+</strong></dt><dd>
+This is the child site for the dialog, which may be used to
+    specialise the megawidget by creating other widgets within it.  By
+    default it is created with the options
+    <code>(borderwidth = 1, relief = 'raised')</code>. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Toplevel.</p>
+
+
+</dd></dl>
+<a name=component.scrolledtext></a>
+<dl><dt> <strong>scrolledtext
+</strong></dt><dd>
+The scrolled text to contain the text for the dialog. By default, this component is a <a href="ScrolledText.html">Pmw.ScrolledText</a>.</p>
+
+
+</dd></dl>
+<a name=component.separator></a>
+<dl><dt> <strong>separator
+</strong></dt><dd>
+If the <strong>separatorwidth</strong> initialisation option is non-zero, the
+    <strong>separator</strong> component is the line dividing the area between the
+    button box and the child site. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>label
+</strong></dt><dd>
+Alias for <strong>scrolledtext_label</strong>.
+</dd></dl>
+<dl><dt> <strong>text
+</strong></dt><dd>
+Alias for <strong>scrolledtext_text</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="Dialog.html#methods">Pmw.Dialog</a></strong>.
+In addition, methods from the
+<strong><a href="ScrolledText.html#methods">Pmw.ScrolledText</a></strong> class
+are forwarded by this megawidget to the
+<strong>scrolledtext</strong> component.
+<p></p>
+<a name=method.bbox></a>
+<dl><dt> <strong>bbox</strong>(<em>index</em>)</dt><dd>
+This method is explicitly forwarded to the <strong>text</strong> component's
+    <code>bbox()</code> method.  Without this explicit forwarding, the <code>bbox()</code>
+    method (aliased to <code>grid_bbox()</code>) of the <strong>hull</strong> would be invoked,
+    which is probably not what the programmer intended.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        # Create the dialog.
+        dialog = Pmw.TextDialog(parent, scrolledtext_labelpos = 'n',
+                title = 'My TextDialog',
+                defaultbutton = 0,
+                label_text = 'Lawyer jokes')
+        dialog.withdraw()
+        dialog.insert('end', jokes)
+        dialog.configure(text_state = 'disabled')
+
+        # Create button to launch the dialog.
+        w = Tkinter.Button(parent, text = 'Show text dialog',
+                command = dialog.activate)
+        w.pack(padx = 8, pady = 8)
+
+jokes = """
+Q: What do you call 5000 dead lawyers at the bottom of the ocean?
+A: A good start!
+
+Q: How can you tell when a lawyer is lying?
+A: His lips are moving.
+
+Q: Why won't sharks attack lawyers?
+A: Professional courtesy.
+
+Q: What do have when a lawyer is buried up to his neck in sand?
+A: Not enough sand.
+
+Q: How do you get a lawyer out of a tree?
+A: Cut the rope.
+
+Q: What is the definition of a shame (as in "that's a shame")?
+A: When a bus load of lawyers goes off a cliff.
+
+Q: What is the definition of a "crying shame"?
+A: There was an empty seat.
+
+Q: What do you get when you cross the Godfather with a lawyer?
+A: An offer you can't understand.
+
+Q. What do lawyers use as contraceptives?
+A. Their personalities.
+
+Q. What's brown and black and looks good on a lawyer?
+A. A doberman.
+
+Q. Why are lawyers buried 12 feet underground?
+A. Deep down their good.
+
+Q. What's the difference between a catfish and a lawyer?
+A. One's a slimy scum-sucking scavenger, the other is just a fish.
+
+"""
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 18 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/TimeCounter.gif b/Pmw/Pmw_1_2/doc/TimeCounter.gif
new file mode 100644 (file)
index 0000000..26cbdba
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/TimeCounter.gif differ
diff --git a/Pmw/Pmw_1_2/doc/TimeCounter.html b/Pmw/Pmw_1_2/doc/TimeCounter.html
new file mode 100644 (file)
index 0000000..6fbdea3
--- /dev/null
@@ -0,0 +1,363 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw.TimeCounter reference manual</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw.TimeCounter</h1>
+    
+<center><IMG SRC=TimeCounter.gif ALT="" WIDTH=170 HEIGHT=85></center>
+<dl>
+<dt> <h3>Name</h3></dt><dd>
+<p>Pmw.TimeCounter() - 
+    counter for display and input of time
+</p>
+
+
+</dd>
+<dt> <h3>Inherits</h3></dt><dd>
+<a href="MegaWidget.html">Pmw.MegaWidget</a><br>
+</dd>
+<dt> <h3>Description</h3></dt><dd>
+<p>
+    A time counter is similar to a regular <a href="Counter.html">Pmw.Counter</a> except that the
+    user may increment and decrement the hours, minutes and seconds
+    individually.</p>
+
+<p></p>
+
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+Options for this megawidget and its base
+classes are described below.<p></p>
+<a name=option.autorepeat></a>
+<dl><dt> <strong>autorepeat
+</strong></dt><dd>
+If true, the counter will continue to count up or down while an
+    arrow button is held pressed down. The default is <strong>1</strong>.</p>
+
+
+</dd></dl>
+<a name=option.buttonaspect></a>
+<dl><dt> <strong>buttonaspect
+</strong></dt><dd>
+Initialisation option. Specifies the width of the arrow buttons as a proportion of their
+    height.  Values less than <strong>1.0</strong> will produce thin arrow buttons. 
+    Values greater than <strong>1.0</strong> will produce fat arrow buttons. The default is <strong>1.0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.command></a>
+<dl><dt> <strong>command
+</strong></dt><dd>
+This specifies a function to call whenever the <strong>&lt;Return&gt;</strong> key is
+    pressed in one of the entry fields or <code>invoke()</code> is called. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.initwait></a>
+<dl><dt> <strong>initwait
+</strong></dt><dd>
+Specifies the initial delay (in milliseconds) before a depressed
+    arrow button automatically starts to repeat counting. The default is <strong>300</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelmargin></a>
+<dl><dt> <strong>labelmargin
+</strong></dt><dd>
+Initialisation option. If the <strong>labelpos</strong> option is not <strong>None</strong>, this specifies the
+        distance between the <strong>label</strong> component and the rest of the
+        megawidget. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.labelpos></a>
+<dl><dt> <strong>labelpos
+</strong></dt><dd>
+Initialisation option. Specifies where to place the <strong>label</strong> component.  If not
+        <strong>None</strong>, it should be a concatenation of one or two of the
+        letters <strong>'n'</strong>, <strong>'s'</strong>, <strong>'e'</strong> and <strong>'w'</strong>.  The first letter
+        specifies on which side of the megawidget to place the label. 
+        If a second letter is specified, it indicates where on that
+        side to place the label.  For example, if <strong>labelpos</strong> is <strong>'w'</strong>,
+        the label is placed in the center of the left hand side; if
+        it is <strong>'wn'</strong>, the label is placed at the top of the left
+        hand side; if it is <strong>'ws'</strong>, the label is placed at the
+        bottom of the left hand side.</p>
+<p>        If <strong>None</strong>, a label component is not created. The default is <strong>None</strong>.</p>
+
+
+
+</dd></dl>
+<a name=option.max></a>
+<dl><dt> <strong>max
+</strong></dt><dd>
+Specifies the maximum acceptable time in the form "HH:MM:SS", or
+    <strong>None</strong> if no maximum checking should be performed. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.min></a>
+<dl><dt> <strong>min
+</strong></dt><dd>
+Specifies the minimum acceptable time in the form "HH:MM:SS", or
+    <strong>None</strong> if no minimum checking should be performed. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+<a name=option.padx></a>
+<dl><dt> <strong>padx
+</strong></dt><dd>
+Initialisation option. Specifies how much wider to make each column than the default
+    width (where a column consists of two arrows and an entry field). 
+    The entry fields expand to fill the extra space, but the arrow
+    buttons are centered in the available space. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.pady></a>
+<dl><dt> <strong>pady
+</strong></dt><dd>
+Initialisation option. Specifies how much higher to make each row of arrow buttons than
+    the default hight.  The arrow buttons are centered in the
+    available space. The default is <strong>0</strong>.</p>
+
+
+</dd></dl>
+<a name=option.repeatrate></a>
+<dl><dt> <strong>repeatrate
+</strong></dt><dd>
+Specifies the delay (in milliseconds) between automatic counts
+    while an arrow button is held pressed down. The default is <strong>50</strong>.</p>
+
+
+</dd></dl>
+<a name=option.value></a>
+<dl><dt> <strong>value
+</strong></dt><dd>
+Initialisation option. Specifies the initial contents of the time counter, in the form
+    "HH:MM:SS".  If this is <strong>None</strong>, the current time is used as the
+    initial contents. The default is <strong>None</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+Components created by this megawidget and its base
+classes are described below.<p></p>
+<a name=component.downhourarrow></a>
+<dl><dt> <strong>downhourarrow
+</strong></dt><dd>
+The arrow button used for decrementing the hour field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+<a name=component.downminutearrow></a>
+<dl><dt> <strong>downminutearrow
+</strong></dt><dd>
+The arrow button used for decrementing the minute field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+<a name=component.downsecondarrow></a>
+<dl><dt> <strong>downsecondarrow
+</strong></dt><dd>
+The arrow button used for decrementing the second field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+<a name=component.frame></a>
+<dl><dt> <strong>frame
+</strong></dt><dd>
+If the <strong>label</strong> component has been created (that is, the <strong>labelpos</strong>
+    option is not <strong>None</strong>), the <strong>frame</strong> component is created to act as
+    the container of the entry fields and arrow buttons.  If there is
+    no <strong>label</strong> component, then no <strong>frame</strong> component is created and the
+    <strong>hull</strong> component acts as the container.  In either case the border
+    around the container of the entry fields and arrow buttons will be
+    raised (but not around the label). By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.hourentryfield></a>
+<dl><dt> <strong>hourentryfield
+</strong></dt><dd>
+The entry field where the hours are entered and displayed. By default, this component is a <a href="EntryField.html">Pmw.EntryField</a>.</p>
+
+
+</dd></dl>
+<a name=component.hull></a>
+<dl><dt> <strong>hull
+</strong></dt><dd>
+This acts as the body for the entire megawidget.  Other components
+    are created as children of the hull to further specialise this
+    class. By default, this component is a Tkinter.Frame.</p>
+
+
+</dd></dl>
+<a name=component.label></a>
+<dl><dt> <strong>label
+</strong></dt><dd>
+If the <strong>labelpos</strong> option is not <strong>None</strong>, this component is
+        created as a text label for the megawidget.  See the
+        <strong>labelpos</strong> option for details.  Note that to set, for example,
+        the <strong>text</strong> option of the label, you need to use the <strong>label_text</strong>
+        component option. By default, this component is a Tkinter.Label.</p>
+
+
+</dd></dl>
+<a name=component.minuteentryfield></a>
+<dl><dt> <strong>minuteentryfield
+</strong></dt><dd>
+The entry field where the minutes are entered and displayed. By default, this component is a <a href="EntryField.html">Pmw.EntryField</a>.</p>
+
+
+</dd></dl>
+<a name=component.secondentryfield></a>
+<dl><dt> <strong>secondentryfield
+</strong></dt><dd>
+The entry field where the seconds are entered and displayed. By default, this component is a <a href="EntryField.html">Pmw.EntryField</a>.</p>
+
+
+</dd></dl>
+<a name=component.uphourarrow></a>
+<dl><dt> <strong>uphourarrow
+</strong></dt><dd>
+The arrow button used for incrementing the hour field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+<a name=component.upminutearrow></a>
+<dl><dt> <strong>upminutearrow
+</strong></dt><dd>
+The arrow button used for incrementing the minute field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+<a name=component.upsecondarrow></a>
+<dl><dt> <strong>upsecondarrow
+</strong></dt><dd>
+The arrow button used for incrementing the second field. By default, this component is a Tkinter.Canvas. Its component group is <strong>Arrow</strong>.</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Component aliases</h3></dt><dd>
+Sub-components of components of this megawidget
+may be accessed via the following aliases.<p></p>
+<dl><dt> <strong>hourentry
+</strong></dt><dd>
+Alias for <strong>hourentryfield_entry</strong>.
+</dd></dl>
+<dl><dt> <strong>minuteentry
+</strong></dt><dd>
+Alias for <strong>minuteentryfield_entry</strong>.
+</dd></dl>
+<dl><dt> <strong>secondentry
+</strong></dt><dd>
+Alias for <strong>secondentryfield_entry</strong>.
+</dd></dl>
+</dd>
+<a name=methods></a>
+<dt> <h3>Methods</h3></dt><dd>
+Only methods specific to this megawidget are described below.
+For a description of its inherited methods, see the
+manual for its base class
+<strong><a href="MegaWidget.html#methods">Pmw.MegaWidget</a></strong>.
+<p></p>
+<a name=method.decrement></a>
+<dl><dt> <strong>decrement</strong>(<em>seconds</em> = <strong>1</strong>)</dt><dd>
+Decrement the time by <em>seconds</em> seconds.</p>
+
+
+</dd></dl>
+<a name=method.getint></a>
+<dl><dt> <strong>getint</strong>()</dt><dd>
+Return the currently displayed time as a number of seconds.</p>
+
+
+</dd></dl>
+<a name=method.getstring></a>
+<dl><dt> <strong>getstring</strong>()</dt><dd>
+Same as <code>getvalue()</code> method.</p>
+
+
+</dd></dl>
+<a name=method.getvalue></a>
+<dl><dt> <strong>getvalue</strong>()</dt><dd>
+Return the currently displayed time as a string in the form
+    "HH:MM:SS".</p>
+
+
+</dd></dl>
+<a name=method.increment></a>
+<dl><dt> <strong>increment</strong>(<em>seconds</em> = <strong>1</strong>)</dt><dd>
+Increment the time by <em>seconds</em> seconds.</p>
+
+
+</dd></dl>
+<a name=method.invoke></a>
+<dl><dt> <strong>invoke</strong>()</dt><dd>
+Invoke the command specified by the <strong>command</strong> option as if the
+    <strong>&lt;Return&gt;</strong> key had been pressed.</p>
+
+
+</dd></dl>
+<a name=method.setvalue></a>
+<dl><dt> <strong>setvalue</strong>(<em>text</em>)</dt><dd>
+Set the contents of the time counter, where <em>text</em> must be in the
+    form "HH:MM:SS".</p>
+
+
+</dd></dl>
+</dd>
+<dt> <h3>Example</h3></dt><dd>
+The image at the top of this manual is a snapshot
+of the window (or part of the window) produced
+by the following code.<p></p>
+<pre>
+class Demo:
+    def __init__(self, parent):
+        self._time = Pmw.TimeCounter(parent,
+                labelpos = 'w',
+                label_text = 'HH:MM:SS',
+                min = '00:00:00',
+                max = '23:59:59')
+        self._time.pack(padx=10, pady=5)
+
+        button = Tkinter.Button(parent, text = 'Show', command = self.show)
+        button.pack()
+
+    def show(self):
+        stringVal = self._time.getstring()
+        intVal =  self._time.getint()
+        print stringVal + '  (' + str(intVal) + ')'
+
+</pre>
+</dd>
+</dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    <br>Manual page last reviewed: 25 May 2002
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/blue_line.gif b/Pmw/Pmw_1_2/doc/blue_line.gif
new file mode 100644 (file)
index 0000000..2063df0
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/blue_line.gif differ
diff --git a/Pmw/Pmw_1_2/doc/blueball.gif b/Pmw/Pmw_1_2/doc/blueball.gif
new file mode 100644 (file)
index 0000000..013183a
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/blueball.gif differ
diff --git a/Pmw/Pmw_1_2/doc/bugs.html b/Pmw/Pmw_1_2/doc/bugs.html
new file mode 100644 (file)
index 0000000..f46e8e9
--- /dev/null
@@ -0,0 +1,378 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>List of known bugs</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">List of known bugs</h1>
+    
+<p>
+This is a list of some of the known bugs in Pmw.  If you fix any of
+these, please let the maintainer (<em>gregm@iname.com</em>) know.</p>
+<ul><li><p>Under the Enlightenment window manager, if show() is called when
+      a window is already displayed (and is not obscured by other
+      windows), then the application will hang for two seconds.  This
+      is either a bug in Tcl/Tk or in Enlightenment.  See the comment
+      in the Tk function WaitForConfigureNotify() in the Tk source
+      file tk8.3.2/unix/tkUnixWm.c:</p>
+<dl><dd><pre> /*
+  * One more tricky detail about this procedure.  In some cases the
+  * window manager will decide to ignore a configure request (e.g.
+  * because it thinks the window is already in the right place).
+  * To avoid hanging in this situation, only wait for a few seconds,
+  * then give up.
+  */</pre></dd></dl>
+
+
+</li>
+<li><p>On NT, Pmw.MenuBar does not display message bar help for menu
+      items.  It seems that Tk menu widgets do not support &lt;Motion&gt;
+      events on MS.  This probably is an issue that should be taken up
+      with the Tcl/Tk people.  (Reported by Stefan Schone.  Pmw.0.7)</p>
+
+</li>
+<li><p>Run the CounterDialog.py demo, select the show dialog button and
+      press ok.  Now exit the dialog (either with the exit button or
+      the close box).  The following error appears:</p>
+<dl><dd><pre> Menu ID 256 is already in use!Fatal Python Error: Tcl/Tk panic</pre></dd></dl>
+
+<p>      This may be a problem with Mac version of Tk.  (Reported by
+      Anthony Wilson.)</p>
+
+
+</li>
+<li><p>Pmw.Balloons bind to widgets and canvas items.  This means that
+      bindings made by other users are deleted when the balloon makes
+      its bindings.  (For example, the "Delete" canvas item in the
+      Balloon demo overrides that &lt;ButtonPress&gt; binding and so that
+      balloon is not withdrawn when the mouse button is pressed over
+      the item.)</p>
+<p>      The obvious solution is for Pmw.Balloon to add its bindings with
+      a <em>+</em>.  But this would make the unbind and tagunbind methods
+      inconsistent - they would remove all bindings, not just the ones
+      added by the balloon.  A better way would be for the balloon to
+      add a bindtag to each widget`s bindtag list - then it would not
+      upset any other bindings and it could be deleted cleanly. 
+      (Reported by Joe Saltiel)</p>
+
+
+</li></ul>
+
+<dl><dd><pre> import Tkinter
+ import Pmw
+ def foo(event):
+     print '&lt;Enter&gt; event on text'
+ root = Pmw.initialise()
+ balloon = Pmw.Balloon()
+ canvas = Tkinter.Canvas()
+ canvas.pack()
+ text1 = canvas.create_text(50, 50, text = 'hello
+there')
+ # As is, the balloon does not appear over the text, but foo
+ # is called.  Swap the following two lines and the balloon
+ # appears but foo will not be called.
+ canvas.tag_bind(text1, "&lt;Enter&gt;", foo)
+ balloon.tagbind(canvas, text1, 'text 1 help')
+ root.mainloop()</pre></dd></dl>
+<ul><li><p>In Pmw.Balloon, the balloon should not be withdrawn when the
+      pointer leaves a widget or item and it immediatly enters another
+      widget or item with balloon help.  Instead, the balloon should
+      be moved and its contents changed immediately.</p>
+
+</li>
+<li><p>When a Pmw.Balloon is bound to a canvas item, moving the item
+      becomes very slow.  (Reported by Joe Saltiel)</p>
+<dl><dd><pre> &gt; Second, after I fixed my ordering problem I noticed, there
+ &gt; is a pretty big delay in updating widgets that have balloon
+ &gt; messages bound to them.  (For example dragging a box across
+ &gt; a screen, the box has a delayed reaction.) I believe this is
+ &gt; due to some of the timing functions used in PmwBalloon, I am
+ &gt; not sure if there is a way around it.  I set all timers to
+ &gt; zero, and still had the problem.</pre></dd></dl>
+
+
+</li>
+<li><p>When running Pmw demos under ptui the busy cursor does not
+      appear.</p>
+
+</li>
+<li><p>If a combobox has a horizontal scrollbar and it displays its
+      listbox above the entry, then it is misplaced.</p>
+
+</li>
+<li><p>Bug in Pmw.PanedWidget:  repeat by creating new panes in Demo -
+      existing panes jump to the right 1 or 2 pixels.</p>
+
+</li>
+<li><p>Bug in Pmw.PanedWidget:  repeat by setting hull_borderwidth to
+      20 in demo - initial drag jumps to right by about 20 pixels. 
+      Also right hand side border is missing.  (Fix may be similar to
+      method used in Pmw.ScrolledFrame to give canvas border.)</p>
+
+</li>
+<li><p>Fix ButtonRelease events so they do not trigger without a
+      corresponding ButtonPress event.</p>
+<p>      From Joe Saltiel:  I was playing around with a scrolledlistbox
+      and tkFileDialog.  When I have the dialog open above the list
+      box and I doubleclick on it, I invoke the selectioncmd of the
+      listbox as well as the tkFileDialog box, should this be
+      happening?</p>
+
+<p>      Attached is small sample program you can try.  To get the bug to
+      show you must do two things.  First, when you open the file
+      dialog box, make sure the item you are going to select if
+      over(above) the scrolledlistbox.  Second, you have to double
+      click on that item.  If you single click and hit "Open" you do
+      not get the bug.  Nor do you get it unless the file you click on
+      is directly over the clickable region of the scrolledlist box.</p>
+<dl><dd><pre> import Tkinter
+ import Pmw
+ import tkFileDialog
+ import string 
+ def askOpen():
+     file = tkFileDialog.askopenfile(filetypes=[("all files", "*")])  
+     print file
+ def printMe():
+     print "Me"
+ root = Tkinter.Tk()
+ Pmw.initialise(root)
+ frame1 = Tkinter.Frame(root)
+ lst = string.split("abc def ghi jkl mno pqr stu vwx yz")
+ lstbox = Pmw.ScrolledListBox(frame1, items=lst, selectioncommand=printMe)
+ lstbox.grid(row=0, column=0, columnspan=2)
+ Tkinter.Button(frame1, text='open', command=askOpen).grid(row=1, column=0)
+ Tkinter.Button(frame1, text='exit', command=root.destroy).grid(row=1, column=1)
+ frame1.pack()
+ root.mainloop()</pre></dd></dl>
+
+
+<p>      Response:  I have found where the problem is but I am not sure
+      how to fix it.  It appears that the tkFileDialog box closes on a
+      ButtonPress event.  The corresponding ButtonRelease event is
+      then sent to whichever widget is under the cursor at the time of
+      the Release.  I have reproduced the problem with a Tcl-only
+      script:</p>
+<dl><dd><pre> listbox .l
+ .l insert 0 1 2 3 4
+ bind .l &lt;ButtonRelease-1&gt; {puts AAAGGHHH!}
+
+ button .b -text open -command tk_getOpenFile
+ pack .l .b</pre></dd></dl>
+
+
+<p>      If you do a quick Press-Release-Press over the file dialog, it
+      is withdrawn.  If you then keep the mouse button down and move
+      the mouse around, you will see that the button and the listbox
+      still respond to it.  If you do the final button Release over
+      the listbox, its &lt;ButtonRelease-1&gt; binding is invoked.</p>
+
+<p>      I think the correct solution is to modify Pmw to be very careful
+      when to accept ButtonRelease events.  It will need to also bind
+      to ButtonPress events and make sure that it gets a Press before
+      it accepts the Release.  I'll try to do the change as soon as
+      possible, but the code involved is fairly complex so I it may
+      take a little time.</p>
+
+
+</li>
+<li><p>Investigate bug in Tk8.0:  When a dialog pops up over the
+      pointer then the keyboard focus is not set and so &lt;Return&gt; does
+      not invoke default button.</p>
+
+</li>
+<li><p>Under both X and NT, the arrows in the timecounter, counter and
+      combobox do not match the scrollbar arrows.</p>
+
+</li>
+<li><p>Pmw.Group does not work correctly when the tag is a compound
+      widget.  The tag is placed such that the top of the tag is cut
+      off.  (Reported by Peter Stoehr.)</p>
+<dl><dd><pre> import Tkinter
+ import Pmw
+ root = Tkinter.Tk()
+ Pmw.initialise(root, fontScheme = 'pmw1')
+ exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy)
+ exitButton.pack(side = 'bottom')
+ def makeGroup(tagClassName):
+     tagClass = eval(tagClassName)
+     group = Pmw.Group(
+         tag_pyclass = tagClass,
+         hull_background = 'red',
+         groupchildsite_background = 'blue',
+     )
+     group.pack(fill = 'both', expand = 1, padx = 6, pady = 6)
+     child = Tkinter.Label(group.interior(),
+         text = 'Group with tag ' + tagClassName,
+         background = 'aliceblue',
+     )
+     child.pack(padx = 10, pady = 5, expand = 1, fill = 'both')
+
+     return group
+ grp1 = makeGroup('Pmw.EntryField')
+ grp2 = makeGroup('Pmw.ComboBox')
+ grp3 = makeGroup('Tkinter.Entry')
+ root.mainloop()</pre></dd></dl>
+
+<p>      Also, Pmw.Group does not resize correctly if the simple widget
+      changes size.  For example:</p>
+<dl><dd><pre> grp3.configure(tag_font = ('Helveltica', '-160'))</pre></dd></dl>
+
+
+
+</li>
+<li><p>Bug(s) in PmwScrolledCanvas.  There is a bug in 0.8.1
+      PmwScrolledCanvas._setRegion.  If there are no objects in the
+      canvas, then error occurs on len(region) because region is None. 
+      Below is an attempt to fix it.  Click on Show, then on Delete. 
+      The window then continuously resizes.  If the ScrolledCanvas is
+      created with canvasmargin = 0, the problem goes away.  (Reported
+      by Anders Henja.)</p>
+<dl><dd><pre> import Tkinter
+ import Pmw
+ def _setRegion(self):
+     # Attempt to fix PmwScrolledCanvas._setRegion.
+     self.setregionTimer = None
+     region = self._canvas.bbox('all')
+     canvasmargin = self['canvasmargin']
+     if region is None:
+         region = (0, 0, 0, 0)
+     region = (region[0] - canvasmargin, region[1] - canvasmargin,
+         region[2] + canvasmargin, region[3] + canvasmargin)
+     self._canvas.configure(scrollregion = region)
+ def show():
+     canvas.component('canvas').delete('all')
+     canvas.create_oval(0, 0, 800, 600, fill = 'red')
+     canvas.configure(canvas_width = 600, canvas_height = 450)
+     canvas.resizescrollregion()
+ def delete():
+     canvas.component('canvas').delete('all')
+     canvas.configure(canvas_width = 0, canvas_height = 0)
+     canvas.resizescrollregion()
+ root=Tkinter.Tk()
+ Pmw.initialise(root)
+ buttonbox=Pmw.ButtonBox()
+ buttonbox.pack(fill='x',side='bottom',padx=5,pady=5)
+ buttonbox.add('Show',command=show)
+ buttonbox.add('Delete',command=delete)
+ buttonbox.alignbuttons()
+ canvas=Pmw.ScrolledCanvas(canvasmargin=2)
+ canvas.__class__._setRegion = _setRegion
+ canvas.pack(fill='both',side='right',expand=1)
+ root.mainloop()</pre></dd></dl>
+
+
+</li>
+<li><p>Bug in Pmw.Dialog:  if <strong>defaultbutton</strong> is configured before
+      <strong>buttons</strong> during <strong>self.initialiseoptions()</strong> (that is if
+      <strong>self._constructorKeywords.keys()</strong> returns a different order),
+      then <strong>setdefault()</strong> fails.</p>
+
+</li>
+<li><p>Bugs in Tk which affect Pmw.MainMenuBar:</p>
+<ul><li><p>Extra bindings assigned to a Tkinter.Menu widget using
+          bindtags have no effect.  Hence the method used in
+          Pmw.MenuBar for status help (bind_class followed by
+          bindtags) does not work and therefore binding to the menu
+          widget is used instead.</p>
+
+</li>
+<li><p>The <strong>'active'</strong> tag for the <code>index()</code> method of Tkinter.Menu
+          always returns <strong>None</strong>.  Hence, in the menu widget motion
+          binding, <code>event.y</code> and the <strong>'@'</strong> format is used instead, for
+          all menus except the toplevel main menu.</p>
+
+</li>
+<li><p>For the toplevel main menu, <code>event.x</code> must be used for the
+          <code>index()</code> method, but it returns the wrong index.  It
+          appears that the Tk widget is assuming vertical layout
+          to calculate distances, rather than horizontal.</p>
+
+</li>
+<li><p>For toplevel main menus, several Tk commands, such as
+          <code>winfo_height()</code>, do not work.  This prevents the use of
+          balloon help for Pmw.MainMenuBar.</p>
+
+</li></ul>
+
+</li>
+<li><p>Bug in Pmw.ComboBox:  Tab to combobox arrow, use up/down arrow
+     keys to change selection, hit return, nothing happens, &lt;Shift
+     Tab&gt; to entry window, hit return, combobox changes</p>
+<ul><li><p>actually, it would be better if you could not tab to
+          the arrow, only the entry field, like the Pmw.Counter.</p>
+
+</li>
+<li><p>the problem is if the entry field is not editable, what to
+          do then?</p>
+
+</li></ul>
+
+</li>
+<li><p>Bug in TimeCounter: Arrow keys don't work when focus is on entry.</p>
+
+</li>
+<li><p>Bug in Pmw.NoteBook: The size of the tab does not change when
+    the text value changes</p>
+
+</li>
+<li><p>Bug in Pmw.NoteBook: The name of the tab components has a "-" sign
+    in it, which means that component options can not be used in the
+    configure command. Eg:</p>
+<dl><dd><pre> n = Pmw.NoteBook()
+ p = n.add('page1')
+ n.configure(page1_background = 'red')   # works
+ n.configure(page1-tab_background = 'red')   # fail, must do this:
+ n.component('page1-tab').configure(background = 'red')   # works</pre></dd></dl>
+
+
+</li></ul>
+<p></p>
+
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/changes.html b/Pmw/Pmw_1_2/doc/changes.html
new file mode 100644 (file)
index 0000000..f3dd640
--- /dev/null
@@ -0,0 +1,1741 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Changes to Pmw</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Changes to Pmw</h1>
+    
+<p>
+  6 January 1997</p>
+
+<ul><li><p>Release of version 0.1</p>
+
+</li></ul>
+<p>  14 February 1997</p>
+
+<ul><li><p>Fixed bug in Counter demo for the Macintosh - the maximum size of an
+    integer is smaller than the value returned by time.time().</p>
+
+</li>
+<li><p>Fixed bug in Grid demo for Tk 4.2 - grid_bbox returns garbage if it is
+    called without update_idletasks.  Also, grid_bbox can only have two
+    arguments in Tk 4.1.</p>
+
+</li>
+<li><p>Modified ScrolledText demo so that the text widget contains enough text
+    to require a vertical scrollbar.</p>
+
+</li>
+<li><p>Changes to PmwBase:</p>
+<ul><li><p>Prefixed the name of several private variables with a double underscore.</p>
+
+</li>
+<li><p>Added symbolic constants for the indexes into an optionInfo list.</p>
+
+</li>
+<li><p>Changed names of several methods and variables to be more descriptive.</p>
+
+</li>
+<li><p>Removed options() method.</p>
+
+</li>
+<li><p>Simplified configuration option data structures.  Modified option
+      handling code so that default options are set correctly.  If an
+      option is created before initialise() is called then initialise()
+      checks if the option is set by the keyword arguments to
+      initialise().  If not, then it is given the value found in the
+      Tk option database, if a value exists, or the default value.  If an
+      option is created after initialise() is called, then it is given the
+      value found in the Tk option database, if a value exists, or the
+      default value.</p>
+
+</li></ul>
+
+</li>
+<li><p>Replaced usage of self._hull in megawidgets by interior() method.</p>
+
+</li>
+<li><p>Added autoclear option to ComboBox.</p>
+
+</li>
+<li><p>Fixed bug in ComboBox - fast clicking on the arrow button could result
+    in an attempt to grab a window that was not yet visible.</p>
+
+</li>
+<li><p>Added "sys.exc_traceback = None" to the except clauses of all try
+    statements so that references to objects in the stack trace would not
+    be left.</p>
+
+</li>
+<li><p>Added takefocus option to PushButton.</p>
+
+</li>
+<li><p>Modified the getcurselection() method of ScrolledListBox so that it
+    returns a string if the selection mode is <strong>'single'</strong> or <strong>'browse'</strong>, rather
+    than a tuple with one element.  This also affects methods forwarded and
+    derived from ScrolledListBox.</p>
+
+</li>
+<li><p>Modified ScrolledListBox so that it avoids unnecessary updates by
+    using idle timer.</p>
+
+</li>
+<li><p>Modified ScrolledText to use grid instead of pack.</p>
+
+</li>
+<li><p>Added shutdown() function to Tk module to clean up all references to
+    the Tcl interpreter and then delete it.</p>
+
+</li>
+<li><p>Fixed bug in Tk module for the Macintosh - update() was being called in
+    initialise() before the Tcl interpreter was created.</p>
+
+</li></ul>
+<p>  14 February 1997</p>
+
+<ul><li><p>Version 0.1.1 completed and released internally.</p>
+
+</li></ul>
+<p>  6 March 1997</p>
+
+<ul><li><p>Pmw now uses the standard Tkinter module.  The Tk module has been
+    dropped.  This means that the Tk module functions such as after,
+    bell, bind, update, etc, are no longer available and the equivalent
+    Tkinter methods should be used.</p>
+
+</li>
+<li><p>To restore some of the features of the Tk module, Pmw.initialise()
+    now adds run-time hooks into Tkinter to get notification of when Tk
+    widgets are created and destroyed.  It also modifies the CallWrapper
+    class so that errors during callbacks and bindings can be displayed
+    in a window.  If Pmw.initialise() is not called, Tkinter is not
+    modified and these features are not available.</p>
+
+</li>
+<li><p>If a Tk widget which is acting as the hull of a megawidget is
+    destroyed, then the megawidget is destroyed as well.  This can
+    only happen if Pmw.initialise() is called.</p>
+
+</li>
+<li><p>Pmw.initialise() now takes the Tkinter root as its argument.</p>
+
+</li>
+<li><p>The parent of megawidgets now defaults to the Tk root.  Previously,
+    the parent of non-toplevel megawidgets had to be given.</p>
+
+</li>
+<li><p>Added PmwBase.tracetk() function to get trace of calls to the Tcl
+    interpreter for debugging.</p>
+
+</li>
+<li><p>Added functions to PmwBase to display a busy cursor over the
+    application such as when a modal dialog is displayed or it is
+    blocked doing a long calculation.  Uses busy command of the blt
+    extension, if present.</p>
+
+</li>
+<li><p>Created a nifty new demo which demonstrates most of the megawidgets
+    in a convenient way.</p>
+
+</li>
+<li><p>Added a TextDialog.</p>
+
+</li>
+<li><p>Added functionality to handle the grabbing of nested modal dialogs
+    correctly.</p>
+
+</li>
+<li><p>Added an activatecommand option to Dialog which allows, for example,
+    the PromptDialog widget to set the keyboard focus when it is
+    activated.</p>
+
+</li>
+<li><p>Added tests for Counter and logicalfont.</p>
+
+</li>
+<li><p>The ScrolledListBox selectioncommand is no longer given the widget
+    as its first argument.</p>
+
+</li>
+<li><p>Several method, function and component names were changed, to be
+    consistent with the coding conventions.</p>
+
+</li>
+<li><p>Some of the effects of moving from the Tk module to Tkinter are:</p>
+<ul><li><p>The Tk module used to exit if there were no non-root toplevel
+      windows shown.  This is no longer the case and so the application
+      must handle this explicitly, particularly if the root window is
+      withdrawn and the last non-root toplevel is deleted by the window
+      manager.</p>
+
+</li>
+<li><p>The Tk module bind functions and methods used to take a noEvent
+      argument to indicate that the Tk event should not be passed to the
+      callback.  Tkinter does not support this.</p>
+
+</li>
+<li><p>The Tk module initialise() function should be replaced by
+      "root = Tkinter.Tk()" and root should be used instead of "Tk.Root()"</p>
+
+</li>
+<li><p>The Tk module quit() function should be replace by "root.destroy()".</p>
+
+</li>
+<li><p>Toplevels are not hidden when created.  To be consistent,
+      MegaToplevels are not hidden either.</p>
+
+</li>
+<li><p>The hide and show methods are not available for Tkinter Toplevels,
+      only MegaToplevels</p>
+
+</li>
+<li><p>There is no grid_configure method.</p>
+
+</li>
+<li><p>Tkinter.Canvas.coords() returns a python list, not a tuple.</p>
+
+</li>
+<li><p>The Tkinter cget and configure widget methods always return
+      strings for the option values.  The Tk module used to convert the
+      string to the appropriate python type (such as string, integer,
+      float, Variable, Image, callback function).</p>
+
+</li>
+<li><p>Tkinter Menu and Toplevel classes incorrectly have a pack method.</p>
+
+</li>
+<li><p>Menu class has no geometry method.</p>
+
+</li>
+<li><p>Canvas focus returns <strong>''</strong> rather than None.</p>
+
+</li>
+<li><p>Text mark_gravity returns <strong>''</strong> rather than None.</p>
+
+</li></ul>
+
+</li></ul>
+<p>  13 March 1997</p>
+
+<ul><li><p>Release of version 0.2</p>
+
+</li></ul>
+<p>  17 March 1997</p>
+
+<ul><li><p>Set default WM_DELETE_WINDOW protocol of Tkinter.Toplevel to
+    destroy() and removed duplicated protocol request from all demos.</p>
+
+</li>
+<li><p>Modified text of ShowBusy demo to indicate that busy cursor will
+    only be seen if the BLT extension is present.</p>
+
+</li>
+<li><p>Replaced call to update() in PmwLabeledWidget.py with update_idletasks().</p>
+
+</li>
+<li><p>Changed name of PromptDialog component from <strong>'entry'</strong> to <strong>'entryfield'</strong>.</p>
+
+</li></ul>
+<p>  28 April 1997</p>
+
+<ul><li><p>Version 0.3 released internally</p>
+
+</li></ul>
+<p>  19 August 1997</p>
+
+<ul><li><p>Many changes made (see the version 0.4 porting guide for
+    more details).</p>
+
+</li>
+<li><p>The option propagation mechanism that iwidgets uses is too
+    cumbersome, too hard to understand and, in python, too slow. 
+    Developed a new mechanism which is more explicit in naming
+    options.  This resulted in most options which were simply
+    propagated to components being removed.  Removed keep(), rename()
+    and ignore() methods and "usual" options.</p>
+
+</li>
+<li><p>For speed, Pmw no longer queries the Tk option database for
+    default values for megawidget options.  Hence, resource names and
+    classes do not need to be supplied when creating options and
+    <strong>None</strong> is returned for the resource name and class when using
+    <code>configure()</code> to query the options.  Option "types" no longer
+    used.</p>
+
+</li>
+<li><p>Changed method and component names to be more consistent.</p>
+
+</li>
+<li><p>Replaced most uses of pack() with grid().</p>
+
+</li>
+<li><p>Megawidgets no longer inherit from LabeledWidget.  Instead they
+    call createlabel() to optionally create the label component.</p>
+
+</li>
+<li><p>Removed child site from EntryField and rewrote ComboBox
+    accordingly.</p>
+
+</li>
+<li><p>Wrote lots more documentation, including automatically generated
+    reference manuals.</p>
+
+</li>
+<li><p>Removed PushButton and rewrote ButtonBox to directly create
+    Tkinter.Buttons rather than PushButtons.</p>
+
+</li>
+<li><p>Added initialisation options - options which can be set at
+    creation time but not later using configure().</p>
+
+</li>
+<li><p>Added aliases for components.</p>
+
+</li>
+<li><p>Modified the base classes so that during option configuration,
+    components are configured <em>before</em> configuration called functions
+    are called.</p>
+
+</li>
+<li><p>Added several more megawidgets.</p>
+
+</li>
+<li><p>Added interface to BLT graph and vector commands.</p>
+
+</li>
+<li><p>Created PmwLazy module for lazy importing of Pmw - avoids loading
+    megawidgets which are not used.</p>
+
+</li>
+<li><p>Added several more functions for handling color and fonts.</p>
+
+</li>
+<li><p>Replaced Counter and EntryField <em>time</em> with <em>timeN</em> and <em>time24</em></p>
+
+</li>
+<li><p>Pmw.initialise() will now create Tkinter.Tk if not given root.</p>
+
+</li></ul>
+<p>  1 September 1997</p>
+
+<ul><li><p>Release of version 0.4</p>
+
+</li></ul>
+<p>  5 September 1997</p>
+
+<ul><li><p>Modified the base classes so that the Tk option database resource
+    class of megawidgets can be overridden in the call to the
+    constructor using the <strong>hull_class</strong> option.</p>
+
+</li>
+<li><p>The separators in Pmw.PanedWidget are now active - they can be
+    grabbed, like the handles, and moved around.  The cursor now
+    changes to the correct left/right or up/down cursor when over a
+    separator or handle.  (Clemens Hintze)</p>
+
+</li>
+<li><p>Fixed bug in MessageInfo demo Dismiss button.  If it is invoked,
+    an error occurs saying "not enough arguments".  (Mark Colclough)</p>
+
+</li></ul>
+<p>  9 September 1997</p>
+
+<ul><li><p>Added the <strong>useTkOptionDb</strong> argument to Pmw.initialise which
+    specifies that the initial values of megawidget options are to be
+    set by querying the Tk option database.</p>
+
+</li>
+<li><p>When used to query options, the configure() method now returns the
+    resource class and name of the options.</p>
+
+</li></ul>
+<p>  19 September 1997</p>
+
+<ul><li><p>Changed functions datestringtoint() and timestringtoint() to
+    datestringtojdn() and timestringtoseconds().  Changed return value
+    of datestringtojdn() to be Julian Day Numbers rather than seconds
+    since the epoch.</p>
+
+</li>
+<li><p>Fixed a bug in the date Counter due to use of time.timezone, by
+    replacing, when calculating date increments, calls to the time
+    module with calls to datestringtojdn().</p>
+
+</li>
+<li><p>Added century pivot year (setyearpivot function) to Counter date
+    datatypes to handle two-digit years.</p>
+
+</li>
+<li><p>Added date_dmy4, date_mdy4 and date_y4md datatypes to Counter.</p>
+
+</li>
+<li><p>Modified demos All.py and ScrolledText.py so that demos can be called
+    from directories other than the demos directory.  (Case Roole and 
+    Guido van Rossum)</p>
+
+</li>
+<li><p>Changed the default for the Pmw.Balloon <em>label_justify</em> option to
+    <em>left</em> to improve appearance of multi-line balloons.  Pmw.Balloon
+    now replaces newlines with spaces in the statusHelp string so that
+    the strings look better when displayed in a Pmw.MessageBar. 
+    (Andreas Kostyrka)</p>
+
+</li>
+<li><p>Pmw.Blt now calls <em>package require BLT</em> when checking for the
+    existence of Blt, so that it can be loaded if it is not statically
+    linked.  (Clemens Hintze, Matthias Klose)</p>
+
+</li>
+<li><p>Copied earthris.gif and flagup.bmp files from Tcl distribution to
+    test directory, just in case they have not been installed. 
+    (Jonathan Kelly)</p>
+
+</li>
+<li><p>Lots of improvements to the documentation and documenting recent
+    changes.</p>
+
+</li></ul>
+<p>  16 October 1997</p>
+
+<ul><li><p>Modified Pmw.Balloon and Pmw.ComboBox to work around a bug in the
+    Windows95 version of Tk which caused the popup windows to appear
+    in the wrong place.  (Fredrik Lundh and Jerome Gay)</p>
+
+</li>
+<li><p>Added Pmw.maxfontwidth() function. (Rob Pearson)</p>
+
+</li></ul>
+<p>  24 October 1997</p>
+
+<ul><li><p>Changed PmwBase._reporterror to handle the class exceptions of
+    python 1.5.  (Case Roole)</p>
+
+</li></ul>
+<p>  29 October 1997</p>
+
+<ul><li><p>Fixed a bug in forwardmethods() function which occurred if the
+    <em>toClass</em> class had a method called <strong>type</strong>.</p>
+
+</li></ul>
+<p>  7 November 1997</p>
+
+<ul><li><p>Changed tests/Test._getErrorValue to handle the class exceptions of
+    python 1.5.  (Michael McLay)</p>
+
+</li>
+<li><p>Changed bug fix in forwardmethods() function to use the
+    <code>exec execString in d</code> construct. (Guido van Rossum)</p>
+
+</li>
+<li><p>Can now use Pmw.MegaArchetype as a base class just to get option
+    handling; it will not create the hull component unless requested. 
+    Moved __str__() and interior() methods from Pmw.MegaToplevel and
+    Pmw.MegaWidget to Pmw.MegaArchetype class.</p>
+
+</li></ul>
+<p>  10 November 1997</p>
+
+<ul><li><p>Added <em>textclass</em> option to Pmw.ScrolledText and <em>listboxclass</em>
+    option for Pmw.ScrolledListBox to allow embedding of custom
+    widgets.</p>
+
+</li>
+<li><p>Added Mitch Chapman's <strong>FontText</strong> module to the <code>demos</code> directory
+    and used it to display the demo source code in color.</p>
+
+</li>
+<li><p>Added two notebook megawwidgets, Pmw.NoteBookR and Pmw.NoteBookS. 
+    (Case Roole and Joe Saltiel)</p>
+
+</li>
+<li><p>Added Pmw.ScrolledCanvas megawidget. (Joe Saltiel)</p>
+
+</li>
+<li><p>Added Pmw.TreeBrowse megawidget. (Michael McLay)</p>
+
+</li>
+<li><p>Added Pmw.Group megawidget and modified to use <code>grid()</code> instead
+    of <code>pack()</code>. (Case Roole)</p>
+
+</li>
+<li><p>Release of version 0.5</p>
+
+</li></ul>
+<p>  12 November 1997</p>
+
+<ul><li><p>Added <em>pyclass</em> option to components and removed <em>textclass</em>
+    option from Pmw.ScrolledText and <em>listboxclass</em> option from
+    Pmw.ScrolledListBox.  (Suggested by Shen Wang)</p>
+
+</li>
+<li><p>Added label component to Pmw.ButtonBox megawidget.</p>
+
+</li>
+<li><p>Fixed mis-spelling of PmwTreeBrowse in Pmw.py.</p>
+
+</li>
+<li><p>Release of version 0.5.1</p>
+
+</li></ul>
+<p>  5 December 1997</p>
+
+<ul><li><p>The pyclass option can now be None.  If so, createcomponent
+    returns None.</p>
+
+</li>
+<li><p>Removed tagtype option from Pmw.Group.  Can now use the more
+    general tag_pyclass instead.</p>
+
+</li>
+<li><p>Added tcl call to <code>load {} Blt</code> when testing for presence of Blt.</p>
+
+</li>
+<li><p>Added julian and papal options to Pmw.ymdtojulian and
+    Pmw.juliantoymd functions and made sure divisions give the same
+    result as C even when operands are negative.</p>
+
+</li>
+<li><p>Exported ymdtojulian and juliantoymd functions.</p>
+
+</li>
+<li><p>Fixed bug in activate method.  Did not prepend TclError with Tkinter.</p>
+
+</li>
+<li><p>When the Blt busy hold command is called from showbusycursor, the
+    bindtags on the busy window are set so that no events cause
+    callbacks to occur for the toplevel or all bindings.  Also, while
+    a busy window is up, the focus is changed to the busy window so
+    that no keyboard events are accepted.  This fixes a bug where the
+    Tkinter._nametowidget function could crash with a <code>KeyError: _Busy</code>
+    if there was a binding on a toplevel window and the mouse
+    was pressed while the busy cursor was up.</p>
+
+</li></ul>
+<p>  9 December 1997</p>
+
+<ul><li><p>Fixed bug in Pmw.datestringtojdn() when dealing with century year,
+    such as 2000.</p>
+
+</li></ul>
+<p>  10 December 1997</p>
+
+<ul><li><p>Added <em>where</em> option to <code>Pmw.ScrolledText.importfile()</code>.  (Graham
+    Matthews)</p>
+
+</li></ul>
+<p>  16 December 1997</p>
+
+<ul><li><p>Modified Pmw.RadioSelect and Pmw.ButtonBox so that you can no
+    longer index their buttons using regular expressions.  This
+    feature seemed to have little use and caused problems with buttons
+    labeled for example <em>a*</em> and <em>b*</em>.  (Problem reported by Rob
+    Hooft)</p>
+
+</li>
+<li><p>Added updateFunction option to Pmw.busycallback().  If set, the
+    function will be called just after the command given to
+    Pmw.busycallback().  If the function is set the Tkinter update()
+    method, then this will clear any events that may have occurred
+    while the command was executing.</p>
+
+</li></ul>
+<p>  30 December 1997</p>
+
+<ul><li><p>Changed ymdtojulian and juliantoymd functions to jdntoymd and
+    ymdtojdn, because the meaning of "julian" is ambiguous, whereas
+    the meaning of "Julian Day Number" is not (maybe).</p>
+
+</li>
+<li><p>Converted Pmw to use python 1.5 package mechanism.  (Michael McLay
+    and Case Roole)</p>
+
+</li>
+<li><p>Removed Pmw.py and PmwLazy files.  Added __init__.py, PmwLoader.py
+    and Pmw.def files.  (Case Roole)</p>
+
+</li>
+<li><p>Applications can now specify at runtime which version of Pmw to
+    use and also which alpha versions, if any.  (Case Roole)</p>
+
+</li>
+<li><p>Modified Pmw code for the version of Tkinter released with python
+    1.5.</p>
+
+</li>
+<li><p>Release of version 0.6</p>
+
+</li></ul>
+<p>  5 January 1998</p>
+
+<ul><li><p>Fixed alpha version handling so that alpha versions do not have to
+    supply PmwBase.py and PmwUtils.py.  (Case Roole)</p>
+
+</li>
+<li><p>Added example alpha directory and documentation.  (Case Roole)</p>
+
+</li></ul>
+<p>  7 January 1998</p>
+
+<ul><li><p>Added selectmode option to Pmw.RadioSelect megawidget.  (Roman
+    Sulzhyk)</p>
+
+</li>
+<li><p>Added some changes to Pmw.ScrolledCanvas to get around some bugs. 
+    (Joe Saltiel)</p>
+
+</li>
+<li><p>Release of version 0.6.1</p>
+
+</li></ul>
+<p>  8 January 1998</p>
+
+<ul><li><p>Added some more changes to Pmw.ScrolledCanvas.  (from Joe Saltiel)</p>
+
+</li></ul>
+<p>  12 January 1998</p>
+
+<ul><li><p>Added Pmw.OptionMenu megawidget. (Roman Sulzhyk)</p>
+
+</li></ul>
+<p>  20 February 1998</p>
+
+<ul><li><p>Added new Pmw.MenuBar features to delete menus and menuitems,
+    enable and disable menu bar and to add cascade menus.  (Rob Pearson)</p>
+
+</li>
+<li><p>Added extra arguments to Pmw.Color.spectrum for more control over
+    color choice.</p>
+
+</li></ul>
+<p>  23 February 1998</p>
+
+<ul><li><p>Added canvasbind() method to Pmw.Balloon.</p>
+
+</li>
+<li><p>Fixed demos/All.py so that it will correctly determine which Pmw
+    version to use even if it is in a directory symlinked to the demos
+    directory.</p>
+
+</li>
+<li><p>Removed "import DemoVersion" from all demos, except All.py, so
+    that they will work unchanged when copied outside of the Pmw
+    distribution.</p>
+
+</li>
+<li><p>Release of version 0.6.2</p>
+
+</li></ul>
+<p>  26 February 1998</p>
+
+<ul><li><p>Fixed PmwLoader so that it works on Macintoshes.  (Jack Jansen)</p>
+
+</li></ul>
+<p>  2 March 1998</p>
+
+<ul><li><p>Fixed PmwBase and PmwBlt so that an attempt is made to dynamically
+    load Blt before it is used.  Previously only attempted to load Blt
+    when calling showbusycursor.</p>
+
+</li></ul>
+<p>  16 March 1998</p>
+
+<ul><li><p>Added hulldestroyed() method.</p>
+
+</li>
+<li><p>Modified displayerror() function to use value given to
+    reporterrorstofile() if it is set.</p>
+
+</li>
+<li><p>Fixed bug in Pmw.EntryField which occurred when the <em>command</em>
+    option destroyed the megawidget.</p>
+
+</li>
+<li><p>Pmw.EntryField invoke method now passes on the value returned by
+    the <em>command</em> function.</p>
+
+</li></ul>
+<p>  3 April 1998</p>
+
+<ul><li><p>Added Pmw.ScrolledFrame megawidget.  (Joe Saltiel)</p>
+
+</li>
+<li><p>Color.rgb2hsi() now uses the built-in <code>min()</code> and <code>max()</code> functions.</p>
+
+</li></ul>
+<p>  20 April 1998</p>
+
+<ul><li><p>Moved time and date functions from PmwCounter.py to new file,
+    PmwTimeFuncs.py.</p>
+
+</li>
+<li><p>Added optional <em>separator</em> argument to <code>timestringtoseconds</code> and
+    <code>datestringtojdn</code> functions.  These functions are now stricter
+    when checking if a string is a valid date or time.  For example,
+    it now checks for correct day in month, month in year, etc.  These
+    changes also affect the Pmw.Counter date and time validators.</p>
+
+</li>
+<li><p>The <code>datestringtojdn</code> function now accepts all combinations of
+    <strong>'d'</strong>, <strong>'m'</strong>, <strong>'y'</strong> as format string.</p>
+
+</li>
+<li><p>Moved functions to bottom of file and class to top of file in
+    PmwEntryField.py and PmwCounter.py.</p>
+
+</li>
+<li><p>The validation for Pmw.EntryField <em>integer</em>, <em>hexadecimal</em> and
+    <em>real</em> types now use string.atol or string.atof rather than
+    regular expressions.</p>
+
+</li>
+<li><p>The validation for the Pmw.EntryField <em>real</em> type accepts a
+    <em>separator</em> argument, for those who prefer a comma instead of a
+    full stop/period/point as the decimal dividing symbol.</p>
+
+</li>
+<li><p>The Pmw.EntryField <em>time*</em> and <em>date_*</em> validators have been
+    removed.  The functionality can be replaced by using the new
+    <em>time</em> and <em>date</em> validators with <em>min</em> and <em>max</em> fields.</p>
+
+</li>
+<li><p>The Pmw.EntryField <em>maxwidth</em> option has been removed.  The
+    functionality can be replaced by using the <em>max</em> field of the
+    validator.</p>
+
+</li>
+<li><p>Added an <em>extravalidators</em> option to Pmw.EntryField.  This allows
+    new types of validation to be added, particularly in classes
+    derived from Pmw.EntryField.  It also allows the use of different
+    names for the same validation, by using aliases.  Added
+    SpecialEntry demo to show <em>extravalidators</em> option, based on work
+    by Joachim Schmitz.</p>
+
+</li>
+<li><p>Fixed a bug in Pmw.EntryField when combining use of <em>value</em> and
+    <em>entry_textvariable</em> options.</p>
+
+</li>
+<li><p>The Pmw.EntryField <em>validate</em> option now also accepts a dictionary
+    to handle minimum and maximum validation and to allow the passing
+    of other arguments to the validating functions, such as date, time
+    and number formats and separators.</p>
+
+</li>
+<li><p>Fixed bug in Pmw.EntryField where the entry would scroll to the
+    start of the text if an invalid character was typed.</p>
+
+</li>
+<li><p>Added checkentry() method to Pmw.EntryField, so that it can be
+    updated if the entry widget is tied to a textvariable.</p>
+
+</li></ul>
+<p>  10 May 1998</p>
+
+<ul><li><p>The activate() method now takes a geometry option to allow more
+    flexible positioning of the modal dialog.</p>
+
+</li>
+<li><p>Fixed rarely occurring bug in deactivate() method if it is called
+    (perhaps from a timer) during the call to wait_visibility() in the
+    activate() method.  This bug used to generate an error and the
+    application would not exit properly.</p>
+
+</li>
+<li><p>Fixed another rarely occurring bug in deactivate() method if it is
+    called while another application has the grab.</p>
+
+</li>
+<li><p>Removed "sys.exc_traceback = None" for except clauses which used
+    to be required by python 1.4 so that references to objects in the
+    stack trace would not be left.</p>
+
+</li>
+<li><p>Now uses sys.exc_info() function when displaying exception
+    traceback.</p>
+
+</li>
+<li><p>The <strong>state</strong> option of Pmw.Balloon and the <strong>orient</strong> option of
+    several others now generate an exception if they have a bad value.</p>
+
+</li>
+<li><p>Added a deactivatecommand option to Pmw.MegaToplevel which can be
+    used, for example, to cancel timers.</p>
+
+</li>
+<li><p>Made changes to Pmw.Counter so that the entry display continuously
+    changes when arrow key presses are repeated quickly.</p>
+
+</li>
+<li><p>Made changes to Pmw.Counter so that the insertion cursor is maintained
+    while counting and the entry scrolls to the end if the value is long.</p>
+
+</li>
+<li><p>Pmw.Counter now behaves correctly when counting past the maximum
+    and minimum values of the EntryField.</p>
+
+</li></ul>
+<p>  28 May 1998</p>
+
+<ul><li><p>Made all Pmw.EntryField standard validators publicly available
+    as <code>Pmw.numericvalidator</code>, etc.</p>
+
+</li>
+<li><p>Now uses faster <code>string.replace()</code> instead of <code>regsub.gsub()</code> when
+    applicable.</p>
+
+</li>
+<li><p>If the <em>balloonHelp</em> argument of the Pmw.Balloon bind methods is
+    <strong>None</strong>, no balloon is displayed.</p>
+
+</li>
+<li><p>Merged the code from the PmwUtils module (forwardmethods()) into
+    PmwBase, since it was always used, was used nowhere else, and made
+    freezing a little more complicated.</p>
+
+</li>
+<li><p>Added a short delay between calling Tkinter bell() method (sounds nicer).</p>
+
+</li>
+<li><p>The functions <code>datestringtojdn()</code> and <code>timestringtoseconds()</code> now
+    return ValueError on invalid input.</p>
+
+</li>
+<li><p>Created bundlepmw.py, to help when freezing in Pmw.  Placed in bin
+    directory.</p>
+
+</li></ul>
+<p>  29 May 1998</p>
+
+<ul><li><p>Fixed rare bug in Pmw.Counter which occured if the counter was
+    unmapped while the mouse button was held down over an arrow button.</p>
+
+</li>
+<li><p>Created contrib directory and placed PmwVerticalGuage.py in it. 
+    (Chris Wright)</p>
+
+</li>
+<li><p>Patched PmwNoteBookR.py.  (Siggy Brentrup)</p>
+
+</li>
+<li><p>Added addoptions() method to Pmw.MegaArchetype class. (Dieter Maurer)</p>
+
+</li>
+<li><p>By default, MenuBar creates hotkeys for menus and menu items for
+    keyboard traversal.  Added traversSpec argument to MenuBar add
+    methods.  (Michael McLay)</p>
+
+</li></ul>
+<p>  31 May 1998</p>
+
+<ul><li><p>Cleaned up bbox() methods in Pmw.ScrolledCanvas and
+    Pmw.ScrolledListBox.</p>
+
+</li>
+<li><p>The createcomponent() method now disallows the creation of
+    component names containing an underscore, since the query
+    functions would not be able to find them.</p>
+
+</li></ul>
+<p>  2 June 1998</p>
+
+<ul><li><p>Release of version 0.7</p>
+
+</li></ul>
+<p>  3 June 1998</p>
+
+<ul><li><p>Moved Pmw.TreeBrowse megawidget to contrib directory.</p>
+
+</li></ul>
+<p>  17 June 1998</p>
+
+<ul><li><p>Added PmwFullTimeCounter.py to contrib directory (Daniel Michelson)</p>
+
+</li></ul>
+<p>  1 July 1998</p>
+
+<ul><li><p>Changed mispelt file PmwVerticalGuage.py to PmwVerticalGauge.py
+    in contrib directory.</p>
+
+</li></ul>
+<p>  7 July 1998</p>
+
+<ul><li><p>Fixed bug in Pmw.Counter real datatype.  Sometimes incorrectly
+    counted negative decimal fractions.  (Reported by David Ascher)</p>
+
+</li></ul>
+<p>  12 July 1998</p>
+
+<ul><li><p>The <em>format</em> argument of Pmw.datestringtojdn() now defaults to
+    <strong>'ymd'</strong>.</p>
+
+</li>
+<li><p>Removed Tkinter_test.py from tests since it does not test any Pmw
+    functionality (only Tkinter) and it fails under MS-Windows 95.</p>
+
+</li></ul>
+<p>  23 August 1998</p>
+
+<ul><li><p>Changed several exception types to be more consistent.</p>
+
+</li>
+<li><p>Made the interface to Pmw.Blt.Vector more like the builtin python
+    list type.</p>
+
+</li>
+<li><p>It is no longer an error to call Pmw.setversion() or
+    Pmw.setalphaversions() after initialisation, as long as the
+    requested version matches the actual version.</p>
+
+</li>
+<li><p>Fixed Pmw.NoteBookR so that it behaves better when the
+    highlightthickness is changed.</p>
+
+</li>
+<li><p>The setyearpivot() function now returns a tuple containing the old
+    values of <em>pivot</em> and <em>century</em>.</p>
+
+</li>
+<li><p>Added PmwFileDialog.py to contrib directory (Rob Hooft)</p>
+
+</li>
+<li><p>Modified demos so that full tracebacks are displayed if an error
+    occurs when importing a module.</p>
+
+</li>
+<li><p>Removed justify() method from Pmw.ScrolledListBox, since it is
+    just a wrapper around the xview and yview methods of the listbox. 
+    Also, it was not a permanent justification, as the name implied.</p>
+
+</li></ul>
+<p>  20 September 1998</p>
+
+<ul><li><p>Changed implementation of Pmw.ScrolledCanvas.</p>
+
+</li>
+<li><p>Added <strong>borderframe</strong> option to Pmw.ScrolledText and Pmw.ScrolledCanvas.</p>
+
+</li></ul>
+<p>  18 October 1998</p>
+
+<ul><li><p>Major overhaul of all scrolled widgets.  Modified all to use
+    similar structure, given the peculiarities of each.  Fixed several
+    subtle bugs.</p>
+
+</li>
+<li><p>Pmw.ScrolledFrame: now uses a frame positioned within a clipping
+    frame using the place geometry manager.  Added borderframe,
+    horizflex, horizfraction, usehullsize, vertflex, vertfraction
+    options.  Added reposition() method.  Removed getFrame() method;
+    use interior() method instead.</p>
+
+</li>
+<li><p>Pmw.ScrolledListBox: added usehullsize option.</p>
+
+</li>
+<li><p>Pmw.ScrolledText: added borderframe and usehullsize options.</p>
+
+</li>
+<li><p>Pmw.ScrolledCanvas:  simplified widget structure.  Added
+    borderframe, canvasmargin, scrollmargin and usehullsize options. 
+    Added label.</p>
+
+</li>
+<li><p>Modified Pmw.OptionMenu to use standard widgets rather than call
+    tcl procedure.  Added <strong>initialitem</strong> option.  Now handles
+    <strong>menubutton_textvariable</strong> component option correctly.</p>
+
+</li></ul>
+<p>  1 November 1998</p>
+
+<ul><li><p>Documented more Pmw functions and Pmw.ComboBox.</p>
+
+</li></ul>
+<p>  15 November 1998</p>
+
+<ul><li><p>Fixed some bugs, cleaned up code and wrote documentation for
+    Pmw.Group.  Removed <strong>ringpadx</strong> and <strong>ringpady</strong> options, since this
+    functionality is more generally available by padding the
+    megawidget itself and by padding the children of the megawidget. 
+    Modified Pmw.aligngrouptags so that it takes into account the
+    borderwidth and highlightthickness of the ring and so that it
+    works when there is no tag widget.  Added <strong>tagindent</strong> option.</p>
+
+</li></ul>
+<p>  18 November 1998</p>
+
+<ul><li><p>Renamed canvasbind() and canvasunbind() methods of Pmw.Balloon to
+    tagbind() and tagunbind() and modified so that they work with both
+    Tkinter.Canvas items and Tkinter.Text tagged items.</p>
+
+</li></ul>
+<p>  19 November 1998</p>
+
+<ul><li><p>Added havebltbusy() method to Pmw.Blt. (Robin Becker)</p>
+
+</li></ul>
+<p>  21 November 1998</p>
+
+<ul><li><p>Modified contrib/PmwFileDialog.py so that when a file is selected
+    with the mouse, the highlight (in the file list) persists and the
+    file list does not scroll to the top. (Rob Hooft)</p>
+
+</li>
+<li><p>Modified Pmw.Balloon so that it can be bound to a tag associated
+    with several Canvas or Text items.  (Magnus Kessler)</p>
+
+</li></ul>
+<p>  21 November 1998</p>
+
+<ul><li><p>Cleaned up appearance and colors of Pmw.NoteBookR tabs.  (Georg
+    Mischler)</p>
+
+</li>
+<li><p>Added <strong>buttontype</strong> option to Pmw.RadioSelect to support
+    radiobuttons and checkbuttons.  (Georg Mischler)</p>
+
+</li></ul>
+<p>  23 November 1998</p>
+
+<ul><li><p>Updated usage of <code>bind_class(tag)</code> due to change in return value
+    in Tkinter module in python 1.5.2.  (Magnus Kessler, Fredrik Lundh)</p>
+
+</li>
+<li><p>The default time displayed in Pmw.TimeCounter is now the current
+    local time, not GMT as before.</p>
+
+</li>
+<li><p>The times displayed in the Counter demonstration are now the
+    current local time, not GMT as before.</p>
+
+</li></ul>
+<p>  7 December 1998</p>
+
+<ul><li><p>Modified Pmw.ComboBox to take advantage of the fix to the Tkinter
+    <code>bind()</code> method callback handling of <code>Event.widget</code> in python
+    1.5.2.  It works even if the <strong>selectioncommand</strong> destroys the
+    combobox.  For simple comboboxes, the invoke() method now returns
+    the return value of the <strong>selectioncommand</strong>.</p>
+
+</li>
+<li><p>Modified Pmw.EntryField to take advantage of the fix to the
+    Tkinter <code>bind()</code> method callback handling of <code>Event.widget</code> in
+    python 1.5.2.  It works even if a user-supplied callback
+    (<strong>command</strong>, <strong>invalidcommand</strong>, <strong>validator</strong> or <strong>stringtovalue</strong>)
+    destroys the entryfield.  Cleans up correctly when destroyed.  The
+    invoke() method now returns the return value of the <strong>command</strong>.</p>
+
+</li>
+<li><p>The invoke() method of Pmw.TimeCounter now returns the return
+    value of the <strong>command</strong>.</p>
+
+</li>
+<li><p>Modified Pmw.ButtonBox to use the new (in Tk8.0) <strong>default</strong> option
+    of the Tkinter <strong>Button</strong> widget instead of a separate frame. 
+    Changed default padding to be more compact.  Removed "ring" frame
+    component and "ringborderwidth", "ringpadx" and "ringpady"
+    options.  (Georg Mischler)</p>
+
+</li>
+<li><p>Changed <strong>'pmw1'</strong> fontScheme to set default fonts only when running
+    under posix, since the default fonts on other systems look better.</p>
+
+</li></ul>
+<p>  10 December 1998</p>
+
+<ul><li><p>Release of version 0.8</p>
+
+</li></ul>
+<p>  20 January 1999</p>
+
+<ul><li><p>Added <strong>master</strong> option to Pmw.MegaToplevel and removed <strong>master</strong>
+    argument from the activate method.</p>
+
+</li>
+<li><p>Replaced rand module in demos with a simple random number
+    generator (since rand is not built-in on all versions of python).</p>
+
+</li></ul>
+<p>  22 February 1999</p>
+
+<ul><li><p>Modified <code>__init__.py</code> so that it only accepts directories whose
+    names begin with <strong>Pmw_M_N</strong> and which have a /lib/PmwLoader.py/
+    file.</p>
+
+</li></ul>
+<p>  13 May 1999</p>
+
+<ul><li><p>Changed Pmw.ScrolledCanvas, Pmw.ScrolledText and Pmw.ScrolledListBox
+    to speed up scrolling if the scrollmodes are not both dynamic.</p>
+
+</li>
+<li><p>Changed busy cursor and activate/deactivate code so that it works
+    correctly under fast mouse clicking or fast keyboarding (using
+    accelerators).  Also fixed so that grab is correctly restored
+    after a Pmw.ComboBox popup list is unmapped inside a modal dialog. 
+    (Clemens Hintze)</p>
+
+</li>
+<li><p>Several dialogs now give focus to one of their components (listbox
+    or entry widget) when activated.  (Clemens Hintze)</p>
+
+</li>
+<li><p>Fixed Pmw.ComboBox so that it unposts popup if the combobox is
+    unmapped and returns grab and focus correctly if destroyed.</p>
+
+</li>
+<li><p>Improved tracetk() output to be more readable.  Also displays
+    nested calls to the Tk mainloop better and shows callbacks from
+    tcl to python.</p>
+
+</li>
+<li><p>Upgraded Blt support to blt2.4i.  Graph widget is not backwards
+    compatible with blt2.1.</p>
+
+</li></ul>
+<p>  19 May 1999</p>
+
+<ul><li><p>Fixed bug in Pmw.Balloon in placement of balloons over canvas
+    items when the canvas was scrolled. (Tessa Lau)</p>
+
+</li></ul>
+<p>  20 May 1999</p>
+
+<ul><li><p>Added new Tk event types (new in Tk 8.0 and 8.0.5) to PmwBase
+    error display method.  Also added check for unknown event types to
+    safeguard against future changes.  (Magnus Kessler)</p>
+
+</li>
+<li><p>Added <strong>exclude</strong> argument to <code>showbusycursor()</code>.  (Rob Hooft)</p>
+
+</li></ul>
+<p>  1 June 1999</p>
+
+<ul><li><p>Added wrappers for Blt Stripchart and Tabset widgets.  (Nick Belshaw)</p>
+
+</li>
+<li><p>Changed createcomponent() so that arguments to the constructor of
+    the component can now be specified as either multiple trailing
+    arguments to createcomponent() or as a single tuple argument.</p>
+
+</li></ul>
+<p>  7 June 1999</p>
+
+<ul><li><p>Added call to update_idletasks() in Pmw.ScrolledCanvas,
+    Pmw.ScrolledFrame, Pmw.ScrolledText and Pmw.ScrolledListBox to
+    avoid endless mapping/unmapping of two dynamic scrollbars when the
+    window is first mapped and only one scrollbar is needed.
+    (Reported by Mark C Favas, solution suggested by Dieter Maurer.)</p>
+
+</li></ul>
+<p>  10 June 1999</p>
+
+<ul><li><p>Fixed bug in bundlepmw.py when called with -noblt option. 
+    (Reported by Kevin O'Connor)</p>
+
+</li>
+<li><p>Pmw.ComboBox now unposts the dropdown listbox before the selection
+    callback is invoked, to avoid problems when the callback takes a
+    long time to run.  (Reported by Randall Hopper)</p>
+
+</li></ul>
+<p>  11 June 1999</p>
+
+<ul><li><p>Release of version 0.8.1</p>
+
+</li></ul>
+<p>  29 June 1999</p>
+
+<ul><li><p>PmwMessageBar.message() now replaces newlines with spaces before
+    displaying message.  Also applies to helpmessage().</p>
+
+</li></ul>
+<p>  2 July 1999</p>
+
+<ul><li><p>Improved toplevel window positioning under NT, and stopped most of
+    the ugly flashing.</p>
+
+</li></ul>
+<p>  5 July 1999</p>
+
+<ul><li><p>The <strong>pmw1</strong> fontScheme is now supported under NT, as is the <em>size</em>
+    option to <code>Pmw.initialise()</code>.</p>
+
+</li></ul>
+<p>  6 July 1999</p>
+
+<ul><li><p>Changed the names of positional arguments in the following
+    methods, so that they have less chance of conflicting with keyword
+    arguments:  MegaArchetype.createcomponent(), ButtonBox.insert(),
+    ButtonBox.add(), MenuBar.addcascademenu(), MenuBar.addmenuitem()
+    and RadioSelect.add().</p>
+
+</li></ul>
+<p>  9 July 1999</p>
+
+<ul><li><p>Added images and example code to the megawidget reference manuals.
+    (Suggested by Joerg Henrichs)</p>
+
+</li>
+<li><p>Fixed showbusycursor() under NT.  It now calls update() instead of
+    update_idletasks() to force display of cursor.  (Solution
+    suggested by George Howlett)</p>
+
+</li>
+<li><p>Improved display of arrows in ComboBox, Counter and TimeCounter.</p>
+
+</li></ul>
+<p>  16 July 1999</p>
+
+<ul><li><p>Removed Pmw.maxfontwidth() function, since better functionality is
+    now supplied by the Tk "font measure" command.</p>
+
+</li>
+<li><p>Removed Pmw.fontexists() function, since in Tk8.0 all fonts exist.</p>
+
+</li></ul>
+<p>  28 July 1999</p>
+
+<ul><li><p>Fixed bug in date counter with separator other than <strong>'/'</strong> and time
+    counter with separator other than <strong>':'</strong>.  (David M.  Cooke, Alan
+    Robinson)</p>
+
+</li>
+<li><p>Under NT, the font named <strong>'fixed'</strong> is not fixed width, so added
+    alias from <strong>'Fixed'</strong> to <strong>'Courier'</strong>.</p>
+
+</li>
+<li><p>Changed the <code>bind()</code> and <code>tagbind()</code> methods of Pmw.Balloon to
+    remove a potential memory leak.  The methods now store the
+    <em>funcids</em> of the callback functions, so that if the same widget or
+    tag is bound twice, the balloon can remove the old bindings. 
+    (Peter Stoehr)</p>
+
+</li>
+<li><p>Changed NoteBookR so that lowercmd, creatcmd and raisecmd are
+    called in that order when a page is selected.  Also fixed bug
+    which always raised page 0 when notebook is resized.  (Scott
+    Evans, Charles Choi)</p>
+
+</li></ul>
+<p>  1 August 1999</p>
+
+<ul><li><p>Added <strong>dynamicGroups</strong> argument to <code>defineoptions()</code> method and
+    modified ButtonBox, MenuBar, PanedWidget, RadioSelect to register
+    their dynamic groups.</p>
+
+</li>
+<li><p><code>Pmw.initialise()</code> can now be called multiple times, with
+    different <em>root</em> arguments, but only sequentially.  Pmw does not
+    (yet) support multiple simultaneous interpreters.  Modified
+    Pmw.EntryField so that it recreates class bindings when
+    Tkinter.root changes.</p>
+
+</li></ul>
+<p>  4 August 1999</p>
+
+<ul><li><p>Added relmouse option to Pmw.Balloon.  Fixed Pmw.Balloon so that
+    the balloon is not displayed off-screen.  (Tessa Lau)</p>
+
+</li></ul>
+<p>  16 August 1999</p>
+
+<ul><li><p>Added disableKeyboardWhileBusy option to initialise().  To ignore
+    keyboard input while displaying the busy cursor, Pmw sets the
+    focus for each toplevel window to the Blt busy window.  However,
+    under NT, this causes each window to be raised.  If this is not
+    acceptable, programs running on NT can request show/hidebusycursor
+    not to ignore keyboard input. </p>
+
+</li></ul>
+<p>  25 August 1999</p>
+
+<ul><li><p>Added Pmw.Blt.busy_forget() and used it in Pmw.hidebusycursor()
+    when running under NT.  There is a bug in the Blt busy release
+    command under NT where it sometimes fails to display the busy
+    cursor.  Using busy forget avoids the problem.</p>
+
+</li></ul>
+<p>  27 September 1999</p>
+
+<ul><li><p>Added busyCursorName option to Pmw.initialise() and added cursor
+    argument to Pmw.Blt.busy_hold().  (Mark Favas)</p>
+
+</li></ul>
+<p>  20 October 1999</p>
+
+<ul><li><p>Replaced Pmw.NoteBookR and Pmw.NoteBookS with completely rewritten
+    Pmw.NoteBook.</p>
+
+</li>
+<li><p>Renamed Pmw.OptionMenu.get() to Pmw.OptionMenu.getcurselection()
+    and Pmw.PanedWidget.remove() to Pmw.PanedWidget.delete(), to be
+    more consistent with other megawidgets.</p>
+
+</li>
+<li><p>The index() method of several megawidgets now use Pmw.END,
+    Pmw.SELECT and Pmw.DEFAULT instead of strings, since these may
+    conflict with component names. </p>
+
+</li>
+<li><p>Pmw.OptionMenu.index() now uses Pmw.SELECT to return
+    index of the currently selected menu item, rather than None.</p>
+
+</li>
+<li><p>Added destroy() method to Pmw.MegaArchetype to handle cleaning up
+    of _hullToMegaWidget mapping. </p>
+
+</li>
+<li><p>Removed exclude argument from Pmw.showbusycursor() and added
+    Pmw.excludefrombusycursor() function instead.  (Rob Hooft)</p>
+
+</li>
+<li><p>Fixed several bugs for Windows NT.</p>
+
+</li>
+<li><p>Added Pmw.ButtonBox.button() and Pmw.RadioSelect.button().</p>
+
+</li>
+<li><p>Added Pmw.Color.bordercolors().</p>
+
+</li></ul>
+<p>  21 October 1999</p>
+
+<ul><li><p>Release of version 0.8.3. (Version 0.8.2 was not released.)</p>
+
+</li></ul>
+<p>  30 October 1999</p>
+
+<ul><li><p>Added arrownavigation option and previouspage() and nextpage()
+    methods to Pmw.NoteBook.  (Peter Funk)</p>
+
+</li>
+<li><p>Renamed the <code>setnaturalpagesize()</code> method of Pmw.NoteBook to
+    <code>setnaturalsize()</code> to be consistent with Pmw.PanedWidget.</p>
+
+</li>
+<li><p>Changed Pmw.excludefrombusycursor() to Pmw.setbusycursorattributes().
+    Removed busyCursorName option from Pmw.initialise() and added
+    cursorName attribute to Pmw.setbusycursorattributes().</p>
+
+</li>
+<li><p>Added documentation source and build scripts to ftp site.</p>
+
+</li></ul>
+<p>  6 November 1999</p>
+
+<ul><li><p>Fixed memory leaks when destroying megawidgets.  Added automatic
+    check for memory leak to test script used by all tests. 
+    Pmw.initialise() now uses a hook into Tkinter.Widget.destroy
+    rather than Tkinter.Frame.destroy to handle the case of
+    Pmw.NoteBook being destroyed (since the notebook hull is a canvas
+    and not a frame).  Window manager delete protocol callbacks are
+    now cleaned up.  Pmw.ScrolledListBox event bindings now do not
+    leak.  (Reported by Jeff Weeks)</p>
+
+</li>
+<li><p>Removed key bindings for Pmw.ScrolledListBox except space and return keys.</p>
+
+</li></ul>
+<p>  20 November 1999</p>
+
+<ul><li><p>Fixed bug in Pmw.Balloon when the canvas or text item that
+    triggered the balloon is deleted before the balloon is displayed
+    by the <strong>initwait</strong> timer.  (Magnus Kessler)</p>
+
+</li>
+<li><p>Added <strong>'nograb'</strong> to <em>globalMode</em> option of <code>activate()</code> method. (Rob Hooft)</p>
+
+</li>
+<li><p>Added __setitem__ method to Pmw.MegaArchetype, so that megawidget
+    options can be now set using <code>megawidget['option'] = value</code> style.
+    (Oliver Gathmann)</p>
+
+</li></ul>
+<p>  27 December 1999</p>
+
+<ul><li><p>Converted from <code>regex</code> module to <code>re</code> module, since <code>regex</code> is not
+    implemented for Jpython.  (Finn Bock)</p>
+
+</li></ul>
+<p>  30 December 1999</p>
+
+<ul><li><p>Added <code>clear()</code> method to Pmw.ScrolledListBox (suggested by Carson
+    Fenimore).</p>
+
+</li></ul>
+<p>  15 March 2000</p>
+
+<ul><li><p>Fixed problem in PmwBase when deleting windows that were created
+    before Pmw was initialised (such as splash windows displayed while
+    the application is coming up).  (Mark Favas)</p>
+
+</li>
+<li><p>Added splash window to Pmw demo.  (Mark Favas)</p>
+
+</li></ul>
+<p>  30 April 2000</p>
+
+<ul><li><p>Added Pmw.MainMenuBar megawidget, which uses the menubar feature
+    of Tk to provide platform specific menu bars.</p>
+
+</li>
+<li><p>Fixed Pmw.Counter and several other megawidgets so that certain
+    <strong>hull</strong> constructor keywords, such as <strong>hull_relief</strong> and
+    <strong>hull_borderwidth</strong>, are not overriden in the constructor.</p>
+
+</li>
+<li><p>Thanks to Peter Cashin for his help on how to unpack gzipped tar
+    files on Microsoft Windows operating systems.</p>
+
+</li>
+<li><p>Added Pmw.HistoryText megawidget.  This can be used as the basis
+    of an interactive text-based database query gui.  It maintains a
+    history of each query and allows editing of prior queries.</p>
+
+</li>
+<li><p>Added references to the Pmw.Blt.Graph documentation by Bjørn Ove
+    Thue and Hans Petter Langtangen.</p>
+
+</li>
+<li><p>Searched for and fixed memory leaks. There are no more known memory leaks.</p>
+<ul><li><p>For commands created by <code>bind</code>:  these are cleaned up by Tkinter
+      when the widget is destroyed.  Pmw.Balloon, which repeatedly
+      binds to the same widget (or item, using <code>tag_bind</code>), has been
+      fixed by passing the old command into the call to <code>unbind</code> or
+      <code>tag_unbind</code> which is cleaned up by Tkinter.</p>
+
+</li>
+<li><p>For commands created by <code>class_bind</code>:  most class bindings are
+      only created once (per Tk interpreter) and so do not need to be
+      cleaned up.  The exception is adding and deleting menus in
+      Pmw.MenuBar.  This has now been fixed to clean up <code>class_bind</code>
+      commands when deleting menus.</p>
+
+</li>
+<li><p>Callbacks given to command, xscrollcommand, yscrollcommand, etc
+      options are cleaned up by Tkinter when the widget is destroyed. 
+      Cases where Pmw repeatedly sets such options have now been fixed
+      to clean up the old command before configuring the new one. 
+      These are in <code>setitems</code> in Pmw.OptionMenu and when modifying the
+      scrollcommand options in several of the scrolled widgets.</p>
+
+</li>
+<li><p>Pmw now cleans up calbacks it registers with the
+      WM_DELETE_WINDOW protocol for toplevel windows.</p>
+
+</li></ul>
+
+</li>
+<li><p>Added ManualTests.py to tests directory for tests which need to be
+    run by hand.</p>
+
+</li></ul>
+<p>  12 May 2000</p>
+
+<ul><li><p>Release of version 0.8.4.</p>
+
+</li></ul>
+<p>  17 May 2000</p>
+
+<ul><li><p>Modified Pmw.Counter to deal with the presence (python up to
+    1.5.2) or absence (python 1.6 and after) of an <strong>L</strong> at the end of
+    the ascii representation of a long.  (Mark Favas)</p>
+
+</li>
+<li><p>Fixed bug in Pmw.ScrolledFrame when given invalid flex options. 
+    (Stephen D Evans)</p>
+
+</li></ul>
+<p>  23 January 2001</p>
+
+<ul><li><p>Moved Pmw home from www.dscpl.com.au to pmw.sourceforge.net.</p>
+
+</li>
+<li><p>Added pmw2 font scheme, since the font used for balloon text with
+    pmw1 is too small on Linux.</p>
+
+</li>
+<li><p>Removed syntax coloring from code window in demos.  It did not
+    look good and the pattern matching was not always correct.</p>
+
+</li>
+<li><p>Changed font size used for demos to 12 for Unix, since 14 looked
+    too big under Linux.</p>
+
+</li>
+<li><p>Minor fixes to tests for Tk 8.3.</p>
+
+</li></ul>
+<p>  8 February 2001</p>
+
+<ul><li><p>Release of version 0.8.5</p>
+
+</li></ul>
+<p>  18 February 2001</p>
+
+<ul><li><p>Added xview() and yview() methods to Pmw.ScrolledFrame (suggested
+    by Christer Fernstrom).</p>
+
+</li>
+<li><p>Made tktrace output more readable.</p>
+
+</li>
+<li><p>Added noBltBusy option to Pmw.initialise.</p>
+
+</li>
+<li><p>Fixed bug where combobox dropdown list could stay mapped after
+    entryfield was unmapped.</p>
+
+</li>
+<li><p>Improved scrolling in scrolled frame.</p>
+
+</li></ul>
+<p>  21 February 2001</p>
+
+<ul><li><p>Fixed tests for recent version of Blt graph (reported by
+    Venkatesh Prasad Ranganath).</p>
+
+</li>
+<li><p>Fixed problem in Pmw.ScrolledFrame in python 1.5 - string.atof
+    does not accept a number as argument, but it does in python 2.0.</p>
+
+</li></ul>
+<p>  24 February 2001</p>
+
+<ul><li><p>Modified Pmw.OptionMenu documentation to specify that list
+    elements must be strings (problem reported by Guy Middleton).</p>
+
+</li>
+<li><p>Fixed bug in Pmw.OptionMenu where the wrong item was displayed
+    when an integer item in the menu was selected with the mouse (even
+    though items should be strings).</p>
+
+</li>
+<li><p>Added work around to Pmw.ScrolledFrame for bug in Tk when
+    retrieving value from scrollbars soon after creation.</p>
+
+</li></ul>
+<p>  27 February 2001</p>
+
+<ul><li><p>Added HistoryText and MainMenuBar to bin/bundlepmw.py - accidently
+    left out.</p>
+
+</li></ul>
+<p>  13 April 2001</p>
+
+<ul><li><p>Changed default foreground (text) of Pmw.Balloown to black.  (Eric
+    Pettersen)</p>
+
+</li>
+<li><p>Added default fontScheme to Pmw.initialise().</p>
+
+</li>
+<li><p>Added -fontscheme and -fontsize options to demo.</p>
+
+</li>
+<li><p>Added updatelayout() to Pmw.PanedWidget for use when dynamically
+    adding and deleting panes.  (G Cash)</p>
+
+</li>
+<li><p>Added move() to Pmw.PanedWidget to move panes.  (G Cash)</p>
+
+</li></ul>
+<p>  20 April 2001</p>
+
+<ul><li><p>Fixed bug in Pmw.Balloon where the balloon would reappear if the
+    mouse button was pressed down inside a widget and then, while the
+    mouse button was being held down, the mouse was moved outside of
+    the widget and then moved back over the widget.</p>
+
+</li>
+<li><p>Fixed bug in Pmw.Balloon when destroying widgets while the balloon
+    was up.  In this case, the balloon remained displayed even though
+    the widget had been destroyed. (Reported by Stefan Schone.)</p>
+
+</li>
+<li><p>Fixed bug in Pmw.Balloon when destroying widgets during the
+    initwait period.  In this case, an error occurred when the
+    initwait timer went off when it tried to access the destroyed
+    widget. (Reported by Stefan Schone.)</p>
+
+</li>
+<li><p>Fixed Pmw.Balloon so that unbinding withdraws the balloon if
+    the widget being unbound is the widget which triggered the balloon.</p>
+
+</li>
+<li><p>Modified Pmw.Balloon so that when deleting a canvas or text item,
+    <code>tagunbind()</code> can be called which will withdraw the balloon if it
+    was triggered by the item.  Unfortunately this can not be
+    automated as for widgets since Tk does not support &lt;Destroy&gt;
+    bindings on canvas or text items, so there is no way that
+    Pmw.Balloon can be notified of the deletion of an item.</p>
+
+</li>
+<li><p>Updated tests for python 2.1.</p>
+
+</li></ul>
+<p>  21 May 2001</p>
+
+<ul><li><p>Pmw.OptionMenu now defaults to taking focus (on &lt;Tab&gt; key).</p>
+
+</li></ul>
+<p>  15 May 2002</p>
+
+<ul><li><p>Fixed bug in Pmw.Graph.element_closest() where element names
+    should follow option arguments.  (Val Shkolnikov)</p>
+
+</li></ul>
+<p>  5 June 2002</p>
+
+<ul><li><p>Added command option to Pmw.TimeCounter.</p>
+
+</li>
+<li><p>Finished all documentation.</p>
+
+</li>
+<li><p>Fixed bug in documentation creation script which, since python
+    2.0, printed default values of real options (such as the
+    horizfraction option of Pmw.ScrolledFrame) with too many digits
+    (such as 0.050000000000000003).</p>
+
+</li>
+<li><p>Fixed bug in setgeometryanddeiconify for cygwin python (John
+    Williams).</p>
+
+</li></ul>
+<p>  4 July 2002</p>
+
+<ul><li><p>Added master option to <code>MegaToplevel.show()</code></p>
+
+</li>
+<li><p>Improved <code>MegaToplevel.show()</code> so that tkraise is not called
+    unecessarily, thus avoiding 2 second delay under certain window
+    managers (such as sawfish) in most circumstances.  There are still
+    problems with the Enlightenment window manager.</p>
+
+</li></ul>
+<p>  18 August 2002</p>
+
+<ul><li><p>Added columnheader, rowheader and rowcolumnheader components to
+    Pmw.ScrolledText.  (Rob Pearson)</p>
+
+</li>
+<li><p>Added <code>getvalue()</code> and <code>setvalue()</code> methods to several megawidgets
+    as a consistent way to set and get the user-modifiable state. 
+    (Cimarron Taylor)</p>
+
+</li>
+<li><p>Made sub-classing simpler when no new options or components are
+    being created.  A sub-class of a Pmw megawidget does not need to
+    have an __init__() method.  If it does, it does not need to call
+    defineoptions().  Also, initialiseoptions() no longer requires an
+    argument (for backwards compatibility it may take an argument, but
+    it is ignored).</p>
+
+</li></ul>
+<p>  24 August 2002</p>
+
+<ul><li><p>Release of version 1.0</p>
+
+</li></ul>
+<p>  26 August 2002</p>
+
+<ul><li><p>Minor fixes.</p>
+
+</li>
+<li><p>Release of version 1.1</p>
+
+</li></ul>
+<p>  4 September 2002</p>
+
+<ul><li><p>Added collapse, expand and toggle methods and collapsedsize option
+    to Pmw.Group.  (Rob Pearson)</p>
+
+</li></ul>
+<p>  5 September 2002</p>
+
+<ul><li><p>Added sticky option to several megawidgets.</p>
+
+</li></ul>
+<p>  18 September 2002</p>
+
+<ul><li><p>Added appendtext method to Pmw.ScrolledText.  (Graham Dumpleton)</p>
+
+</li></ul>
+<p>  26 September 2002</p>
+
+<ul><li><p>Modified Pmw.ScrolledListBox to call dblclickcommand on
+    &lt;Double-ButtonRelease-1&gt; rather than &lt;Double-ButtonPress-1&gt; which
+    caused problems if the double button press unmapped the
+    ScrolledListBox.  In this case, the second button release of the
+    double click is given to another widget.  (Eric Pettersen)</p>
+
+</li></ul>
+<p>  14 June 2003</p>
+
+<ul><li><p>Changes for python 2.3 and Tcl/Tk 8.4.2:</p>
+<ul><li><p>Wrapped calls to cget() for Tkinter widgets in a call to
+        str().  Before python 2.3 cget() always returned a string. 
+        Under python 2.3, Tkinter sometimes returns non-string values
+        (such as int, or Tcl_Obj).  Made similar change when using
+        configure() to retrieve values.  Fixed tests to handle integer
+        and Tcl_Obj return value from cget().  (Charles Doutriaux)</p>
+
+</li>
+<li><p>Fixed uses of <code>col</code> field of grid command.  Must use full
+        <code>column</code> under Tcl/Tk 8.4.2.</p>
+
+</li>
+<li><p>Fixed PmwEntryField.py, PmwMessageBar.py, PmwScrolledField.py
+        so that the text is not greyed out under Tcl/Tk 8.4.2.  This
+        was caused by a change in behaviour of the <strong>'disabled'</strong> state
+        and the Tk entry widget.  Now use new <strong>'readonly'</strong> state for
+        Tcl/Tk 8.4.2.</p>
+
+</li>
+<li><p>Test script now ignores Blt test for Tcl/Tk 8.4.2, since it
+        causes Blt 2.4z to core dump.  Blt needs to be fixed.</p>
+
+</li>
+<li><p>Changed Dialog test to work around problem caused by Tk 8.4.2
+        enforcing transient behaviour of windows.  When activate() is
+        called on a dialog whose parent is withdrawn, then the dialog
+        window is made transient.  Under old versions of Tk, the
+        transient dialog was displayed, but under 8.4.2 the dialog is
+        not displayed.  Work around is to deiconify parent of dialog.</p>
+
+</li></ul>
+
+</li></ul>
+<p>  5 August 2003</p>
+
+<ul><li><p>Release of version 1.2</p>
+
+</li></ul>
+<p></p>
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/copyright.html b/Pmw/Pmw_1_2/doc/copyright.html
new file mode 100644 (file)
index 0000000..0f5e7e8
--- /dev/null
@@ -0,0 +1,57 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw copyright</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw copyright</h1>
+    
+<p>
+   Copyright 1997-1999 Telstra Corporation Limited, Australia
+   Copyright 2000-2002 Really Good Software Pty Ltd, Australia</p>
+
+<p>   Permission is hereby granted, free of charge, to any person
+   obtaining a copy of this software and associated documentation
+   files (the "Software"), to deal in the Software without
+   restriction, including without limitation the rights to use, copy,
+   modify, merge, publish, distribute, sublicense, and/or sell copies
+   of the Software, and to permit persons to whom the Software is
+   furnished to do so, subject to the following conditions:</p>
+
+<p>   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.</p>
+
+<p>   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+</p>
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/counter1.gif b/Pmw/Pmw_1_2/doc/counter1.gif
new file mode 100644 (file)
index 0000000..64efe35
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/counter1.gif differ
diff --git a/Pmw/Pmw_1_2/doc/counter2.gif b/Pmw/Pmw_1_2/doc/counter2.gif
new file mode 100644 (file)
index 0000000..be894ed
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/counter2.gif differ
diff --git a/Pmw/Pmw_1_2/doc/demosandtests.html b/Pmw/Pmw_1_2/doc/demosandtests.html
new file mode 100644 (file)
index 0000000..d7190a3
--- /dev/null
@@ -0,0 +1,364 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw demonstrations and tests</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw demonstrations and tests</h1>
+    
+<center><P ALIGN="CENTER">
+<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+</p></center>
+
+<p>
+  Pmw comes with an extensive range of demonstrations and tests.  The
+  demonstrations can be used to get a feel for what is provided by Pmw
+  and the demonstration code can be viewed to see examples of how to
+  use Pmw.  The tests can be executed to check that there are no
+  problems with running Pmw in your environment.
+
+</p>
+
+<dl>
+<dt> <h2>Demonstrations</h2></dt><dd>
+<p>
+  The Pmw <code>demos</code> directory contains demonstration scripts
+  showing many of the features of Pmw megawidgets.  To view a
+  comprehensive package of all the demonstrations, including a view of
+  the source code, run the <code>All.py</code> script.  Run
+  <code>All.py -help</code> for a short description of the script's
+  options.
+
+<p>
+  All of the demonstrations may also be run separately.  Most of the
+  demonstrations show some of the features of one of the Pmw
+  megawidgets.  For example, to see a demonstration of the ButtonBox
+  megawidget, change into the <code>demos</code> directory and
+  run
+
+</p>
+<dl>
+<dd>
+<pre>
+python ButtonBox.py
+</pre>
+</dd>
+</dl>
+
+<p>
+  Other demonstrations, which show other features of Pmw include
+</p>
+<dl>
+<dd>
+<pre>
+BltGraph.py         demonstrates the Pmw interface to
+                    the BLT graph and vector commands
+BltTabset.py        demonstrates the Pmw interface to
+                    the BLT tabset command
+Colors.py           how to set color schemes
+ConfigClass.py      how to configure the python class
+                    of a megawidger component
+ErrorHandling.py    how Pmw displays run time errors
+                    in a window
+ExampleDemo.py      template for new demonstrations
+Grid.py             the Tkinter Grid geometry manager
+LogicalFont.py      how to use standard values for fonts
+MessageInfo.py      how to extend the Pmw MegaToplevel
+                    class
+NestedDialogs.py    how nested modal dialogs behave
+Resources.py        how to use the option database to
+                    modify Tk widget option defaults
+Resources_Pmw.py    how to use the option database to
+                    modify megawidget option defaults
+ShowBusy.py         demonstrates the Pmw interface to
+                    the BLT busy command
+SpecialEntry.py     deriving from Pmw.EntryField
+Spectrum.py         some of the Pmw color handling
+                    functions
+SpeedTest.py        tests the speed of creating Pmw
+                    megawidgets
+TextDisplay.py      how to extend the Pmw MegaWidget
+                    class
+WidgetDestroy.py    megawidget destruction
+</pre>
+</dd>
+</dl>
+
+<b>Creating demonstrations of new megawidgets</b>
+<br>
+<p>
+If you create a new megawidget you can create a demonstration for it
+by using the file
+<a href="ExampleDemo.py"><code>ExampleDemo.py</code></a> as a
+template.  This template allows the demonstration to be run
+individually or to be automatically included as part of the
+demonstration package <code>All.py</code>.  You should take a copy of
+the template and name the new file after your megawidget.  You should
+then replace each instance of the word <code>EXAMPLE</code> with the
+name of your megawidget and replace the code in the
+<code>__init__</code> method with code to create and initialise one or
+more instances of your megawidget, which should be a child of
+<code>parent</code>.  You can add other methods as necessary.
+
+</p>
+
+</dd>
+<dt> <h2>Tests</h2></dt><dd>
+<p>
+  The Pmw <code>tests</code> directory contains a test framework
+  and a set of test scripts for Pmw.
+  The tests cover the standard Tkinter module and most of the Pmw megawidgets.
+  The tests make a great
+  demonstration of the flexibility of the megawidgets.  Simply change
+  into the <code>tests</code> directory and run
+  <code>python All.py</code>.
+
+<p>
+  If all tests pass there should be no output printed to standard
+  output.  If any of the tests fail, please send the test output to
+  the maintainer at
+  <a href="mailto:gregm@iname.com"><i>gregm@iname.com</i></a>.
+
+</p>
+
+<p>
+  All of the tests may be run separately.  Most of the tests test the
+  features of one of the Pmw megawidgets.  For example, to execute the
+  test for the ButtonBox megawidget, run
+
+</p>
+
+<dl>
+<dd>
+<pre>
+python ButtonBox_test.py
+</pre>
+</dd>
+</dl>
+
+<p>
+  The Test.py file contains general testing functions and is imported
+  by all test files.
+  Other files, which test other features of Pmw include
+</p>
+<dl>
+<dd>
+<pre>
+Blt_test.py           BLT vector and graph interface
+Colors_test.py        setting color schemes
+MegaWidget_test.py    creation of megawidget classes
+Options_test.py       option and component handling
+PmwBase_test.py       more option and component handling
+Tkinter_test.py       Tk widgets in the Tkinter module
+</pre>
+</dd>
+</dl>
+
+<b>Creating tests for new megawidgets</b>
+<br>
+<p>
+If you create a new megawidget you should create a test for it.  There
+is no template file for creating tests, but by looking at the other
+Pmw tests (for example,
+<a href="ScrolledText_test.py"><code>ScrolledText_test.py</code></a>) you
+will get some idea of how to create a test for your megawidget.
+
+</p>
+
+<p>
+The test files are designed to be run both individually or
+automatically by the test package <code>All.py</code>.  Each test file
+must define the <code>testData</code> tuple.  This consists of a
+sequence of 2-element tuples, each tuple being a test specification
+for one megawidget.  Usually a file tests only one megawidget and so
+there is only one test specification.  The first element in the
+specification is the megawidget class and the second is a sequence of
+(yet more) 2-element tuples.  In each of these tuples, the first
+element is a sequence of individual tests to perform on an instance of
+the megawidget and the second element is a dictionary to use for
+the keyword arguments when creating the instance.  Each individual
+test is a tuple, the meaning of which depends on the type of the first
+element, which may be either a string, a function or a method of the
+megawidget class, as explained below.
+
+</p>
+
+<ul>
+<li>
+<p>
+If the first element is a string, then it is treated as an option of
+the megawidget and configure() is called to set the option to the
+value specified by the second element.  After setting the option,
+cget() is called to query the option.  If the test tuple has three
+elements, then the value returned by cget() must equal the value
+specified by the third element.  Otherwise, the value returned must
+equal the value specified by the second element. For example,
+
+</p>
+<dl>
+<dd>
+<pre>
+('vscrollmode', 'static'),
+('text_relief', 'sunken'),
+('vscrollmode', 'bogus', 'ValueError: bad vscrollmode ' +
+  'option "bogus": should be static, dynamic, or none'),
+</pre>
+</dd>
+</dl>
+
+</li>
+<li>
+<p>
+If the first element is a function or method, then the function or
+method is called.  The arguments to the call are given by the second
+element.  (As a special case, if the second element is not a tuple, it
+is used as the only argument to the call.) The test tuple may have 2,
+3 or 4 elements.
+
+</p>
+<ul>
+<li>
+<p>
+If it has two elements, then the value returned by the call must be
+None.  For example,
+
+</p>
+<dl>
+<dd>
+<pre>
+(c.exportfile, '/tmp/ScrolledText_test.py'),
+(os.unlink, '/tmp/ScrolledText_test.py'),
+</pre>
+</dd>
+</dl>
+
+</li>
+<li>
+<p>
+If it has four elements, then the third element is a dictionary to use
+for the keyword arguments in the call and the value returned by the
+call must equal the value specified by the fourth element.  For
+example,
+
+</p>
+<dl>
+<dd>
+<pre>
+(c.search, ('abc', '0.0'), {'nocase': 1}, '2.24'),
+</pre>
+</dd>
+</dl>
+
+</li>
+<li>
+<p>
+If is has three elements and the third element is a dictionary, then
+it is used for the keyword arguments in the call and the value
+returned by the call must be None.  For example
+
+</p>
+<dl>
+<dd>
+<pre>
+(c.configurepane, 'first', {'size' : 200}),
+</pre>
+</dd>
+</dl>
+
+</li>
+<li>
+<p>
+If is has three elements and the third element is not a dictionary,
+then the value returned by the call must equal the value specified by
+the third element.  For example,
+
+</p>
+<dl>
+<dd>
+<pre>
+(c.components, (), ['hull', 'label']),
+(c.add, ('Legumes',),
+  'ValueError: name "Legumes" already exists'),
+</pre>
+</dd>
+</dl>
+
+</li>
+</ul>
+</li>
+</ul>
+
+<p>
+Some special functions and values supplied by the Test module that may
+be used in the tests include:
+</p>
+<dl>
+<dd>
+<pre>
+Test.callback       callback taking no arguments
+Test.callback1      callback taking one argument
+Test.callbackN      callback taking any number of arguments
+
+Test.currentWidget  returns the widget instance being tested
+Test.num_options    returns number of options for the widget
+
+Test.earthris       a sample Tkinter.PhotoImage
+Test.flagup         a sample Tkinter.BitmapImage
+Test.floatvar       a Tkinter.DoubleVar
+Test.stringvar      a Tkinter.StringVar
+</pre>
+</dd>
+</dl>
+
+<p>
+  To slow down a test (to see what is being displayed), add the
+  following line which sets the delay between tests to (say) 1000
+  milliseconds:
+
+</p>
+<dl>
+<dd>
+<pre>
+Test.setdelay(1000)
+</pre>
+</dd>
+</dl>
+
+<p>
+  To print information about what is being tested, add the line:
+
+</p>
+<dl>
+<dd>
+<pre>
+Test.setverbose(1)
+</pre>
+</dd>
+</dl>
+
+</dd>
+</dl>
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/dynamicloader.html b/Pmw/Pmw_1_2/doc/dynamicloader.html
new file mode 100644 (file)
index 0000000..01d701c
--- /dev/null
@@ -0,0 +1,147 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Dynamic loader</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Dynamic loader</h1>
+    
+<p>
+    There are two aspects of Pmw, unrelated to megawidgets, that
+    require special attention.  Firstly, Pmw is made up of many
+    sub-modules, potentially making access to its various classes and
+    functions cumbersome for the user.  Secondly, Pmw is regularly
+    being modified and added to, thus requiring the release of new
+    versions.  Therefore, techniques for making access to the
+    sub-modules easy and efficient and for dealing with the different
+    versions have been developed.  These techniques are incorporated
+    into the dynamic loader which Pmw creates when it is first
+    imported.</p>
+
+<p>    The first purpose of the loader is to give access to all Pmw classes
+    and functions through a single entry point, the <strong>Pmw.</strong> prefix.  For
+    example, to access the ComboBox class (which resides in one of the
+    sub-modules of Pmw), you just have to use <code>Pmw.ComboBox</code>.  Without
+    the loader, this would be a more complicated reference, such as,
+    hypothetically, <code>Pmw.PmwComboBox.ComboBox</code>.</p>
+
+<p>    The second purpose of the loader is to delay the importing of the
+    sub-modules until they are needed.  This improves the startup time
+    of applications which only use a few Pmw megawidgets.  It also
+    allows more megawidgets to be added to the library without slowing
+    down applications which do not use them.</p>
+
+<p>    The third purpose of the loader is to allow a script using Pmw to
+    specify which version of Pmw it requires.  This allows an
+    application to continue working correctly even after newer releases
+    of Pmw have been made which are not compatible with the version
+    expected by the application.  Several versions of Pmw can be
+    installed at once, with the actual version used being specified by
+    each application.  In addition, the loader can be configured to
+    search in one or more alpha versions of Pmw.  These versions may
+    contain new megawidgets, or new versions of existing megawidgets,
+    that are currently not in the base releases.</p>
+
+<p>    Several functions are available to set and query the version of
+    Pmw being used.  These are <code>Pmw.setversion()</code> and
+    <code>Pmw.setalphaversions()</code> which specify the version and alpha
+    versions (if any) to use for this session; <code>Pmw.version()</code> which
+    returns the version(s) being used by this session; and
+    <code>Pmw.installedversions()</code> which returns the version(s) of Pmw
+    currently installed.  These are described in the
+    <a href="PmwFunctions.html">Pmw functions reference manual</a>.</p>
+
+<p>    When Pmw is first imported, an instance of PmwLoader is created
+    and placed into <code>sys.modules['Pmw']</code>.  From that point on, any
+    reference to attributes of the Pmw 'module' is handled by the
+    loader.  The real Pmw package is stored in <code>sys.modules['_Pmw']</code>.</p>
+
+<p>    The loader searches the Pmw package base directory for
+    sub-directories with the prefixes <code>Pmw_</code> and <code>Alpha_</code>, which
+    contain Pmw base releases and alpha releases.  The version numbers
+    are given by the part of the directory name following the prefix. 
+    These versions are available for use and are those returned by the
+    <code>Pmw.installedversions</code> function.  The initial version is set to
+    the base release with the greatest version number.  When the first
+    reference to a Pmw class or function is made, the loader reads the
+    files named <strong>Pmw.def</strong> in the current base version directory and
+    also in the alpha directories (if any).  These files list all the
+    classes and functions supported by the version.  Pmw attributes
+    are first searched for in the alpha directories and then in the
+    base version directory.  The first directory which supports the
+    reference is used.  In this way, alpha versions override base
+    versions.</p>
+
+<p>    The directory <code>Alpha_99_9_example</code> contains a simple example of
+    how to structure an alpha version.  The following code can be used
+    to request that the alpha version be used and then creates an
+    instance of a new megawidget defined in the alpha version.</p>
+
+<dl><dd><pre> import Pmw
+ Pmw.setalphaversions('99.9.example')
+
+ # Create a standard message dialog using the base Pmw version.
+ ordinary = Pmw.MessageDialog(
+     message_text = 'Ordinary\nPmw Dialog')
+
+ # Create an example dialog using the alpha Pmw version.
+ alpha = Pmw.AlphaExample()</pre></dd></dl>
+
+<p>    <strong>Freezing Pmw</strong></p>
+
+<p>    Since the dynamic loader requires that Pmw be installed at run
+    time, it can not be used when <em>freezing</em> Pmw.  In this case, a
+    single module containing all Pmw code is required, which can then
+    be frozen with the rest of the application's modules.  The
+    <code>bundlepmw.py</code> script in the Pmw <code>bin</code> directory can be used to
+    create such a file.  This script concatenates (almost) all Pmw
+    megawidget files into a single file, <code>Pmw.py</code>, which it writes to
+    the current directory.  The script is called like this:</p>
+
+<dl><dd><pre> bundlepmw.py [-noblt] [-nocolor] /path/to/Pmw/Pmw_X_X_X/lib</pre></dd></dl>
+
+<p>    The last argument should be the path to the <code>lib</code> directory of the
+    required version of Pmw.  By default, the <code>Pmw.py</code> file imports
+    the <code>PmwBlt</code> and <code>PmwColor</code> modules and so, to freeze an
+    application using Pmw, you will need to copy the files <code>PmwBlt.py</code>
+    and <code>PmwColor.py</code> to the application directory before freezing.</p>
+
+<p>    If you are sure that your application does not use any of the
+    <code>Pmw.Blt</code> or <code>Pmw.Color</code> functions, you can use the <code>-noblt</code> or
+    <code>-nocolor</code> options.  In this case <code>Pmw.py</code> will be modified so
+    that it does not import these module(s) and so will not need to be
+    included when freezing the application.</p>
+
+<p>    If your application only uses a few Pmw megawidgets, you can
+    remove the references to the usused ones in the <code>files</code> list in
+    the <code>bundlepmw.py</code> code.  To make the change, take a copy of the
+    script and modify it.  This will make the <code>Pmw.py</code> file smaller. 
+    However, be sure that you do not delete megawidgets that are
+    components or base classes of megawidgets that you use.</p>
+
+<p></p>
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/example.py b/Pmw/Pmw_1_2/doc/example.py
new file mode 100644 (file)
index 0000000..0eed16f
--- /dev/null
@@ -0,0 +1,79 @@
+import Tkinter 
+import Pmw
+class ThresholdScale(Pmw.MegaWidget):
+    """ Megawidget containing a scale and an indicator.
+    """
+    def __init__(self, parent = None, **kw):
+
+        # Define the megawidget options.
+        optiondefs = (
+           ('colors',    ('green', 'red'), None),
+           ('threshold', 50,               None),
+           ('value',     None,             Pmw.INITOPT),
+        )
+        self.defineoptions(kw, optiondefs)
+        # Initialise base class (after defining options).
+        Pmw.MegaWidget.__init__(self, parent)
+        # Create the components.
+        interior = self.interior()
+        # Create the indicator component.
+        self.indicator = self.createcomponent('indicator',
+                (), None,
+                Tkinter.Frame, interior,
+                       width = 16,
+                       height = 16,
+                       borderwidth = 2,
+                       relief = 'raised')
+        self.indicator.grid()
+        # Create the scale component.
+        self.scale = self.createcomponent('scale',
+                (), None,
+                Tkinter.Scale, interior,
+                       command = self._doCommand,
+                       tickinterval = 20,
+                       length = 200,
+                       from_ = 100,
+                       to = 0,
+                       showvalue = 0)
+        self.scale.grid()
+        value = self['value']
+        if value is not None:
+            self.scale.set(value)
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def _doCommand(self, valueStr):
+       if self.scale.get() > self['threshold']:
+           color = self['colors'][1]
+       else:
+           color = self['colors'][0]
+       self.indicator.configure(background = color)
+
+Pmw.forwardmethods(ThresholdScale, Tkinter.Scale, 'scale')
+# Initialise Tkinter and Pmw.
+root = Pmw.initialise()
+root.title('Pmw ThresholdScale demonstration')
+
+# Create and pack two ThresholdScale megawidgets.
+mega1 = ThresholdScale()
+mega1.pack(side = 'left', padx = 10, pady = 10)
+
+mega2 = ThresholdScale(
+       colors = ('green', 'yellow'),
+       threshold = 75,
+        value = 80,
+       indicator_width = 32,
+       scale_width = 25)
+mega2.pack(side = 'left', padx = 10, pady = 10)
+
+# Let's go.
+root.mainloop()
diff --git a/Pmw/Pmw_1_2/doc/example1.gif b/Pmw/Pmw_1_2/doc/example1.gif
new file mode 100644 (file)
index 0000000..b54ca93
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/example1.gif differ
diff --git a/Pmw/Pmw_1_2/doc/example2.gif b/Pmw/Pmw_1_2/doc/example2.gif
new file mode 100644 (file)
index 0000000..bd5889b
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/example2.gif differ
diff --git a/Pmw/Pmw_1_2/doc/exercises.py b/Pmw/Pmw_1_2/doc/exercises.py
new file mode 100644 (file)
index 0000000..edd4f52
--- /dev/null
@@ -0,0 +1,123 @@
+import Tkinter 
+import Pmw
+class ThresholdScale(Pmw.MegaWidget):
+    """ Megawidget containing a scale and an indicator.
+    """
+    def __init__(self, parent = None, **kw):
+        # Define the megawidget options.
+        optiondefs = (
+           ('colors',      ('green', 'red'), None),
+           ('orient',      'vertical',       Pmw.INITOPT),
+           ('labelmargin', 0,                Pmw.INITOPT),
+           ('labelpos',    None,             Pmw.INITOPT),
+           ('threshold',   (50,),            None),
+           ('value',       None,             Pmw.INITOPT),
+        )
+        self.defineoptions(kw, optiondefs)
+        # Initialise base class (after defining options).
+        Pmw.MegaWidget.__init__(self, parent)
+        # Create the components.
+        interior = self.interior()
+        # Create the indicator component.
+        self.indicator = self.createcomponent('indicator',
+                (), None,
+                Tkinter.Frame, interior,
+                       width = 16,
+                       height = 16,
+                       borderwidth = 2,
+                       relief = 'raised')
+        # Create the value component.
+        self.value = self.createcomponent('value',
+                (), None,
+                Tkinter.Label, interior,
+                   width = 3)
+        # Create the scale component.
+       if self['orient'] == 'vertical':
+           # The default scale range seems to be
+           # the wrong way around - reverse it.
+           from_ = 100
+           to = 0
+       else:
+           from_ = 0
+           to = 100
+
+        self.scale = self.createcomponent('scale',
+                (), None,
+                Tkinter.Scale, interior,
+                       orient = self['orient'],
+                       command = self._doCommand,
+                       tickinterval = 20,
+                       length = 200,
+                       from_ = from_,
+                       to = to,
+                       showvalue = 0)
+        value = self['value']
+        if value is not None:
+            self.scale.set(value)
+       # Use grid to position all components
+       if self['orient'] == 'vertical':
+           self.indicator.grid(row = 1, column = 1)
+           self.value.grid(row = 2, column = 1)
+           self.scale.grid(row = 3, column = 1)
+           # Create the label.
+           self.createlabel(interior, childRows=3)
+       else:
+           self.indicator.grid(row = 1, column = 1)
+           self.value.grid(row = 1, column = 2)
+           self.scale.grid(row = 1, column = 3)
+           # Create the label.
+           self.createlabel(interior, childCols=3)
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def _doCommand(self, valueStr):
+       valueInt = self.scale.get()
+       colors = self['colors']
+       thresholds = self['threshold']
+       color = colors[-1]
+       for index in range(len(colors) - 1):
+           if valueInt <= thresholds[index]:
+               color = colors[index]
+               break
+       self.indicator.configure(background = color)
+       self.value.configure(text = valueStr)
+
+Pmw.forwardmethods(ThresholdScale, Tkinter.Scale, 'scale')
+# Initialise Tkinter and Pmw.
+root = Pmw.initialise()
+root.title('Pmw ThresholdScale demonstration')
+
+# Create and pack two ThresholdScale megawidgets.
+mega1 = ThresholdScale(scale_showvalue = 1)
+mega1.pack(side = 'left', padx = 10, pady = 10)
+
+mega2 = ThresholdScale(
+       colors = ('green', 'yellow', 'red'),
+       threshold = (50, 75),
+        value = 80,
+       indicator_width = 32,
+       scale_width = 25)
+mega2.pack(side = 'left', padx = 10, pady = 10)
+
+# Create and pack two horizontal ThresholdScale megawidgets.
+mega3 = ThresholdScale(
+       orient = 'horizontal',
+       labelpos = 'n',
+       label_text = 'Horizontal')
+mega3.pack(side = 'top', padx = 10, pady = 10)
+mega4 = ThresholdScale(orient = 'horizontal')
+mega4.pack(side = 'top', padx = 10, pady = 10)
+
+# Let's go.
+root.mainloop()
diff --git a/Pmw/Pmw_1_2/doc/features.html b/Pmw/Pmw_1_2/doc/features.html
new file mode 100644 (file)
index 0000000..055cce7
--- /dev/null
@@ -0,0 +1,87 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw features</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw features</h1>
+    
+<p>
+    Pmw is a toolkit for building high-level compound widgets, or
+    <em>megawidgets</em>, constructed using other widgets as component parts. 
+    It promotes consistent look and feel within and between graphical
+    applications, is highly configurable to your needs and is easy to
+    use.</p>
+
+<p>    Pmw consists of:</p>
+<ul><li><p>A few base classes, providing a foundation for building
+          megawidgets.</p>
+
+</li>
+<li><p>A library of flexible and extensible megawidgets built on
+          the base classes, such as buttonboxes, notebooks,
+          comboboxes, selection widgets, paned widgets, scrolled
+          widgets and dialog windows.</p>
+
+</li>
+<li><p>A lazy importer/dynamic loader which is automatically
+          invoked when Pmw is first imported.  This gives unified
+          access to all Pmw classes and functions through the <strong>Pmw.</strong>
+          prefix.  It also speeds up module loading time by only
+          importing Pmw sub-modules when needed.</p>
+
+</li>
+<li><p>Complete reference documentation, covering all classes and
+          functions including all megawidgets and their options,
+          methods and components.  Helpful tutorial material is also
+          available.</p>
+
+</li>
+<li><p>A test framework and tests for Pmw megawidgets.</p>
+
+</li>
+<li><p>A slick demonstration of the megawidgets.</p>
+
+</li>
+<li><p>An interface to the BLT busy, graph and vector commands.</p>
+
+</li></ul>
+
+<p>    The interface to Pmw megawidgets is similar to basic Tk widgets, so it
+    is easy for developers to include both megawidgets and basic Tk
+    widgets in their graphical applications.  In addition, Pmw
+    megawidgets may themselves be extended, using either inheritance or
+    composition.</p>
+
+<p>    The use of the Pmw megawidgets replaces common widget combinations
+    with higher level abstractions.  This simplifies code, making it
+    more readable and maintainable.  The ability to extend Pmw
+    megawidgets enables developers to create new megawidgets based on
+    previous work.</p>
+
+<p></p>
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/halfblueball.gif b/Pmw/Pmw_1_2/doc/halfblueball.gif
new file mode 100644 (file)
index 0000000..6977920
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/halfblueball.gif differ
diff --git a/Pmw/Pmw_1_2/doc/howtobuild.html b/Pmw/Pmw_1_2/doc/howtobuild.html
new file mode 100644 (file)
index 0000000..4a408b4
--- /dev/null
@@ -0,0 +1,465 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>How to build Pmw megawidgets</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">How to build Pmw megawidgets</h1>
+    
+<center><P ALIGN="CENTER">
+<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+</p></center>
+
+<dl>
+<dt> <h3>Introduction</h3></dt><dd>
+<p>
+  This document briefly describes how to design and code Pmw
+  megawidgets by inheriting from the Pmw base classes.  It shows step
+  by step how to build a simple example megawidget.  This megawidget
+  allows the user to select one of a range of numbers and it also
+  indicates if the selected number is greater than a given threshold.
+
+</p>
+
+</dd>
+<dt> <h3>Choosing the components</h3></dt><dd>
+
+<p>
+  The megawidget will be built using a Tkinter.Scale widget to allow
+  the user to select a number in a range, and a Tkinter.Frame widget
+  to act as an indicator, displaying red (say) if the selected number
+  exceeds the threshold.  It will look something like this:
+
+</p>
+
+<center><P ALIGN="CENTER">
+  <IMG SRC = scale1.gif ALT = "Scale 2" WIDTH=70 HEIGHT=244>
+</p></center>
+  
+<p>
+  The programmer using this megawidget will need access to the scale
+  widget, since they will need to set the scale's range.  Therefore
+  the scale will be made a component of the megawidget.  The
+  programmer will probably not need access to the indicator frame,
+  but, just in case the need arises to change the borderwidth or
+  relief of the indicator, we will make it a component too.  This
+  illustrates a convention about components - for maximum
+  configurability, make all sub-widgets components.
+
+</p>
+
+</dd>
+<dt> <h3>Choosing the options</h3></dt><dd>
+
+<p>
+  Apart from the component options now available through the scale and indicator
+  components, the megawidget will need a few options of its own.  It
+  will need a <strong>threshold</strong> option to set the threshold. 
+  It may also need options to set the colors of the indicator when the
+  selected value is both above and below the threshold.  Other options
+  could be <strong>orient</strong> or <strong>indicatorpos</strong> to
+  specify the relative position of components and
+  <strong>margin</strong>, <strong>padx</strong> or
+  <strong>pady</strong> to specify spacing between and around the
+  components.  For this example, we will define three options -
+  <strong>threshold</strong>, <strong>colors</strong> and
+  <strong>value</strong>.  The <strong>colors</strong> option will be
+  a 2-element sequence specifying two colors (below threshold, above
+  threshold).  The <strong>value</strong> option will be the initial
+  value of the scale.
+
+</p>
+
+</dd>
+<dt> <h3>Coding the megawidget</h3></dt><dd>
+
+<p>
+  The first things to do are to decide on a name for the new
+  megawidget, decide which base class to inherit from and to begin to
+  write the constructor.  Most Pmw megawidgets are derived from either
+  Pmw.MegaWidget, Pmw.MegaToplevel or Pmw.Dialog.  In this case, since
+  the widget is not to be contained within its own toplevel window, we
+  will inherit from Pmw.MegaWidget.  The constructors of megawidgets
+  take one argument (the widget to use as the parent of the
+  megawidget's hull, defaulting to the root window) and any number of
+  keyword arguments.
+
+</p>
+
+<pre>
+class ThresholdScale(Pmw.MegaWidget):
+    """ Megawidget containing a scale and an indicator.
+    """
+    def __init__(self, parent = None, **kw):
+</pre>
+
+<p>
+  Next, we need to define the options supplied by this megawidget. 
+  Each option is specified by a 3-element sequence.  The first element
+  is the option's name.  The second element is the default value.  The
+  third element is either a callback function,
+  <strong>Pmw.INITOPT</strong> or <strong>None</strong>.  In the first
+  case, the function is called at the end of construction (during the 
+  call to <code>self.inialiseoptions</code>) and also
+  whenever the option is set by a call to
+  <code>configure</code>.  <strong>Pmw.INITOPT</strong> indicates that
+  the option is an initialisation option - it cannot be set by calling
+  <code>configure</code>.  <strong>None</strong> indicates that the
+  option can be set by calling <code>configure</code>, but that there
+  is no callback function.
+
+</p>
+
+<p>
+  The call to <code>self.defineoptions</code> also includes the
+  keyword arguments passed in to the constructor.  The value given to
+  any option specified in the keywords will override the default
+  value.
+
+</p>
+
+<pre>
+        # Define the megawidget options.
+        optiondefs = (
+            ('colors',    ('green', 'red'), None),
+            ('threshold', 50,               None),
+            ('value',     None,             Pmw.INITOPT),
+        )
+        self.defineoptions(kw, optiondefs)
+</pre>
+
+<p>
+  After defining the options, the constructor of the base class should
+  be called.  The options need to be defined first so that a derived
+  class can redefine the default value of an option defined in a base
+  class.  This is because the value specified by the derived class
+  must be made available before the base class constructor is called.
+  The keyword
+  arguments should not be passed into the base class constructor since
+  they have already been dealt with in the previous step.
+
+</p>
+
+<pre>
+        # Initialise base class (after defining options).
+        Pmw.MegaWidget.__init__(self, parent)
+</pre>
+
+<p>
+  Now we should create the components.  The components are created as
+  children (or grandchildren ...) of the megawidget's interior.
+
+</p>
+
+<pre>
+        # Create the components.
+        interior = self.interior()
+</pre>
+
+<p>
+  The first component to create is the indicator.  The
+  <code>createcomponent</code> method creates the sub-widget and
+  registers the widget as a component of this megawidget.  It takes
+  five arguments plus any number of keyword arguments.  The arguments
+  are name, aliases, group, class and constructor arguments.  See the
+  <a href="MegaArchetype.html">Pmw.MegaArchetype reference manual</a>)
+  for full details.
+
+</p>
+
+<pre>
+        # Create the indicator component.
+        self.indicator = self.createcomponent('indicator',
+                (), None,
+                Tkinter.Frame, (interior,),
+                        width = 16,
+                        height = 16,
+                        borderwidth = 2,
+                        relief = 'raised')
+        self.indicator.grid()
+</pre>
+
+<p>
+  The scale component is created in a similar way.  In this case, the
+  initial value of the scale is also set to the value of the
+  <strong>value</strong> initialisation option.
+
+</p>
+
+<pre>
+        # Create the scale component.
+        self.scale = self.createcomponent('scale',
+                (), None,
+                Tkinter.Scale, (interior,),
+                        command = self._doCommand,
+                        tickinterval = 20,
+                        length = 200,
+                        from_ = 100,
+                        to = 0,
+                        showvalue = 0)
+        self.scale.grid()
+        value = self['value']
+        if value is not None:
+            self.scale.set(value)
+</pre>
+
+<p>
+  At the end of the constructor, the <code>initialiseoptions</code>
+  method is called to check that all keyword arguments have been used
+  (that is, the caller did not specify any unknown or misspelled
+  options) and to call the option callback functions.
+
+</p>
+
+<pre>
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+</pre>
+
+<p>
+  All other methods must now be defined.  In this case, only one
+  method is required - a method called whenever the scale changes and
+  which sets the indicator color according to the threshold.
+
+</p>
+
+<pre>
+    def _doCommand(self, valueStr):
+        if self.scale.get() > self['threshold']:
+            color = self['colors'][1]
+        else:
+            color = self['colors'][0]
+        self.indicator.configure(background = color)
+</pre>
+
+<p>
+  To complete the megawidget, methods from other classes can be
+  copied into this class.  In this case, all Tkinter.Scale methods
+  not already defined by the megawidget are made available as methods
+  of this class and are forwarded to the scale component.  Note that
+  the third argument to <code>Pmw.forwardmethods</code> is the name of
+  the instance variable referring to the Tkinter.Scale widget and not
+  the name of the component.  This function is called outside of and
+  after the class definition.
+
+</p>
+
+<pre>
+Pmw.forwardmethods(ThresholdScale, Tkinter.Scale, 'scale')
+</pre>
+
+<p>
+    <strong>Important note:</strong> If a megawidget defines options
+    using <code>defineoptions()</code>, then this method must be
+    called in the megawidget constructor before the call to the base
+    class constructor and a matching call to
+    <code>initialiseoptions()</code> must made at the end of the
+    constructor.  For example:
+
+</p>
+<pre>
+    def __init__(self, parent = None, **kw):
+       optionDefs = ...
+       self.defineoptions(kw, optionDefs)
+       BaseClass.__init__(self, parent)
+       ...
+       self.initialiseoptions()
+</pre>
+
+</dd>
+<dt> <h3>Creating instances of the megawidget</h3></dt><dd>
+
+<p>
+  The code below creates two of our example megawidgets.  The first is
+  created with default values for all options.  The second is created
+  with new values for the options.  It also redefines some of the
+  options of the components.
+
+</p>
+
+<dl>
+<dd>
+<pre>
+# Create and pack two ThresholdScale megawidgets.
+mega1 = ThresholdScale()
+mega1.pack(side = 'left', padx = 10, pady = 10)
+
+mega2 = ThresholdScale(
+        colors = ('green', 'yellow'),
+        threshold = 75,
+        value = 80,
+        indicator_width = 32,
+        scale_width = 25)
+mega2.pack(side = 'left', padx = 10, pady = 10)
+</pre>
+</dd>
+</dl>
+
+<center><P ALIGN="CENTER">
+  <IMG SRC = scale2.gif ALT = "Scale 1" WIDTH=150 HEIGHT=244>
+</p></center>
+  
+</dd>
+<dt> <h3>The complete code</h3></dt><dd>
+
+<p>
+  The complete code for this example can be seen
+  <a href="example.py">here</a>.
+
+</p>
+
+</dd>
+<dt> <h3>Exercises</h3></dt><dd>
+
+<p>
+  These exercises build on the example presented so far.
+
+</p>
+
+<ol>
+  <li>
+    Change the call to create <code>mega1</code> so that the scale
+    widget displays the current value next to the slider.  (You may
+    need to look at the Tk scale manual page to find which option to
+    the <strong>scale</strong> component to set.)  You will be able to
+    do this without modifying the ThresholdScale class code.
+
+  </li>
+  <li>
+    Add a Tkinter.Label component between the indicator and scale
+    components.  Modify the <code>_doCommand</code> method so that it
+    displays the current value of the scale in this label.
+
+  </li>
+  <li>
+    Modify the <strong>colors</strong> and <strong>threshold</strong>
+    options so that they both accept a tuple.  Now implement multiple
+    thresholds, so that the indicator displays one of several colors,
+    depending on the value of the scale.
+
+  </li>
+  <li>
+    Add an <strong>orient</strong> initialisation option and lay out
+    the components horizontally or vertically depending on its value.
+
+  </li>
+  <li>
+    Read the description of the <code>createlabel()</code> method in
+    the <a href="MegaArchetype.html">Pmw.MegaArchetype reference
+    manual</a> and add <strong>labelpos</strong> and
+    <strong>labelmargin</strong> initialisation options which allow
+    the creation of a label for the megawidget.
+
+  </li>
+</ol>
+
+<p>
+  An example of how these changes can be made can be seen
+  <a href="exercises.py">here</a>.
+
+</p>
+
+</dd>
+<dt> <h3>Contributing your megawidgets to Pmw</h3></dt><dd>
+
+<p>
+  If you have completed a megawidget that may be useful to others, you
+  may like to consider contributing it to Pmw.  See
+  <a href="starting.html#contributions">Contributions welcome</a> for
+  how to contribute.
+
+</p>
+
+</dd>
+<dt> <h3>Pmw coding conventions</h3></dt><dd>
+
+<p>
+As a final note, the Pmw code makes an attempt to follow these coding
+conventions.
+</p>
+
+<ul>
+  <li>
+    Class names: initial of each word is upper case (including first word).
+
+  </li>
+  <li>
+    Public method and function names: all in lower case.
+
+  </li>
+  <li>
+    Megawidget options: all in lower case.
+
+  </li>
+  <li>
+    Megawidget component names: all in lower case.
+
+  </li>
+  <li>
+    Function arguments: initial of each word is upper case (except first word).
+
+  </li>
+  <li>
+    Private names:  initial of each word is upper case (except first
+    word if not a class)
+
+  </li>
+  <li>
+    Underscores as word separators are only used when overriding
+    Tkinter methods of same name.
+
+  </li>
+  <li>
+    Indent is four spaces.
+
+  </li>
+  <li>
+    Continuation lines are indented by eight spaces, so that they
+    won't be confused with a following nested code block. 
+    Continuation lines should be used when a statement, which would
+    normally be written on one line, is longer than 80 characters. 
+    Examples are "if" statements which contain many conditions and
+    function calls with many arguments.
+
+  </li>
+  <li>
+
+    Surround <code>=</code> with spaces when used with keyword
+    parameters in function calls.
+
+  </li>
+  <li>
+
+    Multi-line function calls should have one keyword parameter per
+    line.
+
+  </li>
+</ul>
+</dd>
+</dl>
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/howtouse.html b/Pmw/Pmw_1_2/doc/howtouse.html
new file mode 100644 (file)
index 0000000..f7e43b9
--- /dev/null
@@ -0,0 +1,719 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>How to use Pmw megawidgets</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">How to use Pmw megawidgets</h1>
+    
+<center><P ALIGN="CENTER">
+<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+</p></center>
+
+<dl>
+<dt> <h3>Introduction</h3></dt><dd>
+<p>
+  This document briefly describes the features of the Pmw megawidget
+  toolkit and how to use the megawidgets.  Using examples, it
+  describes those features common to all Pmw megawidgets.  For a
+  description of individual Pmw megawidgets see the
+  <a href="refindex.html">reference manuals</a>.
+  For complete information on general Pmw megawidget functionality see the
+  <a href="MegaArchetype.html">Pmw.MegaArchetype reference manual</a>.
+  For a lot more example code, run any of the files in the
+  Pmw <code>demos</code> directory.
+
+</p>
+
+<p>
+  A simple example of a megawidget is a counter.  This widget
+  contains an entry field and two small arrow buttons.  Users may
+  enter a value directly into the entry field or they may use the
+  buttons to increment and decrement the value displayed without
+  having to use the keyboard.  Having this and other megawidgets in
+  your toolbox allows you to choose the best graphical interface for
+  your application.
+
+</p>
+</dd>
+<dt> <h3>Getting started</h3></dt><dd>
+
+<b>Initialisation of Pmw</b>
+<br>
+<p>
+  To run the examples in the tutorial, make sure that the
+  Pmw <code>lib</code> directory is in <code>sys.path</code>.  You
+  should be able to cut and paste the examples into an interactive
+  python session, or you can copy them to a file and run the file with
+  python.
+
+</p>
+<p>
+  The following two lines should be entered before any of the
+  examples.  These import and initialise Pmw.
+  For more information on <code>Pmw.initialise()</code> see the
+  <a href="PmwFunctions.html">Pmw functions reference manual</a>.
+
+</p>
+
+<dl>
+<dd>
+<pre>
+import Pmw
+root = Pmw.initialise()
+</pre>
+</dd>
+</dl>
+
+<p>
+  If necessary, you can have more control over how Tkinter and Pmw are
+  initialised by using this form of initialisation:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+import Tkinter
+root = Tkinter.Tk()
+import Pmw
+Pmw.initialise(root)
+</pre>
+</dd>
+</dl>
+
+</dd>
+<dt> <h3>Megawidget construction</h3></dt><dd>
+
+<b>Creating a counter</b>
+<br>
+<p>
+  Now that you have the formalities out of the way, you can create and
+  pack a counter megawidget (see
+  <a href="Counter.html">Pmw.Counter reference manual</a>) using
+  its default configuration like this:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter1 = Pmw.Counter()
+counter1.pack(padx = 10, pady = 10)
+</pre>
+</dd>
+</dl>
+
+<p>
+  Now enter a number and click on the arrow buttons to see the number
+  increment or decrement.  The result looks something like this:
+
+</p>
+
+<center><P ALIGN="CENTER">
+  <IMG SRC = counter1.gif ALT = "Counter 1" WIDTH=220 HEIGHT=46>
+</p></center>
+
+<p>
+  The above example creates the counter as a child of the root window. 
+  If you want to create it as a child of another window (for example,
+  a Tkinter.Frame widget called 'frame'), add the parent as an
+  argument to the constructor:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter1a = Pmw.Counter(frame)
+</pre>
+</dd>
+</dl>
+
+</dd>
+<dt> <h3>Methods</h3></dt><dd>
+<p>
+  Once a megawidget has been created, you can call any of its other
+  methods in a similar way to Tk widgets.  The following sets the value
+  of the counter and then increments it:
+</p>
+
+<dl>
+<dd>
+<pre>
+counter1.setentry(41)
+counter1.increment()
+</pre>
+</dd>
+</dl>
+
+</dd>
+<dt> <h3>Options</h3></dt><dd>
+<p>
+  Like any widget, a megawidget may have options to allow it to be
+  configured for a particular use.  Options allow the megawidget user
+  to modify the appearance and behaviour of the megawidget.  The
+  counter megawidget has several such options.  One of them,
+  <strong>datatype</strong>, specifies how the counter should count up
+  and down, such as, for example, by integers, reals, times or dates. 
+  The default value is <strong>'numeric'</strong>, which means the
+  counter expects integers to be entered and will support
+  incrementing and decrementing by whole numbers.
+  
+</p>
+  
+<p>
+  Another option is
+  <strong>increment</strong>, which specifies how many units should be
+  added or subtracted when the counter is incremented or decremented. 
+  Using these options, you can create a time counter, supporting the
+  format <strong>HH:MM:SS</strong>, and counting in minutes, like
+  this (note also the call to the <code>setentry</code> method to set
+  the contents of the entry field):
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter2 = Pmw.Counter(
+    datatype = 'time',
+    increment = 60)
+counter2.setentry('00:00:00')
+counter2.pack(padx = 10, pady = 10)
+</pre>
+</dd>
+</dl>
+
+<p>
+  Many megawidget options can be modified using the
+  <code>configure()</code> method.  For example, you can change the
+  value of the <strong>increment</strong> option to 10 minutes like
+  this:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter2.configure(increment = 60 * 10)
+</pre>
+</dd>
+</dl>
+
+<b>Initialisation options</b>
+<br>
+<p>
+  Some megawidget options can only be set when creating the megawidget.
+  These options can not be set by calling the <code>configure()</code>
+  method, but they can be queried in all the usual ways.  For example,
+  the counter has an <strong>orient</strong> initialisation option
+  which specifies whether the arrow buttons should appear to the
+  left and right of the entry field (<strong>'horizontal'</strong>)
+  or above and below (<strong>'vertical'</strong>).  You can create a
+  numeric counter with arrow buttons above and below the entry
+  field like this:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter3 = Pmw.Counter(orient = 'vertical')
+counter3.pack(padx = 10, pady = 10)
+</pre>
+</dd>
+</dl>
+
+<b>Querying options</b>
+<br>
+<p>
+  You can query the value of megawidget options (initialisation or
+  not) in similar ways as for normal Tkinter widgets.  For example,
+  the following code prints the values of some of the counter options.
+
+</p>
+
+<dl>
+<dd>
+<pre>
+print counter3.cget('increment')
+    --> 1
+print counter3.configure('orient')
+    --> ('orient', 'orient', 'Orient', 'horizontal', 'vertical')
+</pre>
+</dd>
+</dl>
+
+<p>
+  When a Tk widget option is queried, its value is always
+  returned as a string, regardless of the type used when setting the
+  option.  However, when a Pmw megawidget option is queried, a
+  reference to the object used when setting the option is returned. 
+  In other words it is not always a string.  For example, the type
+  returned by <code>cget('increment')</code> above was integer.
+
+</p>
+
+</dd>
+<dt> <h3>Components</h3></dt><dd>
+<p>
+  Megawidgets are made up of other widgets, which we call
+  <em>components</em>.  Each component is known by a logical name and
+  may be either a simple Tk widget, or may itself be a megawidget. 
+  Pmw gives the megawidget user access to not only the functionality
+  supported directly by the megawidget through its options and methods,
+  but also to the components of the megawidget and their options and
+  methods.  To access a component directly, use the
+  <code>component()</code> method.  For example, to call method
+  <strong>doit</strong> of component <strong>comp</strong>
+  of megawidget <strong>mega</strong>:
+
+  </p>
+
+<dl>
+<dd>
+<pre>
+mega.component('comp').doit()
+</pre>
+</dd>
+</dl>
+
+<b>Component options</b>
+<br>
+<p>
+  There is a short-hand way to access the options of components, by
+  using the notation <em>component_option</em>.  This allows, for
+  example, a counter megawidget to be configured with different
+  colored backgrounds for each of its arrow button components (these
+  components are called <strong>downarrow</strong> and
+  <strong>uparrow</strong>):
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter2.configure(
+    downarrow_background = 'green',
+    uparrow_background = 'red')
+</pre>
+</dd>
+</dl>
+
+<b>The hull</b>
+<br>
+<p>
+  All megawidgets are enclosed in a containing widget which is created
+  automatically by the Pmw base classes.  For normal megawidgets the
+  container is a Tkinter Frame widget.  For megawidgets which are
+  toplevel windows, the container is a Tkinter Toplevel widget.  The
+  containing widget is accessible as the <strong>hull</strong>
+  component.
+
+</p>
+
+<p>
+  To access options of the containing widget use the form
+  <strong>hull_</strong><em>option</em>.  For example to create a
+  counter megawidget with a wide sunken border around it: 
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter4 = Pmw.Counter(
+    hull_relief = 'sunken',
+    hull_borderwidth = 5 
+)
+</pre>
+</dd>
+</dl>
+
+
+<b>The interior</b>
+<br>
+<p>
+  Some megawidgets, such as Dialog and LabeledWidget, also have a
+  frame into which users can pack other widgets.  This frame may be a
+  component but can also be accessed with the <code>interior()</code>
+  method.  For the Pmw.MegaToplevel and Pmw.MegaWidget classes, the
+  interior widget is the same as the hull widget.  For other
+  megawidgets, the hull is the outer, containing widget and the
+  interior is the empty frame which can be used to extend the
+  megawidget by including extra internal widgets.
+
+</p>
+
+<b>Sub components and aliases</b>
+<br>
+<p>
+  Components may themselves be megawidgets and so their
+  (sub-)components can be referred to using the notation
+  <em>component_sub-component</em>.  For example, the
+  <strong>entryfield</strong> component of the counter is a
+  Pmw.EntryField megawidget (which handles the input validation).  In
+  turn, this has a Tkinter.Entry component named
+  <strong>entry</strong>.  Therefore, you can change the background of
+  the counter's Tkinter.Entry widget with:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter2.configure(entryfield_entry_background = 'yellow')
+</pre>
+</dd>
+</dl>
+
+<p>
+  Most component path names (like <strong>entryfield_entry</strong>)
+  have a shorter <strong>alias</strong> defined for them.  In this
+  case, you can use the equivalent:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter2.configure(entry_background = 'yellow')
+</pre>
+</dd>
+</dl>
+
+<b>Changing the python class of a component</b>
+<br>
+<p>
+  Each megawidget component is an instance of some python class.  The
+  default class of each component is given in the reference manual. 
+  By using the special <strong>pyclass</strong> component option, you
+  can specify a different python class to use when creating the
+  component.  For example, to create a Pmw.Counter megawidget which
+  has a Tkinter.Button as its label, rather than the default
+  Tkinter.Label:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+counter5 = Pmw.Counter(
+        labelpos = 'w',
+        label_text = 'Hello',
+        label_pyclass = Tkinter.Button
+)
+
+</pre>
+</dd>
+</dl>
+
+</dd>
+<dt> <h3>Forwarding methods</h3></dt><dd>
+<p>
+  Since a Pmw megawidget is a normal python class, it both inherits
+  methods from its base classes and also may have other methods
+  defined for it in the usual way.
+  Pmw also supports a third way that a megawidget may gain methods -
+  by 'forwarding' methods to one or more of its subwidgets.  This is 
+  also known as 'delegating'. 
+  For example, a Pmw.Counter megawidget delegates the methods related
+  to its Pmw.EntryField component, <strong>entryfield</strong>, to the
+  component.  It does not have to explicitely define methods which
+  call the component methods.
+  This is why we can call <strong>counter2.setentry()</strong> - since
+  <strong>setentry()</strong> is a method of the Pmw.EntryField
+  component, it is available to the Pmw.Counter.
+
+</p>
+<p>
+  Methods already defined by a class or its base classes take
+  precedence over delegated methods.  For example, Pmw.Counter
+  inherits a <strong>cget</strong> method from Pmw.MegaArchetype. 
+  Therefore, this method is not delegated to the <strong>cget</strong>
+  method of Pmw.EntryField.
+
+</p>
+  
+</dd>
+<dt> <h3>Extending Pmw megawidgets</h3></dt><dd>
+
+<p>
+  There are several ways of extending Pmw megawidgets.  Firstly, the
+  flexibility of the options and components allows the widget's
+  appearance and behaviour to be greatly modified.  Secondly, widgets
+  of the user's choice can be added inside some megawidgets by using
+  the interior() method.  The Pmw classes MegaToplevel, MegaWidget,
+  Dialog and LabeledWidget are particularly designed to be extended in
+  this way.  For example, to create a dialog window containing a
+  counter:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+dialog = Pmw.Dialog(
+        title = 'Counter dialog',
+        buttons = ('OK', 'Cancel'))
+interior = dialog.interior()
+counter = Pmw.Counter(interior)
+counter.pack(padx = 20, pady = 20)
+</pre>
+</dd>
+</dl>
+
+<center><P ALIGN="CENTER">
+  <IMG SRC = counter2.gif ALT = "Counter 2" WIDTH=266 HEIGHT=126>
+</p></center>
+
+<p>
+  A third way to extend megawidgets is to inherit from (or subclass)
+  them.  See <a href="howtobuild.html">How to build Pmw
+  megawidgets</a> for information on how to use inheritance to extend
+  a megawidget by adding new options.  For simpler cases, where new
+  methods are to be added to an existing megawidget and/or the default
+  values for some options are to be changed, normal subclassing can be
+  used.  For example, to create new classes based on a Pmw.Counter,
+  one with a new method <code>getminutes()</code> and one with a
+  default datatype of 'time' and a white entry background:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+class MinuteCounter1(Pmw.Counter):
+
+    def getminutes(self):
+       return Pmw.timestringtoseconds(self.getvalue()) / 60
+
+class MinuteCounter2(Pmw.Counter):
+
+    def __init__(self, parent = None, **kw):
+        kw['datatype'] = 'time'
+        kw['entry_background'] = 'white'
+        kw['entryfield_value'] = '00:00:00'
+        kw['increment'] = 60
+       apply(Pmw.Counter.__init__, (self, parent), kw)
+</pre>
+</dd>
+</dl>
+
+</dd>
+<dt> <h2>A quick example</h2></dt><dd>
+<p>
+  The following code is a small example of how to use Pmw megawidgets. 
+  It is a complete program which displays three ways for the user to
+  enter a value -  using an up-down counter, an entry field with
+  validation and a dropdown combobox.
+
+</p>
+<dl>
+<dd>
+<pre>
+import Pmw
+root = Pmw.initialise(fontScheme = 'pmw1')
+
+counter = Pmw.Counter(
+        label_text = 'Counter:',
+        labelpos = 'w',
+        entryfield_value = '00:00:00',
+        entryfield_validate = 'time',
+        datatype='time',
+        increment=5*60,
+)
+counter.pack(fill = 'x', padx = 10, pady = 10)
+
+entry = Pmw.EntryField(
+        label_text = 'Real entry:',
+        labelpos = 'w',
+        value = '+2.9979e+8',
+        validate = 'real',
+)
+entry.pack(fill = 'x', padx = 10, pady = 10)
+
+combo = Pmw.ComboBox(
+        label_text = 'ComboBox:',
+        labelpos = 'w',
+        scrolledlist_items = map(str, range(20))
+)
+combo.pack(fill = 'x', padx = 10, pady = 10)
+
+# Make the labels line up neatly
+Pmw.alignlabels((counter, entry, combo))
+
+root.title('Pmw megawidgets example')
+root.mainloop()
+</pre>
+</dd>
+</dl>
+
+<center><P ALIGN="CENTER">
+  <IMG SRC = example1.gif ALT = "Example 1" WIDTH=321 HEIGHT=140>
+</p></center>
+
+</dd>
+<dt> <h3>Another example</h3></dt><dd>
+<p>
+  The following also shows how to use Pmw megawidgets.  It displays a
+  RadioSelect megawidget and an exit button packed into the root
+  window.
+
+</p>
+
+<dl>
+<dd>
+<pre>
+import Tkinter
+import Pmw
+
+def callback(tag):
+    # This is called whenever the user clicks on a
+    # button in the RadioSelect widget.
+    print tag, 'was pressed.'
+
+# Initialise Tkinter and Pmw.
+root = Pmw.initialise(fontScheme = 'pmw1')
+root.title('Pmw RadioSelect demonstration')
+
+# Create and pack a RadioSelect widget.
+radio = Pmw.RadioSelect(
+        command = callback,
+        labelpos = 'w',
+        label_text = 'Food group:')
+radio.pack(padx = 20, pady = 20)
+
+# Add some buttons to the RadioSelect.
+for text in ('Fruit', 'Vegetables', 'Cereals', 'Legumes'):
+    radio.add(text)
+radio.invoke('Vegetables')
+
+# Create an exit button.
+exit = Tkinter.Button(text = 'Exit', command = root.destroy)
+exit.pack(pady = 20)
+
+# Let's go.
+root.mainloop()
+</pre>
+</dd>
+</dl>
+
+<center><P ALIGN="CENTER">
+  <IMG SRC = example2.gif ALT = "Example 2" WIDTH=503 HEIGHT=158>
+</p></center>
+
+</dd>
+<dt> <h3>Using the Tk option database</h3></dt><dd>
+<p>
+  There are several ways to use the Tk option database to customise a
+  Pmw application.  Firstly you can customise all the basic Tk widgets
+  in the usual way.  For example, to set the background of all
+  Tkinter.Label widgets (whether a megawidget component or not):
+
+</p>
+
+<dl>
+<dd>
+<pre>
+root.option_add('*Label.background', 'pink')
+</pre>
+</dd>
+</dl>
+
+<p>
+  To set the background of all Pmw.EntryField <strong>label</strong>
+  components:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+root.option_add('*EntryField.Label.background', 'green')
+</pre>
+</dd>
+</dl>
+
+<p>
+  To set the background of all Pmw.EntryField components, including
+  the <strong>hull</strong> component:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+root.option_add('*EntryField*background', 'blue')
+</pre>
+</dd>
+</dl>
+
+<p>
+  The above option settings affect basic Tk widgets and, since it is
+  built into the Tk widgets, this functionality is always available. 
+  However, to be able to use the Tk option database to set the default
+  values for Pmw megawidget options, <code>Pmw.initialise()</code>
+  must be called with <code>useTkOptionDb = 1</code>.  If this is not
+  done, Pmw does not query the Tk option database for megawidget
+  option defaults.  This is the default behaviour because there is a
+  slight performance penalty for using the Tk option database.
+
+</p>
+
+<p>
+  Assuming <code>useTkOptionDb</code> has been set, the default
+  buttonbox position of all Pmw.Dialog megawidgets can be changed
+  with:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+root.option_add('*Dialog.buttonboxpos', 'e')
+</pre>
+</dd>
+</dl>
+
+<p>
+  To set the label position of all Pmw.EntryField megawidgets, thus giving
+  them a <strong>label</strong> component by default:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+root.option_add('*EntryField.labelpos', 'w')
+</pre>
+</dd>
+</dl>
+
+</dd>
+</dl>
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/index.html b/Pmw/Pmw_1_2/doc/index.html
new file mode 100644 (file)
index 0000000..ef531a2
--- /dev/null
@@ -0,0 +1,131 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw megawidgets 1.2</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw 1.2</h1>
+    
+<h2 ALIGN="CENTER">Python megawidgets</h2>
+
+<center><P ALIGN="CENTER">
+<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+</p></center>
+
+<p>
+Pmw is a toolkit for building high-level compound widgets in Python
+using the Tkinter module.
+</p>
+
+<p>
+It consists of a set of base classes and a library of
+flexible and extensible megawidgets built on this foundation.  These
+megawidgets include notebooks, comboboxes, selection widgets, paned
+widgets, scrolled widgets, dialog windows, etc.
+
+</p>
+
+<p>
+<b>Local documentation</b>
+</p>
+
+<dl>
+<dd>
+
+    <IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="features.html">Main features</a>
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="starting.html">Getting started</a> - including downloading
+       and installation
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="howtouse.html">How to use Pmw megawidgets</a> - creating
+       and configuring megawidgets
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="howtobuild.html">How to build Pmw megawidgets</a> - inheriting
+       (sub-classing) from Pmw megawidgets
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="demosandtests.html">Demonstrations and tests</a> - how to run
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="dynamicloader.html">Dynamic loader</a> - also discusses how
+       to "freeze" Pmw
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="refindex.html">Reference manuals</a> - complete documentation
+       of all Pmw classes and functions
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="porting.html">Porting between different versions of Pmw</a>
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="changes.html">Change log</a>
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="todo.html">Todo list</a> and <a href="bugs.html">list of known bugs</a>
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+       <a href="copyright.html">Copyright</a>
+</dd>
+</dl>
+
+<p>
+<b>External links</b>
+</p>
+
+<dl>
+<dd>
+
+    <IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+    <a href="http://sourceforge.net/projects/pmw/">Pmw project home page
+    on SourceForge</a> - contains CVS source repository, bug tracking,
+    release distributions, mailing list, etc
+
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+    <a href="http://lists.sourceforge.net/lists/listinfo/pmw-general">Pmw-general
+    mailing list</a> - subscribe to this list to get announcements of
+    Pmw releases and general discussion on Pmw
+
+<br><IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14>
+    <a href="http://www.ifi.uio.no/~hpl/Pmw.Blt/doc/">A User's Guide
+       to Pmw.Blt</a>
+       - an excellent tutorial and reference covering the Pmw interface
+       to the powerful Blt graph widget, written by Bjørn Ove Thue
+       and Hans Petter Langtangen.  You can also download <a
+       href="http://www.ifi.uio.no/~hpl/Pmw.Blt/Pmw.Blt.doc.tar.gz">the full
+       HTML document</a> for local viewing.
+
+</dd>
+</dl>
+
+<p>
+See the 
+<a href="http://pmw.sourceforge.net/">Pmw megawidgets home page</a>
+for the latest information about Pmw.
+
+</p>
+
+<p>
+
+Comments, bugs, fixes to the <a
+href="http://lists.sourceforge.net/lists/listinfo/pmw-general">Pmw
+discussion and announcement mailing list</a>.
+
+</p>
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+    
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/porting.html b/Pmw/Pmw_1_2/doc/porting.html
new file mode 100644 (file)
index 0000000..64a7cb5
--- /dev/null
@@ -0,0 +1,325 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Porting between different versions of Pmw</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Porting between different versions of Pmw</h1>
+    
+<p>
+    This document contains a brief guide to porting existing code
+    between different versions of Pmw.  It includes significant
+    functionality changes but does not include bug fixes or compatible
+    enhancements.  For details of all changes, see
+    <a href="changes.html">Changes to Pmw versions</a>.</p>
+
+<p>    <strong>Porting from 0.8.5 to 1.0, 1.1 and 1.2</strong></p>
+
+<ul><li><p>Bug fix, documention and new features only.  No
+      backwards-incompatible changes.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.8.4 to 0.8.5</strong></p>
+
+<ul><li><p>Bug fix release only. No interface changes.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.8.3 to 0.8.4</strong></p>
+
+<ul><li><p>Change the <code>setnaturalpagesize()</code> method of Pmw.NoteBook to
+      <code>setnaturalsize()</code> (to be consistent with Pmw.PanedWidget).</p>
+
+</li>
+<li><p>Change Pmw.excludefrombusycursor() to Pmw.setbusycursorattributes().
+      Replace busyCursorName option of Pmw.initialise() with
+      cursorName attribute of Pmw.setbusycursorattributes().</p>
+
+</li>
+<li><p>Several rarely used key bindings for Pmw.ScrolledListBox were
+      removed, changing the behaviour of the megawidget.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.8.1 to 0.8.3</strong></p>
+
+<ul><li><p>The megawidgets Pmw.NoteBookR and Pmw.NoteBookS have been
+      replaced by a new Pmw.NoteBook.  The interfaces are not
+      compatible, so see the Pmw.NoteBook reference manual for
+      details.</p>
+
+</li>
+<li><p>Change the get() method of Pmw.OptionMenu to getcurselection()
+      and the remove() method of Pmw.PanedWidget to delete().</p>
+
+</li>
+<li><p>If you use <strong>'end'</strong>, <strong>'default'</strong> or <strong>None</strong> in calls to the
+      index() method of several megawidgets, change these to
+      <strong>Pmw.END</strong>, <strong>Pmw.DEFAULT</strong> and <strong>Pmw.SELECT</strong>, respectively.</p>
+
+</li>
+<li><p>The exclude argument has been removed from Pmw.showbusycursor(). 
+      Use Pmw.excludefrombusycursor() instead.</p>
+
+</li>
+<li><p>The names of some of the positional arguments in the following
+      methods have changed:  MegaArchetype.createcomponent(),
+      ButtonBox.insert(), ButtonBox.add(), MenuBar.addcascademenu(),
+      MenuBar.addmenuitem() and RadioSelect.add().</p>
+
+</li>
+<li><p>The Pmw.maxfontwidth() function has been removed.  Use the
+      <code>font_measure()</code> Tkinter method, or if that has not yet been
+      implemented:</p>
+<dl><dd><pre> someWidget.tk.call('font', 'measure', someFont, 'W')</pre></dd></dl>
+
+
+</li>
+<li><p>The Pmw.fontexists() function has been removed.  This is
+      because, since Tk8.0, all fonts exist, so it no longer has
+      any meaning.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.8 to 0.8.1</strong></p>
+
+<ul><li><p>The Blt.Graph now supports blt2.4i which is not backwards
+      compatible with blt2.1.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.7 to 0.8</strong></p>
+
+<ul><li><p>The <em>format</em> argument of Pmw.datestringtojdn() now defaults to
+      <strong>'ymd'</strong>.  If you want to display dates with year, month and day
+      in a different order, add a <em>format</em> option to
+      Pmw.datestringtojdn() or to the <strong>datatype</strong> option of Pmw.Counter
+      or the <strong>validate</strong> option of Pmw.EntryField.</p>
+
+</li>
+<li><p>The justify() method from Pmw.ScrolledListBox has been removed. 
+      Use the xview() or yview() methods instead.</p>
+
+</li>
+<li><p>Replace the getFrame() method of Pmw.ScrolledFrame with the
+      interior() method.</p>
+
+</li>
+<li><p>Replace the <strong>ringpadx</strong> and <strong>ringpady</strong> options of Pmw.Group by
+      padding the megawidget itself or by padding the children of the
+      megawidget. </p>
+
+</li>
+<li><p>Replace the canvasbind() and canvasunbind() methods of
+      Pmw.Balloon with tagbind() and tagunbind().</p>
+
+</li>
+<li><p>The return value of Pmw.EntryField <strong>command</strong> callback is now
+      ignored.  Previously, if the callback destroyed the megawidget,
+      it was required to return the string <strong>'break'</strong>, to work around a
+      problem in the event handling mechanism in Tkinter.  With python
+      1.5.2, Tkinter has been fixed.  Therefore, user-supplied
+      callback functions should use Pmw.hulldestroyed to check if the
+      megawidget has been destroyed before performing any operations
+      on it.</p>
+
+</li>
+<li><p>If you require the <strong>'pmw1'</strong> fontScheme when running under
+      Microsoft Windows and Macintosh, you will need to set the Tk
+      font options manually.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.6 to 0.7</strong></p>
+
+<ul><li><p>Replace the <strong>maxwidth</strong> option of Pmw.EntryField with the <strong>'max'</strong>
+      field of the <strong>validate</strong> option.</p>
+
+</li>
+<li><p>To specify that there should be no validation performed for a
+      Pmw.EntryField, the <strong>validate</strong> option must be None, not <strong>''</strong> as
+      before.</p>
+
+</li>
+<li><p>The date and time values of the Pmw.EntryField <strong>validate</strong> option
+      (such as <strong>'date_dmy'</strong> and <strong>'time24'</strong>, etc) are no longer supported. 
+      Instead use a dictionary as the value of the <strong>validate</strong> option
+      with <strong>'date'</strong> or <strong>'time'</strong> in the <strong>'validator'</strong> field.  Include
+      other fields in the dictionary to further specify the
+      validation.</p>
+
+</li>
+<li><p>Pmw.Counter no longer supports the old date and time values for
+      the <strong>datatype</strong> option.  Use a dictionary with a <strong>'counter'</strong>
+      field of <strong>'date'</strong> or <strong>'time'</strong> and other fields to further
+      specify the counting.</p>
+
+</li>
+<li><p>Pmw.Counter no longer supports the <strong>min</strong> and <strong>max</strong> options.  Use
+      the Pmw.EntryField <strong>validate</strong> option instead.</p>
+
+</li>
+<li><p>The bbox method of Pmw.ScrolledListBox now refers to the bbox
+      method of the <strong>listbox</strong> component, not the <strong>hull</strong> component.</p>
+
+</li>
+<li><p>By default, Pmw.MenuBar now automatically adds hotkeys to menus
+      and menu items for keyboard traversal.  To turn this off, use the
+      <code>hotkeys = 0</code> option.</p>
+
+</li>
+<li><p>The createcomponent() method now disallows the creation of
+      component names containing an underscore.  If any component
+      names contain an underscore, rename them.</p>
+
+</li></ul>
+<p>    <strong>Porting from 0.5 to 0.6</strong></p>
+
+<p>    To port applications using Pmw version 0.5 to version 0.6, make
+    sure you are using python1.5.  Then, simply change any lines in
+    your application like this:</p>
+
+<dl><dd><pre> from PmwLazy import Pmw</pre></dd></dl>
+
+<p>    to this:</p>
+
+<dl><dd><pre> import Pmw</pre></dd></dl>
+
+<p>    Also, if you have added the <code>lib</code> directory of a specific version
+    of Pmw to <code>sys.path</code> or <code>PYTHONPATH</code>, this can be removed, as long
+    as Pmw can now be found from the default path, such as in the
+    python <code>site-packages</code> directory.</p>
+
+<p>    <strong>Porting from 0.2 to 0.4</strong></p>
+
+<ul><li><p>To get Pmw.0.2 default fonts (helvetica with bold italic menus
+      and italic scales) initialise with:</p>
+<dl><dd><pre> Pmw.initialise(fontScheme = 'pmw1')</pre></dd></dl>
+
+<p>      If no <strong>fontScheme</strong> is given, the standard Tk default fonts are used.</p>
+
+
+</li>
+<li><p>Remove all calls to setdefaultresources(), usual(), keep(),
+      renameoptions(), ignore() and defineoptiontypes().</p>
+
+</li>
+<li><p>Move call to defineoptions() to before call to base class
+      constructor, create optiondefs tuple from self.defineoptions
+      arguments, then call defineoptions().</p>
+
+</li>
+<li><p>Remove resource class and name from optiondefs.</p>
+
+</li>
+<li><p>The last element in the optiondefs tuple (callback function)
+      must be given (may be None).</p>
+
+</li>
+<li><p>Add to classes currently without any options:</p>
+<dl><dd><pre> optiondefs = ()
+ self.defineoptions(kw, optiondefs)</pre></dd></dl>
+
+
+</li>
+<li><p>Use createcomponent() to create components - this replaces the
+      calls to the component widget constructor and to
+      registercomponent().</p>
+
+</li>
+<li><p>Do not inherit from Pmw.LabeledWidget.  Instead, replace with
+      Pmw.MegaWidget with labelpos and labelmargin options and a call
+      to self.createlabel().  If calling createlabel(), must replace
+      pack() with grid().</p>
+
+</li>
+<li><p>When calling a megawidget constructor, include subcomponent name when
+      setting subcomponent options (eg labeltext -&gt; label_text)</p>
+
+</li>
+<li><p>The items option of ScrolledListBox is an initialisation option
+      only - use setlist() method after initialisation.</p>
+
+</li>
+<li><p>The <strong>autorelief</strong> option for Counter, EntryField, ScrolledText,
+      TextDialog has been removed.</p>
+
+</li>
+<li><p>ScrolledListBox.getcurselection() always returns a tuple of strings,
+      possibly of zero length.</p>
+
+</li>
+<li><p>Counter increment is always initialised to 1.</p>
+
+</li>
+<li><p>The <strong>'time'</strong> Counter <strong>datatype</strong> option has been replaced by
+      <strong>'timeN'</strong> and <strong>'time24'</strong>.</p>
+
+</li>
+<li><p>The <strong>'time'</strong> EntryField <strong>validate</strong> option has been replaced by
+      <strong>'timeN'</strong> and <strong>'time24'</strong>.</p>
+
+</li>
+<li><p>Replace call to initialise() with initialiseoptions(), removing
+      "kw" arg.  This should always be the last line in a megawidget
+      constructor.</p>
+
+</li>
+<li><p>Replace hide() with withdraw().</p>
+
+</li>
+<li><p>Now need iconpos option for MessageDialogs with icon_bitmap option set.</p>
+
+</li>
+<li><p>Example megawidget class definition:</p>
+
+</li></ul>
+<dl><dd><pre>class MyBigWidget(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+        # Define the megawidget options.
+        optiondefs = (
+            ('errorbackground',   'pink',      None),
+            ('maxwidth',          0,           self._myfunc),
+            ('myinit',            'good',      Pmw.INITOPT),
+        )
+        self.defineoptions(kw, optiondefs)
+
+        # Initialise the base class (after defining the options).
+        Pmw.MegaWidget.__init__(self, parent)
+
+        # Create the components.
+        interior = self.interior()
+        self._widget = self.createcomponent('component',
+                (('alias', 'component_alias'),), None,
+                Tkinter.Button, (interior,))
+        self._widget.grid(column=0, row=0, sticky='nsew')
+
+        self.createlabel(interior)
+
+        # Initialise instance variables.
+        self.deriveddummy = None
+
+        # Check keywords and initialise options.
+        self.initialiseoptions(MyBigWidget)
+</pre></dd></dl>
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/refindex.html b/Pmw/Pmw_1_2/doc/refindex.html
new file mode 100644 (file)
index 0000000..19a549e
--- /dev/null
@@ -0,0 +1,79 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw reference manual index</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw reference manual<br>index</h1>
+    
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+<dl><dt> <strong>Base classes</strong></dt><dd>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MegaArchetype.html">Pmw.MegaArchetype</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MegaWidget.html">Pmw.MegaWidget</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MegaToplevel.html">Pmw.MegaToplevel</a>
+</dd></dl>
+<dl><dt> <strong>Widgets</strong></dt><dd>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ButtonBox.html">Pmw.ButtonBox</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ComboBox.html">Pmw.ComboBox</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="Counter.html">Pmw.Counter</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="EntryField.html">Pmw.EntryField</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="Group.html">Pmw.Group</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="HistoryText.html">Pmw.HistoryText</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="LabeledWidget.html">Pmw.LabeledWidget</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MainMenuBar.html">Pmw.MainMenuBar</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MenuBar.html">Pmw.MenuBar</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MessageBar.html">Pmw.MessageBar</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="NoteBook.html">Pmw.NoteBook</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="OptionMenu.html">Pmw.OptionMenu</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="PanedWidget.html">Pmw.PanedWidget</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="RadioSelect.html">Pmw.RadioSelect</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ScrolledCanvas.html">Pmw.ScrolledCanvas</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ScrolledField.html">Pmw.ScrolledField</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ScrolledFrame.html">Pmw.ScrolledFrame</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ScrolledListBox.html">Pmw.ScrolledListBox</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ScrolledText.html">Pmw.ScrolledText</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="TimeCounter.html">Pmw.TimeCounter</a>
+</dd></dl>
+<dl><dt> <strong>Dialogs</strong></dt><dd>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="AboutDialog.html">Pmw.AboutDialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="ComboBoxDialog.html">Pmw.ComboBoxDialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="CounterDialog.html">Pmw.CounterDialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="Dialog.html">Pmw.Dialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="MessageDialog.html">Pmw.MessageDialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="PromptDialog.html">Pmw.PromptDialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="SelectionDialog.html">Pmw.SelectionDialog</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="TextDialog.html">Pmw.TextDialog</a>
+</dd></dl>
+<dl><dt> <strong>Miscellaneous</strong></dt><dd>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="Balloon.html">Pmw.Balloon</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="Blt.html">Pmw.Blt</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="Color.html">Pmw.Color</a>
+<IMG SRC = blueball.gif ALT = "" WIDTH=14 HEIGHT=14><a href="PmwFunctions.html">Module functions</a>
+</dd></dl>
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/scale1.gif b/Pmw/Pmw_1_2/doc/scale1.gif
new file mode 100644 (file)
index 0000000..5cf5d60
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/scale1.gif differ
diff --git a/Pmw/Pmw_1_2/doc/scale2.gif b/Pmw/Pmw_1_2/doc/scale2.gif
new file mode 100644 (file)
index 0000000..5682715
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/scale2.gif differ
diff --git a/Pmw/Pmw_1_2/doc/starting.html b/Pmw/Pmw_1_2/doc/starting.html
new file mode 100644 (file)
index 0000000..be44745
--- /dev/null
@@ -0,0 +1,382 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Getting started with Pmw</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Getting started with Pmw</h1>
+    
+<center><P ALIGN="CENTER">
+<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+</p></center>
+
+<dl>
+<dt> <h2>Introduction</h2></dt><dd>
+<p>
+This document describes how to fetch and install Pmw, and how to run
+the demonstrations and tests.
+
+</p>
+
+</dd>
+<dt> <h2>Requirements</h2></dt><dd>
+<p>
+Pmw.1.2 requires the _tkinter and Tkinter modules.  It works
+with python versions 1.5.2 and greater (tested up to 2.2.1) and Tk
+versions 8.0 and greater (tested up to 8.3.2).
+
+</p>
+
+<p>
+If the BLT extension to Tk is present, Pmw will use the BLT busy
+command during modal dialogs to display a clock cursor.  Also, the
+Pmw.Blt interface to the BLT busy, graph, stripchart, tabset and
+vector commands will be available.  BLT versions 2.4i and greater are
+supported (tested up to 2.4u).  You can find BLT at
+<a href="http://www.tcltk.com/blt/">http://www.tcltk.com/blt/</a>.
+
+</p>
+
+</dd>
+<dt> <h2>Distribution and installation</h2></dt><dd>
+<p>
+Releases of the Pmw distribution are available via http from
+<code>http://download.sourceforge.net/pmw/</code>.  This release is available
+as <a href="http://download.sourceforge.net/pmw/Pmw.1.2.tar.gz">
+<code>Pmw.1.2.tar.gz</code></a>, released on 5 August 2003. 
+This is a compressed tar file.  Under Linux, Unix, etc, you will need to
+unpack it using <code>tar</code> and you may also need to use
+<code>gzip</code> or <code>gunzip</code> to uncompress it.
+Under Microsoft Windows, you will need a program such as WinZip (<a
+href="http://www.winzip.com">http://www.winzip.com</a>) that can
+unpack the gzipped tar files.  You may need to change the suffix of
+the file to <strong>.tgz</strong> for WinZip to recognise it.
+
+</p>
+
+<p>
+
+This will unpack into a directory named Pmw.  You now need to put this
+directory somewhere python can find it, preferably in one of the
+standard places, such as in the <code>site-packages</code> directory
+(eg: <code>/usr/lib/python2.2/site-packages/Pmw</code>) or the
+<code>sys.prefix</code> directory (eg: <code>C:\Program
+Files\Python\Pmw</code> or <code>/usr/lib/python2.2</code>).
+
+</p>
+
+<p>
+
+For example, under Unix, assuming you have placed the tar file in the
+<code>/tmp</code> directory, you can simply run the following
+commands:
+
+</p>
+
+<dl>
+<dd>
+<pre>
+cd /usr/lib/python2.2/site-packages
+gunzip /tmp/Pmw.1.2.tar.gz (or gzip -d /tmp/Pmw.1.2.tar.gz)
+tar xvf /tmp/Pmw.1.2.tar
+</pre>
+</dd>
+</dl>
+
+<p>
+
+If you do not have write permission for these standard directories,
+place the Pmw
+directory somewhere on your <code>PYTHONPATH</code> or
+<code>sys.path</code>.  If this is not possible, place the Pmw
+directory somewhere else and add the parent directory to your
+<code>PYTHONPATH</code> or <code>sys.path</code>.
+
+</p>
+
+<p>
+
+If you have previously installed Pmw version 0.6 or later, then the
+new version can share the same <code>Pmw</code> directory as the
+previous versions.  You will need to perform the <code>tar</code>
+extraction in the directory containing (that is, the parent directory
+of) the existing <code>Pmw</code> directory.  By default, your
+applications will use the most recent version of Pmw.  If required,
+the function <code>Pmw.setversion()</code> can be used to specify a
+version to be used.  See the reference manual for details.  If you are
+no longer using the older versions, you can safely remove the
+corresponding subdirectories from the <code>Pmw</code> directory.
+
+</p>
+
+<p>
+
+If you need assistance in installing BLT under Unix, please contact me
+(<a href="mailto:gregm@iname.com"><i>gregm@iname.com</i></a>) and I
+will try to help.  For other operating systems, such as Microsoft or
+Macintosh, you should try asking the python newsgroup.  If anyone can
+give me a description of how to install BLT under other operating
+systems please contribute it and I will place it here.
+
+</p>
+
+</dd>
+<dt> <h2>Documentation</h2></dt><dd>
+<p>
+The <code>doc</code> directory for each Pmw version contains all the
+documentation for that version of Pmw.  See the local <a
+href="index.html">home page</a> for a complete list of documents.  The
+files in this directory are also available from the <a
+href="http://pmw.sourceforge.net/">official Pmw home page</a>.
+
+</p>
+
+<p>
+An excellent tutorial and reference covering the Pmw interface to the
+powerful Blt graph widget, "<a
+href="http://www.ifi.uio.no/~hpl/Pmw.Blt/doc/">A User's Guide to
+Pmw.Blt</a>" written by Bjørn Ove Thue and Hans Petter Langtangen, is
+available.  You can also download <a
+href="http://www.ifi.uio.no/~hpl/Pmw.Blt/Pmw.Blt.doc.tar.gz">the full
+HTML document</a> for local viewing.
+
+</p>
+</dd>
+<dt> <h2>Demonstrations and tests</h2></dt><dd>
+<p>
+  A good way to get an overview of the functionality provided by Pmw
+  is to run the demonstrations and tests and look at the demonstration
+  code.  To view a comprehensive demonstration of many of the features
+  of Pmw run the <code>All.py</code> script, which can be found in the
+  <code>demos</code> subdirectory of each version of Pmw.
+</p>
+
+<p>
+
+  You do not have to install Pmw to run the demonstrations and tests,
+  simply change into the appropriate directory and run the file
+  <code>All.py</code>.  See <a
+  href="demosandtests.html">Demonstrations and tests</a> for more
+  information about running the demonstrations and tests and how to
+  create your own.
+</p>
+
+<p>
+
+Note that there are some bugs in later versions of BLT (at least 2.4t
+and 2.4u) which cause some tests of Pmw.Blt.Graph to crash with
+python2.0 under Linux.  These tests have been commented out (until BLT
+is fixed).
+
+<a name=contributions></a>
+</dd>
+<dt> <h2>Contributions welcome</h2></dt><dd>
+
+<p>
+If you create some whiz-bang megawidgets and would like to contribute
+them to Pmw, they will be most welcome.  You should be able to get
+some idea of the coding style used in Pmw code by reading <a
+href="howtobuild.html">How to build Pmw megawidgets</a> and by looking
+at the Pmw library code itself in the <code>lib</code> directory of
+each Pmw version.
+
+</p>
+
+<p>
+If you would like to contribute a megawidget, it would be preferable if it
+also came with a simple demonstration and a test script.  See <a
+href="demosandtests.html">Demonstrations and tests</a> for information
+about how to create new demonstrations and tests.
+</p>
+
+<p>
+Each megawidget should also have a reference manual describing its
+options, components and methods.
+
+</p>
+
+<a name=docgen></a>
+</dd>
+<dt> <h2>Generating the documentation</h2></dt><dd>
+
+<p>
+The released reference manuals are
+automatically generated by merging specially marked-up text with the
+output from megawidget query methods, such as
+<code>components()</code>, <code>options()</code> and
+<code>componentaliases()</code>, and various other introspective
+devices.  If you are interested to see how the documentation is generated,
+you can fetch the marked-up text and the python script to convert the
+text to html from
+<a href="http://download.sourceforge.net/pmw/Pmw.1.2.docsrc.tar.gz">
+<code>http://download.sourceforge.net/pmw/Pmw.1.2.docsrc.tar.gz</code>
+</a>.  Download this
+file into the <code>Pmw/Pmw_1_2</code> directory of the Pmw source
+tree.  Unzip and untar the file.  This will create a
+<code>docsrc</code> sub-directory of <code>Pmw/Pmw_1_2</code>.  If
+you want to keep the documentation which came with the Pmw
+distribution, rename the old <code>doc</code> directory.  Then change
+directory to <code>docsrc</code> and run <code>createmanuals.py</code>.
+After printing lots of warnings about documentation that has not been
+written yet, this will create a new <code>doc</code> directory
+containing all the html documentation.
+</p>
+
+<p>
+Here is an example set of commands to unpack the documentation source
+and regenerate the documentation, assuming you have downloaded the
+source in the Pmw/Pmw_1_2 directory:
+</p>
+
+<dl>
+<dd>
+<pre>
+cd Pmw/Pmw_1_2
+gunzip Pmw.1.2.docsrc.tar.gz
+tar xvf Pmw.1.2.docsrc.tar
+mv doc doc.old
+cd docsrc
+./createmanuals.py
+</pre>
+</dd>
+</dl>
+
+<p>
+If running under Unix, you will need to run the
+<code>createmanuals.py</code> script with a valid DISPLAY environment
+variable, since it creates each megawidget and then queries it for its
+options, components, etc.  This is because Tk (and hence Tkinter)
+requires a connection to an X server to run.
+
+</p>
+
+</dd>
+<dt> <h2>Future plans and bugs</h2></dt><dd>
+
+<p>
+The <a href="todo.html">todo list</a> contains a long list of of
+suggestions, bugs and enhancements for Pmw.  If you are interested in
+doing any of these, please let the maintainer
+(<a href="mailto:gregm@iname.com"><i>gregm@iname.com</i></a>) know.
+Some of the items in the todo list may be considered bugs.  There are
+also some other problems due to idiosyncrasies in the implementation
+of Tk.
+
+</p>
+
+</dd>
+<dt> <h2>Licence</h2></dt><dd>
+
+<p>
+The official Pmw licence (see <a href="copyright.html">copyright</a>)
+basically lets you do anything with Pmw as long as you don't hurt anyone.
+There is also another licence, the "Postcard Licence":
+</p>
+<cite>
+"I'd like to get a postcard from you!  I'm interested in who is using
+Pmw, where you live and where in the world Pmw is doing it's job"
+</cite>
+<p>
+Please send me an e-mail to
+<a href="mailto:gregm@iname.com"><i>gregm@iname.com</i></a>
+to get my postal address.
+</p>
+
+</dd>
+<dt> <h2>Acknowledgements</h2></dt><dd>
+
+<p>
+The initial ideas for Pmw were blatantly stolen from the itcl
+extensions
+<a href="http://www.tcltk.com/itk">[incr Tk]</a>
+by Michael McLennan and
+<a href="http://www.tcltk.com/iwidgets">[incr Widgets]</a>
+by Mark Ulferts.  Several of the megawidgets are direct translations
+from the itcl to python.
+</p>
+
+<p>
+The base classes and most megawidgets were written by Greg McFarlane
+and Peter Munnings.  Contributed megawidgets include:  Pmw.TimeCounter
+by Joe VanAndel, Pmw.Group and an early version of Pmw.NoteBook by Case Roole,
+Pmw.ScrolledCanvas, Pmw.ScrolledFrame and another early version of
+Pmw.NoteBook by Joe Saltiel
+and Pmw.OptionMenu by Roman Sulzhyk.  A big thank you to the following
+people for their bug reports, fixes, enhancements and suggestions:
+
+David Ascher,
+Robin Becker,
+Siggy Brentrup,
+Mark Colclough,
+Jerome Gay,
+Clemens Hintze,
+Rob Hooft
+Jack Jansen,
+Jonathan Kelly,
+Magnus Kessler,
+Matthias Klose,
+Andreas Kostyrka,
+Fredrik Lundh,
+Magnus Lycka,
+Graham Matthews,
+Dieter Maurer,
+Michael McLay,
+Daniel Michelson,
+Georg Mischler,
+Rob Pearson,
+Case Roole,
+Joe Saltiel,
+Roman Sulzhyk,
+Shen Wang,
+Chris Wright,
+  and
+Guido van Rossum.
+
+Special thanks to Case Roole and Michael McLay for help with getting
+Pmw to work with python packages and many other nifty features.
+
+My deepest apologies if I have forgotten anyone. Please let me know.
+
+</p>
+    
+<p>
+The Pmw home page and project site is made available courtesy of
+<a href="http://sourceforge.net">SourceForge</a>.
+
+</p>
+<p>
+
+The current maintainer is Greg McFarlane.  I monitor the <a
+href="http://lists.sourceforge.net/lists/listinfo/pmw-general">Pmw
+discussion and announcement mailing list</a> so please send any
+problems, comments, suggestions or enhancements to the list.  You may
+also contact me directly at <a
+href="mailto:gregm@iname.com"><i>gregm@iname.com</i></a>.
+
+</p>
+</dd>
+</dl>
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/todo.html b/Pmw/Pmw_1_2/doc/todo.html
new file mode 100644 (file)
index 0000000..9ca6889
--- /dev/null
@@ -0,0 +1,1111 @@
+
+    <html>
+    <head>
+    <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
+    <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
+    <title>Pmw todo list</title>
+    </head>
+
+    <body bgcolor="#ffffff" text="#000000" link="#0000ee"
+       vlink="551a8b" alink="ff0000">
+
+    <h1 ALIGN="CENTER">Pmw todo list</h1>
+    
+<p>
+This is a long list of suggestions and enhancements for Pmw.  If
+you are interested in doing any of these, please let the Pmw maintainer
+(<em>gregm@iname.com</em>) know.</p>
+
+<p><strong>New Pmw megawidgets</strong></p>
+<ul><li><p>Multicolumn listbox.</p>
+<p>      Useful features - smooth scrolling, embedded images, different
+      fonts and colours, text correctly masked when it is longer than
+      its column width, interactive resizing of columns.</p>
+
+<p>      Probably should be implemented as canvas widget rather than by
+      using multiple frames or multiple listboxes.  There would be a
+      lot of work needed to position all the elements - you can't just
+      pack or grid them.</p>
+
+
+</li>
+<li><p>File dialog.</p>
+
+</li>
+<li><p>Main window class (App class), with menu bar, information line
+      with status boxes and an about box.  (See iwidgets' mainwindow
+      class for example.) This should handle creation of multiple main
+      windows, recycling of unused main windows and should exit if
+      last open main window is closed.</p>
+
+</li>
+<li><p>Searchable text megawidget.</p>
+
+</li>
+<li><p>Tree browser.</p>
+
+</li>
+<li><p>Check out Doug Hellmann's contributed megawidgets at
+      &lt;http://www.mindspring.com/~doughellmann/Projects/PmwContribD&gt; or
+      &lt;http://members.home.net/doughellmann/PmwContribD/&gt;
+      and integrate into Pmw.</p>
+
+</li></ul>
+
+<p><strong>Changes to current megawidgets</strong></p>
+<p>    MegaToplevel</p>
+<ul><li><p>Modify activate() geometry argument to allow window positioning
+          relative to the pointer, another window or the screen and
+          allow the centering of the window relative to the
+          positioning point or by a specified offset.  Also add the
+          ability to position the window so that the mouse is over a
+          particular widget in the toplevel.</p>
+<p>          Should handle all combinations of</p>
+<dl><dd><pre> when (always/first)
+ where (center/geometry/mouse)
+ parent (screen/window)
+
+ and None (don't position)</pre></dd></dl>
+
+
+<p>          Check Tix4.1.0/library/DialogS.tcl center method for how to
+          center over another window</p>
+
+<p>          Check iwidget's shell.itk for code to center widget over
+          screen or another widget.</p>
+
+<p>          See Pmw.Balloon code for how to position over pointer.</p>
+
+<p>          Tcl code to center over another (parent) window:</p>
+<dl><dd><pre> # center client relative to master (default xoff, yoff = -1)
+ set geomaster [split [wm geometry $master] "x+"]
+ set geoclient [split [wm geometry $client] "x+"]
+
+ if {$xoff == -1} {
+   set xoff [expr (
+     ([lindex $geomaster 0] - [lindex $geoclient 0]) / 2)]
+ }
+ set newxpos [expr [lindex $geomaster 2] + $xoff]
+
+ if {$yoff == -1} {
+   set yoff [expr (
+     ([lindex $geomaster 1] - [lindex $geoclient 1]) / 2)]
+ }
+ set newypos [expr [lindex $geomaster 3] + $yoff]
+
+ wm geometry $client +$newxpos+$newypos</pre></dd></dl>
+
+
+<p>          More tcl code to center dialog over another (parent) window:</p>
+<dl><dd><pre> (args: parent dlg)
+ # First, display the dialog offscreen to get dimensions.
+ set screenW [winfo screenwidth $parent]
+ set screenH [winfo screenheight $parent]
+ set w [expr $screenW + 1]
+ wm geometry $dlg +$w+0
+ update
+
+ # Get relative center of parent. 
+ set w [winfo width $parent]
+ set h [winfo height $parent]
+ set w [expr $w/2]
+ set h [expr $h/2]
+
+ # Get and add screen offset of parent.
+ set w [expr $w + [winfo rootx $parent]]
+ set h [expr $h + [winfo rooty $parent]]
+
+ # Get dimensions of dialog.
+ set dlgW [winfo width $dlg]
+ set dlgH [winfo height $dlg]
+
+ # Make adjustments for actual dimensions of dialog.
+ set w [expr $w - $dlgW / 2]
+ set h [expr $h - $dlgH / 2]
+
+ # Let's keep the entire dialog onscreen at all times.
+ # Center in screen if things are awry.
+ set recenter 0
+ if { $w &lt; 0 } { set recenter 1 }
+ if { $h &lt; 0 } { set recenter 1 }
+ if { [expr $w + $dlgW] &gt; $screenW } { set recenter 1 }
+ if { [expr $h + $dlgH] &gt; $screenH } { set recenter 1 }
+ if { $recenter } {
+   set w [expr ($screenW -$dlgW) / 2]
+   set h [expr ($screenH - $dlgH) / 2]
+ }
+
+ wm geometry $dlg +$w+$h</pre></dd></dl>
+
+
+
+</li>
+<li><p>Add geometry argument to show() (same as activate() above).</p>
+
+</li></ul>
+
+<p>    Dialog</p>
+<ul><li><p>Add label (header?) to Dialog class.  May not be necessary, or
+          too complicated.</p>
+
+</li></ul>
+
+<p>    ButtonBox</p>
+<ul><li><p>When a horizontal ButtonBox is stretched, the left button
+          stays anchored to the left edge and there is too much space
+          between the last button and the right edge.</p>
+
+</li>
+<li><p>Add an option to either evenly space the buttons across the
+          button box, or to keep them together and justify them to the
+          left, right or center.  Check that deleting buttons works
+          correctly.</p>
+
+</li></ul>
+
+<p>    ComboBox</p>
+<ul><li><p>Remove arrowrelief option from ComboBox and do what counter
+          does:  gets value of arrow's relief just before sinking it,
+          then restores it later.</p>
+
+</li>
+<li><p>Change bindings: remove all bindings from arrow key and remove
+          arrow key from &lt;tab&gt; focus sequence; only implement these
+          bindings on the entry widget:</p>
+<dl><dd><pre> Up    popup dropdown list, scroll up if already displayed
+ Down  popup dropdown list, scroll down if already displayed
+ Esc   popdown dropdown list, return entry to previous value
+ Enter popdown dropdown list, execute current selection</pre></dd></dl>
+
+<p>          Remove bindings from listbox and scrollbar(s), so that all
+          bindings are via the entry widget?</p>
+
+
+</li>
+<li><p>When entering keys when list is displayed, scroll list to
+          first entry beginning with entered keys.  If no match,
+          scroll list to top.</p>
+
+</li>
+<li><p>Remove many of the arrow bindings from Pmw.ComboBox - there
+          are just too many key bindings on the arrow button.  There
+          is no need for it to respond to keys such as the up/down
+          keys when the adjacent Entry widget already does so.  I
+          propose to remove all Pmw.ComboBox arrow button key bindings
+          except for &lt;space&gt;, which can be used to bring up the
+          dropdown list.  The Entry widget behaviour would remain
+          unchanged:  when it has focus, you can use the up/down keys
+          to go to the next/previous entries and then use &lt;Return&gt; to
+          invoke the selection command.</p>
+<p>          Alternatively, make the bindings the same as the MS-Windows
+          combobox. (Use the url entry field in Navigator or IE as an
+          example of MS-Windows behaviour).  These have been reported
+          to be:</p>
+<ul><li><p>All mouse actions are exclusively triggered by the left
+              button.</p>
+
+</li>
+<li><p>Right button displays "Direkthilfe" on my german system
+              ("Direct Help").  This is a floating button, that
+              triggers display of a tool tip like the |?| button that
+              appears next to the |x| at the right end of the title
+              bar of some native windows dialogs.</p>
+
+</li>
+<li><p>The arrow is very slim (acutally flat:  width/height is
+              about 2/1)</p>
+
+</li>
+<li><p>Entry and popup have the same color ("window color")</p>
+
+</li>
+<li><p>The popup has a 1 pixel dark border, no spacing between
+              popup and scrollbar.</p>
+
+</li>
+<li><p>If the box has the focus, the full entry is displayed in
+              "selected" style.</p>
+
+</li>
+<li><p>If the box has the focus, up and left keys rotate items
+              up, down and right keys rotate items down, all with
+              immediate effect.</p>
+
+</li>
+<li><p>If the box has the focus, keys a-z (not case sensitive)
+              rotate through the items with same first character, with
+              immediate effect.</p>
+
+</li>
+<li><p>No separate focus for the arrowbutton</p>
+
+</li>
+<li><p>Discussing how the combobox behaves with arrow keys when
+              it has the focus:  "The concept is almost identical to
+              what you already have, just gives more visual feedback. 
+              In your current implementation you allow to rotate
+              through the values with the up and down arrow keys,
+              showing the strings in the entryfield, and accepting the
+              values when the user presses the spacebar (hmmm, how can
+              I exit this without moving back to the original value
+              manually?).  On Windows, the choice is not shown in the
+              entryfield, but the popup opens when you press the up or
+              down arrow keys, as if you clicked on the arrowbutton,
+              and you then navigate the values in the listbox.  This
+              avoids the display of not finally selected values in the
+              entryfield and is a lot more obvious and less confusing. 
+              The current behaviour certainly confused me, which is
+              why I first proposed the changes to the moveup/down
+              methods." (Georg Mischler)</p>
+
+</li></ul>
+
+<p>          Also, check bindings on other megawidgets for consistency.</p>
+
+
+</li>
+<li><p>Modify Pmw.ComboBox so that the width of the entry widget is
+          forced to be the same as the width of the dropdown listbox. 
+          If the "width" option to the standard listbox is 0, Tk sets
+          the requested width of the listbox to be just large enough
+          to hold the widest element in the listbox.  Using this
+          option, I can see that listbox.winfo_reqwidth() is changing
+          as I insert items into an unmapped listbox.  The question
+          is, how do I get notified of these events so that I can set
+          the width of the entry?</p>
+<p>          The problem is that the listbox is in another toplevel which
+          has not yet been displayed, so I can't bind to &lt;Configure&gt;
+          to determine its width.</p>
+
+<p>          One suggestion is to override the insert and delete methods
+          of the Listbox class.  The problem with this is what if the
+          font changed, or the borderwidth, etc?  You would need to
+          override and check many more methods.</p>
+
+
+</li>
+<li><p>Add ability to tearoff dropdown list (suggested by Dean N. 
+          Williams).</p>
+
+</li>
+<li><p>Should be able to disable/enable arrow button.</p>
+
+</li></ul>
+
+<p>    Counter</p>
+<ul><li><p>Add option for different increment/decrement behaviour.  For
+          example, assuming increment is 1:</p>
+<ol><li><p>Current behaviour - move to the next multiple of the
+               increment, eg:  1.0 -&gt; 2.0, 1.234 -&gt; 2.0</p>
+
+</li>
+<li><p>Add or subtract the increment to whatever is displayed,
+               eg:  1.0 -&gt; 2.0, 1.234 -&gt; 2.234</p>
+
+</li>
+<li><p>Move to the next multiple of the increment, offset by some value.
+               eg: (if offset is 0.5) 0.5 -&gt; 1.5, 1.234 -&gt; 1.5, 1.678 -&gt; 2.5</p>
+
+</li></ol>
+
+</li>
+<li><p>Add wrap option (to wrap around at limits) (then don't need
+          time24 arg to <strong>'time'</strong> datatype).</p>
+
+</li>
+<li><p>Add a state option to disable Counter.</p>
+
+</li>
+<li><p>Add option to Counter to allow the buttons to be on the same
+          side, one on top of the other, like Tix, Itcl, Motif,
+          Windows 95, etc.  There should probably also be an option to
+          lay the current large buttons on the same side of the entry
+          field, next to each other.</p>
+
+</li>
+<li><p>Redo TimeCounter using vertical Counter, add limitcommand
+          option to Counter to allow overflow from seconds to minutes
+          to hours</p>
+
+</li></ul>
+
+<p>    Arrowed megawidgets (Counter, ComboBox, TimeCounter)</p>
+<ul><li><p>Potential construction speed up if Canvas arrows are replaced 
+          by Label with Bitmap or BitmapImage.  The hard part would be
+          to make the bitmap change size depending on size of Label.</p>
+
+</li>
+<li><p>Pmw.drawarrow should draw arrows which look like Tk cascade
+          menu arrows.</p>
+
+</li></ul>
+
+<p>    EntryField</p>
+<ul><li><p>Can it be modified to change all entered characters to upper
+          or lower case automatically?  Or first-upper or
+          first-of-each-word-upper?</p>
+
+</li>
+<li><p>If the validity of the currently displayed text is ERROR,
+          allow any changes, even those which result in invalid text. 
+          This is useful when invalid data has been given to the
+          <strong>value</strong> option and the user is trying to correct it.</p>
+
+</li></ul>
+
+<p>    LabeledWidget</p>
+<ul><li><p>Add tix-style border.</p>
+
+</li></ul>
+
+<p>    MenuBar</p>
+<ul><li><p>Maybe Pmw.MenuBar should also have (optional) balloon help
+          for menu items as well as menu buttons.  I am not sure
+          whether users would find this useful.</p>
+
+</li>
+<li><p>The status help hints do not appear when using F10/arrow
+          keys.</p>
+
+</li>
+<li><p>Look at the Tk8.0 menu demo and check the help bindings for
+          ideas, in particular, how can you get help when using
+          keyboard bindings.</p>
+
+</li>
+<li><p>Check the new menu features in Tk8.0 for creating "native"
+          menu bars and the special ".help" menu.</p>
+
+</li>
+<li><p>Add index() method.</p>
+
+</li>
+<li><p>Add a <strong>'position'</strong> option to addmenu and deletemenu methods. 
+          This option should accept an index number, a menuName or
+          <strong>Pmw.END</strong>.</p>
+
+</li>
+<li><p>Look at itcl menubar for ideas.</p>
+
+</li></ul>
+
+<p>    Balloon</p>
+<ul><li><p>Positioning of the balloon with respect to the target
+          widget or canvas item: There are a number of ways that
+          Pmw.Balloon could be improved.  For example, currently the
+          the top left corner of the balloon is positioned relative to
+          the bottom left corner of the target, offset by the
+          [xy]offset options.  These options apply to all targets -
+          they can not be set differently for different targets.</p>
+<p>          To make it more configurable, the user should be able to
+          specify, for each target:</p>
+<ul><li><p>the base position in the target relative to which the
+              balloon should be placed (n, s, e, w, nw, sw, ne, se, c)
+              (Currently sw)</p>
+
+</li>
+<li><p>the x and y offsets (Default (20, 1))</p>
+
+</li>
+<li><p>the position in the balloon that should be placed at the
+              offset position (n, s, e, w, nw, sw, ne, se, c)
+              (Currently nw)</p>
+<p>              Note, if this is anything other than nw,
+              update_idletasks() will need to be called to get the
+              size of the balloon before it is positioned - there is a
+              possibility that this may cause weird ugly flashing.</p>
+
+
+</li>
+<li><p>whether either the base x or y position should be taken
+              relative to the current mouse position rather than as
+              one of the corners of the target.  This would be useful
+              for large targets, such as text widgets, or strange
+              shaped canvas items.  This could be specified using
+              special base positions, such as (nm, sm, em, wm).  For
+              example, for <strong>'sm'</strong>, the x base position is the mouse x
+              position and y base position is the bottom (south) edge
+              of the target.</p>
+
+</li></ul>
+
+<p>          The user should be able to specify global defaults for all
+          of these, as well as be able to override them for each
+          target.  The Pmw.Balloon options and their defaults could
+          be:</p>
+<dl><dd><pre> basepoint   sw        # Position on target.
+ anchor      nw        # Position on the balloon
+ xoffset     20        # x distance between basepoint and anchor
+ yoffset     1         # y distance between basepoint and anchor</pre></dd></dl>
+
+
+<p>          To be able to override these, the bind() and tagbind()
+          methods would have to accept these as additional arguments. 
+          Each would default to None, in which case the default values
+          at the time the balloon is deiconified would be used.</p>
+
+<p>          I'm not sure about how to handle the case when the balloon
+          is configured to come up under the mouse.  When this happens
+          the balloon flashes on and off continuously.  This can
+          happen now if you set the yoffset to a negative number. 
+          Should the balloon widget detect this and do something about
+          it?</p>
+
+
+</li>
+<li><p>Add showballoon(x, y, text) method to Balloon and use in
+          balloon help for a listbox:</p>
+<p>          On 3 Dec, Michael Lackhoff wrote:</p>
+
+<dl><dd><pre> And another question:
+ Is it possible to create a balloon-help for the entries
+ in the listbox?  Not all the information is in the
+ listbox and it would be nice if a balloon help could
+ give addtional information.</pre></dd></dl>
+
+<p>          Rather than popup a balloon help window as the mouse moves
+          over items in the listbox, I think it would be better if it
+          pops up after you clicked on an item (or a short time
+          afterwards).  Pmw.Balloon displays the balloon help a short
+          time after the mouse enters a widget, so is not directly
+          usable in this case.  However, a method could be added to
+          Pmw.Balloon to request it to popup the balloon at a
+          particular x,y position.  This method could be called from
+          the listbox_focus method above.  Something like:</p>
+<dl><dd><pre> def listbox_focus(self, event):
+     self.indexlist.component('listbox').focus_set()</pre></dd></dl>
+
+<dl><dd><pre>     text = self.indexlist.getcurselection()
+     # expand text to whatever you want:
+     text = 'This is ' + text
+     self.balloon.showballoon(x, y, text)</pre></dd></dl>
+
+
+<p>          The Pmw.Balloon showballoon() method would have to set a
+          timer which sometime later calls another method which
+          displays the text.  You would also need to bind
+          &lt;ButtonRelease-1&gt; to a hideballoon() method which withdraws
+          the popup.</p>
+
+
+</li>
+<li><p>The balloon can be displayed off-screen if the window is
+          near the edge of the screen.  Add a fix so that the balloon
+          always stays on the screen (but does not popup under the
+          mouse, otherwise it will immediately pop down).</p>
+
+</li>
+<li><p>Add a fix so that the balloon does not disappear if the
+          mouse enters it.  Could do this by setting a short timer on
+          the Leave event before withdrawing the balloon and if there
+          is an Enter event on the balloon itself, do not withdraw it.</p>
+
+</li>
+<li><p>For tagged items in text widgets, the balloon is placed
+          relative to the character in the tagged item closest to the
+          mouse.  This is not consistent:  in the other cases
+          (including canvas), the balloon is placed relative to the
+          bottom left corner of the widget or canvas item.  This
+          should also be the case for text items.</p>
+
+</li>
+<li><p>Is the new (in Tk8) "&lt;&lt;MenuSelect&gt;&gt;" event useful for
+          balloon and/or status help.</p>
+
+</li></ul>
+
+<p>    MessageBar</p>
+<ul><li><p>Finish logmessage functionality.</p>
+
+</li>
+<li><p>Add colours and fonts to MessageBar message types.  For
+          example, systemerror message types could have bold font on a
+          red background.</p>
+
+</li>
+<li><p>Add message logging history view (like the ddd debugger).</p>
+
+</li></ul>
+
+<p>    NoteBook</p>
+<ul><li><p>Notebook should recalculate layout if the requested size of a tab
+          changes (eg font size, text, etc).</p>
+
+</li>
+<li><p>The tabpos option should accept <em>s</em>, <em>e</em> and <em>w</em> as well as <em>n</em>.</p>
+
+</li>
+<li><p>Possible new options (borrowed from iwidgets):</p>
+<ul><li><p><strong>equaltabs</strong></p>
+<p>                If set to true, causes horizontal tabs to be equal in
+                in width and vertical tabs to equal in height.</p>
+
+<p>                Specifies whether to force tabs to be  equal  sized  or
+                not.  A  value of true means constrain tabs to be equal
+                sized. A value of false allows each tab to  size  based
+                on  the  text label size. The value may have any of the
+                forms accepted by the  Tcl_GetBoolean,  such  as  true,
+                false, 0, 1, yes, or no.</p>
+
+<p>                For horizontally positioned tabs (tabpos is either s or
+                n),  true  forces all tabs to be equal width (the width
+                being equal to the longest label plus any  padX  speci-
+                fied). Horizontal tabs are always equal in height.</p>
+
+<p>                For vertically positioned tabs (tabpos is either  w  or
+                e), true forces all tabs to be equal height (the height
+                being equal to the height of the label with the largest
+                font).  Vertically  oriented  tabs  are always equal in
+                width.</p>
+
+<p>                Could have a special value which sets equal sized and
+                also forces tabs to completely fill notebook width
+                (apparently like
+                Windows).</p>
+
+
+</li>
+<li><p><strong>tabgap</strong></p>
+<p>                Specifies the amount of pixel space  to  place  between
+                each tab. Value may be any pixel offset value. In addi-
+                tion, a special keyword overlap  can  be  used  as  the
+                value to achieve a standard overlap of tabs. This value
+                may have any of the forms acceptable to Tk_GetPixels.  </p>
+
+
+</li>
+<li><p><strong>raiseselect</strong></p>
+<p>                Sets whether to raise selected tabs slightly (2 pixels).</p>
+
+<p>                Specifes whether to slightly  raise  the  selected  tab
+                from  the rest of the tabs. The selected tab is drawn 2
+                pixels closer to the outside of  the  tabnotebook  than
+                the  unselected  tabs.  A  value  of true says to raise
+                selected tabs, a value of false turns this feature off.
+                The  default  is  false.  The value may have any of the
+                forms accepted by the  Tcl_GetBoolean,  such  as  true,
+                false, 0, 1, yes, or no.</p>
+
+
+</li>
+<li><p><strong>bevelamount</strong></p>
+<p>                Specifies pixel size of tab corners. 0 means no corners.</p>
+
+
+</li></ul>
+
+</li>
+<li><p>There should be a way to temporarily hide a page, without
+            deleting it (like pack_forget).  (Suggested by Michel Sanner)</p>
+
+</li></ul>
+
+<p>    OptionMenu</p>
+<ul><li><p>Should accept focus and obey up and down arrow keys.</p>
+
+</li></ul>
+
+<p>    PanedWidget</p>
+<ul><li><p>Add index() method</p>
+
+</li>
+<li><p>Modify all methods so that they accept <strong>Pmw.END</strong> as a pane
+          identifier as well as an index or a name.</p>
+
+</li>
+<li><p>Check iwidgets pane and panedwindow classes.</p>
+
+</li></ul>
+
+<p>    RadioSelect</p>
+<ul><li><p>Add insert() and delete() methods.</p>
+
+</li>
+<li><p>The index method should have <strong>forInsert</strong> argument.</p>
+
+</li>
+<li><p>Add Pmw.SELECT to index() method.  For single selectmode
+          this returns an integer, for multiple selectmode this
+          returns a list of integers.</p>
+
+</li>
+<li><p>Add option to set background color on selected buttons. 
+          Maybe should also be able set selected foreground as well. 
+          Any others?</p>
+
+</li></ul>
+
+<p>    LogicalFont</p>
+<ul><li><p>Add boldFixed fonts,</p>
+
+</li>
+<li><p>Search for closest size font if no exact match.</p>
+
+</li>
+<li><p>Maybe replace with Tk8.0 font mechanism.</p>
+
+</li>
+<li><p>Can the Tk8.0 font measuring functionality be used in Pmw somehow?</p>
+
+</li></ul>
+
+<p>    Scrolled widgets</p>
+<ul><li><p>Can some common scrolling methods be factored out, either as
+          a base class, "ScrolledMixin" mixin class or as helper functions? 
+          Candidate methods: constructor, destroy, interior, _hscrollMode,
+          _vscrollMode, _configureScrollCommands, _scrollXNow, _scrollYNow,
+          _scrollBothLater, _scrollBothNow, _toggleHorizScrollbar,
+          _toggleVertScrollbar.</p>
+
+</li>
+<li><p>ScrolledField should have optional arrow buttons, so that it
+          can still be scrolled even if the mouse does not have a
+          middle button.</p>
+
+</li></ul>
+
+<p>    Miscellaneous</p>
+<ul><li><p>Add a button to the Pmw "Stack trace window" which
+          optionally removes all grabs:</p>
+<p>            I normally interact with the "Stack trace window"
+            immediately, and dismiss it afterwards.  In many cases
+            where a bug appears like this, the rest of the application
+            is still functional (many of the problems appearing at
+            this stage of development of my application are unforeseen
+            exceptions communicating with a robot on the other end of
+            a socket, not affecting the GUI per se).  For that reason
+            I'd prefer if the "stack trace window" would push another
+            grab on the grab stack (if any grabs are active at the
+            moment the exception occurs).  Could the window have an
+            extra "Terminate application" option for this case?</p>
+
+
+</li>
+<li><p>need to handle component option queries in configure():</p>
+<dl><dd><pre> foo = Pmw.AboutDialog(applicationname = 'abc XYZ')
+ foo.component('message').configure('text')    - works
+ foo.cget('message_text')                      - works
+ foo.configure('message_text')                 - doesn't</pre></dd></dl>
+
+
+</li>
+<li><p>Implement bindings (ComboBox, etc) via a dictionary lookup,
+          to allow people to invent new bindings, such as for
+          handicapped users.  (Suggested by Michael McLay)</p>
+
+</li>
+<li><p>Modify bundlepmw.py so that it checks Pmw.def to see that no
+          files have been missed.</p>
+
+</li>
+<li><p>Potential cheap speedup by adding this to each module, or
+          inside functions if it has a loop containing calls to
+          builtins:</p>
+<dl><dd><pre> from __builtin__ import *</pre></dd></dl>
+
+
+</li>
+<li><p>Look at how update_idletasks and after_* are used in Pmw -
+          are they consistent?  could it be improved?  What are the
+          problems of using these on other bits of an application
+          (such as when the size of the toplevel is being determined
+          for the window manager).</p>
+
+</li>
+<li><p>If lots of errors occur (such as in a fast time callback)
+          the error window may not appear, since Tk will wait until it
+          is idle - which may never occur.  The solution is to call
+          update_idletask when updating the error window, but only
+          after a short time has passed.  This will provide better
+          user response.  However, it may not be possible to do this
+          if some python interpretes (omppython, for example) do not
+          handle calls to update_idletasks at certain times.</p>
+
+</li>
+<li><p>In the Pmw FAQ, in the "Why don't Pmw megawidgets have a
+          <strong>'state'</strong> option?" section, it mentions several Pmw
+          megawidgets that can not be disabled.  Fix them.</p>
+
+</li>
+<li><p>Add RCSID version string to all files.</p>
+
+</li>
+<li><p>When raising exceptions use the third argument to raise:</p>
+<dl><dd><pre> raise SimulationException, msg, sys.exc_info()[2]</pre></dd></dl>
+
+
+</li>
+<li><p>When update_idletasks is called all pending changes are
+          flushed to the window system server.  However, it may take
+          some time for the server to display the changes.  If it is
+          required that the display be up-to-date, update_idletasks
+          should be followed by a call that blocks until processed by
+          the server and a reply received.  This may be useful in
+          Pmw.busycallback to ensure the busy cursor remains visible
+          until the display is actually modified.</p>
+
+</li>
+<li><p>There is a small bug which appears only with Tk8.0 (the bug
+          is not apparent with Tk4.2).  If a dialog is activated and
+          pops up directly over the cursor and the dialog has a
+          default button, then pressing the &lt;strong&gt;Return&lt;/strong&gt;
+          key will not invoke the default button.  If you move the
+          mouse out of and then back into the dialog, pressing the
+          &lt;strong&gt;Return&lt;/strong&gt; key will work.  This behaviour has
+          been noticed in Tcl-only programs, so it is probably a bug
+          in Tk.  (Tested on Solaris.)</p>
+
+</li>
+<li><p>Modify PmwBlt.py to use blt2.4 instead of blt8.0.unoff.
+          Nick Belshaw &lt;nickb@earth.ox.ac.uk&gt; is looking at wrapping
+          the new BLT StripChart and TabSet into Pmw.</p>
+
+</li>
+<li><p>Perhaps Pmw should have its own exception defined, like
+          TkInters's TclError, perhaps called PmwError.</p>
+
+</li>
+<li><p>This one is caused by a bug in the implementation of Tcl/Tk
+          for Microsoft Windows NT (and maybe other Microsoft
+          products).  Mouse release events can get lost if the
+          grab_set and grab_release commands are used and the mouse
+          goes outside of the window while the mouse button is down. 
+          This can occur while Pmw modal dialogs are active.  Below
+          is some Tkinter-only code which demonstrates the problem.
+          Maybe there is a work around.</p>
+<dl><dd><pre> # Test script to demonstrate bug in Tk
+ #implementation of grab under NT.
+                                 
+ # Click on "Dialog" to bring up the modal
+ # dialog window.  Then button down on the scale,
+ # move the mouse outside the window,
+ # then button up.  The scale slider will still
+ # be sunken and clicks on the "OK" button
+ # will be ineffective.
+ import Tkinter
+ def activate():
+     waitVar.set(0)
+     toplevel.deiconify()
+     toplevel.wait_visibility()
+     toplevel.grab_set()        # Problem here
+     toplevel.focus_set()
+     toplevel.wait_variable(waitVar)
+ def deactivate():
+     toplevel.withdraw()
+     toplevel.grab_release()    # and here
+     waitVar.set(1)
+ root = Tkinter.Tk()
+ toplevel = Tkinter.Toplevel()
+ waitVar = Tkinter.IntVar()
+ toplevel.withdraw()
+ scale = Tkinter.Scale(toplevel, orient='horizontal', length=200)
+ scale.pack()
+ button = Tkinter.Button(toplevel, text='OK', command=deactivate)
+ button.pack()
+ button = Tkinter.Button(text='Dialog', command=activate)
+ button.pack()
+ button = Tkinter.Button(text='Exit', command=root.destroy)
+ button.pack()
+ root.mainloop()</pre></dd></dl>
+
+
+</li></ul>
+
+
+<p><strong>Documentation</strong></p>
+<ul><li><p>Document how to get Pmw working on a Mac, for example:</p>
+<ul><li><p>Unzip and untar</p>
+<p>            This depends on what you use to unpack the tar file.  If
+            you use (macgzip and) SunTar you have to tell it that files
+            with ".py" extensions are text files (in the
+            preferences/file type section).  If you use stuffit
+            expander:  this can be made to do the conversion
+            correctly, but it could be that this only works if you set
+            the .py extension correctly in Internet Config.</p>
+
+<ul><li><p>Where do you untar Pmw?</p>
+
+</li>
+<li><p>How do you get line terminators correct (carriage
+              return/line feed)?</p>
+
+</li>
+<li><p>Is there any problem with file name case?  (mixed
+              upper/lower case)</p>
+
+</li>
+<li><p>Is there any problem with file name length?</p>
+
+</li></ul>
+<p>            (Joseph Saltiel says:  It was the same type of operation
+            as in Windows/Unix.  Run a program that unzips it and
+            untars it.  It seems to get case and length right on its
+            own.)</p>
+
+
+</li>
+<li><p>Let python know where Pmw is</p>
+<ul><li><p>If Pmw is in its own folder you will have to add the
+              parent of that folder to the sys paths in Edit
+              PythonPaths.  If it is in the Python home folder, you
+              do not need to do this.</p>
+
+</li>
+<li><p>Make sure that the Pmw folder is called "Pmw" and not
+              something else.  Since Pmw is a package, python expects
+              to find a "Pmw" folder somewhere in sys.path.</p>
+
+</li></ul>
+<p>            (Joseph Saltiel says:  With the Python distribution on the
+            Mac there is an application called editPythonPrefs, when
+            you run it it gives you a list of a paths.  These paths
+            are similiar to the PYTHONPATH variable.  I just added the
+            path to Pmw at the bottom of this list.)</p>
+
+
+</li></ul>
+
+</li>
+<li><p>Document general ideas about building guis, eg:</p>
+<p>      When I write gui applications, I usually defer creation of windows
+      as much as possible - this means that the application starts up
+      quickly because it usually only has to create the main window. 
+      Whenever another window is required for the first time, it is
+      created then.  When the user has finished with the window, the
+      window is withdrawn, not deleted, so that next time it is required
+      it much faster to come up.</p>
+
+<p>      In summary - don't create a window until you need and
+      don't destroy a window if you may want it again.</p>
+
+<p>      The amount of memory required to keep the windows should not be
+      very much - except for very long running programs where the user
+      may create thousands of different windows.</p>
+
+
+</li>
+<li><p>Add class hierarchy diagram to documentation:</p>
+<dl><dd><pre> MegaArchetype
+     MegaToplevel
+        etc
+     MegaWidget
+        etc</pre></dd></dl>
+
+
+</li>
+<li><p>Add to doco something like:  "Another way to extend a Pmw
+      megawidget is to specify a non-default type for one of the
+      components.  For example <code>text_pytype = FontText</code>."</p>
+
+</li>
+<li><p>Document pyclass and pyclass = None (options for null components
+      are ignored; the only time this can be used is with the
+      Group's tag component - all
+      other's use the component widget in some way)</p>
+
+</li>
+<li><p>Create index of all Pmw methods, functions, options, components.</p>
+
+</li>
+<li><p>Add description of how to run the Pmw demos without installing.</p>
+
+</li>
+<li><p>Add description of how to install Pmw.</p>
+
+</li>
+<li><p>Describe grid structure of megawidgets, so that it is possible
+      to extend megawidgets by adding new widgets into the interior
+      (hence avoiding a childsite in most megawidgets)</p>
+
+</li>
+<li><p>Document error display and difference between callback and
+      binding error reports.</p>
+
+</li>
+<li><p>Document difference between <strong>'Helvetica 12'</strong> and <strong>'Helvetica size: 12'</strong>
+      in logicalfont.</p>
+
+</li>
+<li><p>Add to howtouse, to describe using the option database to set
+        options for a specific megawidget:</p>
+<dl><dd><pre> import Pmw
+ root = Pmw.initialise(useTkOptionDb = 1)
+ root.option_add('*entryfield24*Label.text', 'German')
+ e = Pmw.EntryField(hull_name = 'entryfield24', labelpos = 'w')
+ e.pack()
+ root.update()</pre></dd></dl>
+
+
+</li>
+<li><p>Also document hull_name and hull_class.</p>
+
+</li>
+<li><p>Finish FAQ, ReleaseProcedure and StructuredText test.</p>
+
+</li>
+<li><p>Put html through gifwizard and html lint.</p>
+<dl><dd><pre> http://www.cen.uiuc.edu/cgi-bin/weblint
+ (eg: http://www.cre.canon.co.uk/~neilb/weblint/manpage.html)</pre></dd></dl>
+
+
+</li>
+<li><p>Delete comments from source if they have been added to docs
+      (should not have two copies of anything).</p>
+
+</li>
+<li><p>Need to document non-standard initial values for component
+      options, such as border in ButtonBox and Dialog's childsite.</p>
+
+</li>
+<li><p>Docs should have DEFAULT BINDINGS section (like iwidget combobox).</p>
+
+</li>
+<li><p>Promote home page:</p>
+<dl><dd><pre> http://www.geocities.com/homestead/promote.html
+ http://www.submit-it.com/subopt.htm, etc</pre></dd></dl>
+
+
+</li>
+<li><p>Create man pages as well as html (modify createmanuals to produce both).</p>
+
+</li>
+<li><p>Maybe something with html frames like: itcl2.2/html/index.html</p>
+
+</li>
+<li><p>Add to starting.html a note that Pmw is a python "package" and add
+      a pointer to python documentation on packages.</p>
+
+</li>
+<li><p>Document scrolled widget implementations, explaining why they
+      are all slightly different (because the underlying widgets which
+      are being scrolled have different behaviors).</p>
+
+</li>
+<li><p>Make copyright clearer. Maybe borrow python's?</p>
+
+</li></ul>
+
+<p><strong>Demos</strong></p>
+<ul><li><p>Check for missing demos.</p>
+
+</li>
+<li><p>In all demos can move the three lines beginning with "Import Pmw
+      from the sibling directory", to inside "if __name__" clause.
+      Also, "sibling directory" is now incorrect.  Also, add note that
+      this is only necessary when running demos without installing Pmw.</p>
+
+</li>
+<li><p>Change demo/All.py so that it displays the traceback if it
+      cannot load or run a demo (easier for users to report errors).</p>
+
+</li>
+<li><p>Add option to demo/All.py:  "Display demos in separate window"
+      to allow resizing of sub-demos</p>
+
+</li>
+<li><p>TimeCounter and Spectrum demos beep when they come up, using:</p>
+<dl><dd><pre> root.option_add('*EntryField*value', 'VALUE')</pre></dd></dl>
+
+
+</li>
+<li><p>In demos, add <code>title = 'blah'</code> to top of file and replace
+      <code>root.title(..)</code> with <code>root.title(title)</code> at bottom.</p>
+
+</li>
+<li><p>Add comprehensive speed test demo which creates one or more of
+      each (common) megawidget.  Remove old SpeedTest demo.</p>
+
+</li>
+<li><p>Check demos work when called from ptui.  (Changes have to do
+      with calling compile/exec where __name__ is not the name of the
+      All.py script, but is <strong>'__builtin__'</strong>)</p>
+
+</li>
+<li><p>PromptDialog demo should not remember password.</p>
+
+</li>
+<li><p>Finish Counter, Radioselect demos.</p>
+
+</li>
+<li><p>Modify the All demo so that you can reload a demo module.</p>
+
+</li>
+<li><p>The syntax-coloured code viewer looks strange on Microsoft NT,
+      because the size of the fonts differ.  Check out Guido's
+      idle-0.1 text colouring for Pmw code viewer.</p>
+
+</li>
+<li><p>Document restrictions on adding bindings to a megawidget:  you
+      probably need to bind to components of the megawidget and also
+      check that you are not destroying bindings set up by the
+      megawidget itself.</p>
+
+</li>
+<li><p>Add a demo that demonstrates setting the color scheme at run time.</p>
+
+</li></ul>
+
+<p><strong>Tests</strong></p>
+<ul><li><p>Check for missing tests, such as TimeCounter, RadioSelect,
+      SelectionDialog, MessageBar, MenuBar, ComboBoxDialog, Balloon.</p>
+
+</li>
+<li><p>Create test for useTkOptionDb option to Pmw.initialise().</p>
+
+</li>
+<li><p>Check that destroyed widgets' python classes are garbage
+      collected (add test and/or demo).</p>
+
+</li>
+<li><p>Add tests for changecolor, setscheme, etc.</p>
+
+</li>
+<li><p>Need Resources test.</p>
+
+</li>
+<li><p>Create tests for deriving from Pmw classes (eg ComboBox).</p>
+
+</li></ul>
+
+<p><strong>Ideas</strong></p>
+<ul><li><p>Add more Tix (www.xpi.com/tix/screenshot.html) and iwidgets widgets.</p>
+
+</li>
+<li><p>Look at spinner.itk for how to do vertical orientation on
+      same side for Counter.</p>
+
+</li>
+<li><p>Investigate these new features in Tk8.0 and see if they could be
+      used in Pmw:</p>
+<dl><dd><pre> embedded images in text widgets
+ destroy command ignores windows that don't exist
+</pre></dd></dl>
+
+
+</li></ul>
+
+
+
+    <center><P ALIGN="CENTER">
+    <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
+    </p></center>
+    
+
+    <font size=-1>
+    <center><P ALIGN="CENTER">
+    Pmw 1.2 -
+     5 Aug 2003
+     - <a href="index.html">Home</a>
+    
+    </p></center>
+    </font>
+
+    </body>
+    </html>
+    
diff --git a/Pmw/Pmw_1_2/doc/transdove.gif b/Pmw/Pmw_1_2/doc/transdove.gif
new file mode 100644 (file)
index 0000000..a9d83cd
Binary files /dev/null and b/Pmw/Pmw_1_2/doc/transdove.gif differ
diff --git a/Pmw/Pmw_1_2/lib/Pmw.def b/Pmw/Pmw_1_2/lib/Pmw.def
new file mode 100644 (file)
index 0000000..5965c11
--- /dev/null
@@ -0,0 +1,58 @@
+#                                        [Emacs: -*- python -*-]
+# --- This is the Pmw definition file ---
+#
+# It is invoked by the Pmw dynamic loader in Pmw.__init__.
+#
+#    widgets       : tuple with the names of those widget classes that are 
+#                    stacked in a module of the same name.
+#    widgetclasses : dictionary from names of widget classes to module names.
+#    functions     : dictionary from function names to modules names.
+#    modules       : tuple of module names that don't contain widget classes
+#                    of the same name.
+#
+
+# Widgets whose name is the same as its module.
+_widgets = (
+    'AboutDialog', 'Balloon', 'ButtonBox', 'ComboBox',
+    'ComboBoxDialog', 'Counter', 'CounterDialog', 'Dialog',
+    'EntryField', 'Group', 'HistoryText', 'LabeledWidget',
+    'MainMenuBar', 'MenuBar', 'MessageBar',
+    'MessageDialog', 'NoteBook', 'OptionMenu', 'PanedWidget',
+    'PromptDialog', 'RadioSelect', 'ScrolledCanvas', 'ScrolledField',
+    'ScrolledFrame', 'ScrolledListBox', 'ScrolledText', 'SelectionDialog',
+    'TextDialog', 'TimeCounter',
+)
+
+# Widgets whose name is not the same as its module.
+_extraWidgets = {
+}
+
+_functions = {
+    'logicalfont'           : 'LogicalFont',
+    'logicalfontnames'      : 'LogicalFont',
+    'aboutversion'          : 'AboutDialog',
+    'aboutcopyright'        : 'AboutDialog',
+    'aboutcontact'          : 'AboutDialog',
+    'datestringtojdn'       : 'TimeFuncs',
+    'timestringtoseconds'   : 'TimeFuncs',
+    'setyearpivot'          : 'TimeFuncs',
+    'ymdtojdn'              : 'TimeFuncs',
+    'jdntoymd'              : 'TimeFuncs',
+    'stringtoreal'          : 'TimeFuncs',
+    'aligngrouptags'        : 'Group',
+    'OK'                    : 'EntryField',
+    'ERROR'                 : 'EntryField',
+    'PARTIAL'               : 'EntryField',
+    'numericvalidator'      : 'EntryField',
+    'integervalidator'      : 'EntryField',
+    'hexadecimalvalidator'  : 'EntryField',
+    'realvalidator'         : 'EntryField',
+    'alphabeticvalidator'   : 'EntryField',
+    'alphanumericvalidator' : 'EntryField',
+    'timevalidator'         : 'EntryField',
+    'datevalidator'         : 'EntryField',
+}
+
+_modules = (
+    'Color', 'Blt',
+)
diff --git a/Pmw/Pmw_1_2/lib/PmwAboutDialog.py b/Pmw/Pmw_1_2/lib/PmwAboutDialog.py
new file mode 100644 (file)
index 0000000..fe78d27
--- /dev/null
@@ -0,0 +1,52 @@
+import Pmw
+
+class AboutDialog(Pmw.MessageDialog):
+    # Window to display version and contact information.
+
+    # Class members containing resettable 'default' values:
+    _version = ''
+    _copyright = ''
+    _contact = ''
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('applicationname',   '',          INITOPT),
+           ('iconpos',           'w',         None),
+           ('icon_bitmap',       'info',      None),
+           ('buttons',           ('Close',),  None),
+           ('defaultbutton',     0,           None),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MessageDialog.__init__(self, parent)
+
+       applicationname = self['applicationname']
+        if not kw.has_key('title'):
+            self.configure(title = 'About ' + applicationname)
+
+        if not kw.has_key('message_text'):
+            text = applicationname + '\n\n'
+            if AboutDialog._version != '':
+              text = text + 'Version ' + AboutDialog._version + '\n'
+            if AboutDialog._copyright != '':
+              text = text + AboutDialog._copyright + '\n\n'
+            if AboutDialog._contact != '':
+              text = text + AboutDialog._contact
+
+            self.configure(message_text=text)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+def aboutversion(value):
+    AboutDialog._version = value
+
+def aboutcopyright(value):
+    AboutDialog._copyright = value
+
+def aboutcontact(value):
+    AboutDialog._contact = value
diff --git a/Pmw/Pmw_1_2/lib/PmwBalloon.py b/Pmw/Pmw_1_2/lib/PmwBalloon.py
new file mode 100644 (file)
index 0000000..e1f8868
--- /dev/null
@@ -0,0 +1,365 @@
+import os
+import string
+import Tkinter
+import Pmw
+
+class Balloon(Pmw.MegaToplevel):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = (
+            ('initwait',                 500,            None), # milliseconds
+            ('label_background',         'lightyellow',  None),
+            ('label_foreground',         'black',        None),
+            ('label_justify',            'left',         None),
+            ('master',                   'parent',       None),
+            ('relmouse',                 'none',         self._relmouse),
+            ('state',                    'both',         self._state),
+            ('statuscommand',            None,           None),
+            ('xoffset',                  20,             None), # pixels
+            ('yoffset',                  1,              None), # pixels
+           ('hull_highlightthickness',  1,              None),
+           ('hull_highlightbackground', 'black',        None),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaToplevel.__init__(self, parent)
+
+       self.withdraw()
+       self.overrideredirect(1)
+
+       # Create the components.
+       interior = self.interior()
+       self._label = self.createcomponent('label',
+               (), None,
+               Tkinter.Label, (interior,))
+       self._label.pack()
+
+        # The default hull configuration options give a black border
+        # around the balloon, but avoids a black 'flash' when the
+        # balloon is deiconified, before the text appears.
+        if not kw.has_key('hull_background'):
+            self.configure(hull_background = \
+                    str(self._label.cget('background')))
+
+       # Initialise instance variables.
+       self._timer = None
+
+        # The widget or item that is currently triggering the balloon. 
+        # It is None if the balloon is not being displayed.  It is a
+        # one-tuple if the balloon is being displayed in response to a
+        # widget binding (value is the widget).  It is a two-tuple if
+        # the balloon is being displayed in response to a canvas or
+        # text item binding (value is the widget and the item).
+        self._currentTrigger = None
+       
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self._timer is not None:
+           self.after_cancel(self._timer)
+           self._timer = None
+       Pmw.MegaToplevel.destroy(self)
+
+    def bind(self, widget, balloonHelp, statusHelp = None):
+
+        # If a previous bind for this widget exists, remove it.
+        self.unbind(widget)
+
+       if balloonHelp is None and statusHelp is None:
+           return
+
+       if statusHelp is None:
+           statusHelp = balloonHelp
+       enterId = widget.bind('<Enter>', 
+               lambda event, self = self, w = widget,
+                       sHelp = statusHelp, bHelp = balloonHelp:
+                               self._enter(event, w, sHelp, bHelp, 0))
+
+        # Set Motion binding so that if the pointer remains at rest
+        # within the widget until the status line removes the help and
+        # then the pointer moves again, then redisplay the help in the
+        # status line.
+       # Note:  The Motion binding only works for basic widgets, and
+        # the hull of megawidgets but not for other megawidget components.
+       motionId = widget.bind('<Motion>', 
+               lambda event = None, self = self, statusHelp = statusHelp:
+                       self.showstatus(statusHelp))
+
+       leaveId = widget.bind('<Leave>', self._leave)
+       buttonId = widget.bind('<ButtonPress>', self._buttonpress)
+
+        # Set Destroy binding so that the balloon can be withdrawn and
+        # the timer can be cancelled if the widget is destroyed.
+       destroyId = widget.bind('<Destroy>', self._destroy)
+
+        # Use the None item in the widget's private Pmw dictionary to
+        # store the widget's bind callbacks, for later clean up.
+        if not hasattr(widget, '_Pmw_BalloonBindIds'):
+            widget._Pmw_BalloonBindIds = {}
+        widget._Pmw_BalloonBindIds[None] = \
+                (enterId, motionId, leaveId, buttonId, destroyId)
+
+    def unbind(self, widget):
+        if hasattr(widget, '_Pmw_BalloonBindIds'):
+            if widget._Pmw_BalloonBindIds.has_key(None):
+                (enterId, motionId, leaveId, buttonId, destroyId) = \
+                        widget._Pmw_BalloonBindIds[None]
+                # Need to pass in old bindings, so that Tkinter can
+                # delete the commands.  Otherwise, memory is leaked.
+                widget.unbind('<Enter>', enterId)
+                widget.unbind('<Motion>', motionId)
+                widget.unbind('<Leave>', leaveId)
+                widget.unbind('<ButtonPress>', buttonId)
+                widget.unbind('<Destroy>', destroyId)
+                del widget._Pmw_BalloonBindIds[None]
+
+        if self._currentTrigger is not None and len(self._currentTrigger) == 1:
+            # The balloon is currently being displayed and the current
+            # trigger is a widget.
+            triggerWidget = self._currentTrigger[0]
+            if triggerWidget == widget:
+                if self._timer is not None:
+                    self.after_cancel(self._timer)
+                    self._timer = None
+                self.withdraw()
+                self.clearstatus()
+                self._currentTrigger = None
+
+    def tagbind(self, widget, tagOrItem, balloonHelp, statusHelp = None):
+
+        # If a previous bind for this widget's tagOrItem exists, remove it.
+        self.tagunbind(widget, tagOrItem)
+
+       if balloonHelp is None and statusHelp is None:
+           return
+
+       if statusHelp is None:
+           statusHelp = balloonHelp
+       enterId = widget.tag_bind(tagOrItem, '<Enter>', 
+               lambda event, self = self, w = widget,
+                       sHelp = statusHelp, bHelp = balloonHelp:
+                               self._enter(event, w, sHelp, bHelp, 1))
+       motionId = widget.tag_bind(tagOrItem, '<Motion>', 
+               lambda event = None, self = self, statusHelp = statusHelp:
+                       self.showstatus(statusHelp))
+       leaveId = widget.tag_bind(tagOrItem, '<Leave>', self._leave)
+       buttonId = widget.tag_bind(tagOrItem, '<ButtonPress>', self._buttonpress)
+
+        # Use the tagOrItem item in the widget's private Pmw dictionary to
+        # store the tagOrItem's bind callbacks, for later clean up.
+        if not hasattr(widget, '_Pmw_BalloonBindIds'):
+            widget._Pmw_BalloonBindIds = {}
+        widget._Pmw_BalloonBindIds[tagOrItem] = \
+                (enterId, motionId, leaveId, buttonId)
+
+    def tagunbind(self, widget, tagOrItem):
+        if hasattr(widget, '_Pmw_BalloonBindIds'):
+            if widget._Pmw_BalloonBindIds.has_key(tagOrItem):
+                (enterId, motionId, leaveId, buttonId) = \
+                        widget._Pmw_BalloonBindIds[tagOrItem]
+                widget.tag_unbind(tagOrItem, '<Enter>', enterId)
+                widget.tag_unbind(tagOrItem, '<Motion>', motionId)
+                widget.tag_unbind(tagOrItem, '<Leave>', leaveId)
+                widget.tag_unbind(tagOrItem, '<ButtonPress>', buttonId)
+                del widget._Pmw_BalloonBindIds[tagOrItem]
+
+        if self._currentTrigger is None:
+            # The balloon is not currently being displayed.
+            return
+
+        if len(self._currentTrigger) == 1:
+            # The current trigger is a widget.
+            return
+
+        if len(self._currentTrigger) == 2:
+            # The current trigger is a canvas item.
+            (triggerWidget, triggerItem) = self._currentTrigger
+            if triggerWidget == widget and triggerItem == tagOrItem:
+                if self._timer is not None:
+                    self.after_cancel(self._timer)
+                    self._timer = None
+                self.withdraw()
+                self.clearstatus()
+                self._currentTrigger = None
+        else: # The current trigger is a text item.
+            (triggerWidget, x, y) = self._currentTrigger
+            if triggerWidget == widget:
+                currentPos = widget.index('@%d,%d' % (x, y))
+                currentTags = widget.tag_names(currentPos)
+                if tagOrItem in currentTags:
+                    if self._timer is not None:
+                        self.after_cancel(self._timer)
+                        self._timer = None
+                    self.withdraw()
+                    self.clearstatus()
+                    self._currentTrigger = None
+
+    def showstatus(self, statusHelp):
+       if self['state'] in ('status', 'both'):
+           cmd = self['statuscommand']
+           if callable(cmd):
+               cmd(statusHelp)
+
+    def clearstatus(self):
+        self.showstatus(None)
+
+    def _state(self):
+       if self['state'] not in ('both', 'balloon', 'status', 'none'):
+           raise ValueError, 'bad state option ' + repr(self['state']) + \
+               ': should be one of \'both\', \'balloon\', ' + \
+               '\'status\' or \'none\''
+
+    def _relmouse(self):
+       if self['relmouse'] not in ('both', 'x', 'y', 'none'):
+           raise ValueError, 'bad relmouse option ' + repr(self['relmouse'])+ \
+               ': should be one of \'both\', \'x\', ' + '\'y\' or \'none\''
+
+    def _enter(self, event, widget, statusHelp, balloonHelp, isItem):
+
+        # Do not display balloon if mouse button is pressed.  This
+        # will only occur if the button was pressed inside a widget,
+        # then the mouse moved out of and then back into the widget,
+        # with the button still held down.  The number 0x1f00 is the
+        # button mask for the 5 possible buttons in X.
+        buttonPressed = (event.state & 0x1f00) != 0
+
+       if not buttonPressed and balloonHelp is not None and \
+                self['state'] in ('balloon', 'both'):
+           if self._timer is not None:
+               self.after_cancel(self._timer)
+               self._timer = None
+
+           self._timer = self.after(self['initwait'], 
+                   lambda self = self, widget = widget, help = balloonHelp,
+                           isItem = isItem:
+                           self._showBalloon(widget, help, isItem))
+
+        if isItem:
+            if hasattr(widget, 'canvasx'):
+               # The widget is a canvas.
+                item = widget.find_withtag('current')
+                if len(item) > 0:
+                    item = item[0]
+                else:
+                    item = None
+                self._currentTrigger = (widget, item)
+            else:
+               # The widget is a text widget.
+                self._currentTrigger = (widget, event.x, event.y)
+        else:
+            self._currentTrigger = (widget,)
+
+       self.showstatus(statusHelp)
+
+    def _leave(self, event):
+       if self._timer is not None:
+           self.after_cancel(self._timer)
+           self._timer = None
+       self.withdraw()
+       self.clearstatus()
+        self._currentTrigger = None
+
+    def _destroy(self, event):
+
+        # Only withdraw the balloon and cancel the timer if the widget
+        # being destroyed is the widget that triggered the balloon. 
+        # Note that in a Tkinter Destroy event, the widget field is a
+        # string and not a widget as usual.
+
+        if self._currentTrigger is None:
+            # The balloon is not currently being displayed
+            return
+
+        if len(self._currentTrigger) == 1:
+            # The current trigger is a widget (not an item)
+            triggerWidget = self._currentTrigger[0]
+            if str(triggerWidget) == event.widget:
+                if self._timer is not None:
+                    self.after_cancel(self._timer)
+                    self._timer = None
+                self.withdraw()
+                self.clearstatus()
+                self._currentTrigger = None
+
+    def _buttonpress(self, event):
+       if self._timer is not None:
+           self.after_cancel(self._timer)
+           self._timer = None
+       self.withdraw()
+        self._currentTrigger = None
+
+    def _showBalloon(self, widget, balloonHelp, isItem):
+
+       self._label.configure(text = balloonHelp)
+
+        # First, display the balloon offscreen to get dimensions.
+        screenWidth = self.winfo_screenwidth()
+        screenHeight = self.winfo_screenheight()
+        self.geometry('+%d+0' % (screenWidth + 1))
+        self.update_idletasks()
+
+       if isItem:
+            # Get the bounding box of the current item.
+            bbox = widget.bbox('current')
+            if bbox is None:
+                # The item that triggered the balloon has disappeared,
+                # perhaps by a user's timer event that occured between
+                # the <Enter> event and the 'initwait' timer calling
+                # this method.
+                return
+
+           # The widget is either a text or canvas.  The meaning of
+           # the values returned by the bbox method is different for
+           # each, so use the existence of the 'canvasx' method to
+           # distinguish between them.
+           if hasattr(widget, 'canvasx'):
+               # The widget is a canvas.  Place balloon under canvas
+                # item.  The positions returned by bbox are relative
+                # to the entire canvas, not just the visible part, so
+                # need to convert to window coordinates.
+                leftrel = bbox[0] - widget.canvasx(0)
+                toprel = bbox[1] - widget.canvasy(0)
+                bottomrel = bbox[3] - widget.canvasy(0)
+           else:
+               # The widget is a text widget.  Place balloon under
+                # the character closest to the mouse.  The positions
+                # returned by bbox are relative to the text widget
+                # window (ie the visible part of the text only).
+               leftrel = bbox[0]
+                toprel = bbox[1]
+               bottomrel = bbox[1] + bbox[3]
+       else:
+           leftrel = 0
+            toprel = 0
+           bottomrel = widget.winfo_height()
+
+        xpointer, ypointer = widget.winfo_pointerxy()   # -1 if off screen
+
+        if xpointer >= 0 and self['relmouse'] in ('both', 'x'):
+            x = xpointer
+        else:
+            x = leftrel + widget.winfo_rootx()
+        x = x + self['xoffset']
+
+        if ypointer >= 0 and self['relmouse'] in ('both', 'y'):
+            y = ypointer
+        else:
+            y = bottomrel + widget.winfo_rooty()
+        y = y + self['yoffset']
+
+        edges = (string.atoi(str(self.cget('hull_highlightthickness'))) +
+            string.atoi(str(self.cget('hull_borderwidth')))) * 2
+        if x + self._label.winfo_reqwidth() + edges > screenWidth:
+            x = screenWidth - self._label.winfo_reqwidth() - edges
+
+        if y + self._label.winfo_reqheight() + edges > screenHeight:
+            if ypointer >= 0 and self['relmouse'] in ('both', 'y'):
+                y = ypointer
+            else:
+                y = toprel + widget.winfo_rooty()
+            y = y - self._label.winfo_reqheight() - self['yoffset'] - edges
+
+        Pmw.setgeometryanddeiconify(self, '+%d+%d' % (x, y))
diff --git a/Pmw/Pmw_1_2/lib/PmwBase.py b/Pmw/Pmw_1_2/lib/PmwBase.py
new file mode 100644 (file)
index 0000000..da38e9a
--- /dev/null
@@ -0,0 +1,1933 @@
+# Pmw megawidget base classes.
+
+# This module provides a foundation for building megawidgets.  It
+# contains the MegaArchetype class which manages component widgets and
+# configuration options.  Also provided are the MegaToplevel and
+# MegaWidget classes, derived from the MegaArchetype class.  The
+# MegaToplevel class contains a Tkinter Toplevel widget to act as the
+# container of the megawidget.  This is used as the base class of all
+# megawidgets that are contained in their own top level window, such
+# as a Dialog window.  The MegaWidget class contains a Tkinter Frame
+# to act as the container of the megawidget.  This is used as the base
+# class of all other megawidgets, such as a ComboBox or ButtonBox.
+#
+# Megawidgets are built by creating a class that inherits from either
+# the MegaToplevel or MegaWidget class.
+
+import os
+import string
+import sys
+import traceback
+import types
+import Tkinter
+
+# Special values used in index() methods of several megawidgets.
+END = ['end']
+SELECT = ['select']
+DEFAULT = ['default']
+
+# Constant used to indicate that an option can only be set by a call
+# to the constructor.
+INITOPT = ['initopt']
+_DEFAULT_OPTION_VALUE = ['default_option_value']
+_useTkOptionDb = 0
+
+# Symbolic constants for the indexes into an optionInfo list.
+_OPT_DEFAULT         = 0
+_OPT_VALUE           = 1
+_OPT_FUNCTION        = 2
+
+# Stacks
+
+_busyStack = []
+    # Stack which tracks nested calls to show/hidebusycursor (called
+    # either directly or from activate()/deactivate()).  Each element
+    # is a dictionary containing:
+    #   'newBusyWindows' :  List of windows which had busy_hold called
+    #                       on them during a call to showbusycursor(). 
+    #                       The corresponding call to hidebusycursor()
+    #                       will call busy_release on these windows.
+    #   'busyFocus' :       The blt _Busy window which showbusycursor()
+    #                       set the focus to.
+    #   'previousFocus' :   The focus as it was when showbusycursor()
+    #                       was called.  The corresponding call to
+    #                       hidebusycursor() will restore this focus if
+    #                       the focus has not been changed from busyFocus.
+
+_grabStack = []
+    # Stack of grabbed windows.  It tracks calls to push/popgrab()
+    # (called either directly or from activate()/deactivate()).  The
+    # window on the top of the stack is the window currently with the
+    # grab.  Each element is a dictionary containing:
+    #   'grabWindow' :      The window grabbed by pushgrab().  The
+    #                       corresponding call to popgrab() will release
+    #                       the grab on this window and restore the grab
+    #                       on the next window in the stack (if there is one).
+    #   'globalMode' :      True if the grabWindow was grabbed with a
+    #                       global grab, false if the grab was local
+    #                       and 'nograb' if no grab was performed.
+    #   'previousFocus' :   The focus as it was when pushgrab()
+    #                       was called.  The corresponding call to
+    #                       popgrab() will restore this focus.
+    #   'deactivateFunction' :
+    #       The function to call (usually grabWindow.deactivate) if
+    #       popgrab() is called (usually from a deactivate() method)
+    #       on a window which is not at the top of the stack (that is,
+    #       does not have the grab or focus).  For example, if a modal
+    #       dialog is deleted by the window manager or deactivated by
+    #       a timer.  In this case, all dialogs above and including
+    #       this one are deactivated, starting at the top of the
+    #       stack.
+
+    # Note that when dealing with focus windows, the name of the Tk
+    # widget is used, since it may be the '_Busy' window, which has no
+    # python instance associated with it.
+
+#=============================================================================
+
+# Functions used to forward methods from a class to a component.
+
+# Fill in a flattened method resolution dictionary for a class (attributes are 
+# filtered out). Flattening honours the MI method resolution rules 
+# (depth-first search of bases in order). The dictionary has method names
+# for keys and functions for values.
+def __methodDict(cls, dict):
+
+    # the strategy is to traverse the class in the _reverse_ of the normal
+    # order, and overwrite any duplicates.
+    baseList = list(cls.__bases__)
+    baseList.reverse()
+    
+    # do bases in reverse order, so first base overrides last base
+    for super in baseList:
+       __methodDict(super, dict)
+
+    # do my methods last to override base classes
+    for key, value in cls.__dict__.items():
+       # ignore class attributes
+       if type(value) == types.FunctionType:
+           dict[key] = value
+
+def __methods(cls):
+    # Return all method names for a class.
+
+    # Return all method names for a class (attributes are filtered
+    # out).  Base classes are searched recursively.
+
+    dict = {}
+    __methodDict(cls, dict)
+    return dict.keys()
+       
+# Function body to resolve a forwarding given the target method name and the 
+# attribute name. The resulting lambda requires only self, but will forward 
+# any other parameters.
+__stringBody = (
+    'def %(method)s(this, *args, **kw): return ' +
+    'apply(this.%(attribute)s.%(method)s, args, kw)')
+
+# Get a unique id
+__counter = 0
+def __unique():
+  global __counter
+  __counter = __counter + 1
+  return str(__counter)
+
+# Function body to resolve a forwarding given the target method name and the
+# index of the resolution function. The resulting lambda requires only self, 
+# but will forward any other parameters. The target instance is identified 
+# by invoking the resolution function.
+__funcBody = (
+    'def %(method)s(this, *args, **kw): return ' +
+    'apply(this.%(forwardFunc)s().%(method)s, args, kw)')
+
+def forwardmethods(fromClass, toClass, toPart, exclude = ()):
+    # Forward all methods from one class to another.
+
+    # Forwarders will be created in fromClass to forward method
+    # invocations to toClass.  The methods to be forwarded are
+    # identified by flattening the interface of toClass, and excluding
+    # methods identified in the exclude list.  Methods already defined
+    # in fromClass, or special methods with one or more leading or
+    # trailing underscores will not be forwarded.
+
+    # For a given object of class fromClass, the corresponding toClass
+    # object is identified using toPart.  This can either be a String
+    # denoting an attribute of fromClass objects, or a function taking
+    # a fromClass object and returning a toClass object.
+
+    # Example:
+    #     class MyClass:
+    #     ...
+    #         def __init__(self):
+    #             ...
+    #             self.__target = TargetClass()
+    #             ...
+    #         def findtarget(self):
+    #             return self.__target
+    #     forwardmethods(MyClass, TargetClass, '__target', ['dangerous1', 'dangerous2'])
+    #     # ...or...
+    #     forwardmethods(MyClass, TargetClass, MyClass.findtarget, 
+    #             ['dangerous1', 'dangerous2'])
+
+    # In both cases, all TargetClass methods will be forwarded from
+    # MyClass except for dangerous1, dangerous2, special methods like
+    # __str__, and pre-existing methods like findtarget.
+
+
+    # Allow an attribute name (String) or a function to determine the instance
+    if type(toPart) != types.StringType:
+
+       # check that it is something like a function
+       if callable(toPart):
+
+           # If a method is passed, use the function within it
+           if hasattr(toPart, 'im_func'):
+               toPart = toPart.im_func
+               
+           # After this is set up, forwarders in this class will use
+           # the forwarding function. The forwarding function name is
+           # guaranteed to be unique, so that it can't be hidden by subclasses
+           forwardName = '__fwdfunc__' + __unique()
+           fromClass.__dict__[forwardName] = toPart
+
+       # It's not a valid type
+       else:
+           raise TypeError, 'toPart must be attribute name, function or method'
+
+    # get the full set of candidate methods
+    dict = {}
+    __methodDict(toClass, dict)
+
+    # discard special methods
+    for ex in dict.keys():
+       if ex[:1] == '_' or ex[-1:] == '_':
+           del dict[ex]
+    # discard dangerous methods supplied by the caller
+    for ex in exclude:
+       if dict.has_key(ex):
+           del dict[ex]
+    # discard methods already defined in fromClass
+    for ex in __methods(fromClass):
+       if dict.has_key(ex):
+           del dict[ex]
+
+    for method, func in dict.items():
+       d = {'method': method, 'func': func}
+       if type(toPart) == types.StringType:
+           execString = \
+               __stringBody % {'method' : method, 'attribute' : toPart}
+       else:
+           execString = \
+               __funcBody % {'forwardFunc' : forwardName, 'method' : method}
+
+       exec execString in d
+
+       # this creates a method
+       fromClass.__dict__[method] = d[method]
+
+#=============================================================================
+
+def setgeometryanddeiconify(window, geom):
+    # To avoid flashes on X and to position the window correctly on NT
+    # (caused by Tk bugs).
+
+    if os.name == 'nt' or \
+            (os.name == 'posix' and sys.platform[:6] == 'cygwin'):
+        # Require overrideredirect trick to stop window frame
+        # appearing momentarily.
+        redirect = window.overrideredirect()
+        if not redirect:
+            window.overrideredirect(1)
+        window.deiconify()
+        if geom is not None:
+            window.geometry(geom)
+        # Call update_idletasks to ensure NT moves the window to the
+        # correct position it is raised.
+        window.update_idletasks()
+        window.tkraise()
+        if not redirect:
+            window.overrideredirect(0)
+    else:
+        if geom is not None:
+            window.geometry(geom)
+
+        # Problem!?  Which way around should the following two calls
+        # go?  If deiconify() is called first then I get complaints
+        # from people using the enlightenment or sawfish window
+        # managers that when a dialog is activated it takes about 2
+        # seconds for the contents of the window to appear.  But if
+        # tkraise() is called first then I get complaints from people
+        # using the twm window manager that when a dialog is activated
+        # it appears in the top right corner of the screen and also
+        # takes about 2 seconds to appear.
+
+        #window.tkraise()
+        # Call update_idletasks to ensure certain window managers (eg: 
+        # enlightenment and sawfish) do not cause Tk to delay for
+        # about two seconds before displaying window.
+        #window.update_idletasks()
+        #window.deiconify()
+
+        window.deiconify()
+        if window.overrideredirect():
+            # The window is not under the control of the window manager
+            # and so we need to raise it ourselves.
+            window.tkraise()
+
+#=============================================================================
+
+class MegaArchetype:
+    # Megawidget abstract root class.
+
+    # This class provides methods which are inherited by classes
+    # implementing useful bases (this class doesn't provide a
+    # container widget inside which the megawidget can be built).
+
+    def __init__(self, parent = None, hullClass = None):
+
+       # Mapping from each megawidget option to a list of information
+       # about the option
+       #   - default value
+       #   - current value
+       #   - function to call when the option is initialised in the
+       #     call to initialiseoptions() in the constructor or
+       #     modified via configure().  If this is INITOPT, the
+       #     option is an initialisation option (an option that can
+       #     be set by the call to the constructor but can not be
+       #     used with configure).
+       # This mapping is not initialised here, but in the call to
+       # defineoptions() which precedes construction of this base class.
+       #
+       # self._optionInfo = {}
+
+       # Mapping from each component name to a tuple of information
+       # about the component.
+       #   - component widget instance
+       #   - configure function of widget instance
+       #   - the class of the widget (Frame, EntryField, etc)
+       #   - cget function of widget instance
+       #   - the name of the component group of this component, if any
+       self.__componentInfo = {}
+
+       # Mapping from alias names to the names of components or
+       # sub-components.
+       self.__componentAliases = {}
+
+       # Contains information about the keywords provided to the
+       # constructor.  It is a mapping from the keyword to a tuple
+       # containing:
+       #    - value of keyword
+       #    - a boolean indicating if the keyword has been used.
+       # A keyword is used if, during the construction of a megawidget,
+       #    - it is defined in a call to defineoptions() or addoptions(), or
+       #    - it references, by name, a component of the megawidget, or
+       #    - it references, by group, at least one component
+       # At the end of megawidget construction, a call is made to
+       # initialiseoptions() which reports an error if there are
+       # unused options given to the constructor.
+        #
+        # After megawidget construction, the dictionary contains
+        # keywords which refer to a dynamic component group, so that
+        # these components can be created after megawidget
+        # construction and still use the group options given to the
+        # constructor.
+       #
+       # self._constructorKeywords = {}
+
+        # List of dynamic component groups.  If a group is included in
+        # this list, then it not an error if a keyword argument for
+        # the group is given to the constructor or to configure(), but
+        # no components with this group have been created.
+        # self._dynamicGroups = ()
+
+       if hullClass is None:
+           self._hull = None
+       else:
+           if parent is None:
+               parent = Tkinter._default_root
+
+           # Create the hull.
+           self._hull = self.createcomponent('hull',
+                   (), None,
+                   hullClass, (parent,))
+           _hullToMegaWidget[self._hull] = self
+
+           if _useTkOptionDb:
+               # Now that a widget has been created, query the Tk
+               # option database to get the default values for the
+               # options which have not been set in the call to the
+               # constructor.  This assumes that defineoptions() is
+               # called before the __init__().
+               option_get = self.option_get
+               _VALUE = _OPT_VALUE
+               _DEFAULT = _OPT_DEFAULT
+               for name, info in self._optionInfo.items():
+                   value = info[_VALUE]
+                   if value is _DEFAULT_OPTION_VALUE:
+                       resourceClass = string.upper(name[0]) + name[1:]
+                       value = option_get(name, resourceClass)
+                       if value != '':
+                           try:
+                               # Convert the string to int/float/tuple, etc
+                               value = eval(value, {'__builtins__': {}})
+                           except:
+                               pass
+                           info[_VALUE] = value
+                       else:
+                           info[_VALUE] = info[_DEFAULT]
+
+    def destroy(self):
+        # Clean up optionInfo in case it contains circular references
+        # in the function field, such as self._settitle in class
+        # MegaToplevel.
+
+       self._optionInfo = {}
+        if self._hull is not None:
+            del _hullToMegaWidget[self._hull]
+            self._hull.destroy()
+
+    #======================================================================
+    # Methods used (mainly) during the construction of the megawidget.
+
+    def defineoptions(self, keywords, optionDefs, dynamicGroups = ()):
+       # Create options, providing the default value and the method
+       # to call when the value is changed.  If any option created by
+       # base classes has the same name as one in <optionDefs>, the
+       # base class's value and function will be overriden.
+
+       # This should be called before the constructor of the base
+       # class, so that default values defined in the derived class
+       # override those in the base class.
+
+       if not hasattr(self, '_constructorKeywords'):
+            # First time defineoptions has been called.
+           tmp = {}
+           for option, value in keywords.items():
+               tmp[option] = [value, 0]
+           self._constructorKeywords = tmp
+           self._optionInfo = {}
+           self._initialiseoptions_counter = 0
+        self._initialiseoptions_counter = self._initialiseoptions_counter + 1
+
+        if not hasattr(self, '_dynamicGroups'):
+            self._dynamicGroups = ()
+        self._dynamicGroups = self._dynamicGroups + tuple(dynamicGroups)
+       self.addoptions(optionDefs)
+
+    def addoptions(self, optionDefs):
+       # Add additional options, providing the default value and the
+       # method to call when the value is changed.  See
+       # "defineoptions" for more details
+
+       # optimisations:
+       optionInfo = self._optionInfo
+       optionInfo_has_key = optionInfo.has_key
+       keywords = self._constructorKeywords
+       keywords_has_key = keywords.has_key
+       FUNCTION = _OPT_FUNCTION
+
+       for name, default, function in optionDefs:
+           if '_' not in name:
+               # The option will already exist if it has been defined
+               # in a derived class.  In this case, do not override the
+               # default value of the option or the callback function
+               # if it is not None.
+               if not optionInfo_has_key(name):
+                   if keywords_has_key(name):
+                       value = keywords[name][0]
+                       optionInfo[name] = [default, value, function]
+                       del keywords[name]
+                   else:
+                       if _useTkOptionDb:
+                           optionInfo[name] = \
+                                   [default, _DEFAULT_OPTION_VALUE, function]
+                       else:
+                           optionInfo[name] = [default, default, function]
+               elif optionInfo[name][FUNCTION] is None:
+                   optionInfo[name][FUNCTION] = function
+           else:
+               # This option is of the form "component_option".  If this is
+               # not already defined in self._constructorKeywords add it.
+               # This allows a derived class to override the default value
+               # of an option of a component of a base class.
+               if not keywords_has_key(name):
+                   keywords[name] = [default, 0]
+
+    def createcomponent(self, componentName, componentAliases,
+            componentGroup, widgetClass, *widgetArgs, **kw):
+       # Create a component (during construction or later).
+
+       if self.__componentInfo.has_key(componentName):
+           raise ValueError, 'Component "%s" already exists' % componentName
+
+       if '_' in componentName:
+           raise ValueError, \
+                    'Component name "%s" must not contain "_"' % componentName
+
+       if hasattr(self, '_constructorKeywords'):
+           keywords = self._constructorKeywords
+       else:
+           keywords = {}
+       for alias, component in componentAliases:
+           # Create aliases to the component and its sub-components.
+           index = string.find(component, '_')
+           if index < 0:
+               self.__componentAliases[alias] = (component, None)
+           else:
+               mainComponent = component[:index]
+               subComponent = component[(index + 1):]
+               self.__componentAliases[alias] = (mainComponent, subComponent)
+
+           # Remove aliases from the constructor keyword arguments by
+           # replacing any keyword arguments that begin with *alias*
+           # with corresponding keys beginning with *component*.
+
+           alias = alias + '_'
+           aliasLen = len(alias)
+           for option in keywords.keys():
+               if len(option) > aliasLen and option[:aliasLen] == alias:
+                   newkey = component + '_' + option[aliasLen:]
+                   keywords[newkey] = keywords[option]
+                   del keywords[option]
+
+       componentPrefix = componentName + '_'
+       nameLen = len(componentPrefix)
+       for option in keywords.keys():
+           if len(option) > nameLen and option[:nameLen] == componentPrefix:
+               # The keyword argument refers to this component, so add
+               # this to the options to use when constructing the widget.
+               kw[option[nameLen:]] = keywords[option][0]
+               del keywords[option]
+           else:
+               # Check if this keyword argument refers to the group
+               # of this component.  If so, add this to the options
+               # to use when constructing the widget.  Mark the
+               # keyword argument as being used, but do not remove it
+               # since it may be required when creating another
+               # component.
+               index = string.find(option, '_')
+               if index >= 0 and componentGroup == option[:index]:
+                   rest = option[(index + 1):]
+                   kw[rest] = keywords[option][0]
+                   keywords[option][1] = 1
+
+       if kw.has_key('pyclass'):
+           widgetClass = kw['pyclass']
+           del kw['pyclass']
+       if widgetClass is None:
+           return None
+        if len(widgetArgs) == 1 and type(widgetArgs[0]) == types.TupleType:
+            # Arguments to the constructor can be specified as either
+            # multiple trailing arguments to createcomponent() or as a
+            # single tuple argument.
+            widgetArgs = widgetArgs[0]
+       widget = apply(widgetClass, widgetArgs, kw)
+       componentClass = widget.__class__.__name__
+       self.__componentInfo[componentName] = (widget, widget.configure,
+               componentClass, widget.cget, componentGroup)
+
+       return widget
+
+    def destroycomponent(self, name):
+       # Remove a megawidget component.
+
+       # This command is for use by megawidget designers to destroy a
+       # megawidget component.
+
+       self.__componentInfo[name][0].destroy()
+       del self.__componentInfo[name]
+
+    def createlabel(self, parent, childCols = 1, childRows = 1):
+
+       labelpos = self['labelpos']
+       labelmargin = self['labelmargin']
+       if labelpos is None:
+           return
+
+       label = self.createcomponent('label',
+               (), None,
+               Tkinter.Label, (parent,))
+
+       if labelpos[0] in 'ns':
+           # vertical layout
+           if labelpos[0] == 'n':
+               row = 0
+               margin = 1
+           else:
+               row = childRows + 3
+               margin = row - 1
+           label.grid(column=2, row=row, columnspan=childCols, sticky=labelpos)
+           parent.grid_rowconfigure(margin, minsize=labelmargin)
+       else:
+           # horizontal layout
+           if labelpos[0] == 'w':
+               col = 0
+               margin = 1
+           else:
+               col = childCols + 3
+               margin = col - 1
+           label.grid(column=col, row=2, rowspan=childRows, sticky=labelpos)
+           parent.grid_columnconfigure(margin, minsize=labelmargin)
+
+    def initialiseoptions(self, dummy = None):
+        self._initialiseoptions_counter = self._initialiseoptions_counter - 1
+       if self._initialiseoptions_counter == 0:
+           unusedOptions = []
+           keywords = self._constructorKeywords
+           for name in keywords.keys():
+               used = keywords[name][1]
+               if not used:
+                    # This keyword argument has not been used.  If it
+                    # does not refer to a dynamic group, mark it as
+                    # unused.
+                    index = string.find(name, '_')
+                    if index < 0 or name[:index] not in self._dynamicGroups:
+                        unusedOptions.append(name)
+           if len(unusedOptions) > 0:
+               if len(unusedOptions) == 1:
+                   text = 'Unknown option "'
+               else:
+                   text = 'Unknown options "'
+               raise KeyError, text + string.join(unusedOptions, ', ') + \
+                       '" for ' + self.__class__.__name__
+
+           # Call the configuration callback function for every option.
+           FUNCTION = _OPT_FUNCTION
+           for info in self._optionInfo.values():
+               func = info[FUNCTION]
+               if func is not None and func is not INITOPT:
+                   func()
+
+    #======================================================================
+    # Method used to configure the megawidget.
+
+    def configure(self, option=None, **kw):
+       # Query or configure the megawidget options.
+       #
+       # If not empty, *kw* is a dictionary giving new
+       # values for some of the options of this megawidget or its
+       # components.  For options defined for this megawidget, set
+       # the value of the option to the new value and call the
+       # configuration callback function, if any.  For options of the
+       # form <component>_<option>, where <component> is a component
+       # of this megawidget, call the configure method of the
+       # component giving it the new value of the option.  The
+       # <component> part may be an alias or a component group name.
+       #
+       # If *option* is None, return all megawidget configuration
+       # options and settings.  Options are returned as standard 5
+       # element tuples
+       #
+       # If *option* is a string, return the 5 element tuple for the
+       # given configuration option.
+
+       # First, deal with the option queries.
+       if len(kw) == 0:
+           # This configure call is querying the values of one or all options.
+           # Return 5-tuples:
+           #     (optionName, resourceName, resourceClass, default, value)
+           if option is None:
+               rtn = {}
+               for option, config in self._optionInfo.items():
+                   resourceClass = string.upper(option[0]) + option[1:]
+                   rtn[option] = (option, option, resourceClass,
+                           config[_OPT_DEFAULT], config[_OPT_VALUE])
+               return rtn
+           else:
+               config = self._optionInfo[option]
+               resourceClass = string.upper(option[0]) + option[1:]
+               return (option, option, resourceClass, config[_OPT_DEFAULT],
+                       config[_OPT_VALUE])
+
+       # optimisations:
+       optionInfo = self._optionInfo
+       optionInfo_has_key = optionInfo.has_key
+       componentInfo = self.__componentInfo
+       componentInfo_has_key = componentInfo.has_key
+       componentAliases = self.__componentAliases
+       componentAliases_has_key = componentAliases.has_key
+       VALUE = _OPT_VALUE
+       FUNCTION = _OPT_FUNCTION
+
+       # This will contain a list of options in *kw* which
+       # are known to this megawidget.
+       directOptions = []
+
+       # This will contain information about the options in
+       # *kw* of the form <component>_<option>, where
+       # <component> is a component of this megawidget.  It is a
+       # dictionary whose keys are the configure method of each
+       # component and whose values are a dictionary of options and
+       # values for the component.
+       indirectOptions = {}
+       indirectOptions_has_key = indirectOptions.has_key
+
+       for option, value in kw.items():
+           if optionInfo_has_key(option):
+               # This is one of the options of this megawidget. 
+               # Make sure it is not an initialisation option.
+               if optionInfo[option][FUNCTION] is INITOPT:
+                   raise KeyError, \
+                           'Cannot configure initialisation option "' \
+                           + option + '" for ' + self.__class__.__name__
+               optionInfo[option][VALUE] = value
+               directOptions.append(option)
+           else:
+               index = string.find(option, '_')
+               if index >= 0:
+                   # This option may be of the form <component>_<option>.
+                   component = option[:index]
+                   componentOption = option[(index + 1):]
+
+                   # Expand component alias
+                   if componentAliases_has_key(component):
+                       component, subComponent = componentAliases[component]
+                       if subComponent is not None:
+                           componentOption = subComponent + '_' \
+                                   + componentOption
+
+                       # Expand option string to write on error
+                       option = component + '_' + componentOption
+
+                   if componentInfo_has_key(component):
+                       # Configure the named component
+                       componentConfigFuncs = [componentInfo[component][1]]
+                   else:
+                       # Check if this is a group name and configure all
+                       # components in the group.
+                       componentConfigFuncs = []
+                       for info in componentInfo.values():
+                           if info[4] == component:
+                               componentConfigFuncs.append(info[1])
+
+                        if len(componentConfigFuncs) == 0 and \
+                                component not in self._dynamicGroups:
+                           raise KeyError, 'Unknown option "' + option + \
+                                   '" for ' + self.__class__.__name__
+
+                   # Add the configure method(s) (may be more than
+                   # one if this is configuring a component group)
+                   # and option/value to dictionary.
+                   for componentConfigFunc in componentConfigFuncs:
+                       if not indirectOptions_has_key(componentConfigFunc):
+                           indirectOptions[componentConfigFunc] = {}
+                       indirectOptions[componentConfigFunc][componentOption] \
+                               = value
+               else:
+                   raise KeyError, 'Unknown option "' + option + \
+                           '" for ' + self.__class__.__name__
+
+       # Call the configure methods for any components.
+       map(apply, indirectOptions.keys(),
+               ((),) * len(indirectOptions), indirectOptions.values())
+
+       # Call the configuration callback function for each option.
+       for option in directOptions:
+           info = optionInfo[option]
+           func = info[_OPT_FUNCTION]
+           if func is not None:
+             func()
+
+    def __setitem__(self, key, value):
+        apply(self.configure, (), {key: value})
+
+    #======================================================================
+    # Methods used to query the megawidget.
+
+    def component(self, name):
+       # Return a component widget of the megawidget given the
+       # component's name
+       # This allows the user of a megawidget to access and configure
+       # widget components directly.
+
+       # Find the main component and any subcomponents
+       index = string.find(name, '_')
+       if index < 0:
+           component = name
+           remainingComponents = None
+       else:
+           component = name[:index]
+           remainingComponents = name[(index + 1):]
+
+       # Expand component alias
+       if self.__componentAliases.has_key(component):
+           component, subComponent = self.__componentAliases[component]
+           if subComponent is not None:
+               if remainingComponents is None:
+                   remainingComponents = subComponent
+               else:
+                   remainingComponents = subComponent + '_' \
+                           + remainingComponents
+
+       widget = self.__componentInfo[component][0]
+       if remainingComponents is None:
+           return widget
+       else:
+           return widget.component(remainingComponents)
+
+    def interior(self):
+       return self._hull
+
+    def hulldestroyed(self):
+       return not _hullToMegaWidget.has_key(self._hull)
+
+    def __str__(self):
+       return str(self._hull)
+
+    def cget(self, option):
+       # Get current configuration setting.
+
+       # Return the value of an option, for example myWidget['font']. 
+
+       if self._optionInfo.has_key(option):
+           return self._optionInfo[option][_OPT_VALUE]
+       else:
+           index = string.find(option, '_')
+           if index >= 0:
+               component = option[:index]
+               componentOption = option[(index + 1):]
+
+               # Expand component alias
+               if self.__componentAliases.has_key(component):
+                   component, subComponent = self.__componentAliases[component]
+                   if subComponent is not None:
+                       componentOption = subComponent + '_' + componentOption
+
+                   # Expand option string to write on error
+                   option = component + '_' + componentOption
+
+               if self.__componentInfo.has_key(component):
+                   # Call cget on the component.
+                   componentCget = self.__componentInfo[component][3]
+                   return componentCget(componentOption)
+               else:
+                   # If this is a group name, call cget for one of
+                   # the components in the group.
+                   for info in self.__componentInfo.values():
+                       if info[4] == component:
+                           componentCget = info[3]
+                           return componentCget(componentOption)
+
+       raise KeyError, 'Unknown option "' + option + \
+               '" for ' + self.__class__.__name__
+
+    __getitem__ = cget
+
+    def isinitoption(self, option):
+       return self._optionInfo[option][_OPT_FUNCTION] is INITOPT
+
+    def options(self):
+       options = []
+       if hasattr(self, '_optionInfo'):
+           for option, info in self._optionInfo.items():
+               isinit = info[_OPT_FUNCTION] is INITOPT
+               default = info[_OPT_DEFAULT]
+               options.append((option, default, isinit))
+           options.sort()
+       return options
+
+    def components(self):
+       # Return a list of all components.
+
+       # This list includes the 'hull' component and all widget subcomponents
+
+       names = self.__componentInfo.keys()
+       names.sort()
+       return names
+
+    def componentaliases(self):
+       # Return a list of all component aliases.
+
+       componentAliases = self.__componentAliases
+
+       names = componentAliases.keys()
+       names.sort()
+       rtn = []
+       for alias in names:
+           (mainComponent, subComponent) = componentAliases[alias]
+           if subComponent is None:
+               rtn.append((alias, mainComponent))
+           else:
+               rtn.append((alias, mainComponent + '_' + subComponent))
+           
+       return rtn
+
+    def componentgroup(self, name):
+       return self.__componentInfo[name][4]
+
+#=============================================================================
+
+# The grab functions are mainly called by the activate() and
+# deactivate() methods.
+#
+# Use pushgrab() to add a new window to the grab stack.  This
+# releases the grab by the window currently on top of the stack (if
+# there is one) and gives the grab and focus to the new widget.
+#
+# To remove the grab from the window on top of the grab stack, call
+# popgrab().
+#
+# Use releasegrabs() to release the grab and clear the grab stack.
+
+def pushgrab(grabWindow, globalMode, deactivateFunction):
+    prevFocus = grabWindow.tk.call('focus')
+    grabInfo = {
+        'grabWindow' : grabWindow,
+        'globalMode' : globalMode,
+        'previousFocus' : prevFocus,
+        'deactivateFunction' : deactivateFunction,
+    }
+    _grabStack.append(grabInfo)
+    _grabtop()
+    grabWindow.focus_set()
+
+def popgrab(window):
+    # Return the grab to the next window in the grab stack, if any.
+
+    # If this window is not at the top of the grab stack, then it has
+    # just been deleted by the window manager or deactivated by a
+    # timer.  Call the deactivate method for the modal dialog above
+    # this one on the stack. 
+    if _grabStack[-1]['grabWindow'] != window:
+        for index in range(len(_grabStack)):
+            if _grabStack[index]['grabWindow'] == window:
+                _grabStack[index + 1]['deactivateFunction']()
+                break
+
+    grabInfo = _grabStack[-1]
+    del _grabStack[-1]
+
+    topWidget = grabInfo['grabWindow']
+    prevFocus = grabInfo['previousFocus']
+    globalMode = grabInfo['globalMode']
+
+    if globalMode != 'nograb':
+        topWidget.grab_release()
+
+    if len(_grabStack) > 0:
+        _grabtop()
+    if prevFocus != '':
+        try:
+            topWidget.tk.call('focus', prevFocus)
+        except Tkinter.TclError:
+            # Previous focus widget has been deleted. Set focus
+            # to root window.
+            Tkinter._default_root.focus_set()
+    else:
+        # Make sure that focus does not remain on the released widget.
+        if len(_grabStack) > 0:
+            topWidget = _grabStack[-1]['grabWindow']
+            topWidget.focus_set()
+        else:
+            Tkinter._default_root.focus_set()
+
+def grabstacktopwindow():
+    if len(_grabStack) == 0:
+        return None
+    else:
+        return _grabStack[-1]['grabWindow']
+
+def releasegrabs():
+    # Release grab and clear the grab stack.
+
+    current = Tkinter._default_root.grab_current()
+    if current is not None:
+        current.grab_release()
+    _grabStack[:] = []
+
+def _grabtop():
+    grabInfo = _grabStack[-1]
+    topWidget = grabInfo['grabWindow']
+    globalMode = grabInfo['globalMode']
+
+    if globalMode == 'nograb':
+        return
+
+    while 1:
+        try:
+            if globalMode:
+                topWidget.grab_set_global()
+            else:
+                topWidget.grab_set()
+            break
+        except Tkinter.TclError:
+            # Another application has grab.  Keep trying until
+            # grab can succeed.
+            topWidget.after(100)
+
+#=============================================================================
+
+class MegaToplevel(MegaArchetype):
+
+    def __init__(self, parent = None, **kw):
+       # Define the options for this megawidget.
+       optiondefs = (
+            ('activatecommand',   None,                     None),
+            ('deactivatecommand', None,                     None),
+            ('master',            None,                     None),
+            ('title',             None,                     self._settitle),
+            ('hull_class',        self.__class__.__name__,  None),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       MegaArchetype.__init__(self, parent, Tkinter.Toplevel)
+
+       # Initialise instance.
+
+        # Set WM_DELETE_WINDOW protocol, deleting any old callback, so
+        # memory does not leak.
+        if hasattr(self._hull, '_Pmw_WM_DELETE_name'):
+            self._hull.tk.deletecommand(self._hull._Pmw_WM_DELETE_name)
+        self._hull._Pmw_WM_DELETE_name = \
+                self.register(self._userDeleteWindow, needcleanup = 0)
+       self.protocol('WM_DELETE_WINDOW', self._hull._Pmw_WM_DELETE_name)
+
+       # Initialise instance variables.
+
+       self._firstShowing = 1
+       # Used by show() to ensure window retains previous position on screen.
+
+       # The IntVar() variable to wait on during a modal dialog.
+       self._wait = None
+
+       self._active = 0
+       self._userDeleteFunc = self.destroy
+       self._userModalDeleteFunc = self.deactivate
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _settitle(self):
+       title = self['title']
+       if title is not None:
+           self.title(title)
+
+    def userdeletefunc(self, func=None):
+        if func:
+           self._userDeleteFunc = func
+       else:
+           return self._userDeleteFunc
+
+    def usermodaldeletefunc(self, func=None):
+        if func:
+           self._userModalDeleteFunc = func
+       else:
+           return self._userModalDeleteFunc
+
+    def _userDeleteWindow(self):
+       if self.active():
+           self._userModalDeleteFunc()
+       else:
+           self._userDeleteFunc()
+
+    def destroy(self):
+       # Allow this to be called more than once.
+       if _hullToMegaWidget.has_key(self._hull):
+           self.deactivate()
+
+            # Remove circular references, so that object can get cleaned up.
+            del self._userDeleteFunc
+            del self._userModalDeleteFunc
+
+            MegaArchetype.destroy(self)
+
+    def show(self, master = None):
+       if self.state() != 'normal':
+           if self._firstShowing:
+               # Just let the window manager determine the window
+               # position for the first time.
+               geom = None
+           else:
+               # Position the window at the same place it was last time.
+               geom = self._sameposition()
+            setgeometryanddeiconify(self, geom)
+
+        if self._firstShowing:
+            self._firstShowing = 0
+        else:
+            if self.transient() == '':
+                self.tkraise()
+
+        # Do this last, otherwise get flashing on NT:
+        if master is not None:
+            if master == 'parent':
+                parent = self.winfo_parent()
+                # winfo_parent() should return the parent widget, but the
+                # the current version of Tkinter returns a string.
+                if type(parent) == types.StringType:
+                    parent = self._hull._nametowidget(parent)
+                master = parent.winfo_toplevel()
+            self.transient(master)
+
+        self.focus()
+
+    def _centreonscreen(self):
+       # Centre the window on the screen.  (Actually halfway across
+       # and one third down.)
+
+        parent = self.winfo_parent()
+        if type(parent) == types.StringType:
+            parent = self._hull._nametowidget(parent)
+
+        # Find size of window.
+       self.update_idletasks()
+        width = self.winfo_width()
+        height = self.winfo_height()
+        if width == 1 and height == 1:
+            # If the window has not yet been displayed, its size is
+            # reported as 1x1, so use requested size.
+            width = self.winfo_reqwidth()
+            height = self.winfo_reqheight()
+
+        # Place in centre of screen:
+       x = (self.winfo_screenwidth() - width) / 2 - parent.winfo_vrootx()
+       y = (self.winfo_screenheight() - height) / 3 - parent.winfo_vrooty()
+       if x < 0:
+           x = 0
+       if y < 0:
+           y = 0
+        return '+%d+%d' % (x, y)
+
+    def _sameposition(self):
+       # Position the window at the same place it was last time.
+
+       geometry = self.geometry()
+       index = string.find(geometry, '+')
+       if index >= 0:
+           return geometry[index:]
+        else:
+           return None
+
+    def activate(self, globalMode = 0, geometry = 'centerscreenfirst'):
+       if self._active:
+           raise ValueError, 'Window is already active'
+       if self.state() == 'normal':
+           self.withdraw()
+
+       self._active = 1
+
+       showbusycursor()
+
+       if self._wait is None:
+           self._wait = Tkinter.IntVar()
+       self._wait.set(0)
+
+       if geometry == 'centerscreenalways':
+           geom = self._centreonscreen()
+       elif geometry == 'centerscreenfirst':
+           if self._firstShowing:
+               # Centre the window the first time it is displayed.
+               geom = self._centreonscreen()
+           else:
+               # Position the window at the same place it was last time.
+               geom = self._sameposition()
+       elif geometry[:5] == 'first':
+           if self._firstShowing:
+                geom = geometry[5:]
+           else:
+               # Position the window at the same place it was last time.
+               geom = self._sameposition()
+        else:
+            geom = geometry
+
+       self._firstShowing = 0
+
+        setgeometryanddeiconify(self, geom)
+
+        # Do this last, otherwise get flashing on NT:
+        master = self['master']
+        if master is not None:
+            if master == 'parent':
+                parent = self.winfo_parent()
+                # winfo_parent() should return the parent widget, but the
+                # the current version of Tkinter returns a string.
+                if type(parent) == types.StringType:
+                    parent = self._hull._nametowidget(parent)
+                master = parent.winfo_toplevel()
+            self.transient(master)
+
+        pushgrab(self._hull, globalMode, self.deactivate)
+       command = self['activatecommand']
+       if callable(command):
+           command()
+       self.wait_variable(self._wait)
+
+       return self._result
+
+    def deactivate(self, result=None):
+       if not self._active:
+           return
+       self._active = 0
+
+        # Restore the focus before withdrawing the window, since
+        # otherwise the window manager may take the focus away so we
+        # can't redirect it.  Also, return the grab to the next active
+        # window in the stack, if any.
+        popgrab(self._hull)
+
+        command = self['deactivatecommand']
+        if callable(command):
+            command()
+
+        self.withdraw()
+        hidebusycursor(forceFocusRestore = 1)
+
+        self._result = result
+        self._wait.set(1)
+
+    def active(self):
+       return self._active
+
+forwardmethods(MegaToplevel, Tkinter.Toplevel, '_hull')
+
+#=============================================================================
+
+class MegaWidget(MegaArchetype):
+    def __init__(self, parent = None, **kw):
+       # Define the options for this megawidget.
+       optiondefs = (
+           ('hull_class',       self.__class__.__name__,  None),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       MegaArchetype.__init__(self, parent, Tkinter.Frame)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+forwardmethods(MegaWidget, Tkinter.Frame, '_hull')
+
+#=============================================================================
+
+# Public functions
+#-----------------
+
+_traceTk = 0
+def tracetk(root = None, on = 1, withStackTrace = 0, file=None):
+    global _withStackTrace
+    global _traceTkFile
+    global _traceTk
+
+    if root is None:
+        root = Tkinter._default_root
+
+    _withStackTrace = withStackTrace
+    _traceTk = on
+    if on:
+       if hasattr(root.tk, '__class__'):
+           # Tracing already on
+           return
+       if file is None:
+           _traceTkFile = sys.stderr
+       else:
+           _traceTkFile = file
+       tk = _TraceTk(root.tk)
+    else:
+       if not hasattr(root.tk, '__class__'):
+           # Tracing already off
+           return
+       tk = root.tk.getTclInterp()
+    _setTkInterps(root, tk)
+
+def showbusycursor():
+
+    _addRootToToplevelBusyInfo()
+    root = Tkinter._default_root
+
+    busyInfo = {
+        'newBusyWindows' : [],
+        'previousFocus' : None,
+        'busyFocus' : None,
+    }
+    _busyStack.append(busyInfo)
+
+    if _disableKeyboardWhileBusy:
+        # Remember the focus as it is now, before it is changed.
+        busyInfo['previousFocus'] = root.tk.call('focus')
+
+    if not _havebltbusy(root):
+        # No busy command, so don't call busy hold on any windows.
+        return
+
+    for (window, winInfo) in _toplevelBusyInfo.items():
+       if (window.state() != 'withdrawn' and not winInfo['isBusy']
+                and not winInfo['excludeFromBusy']):
+            busyInfo['newBusyWindows'].append(window)
+            winInfo['isBusy'] = 1
+            _busy_hold(window, winInfo['busyCursorName'])
+
+            # Make sure that no events for the busy window get
+            # through to Tkinter, otherwise it will crash in
+            # _nametowidget with a 'KeyError: _Busy' if there is
+            # a binding on the toplevel window.
+            window.tk.call('bindtags', winInfo['busyWindow'], 'Pmw_Dummy_Tag')
+
+            if _disableKeyboardWhileBusy:
+                # Remember previous focus widget for this toplevel window
+                # and set focus to the busy window, which will ignore all
+                # keyboard events.
+                winInfo['windowFocus'] = \
+                        window.tk.call('focus', '-lastfor', window._w)
+                window.tk.call('focus', winInfo['busyWindow'])
+                busyInfo['busyFocus'] = winInfo['busyWindow']
+
+    if len(busyInfo['newBusyWindows']) > 0:
+        if os.name == 'nt':
+            # NT needs an "update" before it will change the cursor.
+            window.update()
+        else:
+            window.update_idletasks()
+
+def hidebusycursor(forceFocusRestore = 0):
+
+    # Remember the focus as it is now, before it is changed.
+    root = Tkinter._default_root
+    if _disableKeyboardWhileBusy:
+        currentFocus = root.tk.call('focus')
+
+    # Pop the busy info off the stack.
+    busyInfo = _busyStack[-1]
+    del _busyStack[-1]
+
+    for window in busyInfo['newBusyWindows']:
+        # If this window has not been deleted, release the busy cursor.
+        if _toplevelBusyInfo.has_key(window):
+            winInfo = _toplevelBusyInfo[window]
+            winInfo['isBusy'] = 0
+            _busy_release(window)
+
+            if _disableKeyboardWhileBusy:
+                # Restore previous focus window for this toplevel window,
+                # but only if is still set to the busy window (it may have
+                # been changed).
+                windowFocusNow = window.tk.call('focus', '-lastfor', window._w)
+                if windowFocusNow == winInfo['busyWindow']:
+                    try:
+                        window.tk.call('focus', winInfo['windowFocus'])
+                    except Tkinter.TclError:
+                        # Previous focus widget has been deleted. Set focus
+                        # to toplevel window instead (can't leave focus on
+                        # busy window).
+                        window.focus_set()
+
+    if _disableKeyboardWhileBusy:
+        # Restore the focus, depending on whether the focus had changed
+        # between the calls to showbusycursor and hidebusycursor.
+        if forceFocusRestore or busyInfo['busyFocus'] == currentFocus:
+            # The focus had not changed, so restore it to as it was before
+            # the call to showbusycursor,
+            previousFocus = busyInfo['previousFocus']
+            if previousFocus is not None:
+                try:
+                    root.tk.call('focus', previousFocus)
+                except Tkinter.TclError:
+                    # Previous focus widget has been deleted; forget it.
+                    pass
+        else:
+            # The focus had changed, so restore it to what it had been
+            # changed to before the call to hidebusycursor.
+            root.tk.call('focus', currentFocus)
+
+def clearbusycursor():
+    while len(_busyStack) > 0:
+        hidebusycursor()
+
+def setbusycursorattributes(window, **kw):
+    _addRootToToplevelBusyInfo()
+    for name, value in kw.items():
+        if name == 'exclude':
+            _toplevelBusyInfo[window]['excludeFromBusy'] = value
+        elif name == 'cursorName':
+            _toplevelBusyInfo[window]['busyCursorName'] = value
+        else:
+            raise KeyError, 'Unknown busycursor attribute "' + name + '"'
+
+def _addRootToToplevelBusyInfo():
+    # Include the Tk root window in the list of toplevels.  This must
+    # not be called before Tkinter has had a chance to be initialised by
+    # the application.
+
+    root = Tkinter._default_root
+    if root == None:
+        root = Tkinter.Tk()
+    if not _toplevelBusyInfo.has_key(root):
+        _addToplevelBusyInfo(root)
+
+def busycallback(command, updateFunction = None):
+    if not callable(command):
+       raise ValueError, \
+           'cannot register non-command busy callback %s %s' % \
+               (repr(command), type(command))
+    wrapper = _BusyWrapper(command, updateFunction)
+    return wrapper.callback
+
+_errorReportFile = None
+_errorWindow = None
+
+def reporterrorstofile(file = None):
+    global _errorReportFile
+    _errorReportFile = file
+
+def displayerror(text):
+    global _errorWindow
+
+    if _errorReportFile is not None:
+       _errorReportFile.write(text + '\n')
+    else:
+        # Print error on standard error as well as to error window. 
+        # Useful if error window fails to be displayed, for example
+        # when exception is triggered in a <Destroy> binding for root
+        # window.
+        sys.stderr.write(text + '\n')
+
+       if _errorWindow is None:
+           # The error window has not yet been created.
+           _errorWindow = _ErrorWindow()
+
+       _errorWindow.showerror(text)
+
+_root = None
+_disableKeyboardWhileBusy = 1
+
+def initialise(
+        root = None,
+        size = None,
+        fontScheme = None,
+        useTkOptionDb = 0,
+        noBltBusy = 0,
+        disableKeyboardWhileBusy = None,
+):
+    # Remember if show/hidebusycursor should ignore keyboard events.
+    global _disableKeyboardWhileBusy
+    if disableKeyboardWhileBusy is not None:
+        _disableKeyboardWhileBusy = disableKeyboardWhileBusy
+
+    # Do not use blt busy command if noBltBusy is set.  Otherwise,
+    # use blt busy if it is available.
+    global _haveBltBusy
+    if noBltBusy:
+        _haveBltBusy = 0
+
+    # Save flag specifying whether the Tk option database should be
+    # queried when setting megawidget option default values.
+    global _useTkOptionDb
+    _useTkOptionDb = useTkOptionDb
+
+    # If we haven't been given a root window, use the default or
+    # create one.
+    if root is None:
+       if Tkinter._default_root is None:
+           root = Tkinter.Tk()
+       else:
+           root = Tkinter._default_root
+
+    # If this call is initialising a different Tk interpreter than the
+    # last call, then re-initialise all global variables.  Assume the
+    # last interpreter has been destroyed - ie:  Pmw does not (yet)
+    # support multiple simultaneous interpreters.
+    global _root
+    if _root is not None and _root != root:
+        global _busyStack
+        global _errorWindow
+        global _grabStack
+        global _hullToMegaWidget
+        global _toplevelBusyInfo
+        _busyStack = []
+        _errorWindow = None
+        _grabStack = []
+        _hullToMegaWidget = {}
+        _toplevelBusyInfo = {}
+    _root = root
+
+    # Trap Tkinter Toplevel constructors so that a list of Toplevels
+    # can be maintained.
+    Tkinter.Toplevel.title = __TkinterToplevelTitle
+
+    # Trap Tkinter widget destruction so that megawidgets can be
+    # destroyed when their hull widget is destoyed and the list of
+    # Toplevels can be pruned.
+    Tkinter.Toplevel.destroy = __TkinterToplevelDestroy
+    Tkinter.Widget.destroy = __TkinterWidgetDestroy
+
+    # Modify Tkinter's CallWrapper class to improve the display of
+    # errors which occur in callbacks.
+    Tkinter.CallWrapper = __TkinterCallWrapper
+
+    # Make sure we get to know when the window manager deletes the
+    # root window.  Only do this if the protocol has not yet been set. 
+    # This is required if there is a modal dialog displayed and the
+    # window manager deletes the root window.  Otherwise the
+    # application will not exit, even though there are no windows.
+    if root.protocol('WM_DELETE_WINDOW') == '':
+       root.protocol('WM_DELETE_WINDOW', root.destroy)
+
+    # Set the base font size for the application and set the
+    # Tk option database font resources.
+    import PmwLogicalFont
+    PmwLogicalFont._font_initialise(root, size, fontScheme)
+
+    return root
+
+def alignlabels(widgets, sticky = None):
+    if len(widgets) == 0:
+       return
+
+    widgets[0].update_idletasks()
+
+    # Determine the size of the maximum length label string.
+    maxLabelWidth = 0
+    for iwid in widgets:
+       labelWidth = iwid.grid_bbox(0, 1)[2]
+       if labelWidth > maxLabelWidth:
+           maxLabelWidth = labelWidth
+
+    # Adjust the margins for the labels such that the child sites and
+    # labels line up.
+    for iwid in widgets:
+       if sticky is not None:
+           iwid.component('label').grid(sticky=sticky)
+       iwid.grid_columnconfigure(0, minsize = maxLabelWidth)
+#=============================================================================
+
+# Private routines
+#-----------------
+_callToTkReturned = 1
+_recursionCounter = 1
+
+class _TraceTk:
+    def __init__(self, tclInterp):
+        self.tclInterp = tclInterp
+
+    def getTclInterp(self):
+        return self.tclInterp
+
+    # Calling from python into Tk.
+    def call(self, *args, **kw):
+        global _callToTkReturned
+        global _recursionCounter
+
+        _callToTkReturned = 0
+        if len(args) == 1 and type(args[0]) == types.TupleType:
+            argStr = str(args[0])
+        else:
+            argStr = str(args)
+       _traceTkFile.write('CALL  TK> %d:%s%s' %
+                (_recursionCounter, '  ' * _recursionCounter, argStr))
+       _recursionCounter = _recursionCounter + 1
+        try:
+            result = apply(self.tclInterp.call, args, kw)
+       except Tkinter.TclError, errorString:
+            _callToTkReturned = 1
+            _recursionCounter = _recursionCounter - 1
+            _traceTkFile.write('\nTK ERROR> %d:%s-> %s\n' %
+                    (_recursionCounter, '  ' * _recursionCounter,
+                            repr(errorString)))
+            if _withStackTrace:
+                _traceTkFile.write('CALL  TK> stack:\n')
+                traceback.print_stack()
+            raise Tkinter.TclError, errorString
+
+        _recursionCounter = _recursionCounter - 1
+        if _callToTkReturned:
+            _traceTkFile.write('CALL RTN> %d:%s-> %s' %
+                    (_recursionCounter, '  ' * _recursionCounter, repr(result)))
+        else:
+            _callToTkReturned = 1
+            if result:
+                _traceTkFile.write(' -> %s' % repr(result))
+        _traceTkFile.write('\n')
+        if _withStackTrace:
+            _traceTkFile.write('CALL  TK> stack:\n')
+            traceback.print_stack()
+
+        _traceTkFile.flush()
+        return result
+
+    def __getattr__(self, key):
+        return getattr(self.tclInterp, key)
+
+def _setTkInterps(window, tk):
+    window.tk = tk
+    for child in window.children.values():
+      _setTkInterps(child, tk)
+
+#=============================================================================
+
+# Functions to display a busy cursor.  Keep a list of all toplevels
+# and display the busy cursor over them.  The list will contain the Tk
+# root toplevel window as well as all other toplevel windows.
+# Also keep a list of the widget which last had focus for each
+# toplevel.
+
+# Map from toplevel windows to
+#     {'isBusy', 'windowFocus', 'busyWindow',
+#         'excludeFromBusy', 'busyCursorName'}
+_toplevelBusyInfo = {}
+
+# Pmw needs to know all toplevel windows, so that it can call blt busy
+# on them.  This is a hack so we get notified when a Tk topevel is
+# created.  Ideally, the __init__ 'method' should be overridden, but
+# it is a 'read-only special attribute'.  Luckily, title() is always
+# called from the Tkinter Toplevel constructor.
+
+def _addToplevelBusyInfo(window):
+    if window._w == '.':
+        busyWindow = '._Busy'
+    else:
+        busyWindow = window._w + '._Busy'
+
+    _toplevelBusyInfo[window] = {
+        'isBusy' : 0,
+        'windowFocus' : None,
+        'busyWindow' : busyWindow,
+        'excludeFromBusy' : 0,
+        'busyCursorName' : None,
+    }
+
+def __TkinterToplevelTitle(self, *args):
+    # If this is being called from the constructor, include this
+    # Toplevel in the list of toplevels and set the initial
+    # WM_DELETE_WINDOW protocol to destroy() so that we get to know
+    # about it.
+    if not _toplevelBusyInfo.has_key(self):
+        _addToplevelBusyInfo(self)
+        self._Pmw_WM_DELETE_name = self.register(self.destroy, None, 0)
+       self.protocol('WM_DELETE_WINDOW', self._Pmw_WM_DELETE_name)
+
+    return apply(Tkinter.Wm.title, (self,) + args)
+
+_haveBltBusy = None
+def _havebltbusy(window):
+    global _busy_hold, _busy_release, _haveBltBusy
+    if _haveBltBusy is None:
+        import PmwBlt
+        _haveBltBusy = PmwBlt.havebltbusy(window)
+        _busy_hold = PmwBlt.busy_hold
+        if os.name == 'nt':
+            # There is a bug in Blt 2.4i on NT where the busy window
+            # does not follow changes in the children of a window.
+            # Using forget works around the problem.
+            _busy_release = PmwBlt.busy_forget
+        else:
+            _busy_release = PmwBlt.busy_release
+    return _haveBltBusy
+
+class _BusyWrapper:
+    def __init__(self, command, updateFunction):
+       self._command = command
+       self._updateFunction = updateFunction
+
+    def callback(self, *args):
+       showbusycursor()
+       rtn = apply(self._command, args)
+
+       # Call update before hiding the busy windows to clear any
+       # events that may have occurred over the busy windows.
+       if callable(self._updateFunction):
+           self._updateFunction()
+
+       hidebusycursor()
+       return rtn
+
+#=============================================================================
+
+def drawarrow(canvas, color, direction, tag, baseOffset = 0.25, edgeOffset = 0.15):
+    canvas.delete(tag)
+
+    bw = (string.atoi(canvas['borderwidth']) + 
+            string.atoi(canvas['highlightthickness']))
+    width = string.atoi(canvas['width'])
+    height = string.atoi(canvas['height'])
+
+    if direction in ('up', 'down'):
+        majorDimension = height
+        minorDimension = width
+    else:
+        majorDimension = width
+        minorDimension = height
+
+    offset = round(baseOffset * majorDimension)
+    if direction in ('down', 'right'):
+        base = bw + offset
+        apex = bw + majorDimension - offset
+    else:
+        base = bw + majorDimension - offset
+        apex = bw + offset
+
+    if minorDimension > 3 and minorDimension % 2 == 0:
+        minorDimension = minorDimension - 1
+    half = int(minorDimension * (1 - 2 * edgeOffset)) / 2
+    low = round(bw + edgeOffset * minorDimension)
+    middle = low + half
+    high = low + 2 * half
+
+    if direction in ('up', 'down'):
+        coords = (low, base, high, base, middle, apex)
+    else:
+        coords = (base, low, base, high, apex, middle)
+    kw = {'fill' : color, 'outline' : color, 'tag' : tag}
+    apply(canvas.create_polygon, coords, kw)
+
+#=============================================================================
+
+# Modify the Tkinter destroy methods so that it notifies us when a Tk
+# toplevel or frame is destroyed.
+
+# A map from the 'hull' component of a megawidget to the megawidget. 
+# This is used to clean up a megawidget when its hull is destroyed.
+_hullToMegaWidget = {}
+
+def __TkinterToplevelDestroy(tkWidget):
+    if _hullToMegaWidget.has_key(tkWidget):
+        mega = _hullToMegaWidget[tkWidget]
+        try:
+           mega.destroy()
+        except:
+           _reporterror(mega.destroy, ())
+    else:
+        # Delete the busy info structure for this toplevel (if the
+        # window was created before Pmw.initialise() was called, it
+        # will not have any.
+        if _toplevelBusyInfo.has_key(tkWidget):
+            del _toplevelBusyInfo[tkWidget]
+        if hasattr(tkWidget, '_Pmw_WM_DELETE_name'):
+            tkWidget.tk.deletecommand(tkWidget._Pmw_WM_DELETE_name)
+            del tkWidget._Pmw_WM_DELETE_name
+        Tkinter.BaseWidget.destroy(tkWidget)
+
+def __TkinterWidgetDestroy(tkWidget):
+    if _hullToMegaWidget.has_key(tkWidget):
+        mega = _hullToMegaWidget[tkWidget]
+        try:
+           mega.destroy()
+        except:
+           _reporterror(mega.destroy, ())
+    else:
+        Tkinter.BaseWidget.destroy(tkWidget)
+
+#=============================================================================
+
+# Add code to Tkinter to improve the display of errors which occur in
+# callbacks.
+
+class __TkinterCallWrapper:
+    def __init__(self, func, subst, widget):
+       self.func = func
+       self.subst = subst
+       self.widget = widget
+
+    # Calling back from Tk into python.
+    def __call__(self, *args):
+       try:
+           if self.subst:
+               args = apply(self.subst, args)
+            if _traceTk:
+                if not _callToTkReturned:
+                    _traceTkFile.write('\n')
+                if hasattr(self.func, 'im_class'):
+                    name = self.func.im_class.__name__ + '.' + \
+                        self.func.__name__
+                else:
+                    name = self.func.__name__
+                if len(args) == 1 and hasattr(args[0], 'type'):
+                    # The argument to the callback is an event.
+                    eventName = _eventTypeToName[string.atoi(args[0].type)]
+                    if eventName in ('KeyPress', 'KeyRelease',):
+                        argStr = '(%s %s Event: %s)' % \
+                            (eventName, args[0].keysym, args[0].widget)
+                    else:
+                        argStr = '(%s Event, %s)' % (eventName, args[0].widget)
+                else:
+                    argStr = str(args)
+                _traceTkFile.write('CALLBACK> %d:%s%s%s\n' %
+                    (_recursionCounter, '  ' * _recursionCounter, name, argStr))
+                _traceTkFile.flush()
+           return apply(self.func, args)
+       except SystemExit, msg:
+           raise SystemExit, msg
+       except:
+           _reporterror(self.func, args)
+
+_eventTypeToName = {
+    2 : 'KeyPress',         15 : 'VisibilityNotify',   28 : 'PropertyNotify',
+    3 : 'KeyRelease',       16 : 'CreateNotify',       29 : 'SelectionClear',
+    4 : 'ButtonPress',      17 : 'DestroyNotify',      30 : 'SelectionRequest',
+    5 : 'ButtonRelease',    18 : 'UnmapNotify',        31 : 'SelectionNotify',
+    6 : 'MotionNotify',     19 : 'MapNotify',          32 : 'ColormapNotify',
+    7 : 'EnterNotify',      20 : 'MapRequest',         33 : 'ClientMessage',
+    8 : 'LeaveNotify',      21 : 'ReparentNotify',     34 : 'MappingNotify',
+    9 : 'FocusIn',          22 : 'ConfigureNotify',    35 : 'VirtualEvents',
+    10 : 'FocusOut',        23 : 'ConfigureRequest',   36 : 'ActivateNotify',
+    11 : 'KeymapNotify',    24 : 'GravityNotify',      37 : 'DeactivateNotify',
+    12 : 'Expose',          25 : 'ResizeRequest',      38 : 'MouseWheelEvent',
+    13 : 'GraphicsExpose',  26 : 'CirculateNotify',
+    14 : 'NoExpose',        27 : 'CirculateRequest',
+}
+
+def _reporterror(func, args):
+    # Fetch current exception values.
+    exc_type, exc_value, exc_traceback = sys.exc_info()
+
+    # Give basic information about the callback exception.
+    if type(exc_type) == types.ClassType:
+       # Handle python 1.5 class exceptions.
+       exc_type = exc_type.__name__
+    msg = exc_type + ' Exception in Tk callback\n'
+    msg = msg + '  Function: %s (type: %s)\n' % (repr(func), type(func))
+    msg = msg + '  Args: %s\n' % str(args)
+
+    if type(args) == types.TupleType and len(args) > 0 and \
+           hasattr(args[0], 'type'):
+        eventArg = 1
+    else:
+        eventArg = 0
+
+    # If the argument to the callback is an event, add the event type.
+    if eventArg:
+       eventNum = string.atoi(args[0].type)
+        if eventNum in _eventTypeToName.keys():
+            msg = msg + '  Event type: %s (type num: %d)\n' % \
+                    (_eventTypeToName[eventNum], eventNum)
+        else:
+            msg = msg + '  Unknown event type (type num: %d)\n' % eventNum
+
+    # Add the traceback.
+    msg = msg + 'Traceback (innermost last):\n'
+    for tr in traceback.extract_tb(exc_traceback):
+       msg = msg + '  File "%s", line %s, in %s\n' % (tr[0], tr[1], tr[2])
+       msg = msg + '    %s\n' % tr[3]
+    msg = msg + '%s: %s\n' % (exc_type, exc_value)
+
+    # If the argument to the callback is an event, add the event contents.
+    if eventArg:
+       msg = msg + '\n================================================\n'
+       msg = msg + '  Event contents:\n'
+       keys = args[0].__dict__.keys()
+       keys.sort()
+       for key in keys:
+           msg = msg + '    %s: %s\n' % (key, args[0].__dict__[key])
+
+    clearbusycursor()
+    try:
+       displayerror(msg)
+    except:
+        pass
+
+class _ErrorWindow:
+    def __init__(self):
+
+       self._errorQueue = []
+       self._errorCount = 0
+       self._open = 0
+        self._firstShowing = 1
+
+       # Create the toplevel window
+       self._top = Tkinter.Toplevel()
+       self._top.protocol('WM_DELETE_WINDOW', self._hide)
+       self._top.title('Error in background function')
+       self._top.iconname('Background error')
+
+       # Create the text widget and scrollbar in a frame
+       upperframe = Tkinter.Frame(self._top)
+
+       scrollbar = Tkinter.Scrollbar(upperframe, orient='vertical')
+       scrollbar.pack(side = 'right', fill = 'y')
+
+       self._text = Tkinter.Text(upperframe, yscrollcommand=scrollbar.set)
+       self._text.pack(fill = 'both', expand = 1)
+       scrollbar.configure(command=self._text.yview)
+
+       # Create the buttons and label in a frame
+       lowerframe = Tkinter.Frame(self._top)
+
+       ignore = Tkinter.Button(lowerframe,
+               text = 'Ignore remaining errors', command = self._hide)
+       ignore.pack(side='left')
+
+       self._nextError = Tkinter.Button(lowerframe,
+               text = 'Show next error', command = self._next)
+       self._nextError.pack(side='left')
+
+       self._label = Tkinter.Label(lowerframe, relief='ridge')
+       self._label.pack(side='left', fill='x', expand=1)
+
+       # Pack the lower frame first so that it does not disappear
+       # when the window is resized.
+       lowerframe.pack(side = 'bottom', fill = 'x')
+       upperframe.pack(side = 'bottom', fill = 'both', expand = 1)
+
+    def showerror(self, text):
+       if self._open:
+           self._errorQueue.append(text)
+       else:
+           self._display(text)
+           self._open = 1
+
+       # Display the error window in the same place it was before.
+       if self._top.state() == 'normal':
+           # If update_idletasks is not called here, the window may
+           # be placed partially off the screen.  Also, if it is not
+           # called and many errors are generated quickly in
+           # succession, the error window may not display errors
+           # until the last one is generated and the interpreter
+           # becomes idle.
+           # XXX: remove this, since it causes omppython to go into an
+           # infinite loop if an error occurs in an omp callback.
+           # self._top.update_idletasks()
+
+            pass
+       else:
+           if self._firstShowing:
+               geom = None
+           else:
+                geometry = self._top.geometry()
+                index = string.find(geometry, '+')
+                if index >= 0:
+                    geom = geometry[index:]
+                else:
+                    geom = None
+            setgeometryanddeiconify(self._top, geom)
+
+        if self._firstShowing:
+            self._firstShowing = 0
+        else:
+            self._top.tkraise()
+
+        self._top.focus()
+
+       self._updateButtons()
+
+       # Release any grab, so that buttons in the error window work.
+        releasegrabs()
+
+    def _hide(self):
+       self._errorCount = self._errorCount + len(self._errorQueue)
+       self._errorQueue = []
+       self._top.withdraw()
+       self._open = 0
+
+    def _next(self):
+       # Display the next error in the queue. 
+
+       text = self._errorQueue[0]
+       del self._errorQueue[0]
+
+       self._display(text)
+       self._updateButtons()
+
+    def _display(self, text):
+       self._errorCount = self._errorCount + 1
+       text = 'Error: %d\n%s' % (self._errorCount, text)
+       self._text.delete('1.0', 'end')
+       self._text.insert('end', text)
+
+    def _updateButtons(self):
+       numQueued = len(self._errorQueue)
+       if numQueued > 0:
+           self._label.configure(text='%d more errors' % numQueued)
+           self._nextError.configure(state='normal')
+       else:
+           self._label.configure(text='No more errors')
+           self._nextError.configure(state='disabled')
diff --git a/Pmw/Pmw_1_2/lib/PmwBlt.py b/Pmw/Pmw_1_2/lib/PmwBlt.py
new file mode 100644 (file)
index 0000000..38bbaf0
--- /dev/null
@@ -0,0 +1,643 @@
+# Python interface to some of the commands of the 2.4 version of the
+# BLT extension to tcl.
+
+import string
+import types
+import Tkinter
+
+# Supported commands:
+_busyCommand = '::blt::busy'
+_vectorCommand = '::blt::vector'
+_graphCommand = '::blt::graph'
+_testCommand = '::blt::*'
+_chartCommand = '::blt::stripchart'
+_tabsetCommand = '::blt::tabset'
+
+_haveBlt = None
+_haveBltBusy = None
+
+def _checkForBlt(window):
+    global _haveBlt
+    global _haveBltBusy
+
+    # Blt may be a package which has not yet been loaded. Try to load it.
+    try:
+       window.tk.call('package', 'require', 'BLT')
+    except Tkinter.TclError:
+       # Another way to try to dynamically load blt:
+       try:
+           window.tk.call('load', '', 'Blt')
+       except Tkinter.TclError:
+           pass
+
+    _haveBlt= (window.tk.call('info', 'commands', _testCommand) != '')
+    _haveBltBusy = (window.tk.call('info', 'commands', _busyCommand) != '')
+
+def haveblt(window):
+    if _haveBlt is None:
+       _checkForBlt(window)
+    return _haveBlt
+
+def havebltbusy(window):
+    if _haveBlt is None:
+       _checkForBlt(window)
+    return _haveBltBusy
+
+def _loadBlt(window):
+    if _haveBlt is None:
+       if window is None:
+           window = Tkinter._default_root
+           if window is None:
+               window = Tkinter.Tk()
+       _checkForBlt(window)
+
+def busy_hold(window, cursor = None):
+    _loadBlt(window)
+    if cursor is None:
+        window.tk.call(_busyCommand, 'hold', window._w)
+    else:
+        window.tk.call(_busyCommand, 'hold', window._w, '-cursor', cursor)
+
+def busy_release(window):
+    _loadBlt(window)
+    window.tk.call(_busyCommand, 'release', window._w)
+
+def busy_forget(window):
+    _loadBlt(window)
+    window.tk.call(_busyCommand, 'forget', window._w)
+
+#=============================================================================
+# Interface to the blt vector command which makes it look like the
+# builtin python list type.
+# The -variable, -command, -watchunset creation options are not supported.
+# The dup, merge, notify, offset, populate, seq and variable methods
+# and the +, -, * and / operations are not supported.
+
+# Blt vector functions:
+def vector_expr(expression):
+    tk = Tkinter._default_root.tk
+    strList = tk.splitlist(tk.call(_vectorCommand, 'expr', expression))
+    return tuple(map(string.atof, strList))
+
+def vector_names(pattern = None):
+    tk = Tkinter._default_root.tk
+    return tk.splitlist(tk.call(_vectorCommand, 'names', pattern))
+
+class Vector:
+    _varnum = 0
+    def __init__(self, size=None, master=None):
+        # <size> can be either an integer size, or a string "first:last".
+       _loadBlt(master)
+       if master:
+           self._master = master
+       else:
+           self._master = Tkinter._default_root
+       self.tk = self._master.tk
+       self._name = 'PY_VEC' + str(Vector._varnum)
+       Vector._varnum = Vector._varnum + 1
+       if size is None:
+           self.tk.call(_vectorCommand, 'create', self._name)
+       else:
+         self.tk.call(_vectorCommand, 'create', '%s(%s)' % (self._name, size))
+    def __del__(self):
+       self.tk.call(_vectorCommand, 'destroy', self._name)
+    def __str__(self):
+       return self._name
+
+    def __repr__(self):
+       return '[' + string.join(map(str, self), ', ') + ']'
+    def __cmp__(self, list):
+       return cmp(self[:], list)
+
+    def __len__(self): 
+       return self.tk.getint(self.tk.call(self._name, 'length'))
+    def __getitem__(self, key): 
+       oldkey = key
+       if key < 0:
+           key = key + len(self)
+       try:
+           return self.tk.getdouble(self.tk.globalgetvar(self._name, str(key)))
+        except Tkinter.TclError:
+           raise IndexError, oldkey
+    def __setitem__(self, key, value): 
+       if key < 0:
+           key = key + len(self)
+       return self.tk.globalsetvar(self._name, str(key), float(value))
+
+    def __delitem__(self, key):
+       if key < 0:
+           key = key + len(self)
+       return self.tk.globalunsetvar(self._name, str(key))
+
+    def __getslice__(self, start, end):
+       length = len(self)
+       if start < 0:
+           start = 0
+       if end > length:
+           end = length
+       if start >= end:
+           return []
+       end = end - 1  # Blt vector slices include end point.
+       text = self.tk.globalgetvar(self._name, str(start) + ':' + str(end))
+       return map(self.tk.getdouble, self.tk.splitlist(text))
+
+    def __setslice__(self, start, end, list):
+       if start > end:
+           end = start
+       self.set(self[:start] + list + self[end:])
+
+    def __delslice__(self, start, end):
+       if start < end:
+           self.set(self[:start] + self[end:])
+
+    def __add__(self, list):
+       return self[:] + list
+    def __radd__(self, list):
+       return list + self[:]
+    def __mul__(self, n):
+       return self[:] * n
+    __rmul__ = __mul__
+
+    # Python builtin list methods:
+    def append(self, *args):
+       self.tk.call(self._name, 'append', args)
+    def count(self, obj):
+       return self[:].count(obj)
+    def index(self, value):
+       return self[:].index(value)
+    def insert(self, index, value):
+       self[index:index] = [value]
+    def remove(self, value):
+       del self[self.index(value)]
+    def reverse(self):
+       s = self[:]
+       s.reverse()
+       self.set(s)
+    def sort(self, *args):
+       s = self[:]
+       s.sort()
+       self.set(s)
+
+    # Blt vector instance methods:
+    # append - same as list method above
+    def clear(self):
+       self.tk.call(self._name, 'clear')
+    def delete(self, *args):
+       self.tk.call((self._name, 'delete') + args)
+    def expr(self, expression):
+       self.tk.call(self._name, 'expr', expression)
+    def length(self, newSize=None): 
+       return self.tk.getint(self.tk.call(self._name, 'length', newSize))
+    def range(self, first, last=None):
+       # Note that, unlike self[first:last], this includes the last
+       # item in the returned range.
+       text = self.tk.call(self._name, 'range', first, last)
+       return map(self.tk.getdouble, self.tk.splitlist(text))
+    def search(self, start, end=None):
+       return self._master._getints(self.tk.call(
+               self._name, 'search', start, end))
+    def set(self, list):
+       if type(list) != types.TupleType:
+           list = tuple(list)
+       self.tk.call(self._name, 'set', list)
+
+    # The blt vector sort method has different semantics to the python
+    # list sort method.  Call these blt_sort:
+    def blt_sort(self, *args):
+       self.tk.call((self._name, 'sort') + args)
+    def blt_sort_reverse(self, *args):
+       self.tk.call((self._name, 'sort', '-reverse') + args)
+
+    # Special blt vector indexes:
+    def min(self):
+       return self.tk.getdouble(self.tk.globalgetvar(self._name, 'min'))
+    def max(self):
+       return self.tk.getdouble(self.tk.globalgetvar(self._name, 'max'))
+
+    # Method borrowed from Tkinter.Var class:
+    def get(self):
+       return self[:]
+
+#=============================================================================
+
+# This is a general purpose configure routine which can handle the
+# configuration of widgets, items within widgets, etc.  Supports the
+# forms configure() and configure('font') for querying and
+# configure(font = 'fixed', text = 'hello') for setting.
+
+def _doConfigure(widget, subcommand, option, kw):
+
+    if not option and not kw:
+        # Return a description of all options.
+        ret = {}
+        options = widget.tk.splitlist(widget.tk.call(subcommand))
+        for optionString in options:
+            optionInfo = widget.tk.splitlist(optionString)
+            option = optionInfo[0][1:]
+            ret[option] = (option,) + optionInfo[1:]
+        return ret
+
+    if option:
+        # Return a description of the option given by <option>.
+        if kw:
+            # Having keywords implies setting configuration options.
+            # Can't set and get in one command!
+            raise ValueError, 'cannot have option argument with keywords'
+        option = '-' + option
+        optionInfo = widget.tk.splitlist(widget.tk.call(subcommand + (option,)))
+        return (optionInfo[0][1:],) + optionInfo[1:]
+
+    # Otherwise, set the given configuration options.
+    widget.tk.call(subcommand + widget._options(kw))
+
+#=============================================================================
+
+class Graph(Tkinter.Widget):
+    # Wrapper for the blt graph widget, version 2.4.
+
+    def __init__(self, master=None, cnf={}, **kw):
+       _loadBlt(master)
+       Tkinter.Widget.__init__(self, master, _graphCommand, cnf, kw)
+
+    def bar_create(self, name, **kw):
+       self.tk.call((self._w, 'bar', 'create', name) + self._options(kw))
+
+    def line_create(self, name, **kw):
+       self.tk.call((self._w, 'line', 'create', name) + self._options(kw))
+
+    def extents(self, item):
+       return self.tk.getint(self.tk.call(self._w, 'extents', item))
+
+    def invtransform(self, winX, winY):
+       return self._getdoubles(
+               self.tk.call(self._w, 'invtransform', winX, winY))
+
+    def inside(self, x, y):
+       return self.tk.getint(self.tk.call(self._w, 'inside', x, y))
+
+    def snap(self, photoName):
+       self.tk.call(self._w, 'snap', photoName)
+
+    def transform(self, x, y):
+       return self._getdoubles(self.tk.call(self._w, 'transform', x, y))
+
+    def axis_cget(self, axisName, key):
+       return self.tk.call(self._w, 'axis', 'cget', axisName, '-' + key)
+    def axis_configure(self, axes, option=None, **kw):
+        # <axes> may be a list of axisNames.
+       if type(axes) == types.StringType:
+            axes = [axes]
+       subcommand = (self._w, 'axis', 'configure') + tuple(axes)
+       return _doConfigure(self, subcommand, option, kw)
+    def axis_create(self, axisName, **kw):
+       self.tk.call((self._w, 'axis', 'create', axisName) + self._options(kw))
+    def axis_delete(self, *args):
+       self.tk.call((self._w, 'axis', 'delete') + args)
+    def axis_invtransform(self, axisName, value):
+       return self.tk.getdouble(self.tk.call(
+               self._w, 'axis', 'invtransform', axisName, value))
+    def axis_limits(self, axisName):
+       return self._getdoubles(self.tk.call(
+               self._w, 'axis', 'limits', axisName))
+    def axis_names(self, *args):
+        return self.tk.splitlist(
+                self.tk.call((self._w, 'axis', 'names') + args))
+    def axis_transform(self, axisName, value):
+       return self.tk.getint(self.tk.call(
+               self._w, 'axis', 'transform', axisName, value))
+
+    def xaxis_cget(self, key):
+       return self.tk.call(self._w, 'xaxis', 'cget', '-' + key)
+    def xaxis_configure(self, option=None, **kw):
+       subcommand = (self._w, 'xaxis', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def xaxis_invtransform(self, value):
+       return self.tk.getdouble(self.tk.call(
+               self._w, 'xaxis', 'invtransform', value))
+    def xaxis_limits(self):
+       return self._getdoubles(self.tk.call(self._w, 'xaxis', 'limits'))
+    def xaxis_transform(self, value):
+       return self.tk.getint(self.tk.call(
+               self._w, 'xaxis', 'transform', value))
+    def xaxis_use(self, axisName = None):
+       return self.tk.call(self._w, 'xaxis', 'use', axisName)
+
+    def x2axis_cget(self, key):
+       return self.tk.call(self._w, 'x2axis', 'cget', '-' + key)
+    def x2axis_configure(self, option=None, **kw):
+       subcommand = (self._w, 'x2axis', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def x2axis_invtransform(self, value):
+       return self.tk.getdouble(self.tk.call(
+               self._w, 'x2axis', 'invtransform', value))
+    def x2axis_limits(self):
+       return self._getdoubles(self.tk.call(self._w, 'x2axis', 'limits'))
+    def x2axis_transform(self, value):
+       return self.tk.getint(self.tk.call(
+               self._w, 'x2axis', 'transform', value))
+    def x2axis_use(self, axisName = None):
+       return self.tk.call(self._w, 'x2axis', 'use', axisName)
+
+    def yaxis_cget(self, key):
+       return self.tk.call(self._w, 'yaxis', 'cget', '-' + key)
+    def yaxis_configure(self, option=None, **kw):
+       subcommand = (self._w, 'yaxis', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def yaxis_invtransform(self, value):
+       return self.tk.getdouble(self.tk.call(
+               self._w, 'yaxis', 'invtransform', value))
+    def yaxis_limits(self):
+       return self._getdoubles(self.tk.call(self._w, 'yaxis', 'limits'))
+    def yaxis_transform(self, value):
+       return self.tk.getint(self.tk.call(
+               self._w, 'yaxis', 'transform', value))
+    def yaxis_use(self, axisName = None):
+       return self.tk.call(self._w, 'yaxis', 'use', axisName)
+
+    def y2axis_cget(self, key):
+       return self.tk.call(self._w, 'y2axis', 'cget', '-' + key)
+    def y2axis_configure(self, option=None, **kw):
+       subcommand = (self._w, 'y2axis', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def y2axis_invtransform(self, value):
+       return self.tk.getdouble(self.tk.call(
+               self._w, 'y2axis', 'invtransform', value))
+    def y2axis_limits(self):
+       return self._getdoubles(self.tk.call(self._w, 'y2axis', 'limits'))
+    def y2axis_transform(self, value):
+       return self.tk.getint(self.tk.call(
+               self._w, 'y2axis', 'transform', value))
+    def y2axis_use(self, axisName = None):
+       return self.tk.call(self._w, 'y2axis', 'use', axisName)
+
+    def crosshairs_cget(self, key):
+       return self.tk.call(self._w, 'crosshairs', 'cget', '-' + key)
+    def crosshairs_configure(self, option=None, **kw):
+       subcommand = (self._w, 'crosshairs', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def crosshairs_off(self):
+       self.tk.call(self._w, 'crosshairs', 'off')
+    def crosshairs_on(self):
+       self.tk.call(self._w, 'crosshairs', 'on')
+    def crosshairs_toggle(self):
+       self.tk.call(self._w, 'crosshairs', 'toggle')
+
+    def element_activate(self, name, *args):
+       self.tk.call((self._w, 'element', 'activate', name) + args)
+    def element_bind(self, tagName, sequence=None, func=None, add=None):
+        return self._bind((self._w, 'element', 'bind', tagName),
+                sequence, func, add)
+    def element_unbind(self, tagName, sequence, funcid=None):
+        self.tk.call(self._w, 'element', 'bind', tagName, sequence, '')
+        if funcid:
+            self.deletecommand(funcid)
+
+    def element_cget(self, name, key):
+       return self.tk.call(self._w, 'element', 'cget', name, '-' + key)
+
+    def element_closest(self, x, y, *args, **kw):
+        var = 'python_private_1'
+       success = self.tk.getint(self.tk.call(
+                (self._w, 'element', 'closest', x, y, var) +
+                        self._options(kw) + args))
+       if success:
+           rtn = {}
+           rtn['dist'] = self.tk.getdouble(self.tk.globalgetvar(var, 'dist'))
+           rtn['x'] = self.tk.getdouble(self.tk.globalgetvar(var, 'x'))
+           rtn['y'] = self.tk.getdouble(self.tk.globalgetvar(var, 'y'))
+           rtn['index'] = self.tk.getint(self.tk.globalgetvar(var, 'index'))
+           rtn['name'] = self.tk.globalgetvar(var, 'name')
+           return rtn
+       else:
+           return None
+
+    def element_configure(self, names, option=None, **kw):
+        # <names> may be a list of elemNames.
+       if type(names) == types.StringType:
+            names = [names]
+       subcommand = (self._w, 'element', 'configure') + tuple(names)
+       return _doConfigure(self, subcommand, option, kw)
+
+    def element_deactivate(self, *args):
+       self.tk.call((self._w, 'element', 'deactivate') + args)
+
+    def element_delete(self, *args):
+       self.tk.call((self._w, 'element', 'delete') + args)
+    def element_exists(self, name):
+       return self.tk.getboolean(
+               self.tk.call(self._w, 'element', 'exists', name))
+
+    def element_names(self, *args):
+        return self.tk.splitlist(
+                self.tk.call((self._w, 'element', 'names') + args))
+    def element_show(self, nameList=None):
+       if nameList is not None:
+           nameList = tuple(nameList)
+       return self.tk.splitlist(
+               self.tk.call(self._w, 'element', 'show', nameList))
+    def element_type(self, name):
+       return self.tk.call(self._w, 'element', 'type', name)
+
+    def grid_cget(self, key):
+       return self.tk.call(self._w, 'grid', 'cget', '-' + key)
+    def grid_configure(self, option=None, **kw):
+       subcommand = (self._w, 'grid', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+
+    def grid_off(self):
+       self.tk.call(self._w, 'grid', 'off')
+    def grid_on(self):
+       self.tk.call(self._w, 'grid', 'on')
+    def grid_toggle(self):
+       self.tk.call(self._w, 'grid', 'toggle')
+
+    def legend_activate(self, *args):
+       self.tk.call((self._w, 'legend', 'activate') + args)
+    def legend_bind(self, tagName, sequence=None, func=None, add=None):
+        return self._bind((self._w, 'legend', 'bind', tagName),
+                sequence, func, add)
+    def legend_unbind(self, tagName, sequence, funcid=None):
+        self.tk.call(self._w, 'legend', 'bind', tagName, sequence, '')
+        if funcid:
+            self.deletecommand(funcid)
+
+    def legend_cget(self, key):
+       return self.tk.call(self._w, 'legend', 'cget', '-' + key)
+    def legend_configure(self, option=None, **kw):
+       subcommand = (self._w, 'legend', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def legend_deactivate(self, *args):
+       self.tk.call((self._w, 'legend', 'deactivate') + args)
+    def legend_get(self, pos):
+       return self.tk.call(self._w, 'legend', 'get', pos)
+
+    def pen_cget(self, name, key):
+       return self.tk.call(self._w, 'pen', 'cget', name, '-' + key)
+    def pen_configure(self, names, option=None, **kw):
+        # <names> may be a list of penNames.
+       if type(names) == types.StringType:
+            names = [names]
+       subcommand = (self._w, 'pen', 'configure') + tuple(names)
+       return _doConfigure(self, subcommand, option, kw)
+    def pen_create(self, name, **kw):
+       self.tk.call((self._w, 'pen', 'create', name) + self._options(kw))
+    def pen_delete(self, *args):
+       self.tk.call((self._w, 'pen', 'delete') + args)
+    def pen_names(self, *args):
+        return self.tk.splitlist(self.tk.call((self._w, 'pen', 'names') + args))
+
+    def postscript_cget(self, key):
+       return self.tk.call(self._w, 'postscript', 'cget', '-' + key)
+    def postscript_configure(self, option=None, **kw):
+       subcommand = (self._w, 'postscript', 'configure')
+       return _doConfigure(self, subcommand, option, kw)
+    def postscript_output(self, fileName=None, **kw):
+       prefix = (self._w, 'postscript', 'output')
+       if fileName is None:
+           return self.tk.call(prefix + self._options(kw))
+       else:
+           self.tk.call(prefix + (fileName,) + self._options(kw))
+
+    def marker_after(self, first, second=None):
+       self.tk.call(self._w, 'marker', 'after', first, second)
+    def marker_before(self, first, second=None):
+       self.tk.call(self._w, 'marker', 'before', first, second)
+    def marker_bind(self, tagName, sequence=None, func=None, add=None):
+        return self._bind((self._w, 'marker', 'bind', tagName),
+                sequence, func, add)
+    def marker_unbind(self, tagName, sequence, funcid=None):
+        self.tk.call(self._w, 'marker', 'bind', tagName, sequence, '')
+        if funcid:
+            self.deletecommand(funcid)
+
+    def marker_cget(self, name, key):
+       return self.tk.call(self._w, 'marker', 'cget', name, '-' + key)
+    def marker_configure(self, names, option=None, **kw):
+        # <names> may be a list of markerIds.
+       if type(names) == types.StringType:
+            names = [names]
+       subcommand = (self._w, 'marker', 'configure') + tuple(names)
+       return _doConfigure(self, subcommand, option, kw)
+    def marker_create(self, type, **kw):
+       return self.tk.call(
+                (self._w, 'marker', 'create', type) + self._options(kw))
+
+    def marker_delete(self, *args):
+       self.tk.call((self._w, 'marker', 'delete') + args)
+    def marker_exists(self, name):
+       return self.tk.getboolean(
+               self.tk.call(self._w, 'marker', 'exists', name))
+    def marker_names(self, *args):
+        return self.tk.splitlist(
+                self.tk.call((self._w, 'marker', 'names') + args))
+    def marker_type(self, name):
+       type = self.tk.call(self._w, 'marker', 'type', name)
+       if type == '':
+           type = None
+       return type
+
+#=============================================================================
+class Stripchart(Graph):
+    # Wrapper for the blt stripchart widget, version 2.4.
+
+    def __init__(self, master=None, cnf={}, **kw):
+       _loadBlt(master)
+       Tkinter.Widget.__init__(self, master, _chartCommand, cnf, kw)
+
+#=============================================================================
+class Tabset(Tkinter.Widget): 
+
+    # Wrapper for the blt TabSet widget, version 2.4.
+
+    def __init__(self, master=None, cnf={}, **kw):
+       _loadBlt(master)
+       Tkinter.Widget.__init__(self, master, _tabsetCommand, cnf, kw)
+
+    def activate(self, tabIndex):
+        self.tk.call(self._w, 'activate', tabIndex)
+
+    # This is the 'bind' sub-command:
+    def tag_bind(self, tagName, sequence=None, func=None, add=None):
+        return self._bind((self._w, 'bind', tagName), sequence, func, add)
+
+    def tag_unbind(self, tagName, sequence, funcid=None):
+        self.tk.call(self._w, 'bind', tagName, sequence, '')
+        if funcid:
+            self.deletecommand(funcid)
+
+    def delete(self, first, last = None):
+       self.tk.call(self._w, 'delete', first, last)
+
+    # This is the 'focus' sub-command:
+    def tab_focus(self, tabIndex):
+       self.tk.call(self._w, 'focus', tabIndex)
+       
+    def get(self, tabIndex):
+       return self.tk.call(self._w, 'get', tabIndex)
+
+    def index(self, tabIndex):
+       index = self.tk.call(self._w, 'index', tabIndex)
+        if index == '':
+            return None
+        else:
+            return self.tk.getint(self.tk.call(self._w, 'index', tabIndex))
+
+    def insert(self, position, name1, *names, **kw):
+       self.tk.call(
+            (self._w, 'insert', position, name1) + names + self._options(kw))
+
+    def invoke(self, tabIndex):
+       return self.tk.call(self._w, 'invoke', tabIndex)
+
+    def move(self, tabIndex1, beforeOrAfter, tabIndex2):
+       self.tk.call(self._w, 'move', tabIndex1, beforeOrAfter, tabIndex2)
+       
+    def nearest(self, x, y):
+       return self.tk.call(self._w, 'nearest', x, y)
+
+    def scan_mark(self, x, y):
+        self.tk.call(self._w, 'scan', 'mark', x, y)
+
+    def scan_dragto(self, x, y):
+        self.tk.call(self._w, 'scan', 'dragto', x, y)
+
+    def see(self, index):
+        self.tk.call(self._w, 'see', index)
+       
+    def see(self, tabIndex):
+       self.tk.call(self._w,'see',tabIndex)
+       
+    def size(self):
+       return self.tk.getint(self.tk.call(self._w, 'size'))
+
+    def tab_cget(self, tabIndex, option):
+        if option[:1] != '-':
+            option = '-' + option
+        if option[-1:] == '_':
+            option = option[:-1]
+        return self.tk.call(self._w, 'tab', 'cget', tabIndex, option)
+
+    def tab_configure(self, tabIndexes, option=None, **kw):
+        # <tabIndexes> may be a list of tabs.
+       if type(tabIndexes) in (types.StringType, types.IntType):
+            tabIndexes = [tabIndexes]
+       subcommand = (self._w, 'tab', 'configure') + tuple(tabIndexes)
+       return _doConfigure(self, subcommand, option, kw)
+
+    def tab_names(self, *args):
+        return self.tk.splitlist(self.tk.call((self._w, 'tab', 'names') + args))
+
+    def tab_tearoff(self, tabIndex, newName = None):
+        if newName is None:
+            name = self.tk.call(self._w, 'tab', 'tearoff', tabIndex)
+            return self.nametowidget(name)
+        else:
+            self.tk.call(self._w, 'tab', 'tearoff', tabIndex, newName)
+
+    def view(self):
+        s = self.tk.call(self._w, 'view')
+        return tuple(map(self.tk.getint, self.tk.splitlist(s)))
+    def view_moveto(self, fraction):
+        self.tk.call(self._w, 'view', 'moveto', fraction)
+    def view_scroll(self, number, what):
+        self.tk.call(self._w, 'view', 'scroll', number, what)
diff --git a/Pmw/Pmw_1_2/lib/PmwButtonBox.py b/Pmw/Pmw_1_2/lib/PmwButtonBox.py
new file mode 100644 (file)
index 0000000..6da5e0a
--- /dev/null
@@ -0,0 +1,224 @@
+# Based on iwidgets2.2.0/buttonbox.itk code.
+
+import types
+import Tkinter
+import Pmw
+
+class ButtonBox(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('labelmargin',       0,              INITOPT),
+           ('labelpos',          None,           INITOPT),
+           ('orient',            'horizontal',   INITOPT),
+           ('padx',              3,              INITOPT),
+           ('pady',              3,              INITOPT),
+       )
+       self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',))
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       if self['labelpos'] is None:
+           self._buttonBoxFrame = self._hull
+           columnOrRow = 0
+       else:
+           self._buttonBoxFrame = self.createcomponent('frame',
+                   (), None,
+                   Tkinter.Frame, (interior,))
+           self._buttonBoxFrame.grid(column=2, row=2, sticky='nsew')
+           columnOrRow = 2
+
+           self.createlabel(interior)
+
+       orient = self['orient']
+       if orient == 'horizontal':
+           interior.grid_columnconfigure(columnOrRow, weight = 1)
+       elif orient == 'vertical':
+           interior.grid_rowconfigure(columnOrRow, weight = 1)
+       else:
+           raise ValueError, 'bad orient option ' + repr(orient) + \
+               ': must be either \'horizontal\' or \'vertical\''
+
+       # Initialise instance variables.
+
+       # List of tuples describing the buttons:
+       #   - name
+       #   - button widget
+       self._buttonList = []
+
+       # The index of the default button.
+       self._defaultButton = None
+
+       self._timerId = None
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self._timerId:
+           self.after_cancel(self._timerId)
+           self._timerId = None
+       Pmw.MegaWidget.destroy(self)
+
+    def numbuttons(self):
+        return len(self._buttonList)
+
+    def index(self, index, forInsert = 0):
+       listLength = len(self._buttonList)
+       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, 'ButtonBox has no buttons'
+       elif index is Pmw.DEFAULT:
+           if self._defaultButton is not None:
+               return self._defaultButton
+           raise ValueError, 'ButtonBox has no default'
+       else:
+            names = map(lambda t: t[0], self._buttonList)
+            if index in names:
+                return names.index(index)
+           validValues = 'a name, a number, Pmw.END or Pmw.DEFAULT'
+           raise ValueError, \
+               'bad index "%s": must be %s' % (index, validValues)
+
+    def insert(self, componentName, beforeComponent = 0, **kw):
+       if componentName in self.components():
+           raise ValueError, 'button "%s" already exists' % componentName
+       if not kw.has_key('text'):
+           kw['text'] = componentName
+        kw['default'] = 'normal'
+       button = apply(self.createcomponent, (componentName,
+               (), 'Button',
+               Tkinter.Button, (self._buttonBoxFrame,)), kw)
+
+       index = self.index(beforeComponent, 1)
+       horizontal = self['orient'] == 'horizontal'
+       numButtons = len(self._buttonList)
+
+       # Shift buttons up one position.
+       for i in range(numButtons - 1, index - 1, -1):
+           widget = self._buttonList[i][1]
+           pos = i * 2 + 3
+           if horizontal:
+               widget.grid(column = pos, row = 0)
+           else:
+               widget.grid(column = 0, row = pos)
+
+       # Display the new button.
+       if horizontal:
+           button.grid(column = index * 2 + 1, row = 0, sticky = 'ew',
+                   padx = self['padx'], pady = self['pady'])
+           self._buttonBoxFrame.grid_columnconfigure(
+                   numButtons * 2 + 2, weight = 1)
+       else:
+           button.grid(column = 0, row = index * 2 + 1, sticky = 'ew',
+                   padx = self['padx'], pady = self['pady'])
+           self._buttonBoxFrame.grid_rowconfigure(
+                   numButtons * 2 + 2, weight = 1)
+       self._buttonList.insert(index, (componentName, button))
+
+       return button
+
+    def add(self, componentName, **kw):
+        return apply(self.insert, (componentName, len(self._buttonList)), kw)
+
+    def delete(self, index):
+        index = self.index(index)
+       (name, widget) = self._buttonList[index]
+       widget.grid_forget()
+       self.destroycomponent(name)
+
+       numButtons = len(self._buttonList)
+
+       # Shift buttons down one position.
+       horizontal = self['orient'] == 'horizontal'
+       for i in range(index + 1, numButtons):
+           widget = self._buttonList[i][1]
+           pos = i * 2 - 1
+           if horizontal:
+               widget.grid(column = pos, row = 0)
+           else:
+               widget.grid(column = 0, row = pos)
+
+       if horizontal:
+           self._buttonBoxFrame.grid_columnconfigure(numButtons * 2 - 1,
+                   minsize = 0)
+           self._buttonBoxFrame.grid_columnconfigure(numButtons * 2, weight = 0)
+       else:
+           self._buttonBoxFrame.grid_rowconfigure(numButtons * 2, weight = 0)
+       del self._buttonList[index]
+
+    def setdefault(self, index):
+       # Turn off the default ring around the current default button.
+       if self._defaultButton is not None:
+           button = self._buttonList[self._defaultButton][1]
+           button.configure(default = 'normal')
+           self._defaultButton = None
+
+       # Turn on the default ring around the new default button.
+       if index is not None:
+           index = self.index(index)
+           self._defaultButton = index
+           button = self._buttonList[index][1]
+           button.configure(default = 'active')
+
+    def invoke(self, index = Pmw.DEFAULT, noFlash = 0):
+       # Invoke the callback associated with the *index* button.  If
+       # *noFlash* is not set, flash the button to indicate to the
+       # user that something happened.
+
+       button = self._buttonList[self.index(index)][1]
+       if not noFlash:
+           state = button.cget('state')
+           relief = button.cget('relief')
+           button.configure(state = 'active', relief = 'sunken')
+           self.update_idletasks()
+           self.after(100)
+           button.configure(state = state, relief = relief)
+       return button.invoke()
+
+    def button(self, buttonIndex):
+       return self._buttonList[self.index(buttonIndex)][1]
+
+    def alignbuttons(self, when = 'later'):
+       if when == 'later':
+           if not self._timerId:
+               self._timerId = self.after_idle(self.alignbuttons, 'now')
+           return
+       self.update_idletasks()
+       self._timerId = None
+
+        # Determine the width of the maximum length button.
+        max = 0
+        horizontal = (self['orient'] == 'horizontal')
+        for index in range(len(self._buttonList)):
+            gridIndex = index * 2 + 1
+            if horizontal:
+                width = self._buttonBoxFrame.grid_bbox(gridIndex, 0)[2]
+            else:
+                width = self._buttonBoxFrame.grid_bbox(0, gridIndex)[2]
+            if width > max:
+                max = width
+
+        # Set the width of all the buttons to be the same.
+       if horizontal:
+           for index in range(len(self._buttonList)):
+               self._buttonBoxFrame.grid_columnconfigure(index * 2 + 1,
+                       minsize = max)
+       else:
+           self._buttonBoxFrame.grid_columnconfigure(0, minsize = max)
diff --git a/Pmw/Pmw_1_2/lib/PmwColor.py b/Pmw/Pmw_1_2/lib/PmwColor.py
new file mode 100644 (file)
index 0000000..fa4aac9
--- /dev/null
@@ -0,0 +1,361 @@
+# Functions for converting colors and modifying the color scheme of
+# an application.
+
+import math
+import string
+import sys
+import Tkinter
+
+_PI = math.pi
+_TWO_PI = _PI * 2
+_THIRD_PI = _PI / 3
+_SIXTH_PI = _PI / 6
+_MAX_RGB = float(256 * 256 - 1) # max size of rgb values returned from Tk
+
+def setscheme(root, background=None, **kw):
+    root = root._root()
+    palette = apply(_calcPalette, (root, background,), kw)
+    for option, value in palette.items():
+       root.option_add('*' + option, value, 'widgetDefault')
+
+def getdefaultpalette(root):
+    # Return the default values of all options, using the defaults
+    # from a few widgets.
+
+    ckbtn = Tkinter.Checkbutton(root)
+    entry = Tkinter.Entry(root)
+    scbar = Tkinter.Scrollbar(root)
+
+    orig = {}
+    orig['activeBackground'] = str(ckbtn.configure('activebackground')[4])
+    orig['activeForeground'] = str(ckbtn.configure('activeforeground')[4])
+    orig['background'] = str(ckbtn.configure('background')[4])
+    orig['disabledForeground'] = str(ckbtn.configure('disabledforeground')[4])
+    orig['foreground'] = str(ckbtn.configure('foreground')[4])
+    orig['highlightBackground'] = str(ckbtn.configure('highlightbackground')[4])
+    orig['highlightColor'] = str(ckbtn.configure('highlightcolor')[4])
+    orig['insertBackground'] = str(entry.configure('insertbackground')[4])
+    orig['selectColor'] = str(ckbtn.configure('selectcolor')[4])
+    orig['selectBackground'] = str(entry.configure('selectbackground')[4])
+    orig['selectForeground'] = str(entry.configure('selectforeground')[4])
+    orig['troughColor'] = str(scbar.configure('troughcolor')[4])
+
+    ckbtn.destroy()
+    entry.destroy()
+    scbar.destroy()
+
+    return orig
+
+#======================================================================
+
+# Functions dealing with brightness, hue, saturation and intensity of colors.
+
+def changebrightness(root, colorName, brightness):
+    # Convert the color name into its hue and back into a color of the
+    # required brightness.
+
+    rgb = name2rgb(root, colorName)
+    hue, saturation, intensity = rgb2hsi(rgb)
+    if saturation == 0.0:
+        hue = None
+    return hue2name(hue, brightness)
+
+def hue2name(hue, brightness = None):
+    # Convert the requested hue and brightness into a color name.  If
+    # hue is None, return a grey of the requested brightness.
+
+    if hue is None:
+       rgb = hsi2rgb(0.0, 0.0, brightness)
+    else:
+       while hue < 0:
+           hue = hue + _TWO_PI
+       while hue >= _TWO_PI:
+           hue = hue - _TWO_PI
+
+       rgb = hsi2rgb(hue, 1.0, 1.0)
+       if brightness is not None:
+           b = rgb2brightness(rgb)
+           i = 1.0 - (1.0 - brightness) * b
+           s = bhi2saturation(brightness, hue, i)
+           rgb = hsi2rgb(hue, s, i)
+
+    return rgb2name(rgb)
+
+def bhi2saturation(brightness, hue, intensity):
+    while hue < 0:
+        hue = hue + _TWO_PI
+    while hue >= _TWO_PI:
+        hue = hue - _TWO_PI
+    hue = hue / _THIRD_PI
+    f = hue - math.floor(hue)
+
+    pp = intensity
+    pq = intensity * f
+    pt = intensity - intensity * f
+    pv = 0
+
+    hue = int(hue)
+    if   hue == 0: rgb = (pv, pt, pp)
+    elif hue == 1: rgb = (pq, pv, pp)
+    elif hue == 2: rgb = (pp, pv, pt)
+    elif hue == 3: rgb = (pp, pq, pv)
+    elif hue == 4: rgb = (pt, pp, pv)
+    elif hue == 5: rgb = (pv, pp, pq)
+
+    return (intensity - brightness) / rgb2brightness(rgb)
+
+def hsi2rgb(hue, saturation, intensity):
+    i = intensity
+    if saturation == 0:
+       rgb = [i, i, i]
+    else:
+       while hue < 0:
+           hue = hue + _TWO_PI
+       while hue >= _TWO_PI:
+           hue = hue - _TWO_PI
+       hue = hue / _THIRD_PI
+       f = hue - math.floor(hue)
+       p = i * (1.0 - saturation)
+       q = i * (1.0 - saturation * f)
+       t = i * (1.0 - saturation * (1.0 - f))
+
+       hue = int(hue)
+       if   hue == 0: rgb = [i, t, p]
+       elif hue == 1: rgb = [q, i, p]
+       elif hue == 2: rgb = [p, i, t]
+       elif hue == 3: rgb = [p, q, i]
+       elif hue == 4: rgb = [t, p, i]
+       elif hue == 5: rgb = [i, p, q]
+
+    for index in range(3):
+       val = rgb[index]
+       if val < 0.0:
+           val = 0.0
+       if val > 1.0:
+           val = 1.0
+       rgb[index] = val
+
+    return rgb
+
+def average(rgb1, rgb2, fraction):
+    return (
+       rgb2[0] * fraction + rgb1[0] * (1.0 - fraction),
+       rgb2[1] * fraction + rgb1[1] * (1.0 - fraction),
+       rgb2[2] * fraction + rgb1[2] * (1.0 - fraction)
+    )
+
+def rgb2name(rgb):
+    return '#%02x%02x%02x' % \
+        (int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255))
+
+def rgb2brightness(rgb):
+    # Return the perceived grey level of the color
+    # (0.0 == black, 1.0 == white).
+
+    rf = 0.299
+    gf = 0.587
+    bf = 0.114
+    return rf * rgb[0] + gf * rgb[1] + bf * rgb[2]
+
+def rgb2hsi(rgb):
+    maxc = max(rgb[0], rgb[1], rgb[2])
+    minc = min(rgb[0], rgb[1], rgb[2])
+
+    intensity = maxc
+    if maxc != 0:
+      saturation  = (maxc - minc) / maxc
+    else:
+      saturation = 0.0
+
+    hue = 0.0
+    if saturation != 0.0:
+       c = []
+       for index in range(3):
+           c.append((maxc - rgb[index]) / (maxc - minc))
+
+       if rgb[0] == maxc:
+           hue = c[2] - c[1]
+       elif rgb[1] == maxc:
+           hue = 2 + c[0] - c[2]
+       elif rgb[2] == maxc:
+           hue = 4 + c[1] - c[0]
+
+       hue = hue * _THIRD_PI
+       if hue < 0.0:
+           hue = hue + _TWO_PI
+
+    return (hue, saturation, intensity)
+
+def name2rgb(root, colorName, asInt = 0):
+    if colorName[0] == '#':
+       # Extract rgb information from the color name itself, assuming
+       # it is either #rgb, #rrggbb, #rrrgggbbb, or #rrrrggggbbbb
+       # This is useful, since tk may return incorrect rgb values if
+       # the colormap is full - it will return the rbg values of the
+       # closest color available.
+        colorName = colorName[1:]
+        digits = len(colorName) / 3
+        factor = 16 ** (4 - digits)
+        rgb = (
+            string.atoi(colorName[0:digits], 16) * factor,
+            string.atoi(colorName[digits:digits * 2], 16) * factor,
+            string.atoi(colorName[digits * 2:digits * 3], 16) * factor,
+        )
+    else:
+       # We have no choice but to ask Tk what the rgb values are.
+       rgb = root.winfo_rgb(colorName)
+
+    if not asInt:
+        rgb = (rgb[0] / _MAX_RGB, rgb[1] / _MAX_RGB, rgb[2] / _MAX_RGB)
+    return rgb
+
+def _calcPalette(root, background=None, **kw):
+    # Create a map that has the complete new palette.  If some colors
+    # aren't specified, compute them from other colors that are specified.
+    new = {}
+    for key, value in kw.items():
+       new[key] = value
+    if background is not None:
+       new['background'] = background
+    if not new.has_key('background'):
+       raise ValueError, 'must specify a background color'
+
+    if not new.has_key('foreground'):
+       new['foreground'] = 'black'
+
+    bg = name2rgb(root, new['background'])
+    fg = name2rgb(root, new['foreground'])
+
+    for i in ('activeForeground', 'insertBackground', 'selectForeground',
+           'highlightColor'):
+       if not new.has_key(i):
+           new[i] = new['foreground']
+
+    if not new.has_key('disabledForeground'):
+       newCol = average(bg, fg, 0.3)
+       new['disabledForeground'] = rgb2name(newCol)
+
+    if not new.has_key('highlightBackground'):
+       new['highlightBackground'] = new['background']
+
+    # Set <lighterBg> to a color that is a little lighter that the
+    # normal background.  To do this, round each color component up by
+    # 9% or 1/3 of the way to full white, whichever is greater.
+    lighterBg = []
+    for i in range(3):
+       lighterBg.append(bg[i])
+       inc1 = lighterBg[i] * 0.09
+       inc2 = (1.0 - lighterBg[i]) / 3
+       if inc1 > inc2:
+           lighterBg[i] = lighterBg[i] + inc1
+       else:
+           lighterBg[i] = lighterBg[i] + inc2
+       if lighterBg[i] > 1.0:
+           lighterBg[i] = 1.0
+
+    # Set <darkerBg> to a color that is a little darker that the
+    # normal background.
+    darkerBg = (bg[0] * 0.9, bg[1] * 0.9, bg[2] * 0.9)
+
+    if not new.has_key('activeBackground'):
+       # If the foreground is dark, pick a light active background.
+       # If the foreground is light, pick a dark active background.
+       # XXX This has been disabled, since it does not look very
+       # good with dark backgrounds. If this is ever fixed, the
+       # selectBackground and troughColor options should also be fixed.
+
+       if rgb2brightness(fg) < 0.5:
+           new['activeBackground'] = rgb2name(lighterBg)
+       else:
+           new['activeBackground'] = rgb2name(lighterBg)
+
+    if not new.has_key('selectBackground'):
+       new['selectBackground'] = rgb2name(darkerBg)
+    if not new.has_key('troughColor'):
+       new['troughColor'] = rgb2name(darkerBg)
+    if not new.has_key('selectColor'):
+       new['selectColor'] = 'yellow'
+
+    return new
+
+def spectrum(numColors, correction = 1.0, saturation = 1.0, intensity = 1.0,
+       extraOrange = 1, returnHues = 0):
+    colorList = []
+    division = numColors / 7.0
+    for index in range(numColors):
+       if extraOrange:
+           if index < 2 * division:
+               hue = index / division
+           else:
+               hue = 2 + 2 * (index - 2 * division) / division
+           hue = hue * _SIXTH_PI
+       else:
+           hue = index * _TWO_PI / numColors
+       if returnHues:
+           colorList.append(hue)
+       else:
+           rgb = hsi2rgb(hue, saturation, intensity)
+           if correction != 1.0:
+               rgb = correct(rgb, correction)
+           name = rgb2name(rgb)
+           colorList.append(name)
+    return colorList
+
+def correct(rgb, correction):
+    correction = float(correction)
+    rtn = []
+    for index in range(3):
+       rtn.append((1 - (1 - rgb[index]) ** correction) ** (1 / correction))
+    return rtn
+
+#==============================================================================
+
+def _recolorTree(widget, oldpalette, newcolors):
+    # Change the colors in a widget and its descendants.
+
+    # Change the colors in <widget> and all of its descendants,
+    # according to the <newcolors> dictionary.  It only modifies
+    # colors that have their default values as specified by the
+    # <oldpalette> variable.  The keys of the <newcolors> dictionary
+    # are named after widget configuration options and the values are
+    # the new value for that option.
+
+    for dbOption in newcolors.keys():
+        option = string.lower(dbOption)
+        try:
+            value = str(widget.cget(option))
+        except:
+            continue
+        if oldpalette is None or value == oldpalette[dbOption]:
+            apply(widget.configure, (), {option : newcolors[dbOption]})
+
+    for child in widget.winfo_children():
+       _recolorTree(child, oldpalette, newcolors)
+
+def changecolor(widget, background=None, **kw):
+     root = widget._root()
+     if not hasattr(widget, '_Pmw_oldpalette'):
+        widget._Pmw_oldpalette = getdefaultpalette(root)
+     newpalette = apply(_calcPalette, (root, background,), kw)
+     _recolorTree(widget, widget._Pmw_oldpalette, newpalette)
+     widget._Pmw_oldpalette = newpalette
+
+def bordercolors(root, colorName):
+    # This is the same method that Tk uses for shadows, in TkpGetShadows.
+
+    lightRGB = []
+    darkRGB = []
+    for value in name2rgb(root, colorName, 1):
+        value40pc = (14 * value) / 10
+        if value40pc > _MAX_RGB:
+            value40pc = _MAX_RGB
+        valueHalfWhite = (_MAX_RGB + value) / 2;
+        lightRGB.append(max(value40pc, valueHalfWhite))
+
+        darkValue = (60 * value) / 100
+        darkRGB.append(darkValue)
+
+    return (
+        '#%04x%04x%04x' % (lightRGB[0], lightRGB[1], lightRGB[2]),
+        '#%04x%04x%04x' % (darkRGB[0], darkRGB[1], darkRGB[2])
+    )
diff --git a/Pmw/Pmw_1_2/lib/PmwComboBox.py b/Pmw/Pmw_1_2/lib/PmwComboBox.py
new file mode 100644 (file)
index 0000000..48b6f9d
--- /dev/null
@@ -0,0 +1,382 @@
+# Based on iwidgets2.2.0/combobox.itk code.
+
+import os
+import string
+import types
+import Tkinter
+import Pmw
+
+class ComboBox(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('autoclear',          0,          INITOPT),
+           ('buttonaspect',       1.0,        INITOPT),
+           ('dropdown',           1,          INITOPT),
+           ('fliparrow',          0,          INITOPT),
+           ('history',            1,          INITOPT),
+           ('labelmargin',        0,          INITOPT),
+           ('labelpos',           None,       INITOPT),
+           ('listheight',         200,        INITOPT),
+           ('selectioncommand',   None,       None),
+           ('sticky',            'ew',        INITOPT),
+           ('unique',             1,          INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       self._entryfield = self.createcomponent('entryfield',
+               (('entry', 'entryfield_entry'),), None,
+               Pmw.EntryField, (interior,))
+       self._entryfield.grid(column=2, row=2, sticky=self['sticky'])
+       interior.grid_columnconfigure(2, weight = 1)
+       self._entryWidget = self._entryfield.component('entry')
+
+       if self['dropdown']:
+           self._isPosted = 0
+            interior.grid_rowconfigure(2, weight = 1)
+
+           # Create the arrow button.
+           self._arrowBtn = self.createcomponent('arrowbutton',
+                   (), None,
+                   Tkinter.Canvas, (interior,), borderwidth = 2,
+                   relief = 'raised',
+                   width = 16, height = 16)
+            if 'n' in self['sticky']:
+                sticky = 'n'
+            else:
+                sticky = ''
+            if 's' in self['sticky']:
+                sticky = sticky + 's'
+           self._arrowBtn.grid(column=3, row=2, sticky = sticky)
+           self._arrowRelief = self._arrowBtn.cget('relief')
+
+           # Create the label.
+           self.createlabel(interior, childCols=2)
+
+           # Create the dropdown window.
+           self._popup = self.createcomponent('popup',
+                   (), None,
+                   Tkinter.Toplevel, (interior,))
+           self._popup.withdraw()
+           self._popup.overrideredirect(1)
+
+           # Create the scrolled listbox inside the dropdown window.
+           self._list = self.createcomponent('scrolledlist',
+                   (('listbox', 'scrolledlist_listbox'),), None,
+                   Pmw.ScrolledListBox, (self._popup,),
+                   hull_borderwidth = 2,
+                   hull_relief = 'raised',
+                   hull_height = self['listheight'],
+                   usehullsize = 1,
+                   listbox_exportselection = 0)
+           self._list.pack(expand=1, fill='both')
+           self.__listbox = self._list.component('listbox')
+
+           # Bind events to the arrow button.
+           self._arrowBtn.bind('<1>', self._postList)
+           self._arrowBtn.bind('<Configure>', self._drawArrow)
+           self._arrowBtn.bind('<3>', self._next)
+           self._arrowBtn.bind('<Shift-3>', self._previous)
+           self._arrowBtn.bind('<Down>', self._next)
+           self._arrowBtn.bind('<Up>', self._previous)
+           self._arrowBtn.bind('<Control-n>', self._next)
+           self._arrowBtn.bind('<Control-p>', self._previous)
+           self._arrowBtn.bind('<Shift-Down>', self._postList)
+           self._arrowBtn.bind('<Shift-Up>', self._postList)
+           self._arrowBtn.bind('<F34>', self._postList)
+           self._arrowBtn.bind('<F28>', self._postList)
+           self._arrowBtn.bind('<space>', self._postList)
+
+           # Bind events to the dropdown window.
+           self._popup.bind('<Escape>', self._unpostList)
+           self._popup.bind('<space>', self._selectUnpost)
+           self._popup.bind('<Return>', self._selectUnpost)
+           self._popup.bind('<ButtonRelease-1>', self._dropdownBtnRelease)
+           self._popup.bind('<ButtonPress-1>', self._unpostOnNextRelease)
+
+           # Bind events to the Tk listbox.
+           self.__listbox.bind('<Enter>', self._unpostOnNextRelease)
+
+           # Bind events to the Tk entry widget.
+           self._entryWidget.bind('<Configure>', self._resizeArrow)
+           self._entryWidget.bind('<Shift-Down>', self._postList)
+           self._entryWidget.bind('<Shift-Up>', self._postList)
+           self._entryWidget.bind('<F34>', self._postList)
+           self._entryWidget.bind('<F28>', self._postList)
+
+            # Need to unpost the popup if the entryfield is unmapped (eg: 
+            # its toplevel window is withdrawn) while the popup list is
+            # displayed.
+            self._entryWidget.bind('<Unmap>', self._unpostList)
+
+       else:
+           # Create the scrolled listbox below the entry field.
+           self._list = self.createcomponent('scrolledlist',
+                   (('listbox', 'scrolledlist_listbox'),), None,
+                   Pmw.ScrolledListBox, (interior,),
+                    selectioncommand = self._selectCmd)
+           self._list.grid(column=2, row=3, sticky='nsew')
+           self.__listbox = self._list.component('listbox')
+
+           # The scrolled listbox should expand vertically.
+           interior.grid_rowconfigure(3, weight = 1)
+
+           # Create the label.
+           self.createlabel(interior, childRows=2)
+
+       self._entryWidget.bind('<Down>', self._next)
+       self._entryWidget.bind('<Up>', self._previous)
+       self._entryWidget.bind('<Control-n>', self._next)
+       self._entryWidget.bind('<Control-p>', self._previous)
+       self.__listbox.bind('<Control-n>', self._next)
+       self.__listbox.bind('<Control-p>', self._previous)
+
+       if self['history']:
+           self._entryfield.configure(command=self._addHistory)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self['dropdown'] and self._isPosted:
+            Pmw.popgrab(self._popup)
+        Pmw.MegaWidget.destroy(self)
+
+    #======================================================================
+
+    # Public methods
+
+    def get(self, first = None, last=None):
+       if first is None:
+           return self._entryWidget.get()
+       else:
+           return self._list.get(first, last)
+
+    def invoke(self):
+       if self['dropdown']:
+           self._postList()
+       else:
+           return self._selectCmd()
+
+    def selectitem(self, index, setentry=1):
+       if type(index) == types.StringType:
+           text = index
+           items = self._list.get(0, 'end')
+           if text in items:
+               index = list(items).index(text)
+           else:
+               raise IndexError, 'index "%s" not found' % text
+       elif setentry:
+           text = self._list.get(0, 'end')[index]
+
+       self._list.select_clear(0, 'end')
+       self._list.select_set(index, index)
+       self._list.activate(index)
+       self.see(index)
+       if setentry:
+           self._entryfield.setentry(text)
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)size method inherited from Tkinter.Frame.Grid.
+    def size(self):
+       return self._list.size()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Frame.Grid.
+    def bbox(self, index):
+       return self._list.bbox(index)
+
+    def clear(self):
+       self._entryfield.clear()
+       self._list.clear()
+
+    #======================================================================
+
+    # Private methods for both dropdown and simple comboboxes.
+
+    def _addHistory(self):
+       input = self._entryWidget.get()
+
+       if input != '':
+           index = None
+           if self['unique']:
+               # If item is already in list, select it and return.
+               items = self._list.get(0, 'end')
+               if input in items:
+                   index = list(items).index(input)
+
+           if index is None:
+               index = self._list.index('end')
+               self._list.insert('end', input)
+
+           self.selectitem(index)
+           if self['autoclear']:
+               self._entryWidget.delete(0, 'end')
+
+           # Execute the selectioncommand on the new entry.
+           self._selectCmd()
+
+    def _next(self, event):
+       size = self.size()
+       if size <= 1:
+           return
+
+       cursels = self.curselection()
+
+       if len(cursels) == 0:
+           index = 0
+       else:
+           index = string.atoi(cursels[0])
+           if index == size - 1:
+               index = 0
+           else:
+               index = index + 1
+
+       self.selectitem(index)
+
+    def _previous(self, event):
+       size = self.size()
+       if size <= 1:
+           return
+
+       cursels = self.curselection()
+
+       if len(cursels) == 0:
+           index = size - 1
+       else:
+           index = string.atoi(cursels[0])
+           if index == 0:
+               index = size - 1
+           else:
+               index = index - 1
+
+       self.selectitem(index)
+
+    def _selectCmd(self, event=None):
+
+       sels = self.getcurselection()
+       if len(sels) == 0:
+           item = None
+       else:
+           item = sels[0]
+           self._entryfield.setentry(item)
+
+       cmd = self['selectioncommand']
+       if callable(cmd):
+            if event is None:
+                # Return result of selectioncommand for invoke() method.
+                return cmd(item)
+            else:
+                cmd(item)
+
+    #======================================================================
+
+    # Private methods for dropdown combobox.
+
+    def _drawArrow(self, event=None, sunken=0):
+        arrow = self._arrowBtn
+       if sunken:
+           self._arrowRelief = arrow.cget('relief')
+           arrow.configure(relief = 'sunken')
+       else:
+           arrow.configure(relief = self._arrowRelief)
+
+       if self._isPosted and self['fliparrow']:
+            direction = 'up'
+        else:
+            direction = 'down'
+        Pmw.drawarrow(arrow, self['entry_foreground'], direction, 'arrow')
+
+    def _postList(self, event = None):
+        self._isPosted = 1
+        self._drawArrow(sunken=1)
+
+        # Make sure that the arrow is displayed sunken.
+        self.update_idletasks()
+
+        x = self._entryfield.winfo_rootx()
+        y = self._entryfield.winfo_rooty() + \
+            self._entryfield.winfo_height()
+        w = self._entryfield.winfo_width() + self._arrowBtn.winfo_width()
+        h =  self.__listbox.winfo_height()
+        sh = self.winfo_screenheight()
+
+        if y + h > sh and y > sh / 2:
+            y = self._entryfield.winfo_rooty() - h
+
+        self._list.configure(hull_width=w)
+
+        Pmw.setgeometryanddeiconify(self._popup, '+%d+%d' % (x, y))
+
+        # Grab the popup, so that all events are delivered to it, and
+        # set focus to the listbox, to make keyboard navigation
+        # easier.
+        Pmw.pushgrab(self._popup, 1, self._unpostList)
+        self.__listbox.focus_set()
+
+        self._drawArrow()
+
+        # Ignore the first release of the mouse button after posting the
+        # dropdown list, unless the mouse enters the dropdown list.
+        self._ignoreRelease = 1
+
+    def _dropdownBtnRelease(self, event):
+       if (event.widget == self._list.component('vertscrollbar') or
+               event.widget == self._list.component('horizscrollbar')):
+           return
+
+       if self._ignoreRelease:
+           self._unpostOnNextRelease()
+           return
+
+        self._unpostList()
+
+       if (event.x >= 0 and event.x < self.__listbox.winfo_width() and
+               event.y >= 0 and event.y < self.__listbox.winfo_height()):
+           self._selectCmd()
+
+    def _unpostOnNextRelease(self, event = None):
+       self._ignoreRelease = 0
+
+    def _resizeArrow(self, event):
+       bw = (string.atoi(self._arrowBtn['borderwidth']) + 
+               string.atoi(self._arrowBtn['highlightthickness']))
+       newHeight = self._entryfield.winfo_reqheight() - 2 * bw
+       newWidth = int(newHeight * self['buttonaspect'])
+       self._arrowBtn.configure(width=newWidth, height=newHeight)
+       self._drawArrow()
+
+    def _unpostList(self, event=None):
+       if not self._isPosted:
+            # It is possible to get events on an unposted popup.  For
+            # example, by repeatedly pressing the space key to post
+            # and unpost the popup.  The <space> event may be
+            # delivered to the popup window even though
+            # Pmw.popgrab() has set the focus away from the
+            # popup window.  (Bug in Tk?)
+            return
+
+        # Restore the focus before withdrawing the window, since
+        # otherwise the window manager may take the focus away so we
+        # can't redirect it.  Also, return the grab to the next active
+        # window in the stack, if any.
+        Pmw.popgrab(self._popup)
+       self._popup.withdraw()
+
+       self._isPosted = 0
+       self._drawArrow()
+
+    def _selectUnpost(self, event):
+        self._unpostList()
+       self._selectCmd()
+
+Pmw.forwardmethods(ComboBox, Pmw.ScrolledListBox, '_list')
+Pmw.forwardmethods(ComboBox, Pmw.EntryField, '_entryfield')
diff --git a/Pmw/Pmw_1_2/lib/PmwComboBoxDialog.py b/Pmw/Pmw_1_2/lib/PmwComboBoxDialog.py
new file mode 100644 (file)
index 0000000..3e5f4a4
--- /dev/null
@@ -0,0 +1,60 @@
+# Not Based on iwidgets version.
+
+import Pmw
+
+class ComboBoxDialog(Pmw.Dialog):
+    # Dialog window with simple combobox.
+    
+    # Dialog window displaying a list and entry field and requesting
+    # the user to make a selection or enter a value
+
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderx',    10,              INITOPT),
+           ('bordery',    10,              INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.Dialog.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       aliases = (
+           ('listbox', 'combobox_listbox'),
+           ('scrolledlist', 'combobox_scrolledlist'),
+           ('entry', 'combobox_entry'),
+           ('label', 'combobox_label'),
+       )
+       self._combobox = self.createcomponent('combobox',
+               aliases, None,
+               Pmw.ComboBox, (interior,),
+               scrolledlist_dblclickcommand = self.invoke,
+               dropdown = 0,
+       )
+       self._combobox.pack(side='top', expand='true', fill='both',
+               padx = self['borderx'], pady = self['bordery'])
+
+        if not kw.has_key('activatecommand'):
+            # Whenever this dialog is activated, set the focus to the
+            # ComboBox's listbox widget.
+            listbox = self.component('listbox')
+            self.configure(activatecommand = listbox.focus_set)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)size method inherited from Tkinter.Toplevel.Grid.
+    def size(self):
+       return self._combobox.size()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Toplevel.Grid.
+    def bbox(self, index):
+       return self._combobox.bbox(index)
+
+Pmw.forwardmethods(ComboBoxDialog, Pmw.ComboBox, '_combobox')
diff --git a/Pmw/Pmw_1_2/lib/PmwCounter.py b/Pmw/Pmw_1_2/lib/PmwCounter.py
new file mode 100644 (file)
index 0000000..af5d2eb
--- /dev/null
@@ -0,0 +1,373 @@
+import string
+import sys
+import types
+import Tkinter
+import Pmw
+
+class Counter(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('autorepeat',     1,             None),
+           ('buttonaspect',   1.0,           INITOPT),
+           ('datatype',       'numeric',     self._datatype),
+           ('increment',      1,             None),
+           ('initwait',       300,           None),
+           ('labelmargin',    0,             INITOPT),
+           ('labelpos',       None,          INITOPT),
+           ('orient',         'horizontal',  INITOPT),
+           ('padx',           0,             INITOPT),
+           ('pady',           0,             INITOPT),
+           ('repeatrate',     50,            None),
+           ('sticky',         'ew',          INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Initialise instance variables.
+       self._timerId = None
+       self._normalRelief = None
+
+       # Create the components.
+       interior = self.interior()
+
+       # If there is no label, put the arrows and the entry directly
+       # into the interior, otherwise create a frame for them.  In
+       # either case the border around the arrows and the entry will
+       # be raised (but not around the label).
+       if self['labelpos'] is None:
+           frame = interior
+            if not kw.has_key('hull_relief'):
+                frame.configure(relief = 'raised')
+            if not kw.has_key('hull_borderwidth'):
+                frame.configure(borderwidth = 1)
+       else:
+           frame = self.createcomponent('frame',
+                   (), None,
+                   Tkinter.Frame, (interior,),
+                    relief = 'raised', borderwidth = 1)
+           frame.grid(column=2, row=2, sticky=self['sticky'])
+           interior.grid_columnconfigure(2, weight=1)
+           interior.grid_rowconfigure(2, weight=1)
+
+       # Create the down arrow.
+       self._downArrowBtn = self.createcomponent('downarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+
+       # Create the entry field.
+       self._counterEntry = self.createcomponent('entryfield',
+               (('entry', 'entryfield_entry'),), None,
+               Pmw.EntryField, (frame,))
+
+       # Create the up arrow.
+       self._upArrowBtn = self.createcomponent('uparrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+
+       padx = self['padx']
+       pady = self['pady']
+       orient = self['orient']
+       if orient == 'horizontal':
+           self._downArrowBtn.grid(column = 0, row = 0)
+           self._counterEntry.grid(column = 1, row = 0,
+                    sticky = self['sticky'])
+           self._upArrowBtn.grid(column = 2, row = 0)
+           frame.grid_columnconfigure(1, weight = 1)
+           frame.grid_rowconfigure(0, weight = 1)
+           if Tkinter.TkVersion >= 4.2:
+               frame.grid_columnconfigure(0, pad = padx)
+               frame.grid_columnconfigure(2, pad = padx)
+               frame.grid_rowconfigure(0, pad = pady)
+       elif orient == 'vertical':
+           self._upArrowBtn.grid(column = 0, row = 0, sticky = 's')
+           self._counterEntry.grid(column = 0, row = 1,
+                    sticky = self['sticky'])
+           self._downArrowBtn.grid(column = 0, row = 2, sticky = 'n')
+           frame.grid_columnconfigure(0, weight = 1)
+           frame.grid_rowconfigure(0, weight = 1)
+           frame.grid_rowconfigure(2, weight = 1)
+           if Tkinter.TkVersion >= 4.2:
+               frame.grid_rowconfigure(0, pad = pady)
+               frame.grid_rowconfigure(2, pad = pady)
+               frame.grid_columnconfigure(0, pad = padx)
+       else:
+           raise ValueError, 'bad orient option ' + repr(orient) + \
+               ': must be either \'horizontal\' or \'vertical\''
+
+       self.createlabel(interior)
+
+       self._upArrowBtn.bind('<Configure>', self._drawUpArrow)
+       self._upArrowBtn.bind('<1>', self._countUp)
+       self._upArrowBtn.bind('<Any-ButtonRelease-1>', self._stopCounting)
+       self._downArrowBtn.bind('<Configure>', self._drawDownArrow)
+       self._downArrowBtn.bind('<1>', self._countDown)
+       self._downArrowBtn.bind('<Any-ButtonRelease-1>', self._stopCounting)
+       self._counterEntry.bind('<Configure>', self._resizeArrow)
+       entry = self._counterEntry.component('entry')
+       entry.bind('<Down>', lambda event, s = self: s._key_decrement(event))
+       entry.bind('<Up>', lambda event, s = self: s._key_increment(event))
+
+       # Need to cancel the timer if an arrow button is unmapped (eg: 
+       # its toplevel window is withdrawn) while the mouse button is
+       # held down.  The canvas will not get the ButtonRelease event
+       # if it is not mapped, since the implicit grab is cancelled.
+       self._upArrowBtn.bind('<Unmap>', self._stopCounting)
+       self._downArrowBtn.bind('<Unmap>', self._stopCounting)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _resizeArrow(self, event):
+       for btn in (self._upArrowBtn, self._downArrowBtn):
+           bw = (string.atoi(btn['borderwidth']) +
+                   string.atoi(btn['highlightthickness']))
+           newHeight = self._counterEntry.winfo_reqheight() - 2 * bw
+           newWidth = int(newHeight * self['buttonaspect'])
+           btn.configure(width=newWidth, height=newHeight)
+           self._drawArrow(btn)
+
+    def _drawUpArrow(self, event):
+       self._drawArrow(self._upArrowBtn)
+
+    def _drawDownArrow(self, event):
+       self._drawArrow(self._downArrowBtn)
+
+    def _drawArrow(self, arrow):
+        if self['orient'] == 'vertical':
+            if arrow == self._upArrowBtn:
+                direction = 'up'
+            else:
+                direction = 'down'
+        else:
+            if arrow == self._upArrowBtn:
+                direction = 'right'
+            else:
+                direction = 'left'
+        Pmw.drawarrow(arrow, self['entry_foreground'], direction, 'arrow')
+
+    def _stopCounting(self, event = None):
+        if self._timerId is not None:
+            self.after_cancel(self._timerId)
+           self._timerId = None
+       if self._normalRelief is not None:
+           button, relief = self._normalRelief
+           button.configure(relief=relief)
+           self._normalRelief = None
+
+    def _countUp(self, event):
+       self._normalRelief = (self._upArrowBtn, self._upArrowBtn.cget('relief'))
+       self._upArrowBtn.configure(relief='sunken')
+       # Force arrow down (it may come up immediately, if increment fails).
+       self._upArrowBtn.update_idletasks()
+       self._count(1, 1)
+
+    def _countDown(self, event):
+       self._normalRelief = (self._downArrowBtn, self._downArrowBtn.cget('relief'))
+       self._downArrowBtn.configure(relief='sunken')
+       # Force arrow down (it may come up immediately, if increment fails).
+       self._downArrowBtn.update_idletasks()
+       self._count(-1, 1)
+
+    def increment(self):
+       self._forceCount(1)
+
+    def decrement(self):
+       self._forceCount(-1)
+
+    def _key_increment(self, event):
+       self._forceCount(1)
+       self.update_idletasks()
+
+    def _key_decrement(self, event):
+       self._forceCount(-1)
+       self.update_idletasks()
+
+    def _datatype(self):
+       datatype = self['datatype']
+
+       if type(datatype) is types.DictionaryType:
+           self._counterArgs = datatype.copy()
+           if self._counterArgs.has_key('counter'):
+               datatype = self._counterArgs['counter']
+               del self._counterArgs['counter']
+           else:
+               datatype = 'numeric'
+       else:
+           self._counterArgs = {}
+
+       if _counterCommands.has_key(datatype):
+           self._counterCommand = _counterCommands[datatype]
+       elif callable(datatype):
+           self._counterCommand = datatype
+       else:
+           validValues = _counterCommands.keys()
+           validValues.sort()
+           raise ValueError, ('bad datatype value "%s":  must be a' +
+                   ' function or one of %s') % (datatype, validValues)
+
+    def _forceCount(self, factor):
+       if not self.valid():
+           self.bell()
+           return
+
+       text = self._counterEntry.get()
+       try:
+           value = apply(self._counterCommand,
+                   (text, factor, self['increment']), self._counterArgs)
+       except ValueError:
+           self.bell()
+           return
+
+        previousICursor = self._counterEntry.index('insert')
+       if self._counterEntry.setentry(value) == Pmw.OK:
+           self._counterEntry.xview('end')
+           self._counterEntry.icursor(previousICursor)
+
+    def _count(self, factor, first):
+       if not self.valid():
+           self.bell()
+           return
+
+       self._timerId = None
+       origtext = self._counterEntry.get()
+       try:
+           value = apply(self._counterCommand,
+                   (origtext, factor, self['increment']), self._counterArgs)
+       except ValueError:
+           # If text is invalid, stop counting.
+           self._stopCounting()
+           self.bell()
+           return
+
+       # If incrementing produces an invalid value, restore previous
+       # text and stop counting.
+        previousICursor = self._counterEntry.index('insert')
+       valid = self._counterEntry.setentry(value)
+       if valid != Pmw.OK:
+           self._stopCounting()
+           self._counterEntry.setentry(origtext)
+           if valid == Pmw.PARTIAL:
+               self.bell()
+           return
+       self._counterEntry.xview('end')
+       self._counterEntry.icursor(previousICursor)
+
+       if self['autorepeat']:
+           if first:
+               delay = self['initwait']
+           else:
+               delay = self['repeatrate']
+           self._timerId = self.after(delay,
+                   lambda self=self, factor=factor: self._count(factor, 0))
+
+    def destroy(self):
+       self._stopCounting()
+        Pmw.MegaWidget.destroy(self)
+
+Pmw.forwardmethods(Counter, Pmw.EntryField, '_counterEntry')
+
+def _changeNumber(text, factor, increment):
+  value = string.atol(text)
+  if factor > 0:
+    value = (value / increment) * increment + increment
+  else:
+    value = ((value - 1) / increment) * increment
+
+  # Get rid of the 'L' at the end of longs (in python up to 1.5.2).
+  rtn = str(value)
+  if rtn[-1] == 'L':
+      return rtn[:-1]
+  else:
+      return rtn
+
+def _changeReal(text, factor, increment, separator = '.'):
+  value = Pmw.stringtoreal(text, separator)
+  div = value / increment
+
+  # Compare reals using str() to avoid problems caused by binary
+  # numbers being only approximations to decimal numbers.
+  # For example, if value is -0.3 and increment is 0.1, then
+  # int(value/increment) = -2, not -3 as one would expect.
+  if str(div)[-2:] == '.0':
+    # value is an even multiple of increment.
+    div = round(div) + factor
+  else:
+    # value is not an even multiple of increment.
+    div = int(div) * 1.0
+    if value < 0:
+      div = div - 1
+    if factor > 0:
+      div = (div + 1)
+
+  value = div * increment
+
+  text = str(value)
+  if separator != '.':
+      index = string.find(text, '.')
+      if index >= 0:
+       text = text[:index] + separator + text[index + 1:]
+  return text
+
+def _changeDate(value, factor, increment, format = 'ymd',
+       separator = '/', yyyy = 0):
+
+  jdn = Pmw.datestringtojdn(value, format, separator) + factor * increment
+
+  y, m, d = Pmw.jdntoymd(jdn)
+  result = ''
+  for index in range(3):
+    if index > 0:
+      result = result + separator
+    f = format[index]
+    if f == 'y':
+      if yyyy:
+        result = result + '%02d' % y
+      else:
+        result = result + '%02d' % (y % 100)
+    elif f == 'm':
+      result = result + '%02d' % m
+    elif f == 'd':
+      result = result + '%02d' % d
+
+  return result
+
+_SECSPERDAY = 24 * 60 * 60
+def _changeTime(value, factor, increment, separator = ':', time24 = 0):
+  unixTime = Pmw.timestringtoseconds(value, separator)
+  if factor > 0:
+    chunks = unixTime / increment + 1
+  else:
+    chunks = (unixTime - 1) / increment
+  unixTime = chunks * increment
+  if time24:
+      while unixTime < 0:
+         unixTime = unixTime + _SECSPERDAY
+      while unixTime >= _SECSPERDAY:
+         unixTime = unixTime - _SECSPERDAY
+  if unixTime < 0:
+    unixTime = -unixTime
+    sign = '-'
+  else:
+    sign = ''
+  secs = unixTime % 60
+  unixTime = unixTime / 60
+  mins = unixTime % 60
+  hours = unixTime / 60
+  return '%s%02d%s%02d%s%02d' % (sign, hours, separator, mins, separator, secs)
+
+# hexadecimal, alphabetic, alphanumeric not implemented
+_counterCommands = {
+    'numeric'   : _changeNumber,      # } integer
+    'integer'   : _changeNumber,      # } these two use the same function
+    'real'      : _changeReal,        # real number
+    'time'      : _changeTime,
+    'date'      : _changeDate,
+}
diff --git a/Pmw/Pmw_1_2/lib/PmwCounterDialog.py b/Pmw/Pmw_1_2/lib/PmwCounterDialog.py
new file mode 100644 (file)
index 0000000..6b042f9
--- /dev/null
@@ -0,0 +1,54 @@
+import Pmw
+
+# A Dialog with a counter
+
+class CounterDialog(Pmw.Dialog):
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderx',    20,  INITOPT),
+           ('bordery',    20,  INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.Dialog.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       # Create the counter.
+       aliases = (
+           ('entryfield', 'counter_entryfield'),
+           ('entry', 'counter_entryfield_entry'),
+           ('label', 'counter_label')
+       )
+       self._cdCounter = self.createcomponent('counter',
+               aliases, None,
+               Pmw.Counter, (interior,))
+       self._cdCounter.pack(fill='x', expand=1,
+               padx = self['borderx'], pady = self['bordery'])
+       
+        if not kw.has_key('activatecommand'):
+            # Whenever this dialog is activated, set the focus to the
+            # Counter's entry widget.
+            tkentry = self.component('entry')
+            self.configure(activatecommand = tkentry.focus_set)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    # Supply aliases to some of the entry component methods.
+    def insertentry(self, index, text):
+       self._cdCounter.insert(index, text)
+
+    def deleteentry(self, first, last=None):
+       self._cdCounter.delete(first, last)
+
+    def indexentry(self, index):
+       return self._cdCounter.index(index)
+
+Pmw.forwardmethods(CounterDialog, Pmw.Counter, '_cdCounter')
diff --git a/Pmw/Pmw_1_2/lib/PmwDialog.py b/Pmw/Pmw_1_2/lib/PmwDialog.py
new file mode 100644 (file)
index 0000000..eaed67a
--- /dev/null
@@ -0,0 +1,184 @@
+# Based on iwidgets2.2.0/dialog.itk and iwidgets2.2.0/dialogshell.itk code.
+
+# Convention:
+#   Each dialog window should have one of these as the rightmost button:
+#     Close         Close a window which only displays information.
+#     Cancel        Close a window which may be used to change the state of
+#                   the application.
+
+import sys
+import types
+import Tkinter
+import Pmw
+
+# A Toplevel with a ButtonBox and child site.
+
+class Dialog(Pmw.MegaToplevel):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('buttonbox_hull_borderwidth',   1,         None),
+           ('buttonbox_hull_relief',        'raised',  None),
+           ('buttonboxpos',                 's',       INITOPT),
+           ('buttons',                      ('OK',),   self._buttons),
+           ('command',                      None,      None),
+           ('dialogchildsite_borderwidth',  1,         None),
+           ('dialogchildsite_relief',       'raised',  None),
+           ('defaultbutton',                None,      self._defaultButton),
+            ('master',                       'parent',  None),
+           ('separatorwidth',               0,         INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaToplevel.__init__(self, parent)
+
+       # Create the components.
+
+       oldInterior = Pmw.MegaToplevel.interior(self)
+
+       # Set up pack options according to the position of the button box.
+        pos = self['buttonboxpos']
+       if pos not in 'nsew':
+           raise ValueError, \
+               'bad buttonboxpos option "%s":  should be n, s, e, or w' \
+                   % pos
+
+       if pos in 'ns':
+           orient = 'horizontal'
+           fill = 'x'
+           if pos == 'n':
+               side = 'top'
+           else:
+               side = 'bottom'
+       else:
+           orient = 'vertical'
+           fill = 'y'
+           if pos == 'w':
+               side = 'left'
+           else:
+               side = 'right'
+
+       # Create the button box.
+       self._buttonBox = self.createcomponent('buttonbox',
+               (), None,
+               Pmw.ButtonBox, (oldInterior,), orient = orient)
+       self._buttonBox.pack(side = side, fill = fill)
+
+       # Create the separating line.
+       width = self['separatorwidth']
+       if width > 0:
+           self._separator = self.createcomponent('separator',
+                   (), None,
+                   Tkinter.Frame, (oldInterior,), relief = 'sunken',
+                   height = width, width = width, borderwidth = width / 2)
+           self._separator.pack(side = side, fill = fill)
+       
+       # Create the child site.
+       self.__dialogChildSite = self.createcomponent('dialogchildsite',
+               (), None,
+               Tkinter.Frame, (oldInterior,))
+       self.__dialogChildSite.pack(side=side, fill='both', expand=1)
+
+       self.oldButtons = ()
+       self.oldDefault = None
+
+       self.bind('<Return>', self._invokeDefault)
+        self.userdeletefunc(self._doCommand)
+        self.usermodaldeletefunc(self._doCommand)
+       
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def interior(self):
+       return self.__dialogChildSite
+
+    def invoke(self, index = Pmw.DEFAULT):
+       return self._buttonBox.invoke(index)
+
+    def _invokeDefault(self, event):
+       try:
+           self._buttonBox.index(Pmw.DEFAULT)
+       except ValueError:
+           return
+       self._buttonBox.invoke()
+
+    def _doCommand(self, name = None):
+        if name is not None and self.active() and \
+                Pmw.grabstacktopwindow() != self.component('hull'):
+            # This is a modal dialog but is not on the top of the grab
+            # stack (ie:  should not have the grab), so ignore this
+            # event.  This seems to be a bug in Tk and may occur in
+            # nested modal dialogs.
+            #
+            # An example is the PromptDialog demonstration.  To
+            # trigger the problem, start the demo, then move the mouse
+            # to the main window, hit <TAB> and then <TAB> again.  The
+            # highlight border of the "Show prompt dialog" button
+            # should now be displayed.  Now hit <SPACE>, <RETURN>,
+            # <RETURN> rapidly several times.  Eventually, hitting the
+            # return key invokes the password dialog "OK" button even
+            # though the confirm dialog is active (and therefore
+            # should have the keyboard focus).  Observed under Solaris
+            # 2.5.1, python 1.5.2 and Tk8.0.
+
+            # TODO:  Give focus to the window on top of the grabstack.
+            return
+
+       command = self['command']
+       if callable(command):
+           return command(name)
+       else:
+           if self.active():
+               self.deactivate(name)
+           else:
+               self.withdraw()
+
+    def _buttons(self):
+       buttons = self['buttons']
+       if type(buttons) != types.TupleType and type(buttons) != types.ListType:
+           raise ValueError, \
+               'bad buttons option "%s": should be a tuple' % str(buttons)
+       if self.oldButtons == buttons:
+         return
+
+       self.oldButtons = buttons
+
+       for index in range(self._buttonBox.numbuttons()):
+           self._buttonBox.delete(0)
+       for name in buttons:
+           self._buttonBox.add(name,
+               command=lambda self=self, name=name: self._doCommand(name))
+
+       if len(buttons) > 0:
+           defaultbutton = self['defaultbutton']
+           if defaultbutton is None:
+               self._buttonBox.setdefault(None)
+           else:
+               try:
+                   self._buttonBox.index(defaultbutton)
+               except ValueError:
+                   pass
+               else:
+                   self._buttonBox.setdefault(defaultbutton)
+       self._buttonBox.alignbuttons()
+
+    def _defaultButton(self):
+       defaultbutton = self['defaultbutton']
+       if self.oldDefault == defaultbutton:
+         return
+
+       self.oldDefault = defaultbutton
+
+       if len(self['buttons']) > 0:
+           if defaultbutton is None:
+               self._buttonBox.setdefault(None)
+           else:
+               try:
+                   self._buttonBox.index(defaultbutton)
+               except ValueError:
+                   pass
+               else:
+                   self._buttonBox.setdefault(defaultbutton)
diff --git a/Pmw/Pmw_1_2/lib/PmwEntryField.py b/Pmw/Pmw_1_2/lib/PmwEntryField.py
new file mode 100644 (file)
index 0000000..039013d
--- /dev/null
@@ -0,0 +1,458 @@
+# Based on iwidgets2.2.0/entryfield.itk code.
+
+import re
+import string
+import types
+import Tkinter
+import Pmw
+
+# Possible return values of validation functions.
+OK = 1
+ERROR = 0
+PARTIAL = -1
+
+class EntryField(Pmw.MegaWidget):
+    _classBindingsDefinedFor = 0
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('command',           None,        None),
+           ('errorbackground',   'pink',      None),
+           ('invalidcommand',    self.bell,   None),
+           ('labelmargin',       0,           INITOPT),
+           ('labelpos',          None,        INITOPT),
+           ('modifiedcommand',   None,        None),
+           ('sticky',            'ew',        INITOPT),
+           ('validate',          None,        self._validate),
+           ('extravalidators',   {},          None),
+           ('value',             '',          INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       self._entryFieldEntry = self.createcomponent('entry',
+               (), None,
+               Tkinter.Entry, (interior,))
+       self._entryFieldEntry.grid(column=2, row=2, sticky=self['sticky'])
+       if self['value'] != '':
+           self.__setEntry(self['value'])
+       interior.grid_columnconfigure(2, weight=1)
+       interior.grid_rowconfigure(2, weight=1)
+
+       self.createlabel(interior)
+
+       # Initialise instance variables.
+
+       self.normalBackground = None
+        self._previousText = None
+
+       # Initialise instance.
+
+       _registerEntryField(self._entryFieldEntry, self)
+
+        # Establish the special class bindings if not already done.
+        # Also create bindings if the Tkinter default interpreter has
+        # changed.  Use Tkinter._default_root to create class
+        # bindings, so that a reference to root is created by
+        # bind_class rather than a reference to self, which would
+        # prevent object cleanup.
+        if EntryField._classBindingsDefinedFor != Tkinter._default_root:
+           tagList = self._entryFieldEntry.bindtags()
+            root  = Tkinter._default_root
+                   
+           allSequences = {}
+           for tag in tagList:
+
+                sequences = root.bind_class(tag)
+                if type(sequences) is types.StringType:
+                    # In old versions of Tkinter, bind_class returns a string
+                    sequences = root.tk.splitlist(sequences)
+
+               for sequence in sequences:
+                   allSequences[sequence] = None
+           for sequence in allSequences.keys():
+               root.bind_class('EntryFieldPre', sequence, _preProcess)
+               root.bind_class('EntryFieldPost', sequence, _postProcess)
+
+           EntryField._classBindingsDefinedFor = root
+
+       self._entryFieldEntry.bindtags(('EntryFieldPre',) +
+               self._entryFieldEntry.bindtags() + ('EntryFieldPost',))
+       self._entryFieldEntry.bind('<Return>', self._executeCommand)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       _deregisterEntryField(self._entryFieldEntry)
+        Pmw.MegaWidget.destroy(self)
+
+    def _getValidatorFunc(self, validator, index):
+       # Search the extra and standard validator lists for the
+       # given 'validator'.  If 'validator' is an alias, then
+       # continue the search using the alias.  Make sure that
+       # self-referencial aliases do not cause infinite loops.
+
+       extraValidators = self['extravalidators']
+       traversedValidators = []
+
+       while 1:
+           traversedValidators.append(validator)
+           if extraValidators.has_key(validator):
+               validator = extraValidators[validator][index]
+           elif _standardValidators.has_key(validator):
+               validator = _standardValidators[validator][index]
+           else:
+               return validator
+           if validator in traversedValidators:
+               return validator
+
+    def _validate(self):
+       dict = {
+           'validator' : None,
+           'min' : None,
+           'max' : None,
+           'minstrict' : 1,
+           'maxstrict' : 1,
+       }
+       opt = self['validate']
+       if type(opt) is types.DictionaryType:
+           dict.update(opt)
+       else:
+           dict['validator'] = opt
+
+       # Look up validator maps and replace 'validator' field with
+       # the corresponding function.
+       validator = dict['validator']
+       valFunction = self._getValidatorFunc(validator, 0)
+       self._checkValidateFunction(valFunction, 'validate', validator)
+       dict['validator'] = valFunction
+
+       # Look up validator maps and replace 'stringtovalue' field
+       # with the corresponding function.
+       if dict.has_key('stringtovalue'):
+           stringtovalue = dict['stringtovalue'] 
+           strFunction = self._getValidatorFunc(stringtovalue, 1)
+           self._checkValidateFunction(
+                   strFunction, 'stringtovalue', stringtovalue)
+       else:
+           strFunction = self._getValidatorFunc(validator, 1)
+           if strFunction == validator:
+               strFunction = len
+       dict['stringtovalue'] = strFunction
+
+       self._validationInfo = dict
+       args = dict.copy()
+       del args['validator']
+       del args['min']
+       del args['max']
+       del args['minstrict']
+       del args['maxstrict']
+       del args['stringtovalue']
+       self._validationArgs = args
+        self._previousText = None
+
+       if type(dict['min']) == types.StringType and strFunction is not None:
+           dict['min'] = apply(strFunction, (dict['min'],), args)
+       if type(dict['max']) == types.StringType and strFunction is not None:
+           dict['max'] = apply(strFunction, (dict['max'],), args)
+
+       self._checkValidity()
+
+    def _checkValidateFunction(self, function, option, validator):
+       # Raise an error if 'function' is not a function or None.
+
+       if function is not None and not callable(function):
+           extraValidators = self['extravalidators']
+           extra = extraValidators.keys()
+           extra.sort()
+           extra = tuple(extra)
+           standard = _standardValidators.keys()
+           standard.sort()
+           standard = tuple(standard)
+           msg = 'bad %s value "%s":  must be a function or one of ' \
+               'the standard validators %s or extra validators %s'
+           raise ValueError, msg % (option, validator, standard, extra)
+
+    def _executeCommand(self, event = None):
+       cmd = self['command']
+       if callable(cmd):
+            if event is None:
+                # Return result of command for invoke() method.
+                return cmd()
+            else:
+                cmd()
+           
+    def _preProcess(self):
+
+        self._previousText = self._entryFieldEntry.get()
+        self._previousICursor = self._entryFieldEntry.index('insert')
+        self._previousXview = self._entryFieldEntry.index('@0')
+       if self._entryFieldEntry.selection_present():
+           self._previousSel= (self._entryFieldEntry.index('sel.first'),
+               self._entryFieldEntry.index('sel.last'))
+       else:
+           self._previousSel = None
+
+    def _postProcess(self):
+
+       # No need to check if text has not changed.
+       previousText = self._previousText
+       if previousText == self._entryFieldEntry.get():
+           return self.valid()
+
+       valid = self._checkValidity()
+        if self.hulldestroyed():
+            # The invalidcommand called by _checkValidity() destroyed us.
+            return valid
+
+       cmd = self['modifiedcommand']
+       if callable(cmd) and previousText != self._entryFieldEntry.get():
+           cmd()
+       return valid
+           
+    def checkentry(self):
+       # If there is a variable specified by the entry_textvariable
+       # option, checkentry() should be called after the set() method
+       # of the variable is called.
+
+       self._previousText = None
+       return self._postProcess()
+
+    def _getValidity(self):
+       text = self._entryFieldEntry.get()
+       dict = self._validationInfo
+       args = self._validationArgs
+
+       if dict['validator'] is not None:
+           status = apply(dict['validator'], (text,), args)
+           if status != OK:
+               return status
+
+       # Check for out of (min, max) range.
+       if dict['stringtovalue'] is not None:
+           min = dict['min']
+           max = dict['max']
+           if min is None and max is None:
+               return OK
+           val = apply(dict['stringtovalue'], (text,), args)
+           if min is not None and val < min:
+               if dict['minstrict']:
+                   return ERROR
+               else:
+                   return PARTIAL
+           if max is not None and val > max:
+               if dict['maxstrict']:
+                   return ERROR
+               else:
+                   return PARTIAL
+       return OK
+
+    def _checkValidity(self):
+       valid = self._getValidity()
+       oldValidity = valid
+
+       if valid == ERROR:
+           # The entry is invalid.
+           cmd = self['invalidcommand']
+           if callable(cmd):
+               cmd()
+            if self.hulldestroyed():
+                # The invalidcommand destroyed us.
+                return oldValidity
+
+           # Restore the entry to its previous value.
+           if self._previousText is not None:
+               self.__setEntry(self._previousText)
+               self._entryFieldEntry.icursor(self._previousICursor)
+               self._entryFieldEntry.xview(self._previousXview)
+               if self._previousSel is not None:
+                   self._entryFieldEntry.selection_range(self._previousSel[0],
+                       self._previousSel[1])
+
+               # Check if the saved text is valid as well.
+               valid = self._getValidity()
+
+       self._valid = valid
+
+        if self.hulldestroyed():
+            # The validator or stringtovalue commands called by
+            # _checkValidity() destroyed us.
+            return oldValidity
+
+       if valid == OK:
+           if self.normalBackground is not None:
+               self._entryFieldEntry.configure(
+                       background = self.normalBackground)
+               self.normalBackground = None
+       else:
+           if self.normalBackground is None:
+               self.normalBackground = self._entryFieldEntry.cget('background')
+               self._entryFieldEntry.configure(
+                       background = self['errorbackground'])
+
+        return oldValidity
+
+    def invoke(self):
+       return self._executeCommand()
+
+    def valid(self):
+        return self._valid == OK
+
+    def clear(self):
+        self.setentry('')
+
+    def __setEntry(self, text):
+       oldState = str(self._entryFieldEntry.cget('state'))
+       if oldState != 'normal':
+           self._entryFieldEntry.configure(state='normal')
+       self._entryFieldEntry.delete(0, 'end')
+       self._entryFieldEntry.insert(0, text)
+       if oldState != 'normal':
+           self._entryFieldEntry.configure(state=oldState)
+
+    def setentry(self, text):
+       self._preProcess()
+        self.__setEntry(text)
+       return self._postProcess()
+
+    def getvalue(self):
+        return self._entryFieldEntry.get()
+
+    def setvalue(self, text):
+        return self.setentry(text)
+
+Pmw.forwardmethods(EntryField, Tkinter.Entry, '_entryFieldEntry')
+
+# ======================================================================
+
+
+# Entry field validation functions
+
+_numericregex = re.compile('^[0-9]*$')
+_alphabeticregex = re.compile('^[a-z]*$', re.IGNORECASE)
+_alphanumericregex = re.compile('^[0-9a-z]*$', re.IGNORECASE)
+
+def numericvalidator(text):
+    if text == '':
+        return PARTIAL
+    else:
+       if _numericregex.match(text) is None:
+           return ERROR
+       else:
+           return OK
+    
+def integervalidator(text):
+    if text in ('', '-', '+'):
+        return PARTIAL
+    try:
+       string.atol(text)
+       return OK
+    except ValueError:
+       return ERROR
+    
+def alphabeticvalidator(text):
+    if _alphabeticregex.match(text) is None:
+       return ERROR
+    else:
+       return OK
+    
+def alphanumericvalidator(text):
+    if _alphanumericregex.match(text) is None:
+       return ERROR
+    else:
+       return OK
+    
+def hexadecimalvalidator(text):
+    if text in ('', '0x', '0X', '+', '+0x', '+0X', '-', '-0x', '-0X'):
+        return PARTIAL
+    try:
+       string.atol(text, 16)
+       return OK
+    except ValueError:
+       return ERROR
+    
+def realvalidator(text, separator = '.'):
+    if separator != '.':
+       if string.find(text, '.') >= 0:
+           return ERROR
+       index = string.find(text, separator)
+       if index >= 0:
+           text = text[:index] + '.' + text[index + 1:]
+    try:
+       string.atof(text)
+       return OK
+    except ValueError:
+       # Check if the string could be made valid by appending a digit
+       # eg ('-', '+', '.', '-.', '+.', '1.23e', '1E-').
+       if len(text) == 0:
+           return PARTIAL
+       if text[-1] in string.digits:
+           return ERROR
+       try:
+           string.atof(text + '0')
+           return PARTIAL
+       except ValueError:
+           return ERROR
+    
+def timevalidator(text, separator = ':'):
+    try:
+       Pmw.timestringtoseconds(text, separator)
+       return OK
+    except ValueError:
+       if len(text) > 0 and text[0] in ('+', '-'):
+           text = text[1:]
+       if re.search('[^0-9' + separator + ']', text) is not None:
+           return ERROR
+       return PARTIAL
+
+def datevalidator(text, format = 'ymd', separator = '/'):
+    try:
+       Pmw.datestringtojdn(text, format, separator)
+       return OK
+    except ValueError:
+       if re.search('[^0-9' + separator + ']', text) is not None:
+           return ERROR
+       return PARTIAL
+
+_standardValidators = {
+    'numeric'      : (numericvalidator,      string.atol),
+    'integer'      : (integervalidator,      string.atol),
+    'hexadecimal'  : (hexadecimalvalidator,  lambda s: string.atol(s, 16)),
+    'real'         : (realvalidator,         Pmw.stringtoreal),
+    'alphabetic'   : (alphabeticvalidator,   len),
+    'alphanumeric' : (alphanumericvalidator, len),
+    'time'         : (timevalidator,         Pmw.timestringtoseconds),
+    'date'         : (datevalidator,         Pmw.datestringtojdn),
+}
+
+_entryCache = {}
+
+def _registerEntryField(entry, entryField):
+    # Register an EntryField widget for an Entry widget
+
+    _entryCache[entry] = entryField
+
+def _deregisterEntryField(entry):
+    # Deregister an Entry widget
+    del _entryCache[entry]
+
+def _preProcess(event):
+    # Forward preprocess events for an Entry to it's EntryField
+
+    _entryCache[event.widget]._preProcess()
+
+def _postProcess(event):
+    # Forward postprocess events for an Entry to it's EntryField
+
+    # The function specified by the 'command' option may have destroyed
+    # the megawidget in a binding earlier in bindtags, so need to check.
+    if _entryCache.has_key(event.widget):
+        _entryCache[event.widget]._postProcess()
diff --git a/Pmw/Pmw_1_2/lib/PmwGroup.py b/Pmw/Pmw_1_2/lib/PmwGroup.py
new file mode 100644 (file)
index 0000000..5fa8a79
--- /dev/null
@@ -0,0 +1,113 @@
+import string
+import Tkinter
+import Pmw
+
+def aligngrouptags(groups):
+    # Adjust the y position of the tags in /groups/ so that they all
+    # have the height of the highest tag.
+
+    maxTagHeight = 0
+    for group in groups:
+       if group._tag is None:
+           height = (string.atoi(str(group._ring.cget('borderwidth'))) +
+                   string.atoi(str(group._ring.cget('highlightthickness'))))
+       else:
+           height = group._tag.winfo_reqheight()
+       if maxTagHeight < height:
+           maxTagHeight = height
+
+    for group in groups:
+       ringBorder = (string.atoi(str(group._ring.cget('borderwidth'))) +
+               string.atoi(str(group._ring.cget('highlightthickness'))))
+       topBorder = maxTagHeight / 2 - ringBorder / 2
+       group._hull.grid_rowconfigure(0, minsize = topBorder)
+       group._ring.grid_rowconfigure(0,
+               minsize = maxTagHeight - topBorder - ringBorder)
+       if group._tag is not None:
+           group._tag.place(y = maxTagHeight / 2)
+
+class Group( Pmw.MegaWidget ):
+    def __init__(self, parent = None, **kw):
+
+        # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+        optiondefs = (
+           ('collapsedsize',    6,         INITOPT),
+           ('ring_borderwidth', 2,         None),
+           ('ring_relief',      'groove',  None),
+           ('tagindent',        10,        INITOPT),
+        )
+        self.defineoptions(kw, optiondefs)
+
+        # Initialise the base class (after defining the options).
+        Pmw.MegaWidget.__init__(self, parent)
+
+        # Create the components.
+        interior = Pmw.MegaWidget.interior(self)
+
+       self._ring = self.createcomponent(
+           'ring', 
+           (), None,
+           Tkinter.Frame, (interior,), 
+           )
+
+       self._groupChildSite = self.createcomponent(
+           'groupchildsite',
+           (), None,
+           Tkinter.Frame, (self._ring,)
+           )
+
+        self._tag = self.createcomponent(
+           'tag',
+           (), None,
+           Tkinter.Label, (interior,),
+           )
+
+       ringBorder = (string.atoi(str(self._ring.cget('borderwidth'))) +
+               string.atoi(str(self._ring.cget('highlightthickness'))))
+       if self._tag is None:
+           tagHeight = ringBorder
+       else:
+           tagHeight = self._tag.winfo_reqheight()
+           self._tag.place(
+                   x = ringBorder + self['tagindent'],
+                   y = tagHeight / 2,
+                   anchor = 'w')
+
+       topBorder = tagHeight / 2 - ringBorder / 2
+       self._ring.grid(column = 0, row = 1, sticky = 'nsew')
+       interior.grid_columnconfigure(0, weight = 1)
+       interior.grid_rowconfigure(1, weight = 1)
+       interior.grid_rowconfigure(0, minsize = topBorder)
+
+       self._groupChildSite.grid(column = 0, row = 1, sticky = 'nsew')
+       self._ring.grid_columnconfigure(0, weight = 1)
+       self._ring.grid_rowconfigure(1, weight = 1)
+       self._ring.grid_rowconfigure(0,
+               minsize = tagHeight - topBorder - ringBorder)
+
+        self.showing = 1
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def toggle(self):
+        if self.showing:
+            self.collapse()
+        else:
+            self.expand()
+        self.showing = not self.showing
+
+    def expand(self):
+        self._groupChildSite.grid(column = 0, row = 1, sticky = 'nsew')
+
+    def collapse(self):
+        self._groupChildSite.grid_forget()
+       if self._tag is None:
+           tagHeight = 0
+       else:
+            tagHeight = self._tag.winfo_reqheight()
+        self._ring.configure(height=(tagHeight / 2) + self['collapsedsize'])
+
+    def interior(self):
+        return self._groupChildSite
diff --git a/Pmw/Pmw_1_2/lib/PmwHistoryText.py b/Pmw/Pmw_1_2/lib/PmwHistoryText.py
new file mode 100644 (file)
index 0000000..0170204
--- /dev/null
@@ -0,0 +1,145 @@
+import Pmw
+
+_ORIGINAL = 0
+_MODIFIED = 1
+_DISPLAY = 2
+
+class HistoryText(Pmw.ScrolledText):
+
+    def __init__(self, parent = None, **kw):
+
+        # Define the megawidget options.
+        optiondefs = (
+           ('compressany',         1,          None),
+           ('compresstail',        1,          None),
+            ('historycommand',      None,       None),
+        )
+        self.defineoptions(kw, optiondefs)
+
+        # Initialise the base class (after defining the options).
+        Pmw.ScrolledText.__init__(self, parent)
+
+        # Initialise instance variables.
+       self._list = []
+       self._currIndex = 0
+       self._pastIndex = None
+       self._lastIndex = 0          # pointer to end of history list
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def addhistory(self):
+       text = self.get()
+       if text[-1] == '\n':
+           text = text[:-1]
+
+       if len(self._list) == 0:
+            # This is the first history entry.  Add it.
+           self._list.append([text, text, _MODIFIED])
+            return
+
+        currentEntry =  self._list[self._currIndex]
+        if text == currentEntry[_ORIGINAL]:
+            # The current history entry has not been modified. Check if
+            # we need to add it again.
+
+            if self['compresstail'] and self._currIndex == self._lastIndex:
+                return
+
+            if self['compressany']:
+                return
+
+        # Undo any changes for the current history entry, since they
+        # will now be available in the new entry.
+        currentEntry[_MODIFIED] = currentEntry[_ORIGINAL]
+
+        historycommand = self['historycommand']
+        if self._currIndex == self._lastIndex:
+            # The last history entry is currently being displayed,
+            # so disable the special meaning of the 'Next' button.
+            self._pastIndex = None
+            nextState = 'disabled'
+        else:
+            # A previous history entry is currently being displayed,
+            # so allow the 'Next' button to go to the entry after this one.
+            self._pastIndex = self._currIndex
+            nextState = 'normal'
+        if callable(historycommand):
+            historycommand('normal', nextState)
+
+        # Create the new history entry.
+        self._list.append([text, text, _MODIFIED])
+
+        # Move the pointer into the history entry list to the end.
+        self._lastIndex = self._lastIndex + 1
+        self._currIndex = self._lastIndex
+
+    def next(self):
+       if self._currIndex == self._lastIndex and self._pastIndex is None:
+           self.bell()
+        else:
+            self._modifyDisplay('next')
+
+    def prev(self):
+        self._pastIndex = None
+       if self._currIndex == 0:
+           self.bell()
+        else:
+            self._modifyDisplay('prev')
+
+    def undo(self):
+       if len(self._list) != 0:
+            self._modifyDisplay('undo')
+
+    def redo(self):
+       if len(self._list) != 0:
+            self._modifyDisplay('redo')
+
+    def gethistory(self):
+        return self._list
+
+    def _modifyDisplay(self, command):
+        # Modify the display to show either the next or previous
+        # history entry (next, prev) or the original or modified
+        # version of the current history entry (undo, redo).
+
+        # Save the currently displayed text.
+        currentText = self.get()
+        if currentText[-1] == '\n':
+            currentText = currentText[:-1]
+
+        currentEntry =  self._list[self._currIndex]
+        if currentEntry[_DISPLAY] == _MODIFIED:
+            currentEntry[_MODIFIED] = currentText
+        elif currentEntry[_ORIGINAL] != currentText:
+            currentEntry[_MODIFIED] = currentText
+            if command in ('next', 'prev'):
+                currentEntry[_DISPLAY] = _MODIFIED
+
+        if command in ('next', 'prev'):
+            prevstate = 'normal'
+            nextstate = 'normal'
+            if command == 'next':
+                if self._pastIndex is not None:
+                    self._currIndex = self._pastIndex
+                    self._pastIndex = None
+                self._currIndex = self._currIndex + 1
+                if self._currIndex == self._lastIndex:
+                    nextstate = 'disabled'
+            elif command == 'prev':
+                self._currIndex = self._currIndex - 1
+                if self._currIndex == 0:
+                    prevstate = 'disabled'
+            historycommand = self['historycommand']
+            if callable(historycommand):
+                historycommand(prevstate, nextstate)
+            currentEntry =  self._list[self._currIndex]
+        else:
+            if command == 'undo':
+                currentEntry[_DISPLAY] = _ORIGINAL
+            elif command == 'redo':
+                currentEntry[_DISPLAY] = _MODIFIED
+
+        # Display the new text.
+        self.delete('1.0', 'end')
+        self.insert('end', currentEntry[currentEntry[_DISPLAY]])
diff --git a/Pmw/Pmw_1_2/lib/PmwLabeledWidget.py b/Pmw/Pmw_1_2/lib/PmwLabeledWidget.py
new file mode 100644 (file)
index 0000000..5efac89
--- /dev/null
@@ -0,0 +1,34 @@
+import Tkinter
+import Pmw
+
+class LabeledWidget(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('labelmargin',            0,      INITOPT),
+           ('labelpos',               None,   INITOPT),
+           ('sticky',                 'nsew', INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = Pmw.MegaWidget.interior(self)
+       self._labelChildSite = self.createcomponent('labelchildsite',
+               (), None,
+               Tkinter.Frame, (interior,))
+       self._labelChildSite.grid(column=2, row=2, sticky=self['sticky'])
+       interior.grid_columnconfigure(2, weight=1)
+       interior.grid_rowconfigure(2, weight=1)
+
+       self.createlabel(interior)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def interior(self):
+       return self._labelChildSite
diff --git a/Pmw/Pmw_1_2/lib/PmwLoader.py b/Pmw/Pmw_1_2/lib/PmwLoader.py
new file mode 100644 (file)
index 0000000..e7132ec
--- /dev/null
@@ -0,0 +1,174 @@
+# This module is used by the Pmw package system.
+# The PmwLoader class can be used to simulate a python module,
+# but also supports importing of submodules on demand.  This technique
+# reduces startup time because Pmw submodules which are not used are
+# not loaded.
+#
+# The PmwLoader class also supports runtime selection of the Pmw
+# version(s) to use.
+
+import sys
+import os
+import string
+import types
+
+_PMW_DEF = 'Pmw.def'           # Pmw definition file
+_BASEMODULE = 'Base'           # Name of Base module
+
+class PmwLoader:
+
+    def __init__(self, dirpath, instdirs, dirs):
+       self._dirpath = dirpath
+       self._instdirs = instdirs
+       self._dirs = dirs
+       self._initialised = 0
+       self._version = string.replace(instdirs[0][4:], '_', '.')
+       self._alpha_versions = ()
+       
+    #======================================================================
+
+    # Public methods.  These methods will be seen as "module methods".
+
+    def setversion(self, version):
+       if self._version == version:
+           return
+       if self._initialised:
+           raise ValueError, 'Cannot change Pmw version after initialisation'
+       self._version = version
+
+    def setalphaversions(self, *alpha_versions):
+       if self._alpha_versions == alpha_versions:
+           return
+       if self._initialised:
+           raise ValueError, \
+                   'Cannot change Pmw alpha versions after initialisation'
+       self._alpha_versions = alpha_versions
+
+    def version(self, alpha = 0):
+       if alpha:
+           return self._alpha_versions
+       else:
+           return self._version
+
+    def installedversions(self, alpha = 0):
+       rtn = []
+       if alpha:
+           dirs = filter(lambda x: x[:5] == 'Alpha', self._dirs)
+           dirs.sort()
+           dirs.reverse()
+           for dir in dirs:
+               rtn.append(string.replace(dir[6:], '_', '.'))
+       else:
+           for dir in self._instdirs:
+               rtn.append(string.replace(dir[4:], '_', '.'))
+       return rtn
+
+    #======================================================================
+
+    # Private methods
+
+    def _getmodule(self,modpath):
+       __import__(modpath)
+       mod = sys.modules[modpath]
+       return mod
+
+    def _initialise(self):
+       searchpath = []
+
+       for version in self._alpha_versions:
+           alphadir = '_Pmw.Alpha_%s.lib' % string.replace(version, '.', '_')
+           searchpath.append(alphadir)
+
+       libdir = '_Pmw.Pmw_%s.lib' % string.replace(self._version, '.', '_')
+       searchpath.append(libdir)
+
+       # Create attributes for the PmwBase classes and functions.
+       for path in searchpath:
+           try:
+               basemodule = self._getmodule(path + '.Pmw' + _BASEMODULE)
+               break
+           except ImportError, msg:
+               if path == searchpath[-1]:
+                   # No PmwBase module found.
+                   raise ImportError, msg
+
+       for k,v in basemodule.__dict__.items():
+           if k[0] is not '_' and type(v) != types.ModuleType:
+               self.__dict__[k] = v
+
+       # Set the Pmw definitions from the Pmw.def file.
+       dict = {
+           '_widgets'      : {},
+           '_extraWidgets' : {},
+           '_functions'    : {},
+           '_modules'      : {},
+       }
+       for name in dict.keys():
+           self.__dict__[name] = {}
+       searchpath.reverse()
+       for path in searchpath:
+           pathbit = apply(os.path.join, tuple(string.split(path[5:], '.')))
+           lpath = os.path.join(self._dirpath, pathbit)
+           d = {}
+           execfile(os.path.join(lpath,_PMW_DEF), d)
+           for k,v in d.items():
+               if dict.has_key(k):
+                   if type(v) == types.TupleType:
+                       for item in v:
+                           modpath = path + '.Pmw' + item
+                           dict[k][item] = modpath
+                   elif type(v) == types.DictionaryType:
+                       for k1, v1 in v.items():
+                           modpath = path + '.Pmw' + v1
+                           dict[k][k1] = modpath
+       self.__dict__.update(dict)
+       self._widgets_keys = self._widgets.keys()
+       self._extraWidgets_keys = self._extraWidgets.keys()
+       self._functions_keys = self._functions.keys()
+       self._modules_keys = self._modules.keys()
+
+       self._initialised = 1
+
+    def __getattr__(self, name):
+       if not self._initialised:
+           self._initialise()
+           # Beware: _initialise may have defined 'name'
+           if name in self.__dict__.keys():
+               return self.__dict__[name]
+
+       # The requested attribute is not yet set. Look it up in the
+       # tables set by Pmw.def, import the appropriate module and
+       # set the attribute so that it will be found next time.
+
+       if name in self._widgets_keys:
+           # The attribute is a widget name.
+           mod = self._getmodule(self._widgets[name])
+           cls = getattr(mod,name)
+           self.__dict__[name] = cls
+           return cls
+
+       if name in self._functions_keys:
+           # The attribute is a function from one of the modules.
+           modname = self._functions[name]
+           mod  = self._getmodule(modname)
+           func = getattr(mod, name)
+           self.__dict__[name] = func
+           return func
+
+       if name in self._modules_keys:
+           # The attribute is a module
+           mod = self._getmodule(self._modules[name])
+           self.__dict__[name] = mod
+           return mod
+
+       if name in self._extraWidgets_keys:
+           # XXX I should import them all, once I've started.
+            # The attribute is a widget name in a module of another name
+           modname = self._extraWidgets[name]
+           mod = self._getmodule(modname)
+           cls = getattr(mod, name)
+            self.__dict__[name] = cls
+            return cls
+
+       # The attribute is not known by Pmw, report an error.
+       raise AttributeError, name
diff --git a/Pmw/Pmw_1_2/lib/PmwLogicalFont.py b/Pmw/Pmw_1_2/lib/PmwLogicalFont.py
new file mode 100644 (file)
index 0000000..716eb19
--- /dev/null
@@ -0,0 +1,191 @@
+import os
+import string
+
+def _font_initialise(root, size=None, fontScheme = None):
+    global _fontSize
+    if size is not None:
+        _fontSize = size
+
+    if fontScheme in ('pmw1', 'pmw2'):
+        if os.name == 'posix':
+            defaultFont = logicalfont('Helvetica')
+            menuFont = logicalfont('Helvetica', weight='bold', slant='italic')
+            scaleFont = logicalfont('Helvetica', slant='italic')
+            root.option_add('*Font',            defaultFont,  'userDefault')
+            root.option_add('*Menu*Font',       menuFont,     'userDefault')
+            root.option_add('*Menubutton*Font', menuFont,     'userDefault')
+            root.option_add('*Scale.*Font',     scaleFont,    'userDefault')
+
+            if fontScheme == 'pmw1':
+                balloonFont = logicalfont('Helvetica', -6, pixel = '12')
+            else: # fontScheme == 'pmw2'
+                balloonFont = logicalfont('Helvetica', -2)
+            root.option_add('*Balloon.*Font', balloonFont, 'userDefault')
+        else:
+            defaultFont = logicalfont('Helvetica')
+            root.option_add('*Font', defaultFont,  'userDefault')
+    elif fontScheme == 'default':
+        defaultFont = ('Helvetica', '-%d' % (_fontSize,), 'bold')
+        entryFont = ('Helvetica', '-%d' % (_fontSize,))
+        textFont = ('Courier', '-%d' % (_fontSize,))
+        root.option_add('*Font',            defaultFont,  'userDefault')
+        root.option_add('*Entry*Font',      entryFont,    'userDefault')
+        root.option_add('*Text*Font',       textFont,     'userDefault')
+
+def logicalfont(name='Helvetica', sizeIncr = 0, **kw):
+  if not _fontInfo.has_key(name):
+    raise ValueError, 'font %s does not exist' % name
+
+  rtn = []
+  for field in _fontFields:
+    if kw.has_key(field):
+      logicalValue = kw[field]
+    elif _fontInfo[name].has_key(field):
+      logicalValue = _fontInfo[name][field]
+    else:
+      logicalValue = '*'
+
+    if _propertyAliases[name].has_key((field, logicalValue)):
+      realValue = _propertyAliases[name][(field, logicalValue)]
+    elif _propertyAliases[name].has_key((field, None)):
+      realValue = _propertyAliases[name][(field, None)]
+    elif _propertyAliases[None].has_key((field, logicalValue)):
+      realValue = _propertyAliases[None][(field, logicalValue)]
+    elif _propertyAliases[None].has_key((field, None)):
+      realValue = _propertyAliases[None][(field, None)]
+    else:
+      realValue = logicalValue
+
+    if field == 'size':
+      if realValue == '*':
+         realValue = _fontSize
+      realValue = str((realValue + sizeIncr) * 10)
+
+    rtn.append(realValue)
+
+  return string.join(rtn, '-')
+
+def logicalfontnames():
+  return _fontInfo.keys()
+
+if os.name == 'nt':
+    _fontSize = 16
+else:
+    _fontSize = 14
+
+_fontFields = (
+  'registry', 'foundry', 'family', 'weight', 'slant', 'width', 'style',
+  'pixel', 'size', 'xres', 'yres', 'spacing', 'avgwidth', 'charset', 'encoding')
+
+# <_propertyAliases> defines other names for which property values may
+# be known by.  This is required because italics in adobe-helvetica
+# are specified by 'o', while other fonts use 'i'.
+
+_propertyAliases = {}
+
+_propertyAliases[None] = {
+  ('slant', 'italic') : 'i',
+  ('slant', 'normal') : 'r',
+  ('weight', 'light') : 'normal',
+  ('width', 'wide') : 'normal',
+  ('width', 'condensed') : 'normal',
+}
+
+# <_fontInfo> describes a 'logical' font, giving the default values of
+# some of its properties.
+
+_fontInfo = {}
+
+_fontInfo['Helvetica'] = {
+  'foundry' : 'adobe',
+  'family' : 'helvetica',
+  'registry' : '',
+  'charset' : 'iso8859',
+  'encoding' : '1',
+  'spacing' : 'p',
+  'slant' : 'normal',
+  'width' : 'normal',
+  'weight' : 'normal',
+}
+
+_propertyAliases['Helvetica'] = {
+  ('slant', 'italic') : 'o',
+  ('weight', 'normal') : 'medium',
+  ('weight', 'light') : 'medium',
+}
+
+_fontInfo['Times'] = {
+  'foundry' : 'adobe',
+  'family' : 'times',
+  'registry' : '',
+  'charset' : 'iso8859',
+  'encoding' : '1',
+  'spacing' : 'p',
+  'slant' : 'normal',
+  'width' : 'normal',
+  'weight' : 'normal',
+}
+
+_propertyAliases['Times'] = {
+  ('weight', 'normal') : 'medium',
+  ('weight', 'light') : 'medium',
+}
+
+_fontInfo['Fixed'] = {
+  'foundry' : 'misc',
+  'family' : 'fixed',
+  'registry' : '',
+  'charset' : 'iso8859',
+  'encoding' : '1',
+  'spacing' : 'c',
+  'slant' : 'normal',
+  'width' : 'normal',
+  'weight' : 'normal',
+}
+
+_propertyAliases['Fixed'] = {
+  ('weight', 'normal') : 'medium',
+  ('weight', 'light') : 'medium',
+  ('style', None) : '',
+  ('width', 'condensed') : 'semicondensed',
+}
+
+_fontInfo['Courier'] = {
+  'foundry' : 'adobe',
+  'family' : 'courier',
+  'registry' : '',
+  'charset' : 'iso8859',
+  'encoding' : '1',
+  'spacing' : 'm',
+  'slant' : 'normal',
+  'width' : 'normal',
+  'weight' : 'normal',
+}
+
+_propertyAliases['Courier'] = {
+  ('weight', 'normal') : 'medium',
+  ('weight', 'light') : 'medium',
+  ('style', None) : '',
+}
+
+_fontInfo['Typewriter'] = {
+  'foundry' : 'b&h',
+  'family' : 'lucidatypewriter',
+  'registry' : '',
+  'charset' : 'iso8859',
+  'encoding' : '1',
+  'spacing' : 'm',
+  'slant' : 'normal',
+  'width' : 'normal',
+  'weight' : 'normal',
+}
+
+_propertyAliases['Typewriter'] = {
+  ('weight', 'normal') : 'medium',
+  ('weight', 'light') : 'medium',
+}
+
+if os.name == 'nt':
+    # For some reason 'fixed' fonts on NT aren't.
+    _fontInfo['Fixed'] = _fontInfo['Courier']
+    _propertyAliases['Fixed'] = _propertyAliases['Courier']
diff --git a/Pmw/Pmw_1_2/lib/PmwMainMenuBar.py b/Pmw/Pmw_1_2/lib/PmwMainMenuBar.py
new file mode 100644 (file)
index 0000000..8d2ca40
--- /dev/null
@@ -0,0 +1,225 @@
+# Main menubar
+
+import string
+import types
+import Tkinter
+import Pmw
+
+class MainMenuBar(Pmw.MegaArchetype):
+
+    def __init__(self, parent = None, **kw):
+
+        # Define the megawidget options.
+        INITOPT = Pmw.INITOPT
+        optiondefs = (
+            ('balloon',      None,       None),
+            ('hotkeys',      1,          INITOPT),
+            ('hull_tearoff', 0,          None),
+        )
+        self.defineoptions(kw, optiondefs, dynamicGroups = ('Menu',))
+
+        # Initialise the base class (after defining the options).
+        Pmw.MegaArchetype.__init__(self, parent, Tkinter.Menu)
+
+        self._menuInfo = {}
+        self._menuInfo[None] = (None, [])
+        # Map from a menu name to a tuple of information about the menu.
+        # The first item in the tuple is the name of the parent menu (for
+        # toplevel menus this is None). The second item in the tuple is
+        # a list of status help messages for each item in the menu.
+        # The key for the information for the main menubar is None.
+
+        self._menu = self.interior()
+        self._menu.bind('<Leave>', self._resetHelpmessage)
+        self._menu.bind('<Motion>',
+            lambda event=None, self=self: self._menuHelp(event, None))
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def deletemenuitems(self, menuName, start, end = None):
+        self.component(menuName).delete(start, end)
+        if end is None:
+            del self._menuInfo[menuName][1][start]
+        else:
+            self._menuInfo[menuName][1][start:end+1] = []
+
+    def deletemenu(self, menuName):
+        """Delete should be called for cascaded menus before main menus.
+        """
+
+        parentName = self._menuInfo[menuName][0]
+        del self._menuInfo[menuName]
+        if parentName is None:
+            parentMenu = self._menu
+        else:
+            parentMenu = self.component(parentName)
+
+        menu = self.component(menuName)
+        menuId = str(menu)
+        for item in range(parentMenu.index('end') + 1):
+            if parentMenu.type(item) == 'cascade':
+                itemMenu = str(parentMenu.entrycget(item, 'menu'))
+                if itemMenu == menuId:
+                    parentMenu.delete(item)
+                    del self._menuInfo[parentName][1][item]
+                    break
+
+        self.destroycomponent(menuName)
+
+    def disableall(self):
+        for index in range(len(self._menuInfo[None][1])):
+            self.entryconfigure(index, state = 'disabled')
+
+    def enableall(self):
+        for index in range(len(self._menuInfo[None][1])):
+            self.entryconfigure(index, state = 'normal')
+
+    def addmenu(self, menuName, balloonHelp, statusHelp = None,
+            traverseSpec = None, **kw):
+        if statusHelp is None:
+            statusHelp = balloonHelp
+        self._addmenu(None, menuName, balloonHelp, statusHelp,
+            traverseSpec, kw)
+
+    def addcascademenu(self, parentMenuName, menuName, statusHelp='',
+            traverseSpec = None, **kw):
+        self._addmenu(parentMenuName, menuName, None, statusHelp,
+            traverseSpec, kw)
+
+    def _addmenu(self, parentMenuName, menuName, balloonHelp, statusHelp,
+            traverseSpec, kw):
+
+        if (menuName) in self.components():
+            raise ValueError, 'menu "%s" already exists' % menuName
+
+        menukw = {}
+        if kw.has_key('tearoff'):
+            menukw['tearoff'] = kw['tearoff']
+            del kw['tearoff']
+        else:
+            menukw['tearoff'] = 0
+        if kw.has_key('name'):
+            menukw['name'] = kw['name']
+            del kw['name']
+
+        if not kw.has_key('label'):
+            kw['label'] = menuName
+
+        self._addHotkeyToOptions(parentMenuName, kw, traverseSpec)
+
+        if parentMenuName is None:
+            parentMenu = self._menu
+            balloon = self['balloon']
+            # Bug in Tk: balloon help not implemented
+            # if balloon is not None:
+            #     balloon.mainmenubind(parentMenu, balloonHelp, statusHelp)
+        else:
+            parentMenu = self.component(parentMenuName)
+
+        apply(parentMenu.add_cascade, (), kw)
+
+        menu = apply(self.createcomponent, (menuName,
+                (), 'Menu',
+                Tkinter.Menu, (parentMenu,)), menukw)
+        parentMenu.entryconfigure('end', menu = menu)
+
+        self._menuInfo[parentMenuName][1].append(statusHelp)
+        self._menuInfo[menuName] = (parentMenuName, [])
+
+        menu.bind('<Leave>', self._resetHelpmessage)
+        menu.bind('<Motion>', 
+            lambda event=None, self=self, menuName=menuName:
+                    self._menuHelp(event, menuName))
+
+    def addmenuitem(self, menuName, itemType, statusHelp = '',
+            traverseSpec = None, **kw):
+
+        menu = self.component(menuName)
+        if itemType != 'separator':
+            self._addHotkeyToOptions(menuName, kw, traverseSpec)
+
+        if itemType == 'command':
+            command = menu.add_command
+        elif itemType == 'separator':
+            command = menu.add_separator
+        elif itemType == 'checkbutton':
+            command = menu.add_checkbutton
+        elif itemType == 'radiobutton':
+            command = menu.add_radiobutton
+        elif itemType == 'cascade':
+            command = menu.add_cascade
+        else:
+            raise ValueError, 'unknown menuitem type "%s"' % itemType
+
+        self._menuInfo[menuName][1].append(statusHelp)
+        apply(command, (), kw)
+
+    def _addHotkeyToOptions(self, menuName, kw, traverseSpec):
+
+        if (not self['hotkeys'] or kw.has_key('underline') or
+                not kw.has_key('label')):
+            return
+
+        if type(traverseSpec) == types.IntType:
+            kw['underline'] = traverseSpec
+            return
+
+        if menuName is None:
+            menu = self._menu
+        else:
+            menu = self.component(menuName)
+        hotkeyList = []
+        end = menu.index('end')
+        if end is not None:
+            for item in range(end + 1):
+                if menu.type(item) not in ('separator', 'tearoff'):
+                    underline = \
+                            string.atoi(str(menu.entrycget(item, 'underline')))
+                    if underline != -1:
+                        label = str(menu.entrycget(item, 'label'))
+                        if underline < len(label):
+                            hotkey = string.lower(label[underline])
+                            if hotkey not in hotkeyList:
+                                hotkeyList.append(hotkey)
+
+        name = kw['label']
+
+        if type(traverseSpec) == types.StringType:
+            lowerLetter = string.lower(traverseSpec)
+            if traverseSpec in name and lowerLetter not in hotkeyList:
+                kw['underline'] = string.index(name, traverseSpec)
+        else:
+            targets = string.digits + string.letters
+            lowerName = string.lower(name)
+            for letter_index in range(len(name)):
+                letter = lowerName[letter_index]
+                if letter in targets and letter not in hotkeyList:
+                    kw['underline'] = letter_index
+                    break
+
+    def _menuHelp(self, event, menuName):
+        if menuName is None:
+            menu = self._menu
+            index = menu.index('@%d'% event.x)
+        else:
+            menu = self.component(menuName)
+            index = menu.index('@%d'% event.y)
+
+        balloon = self['balloon']
+        if balloon is not None:
+            if index is None:
+                balloon.showstatus('')
+            else:
+                if str(menu.cget('tearoff')) == '1':
+                    index = index - 1
+                if index >= 0:
+                    help = self._menuInfo[menuName][1][index]
+                    balloon.showstatus(help)
+
+    def _resetHelpmessage(self, event=None):
+        balloon = self['balloon']
+        if balloon is not None:
+            balloon.clearstatus()
+
+Pmw.forwardmethods(MainMenuBar, Tkinter.Menu, '_hull')
diff --git a/Pmw/Pmw_1_2/lib/PmwMenuBar.py b/Pmw/Pmw_1_2/lib/PmwMenuBar.py
new file mode 100644 (file)
index 0000000..a649295
--- /dev/null
@@ -0,0 +1,243 @@
+# Manager widget for menus.
+
+import string
+import types
+import Tkinter
+import Pmw
+
+class MenuBar(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+
+        # Define the megawidget options.
+        INITOPT = Pmw.INITOPT
+        optiondefs = (
+            ('balloon',      None,       None),
+            ('hotkeys',      1,          INITOPT),
+            ('padx',         0,          INITOPT),
+        )
+        self.defineoptions(kw, optiondefs, dynamicGroups = ('Menu', 'Button'))
+
+        # Initialise the base class (after defining the options).
+        Pmw.MegaWidget.__init__(self, parent)
+
+        self._menuInfo = {}
+        # Map from a menu name to a tuple of information about the menu.
+        # The first item in the tuple is the name of the parent menu (for
+        # toplevel menus this is None). The second item in the tuple is
+        # a list of status help messages for each item in the menu.
+        # The third item in the tuple is the id of the binding used
+        # to detect mouse motion to display status help.
+        # Information for the toplevel menubuttons is not stored here.
+
+        self._mydeletecommand = self.component('hull').tk.deletecommand
+        # Cache this method for use later.
+
+        # Check keywords and initialise options.
+        self.initialiseoptions()
+
+    def deletemenuitems(self, menuName, start, end = None):
+        self.component(menuName + '-menu').delete(start, end)
+        if end is None:
+            del self._menuInfo[menuName][1][start]
+        else:
+            self._menuInfo[menuName][1][start:end+1] = []
+
+    def deletemenu(self, menuName):
+        """Delete should be called for cascaded menus before main menus.
+        """
+
+        # Clean up binding for this menu.
+        parentName = self._menuInfo[menuName][0]
+        bindId = self._menuInfo[menuName][2]
+        _bindtag = 'PmwMenuBar' + str(self) + menuName
+        self.unbind_class(_bindtag, '<Motion>')
+        self._mydeletecommand(bindId) # unbind_class does not clean up
+        del self._menuInfo[menuName]
+
+        if parentName is None:
+            self.destroycomponent(menuName + '-button')
+        else:
+            parentMenu = self.component(parentName + '-menu')
+
+            menu = self.component(menuName + '-menu')
+            menuId = str(menu)
+            for item in range(parentMenu.index('end') + 1):
+                if parentMenu.type(item) == 'cascade':
+                    itemMenu = str(parentMenu.entrycget(item, 'menu'))
+                    if itemMenu == menuId:
+                        parentMenu.delete(item)
+                        del self._menuInfo[parentName][1][item]
+                        break
+
+        self.destroycomponent(menuName + '-menu')
+
+    def disableall(self):
+        for menuName in self._menuInfo.keys():
+            if self._menuInfo[menuName][0] is None:
+                menubutton = self.component(menuName + '-button')
+                menubutton.configure(state = 'disabled')
+
+    def enableall(self):
+        for menuName in self._menuInfo.keys():
+            if self._menuInfo[menuName][0] is None:
+                menubutton = self.component(menuName + '-button')
+                menubutton.configure(state = 'normal')
+
+    def addmenu(self, menuName, balloonHelp, statusHelp = None,
+            side = 'left', traverseSpec = None, **kw):
+
+        self._addmenu(None, menuName, balloonHelp, statusHelp,
+            traverseSpec, side, 'text', kw)
+
+    def addcascademenu(self, parentMenuName, menuName, statusHelp = '',
+            traverseSpec = None, **kw):
+
+        self._addmenu(parentMenuName, menuName, None, statusHelp,
+            traverseSpec, None, 'label', kw)
+
+    def _addmenu(self, parentMenuName, menuName, balloonHelp, statusHelp,
+            traverseSpec, side, textKey, kw):
+
+        if (menuName + '-menu') in self.components():
+            raise ValueError, 'menu "%s" already exists' % menuName
+
+        menukw = {}
+        if kw.has_key('tearoff'):
+            menukw['tearoff'] = kw['tearoff']
+            del kw['tearoff']
+        else:
+            menukw['tearoff'] = 0
+
+        if not kw.has_key(textKey):
+            kw[textKey] = menuName
+
+        self._addHotkeyToOptions(parentMenuName, kw, textKey, traverseSpec)
+
+        if parentMenuName is None:
+            button = apply(self.createcomponent, (menuName + '-button',
+                    (), 'Button',
+                    Tkinter.Menubutton, (self.interior(),)), kw)
+            button.pack(side=side, padx = self['padx'])
+            balloon = self['balloon']
+            if balloon is not None:
+                balloon.bind(button, balloonHelp, statusHelp)
+            parentMenu = button
+        else:
+            parentMenu = self.component(parentMenuName + '-menu')
+            apply(parentMenu.add_cascade, (), kw)
+            self._menuInfo[parentMenuName][1].append(statusHelp)
+
+        menu = apply(self.createcomponent, (menuName + '-menu',
+                (), 'Menu',
+                Tkinter.Menu, (parentMenu,)), menukw)
+        if parentMenuName is None:
+            button.configure(menu = menu)
+        else:
+            parentMenu.entryconfigure('end', menu = menu)
+
+        # Need to put this binding after the class bindings so that
+        # menu.index() does not lag behind.
+        _bindtag = 'PmwMenuBar' + str(self) + menuName
+        bindId = self.bind_class(_bindtag, '<Motion>',
+            lambda event=None, self=self, menuName=menuName:
+                    self._menuHelp(menuName))
+        menu.bindtags(menu.bindtags() + (_bindtag,))
+        menu.bind('<Leave>', self._resetHelpmessage)
+
+        self._menuInfo[menuName] = (parentMenuName, [], bindId)
+
+    def addmenuitem(self, menuName, itemType, statusHelp = '',
+            traverseSpec = None, **kw):
+
+        menu = self.component(menuName + '-menu')
+        if itemType != 'separator':
+            self._addHotkeyToOptions(menuName, kw, 'label', traverseSpec)
+
+        if itemType == 'command':
+            command = menu.add_command
+        elif itemType == 'separator':
+            command = menu.add_separator
+        elif itemType == 'checkbutton':
+            command = menu.add_checkbutton
+        elif itemType == 'radiobutton':
+            command = menu.add_radiobutton
+        elif itemType == 'cascade':
+            command = menu.add_cascade
+        else:
+            raise ValueError, 'unknown menuitem type "%s"' % itemType
+
+        self._menuInfo[menuName][1].append(statusHelp)
+        apply(command, (), kw)
+
+    def _addHotkeyToOptions(self, menuName, kw, textKey, traverseSpec):
+
+        if (not self['hotkeys'] or kw.has_key('underline') or
+                not kw.has_key(textKey)):
+            return
+
+        if type(traverseSpec) == types.IntType:
+            kw['underline'] = traverseSpec
+            return
+
+        hotkeyList = []
+        if menuName is None:
+            for menuName in self._menuInfo.keys():
+                if self._menuInfo[menuName][0] is None:
+                    menubutton = self.component(menuName + '-button')
+                    underline = string.atoi(str(menubutton.cget('underline')))
+                    if underline != -1:
+                        label = str(menubutton.cget(textKey))
+                        if underline < len(label):
+                            hotkey = string.lower(label[underline])
+                            if hotkey not in hotkeyList:
+                                hotkeyList.append(hotkey)
+        else:
+            menu = self.component(menuName + '-menu')
+            end = menu.index('end')
+            if end is not None:
+                for item in range(end + 1):
+                    if menu.type(item) not in ('separator', 'tearoff'):
+                        underline = string.atoi(
+                            str(menu.entrycget(item, 'underline')))
+                        if underline != -1:
+                            label = str(menu.entrycget(item, textKey))
+                            if underline < len(label):
+                                hotkey = string.lower(label[underline])
+                                if hotkey not in hotkeyList:
+                                    hotkeyList.append(hotkey)
+
+        name = kw[textKey]
+
+        if type(traverseSpec) == types.StringType:
+            lowerLetter = string.lower(traverseSpec)
+            if traverseSpec in name and lowerLetter not in hotkeyList:
+                kw['underline'] = string.index(name, traverseSpec)
+        else:
+            targets = string.digits + string.letters
+            lowerName = string.lower(name)
+            for letter_index in range(len(name)):
+                letter = lowerName[letter_index]
+                if letter in targets and letter not in hotkeyList:
+                    kw['underline'] = letter_index
+                    break
+
+    def _menuHelp(self, menuName):
+        menu = self.component(menuName + '-menu')
+        index = menu.index('active')
+
+        balloon = self['balloon']
+        if balloon is not None:
+            if index is None:
+                balloon.showstatus('')
+            else:
+                if str(menu.cget('tearoff')) == '1':
+                    index = index - 1
+                if index >= 0:
+                    help = self._menuInfo[menuName][1][index]
+                    balloon.showstatus(help)
+
+    def _resetHelpmessage(self, event=None):
+        balloon = self['balloon']
+        if balloon is not None:
+            balloon.clearstatus()
diff --git a/Pmw/Pmw_1_2/lib/PmwMessageBar.py b/Pmw/Pmw_1_2/lib/PmwMessageBar.py
new file mode 100644 (file)
index 0000000..55d1bf6
--- /dev/null
@@ -0,0 +1,143 @@
+# Class to display messages in an information line.
+
+import string
+import Tkinter
+import Pmw
+
+class MessageBar(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       defaultMessageTypes = {
+                          # (priority, showtime, bells, logmessage)
+           'systemerror'  : (5, 10, 2, 1),
+           'usererror'    : (4, 5, 1, 0),
+           'busy'         : (3, 0, 0, 0),
+           'systemevent'  : (2, 5, 0, 0),
+           'userevent'    : (2, 5, 0, 0),
+           'help'         : (1, 5, 0, 0),
+           'state'        : (0, 0, 0, 0),
+       }
+       optiondefs = (
+           ('labelmargin',    0,                     INITOPT),
+           ('labelpos',       None,                  INITOPT),
+           ('messagetypes',   defaultMessageTypes,   INITOPT),
+           ('silent',         0,                     None),
+           ('sticky',         'ew',                  INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       self._messageBarEntry = self.createcomponent('entry',
+               (), None,
+               Tkinter.Entry, (interior,))
+
+        # Can't always use 'disabled', since this greys out text in Tk 8.4.2
+        try:
+            self._messageBarEntry.configure(state = 'readonly')
+        except Tkinter.TclError:
+            self._messageBarEntry.configure(state = 'disabled')
+
+       self._messageBarEntry.grid(column=2, row=2, sticky=self['sticky'])
+       interior.grid_columnconfigure(2, weight=1)
+       interior.grid_rowconfigure(2, weight=1)
+
+       self.createlabel(interior)
+
+       # Initialise instance variables.
+       self._numPriorities = 0
+       for info in self['messagetypes'].values():
+           if self._numPriorities < info[0]:
+               self._numPriorities = info[0]
+
+       self._numPriorities = self._numPriorities + 1
+       self._timer = [None] * self._numPriorities
+       self._messagetext = [''] * self._numPriorities
+       self._activemessage = [0] * self._numPriorities
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       for timerId in self._timer:
+           if timerId is not None:
+               self.after_cancel(timerId)
+       self._timer = [None] * self._numPriorities
+       Pmw.MegaWidget.destroy(self)
+
+    def message(self, type, text):
+        # Display a message in the message bar.
+
+       (priority, showtime, bells, logmessage) = self['messagetypes'][type]
+
+       if not self['silent']:
+           for i in range(bells):
+               if i != 0:
+                   self.after(100)
+               self.bell()
+
+       self._activemessage[priority] = 1
+       if text is None:
+           text = ''
+       self._messagetext[priority] = string.replace(text, '\n', ' ')
+       self._redisplayInfoMessage()
+
+       if logmessage:
+           # Should log this text to a text widget.
+           pass
+
+       if showtime > 0:
+           if self._timer[priority] is not None:
+               self.after_cancel(self._timer[priority])
+
+           # Define a callback to clear this message after a time.
+           def _clearmessage(self=self, priority=priority):
+               self._clearActivemessage(priority)
+
+           mseconds = int(showtime * 1000)
+           self._timer[priority] = self.after(mseconds, _clearmessage)
+
+    def helpmessage(self, text):
+        if text is None:
+            self.resetmessages('help')
+        else:
+            self.message('help', text)
+
+    def resetmessages(self, type):
+       priority = self['messagetypes'][type][0]
+       self._clearActivemessage(priority)
+       for messagetype, info in self['messagetypes'].items():
+           thisPriority = info[0]
+           showtime = info[1]
+           if thisPriority < priority and showtime != 0:
+               self._clearActivemessage(thisPriority)
+
+    def _clearActivemessage(self, priority):
+       self._activemessage[priority] = 0
+       if self._timer[priority] is not None:
+           self.after_cancel(self._timer[priority])
+           self._timer[priority] = None
+       self._redisplayInfoMessage()
+
+    def _redisplayInfoMessage(self):
+       text = ''
+        for priority in range(self._numPriorities - 1, -1, -1):
+           if self._activemessage[priority]:
+               text = self._messagetext[priority]
+               break
+       self._messageBarEntry.configure(state = 'normal')
+       self._messageBarEntry.delete(0, 'end')
+       self._messageBarEntry.insert('end', text)
+
+        # Can't always use 'disabled', since this greys out text in Tk 8.4.2
+        try:
+            self._messageBarEntry.configure(state = 'readonly')
+        except Tkinter.TclError:
+            self._messageBarEntry.configure(state = 'disabled')
+
+Pmw.forwardmethods(MessageBar, Tkinter.Entry, '_messageBarEntry')
diff --git a/Pmw/Pmw_1_2/lib/PmwMessageDialog.py b/Pmw/Pmw_1_2/lib/PmwMessageDialog.py
new file mode 100644 (file)
index 0000000..81621c0
--- /dev/null
@@ -0,0 +1,73 @@
+# Based on iwidgets2.2.0/messagedialog.itk code.
+
+import Tkinter
+import Pmw
+
+class MessageDialog(Pmw.Dialog):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderx',       20,    INITOPT),
+           ('bordery',       20,    INITOPT),
+           ('iconmargin',    20,    INITOPT),
+           ('iconpos',       None,  INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.Dialog.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       self._message = self.createcomponent('message',
+               (), None,
+               Tkinter.Label, (interior,))
+
+        iconpos = self['iconpos']
+       iconmargin = self['iconmargin']
+       borderx = self['borderx']
+       bordery = self['bordery']
+       border_right = 2
+       border_bottom = 2
+       if iconpos is None:
+           self._message.grid(column = 1, row = 1)
+       else:
+           self._icon = self.createcomponent('icon',
+                   (), None,
+                   Tkinter.Label, (interior,))
+           if iconpos not in 'nsew':
+               raise ValueError, \
+                   'bad iconpos option "%s":  should be n, s, e, or w' \
+                       % iconpos
+
+           if iconpos in 'nw':
+               icon = 1
+               message = 3
+           else:
+               icon = 3
+               message = 1
+
+           if iconpos in 'ns':
+               # vertical layout
+               self._icon.grid(column = 1, row = icon)
+               self._message.grid(column = 1, row = message)
+               interior.grid_rowconfigure(2, minsize = iconmargin)
+               border_bottom = 4
+           else:
+               # horizontal layout
+               self._icon.grid(column = icon, row = 1)
+               self._message.grid(column = message, row = 1)
+               interior.grid_columnconfigure(2, minsize = iconmargin)
+               border_right = 4
+
+       interior.grid_columnconfigure(0, minsize = borderx)
+       interior.grid_rowconfigure(0, minsize = bordery)
+       interior.grid_columnconfigure(border_right, minsize = borderx)
+       interior.grid_rowconfigure(border_bottom, minsize = bordery)
+
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
diff --git a/Pmw/Pmw_1_2/lib/PmwNoteBook.py b/Pmw/Pmw_1_2/lib/PmwNoteBook.py
new file mode 100644 (file)
index 0000000..300897c
--- /dev/null
@@ -0,0 +1,617 @@
+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')
diff --git a/Pmw/Pmw_1_2/lib/PmwOptionMenu.py b/Pmw/Pmw_1_2/lib/PmwOptionMenu.py
new file mode 100644 (file)
index 0000000..d540d32
--- /dev/null
@@ -0,0 +1,146 @@
+import types
+import Tkinter
+import Pmw
+
+class OptionMenu(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('command',        None,       None),
+            ('items',          (),         INITOPT),
+            ('initialitem',    None,       INITOPT),
+           ('labelmargin',    0,          INITOPT),
+           ('labelpos',       None,       INITOPT),
+           ('sticky',         'ew',       INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       self._menubutton = self.createcomponent('menubutton',
+               (), None,
+               Tkinter.Menubutton, (interior,),
+               borderwidth = 2,
+               indicatoron = 1,
+               relief = 'raised',
+               anchor = 'c',
+               highlightthickness = 2,
+               direction = 'flush',
+                takefocus = 1,
+       )
+       self._menubutton.grid(column = 2, row = 2, sticky = self['sticky'])
+
+       self._menu = self.createcomponent('menu',
+               (), None,
+               Tkinter.Menu, (self._menubutton,),
+               tearoff=0
+       )
+       self._menubutton.configure(menu = self._menu)
+
+       interior.grid_columnconfigure(2, weight = 1)
+       interior.grid_rowconfigure(2, weight = 1)
+
+        # Create the label.
+        self.createlabel(interior)
+
+        # Add the items specified by the initialisation option.
+       self._itemList = []
+        self.setitems(self['items'], self['initialitem'])
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def setitems(self, items, index = None):
+
+        # Clean up old items and callback commands.
+        for oldIndex in range(len(self._itemList)):
+            tclCommandName = str(self._menu.entrycget(oldIndex, 'command'))
+            if tclCommandName != '':   
+                self._menu.deletecommand(tclCommandName)
+        self._menu.delete(0, 'end')
+       self._itemList = list(items)
+
+       # Set the items in the menu component.
+        for item in items:
+            self._menu.add_command(label = item,
+               command = lambda self = self, item = item: self._invoke(item))
+
+       # Set the currently selected value.
+       if index is None:
+            var = str(self._menubutton.cget('textvariable'))
+           if var != '':
+               # None means do not change text variable.
+               return
+           if len(items) == 0:
+               text = ''
+           elif str(self._menubutton.cget('text')) in items:
+                # Do not change selection if it is still valid
+               return
+           else:
+               text = items[0]
+       else:
+           index = self.index(index)
+           text = self._itemList[index]
+
+        self.setvalue(text)
+
+    def getcurselection(self):
+       var = str(self._menubutton.cget('textvariable'))
+       if var == '':
+           return str(self._menubutton.cget('text'))
+       else:
+           return self._menu.tk.globalgetvar(var)
+
+    def getvalue(self):
+        return self.getcurselection()
+
+    def setvalue(self, text):
+       var = str(self._menubutton.cget('textvariable'))
+       if var == '':
+           self._menubutton.configure(text = text)
+       else:
+           self._menu.tk.globalsetvar(var, text)
+
+    def index(self, index):
+       listLength = len(self._itemList)
+       if type(index) == types.IntType:
+           if index < listLength:
+               return index
+           else:
+               raise ValueError, 'index "%s" is out of range' % index
+       elif index is Pmw.END:
+           if listLength > 0:
+               return listLength - 1
+           else:
+               raise ValueError, 'OptionMenu has no items'
+       else:
+           if index is Pmw.SELECT:
+               if listLength > 0:
+                   index = self.getcurselection()
+               else:
+                   raise ValueError, 'OptionMenu has no items'
+            if index in self._itemList:
+                return self._itemList.index(index)
+           raise ValueError, \
+                   'bad index "%s": must be a ' \
+                    'name, a number, Pmw.END or Pmw.SELECT' % (index,)
+
+    def invoke(self, index = Pmw.SELECT):
+       index = self.index(index)
+       text = self._itemList[index]
+
+        return self._invoke(text)
+
+    def _invoke(self, text):
+        self.setvalue(text)
+
+       command = self['command']
+       if callable(command):
+           return command(text)
diff --git a/Pmw/Pmw_1_2/lib/PmwPanedWidget.py b/Pmw/Pmw_1_2/lib/PmwPanedWidget.py
new file mode 100644 (file)
index 0000000..f71d0f6
--- /dev/null
@@ -0,0 +1,627 @@
+# PanedWidget
+# a frame which may contain several resizable sub-frames
+
+import string
+import sys
+import types
+import Tkinter
+import Pmw
+
+class PanedWidget(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+            ('command',            None,         None),
+            ('orient',             'vertical',   INITOPT),
+            ('separatorrelief',    'sunken',     INITOPT),
+            ('separatorthickness', 2,            INITOPT),
+            ('handlesize',         8,            INITOPT),
+            ('hull_width',         400,          None),
+            ('hull_height',        400,          None),
+       )
+       self.defineoptions(kw, optiondefs,
+                dynamicGroups = ('Frame', 'Separator', 'Handle'))
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       self.bind('<Configure>', self._handleConfigure)
+
+       if self['orient'] not in ('horizontal', 'vertical'):
+           raise ValueError, 'bad orient option ' + repr(self['orient']) + \
+               ': must be either \'horizontal\' or \'vertical\''
+
+        self._separatorThickness = self['separatorthickness']
+        self._handleSize = self['handlesize']
+       self._paneNames = []            # List of pane names
+       self._paneAttrs = {}            # Map from pane name to pane info
+
+       self._timerId = None
+       self._frame = {}
+       self._separator = []
+       self._button = []
+       self._totalSize = 0
+       self._movePending = 0
+       self._relsize = {}
+       self._relmin = {}
+       self._relmax = {}
+       self._size = {}
+       self._min = {}
+       self._max = {}
+       self._rootp = None
+       self._curSize = None
+       self._beforeLimit = None
+       self._afterLimit = None
+       self._buttonIsDown = 0
+       self._majorSize = 100
+       self._minorSize = 100
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def insert(self, name, before = 0, **kw):
+       # Parse <kw> for options.
+        self._initPaneOptions(name)
+       self._parsePaneOptions(name, kw)
+
+       insertPos = self._nameToIndex(before)
+       atEnd = (insertPos == len(self._paneNames))
+
+       # Add the frame.
+       self._paneNames[insertPos:insertPos] = [name]
+       self._frame[name] = self.createcomponent(name,
+               (), 'Frame',
+               Tkinter.Frame, (self.interior(),))
+
+       # Add separator, if necessary.
+       if len(self._paneNames) > 1:
+           self._addSeparator()
+       else:
+           self._separator.append(None)
+           self._button.append(None)
+
+       # Add the new frame and adjust the PanedWidget
+       if atEnd:
+           size = self._size[name]
+           if size > 0 or self._relsize[name] is not None:
+               if self['orient'] == 'vertical':
+                   self._frame[name].place(x=0, relwidth=1,
+                                           height=size, y=self._totalSize)
+               else:
+                   self._frame[name].place(y=0, relheight=1,
+                                           width=size, x=self._totalSize)
+           else:
+               if self['orient'] == 'vertical':
+                   self._frame[name].place(x=0, relwidth=1,
+                                           y=self._totalSize)
+               else:
+                   self._frame[name].place(y=0, relheight=1,
+                                           x=self._totalSize)
+       else:
+           self._updateSizes()
+
+       self._totalSize = self._totalSize + self._size[name]
+       return self._frame[name]
+
+    def add(self, name, **kw):
+        return apply(self.insert, (name, len(self._paneNames)), kw)
+
+    def delete(self, name):
+       deletePos = self._nameToIndex(name)
+       name = self._paneNames[deletePos]
+       self.destroycomponent(name)
+       del self._paneNames[deletePos]
+       del self._frame[name]
+       del self._size[name]
+       del self._min[name]
+       del self._max[name]
+       del self._relsize[name]
+       del self._relmin[name]
+       del self._relmax[name]
+
+       last = len(self._paneNames)
+       del self._separator[last]
+       del self._button[last]
+        if last > 0:
+            self.destroycomponent(self._sepName(last))
+            self.destroycomponent(self._buttonName(last))
+
+       self._plotHandles()
+
+    def setnaturalsize(self):
+        self.update_idletasks()
+        totalWidth = 0
+        totalHeight = 0
+        maxWidth = 0
+        maxHeight = 0
+       for name in self._paneNames:
+            frame = self._frame[name]
+            w = frame.winfo_reqwidth()
+            h = frame.winfo_reqheight()
+            totalWidth = totalWidth + w
+            totalHeight = totalHeight + h
+            if maxWidth < w:
+                maxWidth = w
+            if maxHeight < h:
+                maxHeight = h
+
+        # Note that, since the hull is a frame, the width and height
+        # options specify the geometry *outside* the borderwidth and
+        # highlightthickness.
+        bw = string.atoi(str(self.cget('hull_borderwidth')))
+        hl = string.atoi(str(self.cget('hull_highlightthickness')))
+        extra = (bw + hl) * 2
+        if str(self.cget('orient')) == 'horizontal':
+            totalWidth = totalWidth + extra
+            maxHeight = maxHeight + extra
+            self.configure(hull_width = totalWidth, hull_height = maxHeight)
+        else:
+            totalHeight = (totalHeight + extra +
+                    (len(self._paneNames) - 1) * self._separatorThickness)
+            maxWidth = maxWidth + extra
+            self.configure(hull_width = maxWidth, hull_height = totalHeight)
+
+    def move(self, name, newPos, newPosOffset = 0):
+
+        # see if we can spare ourselves some work
+        numPanes = len(self._paneNames)
+        if numPanes < 2:
+            return
+
+        newPos = self._nameToIndex(newPos) + newPosOffset
+        if newPos < 0 or newPos >=numPanes:
+            return
+
+        deletePos = self._nameToIndex(name)
+
+        if deletePos == newPos:
+            # inserting over ourself is a no-op
+            return
+
+        # delete name from old position in list
+        name = self._paneNames[deletePos]
+        del self._paneNames[deletePos]
+
+        # place in new position
+        self._paneNames[newPos:newPos] = [name]
+
+        # force everything to redraw
+        self._plotHandles()
+        self._updateSizes()
+
+    def _nameToIndex(self, nameOrIndex):
+       try:
+           pos = self._paneNames.index(nameOrIndex)
+       except ValueError:
+           pos = nameOrIndex
+
+       return pos
+
+    def _initPaneOptions(self, name):
+       # Set defaults.
+       self._size[name] = 0
+       self._relsize[name] = None
+       self._min[name] = 0
+       self._relmin[name] = None
+       self._max[name] = 100000
+       self._relmax[name] = None
+
+    def _parsePaneOptions(self, name, args):
+       # Parse <args> for options.
+       for arg, value in args.items():
+           if type(value) == types.FloatType:
+               relvalue = value
+               value = self._absSize(relvalue)
+           else:
+               relvalue = None
+
+           if arg == 'size':
+               self._size[name], self._relsize[name] = value, relvalue
+           elif arg == 'min':
+               self._min[name], self._relmin[name] = value, relvalue
+           elif arg == 'max':
+               self._max[name], self._relmax[name] = value, relvalue
+           else:
+               raise ValueError, 'keyword must be "size", "min", or "max"'
+
+    def _absSize(self, relvalue):
+       return int(round(relvalue * self._majorSize))
+
+    def _sepName(self, n):
+       return 'separator-%d' % n
+
+    def _buttonName(self, n):
+       return 'handle-%d' % n
+
+    def _addSeparator(self):
+       n = len(self._paneNames) - 1
+
+       downFunc = lambda event, s = self, num=n: s._btnDown(event, num)
+       upFunc = lambda event, s = self, num=n: s._btnUp(event, num)
+       moveFunc = lambda event, s = self, num=n: s._btnMove(event, num)
+
+       # Create the line dividing the panes.
+       sep = self.createcomponent(self._sepName(n),
+               (), 'Separator',
+               Tkinter.Frame, (self.interior(),),
+               borderwidth = 1,
+               relief = self['separatorrelief'])
+       self._separator.append(sep)
+
+       sep.bind('<ButtonPress-1>', downFunc)
+       sep.bind('<Any-ButtonRelease-1>', upFunc)
+       sep.bind('<B1-Motion>', moveFunc)
+
+       if self['orient'] == 'vertical':
+           cursor = 'sb_v_double_arrow'
+           sep.configure(height = self._separatorThickness,
+                    width = 10000, cursor = cursor)
+       else:
+           cursor = 'sb_h_double_arrow'
+           sep.configure(width = self._separatorThickness,
+                    height = 10000, cursor = cursor)
+
+       self._totalSize = self._totalSize + self._separatorThickness
+
+       # Create the handle on the dividing line.
+       handle = self.createcomponent(self._buttonName(n),
+               (), 'Handle',
+               Tkinter.Frame, (self.interior(),),
+                   relief = 'raised',
+                   borderwidth = 1,
+                   width = self._handleSize,
+                   height = self._handleSize,
+                   cursor = cursor,
+               )
+       self._button.append(handle)
+
+       handle.bind('<ButtonPress-1>', downFunc)
+       handle.bind('<Any-ButtonRelease-1>', upFunc)
+       handle.bind('<B1-Motion>', moveFunc)
+
+       self._plotHandles()
+
+       for i in range(1, len(self._paneNames)):
+           self._separator[i].tkraise()
+       for i in range(1, len(self._paneNames)):
+           self._button[i].tkraise()
+
+    def _btnUp(self, event, item):
+       self._buttonIsDown = 0
+       self._updateSizes()
+       try:
+           self._button[item].configure(relief='raised')
+       except:
+           pass
+
+    def _btnDown(self, event, item):
+       self._button[item].configure(relief='sunken')
+       self._getMotionLimit(item)
+       self._buttonIsDown = 1
+       self._movePending = 0
+
+    def _handleConfigure(self, event = None):
+       self._getNaturalSizes()
+       if self._totalSize == 0:
+           return
+
+       iterRange = list(self._paneNames)
+       iterRange.reverse()
+       if self._majorSize > self._totalSize:
+           n = self._majorSize - self._totalSize
+           self._iterate(iterRange, self._grow, n)
+       elif self._majorSize < self._totalSize:
+           n = self._totalSize - self._majorSize
+           self._iterate(iterRange, self._shrink, n)
+
+       self._plotHandles()
+       self._updateSizes()
+
+    def _getNaturalSizes(self):
+       # Must call this in order to get correct winfo_width, winfo_height
+       self.update_idletasks()
+
+       self._totalSize = 0
+
+       if self['orient'] == 'vertical':
+           self._majorSize = self.winfo_height()
+           self._minorSize = self.winfo_width()
+           majorspec = Tkinter.Frame.winfo_reqheight
+       else:
+           self._majorSize = self.winfo_width()
+           self._minorSize = self.winfo_height()
+           majorspec = Tkinter.Frame.winfo_reqwidth
+
+        bw = string.atoi(str(self.cget('hull_borderwidth')))
+        hl = string.atoi(str(self.cget('hull_highlightthickness')))
+        extra = (bw + hl) * 2
+        self._majorSize = self._majorSize - extra
+        self._minorSize = self._minorSize - extra
+
+       if self._majorSize < 0:
+           self._majorSize = 0
+       if self._minorSize < 0:
+           self._minorSize = 0
+
+       for name in self._paneNames:
+           # adjust the absolute sizes first...
+           if self._relsize[name] is None:
+               #special case
+               if self._size[name] == 0:
+                   self._size[name] = apply(majorspec, (self._frame[name],))
+                   self._setrel(name)
+           else:
+               self._size[name] = self._absSize(self._relsize[name])
+
+           if self._relmin[name] is not None:
+               self._min[name] = self._absSize(self._relmin[name])
+           if self._relmax[name] is not None:
+               self._max[name] = self._absSize(self._relmax[name])
+
+           # now adjust sizes
+           if self._size[name] < self._min[name]:
+               self._size[name] = self._min[name]
+               self._setrel(name)
+
+           if self._size[name] > self._max[name]:
+               self._size[name] = self._max[name]
+               self._setrel(name)
+
+           self._totalSize = self._totalSize + self._size[name]
+
+       # adjust for separators
+       self._totalSize = (self._totalSize +
+                (len(self._paneNames) - 1) * self._separatorThickness)
+
+    def _setrel(self, name):
+       if self._relsize[name] is not None:
+           if self._majorSize != 0:
+               self._relsize[name] = round(self._size[name]) / self._majorSize
+
+    def _iterate(self, names, proc, n):
+       for i in names:
+           n = apply(proc, (i, n))
+           if n == 0:
+               break
+
+    def _grow(self, name, n):
+       canGrow = self._max[name] - self._size[name]
+
+       if canGrow > n:
+           self._size[name] = self._size[name] + n
+           self._setrel(name)
+           return 0
+       elif canGrow > 0:
+           self._size[name] = self._max[name]
+           self._setrel(name)
+           n = n - canGrow
+
+       return n
+
+    def _shrink(self, name, n):
+       canShrink = self._size[name] - self._min[name]
+
+       if canShrink > n:
+           self._size[name] = self._size[name] - n
+           self._setrel(name)
+           return 0
+       elif canShrink > 0:
+           self._size[name] = self._min[name]
+           self._setrel(name)
+           n = n - canShrink
+
+       return n
+
+    def _updateSizes(self):
+       totalSize = 0
+
+       for name in self._paneNames:
+           size = self._size[name]
+           if self['orient'] == 'vertical':
+               self._frame[name].place(x = 0, relwidth = 1,
+                                       y = totalSize,
+                                       height = size)
+           else:
+               self._frame[name].place(y = 0, relheight = 1,
+                                       x = totalSize,
+                                       width = size)
+
+           totalSize = totalSize + size + self._separatorThickness
+
+       # Invoke the callback command
+       cmd = self['command']
+       if callable(cmd):
+           cmd(map(lambda x, s = self: s._size[x], self._paneNames))
+
+    def _plotHandles(self):
+       if len(self._paneNames) == 0:
+           return
+
+       if self['orient'] == 'vertical':
+           btnp = self._minorSize - 13
+       else:
+           h = self._minorSize
+
+           if h > 18:
+               btnp = 9
+           else:
+               btnp = h - 9
+
+       firstPane = self._paneNames[0]
+       totalSize = self._size[firstPane]
+
+       first = 1
+       last = len(self._paneNames) - 1
+
+       # loop from first to last, inclusive
+       for i in range(1, last + 1):
+
+           handlepos = totalSize - 3
+           prevSize = self._size[self._paneNames[i - 1]]
+           nextSize = self._size[self._paneNames[i]]
+
+           offset1 = 0
+
+           if i == first:
+               if prevSize < 4:
+                   offset1 = 4 - prevSize
+           else:
+               if prevSize < 8:
+                   offset1 = (8 - prevSize) / 2
+
+           offset2 = 0
+
+           if i == last:
+               if nextSize < 4:
+                   offset2 = nextSize - 4
+           else:
+               if nextSize < 8:
+                   offset2 = (nextSize - 8) / 2
+
+           handlepos = handlepos + offset1
+
+           if self['orient'] == 'vertical':
+               height = 8 - offset1 + offset2
+
+               if height > 1:
+                   self._button[i].configure(height = height)
+                   self._button[i].place(x = btnp, y = handlepos)
+               else:
+                   self._button[i].place_forget()
+
+               self._separator[i].place(x = 0, y = totalSize,
+                                        relwidth = 1)
+           else:
+               width = 8 - offset1 + offset2
+
+               if width > 1:
+                   self._button[i].configure(width = width)
+                   self._button[i].place(y = btnp, x = handlepos)
+               else:
+                   self._button[i].place_forget()
+
+               self._separator[i].place(y = 0, x = totalSize,
+                                        relheight = 1)
+
+           totalSize = totalSize + nextSize + self._separatorThickness
+
+    def pane(self, name):
+       return self._frame[self._paneNames[self._nameToIndex(name)]]
+
+    # Return the name of all panes
+    def panes(self):
+       return list(self._paneNames)
+
+    def configurepane(self, name, **kw):
+       name = self._paneNames[self._nameToIndex(name)]
+       self._parsePaneOptions(name, kw)
+       self._handleConfigure()
+
+    def updatelayout(self):
+       self._handleConfigure()
+
+    def _getMotionLimit(self, item):
+       curBefore = (item - 1) * self._separatorThickness
+       minBefore, maxBefore = curBefore, curBefore
+
+       for name in self._paneNames[:item]:
+           curBefore = curBefore + self._size[name]
+           minBefore = minBefore + self._min[name]
+           maxBefore = maxBefore + self._max[name]
+
+       curAfter = (len(self._paneNames) - item) * self._separatorThickness
+       minAfter, maxAfter = curAfter, curAfter
+       for name in self._paneNames[item:]:
+           curAfter = curAfter + self._size[name]
+           minAfter = minAfter + self._min[name]
+           maxAfter = maxAfter + self._max[name]
+
+       beforeToGo = min(curBefore - minBefore, maxAfter - curAfter)
+       afterToGo = min(curAfter - minAfter, maxBefore - curBefore)
+
+       self._beforeLimit = curBefore - beforeToGo
+       self._afterLimit = curBefore + afterToGo
+       self._curSize = curBefore
+
+       self._plotHandles()
+
+    # Compress the motion so that update is quick even on slow machines
+    #
+    # theRootp = root position (either rootx or rooty)
+    def _btnMove(self, event, item):
+       self._rootp = event
+
+       if self._movePending == 0:
+           self._timerId = self.after_idle(
+                   lambda s = self, i = item: s._btnMoveCompressed(i))
+           self._movePending = 1
+
+    def destroy(self):
+        if self._timerId is not None:
+          self.after_cancel(self._timerId)
+         self._timerId = None
+        Pmw.MegaWidget.destroy(self)
+
+    def _btnMoveCompressed(self, item):
+       if not self._buttonIsDown:
+           return
+
+       if self['orient'] == 'vertical':
+           p = self._rootp.y_root - self.winfo_rooty()
+       else:
+           p = self._rootp.x_root - self.winfo_rootx()
+
+       if p == self._curSize:
+           self._movePending = 0
+           return
+
+       if p < self._beforeLimit:
+           p = self._beforeLimit
+
+       if p >= self._afterLimit:
+           p = self._afterLimit
+
+       self._calculateChange(item, p)
+       self.update_idletasks()
+       self._movePending = 0
+
+    # Calculate the change in response to mouse motions
+    def _calculateChange(self, item, p):
+
+       if p < self._curSize:
+           self._moveBefore(item, p)
+       elif p > self._curSize:
+           self._moveAfter(item, p)
+
+       self._plotHandles()
+
+    def _moveBefore(self, item, p):
+       n = self._curSize - p
+
+       # Shrink the frames before
+       iterRange = list(self._paneNames[:item])
+       iterRange.reverse()
+       self._iterate(iterRange, self._shrink, n)
+
+       # Adjust the frames after
+       iterRange = self._paneNames[item:]
+       self._iterate(iterRange, self._grow, n)
+
+       self._curSize = p
+
+    def _moveAfter(self, item, p):
+       n = p - self._curSize
+
+       # Shrink the frames after
+       iterRange = self._paneNames[item:]
+       self._iterate(iterRange, self._shrink, n)
+
+       # Adjust the frames before
+       iterRange = list(self._paneNames[:item])
+       iterRange.reverse()
+       self._iterate(iterRange, self._grow, n)
+
+       self._curSize = p
diff --git a/Pmw/Pmw_1_2/lib/PmwPromptDialog.py b/Pmw/Pmw_1_2/lib/PmwPromptDialog.py
new file mode 100644 (file)
index 0000000..9c43919
--- /dev/null
@@ -0,0 +1,51 @@
+# Based on iwidgets2.2.0/promptdialog.itk code.
+
+import Pmw
+
+# A Dialog with an entryfield
+
+class PromptDialog(Pmw.Dialog):
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderx',     20,    INITOPT),
+           ('bordery',     20,    INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.Dialog.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       aliases = (
+           ('entry', 'entryfield_entry'),
+           ('label', 'entryfield_label'),
+       )
+       self._promptDialogEntry = self.createcomponent('entryfield',
+               aliases, None,
+               Pmw.EntryField, (interior,))
+       self._promptDialogEntry.pack(fill='x', expand=1,
+               padx = self['borderx'], pady = self['bordery'])
+       
+        if not kw.has_key('activatecommand'):
+            # Whenever this dialog is activated, set the focus to the
+            # EntryField's entry widget.
+            tkentry = self.component('entry')
+            self.configure(activatecommand = tkentry.focus_set)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    # Supply aliases to some of the entry component methods.
+    def insertentry(self, index, text):
+       self._promptDialogEntry.insert(index, text)
+
+    def deleteentry(self, first, last=None):
+       self._promptDialogEntry.delete(first, last)
+
+    def indexentry(self, index):
+       return self._promptDialogEntry.index(index)
+
+Pmw.forwardmethods(PromptDialog, Pmw.EntryField, '_promptDialogEntry')
diff --git a/Pmw/Pmw_1_2/lib/PmwRadioSelect.py b/Pmw/Pmw_1_2/lib/PmwRadioSelect.py
new file mode 100644 (file)
index 0000000..770fb3c
--- /dev/null
@@ -0,0 +1,234 @@
+import types
+import Tkinter
+import Pmw
+
+class RadioSelect(Pmw.MegaWidget):
+    # A collection of several buttons.  In single mode, only one
+    # button may be selected.  In multiple mode, any number of buttons
+    # may be selected.
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('buttontype',    'button',      INITOPT),
+           ('command',       None,          None),
+           ('labelmargin',   0,             INITOPT),
+           ('labelpos',      None,          INITOPT),
+           ('orient',       'horizontal',   INITOPT),
+           ('padx',          5,             INITOPT),
+           ('pady',          5,             INITOPT),
+           ('selectmode',    'single',      INITOPT),
+       )
+       self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',))
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       if self['labelpos'] is None:
+           self._radioSelectFrame = self._hull
+       else:
+           self._radioSelectFrame = self.createcomponent('frame',
+                   (), None,
+                   Tkinter.Frame, (interior,))
+           self._radioSelectFrame.grid(column=2, row=2, sticky='nsew')
+           interior.grid_columnconfigure(2, weight=1)
+           interior.grid_rowconfigure(2, weight=1)
+
+           self.createlabel(interior)
+
+       # Initialise instance variables.
+       self._buttonList = []
+       if self['selectmode'] == 'single':
+           self._singleSelect = 1
+       elif self['selectmode'] == 'multiple':
+           self._singleSelect = 0
+       else: 
+           raise ValueError, 'bad selectmode option "' + \
+                   self['selectmode'] + '": should be single or multiple'
+
+       if self['buttontype'] == 'button':
+           self.buttonClass = Tkinter.Button
+       elif self['buttontype'] == 'radiobutton':
+           self._singleSelect = 1
+           self.var = Tkinter.StringVar()
+           self.buttonClass = Tkinter.Radiobutton
+       elif self['buttontype'] == 'checkbutton':
+           self._singleSelect = 0
+           self.buttonClass = Tkinter.Checkbutton
+       else:
+           raise ValueError, 'bad buttontype option "' + \
+                   self['buttontype'] + \
+                   '": should be button, radiobutton or checkbutton'
+
+       if self._singleSelect:
+           self.selection = None
+       else:
+           self.selection = []
+
+       if self['orient'] not in ('horizontal', 'vertical'):
+           raise ValueError, 'bad orient option ' + repr(self['orient']) + \
+               ': must be either \'horizontal\' or \'vertical\''
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def getcurselection(self):
+       if self._singleSelect:
+            return self.selection
+        else:
+            return tuple(self.selection)
+
+    def getvalue(self):
+        return self.getcurselection()
+
+    def setvalue(self, textOrList):
+       if self._singleSelect:
+            self.__setSingleValue(textOrList)
+        else:
+           # Multiple selections
+            oldselection = self.selection
+            self.selection = textOrList
+            for button in self._buttonList:
+                if button in oldselection:
+                    if button not in self.selection:
+                        # button is currently selected but should not be
+                        widget = self.component(button)
+                        if self['buttontype'] == 'checkbutton':
+                            widget.deselect()
+                        else:  # Button
+                            widget.configure(relief='raised')
+                else:
+                    if button in self.selection:
+                        # button is not currently selected but should be
+                        widget = self.component(button)
+                        if self['buttontype'] == 'checkbutton':
+                            widget.select()
+                        else:  # Button
+                            widget.configure(relief='sunken')
+
+    def numbuttons(self):
+        return len(self._buttonList)
+
+    def index(self, index):
+       # Return the integer index of the button with the given index.
+
+       listLength = len(self._buttonList)
+       if type(index) == types.IntType:
+           if index < listLength:
+               return index
+           else:
+               raise ValueError, 'index "%s" is out of range' % index
+       elif index is Pmw.END:
+           if listLength > 0:
+               return listLength - 1
+           else:
+               raise ValueError, 'RadioSelect has no buttons'
+       else:
+           for count in range(listLength):
+               name = self._buttonList[count]
+               if index == name:
+                   return count
+           validValues = 'a name, a number or Pmw.END'
+           raise ValueError, \
+                   'bad index "%s": must be %s' % (index, validValues)
+
+    def button(self, buttonIndex):
+       name = self._buttonList[self.index(buttonIndex)]
+        return self.component(name)
+
+    def add(self, componentName, **kw):
+       if componentName in self._buttonList:
+           raise ValueError, 'button "%s" already exists' % componentName
+
+       kw['command'] = \
+                lambda self=self, name=componentName: self.invoke(name)
+       if not kw.has_key('text'):
+           kw['text'] = componentName
+
+       if self['buttontype'] == 'radiobutton':
+           if not kw.has_key('anchor'):
+               kw['anchor'] = 'w'
+           if not kw.has_key('variable'):
+               kw['variable'] = self.var
+           if not kw.has_key('value'):
+               kw['value'] = kw['text']
+       elif self['buttontype'] == 'checkbutton':
+           if not kw.has_key('anchor'):
+               kw['anchor'] = 'w'
+
+       button = apply(self.createcomponent, (componentName,
+               (), 'Button',
+               self.buttonClass, (self._radioSelectFrame,)), kw)
+
+       if self['orient'] == 'horizontal':
+           self._radioSelectFrame.grid_rowconfigure(0, weight=1)
+           col = len(self._buttonList)
+           button.grid(column=col, row=0, padx = self['padx'],
+                   pady = self['pady'], sticky='nsew')
+           self._radioSelectFrame.grid_columnconfigure(col, weight=1)
+       else:
+           self._radioSelectFrame.grid_columnconfigure(0, weight=1)
+           row = len(self._buttonList)
+           button.grid(column=0, row=row, padx = self['padx'],
+                   pady = self['pady'], sticky='ew')
+           self._radioSelectFrame.grid_rowconfigure(row, weight=1)
+
+       self._buttonList.append(componentName)
+       return button
+
+    def deleteall(self):
+       for name in self._buttonList:
+           self.destroycomponent(name)
+       self._buttonList = []
+       if self._singleSelect:
+           self.selection = None
+       else: 
+           self.selection = []
+
+    def __setSingleValue(self, value):
+            self.selection = value
+            if self['buttontype'] == 'radiobutton':
+                widget = self.component(value)
+                widget.select()
+            else:  # Button
+                for button in self._buttonList:
+                    widget = self.component(button)
+                    if button == value:
+                        widget.configure(relief='sunken')
+                    else:
+                        widget.configure(relief='raised')
+
+    def invoke(self, index):
+       index = self.index(index)
+       name = self._buttonList[index]
+
+       if self._singleSelect:
+            self.__setSingleValue(name)
+           command = self['command']
+           if callable(command):
+               return command(name)
+        else:
+           # Multiple selections
+           widget = self.component(name)
+           if name in self.selection:
+               if self['buttontype'] == 'checkbutton':
+                   widget.deselect()
+               else:
+                   widget.configure(relief='raised')
+               self.selection.remove(name)
+               state = 0
+           else:
+               if self['buttontype'] == 'checkbutton':
+                   widget.select()
+               else:
+                   widget.configure(relief='sunken')
+               self.selection.append(name)
+               state = 1
+
+           command = self['command']
+           if callable(command):
+             return command(name, state)
diff --git a/Pmw/Pmw_1_2/lib/PmwScrolledCanvas.py b/Pmw/Pmw_1_2/lib/PmwScrolledCanvas.py
new file mode 100644 (file)
index 0000000..8ab8023
--- /dev/null
@@ -0,0 +1,289 @@
+import Tkinter
+import Pmw
+
+class ScrolledCanvas(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderframe',    0,            INITOPT),
+           ('canvasmargin',   0,            INITOPT),
+           ('hscrollmode',    'dynamic',    self._hscrollMode),
+           ('labelmargin',    0,            INITOPT),
+           ('labelpos',       None,         INITOPT),
+           ('scrollmargin',   2,            INITOPT),
+           ('usehullsize',    0,            INITOPT),
+           ('vscrollmode',    'dynamic',    self._vscrollMode),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       self.origInterior = Pmw.MegaWidget.interior(self)
+
+       if self['usehullsize']:
+           self.origInterior.grid_propagate(0)
+
+       if self['borderframe']:
+           # Create a frame widget to act as the border of the canvas. 
+           self._borderframe = self.createcomponent('borderframe',
+                   (), None,
+                   Tkinter.Frame, (self.origInterior,),
+                   relief = 'sunken',
+                   borderwidth = 2,
+           )
+           self._borderframe.grid(row = 2, column = 2, sticky = 'news')
+
+           # Create the canvas widget.
+           self._canvas = self.createcomponent('canvas',
+                   (), None,
+                   Tkinter.Canvas, (self._borderframe,),
+                   highlightthickness = 0,
+                   borderwidth = 0,
+           )
+           self._canvas.pack(fill = 'both', expand = 1)
+       else:
+           # Create the canvas widget.
+           self._canvas = self.createcomponent('canvas',
+                   (), None,
+                   Tkinter.Canvas, (self.origInterior,),
+                   relief = 'sunken',
+                   borderwidth = 2,
+           )
+           self._canvas.grid(row = 2, column = 2, sticky = 'news')
+
+       self.origInterior.grid_rowconfigure(2, weight = 1, minsize = 0)
+       self.origInterior.grid_columnconfigure(2, weight = 1, minsize = 0)
+       
+       # Create the horizontal scrollbar
+       self._horizScrollbar = self.createcomponent('horizscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (self.origInterior,),
+               orient='horizontal',
+               command=self._canvas.xview
+       )
+
+       # Create the vertical scrollbar
+       self._vertScrollbar = self.createcomponent('vertscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (self.origInterior,),
+               orient='vertical',
+               command=self._canvas.yview
+       )
+
+       self.createlabel(self.origInterior, childCols = 3, childRows = 3)
+
+       # Initialise instance variables.
+       self._horizScrollbarOn = 0
+       self._vertScrollbarOn = 0
+       self.scrollTimer = None
+        self._scrollRecurse = 0
+       self._horizScrollbarNeeded = 0
+       self._vertScrollbarNeeded = 0
+       self.setregionTimer = None
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self.scrollTimer is not None:
+           self.after_cancel(self.scrollTimer)
+           self.scrollTimer = None
+       if self.setregionTimer is not None:
+           self.after_cancel(self.setregionTimer)
+           self.setregionTimer = None
+       Pmw.MegaWidget.destroy(self)
+
+    # ======================================================================
+
+    # Public methods.
+
+    def interior(self):
+       return self._canvas
+
+    def resizescrollregion(self):
+       if self.setregionTimer is None:
+           self.setregionTimer = self.after_idle(self._setRegion)
+
+    # ======================================================================
+
+    # Configuration methods.
+
+    def _hscrollMode(self):
+       # The horizontal scroll mode has been configured.
+
+       mode = self['hscrollmode']
+
+       if mode == 'static':
+           if not self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'none':
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       else:
+           message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+        self._configureScrollCommands()
+
+    def _vscrollMode(self):
+       # The vertical scroll mode has been configured.
+
+       mode = self['vscrollmode']
+
+       if mode == 'static':
+           if not self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'none':
+           if self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       else:
+           message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+        self._configureScrollCommands()
+
+    # ======================================================================
+
+    # Private methods.
+
+    def _configureScrollCommands(self):
+        # If both scrollmodes are not dynamic we can save a lot of
+        # time by not having to create an idle job to handle the
+        # scroll commands.
+
+        # Clean up previous scroll commands to prevent memory leak.
+        tclCommandName = str(self._canvas.cget('xscrollcommand'))
+        if tclCommandName != '':   
+            self._canvas.deletecommand(tclCommandName)
+        tclCommandName = str(self._canvas.cget('yscrollcommand'))
+        if tclCommandName != '':   
+            self._canvas.deletecommand(tclCommandName)
+
+       if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
+            self._canvas.configure(
+                    xscrollcommand=self._scrollBothLater,
+                    yscrollcommand=self._scrollBothLater
+            )
+        else:
+            self._canvas.configure(
+                    xscrollcommand=self._scrollXNow,
+                    yscrollcommand=self._scrollYNow
+            )
+
+    def _scrollXNow(self, first, last):
+        self._horizScrollbar.set(first, last)
+        self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
+
+       if self['hscrollmode'] == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+
+    def _scrollYNow(self, first, last):
+        self._vertScrollbar.set(first, last)
+        self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
+
+        if self['vscrollmode'] == 'dynamic':
+            if self._vertScrollbarNeeded != self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+
+    def _scrollBothLater(self, first, last):
+       # Called by the canvas to set the horizontal or vertical
+       # scrollbar when it has scrolled or changed scrollregion.
+
+       if self.scrollTimer is None:
+           self.scrollTimer = self.after_idle(self._scrollBothNow)
+
+    def _scrollBothNow(self):
+        # This performs the function of _scrollXNow and _scrollYNow.
+        # If one is changed, the other should be updated to match.
+       self.scrollTimer = None
+
+        # Call update_idletasks to make sure that the containing frame
+        # has been resized before we attempt to set the scrollbars. 
+        # Otherwise the scrollbars may be mapped/unmapped continuously.
+        self._scrollRecurse = self._scrollRecurse + 1
+        self.update_idletasks()
+        self._scrollRecurse = self._scrollRecurse - 1
+        if self._scrollRecurse != 0:
+            return
+
+       xview = self._canvas.xview()
+       yview = self._canvas.yview()
+       self._horizScrollbar.set(xview[0], xview[1])
+       self._vertScrollbar.set(yview[0], yview[1])
+
+       self._horizScrollbarNeeded = (xview != (0.0, 1.0))
+       self._vertScrollbarNeeded = (yview != (0.0, 1.0))
+
+       # If both horizontal and vertical scrollmodes are dynamic and
+       # currently only one scrollbar is mapped and both should be
+       # toggled, then unmap the mapped scrollbar.  This prevents a
+       # continuous mapping and unmapping of the scrollbars. 
+       if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
+               self._horizScrollbarNeeded != self._horizScrollbarOn and
+               self._vertScrollbarNeeded != self._vertScrollbarOn and
+               self._vertScrollbarOn != self._horizScrollbarOn):
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+           else:
+               self._toggleVertScrollbar()
+           return
+
+       if self['hscrollmode'] == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+
+       if self['vscrollmode'] == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+
+    def _toggleHorizScrollbar(self):
+
+       self._horizScrollbarOn = not self._horizScrollbarOn
+
+       interior = self.origInterior
+       if self._horizScrollbarOn:
+           self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
+           interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
+       else:
+           self._horizScrollbar.grid_forget()
+           interior.grid_rowconfigure(3, minsize = 0)
+
+    def _toggleVertScrollbar(self):
+
+       self._vertScrollbarOn = not self._vertScrollbarOn
+
+       interior = self.origInterior
+       if self._vertScrollbarOn:
+           self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
+           interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
+       else:
+           self._vertScrollbar.grid_forget()
+           interior.grid_columnconfigure(3, minsize = 0)
+
+    def _setRegion(self):
+       self.setregionTimer = None
+
+       region = self._canvas.bbox('all')
+        if region is not None:
+           canvasmargin = self['canvasmargin']
+           region = (region[0] - canvasmargin, region[1] - canvasmargin,
+               region[2] + canvasmargin, region[3] + canvasmargin)
+           self._canvas.configure(scrollregion = region)
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Frame.Grid.
+    def bbox(self, *args):
+       return apply(self._canvas.bbox, args)
+
+Pmw.forwardmethods(ScrolledCanvas, Tkinter.Canvas, '_canvas')
diff --git a/Pmw/Pmw_1_2/lib/PmwScrolledField.py b/Pmw/Pmw_1_2/lib/PmwScrolledField.py
new file mode 100644 (file)
index 0000000..16eedca
--- /dev/null
@@ -0,0 +1,53 @@
+import Tkinter
+import Pmw
+
+class ScrolledField(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('labelmargin',   0,      INITOPT),
+           ('labelpos',      None,   INITOPT),
+           ('sticky',        'ew',   INITOPT),
+           ('text',          '',     self._text),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       self._scrolledFieldEntry = self.createcomponent('entry',
+               (), None,
+               Tkinter.Entry, (interior,))
+
+        # Can't always use 'disabled', since this greys out text in Tk 8.4.2
+        try:
+            self._scrolledFieldEntry.configure(state = 'readonly')
+        except Tkinter.TclError:
+            self._scrolledFieldEntry.configure(state = 'disabled')
+
+       self._scrolledFieldEntry.grid(column=2, row=2, sticky=self['sticky'])
+       interior.grid_columnconfigure(2, weight=1)
+       interior.grid_rowconfigure(2, weight=1)
+
+       self.createlabel(interior)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _text(self):
+        text = self['text']
+        self._scrolledFieldEntry.configure(state = 'normal')
+        self._scrolledFieldEntry.delete(0, 'end')
+        self._scrolledFieldEntry.insert('end', text)
+
+        # Can't always use 'disabled', since this greys out text in Tk 8.4.2
+        try:
+            self._scrolledFieldEntry.configure(state = 'readonly')
+        except Tkinter.TclError:
+            self._scrolledFieldEntry.configure(state = 'disabled')
+
+Pmw.forwardmethods(ScrolledField, Tkinter.Entry, '_scrolledFieldEntry')
diff --git a/Pmw/Pmw_1_2/lib/PmwScrolledFrame.py b/Pmw/Pmw_1_2/lib/PmwScrolledFrame.py
new file mode 100644 (file)
index 0000000..dcca4ff
--- /dev/null
@@ -0,0 +1,395 @@
+import string
+import types
+import Tkinter
+import Pmw
+
+class ScrolledFrame(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderframe',    1,            INITOPT),
+           ('horizflex',      'fixed',      self._horizflex),
+           ('horizfraction',  0.05,         INITOPT),
+           ('hscrollmode',    'dynamic',    self._hscrollMode),
+           ('labelmargin',    0,            INITOPT),
+           ('labelpos',       None,         INITOPT),
+           ('scrollmargin',   2,            INITOPT),
+           ('usehullsize',    0,            INITOPT),
+           ('vertflex',       'fixed',      self._vertflex),
+           ('vertfraction',   0.05,         INITOPT),
+           ('vscrollmode',    'dynamic',    self._vscrollMode),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       self.origInterior = Pmw.MegaWidget.interior(self)
+
+       if self['usehullsize']:
+           self.origInterior.grid_propagate(0)
+
+       if self['borderframe']:
+           # Create a frame widget to act as the border of the clipper. 
+           self._borderframe = self.createcomponent('borderframe',
+                   (), None,
+                   Tkinter.Frame, (self.origInterior,),
+                   relief = 'sunken',
+                   borderwidth = 2,
+           )
+           self._borderframe.grid(row = 2, column = 2, sticky = 'news')
+
+           # Create the clipping window.
+           self._clipper = self.createcomponent('clipper',
+                   (), None,
+                   Tkinter.Frame, (self._borderframe,),
+                   width = 400,
+                   height = 300,
+                   highlightthickness = 0,
+                   borderwidth = 0,
+           )
+           self._clipper.pack(fill = 'both', expand = 1)
+       else:
+           # Create the clipping window.
+           self._clipper = self.createcomponent('clipper',
+                   (), None,
+                   Tkinter.Frame, (self.origInterior,),
+                   width = 400,
+                   height = 300,
+                   relief = 'sunken',
+                   borderwidth = 2,
+           )
+           self._clipper.grid(row = 2, column = 2, sticky = 'news')
+
+       self.origInterior.grid_rowconfigure(2, weight = 1, minsize = 0)
+       self.origInterior.grid_columnconfigure(2, weight = 1, minsize = 0)
+       
+       # Create the horizontal scrollbar
+       self._horizScrollbar = self.createcomponent('horizscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (self.origInterior,),
+               orient='horizontal',
+               command=self.xview
+       )
+
+       # Create the vertical scrollbar
+       self._vertScrollbar = self.createcomponent('vertscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (self.origInterior,),
+               orient='vertical',
+               command=self.yview
+       )
+
+       self.createlabel(self.origInterior, childCols = 3, childRows = 3)
+
+       # Initialise instance variables.
+       self._horizScrollbarOn = 0
+       self._vertScrollbarOn = 0
+       self.scrollTimer = None
+       self._scrollRecurse = 0
+       self._horizScrollbarNeeded = 0
+       self._vertScrollbarNeeded = 0
+       self.startX = 0
+       self.startY = 0
+       self._flexoptions = ('fixed', 'expand', 'shrink', 'elastic')
+
+       # Create a frame in the clipper to contain the widgets to be
+       # scrolled.
+       self._frame = self.createcomponent('frame',
+               (), None,
+               Tkinter.Frame, (self._clipper,)
+       )
+
+       # Whenever the clipping window or scrolled frame change size,
+       # update the scrollbars.
+       self._frame.bind('<Configure>', self._reposition)
+       self._clipper.bind('<Configure>', self._reposition)
+
+        # Work around a bug in Tk where the value returned by the
+        # scrollbar get() method is (0.0, 0.0, 0.0, 0.0) rather than
+        # the expected 2-tuple.  This occurs if xview() is called soon
+        # after the Pmw.ScrolledFrame has been created.
+        self._horizScrollbar.set(0.0, 1.0)
+        self._vertScrollbar.set(0.0, 1.0)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self.scrollTimer is not None:
+           self.after_cancel(self.scrollTimer)
+           self.scrollTimer = None
+       Pmw.MegaWidget.destroy(self)
+
+    # ======================================================================
+
+    # Public methods.
+
+    def interior(self):
+       return self._frame
+
+    # Set timer to call real reposition method, so that it is not
+    # called multiple times when many things are reconfigured at the
+    # same time.
+    def reposition(self):
+       if self.scrollTimer is None:
+           self.scrollTimer = self.after_idle(self._scrollBothNow)
+
+    # Called when the user clicks in the horizontal scrollbar. 
+    # Calculates new position of frame then calls reposition() to
+    # update the frame and the scrollbar.
+    def xview(self, mode = None, value = None, units = None):
+
+        if type(value) == types.StringType:
+            value = string.atof(value)
+        if mode is None:
+            return self._horizScrollbar.get()
+       elif mode == 'moveto':
+           frameWidth = self._frame.winfo_reqwidth()
+           self.startX = value * float(frameWidth)
+       else: # mode == 'scroll'
+           clipperWidth = self._clipper.winfo_width()
+           if units == 'units':
+               jump = int(clipperWidth * self['horizfraction'])
+           else:
+               jump = clipperWidth
+            self.startX = self.startX + value * jump
+
+       self.reposition()
+
+    # Called when the user clicks in the vertical scrollbar. 
+    # Calculates new position of frame then calls reposition() to
+    # update the frame and the scrollbar.
+    def yview(self, mode = None, value = None, units = None):
+
+        if type(value) == types.StringType:
+            value = string.atof(value)
+        if mode is None:
+            return self._vertScrollbar.get()
+       elif mode == 'moveto':
+           frameHeight = self._frame.winfo_reqheight()
+           self.startY = value * float(frameHeight)
+       else: # mode == 'scroll'
+           clipperHeight = self._clipper.winfo_height()
+           if units == 'units':
+               jump = int(clipperHeight * self['vertfraction'])
+           else:
+               jump = clipperHeight
+            self.startY = self.startY + value * jump
+
+       self.reposition()
+
+    # ======================================================================
+
+    # Configuration methods.
+
+    def _hscrollMode(self):
+       # The horizontal scroll mode has been configured.
+
+       mode = self['hscrollmode']
+
+       if mode == 'static':
+           if not self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'none':
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       else:
+           message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+    def _vscrollMode(self):
+       # The vertical scroll mode has been configured.
+
+       mode = self['vscrollmode']
+
+       if mode == 'static':
+           if not self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'none':
+           if self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       else:
+           message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+    def _horizflex(self):
+       # The horizontal flex mode has been configured.
+
+       flex = self['horizflex']
+
+       if flex not in self._flexoptions:
+           message = 'bad horizflex option "%s": should be one of %s' % \
+                   (flex, str(self._flexoptions))
+           raise ValueError, message
+
+       self.reposition()
+
+    def _vertflex(self):
+       # The vertical flex mode has been configured.
+
+       flex = self['vertflex']
+
+       if flex not in self._flexoptions:
+           message = 'bad vertflex option "%s": should be one of %s' % \
+                   (flex, str(self._flexoptions))
+           raise ValueError, message
+
+       self.reposition()
+
+    # ======================================================================
+
+    # Private methods.
+
+    def _reposition(self, event):
+       self.reposition()
+
+    def _getxview(self):
+
+       # Horizontal dimension.
+       clipperWidth = self._clipper.winfo_width()
+       frameWidth = self._frame.winfo_reqwidth()
+       if frameWidth <= clipperWidth:
+           # The scrolled frame is smaller than the clipping window.
+
+           self.startX = 0
+           endScrollX = 1.0
+
+           if self['horizflex'] in ('expand', 'elastic'):
+               relwidth = 1
+           else:
+               relwidth = ''
+       else:
+           # The scrolled frame is larger than the clipping window.
+
+           if self['horizflex'] in ('shrink', 'elastic'):
+               self.startX = 0
+               endScrollX = 1.0
+               relwidth = 1
+           else:
+               if self.startX + clipperWidth > frameWidth:
+                   self.startX = frameWidth - clipperWidth
+                   endScrollX = 1.0
+               else:
+                   if self.startX < 0:
+                       self.startX = 0
+                   endScrollX = (self.startX + clipperWidth) / float(frameWidth)
+               relwidth = ''
+
+       # Position frame relative to clipper.
+       self._frame.place(x = -self.startX, relwidth = relwidth)
+       return (self.startX / float(frameWidth), endScrollX)
+
+    def _getyview(self):
+
+       # Vertical dimension.
+       clipperHeight = self._clipper.winfo_height()
+       frameHeight = self._frame.winfo_reqheight()
+       if frameHeight <= clipperHeight:
+           # The scrolled frame is smaller than the clipping window.
+
+           self.startY = 0
+           endScrollY = 1.0
+
+           if self['vertflex'] in ('expand', 'elastic'):
+               relheight = 1
+           else:
+               relheight = ''
+       else:
+           # The scrolled frame is larger than the clipping window.
+
+           if self['vertflex'] in ('shrink', 'elastic'):
+               self.startY = 0
+               endScrollY = 1.0
+               relheight = 1
+           else:
+               if self.startY + clipperHeight > frameHeight:
+                   self.startY = frameHeight - clipperHeight
+                   endScrollY = 1.0
+               else:
+                   if self.startY < 0:
+                       self.startY = 0
+                   endScrollY = (self.startY + clipperHeight) / float(frameHeight)
+               relheight = ''
+
+       # Position frame relative to clipper.
+       self._frame.place(y = -self.startY, relheight = relheight)
+       return (self.startY / float(frameHeight), endScrollY)
+
+    # According to the relative geometries of the frame and the
+    # clipper, reposition the frame within the clipper and reset the
+    # scrollbars.
+    def _scrollBothNow(self):
+       self.scrollTimer = None
+
+        # Call update_idletasks to make sure that the containing frame
+        # has been resized before we attempt to set the scrollbars. 
+        # Otherwise the scrollbars may be mapped/unmapped continuously.
+        self._scrollRecurse = self._scrollRecurse + 1
+        self.update_idletasks()
+        self._scrollRecurse = self._scrollRecurse - 1
+        if self._scrollRecurse != 0:
+            return
+
+       xview = self._getxview()
+       yview = self._getyview()
+       self._horizScrollbar.set(xview[0], xview[1])
+       self._vertScrollbar.set(yview[0], yview[1])
+
+       self._horizScrollbarNeeded = (xview != (0.0, 1.0))
+       self._vertScrollbarNeeded = (yview != (0.0, 1.0))
+
+       # If both horizontal and vertical scrollmodes are dynamic and
+       # currently only one scrollbar is mapped and both should be
+       # toggled, then unmap the mapped scrollbar.  This prevents a
+       # continuous mapping and unmapping of the scrollbars. 
+       if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
+               self._horizScrollbarNeeded != self._horizScrollbarOn and
+               self._vertScrollbarNeeded != self._vertScrollbarOn and
+               self._vertScrollbarOn != self._horizScrollbarOn):
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+           else:
+               self._toggleVertScrollbar()
+           return
+
+       if self['hscrollmode'] == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+
+       if self['vscrollmode'] == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+
+    def _toggleHorizScrollbar(self):
+
+       self._horizScrollbarOn = not self._horizScrollbarOn
+
+       interior = self.origInterior
+       if self._horizScrollbarOn:
+           self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
+           interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
+       else:
+           self._horizScrollbar.grid_forget()
+           interior.grid_rowconfigure(3, minsize = 0)
+
+    def _toggleVertScrollbar(self):
+
+       self._vertScrollbarOn = not self._vertScrollbarOn
+
+       interior = self.origInterior
+       if self._vertScrollbarOn:
+           self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
+           interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
+       else:
+           self._vertScrollbar.grid_forget()
+           interior.grid_columnconfigure(3, minsize = 0)
diff --git a/Pmw/Pmw_1_2/lib/PmwScrolledListBox.py b/Pmw/Pmw_1_2/lib/PmwScrolledListBox.py
new file mode 100644 (file)
index 0000000..12e3d5e
--- /dev/null
@@ -0,0 +1,376 @@
+# Based on iwidgets2.2.0/scrolledlistbox.itk code.
+
+import types
+import Tkinter
+import Pmw
+
+class ScrolledListBox(Pmw.MegaWidget):
+    _classBindingsDefinedFor = 0
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('dblclickcommand',    None,            None),
+           ('hscrollmode',        'dynamic',       self._hscrollMode),
+           ('items',              (),              INITOPT),
+           ('labelmargin',        0,               INITOPT),
+           ('labelpos',           None,            INITOPT),
+           ('scrollmargin',       2,               INITOPT),
+           ('selectioncommand',   None,            None),
+           ('usehullsize',        0,               INITOPT),
+           ('vscrollmode',        'dynamic',       self._vscrollMode),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       if self['usehullsize']:
+           interior.grid_propagate(0)
+
+       # Create the listbox widget.
+       self._listbox = self.createcomponent('listbox',
+               (), None,
+               Tkinter.Listbox, (interior,))
+       self._listbox.grid(row = 2, column = 2, sticky = 'news')
+       interior.grid_rowconfigure(2, weight = 1, minsize = 0)
+       interior.grid_columnconfigure(2, weight = 1, minsize = 0)
+
+       # Create the horizontal scrollbar
+       self._horizScrollbar = self.createcomponent('horizscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (interior,),
+               orient='horizontal',
+               command=self._listbox.xview
+       )
+
+       # Create the vertical scrollbar
+       self._vertScrollbar = self.createcomponent('vertscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (interior,),
+               orient='vertical',
+               command=self._listbox.yview
+       )
+
+       self.createlabel(interior, childCols = 3, childRows = 3)
+
+       # Add the items specified by the initialisation option.
+       items = self['items']
+       if type(items) != types.TupleType:
+           items = tuple(items)
+       if len(items) > 0:
+           apply(self._listbox.insert, ('end',) + items)
+
+       _registerScrolledList(self._listbox, self)
+
+        # Establish the special class bindings if not already done.
+        # Also create bindings if the Tkinter default interpreter has
+        # changed.  Use Tkinter._default_root to create class
+        # bindings, so that a reference to root is created by
+        # bind_class rather than a reference to self, which would
+        # prevent object cleanup.
+        theTag = 'ScrolledListBoxTag'
+        if ScrolledListBox._classBindingsDefinedFor != Tkinter._default_root:
+            root  = Tkinter._default_root
+                   
+            def doubleEvent(event):
+                _handleEvent(event, 'double')
+            def keyEvent(event):
+                _handleEvent(event, 'key')
+            def releaseEvent(event):
+                _handleEvent(event, 'release')
+
+            # Bind space and return keys and button 1 to the selectioncommand.
+            root.bind_class(theTag, '<Key-space>', keyEvent)
+            root.bind_class(theTag, '<Key-Return>', keyEvent)
+            root.bind_class(theTag, '<ButtonRelease-1>', releaseEvent)
+
+            # Bind double button 1 click to the dblclickcommand.
+            root.bind_class(theTag, '<Double-ButtonRelease-1>', doubleEvent)
+
+           ScrolledListBox._classBindingsDefinedFor = root
+
+       bindtags = self._listbox.bindtags()
+       self._listbox.bindtags(bindtags + (theTag,))
+
+       # Initialise instance variables.
+       self._horizScrollbarOn = 0
+       self._vertScrollbarOn = 0
+       self.scrollTimer = None
+        self._scrollRecurse = 0
+       self._horizScrollbarNeeded = 0
+       self._vertScrollbarNeeded = 0
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self.scrollTimer is not None:
+           self.after_cancel(self.scrollTimer)
+           self.scrollTimer = None
+       _deregisterScrolledList(self._listbox)
+       Pmw.MegaWidget.destroy(self)
+
+    # ======================================================================
+
+    # Public methods.
+
+    def clear(self):
+       self.setlist(())
+
+    def getcurselection(self):
+       rtn = []
+       for sel in self.curselection():
+           rtn.append(self._listbox.get(sel))
+       return tuple(rtn)
+
+    def getvalue(self):
+        return self.getcurselection()
+
+    def setvalue(self, textOrList):
+        self._listbox.selection_clear(0, 'end')
+        listitems = list(self._listbox.get(0, 'end'))
+        if type(textOrList) == types.StringType:
+            if textOrList in listitems:
+                self._listbox.selection_set(listitems.index(textOrList))
+            else:
+                raise ValueError, 'no such item "%s"' % textOrList
+        else:
+            for item in textOrList:
+                if item in listitems:
+                    self._listbox.selection_set(listitems.index(item))
+                else:
+                    raise ValueError, 'no such item "%s"' % item
+
+    def setlist(self, items):
+        self._listbox.delete(0, 'end')
+       if len(items) > 0:
+           if type(items) != types.TupleType:
+               items = tuple(items)
+           apply(self._listbox.insert, (0,) + items)
+
+    # Override Tkinter.Listbox get method, so that if it is called with
+    # no arguments, return all list elements (consistent with other widgets).
+    def get(self, first=None, last=None):
+       if first is None:
+           return self._listbox.get(0, 'end')
+       else:
+           return self._listbox.get(first, last)
+
+    # ======================================================================
+
+    # Configuration methods.
+
+    def _hscrollMode(self):
+       # The horizontal scroll mode has been configured.
+
+       mode = self['hscrollmode']
+
+       if mode == 'static':
+           if not self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'none':
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       else:
+           message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+        self._configureScrollCommands()
+
+    def _vscrollMode(self):
+       # The vertical scroll mode has been configured.
+
+       mode = self['vscrollmode']
+
+       if mode == 'static':
+           if not self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'none':
+           if self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       else:
+           message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+        self._configureScrollCommands()
+
+    # ======================================================================
+
+    # Private methods.
+
+    def _configureScrollCommands(self):
+        # If both scrollmodes are not dynamic we can save a lot of
+        # time by not having to create an idle job to handle the
+        # scroll commands.
+
+        # Clean up previous scroll commands to prevent memory leak.
+        tclCommandName = str(self._listbox.cget('xscrollcommand'))
+        if tclCommandName != '':   
+            self._listbox.deletecommand(tclCommandName)
+        tclCommandName = str(self._listbox.cget('yscrollcommand'))
+        if tclCommandName != '':   
+            self._listbox.deletecommand(tclCommandName)
+
+       if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
+            self._listbox.configure(
+                    xscrollcommand=self._scrollBothLater,
+                    yscrollcommand=self._scrollBothLater
+            )
+        else:
+            self._listbox.configure(
+                    xscrollcommand=self._scrollXNow,
+                    yscrollcommand=self._scrollYNow
+            )
+
+    def _scrollXNow(self, first, last):
+        self._horizScrollbar.set(first, last)
+        self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
+
+       if self['hscrollmode'] == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+
+    def _scrollYNow(self, first, last):
+        self._vertScrollbar.set(first, last)
+        self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
+
+        if self['vscrollmode'] == 'dynamic':
+            if self._vertScrollbarNeeded != self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+
+    def _scrollBothLater(self, first, last):
+       # Called by the listbox to set the horizontal or vertical
+       # scrollbar when it has scrolled or changed size or contents.
+
+       if self.scrollTimer is None:
+           self.scrollTimer = self.after_idle(self._scrollBothNow)
+
+    def _scrollBothNow(self):
+        # This performs the function of _scrollXNow and _scrollYNow.
+        # If one is changed, the other should be updated to match.
+       self.scrollTimer = None
+
+        # Call update_idletasks to make sure that the containing frame
+        # has been resized before we attempt to set the scrollbars. 
+        # Otherwise the scrollbars may be mapped/unmapped continuously.
+        self._scrollRecurse = self._scrollRecurse + 1
+        self.update_idletasks()
+        self._scrollRecurse = self._scrollRecurse - 1
+        if self._scrollRecurse != 0:
+            return
+
+       xview = self._listbox.xview()
+       yview = self._listbox.yview()
+       self._horizScrollbar.set(xview[0], xview[1])
+       self._vertScrollbar.set(yview[0], yview[1])
+
+       self._horizScrollbarNeeded = (xview != (0.0, 1.0))
+       self._vertScrollbarNeeded = (yview != (0.0, 1.0))
+
+       # If both horizontal and vertical scrollmodes are dynamic and
+       # currently only one scrollbar is mapped and both should be
+       # toggled, then unmap the mapped scrollbar.  This prevents a
+       # continuous mapping and unmapping of the scrollbars. 
+       if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
+               self._horizScrollbarNeeded != self._horizScrollbarOn and
+               self._vertScrollbarNeeded != self._vertScrollbarOn and
+               self._vertScrollbarOn != self._horizScrollbarOn):
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+           else:
+               self._toggleVertScrollbar()
+           return
+
+       if self['hscrollmode'] == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+
+       if self['vscrollmode'] == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+
+    def _toggleHorizScrollbar(self):
+
+       self._horizScrollbarOn = not self._horizScrollbarOn
+
+       interior = self.interior()
+       if self._horizScrollbarOn:
+           self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
+           interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
+       else:
+           self._horizScrollbar.grid_forget()
+           interior.grid_rowconfigure(3, minsize = 0)
+
+    def _toggleVertScrollbar(self):
+
+       self._vertScrollbarOn = not self._vertScrollbarOn
+
+       interior = self.interior()
+       if self._vertScrollbarOn:
+           self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
+           interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
+       else:
+           self._vertScrollbar.grid_forget()
+           interior.grid_columnconfigure(3, minsize = 0)
+
+    def _handleEvent(self, event, eventType):
+        if eventType == 'double':
+            command = self['dblclickcommand']
+        elif eventType == 'key':
+            command = self['selectioncommand']
+        else: #eventType == 'release'
+            # Do not execute the command if the mouse was released
+            # outside the listbox.
+            if (event.x < 0 or self._listbox.winfo_width() <= event.x or
+                    event.y < 0 or self._listbox.winfo_height() <= event.y):
+                return
+
+            command = self['selectioncommand']
+
+        if callable(command):
+            command()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)size method inherited from Tkinter.Frame.Grid.
+    def size(self):
+       return self._listbox.size()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Frame.Grid.
+    def bbox(self, index):
+       return self._listbox.bbox(index)
+
+Pmw.forwardmethods(ScrolledListBox, Tkinter.Listbox, '_listbox')
+
+# ======================================================================
+
+_listboxCache = {}
+
+def _registerScrolledList(listbox, scrolledList):
+    # Register an ScrolledList widget for a Listbox widget
+
+    _listboxCache[listbox] = scrolledList
+
+def _deregisterScrolledList(listbox):
+    # Deregister a Listbox widget
+    del _listboxCache[listbox]
+
+def _handleEvent(event, eventType):
+    # Forward events for a Listbox to it's ScrolledListBox
+
+    # A binding earlier in the bindtags list may have destroyed the
+    # megawidget, so need to check.
+    if _listboxCache.has_key(event.widget):
+        _listboxCache[event.widget]._handleEvent(event, eventType)
diff --git a/Pmw/Pmw_1_2/lib/PmwScrolledText.py b/Pmw/Pmw_1_2/lib/PmwScrolledText.py
new file mode 100644 (file)
index 0000000..f244a1b
--- /dev/null
@@ -0,0 +1,443 @@
+# Based on iwidgets2.2.0/scrolledtext.itk code.   
+
+import Tkinter
+import Pmw
+
+class ScrolledText(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderframe',    0,            INITOPT),
+           ('columnheader',   0,            INITOPT),
+           ('hscrollmode',    'dynamic',    self._hscrollMode),
+           ('labelmargin',    0,            INITOPT),
+           ('labelpos',       None,         INITOPT),
+           ('rowcolumnheader',0,            INITOPT),
+           ('rowheader',      0,            INITOPT),
+           ('scrollmargin',   2,            INITOPT),
+           ('usehullsize',    0,            INITOPT),
+           ('vscrollmode',    'dynamic',    self._vscrollMode),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+
+       if self['usehullsize']:
+           interior.grid_propagate(0)
+
+       if self['borderframe']:
+           # Create a frame widget to act as the border of the text 
+           # widget.  Later, pack the text widget so that it fills
+           # the frame.  This avoids a problem in Tk, where window
+           # items in a text widget may overlap the border of the
+           # text widget.
+           self._borderframe = self.createcomponent('borderframe',
+                   (), None,
+                   Tkinter.Frame, (interior,),
+                   relief = 'sunken',
+                   borderwidth = 2,
+           )
+           self._borderframe.grid(row = 4, column = 4, sticky = 'news')
+
+           # Create the text widget.
+           self._textbox = self.createcomponent('text',
+                   (), None,
+                   Tkinter.Text, (self._borderframe,),
+                   highlightthickness = 0,
+                   borderwidth = 0,
+           )
+           self._textbox.pack(fill = 'both', expand = 1)
+
+            bw = self._borderframe.cget('borderwidth'),
+            ht = self._borderframe.cget('highlightthickness'),
+       else:
+           # Create the text widget.
+           self._textbox = self.createcomponent('text',
+                   (), None,
+                   Tkinter.Text, (interior,),
+           )
+           self._textbox.grid(row = 4, column = 4, sticky = 'news')
+
+            bw = self._textbox.cget('borderwidth'),
+            ht = self._textbox.cget('highlightthickness'),
+
+        # Create the header text widgets
+        if self['columnheader']:
+            self._columnheader = self.createcomponent('columnheader',
+                    (), 'Header',
+                    Tkinter.Text, (interior,),
+                    height=1,
+                    wrap='none',
+                    borderwidth = bw,
+                    highlightthickness = ht,
+            )
+            self._columnheader.grid(row = 2, column = 4, sticky = 'ew')
+            self._columnheader.configure(
+                    xscrollcommand = self._columnheaderscrolled)
+
+        if self['rowheader']:
+            self._rowheader = self.createcomponent('rowheader',
+                    (), 'Header',
+                    Tkinter.Text, (interior,),
+                    wrap='none',
+                    borderwidth = bw,
+                    highlightthickness = ht,
+            )
+            self._rowheader.grid(row = 4, column = 2, sticky = 'ns')
+            self._rowheader.configure(
+                    yscrollcommand = self._rowheaderscrolled)
+
+        if self['rowcolumnheader']:
+            self._rowcolumnheader = self.createcomponent('rowcolumnheader',
+                    (), 'Header',
+                    Tkinter.Text, (interior,),
+                    height=1,
+                    wrap='none',
+                    borderwidth = bw,
+                    highlightthickness = ht,
+            )
+            self._rowcolumnheader.grid(row = 2, column = 2, sticky = 'nsew')
+
+       interior.grid_rowconfigure(4, weight = 1, minsize = 0)
+       interior.grid_columnconfigure(4, weight = 1, minsize = 0)
+
+       # Create the horizontal scrollbar
+       self._horizScrollbar = self.createcomponent('horizscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (interior,),
+               orient='horizontal',
+               command=self._textbox.xview
+       )
+
+       # Create the vertical scrollbar
+       self._vertScrollbar = self.createcomponent('vertscrollbar',
+               (), 'Scrollbar',
+               Tkinter.Scrollbar, (interior,),
+               orient='vertical',
+               command=self._textbox.yview
+       )
+
+       self.createlabel(interior, childCols = 5, childRows = 5)
+
+       # Initialise instance variables.
+       self._horizScrollbarOn = 0
+       self._vertScrollbarOn = 0
+       self.scrollTimer = None
+        self._scrollRecurse = 0
+       self._horizScrollbarNeeded = 0
+       self._vertScrollbarNeeded = 0
+       self._textWidth = None
+
+        # These four variables avoid an infinite loop caused by the
+        # row or column header's scrollcommand causing the main text
+        # widget's scrollcommand to be called and vice versa.
+       self._textboxLastX = None
+       self._textboxLastY = None
+       self._columnheaderLastX = None
+       self._rowheaderLastY = None
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def destroy(self):
+       if self.scrollTimer is not None:
+           self.after_cancel(self.scrollTimer)
+           self.scrollTimer = None
+       Pmw.MegaWidget.destroy(self)
+
+    # ======================================================================
+
+    # Public methods.
+
+    def clear(self):
+       self.settext('')
+
+    def importfile(self, fileName, where = 'end'):
+       file = open(fileName, 'r')
+       self._textbox.insert(where, file.read())
+       file.close()
+
+    def exportfile(self, fileName):
+       file = open(fileName, 'w')
+       file.write(self._textbox.get('1.0', 'end'))
+       file.close()
+
+    def settext(self, text):
+       disabled = (str(self._textbox.cget('state')) == 'disabled')
+       if disabled:
+           self._textbox.configure(state='normal')
+       self._textbox.delete('0.0', 'end')
+       self._textbox.insert('end', text)
+       if disabled:
+           self._textbox.configure(state='disabled')
+
+    # Override Tkinter.Text get method, so that if it is called with
+    # no arguments, return all text (consistent with other widgets).
+    def get(self, first=None, last=None):
+       if first is None:
+           return self._textbox.get('1.0', 'end')
+       else:
+           return self._textbox.get(first, last)
+
+    def getvalue(self):
+        return self.get()
+
+    def setvalue(self, text):
+        return self.settext(text)
+
+    def appendtext(self, text):
+        oldTop, oldBottom = self._textbox.yview()
+     
+        disabled = (str(self._textbox.cget('state')) == 'disabled')
+        if disabled:
+            self._textbox.configure(state='normal')
+        self._textbox.insert('end', text)
+        if disabled:
+            self._textbox.configure(state='disabled')
+     
+        if oldBottom == 1.0:
+            self._textbox.yview('moveto', 1.0)
+
+    # ======================================================================
+
+    # Configuration methods.
+
+    def _hscrollMode(self):
+       # The horizontal scroll mode has been configured.
+
+       mode = self['hscrollmode']
+
+       if mode == 'static':
+           if not self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'dynamic':
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       elif mode == 'none':
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+       else:
+           message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+        self._configureScrollCommands()
+
+    def _vscrollMode(self):
+       # The vertical scroll mode has been configured.
+
+       mode = self['vscrollmode']
+
+       if mode == 'static':
+           if not self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       elif mode == 'none':
+           if self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+       else:
+           message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
+           raise ValueError, message
+
+        self._configureScrollCommands()
+
+    # ======================================================================
+
+    # Private methods.
+
+    def _configureScrollCommands(self):
+        # If both scrollmodes are not dynamic we can save a lot of
+        # time by not having to create an idle job to handle the
+        # scroll commands.
+
+        # Clean up previous scroll commands to prevent memory leak.
+        tclCommandName = str(self._textbox.cget('xscrollcommand'))
+        if tclCommandName != '':   
+            self._textbox.deletecommand(tclCommandName)
+        tclCommandName = str(self._textbox.cget('yscrollcommand'))
+        if tclCommandName != '':   
+            self._textbox.deletecommand(tclCommandName)
+
+       if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
+            self._textbox.configure(
+                    xscrollcommand=self._scrollBothLater,
+                    yscrollcommand=self._scrollBothLater
+            )
+        else:
+            self._textbox.configure(
+                    xscrollcommand=self._scrollXNow,
+                    yscrollcommand=self._scrollYNow
+            )
+
+    def _scrollXNow(self, first, last):
+        self._horizScrollbar.set(first, last)
+        self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
+
+        # This code is the same as in _scrollBothNow.  Keep it that way.
+        if self['hscrollmode'] == 'dynamic':
+            currentWidth = self._textbox.winfo_width()
+            if self._horizScrollbarNeeded != self._horizScrollbarOn:
+                if self._horizScrollbarNeeded or \
+                        self._textWidth != currentWidth:
+                    self._toggleHorizScrollbar()
+            self._textWidth = currentWidth
+
+        if self['columnheader']:
+           if self._columnheaderLastX != first:
+               self._columnheaderLastX = first
+               self._columnheader.xview('moveto', first)
+
+    def _scrollYNow(self, first, last):
+        if first == '0' and last == '0':
+            return
+        self._vertScrollbar.set(first, last)
+        self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
+
+        if self['vscrollmode'] == 'dynamic':
+            if self._vertScrollbarNeeded != self._vertScrollbarOn:
+                self._toggleVertScrollbar()
+
+        if self['rowheader']:
+           if self._rowheaderLastY != first:
+               self._rowheaderLastY = first
+               self._rowheader.yview('moveto', first)
+
+    def _scrollBothLater(self, first, last):
+       # Called by the text widget to set the horizontal or vertical
+       # scrollbar when it has scrolled or changed size or contents.
+
+       if self.scrollTimer is None:
+           self.scrollTimer = self.after_idle(self._scrollBothNow)
+
+    def _scrollBothNow(self):
+        # This performs the function of _scrollXNow and _scrollYNow.
+        # If one is changed, the other should be updated to match.
+       self.scrollTimer = None
+
+        # Call update_idletasks to make sure that the containing frame
+        # has been resized before we attempt to set the scrollbars. 
+        # Otherwise the scrollbars may be mapped/unmapped continuously.
+        self._scrollRecurse = self._scrollRecurse + 1
+        self.update_idletasks()
+        self._scrollRecurse = self._scrollRecurse - 1
+        if self._scrollRecurse != 0:
+            return
+
+       xview = self._textbox.xview()
+       yview = self._textbox.yview()
+
+       # The text widget returns a yview of (0.0, 0.0) just after it
+       # has been created. Ignore this.
+       if yview == (0.0, 0.0):
+           return
+
+        if self['columnheader']:
+           if self._columnheaderLastX != xview[0]:
+               self._columnheaderLastX = xview[0]
+               self._columnheader.xview('moveto', xview[0])
+        if self['rowheader']:
+           if self._rowheaderLastY != yview[0]:
+               self._rowheaderLastY = yview[0]
+               self._rowheader.yview('moveto', yview[0])
+
+       self._horizScrollbar.set(xview[0], xview[1])
+       self._vertScrollbar.set(yview[0], yview[1])
+
+       self._horizScrollbarNeeded = (xview != (0.0, 1.0))
+       self._vertScrollbarNeeded = (yview != (0.0, 1.0))
+
+       # If both horizontal and vertical scrollmodes are dynamic and
+       # currently only one scrollbar is mapped and both should be
+       # toggled, then unmap the mapped scrollbar.  This prevents a
+       # continuous mapping and unmapping of the scrollbars. 
+       if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
+               self._horizScrollbarNeeded != self._horizScrollbarOn and
+               self._vertScrollbarNeeded != self._vertScrollbarOn and
+               self._vertScrollbarOn != self._horizScrollbarOn):
+           if self._horizScrollbarOn:
+               self._toggleHorizScrollbar()
+           else:
+               self._toggleVertScrollbar()
+           return
+
+       if self['hscrollmode'] == 'dynamic':
+
+           # The following test is done to prevent continuous
+           # mapping and unmapping of the horizontal scrollbar. 
+           # This may occur when some event (scrolling, resizing
+           # or text changes) modifies the displayed text such
+           # that the bottom line in the window is the longest
+           # line displayed.  If this causes the horizontal
+           # scrollbar to be mapped, the scrollbar may "cover up"
+           # the bottom line, which would mean that the scrollbar
+           # is no longer required.  If the scrollbar is then
+           # unmapped, the bottom line will then become visible
+           # again, which would cause the scrollbar to be mapped
+           # again, and so on...
+           #
+           # The idea is that, if the width of the text widget
+           # has not changed and the scrollbar is currently
+           # mapped, then do not unmap the scrollbar even if it
+           # is no longer required.  This means that, during
+           # normal scrolling of the text, once the horizontal
+           # scrollbar has been mapped it will not be unmapped
+           # (until the width of the text widget changes).
+
+           currentWidth = self._textbox.winfo_width()
+           if self._horizScrollbarNeeded != self._horizScrollbarOn:
+               if self._horizScrollbarNeeded or \
+                       self._textWidth != currentWidth:
+                   self._toggleHorizScrollbar()
+           self._textWidth = currentWidth
+
+       if self['vscrollmode'] == 'dynamic':
+           if self._vertScrollbarNeeded != self._vertScrollbarOn:
+               self._toggleVertScrollbar()
+
+    def _columnheaderscrolled(self, first, last):
+       if self._textboxLastX != first:
+           self._textboxLastX = first
+           self._textbox.xview('moveto', first)
+
+    def _rowheaderscrolled(self, first, last):
+       if self._textboxLastY != first:
+           self._textboxLastY = first
+           self._textbox.yview('moveto', first)
+
+    def _toggleHorizScrollbar(self):
+
+       self._horizScrollbarOn = not self._horizScrollbarOn
+
+       interior = self.interior()
+       if self._horizScrollbarOn:
+           self._horizScrollbar.grid(row = 6, column = 4, sticky = 'news')
+           interior.grid_rowconfigure(5, minsize = self['scrollmargin'])
+       else:
+           self._horizScrollbar.grid_forget()
+           interior.grid_rowconfigure(5, minsize = 0)
+
+    def _toggleVertScrollbar(self):
+
+       self._vertScrollbarOn = not self._vertScrollbarOn
+
+       interior = self.interior()
+       if self._vertScrollbarOn:
+           self._vertScrollbar.grid(row = 4, column = 6, sticky = 'news')
+           interior.grid_columnconfigure(5, minsize = self['scrollmargin'])
+       else:
+           self._vertScrollbar.grid_forget()
+           interior.grid_columnconfigure(5, minsize = 0)
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Frame.Grid.
+    def bbox(self, index):
+       return self._textbox.bbox(index)
+
+Pmw.forwardmethods(ScrolledText, Tkinter.Text, '_textbox')
diff --git a/Pmw/Pmw_1_2/lib/PmwSelectionDialog.py b/Pmw/Pmw_1_2/lib/PmwSelectionDialog.py
new file mode 100644 (file)
index 0000000..dbfda06
--- /dev/null
@@ -0,0 +1,55 @@
+# Not Based on iwidgets version.
+
+import Pmw
+
+class SelectionDialog(Pmw.Dialog):
+    # Dialog window with selection list.
+    
+    # Dialog window displaying a list and requesting the user to
+    # select one.
+
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderx',     10,    INITOPT),
+           ('bordery',     10,    INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.Dialog.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       aliases = (
+           ('listbox', 'scrolledlist_listbox'),
+           ('label', 'scrolledlist_label'),
+       )
+       self._list = self.createcomponent('scrolledlist',
+               aliases, None,
+               Pmw.ScrolledListBox, (interior,),
+               dblclickcommand = self.invoke)
+       self._list.pack(side='top', expand='true', fill='both',
+               padx = self['borderx'], pady = self['bordery'])
+
+        if not kw.has_key('activatecommand'):
+            # Whenever this dialog is activated, set the focus to the
+            # ScrolledListBox's listbox widget.
+            listbox = self.component('listbox')
+            self.configure(activatecommand = listbox.focus_set)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)size method inherited from Tkinter.Toplevel.Grid.
+    def size(self):
+       return self.component('listbox').size()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Toplevel.Grid.
+    def bbox(self, index):
+       return self.component('listbox').size(index)
+
+Pmw.forwardmethods(SelectionDialog, Pmw.ScrolledListBox, '_list')
diff --git a/Pmw/Pmw_1_2/lib/PmwTextDialog.py b/Pmw/Pmw_1_2/lib/PmwTextDialog.py
new file mode 100644 (file)
index 0000000..1ce9b5c
--- /dev/null
@@ -0,0 +1,38 @@
+# A Dialog with a ScrolledText widget.
+
+import Pmw
+
+class TextDialog(Pmw.Dialog):
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('borderx',     10,    INITOPT),
+           ('bordery',     10,    INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.Dialog.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       aliases = (
+           ('text', 'scrolledtext_text'),
+           ('label', 'scrolledtext_label'),
+       )
+       self._text = self.createcomponent('scrolledtext',
+               aliases, None,
+               Pmw.ScrolledText, (interior,))
+       self._text.pack(side='top', expand=1, fill='both',
+               padx = self['borderx'], pady = self['bordery'])
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    # Need to explicitly forward this to override the stupid
+    # (grid_)bbox method inherited from Tkinter.Toplevel.Grid.
+    def bbox(self, index):
+       return self._text.bbox(index)
+
+Pmw.forwardmethods(TextDialog, Pmw.ScrolledText, '_text')
diff --git a/Pmw/Pmw_1_2/lib/PmwTimeCounter.py b/Pmw/Pmw_1_2/lib/PmwTimeCounter.py
new file mode 100644 (file)
index 0000000..0023e2f
--- /dev/null
@@ -0,0 +1,381 @@
+# Authors: Joe VanAndel and Greg McFarlane
+
+import string
+import sys
+import time
+import Tkinter
+import Pmw
+
+class TimeCounter(Pmw.MegaWidget):
+    """Up-down counter
+
+    A TimeCounter is a single-line entry widget with Up and Down arrows
+    which increment and decrement the Time value in the entry.  
+    """
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       INITOPT = Pmw.INITOPT
+       optiondefs = (
+           ('autorepeat',    1,    None),
+           ('buttonaspect',  1.0,  INITOPT),
+           ('command',       None, None),
+           ('initwait',      300,  None),
+           ('labelmargin',   0,    INITOPT),
+           ('labelpos',      None, INITOPT),
+           ('max',           None, self._max),
+           ('min',           None, self._min),
+           ('padx',          0,    INITOPT),
+           ('pady',          0,    INITOPT),
+           ('repeatrate',    50,   None),
+           ('value',         None, INITOPT),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       self.arrowDirection = {}
+       self._flag = 'stopped'
+       self._timerId = None
+
+       self._createComponents(kw)
+
+       value = self['value']
+       if value is None:
+           now = time.time()
+           value = time.strftime('%H:%M:%S', time.localtime(now))
+       self.setvalue(value)
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _createComponents(self, kw):
+
+       # Create the components.
+       interior = self.interior()
+
+       # If there is no label, put the arrows and the entry directly
+       # into the interior, otherwise create a frame for them.  In
+       # either case the border around the arrows and the entry will
+       # be raised (but not around the label).
+       if self['labelpos'] is None:
+           frame = interior
+            if not kw.has_key('hull_relief'):
+                frame.configure(relief = 'raised')
+            if not kw.has_key('hull_borderwidth'):
+                frame.configure(borderwidth = 1)
+       else:
+           frame = self.createcomponent('frame',
+                   (), None,
+                   Tkinter.Frame, (interior,),
+                    relief = 'raised', borderwidth = 1)
+           frame.grid(column=2, row=2, sticky='nsew')
+           interior.grid_columnconfigure(2, weight=1)
+           interior.grid_rowconfigure(2, weight=1)
+
+       # Create the down arrow buttons.
+
+       # Create the hour down arrow.
+       self._downHourArrowBtn = self.createcomponent('downhourarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downHourArrowBtn] = 'down'
+       self._downHourArrowBtn.grid(column = 0, row = 2)
+
+       # Create the minute down arrow.
+       self._downMinuteArrowBtn = self.createcomponent('downminutearrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downMinuteArrowBtn] = 'down'
+       self._downMinuteArrowBtn.grid(column = 1, row = 2)
+
+       # Create the second down arrow.
+       self._downSecondArrowBtn = self.createcomponent('downsecondarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._downSecondArrowBtn] = 'down'
+       self._downSecondArrowBtn.grid(column = 2, row = 2)
+
+       # Create the entry fields.
+
+       # Create the hour entry field.
+       self._hourCounterEntry = self.createcomponent('hourentryfield',
+               (('hourentry', 'hourentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._hourCounterEntry.grid(column = 0, row = 1, sticky = 'news')
+
+       # Create the minute entry field.
+       self._minuteCounterEntry = self.createcomponent('minuteentryfield',
+               (('minuteentry', 'minuteentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._minuteCounterEntry.grid(column = 1, row = 1, sticky = 'news')
+
+       # Create the second entry field.
+       self._secondCounterEntry = self.createcomponent('secondentryfield',
+               (('secondentry', 'secondentryfield_entry'),), None,
+               Pmw.EntryField, (frame,), validate='integer', entry_width = 2)
+       self._secondCounterEntry.grid(column = 2, row = 1, sticky = 'news')
+
+       # Create the up arrow buttons.
+
+       # Create the hour up arrow.
+       self._upHourArrowBtn = self.createcomponent('uphourarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upHourArrowBtn] = 'up'
+       self._upHourArrowBtn.grid(column = 0, row = 0)
+
+       # Create the minute up arrow.
+       self._upMinuteArrowBtn = self.createcomponent('upminutearrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upMinuteArrowBtn] = 'up'
+       self._upMinuteArrowBtn.grid(column = 1, row = 0)
+
+       # Create the second up arrow.
+       self._upSecondArrowBtn = self.createcomponent('upsecondarrow',
+               (), 'Arrow',
+               Tkinter.Canvas, (frame,),
+               width = 16, height = 16, relief = 'raised', borderwidth = 2)
+       self.arrowDirection[self._upSecondArrowBtn] = 'up'
+       self._upSecondArrowBtn.grid(column = 2, row = 0)
+
+       # Make it resize nicely.
+       padx = self['padx']
+       pady = self['pady']
+       for col in range(3):
+           frame.grid_columnconfigure(col, weight = 1, pad = padx)
+       frame.grid_rowconfigure(0, pad = pady)
+       frame.grid_rowconfigure(2, pad = pady)
+
+       frame.grid_rowconfigure(1, weight = 1)
+
+       # Create the label.
+       self.createlabel(interior)
+
+       # Set bindings.
+
+       # Up hour
+       self._upHourArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upHourArrowBtn: 
+               s._drawArrow(button, 'up'))
+
+       self._upHourArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upHourArrowBtn: 
+               s._countUp(button, 3600))
+
+       self._upHourArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upHourArrowBtn:
+               s._stopUpDown(button))
+
+       # Up minute
+       self._upMinuteArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upMinuteArrowBtn: 
+               s._drawArrow(button, 'up'))
+           
+
+       self._upMinuteArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upMinuteArrowBtn: 
+               s._countUp(button, 60))
+
+       self._upMinuteArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upMinuteArrowBtn:
+               s._stopUpDown(button))
+
+       # Up second
+       self._upSecondArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._upSecondArrowBtn: 
+               s._drawArrow(button, 'up'))
+           
+
+       self._upSecondArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._upSecondArrowBtn: 
+               s._countUp(button, 1))
+
+       self._upSecondArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._upSecondArrowBtn:
+               s._stopUpDown(button))
+
+       # Down hour
+       self._downHourArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downHourArrowBtn: 
+               s._drawArrow(button, 'down'))
+
+       self._downHourArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downHourArrowBtn: 
+               s._countDown(button, 3600))
+       self._downHourArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downHourArrowBtn:
+               s._stopUpDown(button))
+
+
+       # Down minute
+       self._downMinuteArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downMinuteArrowBtn: 
+               s._drawArrow(button, 'down'))
+
+       self._downMinuteArrowBtn.bind('<1>', 
+               lambda event, s=self,button=self._downMinuteArrowBtn:
+                s._countDown(button, 60))
+       self._downMinuteArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downMinuteArrowBtn:
+               s._stopUpDown(button))
+
+       # Down second
+       self._downSecondArrowBtn.bind('<Configure>', 
+               lambda  event, s=self,button=self._downSecondArrowBtn: 
+               s._drawArrow(button, 'down'))
+
+       self._downSecondArrowBtn.bind('<1>', 
+               lambda event, s=self, button=self._downSecondArrowBtn: 
+               s._countDown(button,1))
+       self._downSecondArrowBtn.bind('<Any-ButtonRelease-1>', 
+               lambda event, s=self, button=self._downSecondArrowBtn:
+               s._stopUpDown(button))
+
+       self._hourCounterEntry.component('entry').bind(
+                '<Return>', self._invoke)
+       self._minuteCounterEntry.component('entry').bind(
+               '<Return>', self._invoke)
+       self._secondCounterEntry.component('entry').bind(
+               '<Return>', self._invoke)
+
+       self._hourCounterEntry.bind('<Configure>', self._resizeArrow)
+       self._minuteCounterEntry.bind('<Configure>', self._resizeArrow)
+       self._secondCounterEntry.bind('<Configure>', self._resizeArrow)
+
+    def _drawArrow(self, arrow, direction):
+        Pmw.drawarrow(arrow, self['hourentry_foreground'], direction, 'arrow')
+
+    def _resizeArrow(self, event = None):
+       for btn in (self._upHourArrowBtn, self._upMinuteArrowBtn,
+               self._upSecondArrowBtn,
+               self._downHourArrowBtn,
+               self._downMinuteArrowBtn, self._downSecondArrowBtn):
+           bw = (string.atoi(btn['borderwidth']) +
+                   string.atoi(btn['highlightthickness']))
+           newHeight = self._hourCounterEntry.winfo_reqheight() - 2 * bw
+           newWidth = int(newHeight * self['buttonaspect'])
+           btn.configure(width=newWidth, height=newHeight)
+           self._drawArrow(btn, self.arrowDirection[btn])
+
+    def _min(self):
+       min = self['min']
+        if min is None:
+           self._minVal = 0
+       else:
+           self._minVal = Pmw.timestringtoseconds(min)
+
+    def _max(self):
+       max = self['max']
+       if max is None:
+           self._maxVal = None
+       else:
+           self._maxVal = Pmw.timestringtoseconds(max)
+
+    def getvalue(self):
+        return self.getstring()
+
+    def setvalue(self, text):
+        list = string.split(text, ':')
+       if len(list) != 3:
+           raise ValueError, 'invalid value: ' + text
+
+       self._hour = string.atoi(list[0])
+       self._minute = string.atoi(list[1])
+       self._second = string.atoi(list[2]) 
+
+       self._setHMS()
+
+    def getstring(self):
+       return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)
+
+    def getint(self):
+       return self._hour * 3600 + self._minute * 60 + self._second
+
+    def _countUp(self, button, increment):
+       self._relief = self._upHourArrowBtn.cget('relief')
+       button.configure(relief='sunken')
+       self._count(1, 'start', increment)
+
+    def _countDown(self, button, increment):
+
+       self._relief = self._downHourArrowBtn.cget('relief')
+       button.configure(relief='sunken')
+       self._count(-1, 'start', increment)
+
+    def increment(self, seconds = 1):
+       self._count(1, 'force', seconds)
+
+    def decrement(self, seconds = 1):
+       self._count(-1, 'force', seconds)
+
+    def _count(self, factor, newFlag = None, increment = 1):
+       if newFlag != 'force':
+         if newFlag is not None:
+           self._flag = newFlag
+
+         if self._flag == 'stopped':
+           return
+
+       value = (string.atoi(self._hourCounterEntry.get()) *3600) + \
+             (string.atoi(self._minuteCounterEntry.get()) *60) + \
+             string.atoi(self._secondCounterEntry.get()) + \
+             factor * increment
+       min = self._minVal
+       max = self._maxVal
+       if value < min:
+         value = min
+       if max is not None and value > max:
+         value = max
+
+       self._hour = value /3600
+       self._minute = (value - (self._hour*3600)) / 60
+       self._second = value - (self._hour*3600) - (self._minute*60)
+       self._setHMS()
+
+       if newFlag != 'force':
+         if self['autorepeat']:
+           if self._flag == 'start':
+             delay = self['initwait']
+             self._flag = 'running'
+           else:
+             delay = self['repeatrate']
+           self._timerId = self.after(
+               delay, lambda self=self, factor=factor,increment=increment: 
+                 self._count(factor,'running', increment))
+
+    def _setHMS(self):
+        self._hourCounterEntry.setentry('%02d' % self._hour)
+        self._minuteCounterEntry.setentry('%02d' % self._minute)
+        self._secondCounterEntry.setentry('%02d' % self._second)
+
+    def _stopUpDown(self, button):
+        if self._timerId is not None:
+            self.after_cancel(self._timerId)
+           self._timerId = None
+        button.configure(relief=self._relief)
+        self._flag = 'stopped'
+
+    def _invoke(self, event):
+        cmd = self['command']
+        if callable(cmd):
+           cmd()
+
+    def invoke(self):
+        cmd = self['command']
+        if callable(cmd):
+           return cmd()
+
+    def destroy(self):
+        if self._timerId is not None:
+            self.after_cancel(self._timerId)
+           self._timerId = None
+        Pmw.MegaWidget.destroy(self)
diff --git a/Pmw/Pmw_1_2/lib/PmwTimeFuncs.py b/Pmw/Pmw_1_2/lib/PmwTimeFuncs.py
new file mode 100644 (file)
index 0000000..a520572
--- /dev/null
@@ -0,0 +1,146 @@
+# Functions for dealing with dates and times.
+
+import re
+import string
+
+def timestringtoseconds(text, separator = ':'):
+  inputList = string.split(string.strip(text), separator)
+  if len(inputList) != 3:
+    raise ValueError, 'invalid value: ' + text
+
+  sign = 1
+  if len(inputList[0]) > 0 and inputList[0][0] in ('+', '-'):
+    if inputList[0][0] == '-':
+      sign = -1
+    inputList[0] = inputList[0][1:]
+
+  if re.search('[^0-9]', string.join(inputList, '')) is not None:
+    raise ValueError, 'invalid value: ' + text
+
+  hour = string.atoi(inputList[0])
+  minute = string.atoi(inputList[1])
+  second = string.atoi(inputList[2])
+
+  if minute >= 60 or second >= 60:
+    raise ValueError, 'invalid value: ' + text
+  return sign * (hour * 60 * 60 + minute * 60 + second)
+
+_year_pivot = 50
+_century = 2000
+
+def setyearpivot(pivot, century = None):
+    global _year_pivot
+    global _century
+    oldvalues = (_year_pivot, _century)
+    _year_pivot = pivot
+    if century is not None:
+       _century = century
+    return oldvalues
+
+def datestringtojdn(text, format = 'ymd', separator = '/'):
+  inputList = string.split(string.strip(text), separator)
+  if len(inputList) != 3:
+    raise ValueError, 'invalid value: ' + text
+
+  if re.search('[^0-9]', string.join(inputList, '')) is not None:
+    raise ValueError, 'invalid value: ' + text
+  formatList = list(format)
+  day = string.atoi(inputList[formatList.index('d')])
+  month = string.atoi(inputList[formatList.index('m')])
+  year = string.atoi(inputList[formatList.index('y')])
+
+  if _year_pivot is not None:
+    if year >= 0 and year < 100:
+      if year <= _year_pivot:
+       year = year + _century
+      else:
+       year = year + _century - 100
+
+  jdn = ymdtojdn(year, month, day)
+  if jdntoymd(jdn) != (year, month, day):
+    raise ValueError, 'invalid value: ' + text
+  return jdn
+
+def _cdiv(a, b):
+    # Return a / b as calculated by most C language implementations,
+    # assuming both a and b are integers.
+
+    if a * b > 0:
+       return a / b
+    else:
+       return -(abs(a) / abs(b))
+
+def ymdtojdn(year, month, day, julian = -1, papal = 1):
+
+    # set Julian flag if auto set
+    if julian < 0:
+       if papal:                          # Pope Gregory XIII's decree
+           lastJulianDate = 15821004L     # last day to use Julian calendar
+       else:                              # British-American usage
+           lastJulianDate = 17520902L     # last day to use Julian calendar
+
+       julian = ((year * 100L) + month) * 100 + day  <=  lastJulianDate
+
+    if year < 0:
+       # Adjust BC year
+       year = year + 1
+
+    if julian:
+       return 367L * year - _cdiv(7 * (year + 5001L + _cdiv((month - 9), 7)), 4) + \
+           _cdiv(275 * month, 9) + day + 1729777L
+    else:
+       return (day - 32076L) + \
+           _cdiv(1461L * (year + 4800L + _cdiv((month - 14), 12)), 4) + \
+           _cdiv(367 * (month - 2 - _cdiv((month - 14), 12) * 12), 12) - \
+           _cdiv((3 * _cdiv((year + 4900L + _cdiv((month - 14), 12)), 100)), 4) + \
+           1            # correction by rdg
+
+def jdntoymd(jdn, julian = -1, papal = 1):
+
+    # set Julian flag if auto set
+    if julian < 0:
+       if papal:                          # Pope Gregory XIII's decree
+           lastJulianJdn = 2299160L       # last jdn to use Julian calendar
+       else:                              # British-American usage
+           lastJulianJdn = 2361221L       # last jdn to use Julian calendar
+
+       julian = (jdn <= lastJulianJdn);
+
+    x = jdn + 68569L
+    if julian:
+       x = x + 38
+       daysPer400Years = 146100L
+       fudgedDaysPer4000Years = 1461000L + 1
+    else:
+       daysPer400Years = 146097L
+       fudgedDaysPer4000Years = 1460970L + 31
+
+    z = _cdiv(4 * x, daysPer400Years)
+    x = x - _cdiv((daysPer400Years * z + 3), 4)
+    y = _cdiv(4000 * (x + 1), fudgedDaysPer4000Years)
+    x = x - _cdiv(1461 * y, 4) + 31
+    m = _cdiv(80 * x, 2447)
+    d = x - _cdiv(2447 * m, 80)
+    x = _cdiv(m, 11)
+    m = m + 2 - 12 * x
+    y = 100 * (z - 49) + y + x
+
+    # Convert from longs to integers.
+    yy = int(y)
+    mm = int(m)
+    dd = int(d)
+
+    if yy <= 0:
+       # Adjust BC years.
+           yy = yy - 1
+
+    return (yy, mm, dd)
+
+def stringtoreal(text, separator = '.'):
+    if separator != '.':
+       if string.find(text, '.') >= 0:
+           raise ValueError, 'invalid value: ' + text
+       index = string.find(text, separator)
+       if index >= 0:
+           text = text[:index] + '.' + text[index + 1:]
+    return string.atof(text)
diff --git a/Pmw/Pmw_1_2/lib/__init__.py b/Pmw/Pmw_1_2/lib/__init__.py
new file mode 100644 (file)
index 0000000..83d04e7
--- /dev/null
@@ -0,0 +1 @@
+# File to allow this directory to be treated as a python package.
diff --git a/Pmw/Pmw_1_2/tests/AboutDialog_test.py b/Pmw/Pmw_1_2/tests/AboutDialog_test.py
new file mode 100644 (file)
index 0000000..bf6278f
--- /dev/null
@@ -0,0 +1,59 @@
+# Based on iwidgets2.2.0/tests/messagedialog.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+Pmw.aboutversion('1.0')
+Pmw.aboutcopyright('Copyright Really Good Software')
+Pmw.aboutcontact('For information about this application contact\nyour' +
+       'system administrator')
+
+c = Pmw.AboutDialog
+
+kw_1 = {
+    'applicationname' : 'Really Good Application',
+    'buttonbox_padx': 30,
+}
+tests_1 = (
+  (Test.num_options, (), 14),
+  ('message_anchor', 'center'),
+  ('message_justify', 'center'),
+  ('message_wraplength', 0),
+  ('hull_background', '#d9d9d9'),
+  ('icon_bitmap', 'warning'),
+  ('hull_cursor', 'gumby'),
+  ('icon_image', Test.flagup),
+  ('message_font', Test.font['variable']),
+  ('message_foreground', 'red'),
+  ('message_padx', 15),
+  ('message_pady', 15),
+  ('icon_image', ''),
+  (c.title, 'AboutDialog 1: new title', ''),
+  (c.interior, (), Tkinter.Frame),
+  (Pmw.aboutcontact, ''),
+)
+
+kw_2 = {
+    'applicationname' : 'Another Really Good Application',
+    'buttonboxpos': 'e',
+    'iconpos': 'n',
+    'borderx': 15,
+    'bordery': 15,
+    'separatorwidth': 5,
+}
+tests_2 = (
+  (c.title, 'AboutDialog 2', ''),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/All.py b/Pmw/Pmw_1_2/tests/All.py
new file mode 100755 (executable)
index 0000000..d136174
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+import os
+import re
+import sys
+import Tkinter
+
+import Test
+Test.initialise()
+
+# Uncomment these to modify period between tests and how much output
+# to print:
+#Test.setdelay(1000)
+#Test.setverbose(1)
+
+# Ignore Tkinter test since it does not test any Pmw functionality
+# (only Tkinter) and it fails under MS-Windows 95 (and it hasn't been
+# kept up-to-date with changes to Tk.
+ignoreTests = ('Tkinter_test.py',)
+
+# Also ignore Blt test since it causes Blt 2.4z to core dump.
+if Tkinter.TkVersion >= 8.4:
+    ignoreTests = ignoreTests + ('Blt_test.py',)
+
+allTestData = ()
+files = os.listdir(os.curdir)
+files.sort()
+
+for file in files:
+    if file not in ignoreTests and re.search('^.+_test.py$', file) is not None:
+       test = file[:-3]
+       exec 'import ' + test
+       exec 'allTestData = allTestData + ' + test + '.testData'
+
+Test.runTests(allTestData)
diff --git a/Pmw/Pmw_1_2/tests/Blt_test.py b/Pmw/Pmw_1_2/tests/Blt_test.py
new file mode 100644 (file)
index 0000000..c7f2cdb
--- /dev/null
@@ -0,0 +1,356 @@
+# Tests for Blt widgets.
+
+import os
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+testData = ()
+
+# Blt vector type
+
+def _setVectorItem(index, value):
+    w = Test.currentWidget()
+    w[index] = value
+
+def _getVectorItem(index):
+    w = Test.currentWidget()
+    return w[index]
+
+def _getVectorSlice(index1, index2):
+    w = Test.currentWidget()
+    return w[index1:index2]
+
+def _delVectorItem(index):
+    w = Test.currentWidget()
+    del w[index]
+
+def _vectorExpr(instanceMethod):
+    w = Test.currentWidget()
+    name = '::' + str(w)
+    if instanceMethod:
+        w.expr(name + '+ 0.5')
+    else:
+        return Pmw.Blt.vector_expr(name + '* 2')
+
+def _vectorNames():
+    name = '::' + str(Test.currentWidget())
+    names = Pmw.Blt.vector_names()
+    if name not in names:
+        return names
+    name2 = Pmw.Blt.vector_names(name)
+    if name2 != (name,):
+        return name2
+    return None
+
+if Test.haveBlt():
+    c = Pmw.Blt.Vector
+    tests = (
+      (c.set, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+      (c.__repr__, (), '[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]'),
+      (c.set, ((1, 2, 3, 4, 5, 6, 7, 8, 9, 10),)),
+      (c.__repr__, (), '[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]'),
+      (c.__str__, (), 'PY_VEC4'),
+      (_getVectorItem, 7, 8),
+      (_getVectorSlice, (3, 6), [4.0, 5.0, 6.0]),
+      (_delVectorItem, 9),
+      (c.get, (), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]),
+      (c.append, 10),
+      (c.get, (), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]),
+      (c.length, (), 10),
+      (c.append, 5),
+      (c.__len__, (), 11),
+      (c.count, 5, 2),
+      (c.count, 20, 0),
+      (c.search, 5, (4, 10)),
+      (c.search, 20),
+      (c.index, 5, 4),
+      # Commented tests do not work because of a bug in the blt vector command.
+      # (c.clear, ()),
+      (_getVectorItem, 4, 5),
+      #(c.remove, 5),     # This causes a core in blt 2.4 under Solaris 2.5
+      #(c.index, 5, 9),
+      (c.min, (), 1.0),
+      (c.max, (), 10.0),
+      # (c.reverse, ()),
+      # (c.reverse, ()),
+      # (c.get, (), [1.0, 2.0, 3.0, 4.0, 6.0, 7.0, 8.0, 9.0, 10.0, 5.0]),
+      # (c.insert, (3, 66)),
+      # (c.search, 66, (3,)),
+      (c.get, (), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 5.0]),
+      (c.blt_sort, ()),
+      (c.get, (), [1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]),
+      (c.blt_sort_reverse, ()),
+      (c.get, (), [10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 5.0, 4.0, 3.0, 2.0, 1.0]),
+      (_setVectorItem, (7, 77)),
+      (c.search, 77, (7,)),
+      (_setVectorItem, (2, 77)),
+      (c.search, 77, (2, 7)),
+      (_setVectorItem, (11, 77), 'TclError: can\'t set "PY_VEC4(11)": index "11" is out of range'),
+      (c.get, (), [10.0, 9.0, 77.0, 7.0, 6.0, 5.0, 5.0, 77.0, 3.0, 2.0, 1.0]),
+      (c.delete, (1, 3, 5)),
+      (c.get, (), [10.0, 77.0, 6.0, 5.0, 77.0, 3.0, 2.0, 1.0]),
+      (c.length, (), 8),
+      (c.length, (9), 9),
+      (c.get, (), [10.0, 77.0, 6.0, 5.0, 77.0, 3.0, 2.0, 1.0, 0.0]),
+      (c.range, (1, 3), [77.0, 6.0, 5.0]),
+      (_vectorExpr, 0, (20.0, 154.0, 12.0, 10.0, 154.0, 6.0, 4.0, 2.0, 0.0)),
+      (_vectorExpr, 1),
+      (c.get, (), [10.5, 77.5, 6.5, 5.5, 77.5, 3.5, 2.5, 1.5, 0.5]),
+      (_vectorNames, ()),
+    )
+    testData = testData + ((c, ((tests, {}),)),)
+
+    tests = (
+      (c.get, (), [0.0, 0.0, 0.0, 0.0]),
+      (c.length, (), 4),
+    )
+    testData = testData + ((c, ((tests, {'size' : 4}),)),)
+
+    tests = (
+      # (c.get, (), [0.0, 0.0, 0.0]),  Does not work.
+      (c.length, (), 3),
+      (_getVectorItem, 2, 0),
+      (_getVectorItem, 4, 0),
+      (_getVectorItem, 5, 'IndexError: 5'),
+    )
+    testData = testData + ((c, ((tests, {'size' : '2:4'}),)),)
+
+#=============================================================================
+
+# Blt graph widget
+
+def _axisCommand(graph, value):
+  return 'XX ' + value
+
+def _createMarkerButton():
+    w = Test.currentWidget()
+    button = Tkinter.Button(w, text = 'This is\na button')
+    w.marker_create('window', coords=(10, 200), window=button)
+
+def _axisNamesSorted(pattern = None):
+    w = Test.currentWidget()
+    if pattern is None:
+        names = list(w.axis_names())
+    else:
+        names = list(w.axis_names(pattern))
+    names.sort()
+    return tuple(names)
+
+def _penNamesSorted(pattern = None):
+    w = Test.currentWidget()
+    if pattern is None:
+        names = list(w.pen_names())
+    else:
+        names = list(w.pen_names(pattern))
+    names.sort()
+    return tuple(names)
+
+if Test.haveBlt():
+    c = Pmw.Blt.Graph
+    tests = (
+      ('height', 700),
+      ('width', 900),
+      (c.pack, (), {'fill': 'both', 'expand': 1}),
+
+      (Test.num_options, (), 43),
+      (c.pen_create, 'pen1', {'fill': 'green', 'symbol': 'circle'}),
+      (c.line_create, 'line1', {'xdata': (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 'ydata': (7, 2, 1, 4, 7, 3, 9, 3, 8, 5), 'pen': 'pen1',}),
+      (c.bar_create, 'bar1', {'xdata': Test.vector_x, 'ydata': Test.vector_y[0], 'foreground': 'blue'}),
+      (c.bar_create, 'bar2', {'xdata': Test.vector_x, 'ydata': Test.vector_y[1], 'foreground': 'magenta'}),
+      (c.line_create, 'line2', {'xdata': Test.vector_x, 'ydata': Test.vector_y[2], 'color': 'red'}),
+
+      (c.marker_create, 'text', {'coords': (25, 200), 'rotate': 45, 'text':
+       'This is\na marker', 'name': 'myMarker1'}, 'myMarker1'),
+      (c.marker_create, 'line', {'coords': (35, 120, 15, 280), 'linewidth': 4}, 'marker1'),
+      (c.marker_create, 'polygon', {'coords': (35, 40, 45, 40, 45, 120, 35, 120), 'linewidth': 4}, 'marker2'),
+      (c.marker_create, 'bitmap', {'coords': (25, 200), 'rotate': 45, 'bitmap': 'questhead'}, 'marker3'),
+      (_createMarkerButton, ()),
+
+      (c.marker_after, 'myMarker1'),
+      (c.marker_before, ('myMarker1', 'marker3')),
+      (c.marker_create, 'text', {'coords': (10, 10), 'text':
+       'Bye', 'name': 'myMarker2'}, 'myMarker2'),
+      (c.marker_names, 'my*', ('myMarker1', 'myMarker2')),
+      (c.marker_exists, 'myMarker2', 1),
+      (c.marker_delete, ('myMarker1', 'myMarker2', 'marker3')),
+      (c.marker_exists, 'myMarker2', 0),
+      (c.marker_names, (), ('marker1', 'marker2', 'marker4')),
+      (c.marker_type, 'marker1', 'line'),
+
+      (c.marker_cget, ('marker1', 'linewidth'), '4'),
+      (c.marker_cget, ('marker2', 'linewidth'), '4'),
+      (c.marker_configure, (('marker1', 'marker2'),), {'linewidth': 5}),
+      (c.marker_cget, ('marker1', 'linewidth'), '5'),
+      (c.marker_cget, ('marker2', 'linewidth'), '5'),
+
+      ('background', '#ffdddd'),
+      ('barmode', 'stacked'),
+      ('barwidth', 0.5),
+      ('borderwidth', 100),
+      ('borderwidth', 10),
+      ('barwidth', 0.9),
+      ('bottommargin', 100),
+      ('bufferelements', 1),
+      ('cursor', 'watch'),
+      ('font', Test.font['variable']),
+      ('foreground', 'blue'),
+      ('halo', 20),
+      ('barmode', 'aligned'),
+      ('invertxy', 1),
+      ('justify', 'left'),
+      ('leftmargin', 100),
+      ('plotbackground', 'aquamarine'),
+      ('plotborderwidth', 4),
+      ('plotrelief', 'groove'),
+      ('relief', 'ridge'),
+      ('rightmargin', 100),
+      ('takefocus', '0'),
+      ('tile', Test.earthris),
+      ('barmode', 'infront'),
+      ('title', 'Hello there\nmy little lovely'),
+      ('topmargin', 100),
+      ('invertxy', 0),
+
+      # Change colours so that axis and legend are visible against image tile.
+      (c.xaxis_configure, (), {'color': 'green'}),
+      (c.yaxis_configure, (), {'color': 'green'}),
+      (c.legend_configure, (), {'background': '#ffffcc'}),
+
+      (c.axis_cget, ('x', 'color'), 'green'),
+      (c.axis_configure, ('x2'), {'color': 'red'}),
+      (c.axis_cget, ('x2', 'color'), 'red'),
+      (c.axis_create, 'myaxis', {'rotate': 45}),
+      (c.axis_cget, ('myaxis', 'rotate'), '45.0'),
+      (_axisNamesSorted, (), ('myaxis', 'x', 'x2', 'y', 'y2')),
+      (_axisNamesSorted, ('*x*'), ('myaxis', 'x', 'x2')),
+      # Blt 2.4u returns the empty string for the axis use command
+      # (c.y2axis_use, 'myaxis', 'myaxis'),
+      (c.axis_delete, 'myaxis'),
+
+      (c.extents, 'leftmargin', 100),
+      (c.inside, (1000, 1000), 0),
+      (c.inside, (400, 400), 1),
+      (c.snap, Test.emptyimage),
+
+      (c.element_bind, ('line1', '<1>', Test.callback), Test.callback),
+      (c.element_bind, 'line1', ('<Button-1>',)),
+      (c.legend_bind, ('line1', '<1>', Test.callback), Test.callback),
+      (c.legend_bind, 'line1', ('<Button-1>',)),
+      (c.marker_bind, ('marker1', '<1>', Test.callback), Test.callback),
+      (c.marker_bind, 'marker1', ('<Button-1>',)),
+
+      (c.pen_create, 'mypen', {'type' : 'bar', 'foreground': 'red'}),
+      (c.pen_cget, ('mypen', 'foreground'), 'red'),
+      (c.pen_configure, ('mypen'), {'foreground': 'green'}),
+      (c.pen_cget, ('mypen', 'foreground'), 'green'),
+      (_penNamesSorted, (), ('activeBar', 'activeLine', 'mypen', 'pen1')),
+      (_penNamesSorted, ('*pen*'), ('mypen', 'pen1')),
+      (c.pen_delete, 'mypen'),
+
+      # These tests are not portable
+      # (c.invtransform, (0, 0), (-10.2518, 507.203)),
+      # (c.transform, (-10.2518, 507.203), (0.0, 0.0)),
+
+      # Reset margins to automatic
+      ('bottommargin', 0),
+      ('leftmargin', 0),
+      ('rightmargin', 0),
+      ('topmargin', 0),
+
+      (c.crosshairs_configure, (), {'hide': 0}),
+      (c.crosshairs_configure, (), {'position': '@300,300'}),
+      (c.crosshairs_configure, (), {'color': 'seagreen4'}),
+      (c.crosshairs_toggle, ()),
+      (c.crosshairs_cget, 'hide', 1),
+      (c.crosshairs_configure, (), {'dashes': (4, 8, 8, 8)}),
+      (c.crosshairs_configure, (), {'linewidth': 4}),
+      (c.crosshairs_toggle, ()),
+      (c.crosshairs_cget, 'hide', 0),
+      (c.crosshairs_off, ()),
+      (c.crosshairs_cget, 'hide', 1),
+      (c.crosshairs_on, ()),
+      (c.crosshairs_cget, 'hide', 0),
+
+      # Blt 2.4u gives an error with this (looks like activeBar
+      # is same as activeLine):
+      # (c.pen_configure, 'activeBar', {'foreground': '#ffffaa'}),
+
+      (c.element_configure, 'bar2', {'foreground': '#ffffaa'}),
+      # Blt 2.4u segmentation faults around here, remove tests:
+      # (c.element_activate, 'bar1'),
+      # (c.element_activate, 'bar2'),
+      # (c.element_deactivate, ('bar1', 'bar2')),
+      # (c.element_deactivate, ()),
+      # (c.element_activate, ('bar2',) + tuple(range(Test.vectorSize / 2))),
+      (c.element_configure, 'bar1', {'ydata': Test.vector_y[1]}),
+      (c.element_configure, 'bar2', {'ydata': Test.vector_y[0]}),
+
+      (c.element_cget, ('bar1', 'barwidth'), '0.0'),
+      (c.element_cget, ('bar2', 'barwidth'), '0.0'),
+      (c.element_configure, (('bar1', 'bar2'),), {'barwidth': 0.5}),
+      (c.element_cget, ('bar1', 'barwidth'), '0.5'),
+      (c.element_cget, ('bar2', 'barwidth'), '0.5'),
+
+      # These tests are not portable
+      # (c.element_closest, (330, 430), {}, {'x': 18.0, 'dist': 17.0, 'name': 'bar1', 'index': 18, 'y': 156.0}),
+      # (c.element_closest, (0, 0)),
+      # (c.element_closest, (0, 0), {'halo': 500}, {'x': 0.0, 'dist': 154.797, 'name': 'line2', 'index': 0, 'y': 359.0}),
+      # (c.element_closest, (0, 0), {'halo': 500, 'interpolate': 1}, {'x': -0.0320109, 'dist': 154.797, 'name': 'line2', 'index': 0, 'y': 358.879}),
+
+      (c.element_type, 'bar2', 'bar'),
+      (c.element_type, 'line2', 'line'),
+
+      (c.legend_activate, ('line1', 'bar2',)),
+      (c.legend_activate, ()),
+      (c.legend_deactivate, ('line1', 'bar2',)),
+      (c.legend_deactivate, ()),
+      (c.legend_configure, (), {'hide': 1}),
+      (c.legend_cget, 'hide', 1),
+      (c.legend_configure, (), {'hide': 0}),
+      (c.legend_configure, (), {'position': 'left', 'anchor': 'nw', 'ipadx': 100, 'ipady': 100}),
+      (c.legend_get, '@150,150', 'line1'),
+
+      # This probably works, but I haven't installed the prologue file
+      # (c.postscript_output, '/tmp/tmp.ps', {'landscape': 1}),
+      # (os.unlink, '/tmp/tmp.ps'),
+
+      (c.element_show, (), ('line2', 'bar2', 'bar1', 'line1')),
+      (c.element_show, (('line1', 'bar1'),), ('line1', 'bar1')),
+      (c.element_names, (), ('line1', 'line2', 'bar1', 'bar2')),
+      (c.element_names, 'line*', ('line1', 'line2')),
+      (c.element_show, (('line1', 'line2', 'bar1', 'bar2'),), ('line1', 'line2', 'bar1', 'bar2')),
+      (c.element_exists, 'bar1', 1),
+      (c.element_delete, ('bar1', 'bar2')),
+      (c.element_names, (), ('line1', 'line2')),
+      (c.element_exists, 'bar1', 0),
+      (c.element_delete, ()),
+      (c.element_names, (), ('line1', 'line2')),
+
+      (c.grid_configure, (), {'hide': 0}),
+      (c.grid_toggle, ()),
+      (c.grid_cget, 'hide', 1),
+      (c.grid_on, ()),
+      (c.grid_cget, 'hide', 0),
+      (c.grid_off, ()),
+
+      # These tests are not portable
+      # (c.xaxis_invtransform, 0, -37.1153),
+      # (c.axis_limits, 'x', (-0.98, 49.98)),
+      # (c.axis_transform, ('x', 0), 360),
+      # (c.axis_invtransform, ('y', 0), 444.198),
+      # (c.yaxis_limits, (), (-6.96, 406.96)),
+      # (c.axis_transform, ('y', 0), 620),
+      # (c.axis_invtransform, ('x2', 0), -25.1491),
+      # (c.axis_limits, 'x2', (-10.4, 10.4)),
+      # (c.x2axis_transform, 0, 598),
+      # (c.y2axis_invtransform, 0, 12.2713),
+      # (c.axis_limits, 'y2', (-10.4, 10.4)),
+      # (c.axis_transform, ('y2', 0), 341),
+    )
+    
+    testData = testData + ((c, ((tests, {}),)),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ButtonBox_test.py b/Pmw/Pmw_1_2/tests/ButtonBox_test.py
new file mode 100644 (file)
index 0000000..efd945d
--- /dev/null
@@ -0,0 +1,71 @@
+# Based on iwidgets2.2.0/tests/buttonbox.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ButtonBox
+
+kw_1 = {}
+tests_1 = (
+  (c.pack, ()),
+  (c.add, 'Yes', Tkinter.Button),
+  (c.add, 'No', Tkinter.Button),
+  (c.setdefault, 'Yes'),
+  (c.alignbuttons, ()),
+  (Test.num_options, (), 5),
+  ('Button_activebackground', '#ececec'),
+  ('Button_activeforeground', 'Black'),
+  ('hull_background', '#d9d9d9'),
+  ('hull_cursor', 'gumby'),
+  ('Button_background', 'aliceblue'),
+  ('Button_disabledforeground', '#a3a3a3'),
+  ('Button_foreground', 'Black'),
+  ('Button_highlightcolor', 'Black'),
+  ('Button_highlightthickness', 2),
+  (c.index, 0, 0),
+  (c.index, Pmw.END, 1),
+  (c.index, Pmw.DEFAULT, 0),
+  (c.index, 'No', 1),
+  (c.index, 'Yes', 0),
+  (c.add, 'Maybe', Tkinter.Button),
+  (c.insert, ('Never', 0), {'text' : 'Never Never'}, Tkinter.Button),
+  (c.setdefault, 'Never'),
+  (c.invoke, 'Yes', ''),
+  (c.invoke, (), ''),
+  (c.invoke, Pmw.DEFAULT, ''),
+  (c.delete, 'Maybe'),
+  ('Yes_text', 'YES'),
+  (c.index, 12, 'ValueError: index "12" is out of range'),
+  (c.index, 'bogus', 'ValueError: bad index "bogus": ' + \
+      'must be a name, a number, Pmw.END or Pmw.DEFAULT'),
+)
+
+kw_2 = {
+    'orient' : 'vertical',
+    'padx' : 30,
+    'pady' : 30,
+    'labelpos' : 'w',
+    'label_text' : 'Vertical\nButtonBox',
+}
+tests_2 = (
+  (c.pack, ()),
+  (c.add, 'Hello', Tkinter.Button),
+  (c.insert, ('GoodBye', Pmw.END), Tkinter.Button),
+  (c.setdefault, 'Hello'),
+  (c.setdefault, 'GoodBye'),
+  (c.setdefault, None),
+  (c.index, Pmw.DEFAULT, 'ValueError: ButtonBox has no default'),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/Colors_test.py b/Pmw/Pmw_1_2/tests/Colors_test.py
new file mode 100644 (file)
index 0000000..24c5dd9
--- /dev/null
@@ -0,0 +1,46 @@
+# Tests for Pmw color handling.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+testData = ()
+
+defaultPalette = Pmw.Color.getdefaultpalette(Test.root)
+
+c = Tkinter.Button
+
+colors = ('red', 'orange', 'yellow', 'green', 'blue', 'purple', 'white')
+normalcolors = map(Pmw.Color.changebrightness,
+       (Test.root,) * len(colors), colors, (0.85,) * len(colors))
+
+kw = {}
+tests = (
+  (Pmw.Color.setscheme, (Test.root, normalcolors[0]), {'foreground' : 'white'}),
+)
+testData = testData + ((c, ((tests, kw),)),)
+
+for color in normalcolors[1:]:
+    kw = {'text' : color}
+    tests = (
+      (c.pack, ()),
+      ('state', 'active'),
+    )
+    testData = testData + ((c, ((tests, kw),)),)
+
+    kw = {}
+    tests = (
+      (Pmw.Color.setscheme, (Test.root, color), {'foreground' : 'red'}),
+    )
+    testData = testData + ((c, ((tests, kw),)),)
+
+# Restore the default colors.
+kw = {}
+tests = (
+  (Pmw.Color.setscheme, (Test.root,), defaultPalette),
+)
+testData = testData + ((c, ((tests, kw),)),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ComboBox_test.py b/Pmw/Pmw_1_2/tests/ComboBox_test.py
new file mode 100644 (file)
index 0000000..a4ff3cc
--- /dev/null
@@ -0,0 +1,184 @@
+# Based on iwidgets2.2.0/tests/combobox.test code. 
+
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+if Tkinter.TkVersion >= 8.4:
+  expected1 = 'TclError: bad relief "bogus": must be '
+  expected2 = 'TclError: bad state "bogus": must be ' + \
+    'disabled, normal, or readonly'
+elif Tkinter.TkVersion >= 8.3:
+  expected1 = 'TclError: bad relief "bogus": must be '
+  expected2 = 'TclError: bad state "bogus": must be disabled or normal'
+else:
+  expected1 = 'TclError: bad relief type "bogus": must be '
+  expected2 = 'TclError: bad state value "bogus": must be normal or disabled'
+
+c = Pmw.ComboBox
+
+kw_1a = {
+  'labelpos' : 'w',
+  'label_text' : 'Label:',
+  'autoclear': 1,
+  'listheight': 250,
+  'scrolledlist_items': ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'),
+}
+
+kw_1b = {
+  'dropdown': 0,
+  'entry_state': 'disabled',
+  'selectioncommand' : Test.callback1,
+  'scrolledlist_items': ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'),
+  'listheight' : 200,
+  'label_text' : 'DropDown:',
+  'labelpos' : 'w',
+  'listbox_cursor' : 'hand1',
+  'unique' : 1
+}
+
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 11),
+  ('entry_width', 20),
+  ('entry_textvariable', Test.stringvar),
+  ('label_text', 'ComboBox:'),
+  ('label_image', Test.flagup),
+  ('label_image', ''),
+  ('entry_borderwidth', 10),
+  ('entry_borderwidth', 2),
+  ('hull_background', 'steelblue'),
+  ('entry_foreground', 'white'),
+  ('hull_background', 'grey85'),
+  ('entry_foreground', 'Black'),
+  ('entry_textvariable', ''),
+  ('entry_state', 'disabled'),
+  ('entry_state', 'normal'),
+  ('label_font', Test.font['variable']),
+  ('entry_font', Test.font['large']),
+  ('entry_font', Test.font['variable']),
+  (c.invoke, ()),
+  ('hull_cursor', ''),
+  ('entry_relief', 'raised'),
+  ('entry_relief', 'groove'),
+  ('entry_relief', 'flat'),
+  ('entry_relief', 'sunken'),
+  ('entry_exportselection', 1),
+  ('entry_exportselection', 0),
+  ('entryfield_invalidcommand', Test.bell),
+  ('listbox_cursor', 'hand1'),
+  ('listbox_cursor', 'hand2'),
+  ('entry_selectbackground', '#b2dfee'),
+  ('listbox_selectbackground', 'steelblue'),
+  ('entry_selectborderwidth', 1),
+  ('entry_selectforeground', 'Black'),
+  ('entry_background', 'white'),
+  ('entryfield_validate', 'alphabetic'),
+  (c.setentry, '1234', 0),
+  (c.get, (), 'this is some text'),
+  ('entryfield_validate', None),
+  ('scrolledlist_hscrollmode', 'dynamic'),
+  ('scrolledlist_hscrollmode', 'dynamic'),
+  ('scrolledlist_vscrollmode', 'dynamic'),
+  ('scrolledlist_vscrollmode', 'dynamic'),
+  ('entry_borderwidth', 'bogus', 'TclError: bad screen distance "bogus"'),
+  ('entry_cursor', 'bogus', 'TclError: bad cursor spec "bogus"'),
+  ('entry_exportselection', 'bogus',
+    'TclError: expected boolean value but got "bogus"'),
+  ('scrolledlist_hscrollmode', 'bogus',
+    'ValueError: bad hscrollmode option "bogus": should be static, dynamic, ' +
+       'or none'),
+  ('listbox_cursor', 'bogus', 'TclError: bad cursor spec "bogus"'),
+  ('entry_relief', 'bogus', expected1 + Test.reliefs),
+  ('entry_selectborderwidth', 'bogus', 'TclError: bad screen distance "bogus"'),
+  ('entry_state', 'bogus', expected2),
+  ('entryfield_validate', 'bogus',
+    "ValueError: bad validate value \"bogus\":  must be a function or one of " +
+       "the standard validators ('alphabetic', 'alphanumeric', 'date', " +
+       "'hexadecimal', 'integer', 'numeric', 'real', 'time') or extra " +
+       "validators ()"),
+  ('scrolledlist_vscrollmode', 'bogus',
+    'ValueError: bad vscrollmode option "bogus": should be static, dynamic, ' +
+       'or none'),
+  ('entry_width', 'bogus', 'TclError: expected integer but got "bogus"'),
+  (c.interior, (), Tkinter.Frame),
+  (c.setentry, 'This is some text', 1),
+  (c.get, (), 'This is some text'),
+  (c.get, 2, 'C'),
+  (c.get, (2, 4), ('C', 'D', 'E')),
+  ('listbox_exportselection', 0),
+  (c.selectitem, 3),
+  (c.getcurselection, (), ('D',)),
+  (c.get, (), 'D'),
+  (c.selectitem, 'H'),
+  (c.getcurselection, (), ('H',)),
+  (c.get, (), 'H'),
+  (c.setentry, '', 1),
+  (c.size, (), 10),
+  (c.get, (), ''),
+  (c.delete, (0, 'end')),
+  (c.insert, (0, 'Test1', 'Test2', 'Test3', 'Test4')),
+  (c.insert, ('end', 'More Test')),
+  (c.size, (), 5),
+  (c.delete, (1),),
+  (c.delete, (0, 2)),
+  (c.size, (), 1),
+  (c.get, 0, 'More Test'),
+  (c.setentry, '', 1),
+  (c.get, (), ''),
+  (c.selectitem, 'More Test'),
+  (c.curselection, (), ('0',)),
+  (c.delete, (0, 'end')),
+  (c.size, (), 0),
+  (c.getcurselection, (), ()),
+  (c.insert, ('end', 'Test1', 'Test2', 'Really Long String Test')),
+  (c.size, (), 3),
+  (c.get, 0, 'Test1'),
+  (c.get, 2, 'Really Long String Test'),
+  (c.insert, (0, 'Test3', 'Test4', 'Really Long String Test')),
+  (c.size, (), 6),
+  (c.insert, (1, 'Test5', 'Test6', 'Really Long String Test')),
+  (c.size, (), 9),
+  (c.insert, (5, 'Test7', 'Test8', 'Really Long String Test')),
+  (c.size, (), 12),
+  (c.see, 0),
+  (c.see, 11),
+  (c.get, 'end', 'Really Long String Test'),
+  (c.selectitem, 5),
+  (c.curselection, (), ('5',)),
+  (c.clear, ()),
+  (c.get, (), ''),
+  (c.size, (), 0),
+)
+
+kw_2 = {
+  'fliparrow': 1,
+  'history': 1,
+  'buttonaspect': 0.5,
+  'arrowbutton_relief': 'groove',
+  'selectioncommand' : Test.callback,
+  'hull_background' : 'red',
+  'scrolledlist_items' : (123, 456, 789, 101112),
+  'listheight' : 50,
+  'label_text' : 'Numeric Simple:',
+  'labelpos' : 'w',
+  'entryfield_validate' : 'numeric',
+  'unique' : 0,
+}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+)
+
+alltests = (
+  (tests_1, kw_1a),
+  (tests_1, kw_1b),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/CounterDialog_test.py b/Pmw/Pmw_1_2/tests/CounterDialog_test.py
new file mode 100644 (file)
index 0000000..15e88ff
--- /dev/null
@@ -0,0 +1,98 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.CounterDialog
+
+kw_1 = {
+    'counter_labelpos': 'n',
+    'counter_buttonaspect': 2.0,
+    'counter_autorepeat': 0,
+    'counter_initwait': 1000,
+    'counter_padx': 5,
+    'counter_pady': 5,
+    'counter_repeatrate': 20,
+    'label_text' : 'Counter:',
+    'buttons' : ('OK', 'Cancel', 'Help'),
+}
+tests_1 = (
+    (Test.num_options, (), 11),
+    ('counter_Arrow_borderwidth', 10),
+    ('counter_hull_background', 'yellow'),
+    ('command', Test.callback1),
+    ('hull_cursor', 'gumby'),
+    ('counter_datatype', 'time'),
+    ('counter_datatype', 'numeric'),
+    ('entry_borderwidth', 6),
+    ('entry_relief', 'raised'),
+    ('entry_exportselection', 0),
+    ('entry_foreground', 'blue'),
+    ('hull_highlightcolor', 'Red'),
+    ('hull_highlightthickness', 2),
+    ('counter_increment', 1),
+    ('entry_insertbackground', 'Yellow'),
+    ('entry_insertbackground', 'Black'),
+    ('entry_insertborderwidth', 1),
+    ('entry_insertborderwidth', 0),
+    ('entry_insertofftime', 400),
+    ('entry_insertontime', 700),
+    ('entry_insertwidth', 3),
+    ('entryfield_invalidcommand', Test.callback),
+    ('entry_show', '*'),
+    ('entry_background', 'red'),
+    (c.setentry, '69', 1),
+    ('entry_justify', 'right'),
+    ('entry_justify', 'center'),
+    ('entry_justify', 'left'),
+    ('label_text', 'Label'),
+    ('entry_relief', 'raised'),
+    ('entry_relief', 'sunken'),
+    ('entry_state', 'disabled'),
+    ('entry_state', 'normal'),
+    ('entry_background', 'GhostWhite'),
+    ('entryfield_validate', 'numeric'),
+    ('entryfield_validate', 'alphabetic'),
+    ('entry_width', 30),
+    ('relief', 'bogus', 'KeyError: Unknown option "relief" for CounterDialog'),
+    (c.interior, (), Tkinter.Frame),
+    (c.insert, ('end', 69)),
+    (c.increment, ()),
+    (c.decrement, ()),
+    ('defaultbutton', 1),
+    (c.invoke, (), 'Cancel'),
+    (c.clear, ()),
+    (c.get, (), ''),
+    (c.insert, ('end', 'Test String')),
+    (c.get, (), 'Test String'),
+    (c.delete, (0, 'end')),
+    (c.insert, ('end', 'Another Test')),
+    (c.icursor, 'end'),
+    (c.index, 'end', 12),
+    (c.selection_from, 0),
+    (c.selection_to, 'end'),
+    (c.xview, '3'),
+    (c.clear, ()),
+)
+
+kw_2 = {
+    'buttonboxpos': 'e',
+    'counter_labelpos': 'w',
+    'label_text' : 'Another counter',
+    'buttonbox_pady': 25,
+    'buttons' : ('OK', 'Cancel'),
+}
+tests_2 = (
+    (c.title, 'CounterDialog 2', ''),
+)
+
+alltests = (
+    (tests_1, kw_1),
+    (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/Counter_test.py b/Pmw/Pmw_1_2/tests/Counter_test.py
new file mode 100644 (file)
index 0000000..53c39b8
--- /dev/null
@@ -0,0 +1,188 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.Counter
+
+_myValidators = {
+    'hello' : (lambda s: s == 'hello', len),
+}
+
+kw_1 = {
+    'labelpos' : 'w',
+    'label_text' : 'Counter:',
+    'buttonaspect': 2.0,
+    'autorepeat': 0,
+    'initwait': 1000,
+    'padx': 5,
+    'pady': 5,
+    'repeatrate': 20,
+    'entryfield_value': 'First value',
+}
+tests_1 = (
+    (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+    (c.get, (), 'First value'),
+    (Test.num_options, (), 12),
+    ('Arrow_borderwidth', 10),
+    ('hull_background', 'yellow'),
+    ('Arrow_background', 'green'),
+    ('label_background', 'blue'),
+    ('hull_borderwidth', 10),
+    ('entryfield_command', Test.callback),
+    ('entryfield_errorbackground', 'red'),
+    ('hull_cursor', 'gumby'),
+    ('datatype', 'time'),
+    ('datatype', 'numeric'),
+    ('entry_borderwidth', 6),
+    ('entry_relief', 'raised'),
+    ('entry_exportselection', 0),
+    ('entry_foreground', 'blue'),
+    ('hull_highlightcolor', 'Red'),
+    ('hull_highlightthickness', 2),
+    ('increment', 1),
+    ('entry_insertbackground', 'Yellow'),
+    ('entry_insertbackground', 'Black'),
+    ('entry_insertborderwidth', 1),
+    ('entry_insertborderwidth', 0),
+    ('entry_insertofftime', 400),
+    ('entry_insertontime', 700),
+    ('entry_insertwidth', 3),
+    ('entryfield_invalidcommand', Test.callback),
+    ('entry_show', '*'),
+    ('entry_background', 'red'),
+    (c.setentry, '69', Pmw.OK),
+    ('entry_show', ''),
+    ('entry_justify', 'right'),
+    ('entry_justify', 'center'),
+    ('entry_justify', 'left'),
+    ('label_text', 'Label'),
+    ('entry_relief', 'raised'),
+    ('entry_relief', 'sunken'),
+    ('entry_state', 'disabled'),
+    ('entry_state', 'normal'),
+    ('entry_background', 'GhostWhite'),
+    ('entryfield_validate', 'alphabetic'),
+    ('entryfield_validate', 'numeric'),
+    ('entry_width', 30),
+    ('relief', 'bogus', 'KeyError: Unknown option "relief" for Counter'),
+    (c.invoke, (), 1),
+    (c.interior, (), Tkinter.Frame),
+    (c.increment, ()),
+    (c.get, (), '70'),
+    ('increment', 5),
+    (c.get, (), '70'),
+    (c.decrement, ()),
+    (c.get, (), '65'),
+    (c.insert, ('end', 2)),
+    (c.get, (), '652'),
+    (c.invoke, (), 1),
+    (c.clear, ()),
+    (c.get, (), ''),
+    (c.insert, ('end', 'Test String')),
+    (c.get, (), 'Test String'),
+    (c.delete, (0, 'end')),
+    (c.insert, ('end', 'Another Test')),
+    (c.icursor, 'end'),
+    (c.index, 'end', 12),
+    (c.selection_from, 0),
+    (c.selection_to, 'end'),
+    (c.xview, '3'),
+    (c.clear, ()),
+    (c.insert, ('end', '100')),
+    ('entryfield_validate', {'validator' : 'real', 'min' : 10}),
+    (c.setentry, '50', Pmw.OK),
+    (c.setentry, 'hello', Pmw.ERROR),
+    ('entryfield_extravalidators', _myValidators),
+    ('entryfield_validate', 'hello'),
+    (c.setentry, 'hello', Pmw.OK),
+    (c.setentry, 'foo', Pmw.ERROR),
+    (c.valid, (), 1),
+    (c.cget, 'entry_background', 'GhostWhite'),
+    ('entry_textvariable', Test.stringvar),
+    (c.checkentry, (), 0),
+    (c.cget, 'entry_background', 'red'),
+    ('entryfield_validate', {'validator' : 'date', 'format' : 'dmy'}),
+    (c.valid, (), 0),
+    ('datatype', {'counter' : 'date', 'format' : 'dmy', 'yyyy' : 1}),
+    (c.setentry, '22/12/1999', Pmw.OK),
+    ('increment', 10),
+    (c.increment, ()),
+    (c.get, (), '01/01/2000'),
+
+    ('entryfield_validate', {'validator' : 'time', 'min' : '10:00:00'}),
+    (c.valid, (), 0),
+    ('increment', 60*60),
+    ('datatype', {'counter' : 'time'}),
+    (c.setentry, '11:00:00', Pmw.OK),
+    (c.decrement, ()),
+    (c.get, (), '10:00:00'),
+    (c.decrement, ()),
+    (c.get, (), '10:00:00'),
+
+    ('entryfield_validate', {'validator' : 'time', 'separator' : '.'}),
+    (c.valid, (), 0),
+    ('datatype', {'counter' : 'time', 'separator' : '.'}),
+    (c.setentry, '11.00.00', Pmw.OK),
+    (c.decrement, ()),
+    (c.get, (), '10.00.00'),
+
+    ('entryfield_validate', {'validator' : 'date', 'format' : 'dmy'}),
+    (c.valid, (), 0),
+    ('increment', 1),
+    ('datatype', {'counter' : 'date', 'format' : 'dmy'}),
+    (c.setentry, '25/12/99', Pmw.OK),
+    (c.decrement, ()),
+    (c.get, (), '24/12/99'),
+
+    ('entryfield_validate', {'validator' : 'date', 'separator' : '#@!',
+            'max' : '99#@!12#@!26'}),
+    (c.valid, (), 0),
+    ('datatype', {'counter' : 'date', 'separator' : '#@!'}),
+    (c.setentry, '99#@!12#@!25', Pmw.OK),
+    (c.increment, ()),
+    (c.get, (), '99#@!12#@!26'),
+    ('increment', 10),
+    (c.increment, ()),
+    (c.get, (), '99#@!12#@!26'),  # max exceeded
+    ('entryfield_validate', {'validator' : 'date', 'separator' : '#@!',
+            'max' : '00#@!01#@!10'}),
+    (c.increment, ()),
+    (c.get, (), '00#@!01#@!05'),  # max not exceeded
+    ('increment', 1),
+
+    ('entryfield_validate', {'validator' : 'date', 'format' : 'ymd',
+        'separator' : '-' }),
+    (c.valid, (), 0),
+    ('datatype', {'counter' : 'date', 'format' : 'ymd', 'yyyy' : 1,
+        'separator' : '-' }),
+    (c.setentry, '1999-12-22', 1),
+    ('increment', 10),
+    (c.increment, ()),
+    (c.get, (), '2000-01-01'),
+    ('increment', 1),
+)
+
+tests_2 = (
+    (c.pack, (), {'padx' : 10, 'pady' : 10}),
+)
+
+alltests = [(tests_1, kw_1)]
+
+poslist = ('nw', 'n', 'ne', 'en', 'e', 'es', 'se', 's', 'sw', 'ws', 'w', 'wn',)
+for count in range(len(poslist)):
+    pos = poslist[count]
+    margin = count * 10
+    kw_2 = {
+      'entry_width' : 12,
+      'labelpos' : pos,
+      'labelmargin' : margin,
+      'label_text' : 'Counter:',
+    }
+    alltests.append((tests_2, kw_2))
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/Dialog_test.py b/Pmw/Pmw_1_2/tests/Dialog_test.py
new file mode 100644 (file)
index 0000000..d309acc
--- /dev/null
@@ -0,0 +1,122 @@
+# Based on iwidgets2.2.0/tests/dialog.test code.   
+
+import sys
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+if Tkinter.TkVersion >= 8.3:
+  version = sys.version_info
+  if version[0] > 2 or (version[0] == 2 and version[1] > 0):
+      expected1 = "AttributeError: Dialog instance has no attribute 'bogus'"
+  else:
+      expected1 = "AttributeError: 'Dialog' instance has no attribute 'bogus'"
+else:
+  expected1 = 'AttributeError: bogus'
+
+c = Pmw.Dialog
+
+def _addListbox():
+    global _lb
+    w = Test.currentWidget()
+    _lb = Tkinter.Listbox(w.interior(), relief = 'sunken')
+    _lb.pack(fill = 'both', expand = 'yes')
+
+def _addListEntry(text):
+    _lb.insert('end', text)
+
+def _test_deactivate(result):
+    w = Test.currentWidget()
+    w.after(Test.delay() + 4000,
+        lambda widget=w, r=result: widget.deactivate(r))
+
+def _createOtherToplevel():
+    global tempToplevel
+    Test.root.deiconify()
+    Test.root.geometry('+0+0')
+    tempToplevel = Tkinter.Toplevel()
+    tempToplevel.geometry('+0+0')
+    label = Tkinter.Label(tempToplevel, text =
+        'The cursor should turn to a\n' +
+        'clock over this window if the\n' +
+       'blt busy command is available.\n' +
+       'In any case, the button will be inactive\n' +
+       'while the modal dialog is active.')
+    label.pack(padx=100, pady=100)
+    button = Tkinter.Button(tempToplevel, text = 'Try to press me')
+    button.pack(pady=100, expand=1)
+
+def _hideOtherToplevel():
+    global tempToplevel
+    tempToplevel.withdraw()
+    Test.root.withdraw()
+
+def _bogus():
+    w = Test.currentWidget()
+    w.bogus()
+
+kw_1 = {
+  'buttons' : (),
+  'buttonbox_padx': 30,
+}
+tests_1 = (
+  ('buttons', ('OK',)),
+  ('buttons', ('OK', 'Cancel',)),
+  ('defaultbutton', 'OK'),
+  (_addListbox, ()),
+  (Test.num_options, (), 9),
+  ('hull_background', '#d9d9d9'),
+  ('buttons', ('A', 'B', 'C', 'D')),
+  ('hull_cursor', 'gumby'),
+  (c.title, 'Dialog Shell', ''),
+  (c.interior, (), Tkinter.Frame),
+  ('buttons', ()),
+  ('buttons', ('OK',)),
+  ('buttons', ('OK', 'Cancel')),
+  ('buttons', ('OK', 'Cancel', 'Help')),
+  ('defaultbutton', 'OK'),
+  ('buttons', ('Apply', 'OK', 'Cancel', 'Help')),
+  ('buttons', ('Apply', 'OK', 'Cancel')),
+  ('defaultbutton', 'Cancel'),
+  (c.invoke, 'OK', 'None'),
+  ('buttonbox_OK_text', 'OOOOOKKKKK'),
+  (c.show, ()),
+  (c.withdraw, (), ''),
+  ('buttons', ('Apply', 'OK', 'Cancel', 'Foo')),
+  ('buttons', ('Apply', 'OK', 'Cancel')),
+  (c.show, ()),
+  (c.withdraw, (), ''),
+  (_createOtherToplevel, ()),
+  (_addListEntry, 'Testing application activate/deactivate'),
+  (_addListEntry, 'Please wait'),
+  (_test_deactivate, 'Hello World'),
+  (c.activate, (), 'Hello World'),
+  ('defaultbutton', ''),
+  (_addListEntry, 'Now testing global activate/deactivate'),
+  (_addListEntry, 'Please wait a bit more'),
+  (_test_deactivate, 'Hello World'),
+  (c.activate, (1), 'Hello World'),
+  (_hideOtherToplevel, ()),
+  ('buttons', ('Apply', 'OK', 'Cancel', 'Foo', '1')),
+  (c.show, (), {}),
+  (_bogus, (), expected1),
+)
+
+kw_2 = {'buttonboxpos' : 'e', 'separatorwidth' : 5}
+tests_2 = (
+  ('buttons', ('OK',)),
+  ('buttons', ('OK', 'Cancel',)),
+  ('defaultbutton', 'OK'),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/EntryField_test.py b/Pmw/Pmw_1_2/tests/EntryField_test.py
new file mode 100644 (file)
index 0000000..8d9c52e
--- /dev/null
@@ -0,0 +1,109 @@
+# Based on iwidgets2.2.0/tests/entryfield.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+_myValidators = {
+    'hello' : (lambda s: s == 'hello', len),
+}
+
+c = Pmw.EntryField
+
+kw_1 = {'entry_width' : 12, 'labelpos' : 'n', 'label_text' : 'Entry Field:'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 10),
+  ('errorbackground', 'red'),
+  ('hull_background', 'yellow'),
+  ('label_background', 'yellow'),
+  ('entry_background', 'yellow'),
+  ('hull_show', 'X', 'TclError: unknown option "-show"'),
+  ('entry_show', ''),
+  ('entry_borderwidth', 4),
+  ('entry_borderwidth', 2),
+  ('command', Test.callback),
+  ('hull_cursor', 'gumby'),
+  ('entry_exportselection', 0),
+  ('label_foreground', 'Green'),
+  ('entry_foreground', 'Green'),
+  ('label_foreground', 'Black'),
+  ('entry_foreground', 'Black'),
+  ('label_highlightcolor', 'Red'),
+  ('entry_highlightcolor', 'Red'),
+  ('entry_highlightthickness', 2),
+  ('entry_insertbackground', 'Yellow'),
+  ('entry_insertbackground', 'Black'),
+  ('entry_insertborderwidth', 1),
+  ('entry_insertborderwidth', 0),
+  ('entry_insertofftime', 400),
+  ('entry_insertontime', 700),
+  ('entry_insertwidth', 3),
+  ('invalidcommand', Test.callback),
+  ('entry_justify', 'right'),
+  ('entry_justify', 'center'),
+  ('entry_justify', 'left'),
+  ('label_text', 'Label'),
+  ('entry_relief', 'raised'),
+  ('entry_relief', 'sunken'),
+  ('entry_state', 'disabled'),
+  ('entry_state', 'normal'),
+  ('entry_background', 'GhostWhite'),
+  ('validate', 'numeric'),
+  ('validate', 'alphabetic'),
+  ('entry_width', 30),
+  ('validate', 'bogus',
+    "ValueError: bad validate value \"bogus\":  must be a function or one " +
+       "of the standard validators ('alphabetic', 'alphanumeric', 'date', " +
+       "'hexadecimal', 'integer', 'numeric', 'real', 'time') or extra " +
+       "validators ()"),
+  ('relief', 'bogus', 'KeyError: Unknown option "relief" for EntryField'),
+  (c.invoke, (), 1),
+  (c.interior, (), Tkinter.Frame),
+  (c.clear, ()),
+  (c.get, (), ''),
+  (c.insert, ('end', 'Test String')),
+  (c.get, (), 'Test String'),
+  (c.delete, (0, 'end')),
+  (c.insert, ('end', 'Another Test')),
+  (c.icursor, 'end'),
+  (c.index, 'end', 12),
+  (c.selection_from, 0),
+  (c.selection_to, 'end'),
+  (c.xview, '3'),
+  (c.clear, ()),
+  (c.insert, ('end', '100')),
+  ('validate', {'validator' : 'real', 'min' : 10}),
+  (c.setentry, '50', 1),
+  (c.setentry, 'hello', 0),
+  ('extravalidators', _myValidators),
+  ('validate', 'hello'),
+  (c.setentry, 'hello', 1),
+  (c.setentry, 'foo', 0),
+  (c.valid, (), 1),
+  (c.cget, 'entry_background', 'GhostWhite'),
+  ('entry_textvariable', Test.stringvar),
+  (c.checkentry, (), 0),
+  (c.cget, 'entry_background', 'red'),
+)
+
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10}),
+)
+
+alltests = [(tests_1, kw_1)]
+
+poslist = ('nw', 'n', 'ne', 'en', 'e', 'es', 'se', 's', 'sw', 'ws', 'w', 'wn',)
+for pos in poslist:
+  kw_2 = {
+    'labelpos' : pos,
+    'label_text' : 'Entry Field',
+  }
+  alltests.append((tests_2, kw_2))
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/LabeledWidget_test.py b/Pmw/Pmw_1_2/tests/LabeledWidget_test.py
new file mode 100644 (file)
index 0000000..0ac7462
--- /dev/null
@@ -0,0 +1,49 @@
+# Based on iwidgets2.2.0/tests/labeledwidget.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.LabeledWidget
+
+def _addListbox():
+    w = Test.currentWidget()
+    lb = Tkinter.Listbox(w.interior(), relief = 'sunken')
+    lb.pack(padx = 10, pady = 10)
+
+def _testalignLabels():
+    w = Test.currentWidget()
+    return Pmw.alignlabels((w,))
+
+kw_1 = {'labelpos': 'nw'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (_addListbox, ()),
+  (Test.num_options, (), 3),
+  ('label_textvariable', Test.stringvar),
+  ('label_textvariable', ''),
+  ('label_text', 'Label'),
+  ('label_font', Test.font['small']),
+  ('label_image', Test.flagup),
+  ('label_image', ''),
+  (c.interior, (), Tkinter.Frame),
+  (_testalignLabels, (), None),
+)
+
+kw_2 = {'label_text' : 'ListBox', 'labelpos' : 's'}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (_addListbox, ()),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ManualTests.py b/Pmw/Pmw_1_2/tests/ManualTests.py
new file mode 100755 (executable)
index 0000000..94d31b2
--- /dev/null
@@ -0,0 +1,488 @@
+#!/bin/env python
+
+# This is a rough collection of tests that can not be automated.
+# To add a new test, create a function with name ending in '_test'.
+
+import os
+import string
+import time
+import sys
+import Test
+import Tkinter
+import Pmw
+
+# ----------------------------------------------------------------------
+
+def scrolledframeflashing_test():
+    # Script which demonstrates continuous flashing of dynamic scrollbars
+    # in Pmw.ScrolledFrame.
+    #
+    # When this script is run, the two scrollbars will be continuously
+    # mapped and unmapped and the window will continuously change size.
+
+    frame = Tkinter.Frame(root)
+    frame.pack(fill = 'both', expand = 1)
+
+    sf = Pmw.ScrolledFrame(frame, borderframe = 0)
+    sf.pack(fill = 'both', expand = 1)
+
+    inner = Tkinter.Frame(sf.interior(),
+            width = 401,
+            height = 300,
+            borderwidth = 0,
+            highlightthickness = 0,
+    )
+    inner.pack(fill = 'both', expand = 1)
+
+# ----------------------------------------------------------------------
+
+def scrolledlistboxflashing_test():
+    # Script which demonstrates continuous flashing of dynamic scrollbars
+    # in Pmw.ScrolledListBox.
+    #
+    # When this script is run, the two scrollbars will be continuously
+    # mapped and unmapped and the window will continuously change size.
+
+    frame = Tkinter.Frame(root)
+    frame.pack(fill = 'both', expand = 1)
+
+    sf = Pmw.ScrolledListBox(frame,
+            listbox_width = 20,
+            listbox_height = 10
+    )
+    sf.pack(fill = 'both', expand = 1)
+    for i in range(11):
+        sf.insert('end', '2' * 20)
+
+# ----------------------------------------------------------------------
+
+def scrolledlistboxflashing2_test():
+    # Another script which demonstrates continuous flashing of dynamic
+    # scrollbars in Pmw.ScrolledListBox under Pmw.0.8.
+    #
+    # When this script is run, the two scrollbars will be continuously
+    # mapped and unmapped and the window will continuously change size.
+    #
+    # (This did not display error when tried with Pmw.0.8, 99/8/3)
+
+    def insert():
+        sectionList = ['1', '2', '3', '4', '5', '6', '7', '8', '9',
+            '123456789012345678901']
+        for counter in sectionList: 
+          slb.insert('end', counter)
+          
+    def clear():
+        slb.delete(0, 'end')
+        
+    global slb
+    slb = Pmw.ScrolledListBox(root)
+    slb.pack()
+
+    root.after(2000,insert)
+    root.after(3000,clear) 
+    root.after(4000,insert)
+
+    root.geometry('400x400')
+
+# ----------------------------------------------------------------------
+
+def scrolledtextflashing_test():
+    # Script which demonstrates continuous flashing of dynamic scrollbars
+    # in Pmw.ScrolledText.
+    #
+    # When this script is run, the two scrollbars will be continuously
+    # mapped and unmapped and the window will continuously change size.
+
+    frame = Tkinter.Frame(root)
+    frame.pack(fill = 'both', expand = 1)
+
+    sf = Pmw.ScrolledText(frame,
+            text_width = 20,
+            text_height = 10,
+            text_wrap = 'none',
+            borderframe = 0
+    )
+    sf.pack(fill = 'both', expand = 1)
+    for i in range(11):
+        sf.insert('end', '2' * 20)
+        if i != 10:
+            sf.insert('end', '\n')
+
+# ----------------------------------------------------------------------
+
+def scrolledcanvasflashing_test():
+    # Script which demonstrates continuous flashing of dynamic scrollbars
+    # in Pmw.ScrolledCanvas.
+    #
+    # When this script is run, the two scrollbars will be continuously
+    # mapped and unmapped and the window will continuously change size.
+
+    frame = Tkinter.Frame(root)
+    frame.pack(fill = 'both', expand = 1)
+
+    sf = Pmw.ScrolledCanvas(frame,
+            canvas_scrollregion = (0, 0, 301, 200),
+            canvas_width=300,
+            canvas_height=200,
+            borderframe = 0
+    )
+    sf.pack(fill = 'both', expand = 1)
+
+# ----------------------------------------------------------------------
+
+def scrolledframeflashing2_test():
+    # The two scrollbars will be continuously mapped and unmapped, but
+    # the toplevel window will remain the same size.
+
+    root.geometry('550x500')
+
+    frame = Tkinter.Frame()
+    frame.pack()
+
+    sf = Pmw.ScrolledFrame(frame, borderframe = 0)
+    sf.pack(fill = 'both')
+
+    inner = Tkinter.Frame(sf.interior(),
+            width = 401,
+            height = 300,
+            borderwidth = 0,
+            highlightthickness = 0,
+    )
+    inner.pack()
+
+# ----------------------------------------------------------------------
+
+def reinitialise_test():
+    global text
+    text = """
+    Demonstrates bug in Pmw.0.8.1 and earlier.
+    Click on this button, click on OK in the dialog, then Exit below.
+    When this window appears again, clicking on this button gives
+    an error:
+    TclError: can't invoke "wm" command:  application has been destroyed
+    """
+    class test:
+        def __init__(self):
+            root = Tkinter.Tk()
+            Pmw.initialise(root)
+            self.messagedialog = Pmw.MessageDialog(message_text = 'Testing')
+            self.messagedialog.withdraw()
+            button = Tkinter.Button(
+                    text = text, command = self.messagedialog.activate)
+            button.pack(pady = 20)
+            exit = Tkinter.Button(text = 'Exit', command = root.destroy)
+            exit.pack(pady = 20)
+            root.mainloop()
+
+    test()
+    test()
+
+# ----------------------------------------------------------------------
+
+def componentgroup_test():
+    def addbutton(bb):
+        bb.configure(Button_background = 'yellow')
+        bb.add('Apples')
+        bb.after(3000, lambda bb = bb:
+                bb.configure(Button_background = 'green'))
+
+    bb = Pmw.ButtonBox(Button_background = 'red')
+    bb.add('Bananas')
+    bb.pack()
+
+    mb = Pmw.MenuBar(Button_background = 'red')
+    mb.configure(Button_background = 'yellow')
+    mb.pack()
+
+    pw = Pmw.PanedWidget(Frame_background = 'red')
+    pw.configure(Frame_background = 'yellow')
+    pw.pack()
+
+    rs = Pmw.RadioSelect(Button_background = 'red')
+    rs.configure(Button_background = 'yellow')
+    rs.pack()
+
+    bb.after(3000, lambda bb = bb, addbutton = addbutton: addbutton(bb))
+
+# ----------------------------------------------------------------------
+
+def balloon_test():
+
+    # TODO
+
+    # Test that the balloon does not reappear if the mouse button is
+    # pressed down inside a widget and then, while the mouse button is
+    # being held down, the mouse is moved outside of the widget and
+    # then moved back over the widget.
+
+    # Test that when a widget is destroyed while a balloon is being
+    # displayed for it then the balloon is withdrawn.
+
+    # Test that when a widget is destroyed while a balloon is being
+    # displayed for another widget then the balloon is not withdrawn.
+
+    # Test that there is no eror when a widget is destroyed during the
+    # initwait period (between when the mouse enters the widget and
+    # when the initwait timer goes off).
+
+    # Test that if unbind() is called on a widget that triggered the
+    # balloon to be displayed then the balloon is withdrawn.  Also
+    # test that if another widget triggered the balloon then the
+    # balloon is not withdrawn.
+
+    # Test that if tagunbind() is called on a canvas or text item that
+    # triggered the balloon to be displayed then the balloon is
+    # withdrawn.  Also test that if another widget or item triggered
+    # the balloon then the balloon is not withdrawn.
+
+    pass
+
+# ----------------------------------------------------------------------
+
+# A class which prints out a message when an instance is deleted.
+class MyToplevel(Tkinter.Toplevel):
+
+    def __init__(self):
+        Tkinter.Toplevel.__init__(self)
+
+    def __del__(self):
+        print 'Window deleted'
+
+def _runMemoryLeakTest():
+    global top
+    top = MyToplevel()
+    Pmw.MegaToplevel(top)
+    Pmw.AboutDialog(top)
+    Pmw.ComboBoxDialog(top)
+    Pmw.CounterDialog(top)
+    Pmw.Dialog(top)
+    Pmw.MessageDialog(top)
+    Pmw.PromptDialog(top)
+    Pmw.SelectionDialog(top)
+    Pmw.TextDialog(top)
+
+    Pmw.ButtonBox(top).pack()
+    Pmw.ComboBox(top).pack()
+    Pmw.Counter(top).pack()
+    Pmw.EntryField(top).pack()
+    Pmw.Group(top).pack()
+    Pmw.LabeledWidget(top).pack()
+    Pmw.MenuBar(top).pack()
+    Pmw.MessageBar(top).pack()
+    Pmw.NoteBook(top).pack()
+    Pmw.OptionMenu(top).pack()
+    Pmw.PanedWidget(top).pack()
+    Pmw.RadioSelect(top).pack()
+    Pmw.ScrolledCanvas(top).pack()
+    Pmw.ScrolledField(top).pack()
+    Pmw.ScrolledFrame(top).pack()
+    Pmw.ScrolledListBox(top).pack()
+    Pmw.ScrolledText(top).pack()
+    Pmw.TimeCounter(top).pack()
+
+def _killMemoryLeakTest():
+    global top
+    top.destroy()
+    del top
+
+memoryLeakMessage = """
+Click on the "Run test" button to create instances of
+all Pmw megawidgets. Then click on the "Destroy" button.
+The message "Window deleted" should be printed to
+standard output.
+"""
+def memoryleak_test():
+    label = Tkinter.Label(text = memoryLeakMessage)
+    label.pack()
+    run = Tkinter.Button(text = 'Run test', command = _runMemoryLeakTest)
+    run.pack()
+    kill = Tkinter.Button(text = 'Destroy', command = _killMemoryLeakTest)
+    kill.pack()
+
+# ----------------------------------------------------------------------
+
+def memoryleak2_test():
+
+    print 'This test continuously creates and deletes megawidgets and'
+    print 'their components.  It calls the "top" program, so'
+    print 'may not work on non-Unix operating systems. Run it for a long,'
+    print 'long time and check that the process memory size does not'
+    print 'continue to increase.  Kill with <Control-C>.'
+
+    pid = os.getpid()
+
+    label = Tkinter.Label()
+    label.pack()
+
+    # Setup each test:
+
+    # 1. Create/delete all megawidgets:
+    megawidgets = (
+        Pmw.AboutDialog, Pmw.Balloon, Pmw.ButtonBox, Pmw.ComboBox,
+        Pmw.ComboBoxDialog, Pmw.Counter, Pmw.CounterDialog, Pmw.Dialog,
+        Pmw.EntryField, Pmw.Group, Pmw.HistoryText, Pmw.LabeledWidget,
+        Pmw.MainMenuBar, Pmw.MenuBar, Pmw.MessageBar, Pmw.MessageDialog,
+        Pmw.NoteBook, Pmw.OptionMenu, Pmw.PanedWidget, Pmw.PromptDialog,
+        Pmw.RadioSelect, Pmw.ScrolledCanvas, Pmw.ScrolledField,
+        Pmw.ScrolledFrame, Pmw.ScrolledListBox, Pmw.ScrolledText,
+        Pmw.SelectionDialog, Pmw.TextDialog, Pmw.TimeCounter,
+    )
+
+    # 2. Balloon binding:
+    toplevel = Tkinter.Toplevel()
+    balloon = Pmw.Balloon(toplevel)
+    button = Tkinter.Button(toplevel)
+    button.pack()
+    canvas = Tkinter.Canvas(toplevel)
+    item = canvas.create_rectangle(0, 0, 100, 100)
+    canvas.pack()
+
+    # 3. Adding and deleting menu:
+    toplevel = Tkinter.Toplevel()
+    mainmenu = Pmw.MainMenuBar(toplevel)
+    mainmenu.addmenu('Foo', 'help')
+    toplevel.configure(menu = mainmenu)
+
+    # 4. Adding and deleting notebook page:
+    toplevel = Tkinter.Toplevel()
+    notebook = Pmw.NoteBook(toplevel)
+    notebook.pack()
+
+    # 5. Adding and deleting panedwidget pane:
+    toplevel = Tkinter.Toplevel()
+    panedwidget = Pmw.PanedWidget(toplevel)
+    panedwidget.pack()
+    panedwidget.insert('Foo', size = 100)
+
+    # 6. Adding and deleting MenuBar menu:
+    toplevel = Tkinter.Toplevel()
+    menubar = Pmw.MenuBar(toplevel)
+    menubar.pack()
+
+    # 7. Setting OptionMenu items:
+    toplevel = Tkinter.Toplevel()
+    optionmenu = Pmw.OptionMenu(toplevel, items = ('XXX', 'YYY', 'ZZZ'))
+    optionmenu.pack()
+
+    # 8. Setting Tkinter.Canvas scrollcommand option:
+    toplevel = Tkinter.Toplevel()
+    scrollcanvas = Pmw.ScrolledCanvas(toplevel)
+    scrollcanvas.pack()
+
+    global prevSize
+    prevSize = -1
+
+    # Loop and run each test:
+    count = 0
+    while 1:
+        count = count + 1
+        label.configure(text = count)
+
+        # 1. Create/delete all megawidgets:
+        for widgetClass in megawidgets:
+            widget = widgetClass()
+            if widgetClass == Pmw.MainMenuBar:
+                root.configure(menu = widget)
+            elif hasattr(widgetClass, 'pack'):
+                widget.pack()
+            root.update()
+            widget.destroy()
+
+        # 2. Balloon binding:
+        balloon.bind(button, 'help')
+        balloon.tagbind(canvas, item, 'help')
+            # tagbind leaks due to a bug in Tkinter (v1.127) Canvas - it adds
+            # bindings to self._tagcommands but does not delete them.
+        root.update()
+
+        # 3. Adding and deleting MainMenuBar menu:
+        mainmenu.addmenu('File', 'help')
+        root.update()
+        mainmenu.deletemenu('File')
+        root.update()
+
+        # 4. Adding and deleting notebook page:
+        notebook.insert('File')
+        root.update()
+        notebook.delete('File')
+        root.update()
+
+        # 5. Adding and deleting panedwidget pane:
+        panedwidget.insert('File', size = 100)
+        root.update()
+        panedwidget.delete('File')
+        root.update()
+
+        # 6. Adding and deleting MenuBar menu:
+        menubar.addmenu('File', 'help')
+        root.update()
+        menubar.deletemenu('File')
+        root.update()
+
+        # 7. Setting OptionMenu items:
+        optionmenu.setitems(('aaa', 'bbb', 'ccc'))
+        root.update()
+
+        # 8. Setting Tkinter.Canvas scrollcommand option:
+        scrollcanvas.configure(hscrollmode = 'static')
+        scrollcanvas.configure(hscrollmode = 'dynamic')
+
+        # Check memory usage:
+        # lines = os.popen('top').readlines()
+        lines = os.popen('top -b -n 1 -p %d' % pid).readlines()
+        for line in lines:
+            # if string.find(line, 'python1.5.2') > 0:
+            if string.find(line, '^ *%d' % pid) > 0:
+                break
+        # size = string.atoi(string.lstrip(line[27:32]))
+        size = string.atoi(string.lstrip(line[22:29]))
+        if prevSize != size:
+            print time.strftime('%H:%M:%S', time.localtime(time.time())),
+            print line[:-1]
+            prevSize = size
+
+# ----------------------------------------------------------------------
+
+def usageExit():
+    print 'Usage:', sys.argv[0], '<test>'
+    print '  where <test> is one of:'
+    for test in tests:
+        print '   ', test
+    sys.exit()
+
+tests = []
+for name in locals().keys():
+    if name[-5:] == '_test':
+        tests.append(name)
+tests.sort()
+
+if len(sys.argv) != 2:
+    usageExit()
+
+testName = sys.argv[1]
+if testName not in tests:
+    print 'Unknown test "' + testName + '"'
+    usageExit()
+
+if testName == 'reinitialise_test':
+    # Run this by itself, since it calls Tkinter.Tk, mainloop, etc.
+    reinitialise_test()
+    sys.exit()
+
+# Use Pmw version in this distribution:
+Test.initialise()
+root = Test.root
+root.deiconify()
+
+# To use a different version of Pmw, comment out the three above lines
+# and the "import Test" line and uncomment these three:
+#   root = Tkinter.Tk()
+#   Pmw.setversion('1.0')
+#   Pmw.initialise(root)
+
+testFunction = locals()[testName]
+testFunction()
+
+if testName != 'memoryleak2_test':
+    # This does not use mainloop.
+    root.mainloop()
diff --git a/Pmw/Pmw_1_2/tests/MegaWidget_test.py b/Pmw/Pmw_1_2/tests/MegaWidget_test.py
new file mode 100644 (file)
index 0000000..62cff8a
--- /dev/null
@@ -0,0 +1,129 @@
+# Based on itk2.2/tests/widget.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+class TestWidget(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+
+       # Define the megawidget options.
+       optiondefs = (
+           ('status',         '',          self._status),
+           ('background',     'linen',     None),
+           ('borderwidth',    2,           None),
+           ('foreground',     'navy',      None),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       self._label = self.createcomponent('label',
+               (), None,
+               Tkinter.Label, (interior,))
+       self._label.pack(side='left', padx=2)
+
+       self._button = self.createcomponent('button',
+               (), 'Mygroup',
+               Tkinter.Button, (interior,), text = 'Push Me',
+               activebackground = 'white', background = 'ivory')
+       self._button.pack(side='right', fill='x', padx=2)
+
+       # Initialise instance variables.
+       self._statusList = []
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def statusList(self, val=None):
+        if val is None:
+           return self._statusList
+       else:
+           self._statusList = val
+
+    def action(self, info):
+        self._statusList.append(info)
+
+    def _status(self):
+        self._statusList.append(self['status'])
+
+def _componentOption(component, option):
+    w = Test.currentWidget()
+    return w.component(component).cget(option)
+
+def _componentInvoke(component):
+    w = Test.currentWidget()
+    w.component(component).invoke()
+
+def _addComponent():
+    w = Test.currentWidget()
+    label2 = w.createcomponent('label2',
+           (), 'Mygroup',
+           Tkinter.Label, (w.interior(),),
+           text = 'Temporary', background = 'yellow')
+    label2.pack(fill = 'x')
+    return label2.cget('text')
+
+expectedOptions = {
+    'background': ('background', 'background', 'Background', 'linen', 'linen'),
+    'borderwidth': ('borderwidth', 'borderwidth', 'Borderwidth', 2, 2),
+    'foreground': ('foreground', 'foreground', 'Foreground', 'navy', 'navy'),
+    'status': ('status', 'status', 'Status', '', ''),
+}
+
+c = TestWidget
+tests = (
+  # Set status list to a known state, since configure(status) may have
+  # been called during contruction.
+  (c.statusList, ([''])),
+  (c.pack, ()),
+  (c.configure, (), {}, expectedOptions),
+  (c.configure, ('background'), expectedOptions['background']),
+  (c.configure, ('borderwidth'), expectedOptions['borderwidth']),
+  (c.configure, ('foreground'), expectedOptions['foreground']),
+  (c.configure, ('status'), expectedOptions['status']),
+  ('hull_background', 'red'),
+  ('label_background', 'red'),
+  ('borderwidth', 1),
+  ('button_command', Test.callback),
+  ('hull_cursor', 'trek'),
+  ('label_cursor', 'trek'),
+  ('Mygroup_foreground', 'IndianRed'),
+  ('button_activebackground', 'MistyRose'),
+  ('button_background', 'MistyRose2'),
+  ('status', 'test message'),
+  ('label_text', 'Label:'),
+  (c.components, (), ['button', 'hull', 'label']),
+  (c.component, ('hull'), Tkinter.Frame),
+  (c.component, ('label'), Tkinter.Label),
+  (c.component, ('button'), Tkinter.Button),
+  (_componentOption, ('hull', 'cursor'), 'trek'),
+  (_componentOption, ('label', 'cursor'), 'trek'),
+  (_componentOption, ('hull', 'background'), 'red'),
+  (_componentOption, ('label', 'background'), 'red'),
+  (_componentOption, ('button', 'background'), 'MistyRose2'),
+  (_componentOption, ('label', 'text'), 'Label:'),
+  (_componentOption, ('button', 'text'), 'Push Me'),
+  (c.statusList, (), ['', 'test message']),
+  ('button_command', Test.actioncallback),
+  (c.statusList, ([])),
+  (_componentInvoke, 'button'),
+  ('status', 'in between'),
+  (_componentInvoke, 'button'),
+  (c.statusList, (), ['button press', 'in between', 'button press']),
+  (_addComponent, (), 'Temporary'),
+  (c.components, (), ['button', 'hull', 'label', 'label2']),
+  (_componentOption, ('label2', 'background'), 'yellow'),
+  (c.destroycomponent, ('label2')),
+  (c.components, (), ['button', 'hull', 'label']),
+)
+testData = ((c, ((tests, {}),)),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/MessageDialog_test.py b/Pmw/Pmw_1_2/tests/MessageDialog_test.py
new file mode 100644 (file)
index 0000000..7edc6ce
--- /dev/null
@@ -0,0 +1,58 @@
+# Based on iwidgets2.2.0/tests/messagedialog.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.MessageDialog
+
+kw_1 = {
+    'message_text' : 'Are you sure you want to do that?',
+    'buttons' : ('OK', 'Cancel'),
+    'icon_bitmap' : 'questhead',
+    'iconmargin': '60',
+    'iconpos' : 'w',
+    'buttonbox_padx': 30,
+}
+tests_1 = (
+  (Test.num_options, (), 13),
+  ('message_anchor', 'center'),
+  ('message_justify', 'center'),
+  ('message_wraplength', 0),
+  ('hull_background', '#d9d9d9'),
+  ('icon_bitmap', 'warning'),
+  ('hull_cursor', 'gumby'),
+  ('icon_image', Test.flagup),
+  ('message_font', Test.font['variable']),
+  ('message_foreground', 'red'),
+  ('message_padx', 15),
+  ('message_pady', 15),
+  ('icon_image', ''),
+  (c.title, 'MessageDialog 1: new title', ''),
+  (c.interior, (), Tkinter.Frame),
+  ('defaultbutton', 'OK'), 
+)
+
+kw_2 = {
+    'message_text' : 'On the left',
+    'buttons' : ('OK', 'Cancel'),
+    'buttonboxpos': 'e',
+    'borderx': 55,
+    'bordery': 55,
+    'separatorwidth': 5,
+}
+tests_2 = (
+  (c.title, 'MessageDialog 2', ''),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/NoteBook_test.py b/Pmw/Pmw_1_2/tests/NoteBook_test.py
new file mode 100644 (file)
index 0000000..f33c7d3
--- /dev/null
@@ -0,0 +1,173 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.NoteBook
+
+class callbackCollector:
+    def __init__(self):
+        self.list = []
+    def __call__(self, pageName):
+        self.list.append(pageName)
+    def get(self):
+        rtn = self.list
+        self.list = []
+        return rtn
+
+createCallback = callbackCollector()
+raiseCallback = callbackCollector()
+lowerCallback = callbackCollector()
+
+def checkCallbacks(clear = 0):
+    rtn = createCallback.get(), raiseCallback.get(), lowerCallback.get()
+    if not clear:
+        return rtn
+
+def _populatePage(pageName):
+    w = Test.currentWidget()
+    page = w.page(pageName)
+    text = Tkinter.Text(page)
+    text.pack()
+    return w.pagenames()[w.index(pageName)]
+
+def _getTopPageName():
+    w = Test.currentWidget()
+    return w._topPageName
+
+kw_1 = {'tabpos' : None}
+tests_1_common = (
+  (Test.num_options, (), 7),
+  ('createcommand', createCallback),
+  ('raisecommand', raiseCallback),
+  ('lowercommand', lowerCallback),
+  (checkCallbacks, 1),
+  (c.index, Pmw.END, 'ValueError: NoteBook has no pages'),
+  (c.index, Pmw.SELECT, 'ValueError: NoteBook has no pages'),
+  (c.setnaturalsize, ()),
+  (c.getcurselection, ()),
+  (c.insert, ('Temp', 0), {'page_pyclass' : Tkinter.Canvas}, Tkinter.Canvas),
+  (checkCallbacks, (), (['Temp'], ['Temp'], [])),
+  (c.getcurselection, (), 'Temp'),
+  (c.setnaturalsize, ()),
+  (c.delete, 'Temp'),
+  (checkCallbacks, (), ([], [], [])),
+  (c.getcurselection, ()),
+  (c.insert, ('Temp', Pmw.END), Tkinter.Frame),
+  (checkCallbacks, (), (['Temp'], ['Temp'], [])),
+  (c.delete, 'Temp'),
+  (c.add, 'Start', Tkinter.Frame),
+  ('Start_background', 'green'),
+  (c.insert, ('Final', Pmw.END), {'page_background' : 'blue'}, Tkinter.Frame),
+  (c.insert, ('Middle', 'Final'), Tkinter.Frame),
+  (c.index, Pmw.SELECT, 0),
+  (c.insert, ('First', 'Start'), Tkinter.Frame),
+  (c.index, Pmw.SELECT, 1),
+  (c.getcurselection, (), 'Start'),
+  (c.selectpage, Pmw.END),
+  (checkCallbacks, (), (['Start', 'Final'], ['Start', 'Final'], ['Start'])),
+  (c.index, Pmw.SELECT, 3),
+  (c.getcurselection, (), 'Final'),
+  (c.recolorborders, ()),
+  (c.selectpage, 2),
+  (c.index, Pmw.SELECT, 2),
+  (c.getcurselection, (), 'Middle'),
+  (checkCallbacks, (), (['Middle'], ['Middle'], ['Final'])),
+  (c.selectpage, 3),
+  (c.selectpage, 2),
+  (checkCallbacks, (), ([], ['Final', 'Middle'], ['Middle', 'Final'])),
+  (c.selectpage, 'Final'),
+  (c.index, Pmw.SELECT, 3),
+  (c.getcurselection, (), 'Final'),
+  (c.add, 'Last', Tkinter.Frame),
+  (c.pagenames, (), ['First', 'Start', 'Middle', 'Final', 'Last']),
+  (c.setnaturalsize, ()),
+  (_populatePage, Pmw.SELECT, 'Final'),
+  (_populatePage, 'Middle', 'Middle'),
+  (c.setnaturalsize, ()),
+  (c.add, 'Start', 'ValueError: Page "Start" already exists.'),
+  ('Page_background', 'yellow'),
+  (c.index, 1, 1),
+  (c.index, 10, 'ValueError: index "10" is out of range'),
+  (c.index, Pmw.END, 4),
+  (c.index, 'First', 0),
+  (c.index, 'Middle', 2),
+  (c.index, 'bogus', 'ValueError: bad index "bogus": ' + \
+      'must be a name, a number, Pmw.END or Pmw.SELECT'),
+  (c.previouspage, ()),
+  (c.getcurselection, (), 'Middle'),
+  (c.previouspage, 'Start'),
+  (c.getcurselection, (), 'First'),
+  (c.nextpage, ()),
+  (c.getcurselection, (), 'Start'),
+  (c.nextpage, 'Middle'),
+  (c.getcurselection, (), 'Final'),
+  (c.delete, ('First', 'Start', 'Middle', 'Final', 'Last')),
+  (c.add, 'Temp', {'page_pyclass' : Tkinter.Button}, Tkinter.Button),
+  (c.delete, 'Temp'),
+  (c.add, 'Temp', {'page_pyclass' : Tkinter.Text}, Tkinter.Text),
+  (c.delete, 'Temp'),
+  (c.add, 'Temp', {'page_pyclass' : Pmw.ScrolledText,
+      'page_vscrollmode' : 'static', 'page_text_state' : 'disabled'},
+      Pmw.ScrolledText),
+  ('Temp_text_background', 'red'),
+  (c.page, 'Temp', Pmw.ScrolledText),
+  (c.pagenames, (), ['Temp']),
+  (c.getcurselection, (), 'Temp'),
+  (c.delete, 'Temp'),
+  (c.getcurselection, (), None),
+  (c.add, 'Start', Tkinter.Frame),
+  (c.getcurselection, (), 'Start'),
+)
+
+tests_1 = tests_1_common + (
+  (_getTopPageName, (), None),
+  (c.pack, ()),
+  (_getTopPageName, (), 'Start'),
+  (c.delete, 'Start'),
+) + tests_1_common + (
+  (_getTopPageName, (), 'Start'),
+  (c.delete, 'Start'),
+  (c.pack_forget, ()),
+) + tests_1_common + (
+  (_getTopPageName, (), None),
+  (c.pack, ()),
+  (_getTopPageName, (), 'Start'),
+)
+
+kw_2 = {
+    'tabpos' : None,
+    'borderwidth' : 10,
+    'pagemargin' : 10,
+}
+
+tests_2 = (
+  (c.pack, ()),
+  ('hull_relief', 'sunken'),
+  ('hull_borderwidth', 20),
+) + tests_1_common
+
+kw_3 = {}
+
+tests_3 = (
+  (c.pack, ()),
+) + tests_1_common + (
+  ('Tab_background', 'red'),
+  (c.add, 'One', Tkinter.Frame),
+  (c.tab, 'One', Tkinter.Button),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_1, kw_2),
+  (tests_1, kw_3),
+  (tests_2, kw_1),
+  (tests_2, kw_3),
+  (tests_3, kw_3),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/OptionMenu_test.py b/Pmw/Pmw_1_2/tests/OptionMenu_test.py
new file mode 100644 (file)
index 0000000..3ffa9fa
--- /dev/null
@@ -0,0 +1,53 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.OptionMenu
+
+kw_1 = {
+    'labelpos' : 'nw',
+    'label_text' : 'Option Menu:',
+    'items' : ('Chips', 'Lollies', 'Junk', 'More junk'),
+    'initialitem' : 1,
+}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 6),
+  (c.getcurselection, (), 'Lollies'),
+  (c.index, 'Junk', 2),
+  (c.index, 'Nowhere', 'ValueError: bad index "Nowhere": must be ' +
+    'a name, a number, Pmw.END or Pmw.SELECT'),
+  (c.index, Pmw.END, 3),
+  (c.index, Pmw.SELECT, 1),
+  (c.index, 1, 1),
+  (c.invoke, 'Chips'),
+  (c.getcurselection, (), 'Chips'),
+  ('command', Test.callback1),
+  (c.invoke, (), 'Chips'),
+  (c.invoke, 'Lollies', 'Lollies'),
+  (c.getcurselection, (), 'Lollies'),
+  ('hull_background', 'yellow'),
+  ('hull_show', 'X', 'TclError: unknown option "-show"'),
+  (c.index, Pmw.SELECT, 1),
+  (c.setitems, (('Chips', 'Junk', 'Lollies', 'More junk'),)),
+  (c.index, Pmw.SELECT, 2),
+  (c.setitems, (('Fruit', 'Vegetables', 'Cereals', 'Legumes'),)),
+  (c.index, Pmw.SELECT, 0),
+  (c.getcurselection, (), 'Fruit'),
+  (c.setitems, (('Vegetables', 'Cereals', 'Legumes'), Pmw.END)),
+  (c.getcurselection, (), 'Legumes'),
+  (c.index, 'Vegetables', 0),
+  (c.invoke, 'Legumes', 'Legumes'),
+  ('hull_cursor', 'gumby'),
+  ('label_foreground', 'Green'),
+  ('label_foreground', 'Black'),
+  ('label_highlightcolor', 'Red'),
+  ('label_text', 'Label'),
+)
+
+testData = ((c, ((tests_1, kw_1),)),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/Options_test.py b/Pmw/Pmw_1_2/tests/Options_test.py
new file mode 100644 (file)
index 0000000..aca085c
--- /dev/null
@@ -0,0 +1,304 @@
+# This tests Pmw option and component handling.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+"""
+    Definitions:
+       initialisation option:  an option that can be set in the call
+           to the constructor but not in configure()
+       configuration option:  an option that can be set in the call
+           to the constructor and to configure()
+       option: either an initialisation option or a configuration option
+
+    Tests
+    -----
+    in constructor:
+    + define an option, its default value and whether it is an
+       initialisation or a configuration option
+    + set a callback function for a configuration option
+    + set a different default for an option of a base class
+    + set a different default for an option of a component of a base class
+    + override the callback for a configuration option of a base class
+    + create a component
+    + create an alias for a component
+    + create an alias for a sub-component
+
+    calling constructor:
+    + set an option
+    + set an option of a base class
+    + set an option of a component created in the constructor
+    + set an option of an aliased component or sub-component created in
+        the constructor
+    + set an option of one or more components via their group name
+    + use the default value of an option
+    + use the default value of an option of a base class
+    + use the default value of an option of a base class where the default
+       value is redefined in the derived class
+
+    calling configure:
+    + set a configuration option
+    + set a configuration option of a base class
+    + set a configuration option of a component
+    + set a configuration option of an aliased component or sub-component
+    + set a configuration option of one or more components via their group name
+    + set a configuration option with a callback
+    + set a configuration option of a base class with a callback in the
+       derived class
+"""
+
+class Simple(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+       optiondefs = (
+           ('initsimple1', 'initsimple1', Pmw.INITOPT),
+           ('initsimple2', 'initsimple2', Pmw.INITOPT),
+           ('optsimple1', 'optsimple1', None),
+           ('optsimple2', 'optsimple2', None),
+       )
+       self.defineoptions(kw, optiondefs)
+       Pmw.MegaWidget.__init__(self, parent)
+
+       interior = self.interior()
+       self._widget = self.createcomponent('widget',
+               (('widgy', 'widget'),), None,
+               Tkinter.Button, (interior,))
+       self._widget.grid(column=0, row=0, sticky='nsew')
+
+       self.initialiseoptions()
+
+class Complex(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+       optiondefs = (
+           ('initcomplex1', 'initcomplex1', Pmw.INITOPT),
+           ('initcomplex2', 'initcomplex2', Pmw.INITOPT),
+           ('optcomplex1', 'optcomplex1', None),
+           ('optcomplex2', 'optcomplex2', None),
+       )
+       self.defineoptions(kw, optiondefs)
+       Pmw.MegaWidget.__init__(self, parent)
+
+       interior = self.interior()
+       self._simple = self.createcomponent('simple',
+               (('widget', 'simple_widget'),), None,
+               Simple, (interior,))
+       self._simple.grid(column=0, row=0, sticky='nsew')
+
+       self.initialiseoptions()
+
+class Base(Pmw.MegaWidget):
+    def __init__(self, parent = None, **kw):
+       optiondefs = (
+           ('initbase1', 'initbase1', Pmw.INITOPT),
+           ('initbase2', 'initbase2', Pmw.INITOPT),
+           ('initbase3', 'initbase3', Pmw.INITOPT),
+           ('optbase1', 'optbase1', self._optbase1),
+           ('optbase2', 'optbase2', None),
+           ('optbase3', 'optbase3', None),
+       )
+       self.defineoptions(kw, optiondefs)
+       Pmw.MegaWidget.__init__(self, parent)
+
+       oldInterior = Pmw.MegaWidget.interior(self)
+       self._widget = self.createcomponent('basesimple',
+               (('widget', 'basesimple_widget'),), None,
+               Simple, (oldInterior,))
+       self._widget.grid(column=0, row=0, sticky='nsew')
+
+       self._child = self.createcomponent('child',
+               (), 'Mygroup',
+               Tkinter.Frame, (oldInterior,))
+       self._child.grid(column=0, row=1, sticky='nsew')
+
+       self._groupie = self.createcomponent('groupie',
+               (), 'Mygroup',
+               Tkinter.Button, (oldInterior,), text = 'XXXXX')
+       self._groupie.grid(column=0, row=2, sticky='nsew')
+
+       self.basedummy = []
+
+       self.initialiseoptions()
+
+    def _optbase1(self):
+       self.basedummy.append(self['optbase1'])
+
+    def getbasedummy(self):
+       return self.basedummy
+
+    def interior(self):
+       return self._child
+
+class Derived(Base):
+    def __init__(self, parent = None, **kw):
+       # Define the options for this megawidget.
+       optiondefs = (
+           ('initbase2', 'initbase2inderived', Pmw.INITOPT),
+           ('initderived1', 'initderived1', Pmw.INITOPT),
+           ('initderived2', 'initderived2', Pmw.INITOPT),
+           ('optbase1', 'optbase1', self._optbase1),
+           ('optderived1', 'optderived1', None),
+           ('optderived2', 'optderived2', None),
+           ('groupie_text', 'YYYYY', None),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining my options).
+       Base.__init__(self, parent)
+
+       # Create components.
+       interior = self.interior()
+       self._widget = self.createcomponent('derivedcomplex',
+               (('derivedsimple', 'derivedcomplex_simple'),), None,
+               Complex, (interior,))
+       self._widget.grid(column=0, row=0, sticky='nsew')
+
+       # Initialise instance.
+
+       # Initialise instance variables.
+       self.deriveddummy = []
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def _optbase1(self):
+       self.deriveddummy.append(self['optbase1'])
+
+    def getderiveddummy(self):
+       return self.deriveddummy
+
+testData = ()
+
+c = Simple
+kw_1 = {
+    'hull_borderwidth' :2,
+    'hull_relief' :'sunken',
+    'hull_background' :'red',
+    'widget_text' :'simple',
+    'widgy_foreground' :'red',
+    'initsimple1' :'initsimple1_new',
+}
+tests = (
+    (c.pack, ()),
+    (c.components, (), ['hull', 'widget']),
+    (c.componentaliases, (), [('widgy', 'widget'),]),
+    (c.options, (), [('initsimple1', 'initsimple1', 1), ('initsimple2', 'initsimple2', 1), ('optsimple1', 'optsimple1', 0), ('optsimple2', 'optsimple2', 0)]),
+    (c.cget, 'initsimple1', 'initsimple1_new'),
+    (c.cget, 'initsimple2', 'initsimple2'),
+    (c.cget, 'optsimple1', 'optsimple1'),
+    (c.cget, 'optsimple2', 'optsimple2'),
+    (c.cget, 'widget_foreground', 'red'),
+    ('optsimple1', 'optsimple1_new'),
+    (c.cget, 'optsimple1', 'optsimple1_new'),
+)
+testData = testData + ((c, ((tests, kw_1),)),)
+
+
+c = Complex
+kw_1 = {
+    'hull_borderwidth' : 2,
+    'hull_relief' : 'sunken',
+    'hull_background' : 'red',
+    'simple_widget_text' : 'complex',
+    'widget_foreground' : 'yellow',
+}
+tests = (
+    (c.pack, ()),
+    (c.components, (), ['hull', 'simple']),
+    (c.componentaliases, (), [('widget', 'simple_widget'),]),
+    (c.options, (), [('initcomplex1', 'initcomplex1', 1), ('initcomplex2', 'initcomplex2', 1), ('optcomplex1', 'optcomplex1', 0), ('optcomplex2', 'optcomplex2', 0)]),
+)
+testData = testData + ((c, ((tests, kw_1),)),)
+
+c = Base
+kw_1 = {
+    'hull_borderwidth' : 2,
+    'hull_relief' : 'sunken',
+    'hull_background' : 'red',
+    'basesimple_widget_text' : 'base',
+    'widget_foreground' : 'green',
+    'initbase1' : 'initbase1_new',
+}
+tests = (
+    (c.pack, ()),
+    (c.components, (), ['basesimple', 'child', 'groupie', 'hull']),
+    (c.componentaliases, (), [('widget', 'basesimple_widget'),]),
+    (c.options, (), [('initbase1', 'initbase1', 1), ('initbase2', 'initbase2', 1), ('initbase3', 'initbase3', 1), ('optbase1', 'optbase1', 0), ('optbase2', 'optbase2', 0), ('optbase3', 'optbase3', 0)]),
+    (c.cget, 'widget_foreground', 'green'),
+    (c.cget, 'basesimple_widget_foreground', 'green'),
+    (c.cget, 'basesimple_widgy_foreground', 'green'),
+    ('widget_foreground', 'blue'),
+    (c.cget, 'widget_foreground', 'blue'),
+    (c.cget, 'basesimple_widget_foreground', 'blue'),
+    (c.cget, 'basesimple_widgy_foreground', 'blue'),
+    (c.cget, 'optbase1', 'optbase1'),
+    (c.cget, 'groupie_text', 'XXXXX'),
+    # When Test created the widget, it performed a test where it configured
+    # each option. Hence, _optbase1() has been called twice:
+    (c.getbasedummy, (), ['optbase1', 'optbase1']),
+    ('optbase1', 'basedummy_new'),
+    (c.getbasedummy, (), ['optbase1', 'optbase1', 'basedummy_new']),
+)
+testData = testData + ((c, ((tests, kw_1),)),)
+
+
+c = Derived
+kw_1 = {
+    'hull_borderwidth' : 2,
+    'hull_relief' : 'sunken',
+    'hull_background' : 'red',
+    'basesimple_widget_text' : 'base simple',
+    'derivedcomplex_widget_text' : 'derived complex',
+    'initderived1' : 'initderived1_new',
+    'initbase1' : 'initbase1_new',
+    'optbase3' : 'optbase3_new',
+    'derivedcomplex_initcomplex1' : 'derivedcomplex_initcomplex1',
+    'derivedsimple_initsimple1' : 'derivedsimple_initsimple1',
+    'hull_cursor' : 'gumby',
+    'Mygroup_borderwidth' : 2,
+    'Mygroup_relief' : 'ridge',
+}
+tests = (
+    (c.pack, ()),
+    (c.components, (), ['basesimple', 'child', 'derivedcomplex', 'groupie', 'hull']),
+    (c.componentaliases, (), [('derivedsimple', 'derivedcomplex_simple'), ('widget', 'basesimple_widget'),]),
+    (c.options, (), [('initbase1', 'initbase1', 1), ('initbase2', 'initbase2inderived', 1), ('initbase3', 'initbase3', 1), ('initderived1', 'initderived1', 1), ('initderived2', 'initderived2', 1), ('optbase1', 'optbase1', 0), ('optbase2', 'optbase2', 0), ('optbase3', 'optbase3', 0), ('optderived1', 'optderived1', 0), ('optderived2', 'optderived2', 0), ]),
+    (c.getbasedummy, (), []),
+    (c.getderiveddummy, (), ['optbase1', 'optbase1']),
+    ('optbase1', 'derivedbasedummy_new'),
+    (c.getbasedummy, (), []),
+    (c.getderiveddummy, (), ['optbase1', 'optbase1', 'derivedbasedummy_new']),
+    (c.cget, 'optbase3', 'optbase3_new'),
+    ('optbase3', 'optbase3_newer'),
+    (c.cget, 'optbase3', 'optbase3_newer'),
+    (c.cget, 'optderived1', 'optderived1'),
+    (c.cget, 'initderived1', 'initderived1_new'),
+    (c.cget, 'initbase2', 'initbase2inderived'),
+    (c.cget, 'initbase1', 'initbase1_new'),
+    (c.cget, 'initbase3', 'initbase3'),
+    (c.cget, 'groupie_text', 'YYYYY'),
+    ('groupie_text', 'ZZZZZ'),
+    (c.cget, 'groupie_text', 'ZZZZZ'),
+    (c.cget, 'derivedcomplex_optcomplex1', 'optcomplex1'),
+    ('derivedcomplex_optcomplex1', 'optcomplex1_new'),
+    (c.cget, 'derivedcomplex_optcomplex1', 'optcomplex1_new'),
+    (c.cget, 'derivedsimple_optsimple2', 'optsimple2'),
+    ('derivedsimple_optsimple2', 'optsimple2_new'),
+    (c.cget, 'derivedcomplex_simple_optsimple2', 'optsimple2_new'),
+    ('derivedcomplex_simple_optsimple2', 'optsimple2_newer'),
+    (c.cget, 'derivedsimple_optsimple2', 'optsimple2_newer'),
+    (c.cget, 'hull_cursor', 'gumby'),
+    (c.cget, 'groupie_relief', 'ridge'),
+    (c.cget, 'Mygroup_relief', 'ridge'),
+    ('Mygroup_relief', 'sunken'),
+    (c.cget, 'groupie_relief', 'sunken'),
+    (c.cget, 'Mygroup_relief', 'sunken'),
+    ('groupie_relief', 'groove'),
+    (c.cget, 'groupie_relief', 'groove'),
+)
+testData = testData + ((c, ((tests, kw_1),)),)
+
+if __name__ == '__main__':
+    #Test.setverbose(1)
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/PanedWidget_test.py b/Pmw/Pmw_1_2/tests/PanedWidget_test.py
new file mode 100644 (file)
index 0000000..d549b92
--- /dev/null
@@ -0,0 +1,39 @@
+import os
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.PanedWidget
+
+def _setbackground(name, colour):
+    w = Test.currentWidget()
+    w.pane(name).configure(background = colour)
+
+kw_1 = {'orient': 'horizontal', 'hull_width': 400, 'hull_height': 300}
+tests_1 = (
+  (c.pack, ()),
+  (Test.num_options, (), 5),
+  (c.add, 'left', {'min' : 100}, Tkinter.Frame),
+  (_setbackground, ('left', 'red')),
+  (c.add, 'middle', {'max' : 100}, Tkinter.Frame),
+  (_setbackground, ('middle', 'green')),
+  (c.add, 'right', {'size' : 100}, Tkinter.Frame),
+  (c.insert, ('first', 'middle'), {'size' : 100}, Tkinter.Frame),
+  (_setbackground, ('right', 'yellow')),
+  (_setbackground, ('first', 'blue')),
+  (c.delete, 'middle'),
+  (c.pane, 'left', Tkinter.Frame),
+  (c.panes, (), ['left', 'first', 'right']),
+  (c.configurepane, 'first', {'size' : 200}),
+)
+
+alltests = (
+  (tests_1, kw_1),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/PmwBase_test.py b/Pmw/Pmw_1_2/tests/PmwBase_test.py
new file mode 100644 (file)
index 0000000..e3f976e
--- /dev/null
@@ -0,0 +1,181 @@
+# Tests for Pmw megawidgets
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+class TestWidget(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+        # Define the megawidget options.
+        optiondefs = ()
+        self.defineoptions(kw, optiondefs)
+
+        # Initialise the base class (after defining the options).
+        Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       self._label = self.createcomponent('label',
+               (), None,
+               Tkinter.Label, (interior,), text = 'test')
+       self._label.pack(side='left', padx=2)
+
+        # Check keywords and initialise options.
+        self.initialiseoptions(TestWidget)
+
+    def addComponent(self, nickname):
+       self.createcomponent(nickname,
+               (), None,
+               TestComponent, (self.interior(),), status = 'create')
+
+    def addTestWidget(self, widget, option, value):
+       w = self.createcomponent('test',
+               (), None,
+               widget, (self.interior(),))
+       apply(self.configure, (), {'test_' + option : value})
+       if w.__class__.__name__ not in ('Menu', 'Toplevel'):
+           w.pack()
+       if hasattr(widget, 'geometry'):
+           w.geometry('+100+100')
+       return str(w.cget(option))
+
+    def deleteTestWidget(self):
+       w = self.component('test')
+       if hasattr(widget, 'pack'):
+           w.pack_forget()
+       self.destroycomponent('test')
+
+    def packComponent(self, nickname):
+       self.component(nickname).pack()
+
+    def getStatusList(self, nickname):
+       return self.component(nickname)._statusList
+
+    def componentOption(self, nickname, option):
+       return self.component(nickname).cget(option)
+
+class TestComponent(Pmw.MegaWidget):
+
+    def __init__(self, parent = None, **kw):
+       # Define the megawidget options.
+       optiondefs = (
+           ('status', '', self._status),
+       )
+       self.defineoptions(kw, optiondefs)
+
+       # Initialise the base class (after defining the options).
+       Pmw.MegaWidget.__init__(self, parent)
+
+       # Create the components.
+       interior = self.interior()
+       self._label = self.createcomponent('label',
+               (), None,
+               Tkinter.Label, (interior,), text = 'test')
+       self._label.pack(side='left', padx=2)
+
+       self._statusList = []
+
+       # Check keywords and initialise options.
+       self.initialiseoptions()
+
+    def action(self, info):
+        self._statusList.append(info)
+
+    def _status(self):
+        self._statusList.append(self['status'])
+
+c = TestWidget
+tests = (
+  (c.pack, ()),
+  (c.components, (), ['hull', 'label']),
+
+  (c.addComponent, 'k0'),
+  (c.getStatusList, 'k0', ['create']),
+  (c.packComponent, 'k0'),
+  ('k0_status', 'foo'),
+  (c.getStatusList, 'k0', ['create', 'foo']),
+
+  (c.addComponent, 'k1'),
+  (c.packComponent, 'k1'),
+  ('k1_status', 'bar'),
+  (c.getStatusList, 'k1', ['create', 'bar']),
+
+  (c.addComponent, 'k2'),
+  (c.packComponent, 'k2'),
+  ('k2_label_foreground', 'green'),
+  ('hull_cursor', 'gumby'),
+  ('k2_label_cursor', 'gumby'),
+  (c.componentOption, ('k2', 'label_foreground'), 'green'),
+  (c.componentOption, ('k2', 'label_cursor'), 'gumby'),
+
+  (c.addComponent, 'k3'),
+  (c.packComponent, 'k3'),
+  ('k3_label_foreground', 'red'),
+  ('hull_background', 'white'),
+  ('k3_label_background', 'white'),
+  ('hull_cursor', 'dot'),
+  ('k3_label_cursor', 'dot'),
+  (c.componentOption, ('k3', 'label_foreground'), 'red'),
+  (c.componentOption, ('k3', 'label_background'), 'white'),
+  (c.componentOption, ('k3', 'label_cursor'), 'dot'),
+  ('label_background', 'white'),
+  (c.destroycomponent, 'k0'),
+  (c.destroycomponent, 'k1'),
+  (c.destroycomponent, 'k2'),
+  (c.destroycomponent, 'k3'),
+)
+
+# Test each of the standard widgets as components.
+for widget in [Tkinter.Button, Tkinter.Checkbutton, Tkinter.Entry, Tkinter.Label, Tkinter.Listbox, \
+  Tkinter.Menu, Tkinter.Menubutton, Tkinter.Message, Tkinter.Radiobutton, Tkinter.Scale, Tkinter.Text]:
+    tests = tests + (
+      (c.addTestWidget, (widget, 'foreground', 'blue'), 'blue'),
+      (c.deleteTestWidget, ())
+    )
+
+for widget in [Tkinter.Canvas, Tkinter.Frame, Tkinter.Scrollbar, Tkinter.Toplevel]:
+    tests = tests + (
+      (c.addTestWidget, (widget, 'background', 'grey80'), 'grey80'),
+      (c.deleteTestWidget, ())
+    )
+
+# Test the logical fonts.
+for fontName in Pmw.logicalfontnames():
+    for sizeIncr in (-2, 0, 1, 2, 4, 8):
+       font = Pmw.logicalfont(fontName, sizeIncr)
+        tests = tests + (
+          ('label_text', 'Testing font\n' + fontName + ' ' + str(sizeIncr)),
+          ('label_font', font),
+        )
+fontList = (
+  (('Helvetica', 0), {}),
+  (('Times', 0), {}),
+  (('Typewriter', 0), {}),
+  (('Typewriter', 0), {'width' : 'condensed'}),
+  (('Typewriter', -1), {'width' : 'condensed'}),
+  (('Fixed', 0), {}),
+  (('Fixed', 0), {'width' : 'condensed'}),
+  (('Fixed', -1), {'width' : 'condensed'}),
+  (('Helvetica', 2), {'slant' : 'italic'}),
+  (('Helvetica', 0), {'size' : 18}),
+  (('Helvetica', 0), {'weight' : 'bold'}),
+  (('Helvetica', 12), {'weight' : 'bold', 'slant' : 'italic'}),
+  (('Typewriter', 0), {'size' : 8, 'weight' : 'bold'}),
+  (('Fixed', 0), {'size' : 8, 'weight' : 'bold'}),
+  (('Times', 0), {'size' : 24, 'weight' : 'bold', 'slant' : 'italic'}),
+)
+
+for args, dict in fontList:
+    font = apply(Pmw.logicalfont, args, dict)
+    tests = tests + (
+        ('label_text', 'Testing font\n' + str(args) + '\n' + str(dict)),
+        ('label_font', font),
+    )
+
+testData = ((c, ((tests, {'label_text' : 'Testing Pmw base classes'}),)),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/PromptDialog_test.py b/Pmw/Pmw_1_2/tests/PromptDialog_test.py
new file mode 100644 (file)
index 0000000..cd9cdde
--- /dev/null
@@ -0,0 +1,81 @@
+# Based on iwidgets2.2.0/tests/promptdialog.test code. 
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.PromptDialog
+
+kw_1 = {
+    'entryfield_labelpos': 'n',
+    'label_text' : 'Please enter your password',
+    'buttons' : ('OK', 'Cancel', 'Help'),
+}
+tests_1 = (
+  (Test.num_options, (), 11),
+  (c.title, 'PromptDialog 1', ''),
+  ('hull_background', '#d9d9d9'),
+  ('hull_cursor', 'gumby'),
+  ('entry_exportselection', 1),
+  ('entry_foreground', 'Black'),
+  ('entry_background', 'GhostWhite'),
+  ('entry_insertbackground', 'Black'),
+  ('entry_insertborderwidth', 1),
+  ('entry_insertborderwidth', 0),
+  ('entry_insertofftime', 400),
+  ('entry_insertontime', 700),
+  ('entry_insertwidth', 3),
+  ('label_text', 'Label'),
+  ('entry_justify', 'left'),
+  ('entry_relief', 'sunken'),
+  ('entry_state', 'disabled'),
+  ('entry_state', 'normal'),
+  ('entry_background', 'GhostWhite'),
+  ('entryfield_validate', 'numeric'),
+  ('entryfield_validate', 'alphabetic'),
+  ('entryfield_validate', 'alphanumeric'),
+  ('entry_width', 30),
+  (c.interior, (), Tkinter.Frame),
+  (c.insertentry, ('end', 'Test String')),
+  (c.get, (), 'Test String'),
+  (c.deleteentry, (0, 'end')),
+  (c.insertentry, ('end', 'Another Test')),
+  (c.icursor, 'end'),
+  (c.indexentry, 'end', 12),
+  (c.selection_from, 0),
+  (c.selection_to, 'end'),
+  (c.xview, 3),
+  (c.clear, ()),
+  (c.get, (), ''),
+  ('label_bitmap', 'warning'),
+  ('label_image', Test.flagup),
+  ('entry_font', Test.font['variable']),
+  ('entry_foreground', 'red'),
+  ('label_image', ''),
+  ('label_bitmap', ''),
+  (c.title, 'PromptDialog 1: new title', ''),
+  ('defaultbutton', 'OK'), 
+)
+
+kw_2 = {
+    'buttonboxpos': 'e',
+    'entryfield_labelpos': 'w',
+    'label_text' : 'Please enter your password',
+    'buttonbox_pady': 25,
+    'buttons' : ('OK', 'Cancel'),
+}
+tests_2 = (
+  (c.title, 'PromptDialog 2', ''),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/RadioSelect_test.py b/Pmw/Pmw_1_2/tests/RadioSelect_test.py
new file mode 100644 (file)
index 0000000..6f41248
--- /dev/null
@@ -0,0 +1,112 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+if Tkinter.TkVersion >= 8.4:
+  expected1 = 'TclError: bad relief "bogus": must be '
+else:
+  expected1 = 'TclError: bad relief type "bogus": must be '
+
+c = Pmw.RadioSelect
+
+kw_1 = {'labelpos' : 'nw', 'label_text' : 'Radio Select:'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 8),
+  (c.index, Pmw.END, 'ValueError: RadioSelect has no buttons'),
+  (c.add, ('Fruit',), Tkinter.Button),
+  (c.add, ('Vegetables',), Tkinter.Button),
+  (c.add, ('CornFlakes',), {'text': 'Cereals'}, Tkinter.Button),
+  (c.add, ('Legumes',), Tkinter.Button),
+  (c.add, ('Legumes',), 'ValueError: button "Legumes" already exists'),
+  (c.index, 0, 0),
+  (c.index, Pmw.END, 3),
+  (c.index, 'Vegetables', 1),
+  (c.index, 'Fruit', 0),
+  (c.index, 12, 'ValueError: index "12" is out of range'),
+  (c.index, 'bogus', 'ValueError: bad index "bogus": ' + \
+      'must be a name, a number or Pmw.END'),
+  ('hull_background', 'yellow'),
+  ('hull_show', 'X', 'TclError: unknown option "-show"'),
+  ('frame_relief', 'raised'),
+  ('frame_borderwidth', 4),
+  ('frame_borderwidth', 2),
+  ('command', Test.callback1),
+  (c.invoke, 'Vegetables', 'Vegetables'),
+  ('hull_cursor', 'gumby'),
+  ('Button_state', 'disabled'),
+  ('Button_background', 'Green'),
+  ('Button_cursor', 'watch'),
+  ('Button_background', 'grey85'),
+  ('label_foreground', 'Green'),
+  ('label_foreground', 'Black'),
+  ('label_highlightcolor', 'Red'),
+  ('Fruit_background', 'red'),
+  ('Vegetables_background', 'green'),
+  ('CornFlakes_background', 'yellow'),
+  ('Legumes_background', 'brown'),
+  ('Legumes_foreground', 'white'),
+  (c.add, ('Foo',), Tkinter.Button),
+  ('label_text', 'Label'),
+  ('frame_relief', 'sunken'),
+  ('frame_relief', 'bogus', expected1 + Test.reliefs),
+  (c.deleteall, ()),
+)
+
+kw_2 = {
+    'labelpos' : 'nw',
+    'label_text' : 'Multiple:',
+    'selectmode' : 'multiple',
+}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (c.add, ('Fruit',), Tkinter.Button),
+  (c.add, ('Vegetables',), Tkinter.Button),
+  (c.add, ('CornFlakes',), {'text': 'Cereals'}, Tkinter.Button),
+  (c.add, ('Legumes',), Tkinter.Button),
+  ('command', Test.callback2),
+  (c.getcurselection, (), ()),
+  (c.invoke, 'Vegetables', ('Vegetables', 1)),
+  (c.getcurselection, (), ('Vegetables',)),
+  (c.invoke, 'Legumes', ('Legumes', 1)),
+  (c.getcurselection, (), ('Vegetables', 'Legumes')),
+  (c.invoke, 'Fruit', ('Fruit', 1)),
+  (c.getcurselection, (), ('Vegetables', 'Legumes', 'Fruit')),
+  (c.invoke, 'Legumes', ('Legumes', 0)),
+  (c.getcurselection, (), ('Vegetables', 'Fruit')),
+  (c.deleteall, ()),
+  (c.add, ('Fruit',), Tkinter.Button),
+  (c.add, ('Vegetables',), Tkinter.Button),
+  (c.invoke, 'Vegetables', ('Vegetables', 1)),
+  (c.getcurselection, (), ('Vegetables',)),
+)
+
+alltests = [
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+]
+
+
+tests_3 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10}),
+  (c.add, ('Foo',), Tkinter.Button),
+  (c.add, ('Bar',), Tkinter.Button),
+)
+
+poslist = ('nw', 'n', 'ne', 'en', 'e', 'es', 'se', 's', 'sw', 'ws', 'w', 'wn',)
+for pos in poslist:
+  kw_3 = {
+    'labelpos' : pos,
+    'orient' : 'vertical',
+    'padx' : 20,
+    'pady' : 20,
+    'label_text' : 'Radio Select',
+  }
+  alltests.append((tests_3, kw_3))
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ScrolledCanvas_test.py b/Pmw/Pmw_1_2/tests/ScrolledCanvas_test.py
new file mode 100644 (file)
index 0000000..aa98d9c
--- /dev/null
@@ -0,0 +1,105 @@
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ScrolledCanvas
+
+def _createOvals():
+    w = Test.currentWidget()
+    w.create_oval(50, 50, 150, 100, fill = 'red')
+    w.create_oval(100, 50, 150, 150, fill = 'blue')
+    w.create_oval(50, 100, 200, 350, fill = 'yellow')
+
+def _createWindow():
+    w = Test.currentWidget()
+    lb = Pmw.ScrolledListBox(w.interior(),
+           items = range(20), listbox_height = 6)
+    w.create_window(300, 100, window = lb)
+
+def _testYView(doBottom):
+    w = Test.currentWidget()
+    top, bottom = w.yview()
+    if type(top) != type(0.0) or type(bottom) != type(0.0):
+        return 'bad type ' + str(top) + ' ' + str(bottom)
+    if doBottom:
+        if bottom != 1.0:
+            return 'bottom is ' + str(bottom)
+    else:
+        if top != 0.0:
+            return 'top is ' + str(top)
+
+kw_1 = {'labelpos': 'n', 'label_text': 'ScrolledCanvas', 'borderframe' : 1}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 8),
+  (_createOvals, ()),
+  (c.resizescrollregion, ()),
+  (_createWindow, ()),
+  (c.resizescrollregion, ()),
+  ('hull_background', 'aliceblue'),
+  ('Scrollbar_borderwidth', 3),
+  ('hull_cursor', 'gumby'),
+  ('label_text', 'Label'),
+  ('Scrollbar_repeatdelay', 200),
+  ('Scrollbar_repeatinterval', 105),
+  ('vscrollmode', 'none'),
+  ('vscrollmode', 'static'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'none'),
+  ('hscrollmode', 'static'),
+  ('hscrollmode', 'dynamic'),
+  ('Scrollbar_width', 20),
+  ('vscrollmode', 'bogus', 'ValueError: bad vscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  ('hscrollmode', 'bogus', 'ValueError: bad hscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  (c.yview, ('moveto', 0.0)),
+  (_testYView, 0),
+  (c.yview, ('moveto', 0.02)),
+  (c.yview, ('moveto', 0.04)),
+  (c.yview, ('moveto', 0.06)),
+  (c.yview, ('moveto', 0.08)),
+  (c.yview, ('moveto', 0.10)),
+  (c.yview, ('moveto', 0.12)),
+  (c.yview, ('moveto', 0.14)),
+  (c.yview, ('moveto', 0.16)),
+  (c.yview, ('moveto', 0.18)),
+  (c.yview, ('moveto', 0.20)),
+  (c.yview, ('moveto', 0.22)),
+  (c.yview, ('moveto', 0.24)),
+  (c.yview, ('moveto', 0.26)),
+  (c.yview, ('moveto', 0.28)),
+  (c.yview, ('moveto', 0.98)),
+  (_testYView, 1),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -1, 'page')),
+  (_testYView, 0),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 1, 'page')),
+  (_testYView, 1),
+)
+
+kw_2 = {
+  'hscrollmode' : 'dynamic',
+  'label_text' : 'Label',
+  'labelpos' : 'n',
+  'scrollmargin': 20,
+  'canvasmargin': 20,
+  'usehullsize': 1,
+  'hull_width' : 500,
+  'hull_height' : 200,
+}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((Pmw.ScrolledCanvas, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ScrolledField_test.py b/Pmw/Pmw_1_2/tests/ScrolledField_test.py
new file mode 100644 (file)
index 0000000..4620caa
--- /dev/null
@@ -0,0 +1,32 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ScrolledField
+
+kw_1 = {'labelpos': 'nw'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 4),
+  ('text', 'Hello World'),
+  ('label_textvariable', Test.stringvar),
+  ('label_textvariable', ''),
+  ('label_text', 'Label'),
+  ('label_font', Test.font['small']),
+  ('label_image', Test.flagup),
+  ('label_image', ''),
+  ('entry_foreground', 'red'),
+  ('text', 'Foo'),
+  ('entry_font', Test.font['small']),
+)
+
+alltests = (
+  (tests_1, kw_1),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ScrolledFrame_test.py b/Pmw/Pmw_1_2/tests/ScrolledFrame_test.py
new file mode 100644 (file)
index 0000000..1248b74
--- /dev/null
@@ -0,0 +1,98 @@
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ScrolledFrame
+
+def _createInterior():
+    w = Test.currentWidget()
+    for i in range(3):
+       lb = Pmw.ScrolledListBox(w.interior(),
+               items = range(20), listbox_height = 6)
+       lb.pack(padx = 10, pady = 10)
+
+def _testYView(doBottom):
+    w = Test.currentWidget()
+    top, bottom = w.yview()
+    if type(top) != type(0.0) or type(bottom) != type(0.0):
+        return 'bad type ' + str(top) + ' ' + str(bottom)
+    if doBottom:
+        if bottom != 1.0:
+            return 'bottom is ' + str(bottom)
+    else:
+        if top != 0.0:
+            return 'top is ' + str(top)
+
+kw_1 = {'labelpos': 'n', 'label_text': 'ScrolledFrame'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 11),
+  (_createInterior, ()),
+  ('hull_background', 'aliceblue'),
+  ('Scrollbar_borderwidth', 3),
+  ('hull_cursor', 'gumby'),
+  ('label_text', 'Label'),
+  ('Scrollbar_repeatdelay', 200),
+  ('Scrollbar_repeatinterval', 105),
+  ('vscrollmode', 'none'),
+  ('vscrollmode', 'static'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'none'),
+  ('hscrollmode', 'static'),
+  ('hscrollmode', 'dynamic'),
+  ('Scrollbar_width', 20),
+  ('vscrollmode', 'bogus', 'ValueError: bad vscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  ('hscrollmode', 'bogus', 'ValueError: bad hscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  (c.cget, 'vscrollmode', 'bogus'),
+  (c.cget, 'hscrollmode', 'bogus'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'dynamic'),
+  (_testYView, 0),
+  (c.yview, ('moveto', 0.02)),
+  (c.yview, ('moveto', 0.04)),
+  (c.yview, ('moveto', 0.06)),
+  (c.yview, ('moveto', 0.08)),
+  (c.yview, ('moveto', 0.10)),
+  (c.yview, ('moveto', 0.12)),
+  (c.yview, ('moveto', 0.14)),
+  (c.yview, ('moveto', 0.16)),
+  (c.yview, ('moveto', 0.18)),
+  (c.yview, ('moveto', 0.20)),
+  (c.yview, ('moveto', 0.22)),
+  (c.yview, ('moveto', 0.24)),
+  (c.yview, ('moveto', 0.26)),
+  (c.yview, ('moveto', 0.28)),
+  (c.yview, ('moveto', 0.98)),
+  (_testYView, 1),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -1, 'page')),
+  (_testYView, 0),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 1, 'page')),
+  (_testYView, 1),
+)
+
+kw_2 = {
+  'hscrollmode' : 'dynamic',
+  'label_text' : 'Label',
+  'labelpos' : 'n',
+  'scrollmargin': 20,
+}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((Pmw.ScrolledFrame, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ScrolledListBox_test.py b/Pmw/Pmw_1_2/tests/ScrolledListBox_test.py
new file mode 100644 (file)
index 0000000..53b2ed5
--- /dev/null
@@ -0,0 +1,151 @@
+# Based on iwidgets2.2.0/tests/scrolledlistbox.test code.
+
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ScrolledListBox
+
+def _testYView(doBottom):
+    w = Test.currentWidget()
+    top, bottom = w.yview()
+    if type(top) != type(0.0) or type(bottom) != type(0.0):
+        return 'bad type ' + str(top) + ' ' + str(bottom)
+    if doBottom:
+        if bottom != 1.0:
+            return 'bottom is ' + str(bottom)
+    else:
+        if top != 0.0:
+            return 'top is ' + str(top)
+
+kw_1 = {
+  'labelpos': 'n',
+  'label_text': 'Start',
+  'listbox_height' : 20,
+  'listbox_width' : 40
+}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 9),
+  ('label_text', 'ScrolledListBox'),
+  ('listbox_height', 6),
+  ('listbox_width', 20),
+  ('listbox_borderwidth', 3),
+  ('hscrollmode', 'none'),
+  ('hscrollmode', 'static'),
+  ('hscrollmode', 'dynamic'),
+  (c.delete, (0, 'end')),
+  (c.insert, ('end', 'Hello', 'World')),
+  ('listbox_relief', 'raised'),
+  ('listbox_relief', 'sunken'),
+  ('Scrollbar_width', 20),
+  ('Scrollbar_width', 15),
+  ('listbox_background', 'GhostWhite'),
+  ('listbox_selectborderwidth', 3),
+  ('listbox_selectforeground', 'blue'),
+  ('listbox_selectmode', 'browse'),
+  ('listbox_selectmode', 'extended'),
+  ('listbox_selectmode', 'single'),
+  ('listbox_selectmode', 'multiple'),
+  ('listbox_font', Test.font['small']),
+  ('vscrollmode', 'none'),
+  ('vscrollmode', 'static'),
+  ('vscrollmode', 'dynamic'),
+  ('listbox_width', 30),
+  ('listbox_height', 20),
+  ('vscrollmode', 'bogus', 'ValueError: bad vscrollmode option "bogus": ' + \
+    'should be static, dynamic, or none'),
+  ('hscrollmode', 'bogus', 'ValueError: bad hscrollmode option "bogus": ' + \
+      'should be static, dynamic, or none'),
+  (c.cget, 'vscrollmode', 'bogus'),
+  (c.cget, 'hscrollmode', 'bogus'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'dynamic'),
+  (c.insert, (0, 'Test', 'Test', 'Test', 'Test')),
+  (c.insert, ('end', 'More Test')),
+  (c.delete, 1),
+  (c.delete, (0, 3)),
+  ('listbox_exportselection', 0),
+  (c.select_set, 0),
+  (c.select_set, (0, 1)),
+  (c.getcurselection, (), ('World', 'More Test')),
+  (c.select_clear, (0, 'end')),
+  (c.getcurselection, (), ()),
+  (c.delete, (0, 'end')),
+  (c.get, (0, 'end'), ()),
+  (c.insert, ('end', 'Test', 'Test', 'Long String Test')),
+  (c.get, (0, 'end'), ('Test', 'Test', 'Long String Test')),
+  (c.insert, (0, 'Test', 'Test A')),
+  (c.get, (0, 'end'), ('Test', 'Test A', 'Test', 'Test', 'Long String Test')),
+  (c.insert, (1, 'Test', 'Test', 'Long String Test')),
+  (c.get, (0, 4), ('Test', 'Test', 'Test', 'Long String Test', 'Test A')),
+  (c.insert, (5, 'Test', 'Test',
+    'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')),
+  (c.get, 7, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),
+  (c.get, 'end', 'Long String Test'),
+  (c.size, (), 11),
+  (c.delete, (3, 2)),
+  (c.size, (), 11),
+  (c.delete, (3, 3)),
+  (c.size, (), 10),
+  (c.clear, ()),
+  (c.size, (), 0),
+  (c.get, (), ()),
+  (c.yview, ('moveto', 0.0)),
+  (_testYView, 0),
+  (c.insert, ('end', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')),
+  (c.insert, ('end', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')),
+  (c.insert, ('end', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')),
+  (c.insert, ('end', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10')),
+  (_testYView, 0),
+  (c.yview, ('moveto', 0.02)),
+  (c.yview, ('moveto', 0.04)),
+  (c.yview, ('moveto', 0.06)),
+  (c.yview, ('moveto', 0.08)),
+  (c.yview, ('moveto', 0.10)),
+  (c.yview, ('moveto', 0.12)),
+  (c.yview, ('moveto', 0.14)),
+  (c.yview, ('moveto', 0.16)),
+  (c.yview, ('moveto', 0.18)),
+  (c.yview, ('moveto', 0.20)),
+  (c.yview, ('moveto', 0.22)),
+  (c.yview, ('moveto', 0.24)),
+  (c.yview, ('moveto', 0.26)),
+  (c.yview, ('moveto', 0.28)),
+  (c.yview, ('moveto', 0.98)),
+  (_testYView, 1),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -1, 'page')),
+  (_testYView, 0),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 1, 'page')),
+  (_testYView, 1),
+)
+
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+)
+
+alltests = [(tests_1, kw_1)]
+
+poslist = ('nw', 'n', 'ne', 'en', 'e', 'es', 'se', 's', 'sw', 'ws', 'w', 'wn',)
+for pos in poslist:
+    kw_2 = {
+      'listbox_selectmode' : 'extended',
+      'items' : ('Hello', 'Out There', 'World'),
+      'vscrollmode' : 'static',
+      'hscrollmode' : 'dynamic',
+      'label_text' : 'List',
+      'labelpos' : pos,
+      'scrollmargin': 10,
+    }
+    alltests.append((tests_2, kw_2))
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/ScrolledText_test.py b/Pmw/Pmw_1_2/tests/ScrolledText_test.py
new file mode 100644 (file)
index 0000000..53a5ab4
--- /dev/null
@@ -0,0 +1,116 @@
+# Based on iwidgets2.2.0/tests/scrolledtext.test code.   
+
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.ScrolledText
+
+def _testYView(doBottom):
+    w = Test.currentWidget()
+    top, bottom = w.yview()
+    if type(top) != type(0.0) or type(bottom) != type(0.0):
+        return 'bad type ' + str(top) + ' ' + str(bottom)
+    if doBottom:
+        if bottom != 1.0:
+            return 'bottom is ' + str(bottom)
+    else:
+        if top != 0.0:
+            return 'top is ' + str(top)
+
+kw_1 = {'labelpos': 'n', 'label_text': 'ScrolledText'}
+tests_1 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (Test.num_options, (), 10),
+  (c.importfile, 'ScrolledText_test.py'),
+  ('hull_background', 'aliceblue'),
+  ('text_borderwidth', 3),
+  ('Scrollbar_borderwidth', 3),
+  ('hull_cursor', 'gumby'),
+  ('text_exportselection', 0),
+  ('text_exportselection', 1),
+  ('text_foreground', 'Black'),
+  ('text_height', 10),
+  ('text_width', 20),
+  ('text_insertbackground', 'Black'),
+  ('text_insertborderwidth', 1),
+  ('text_insertofftime', 200),
+  ('text_insertontime', 500),
+  ('text_insertwidth', 3),
+  ('label_text', 'Label'),
+  ('text_relief', 'raised'),
+  ('text_relief', 'sunken'),
+  ('Scrollbar_repeatdelay', 200),
+  ('Scrollbar_repeatinterval', 105),
+  ('vscrollmode', 'none'),
+  ('vscrollmode', 'static'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'none'),
+  ('hscrollmode', 'static'),
+  ('hscrollmode', 'dynamic'),
+  ('Scrollbar_width', 20),
+  ('text_selectborderwidth', 2),
+  ('text_state', 'disabled'),
+  ('text_state', 'normal'),
+  ('text_background', 'GhostWhite'),
+  ('text_wrap', 'char'),
+  ('text_wrap', 'none'),
+  ('vscrollmode', 'bogus', 'ValueError: bad vscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  ('hscrollmode', 'bogus', 'ValueError: bad hscrollmode ' +
+    'option "bogus": should be static, dynamic, or none'),
+  (c.cget, 'vscrollmode', 'bogus'),
+  (c.cget, 'hscrollmode', 'bogus'),
+  ('vscrollmode', 'dynamic'),
+  ('hscrollmode', 'dynamic'),
+  (c.insert, ('end', 'Hello there\n')),
+  (_testYView, 0),
+  (c.yview, ('moveto', 0.02)),
+  (c.yview, ('moveto', 0.04)),
+  (c.yview, ('moveto', 0.06)),
+  (c.yview, ('moveto', 0.08)),
+  (c.yview, ('moveto', 0.10)),
+  (c.yview, ('moveto', 0.12)),
+  (c.yview, ('moveto', 0.14)),
+  (c.yview, ('moveto', 0.16)),
+  (c.yview, ('moveto', 0.18)),
+  (c.yview, ('moveto', 0.20)),
+  (c.yview, ('moveto', 0.22)),
+  (c.yview, ('moveto', 0.24)),
+  (c.yview, ('moveto', 0.26)),
+  (c.yview, ('moveto', 0.28)),
+  (c.yview, ('moveto', 0.98)),
+  (_testYView, 1),
+  (c.yview, ('scroll', -1, 'page')),
+  (c.yview, ('scroll', -50, 'page')),
+  (_testYView, 0),
+  (c.yview, ('scroll', 1, 'page')),
+  (c.yview, ('scroll', 50, 'page')),
+  (_testYView, 1),
+  (c.clear, ()),
+  (c.get, (), '\n'),
+)
+
+kw_2 = {
+  'hscrollmode' : 'dynamic',
+  'label_text' : 'Label',
+  'labelpos' : 'n',
+  'scrollmargin': 20,
+}
+tests_2 = (
+  (c.pack, (), {'padx' : 10, 'pady' : 10, 'fill' : 'both', 'expand' : 1}),
+  (c.importfile, 'ScrolledText_test.py'),
+  ('text_relief', 'raised'),
+  ('text_relief', 'sunken'),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((Pmw.ScrolledText, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/SelectionDialog_test.py b/Pmw/Pmw_1_2/tests/SelectionDialog_test.py
new file mode 100644 (file)
index 0000000..b36ad6b
--- /dev/null
@@ -0,0 +1,69 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.SelectionDialog
+
+kw_1 = {
+    'scrolledlist_labelpos': 'n',
+    'label_text' : 'Please select one',
+    'buttons' : ('OK', 'Cancel'),
+    'buttonbox_padx': 30,
+}
+tests_1 = (
+  (Test.num_options, (), 11),
+  ('hull_background', '#d9d9d9'),
+  (c.insert, ('end', 'Calling', 'all', 'cars')),
+  ('label_bitmap', 'warning'),
+  ('hull_cursor', 'gumby'),
+  ('label_image', Test.flagup),
+  ('listbox_font', Test.font['variable']),
+  ('listbox_foreground', 'red'),
+  ('listbox_selectmode', 'multiple'),
+  ('label_image', ''),
+  ('label_bitmap', ''),
+  (c.title, 'SelectionDialog 1: new title', ''),
+  (c.interior, (), Tkinter.Frame),
+  ('defaultbutton', 'OK'), 
+  (c.delete, (0, 'end')),
+  (c.get, (0, 'end'), ()),
+  (c.insert, ('end', 'Test', 'Test', 'Long String Test')),
+  (c.get, (0, 'end'), ('Test', 'Test', 'Long String Test')),
+  (c.insert, (0, 'Test', 'Test A')),
+  (c.get, (0, 'end'), ('Test', 'Test A', 'Test', 'Test', 'Long String Test')),
+  (c.insert, (1, 'Test', 'Test', 'Long String Test')),
+  (c.get, (0, 4), ('Test', 'Test', 'Test', 'Long String Test', 'Test A')),
+  (c.insert, (5, 'Test', 'Test',
+    'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')),
+  (c.get, 7, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'),
+  (c.get, 'end', 'Long String Test'),
+  (c.size, (), 11),
+  (c.delete, (3, 2)),
+  (c.size, (), 11),
+  (c.delete, (3, 3)),
+  (c.size, (), 10),
+  (c.clear, ()),
+  (c.size, (), 0),
+  (c.get, (), ()),
+)
+
+kw_2 = {
+    'buttons' : ('OK', 'Cancel'),
+    'buttonboxpos': 'e',
+    'scrolledlist_labelpos': 'n',
+}
+tests_2 = (
+  (c.title, 'SelectionDialog 2', ''),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/Test.py b/Pmw/Pmw_1_2/tests/Test.py
new file mode 100644 (file)
index 0000000..f6c4500
--- /dev/null
@@ -0,0 +1,521 @@
+# Functions used by widget tests.
+
+import imp
+import os
+import re
+import string
+import sys
+import traceback
+import types
+import Tkinter
+import _tkinter
+
+if Tkinter.TkVersion >= 8.4:
+  refcountafterdestroy = 7
+else:
+  refcountafterdestroy = 6
+
+script_name = imp.find_module(__name__)[1]
+if not os.path.isabs(script_name):
+    script_name = os.path.join(os.getcwd(), script_name)
+
+while 1:
+    script_dir = os.path.dirname(script_name)
+    if not os.path.islink(script_name):
+       break
+    script_name = os.path.join(script_dir, os.readlink(script_name))
+script_dir = os.path.join(os.getcwd(), script_dir)
+script_dir = os.path.normpath(script_dir)
+# Add the '../../..' directory to the path.
+package_dir = os.path.dirname(script_dir)
+package_dir = os.path.dirname(package_dir)
+package_dir = os.path.dirname(package_dir)
+sys.path[:0] = [package_dir]
+
+import Pmw
+# Need to import TestVersion, rather than do its work here, since
+# __name__ will be known there.
+import TestVersion
+
+# Set this to 1 to generate tracebacks on exceptions, rather than
+# catching them and continuing with the tests.
+# This is useful for debugging the test scripts.
+dont_even_try = 0
+
+_delay = 1
+_verbose = 0
+_printTraceback = 0
+_initialised = 0
+
+##############################################################################
+# Public functions:
+
+rand = 12345
+def random():
+    global rand
+    rand = (rand * 125) % 2796203
+    return rand
+
+def initialise():
+    global _initialised, font, flagup, earthris, emptyimage, \
+            stringvar, floatvar, root, reliefs
+    if not _initialised:
+       root = Tkinter.Tk(className = 'PmwTest')
+       root.withdraw()
+        if os.name == 'nt':
+            size = 16
+        else:
+            size = 12
+        Pmw.initialise(root, size = size, fontScheme = 'pmw2')
+       font = {}
+       font['small'] = '6x13'
+       font['large'] = '10x20'
+       font['variable'] = '-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*'
+       flagup = Tkinter.BitmapImage(file = 'flagup.bmp')
+       earthris = Tkinter.PhotoImage(file = 'earthris.gif')
+       emptyimage = Tkinter.PhotoImage()
+       stringvar = Tkinter.StringVar()
+       stringvar.set('this is some text')
+       floatvar = Tkinter.DoubleVar()
+       floatvar.set(50.0)
+       if haveBlt():
+           global vectorSize, vector_x, vector_y
+           vector_x = Pmw.Blt.Vector()
+           vector_y = []
+           for y in range(3):
+               vector_y.append(Pmw.Blt.Vector())
+           vectorSize = 50
+           for index in range(vectorSize):
+               vector_x.append(index)
+               vector_y[0].append(random() % 100)
+               vector_y[1].append(random() % 200)
+               vector_y[2].append(random() % 100 + 300)
+
+       # "solid" relief type was added to 8.0
+       if Tkinter.TkVersion >= 8.0:
+         reliefs = 'flat, groove, raised, ridge, solid, or sunken'
+       else:
+         reliefs = 'flat, groove, raised, ridge, or sunken'
+
+       _initialised = 1
+
+def haveBlt():
+    return Pmw.Blt.haveblt(root)
+
+def bell():
+    root.bell()
+
+def setdelay(newdelay):
+    global _delay
+    _delay = newdelay
+
+def setverbose(newverbose):
+    global _verbose
+    _verbose = newverbose
+
+def printtraceback(newprintTraceback = 1):
+    global _printTraceback
+    _printTraceback = newprintTraceback
+
+def num_options(widget):
+    return len(widget.configure())
+
+def callback():
+    return 1
+
+def callback1(dummy):
+    # Callback taking 1 argument
+    return dummy
+
+def callback2(dummy1, dummy2):
+    # Callback taking 2 arguments
+    return (dummy1, dummy2)
+
+def callbackN(*args):
+    # Callback taking zero or more arguments
+    return args
+
+def actioncallback():
+    w = currentWidget()
+    w.action('button press')
+
+def currentWidget():
+    return _currentWidget
+
+def delay():
+    return _delay
+
+def set_geom(width, height):
+    _currentToplevel.geometry(str(width) + 'x' + str(height))
+
+def runTests(allTestData):
+    root.after(_delay, _runTest, None, None, allTestData, 0, -1, -1)
+    root.mainloop()
+
+_pattern = None
+
+##############################################################################
+# Private functions:
+
+def _print_results(result, expected, description):
+    if type(expected) == types.ClassType:
+       if hasattr(result, '__class__'):
+           ok = (result.__class__ == expected)
+       else:
+           ok = 0
+    else:
+       ok = (result == expected)
+
+       # Megawidgets return a value of the correct type.  Tk widgets
+       # always return a string, so convert the string and check again.
+       if not ok:
+           if type(expected) == types.InstanceType:
+             if result == str(expected) and (
+                  expected is earthris or expected is stringvar or
+                 expected is floatvar or expected is flagup):
+               ok = 1
+              elif hasattr(_tkinter, 'Tcl_Obj') and \
+                    type(result) == _tkinter.Tcl_Obj:
+                  ok = (str(stringvar) == result.string)
+           elif type(expected) == types.IntType:
+               if type(result) is types.StringType:
+                   try:
+                       ok = (string.atoi(result) == expected)
+                   except ValueError:
+                       pass
+                elif hasattr(_tkinter, 'Tcl_Obj') and \
+                        type(result) == _tkinter.Tcl_Obj:
+                    ok = (string.atoi(str(result)) == expected)
+           elif type(expected) == types.FloatType:
+               if type(result) is types.StringType:
+                   try:
+                       ok = (string.atof(result) == expected)
+                   except ValueError:
+                       pass
+           elif expected == callback:
+               ok = re.search('^[0-9]*callback$', str(result)) is not None
+           elif expected == callback1:
+               ok = re.search('^[0-9]*callback1$', str(result)) is not None
+           elif expected == callback2:
+               ok = re.search('^[0-9]*callback2$', str(result)) is not None
+           elif expected == actioncallback:
+               ok = re.search('^[0-9]*actioncallback$',str(result)) is not None
+        
+    if not ok or _verbose > 0:
+       print '====', description
+       if not ok or _verbose > 1:
+           print '==== result was:'
+           print result, type(result)
+    if ok:
+       if _verbose > 1:
+           print '++++ PASSED'
+    else:
+        print '---- result should have been:'
+       print expected, type(expected)
+       if _printTraceback:
+           traceback.print_exc()
+       print '---- FAILED'
+       print
+
+def _destroyToplevel(top, title):
+    if _verbose > 0:
+       print '==== destruction of Toplevel for', title
+    top.destroy()
+
+def _Toplevel(title):
+    if _verbose > 0:
+       print '==== construction of Toplevel for', title
+    top = Tkinter.Toplevel()
+    top.geometry('+100+100')
+    top.title(title)
+    return top
+
+def _constructor(isWidget, top, classCmd, kw):
+    if _verbose > 0:
+       print '====', classCmd.__name__, 'construction'
+    if isWidget:
+       if dont_even_try:
+           w = apply(classCmd, (top,), kw)
+       else:
+           try:
+               w = apply(classCmd, (top,), kw)
+           except:
+               print 'Could not construct', classCmd.__name__
+               traceback.print_exc()
+               print 'Can not continue'
+               print 'Bye'
+               return None
+
+       isMegaWidget = hasattr(classCmd, 'defineoptions')
+       # Check the option types:
+       options = w.configure()
+       option_list = options.keys()
+       option_list.sort()
+       for option in option_list:
+           # Some of the options (like bd, bg and fg) have only two parts
+           # and are just abbreviations.  Only check 'real' options.
+           if len(options[option]) == 5:
+               initoption = isMegaWidget and w.isinitoption(option)
+               if dont_even_try:
+                   value = w.cget(option)
+                   if option not in ('class', 'container') and not initoption:
+                     apply(w.configure, (), {option : value})
+                     newvalue = w.cget(option)
+                     if newvalue != value:
+                       print '====', classCmd.__name__, 'widget', \
+                         '\'' + option + '\'', 'option'
+                       print '---- setting option returns different value'
+                        print '==== new value was:'
+                        print newvalue, type(newvalue)
+                        print '---- set value was:'
+                        print value, type(value)
+                       print '---- FAILED'
+                       print
+               else:
+                   try:
+                       value = w.cget(option)
+                       if option not in ('class', 'container') and not initoption:
+                         try:
+                             apply(w.configure, (), {option : value})
+                             newvalue = w.cget(option)
+                              if hasattr(_tkinter, 'Tcl_Obj') and \
+                              (
+                                    (type(newvalue) == _tkinter.Tcl_Obj
+                                        and str(newvalue) != str(value))
+                                    or
+                                    (type(newvalue) != _tkinter.Tcl_Obj
+                                        and newvalue != value)
+                              ) or \
+                              (
+                                  not hasattr(_tkinter, 'Tcl_Obj') and
+                                    newvalue != value
+                              ):
+                               print '====', classCmd.__name__, 'widget', \
+                                 '\'' + option + '\'', 'option'
+                               print '---- setting option returns different value'
+                                print '==== new value was:'
+                                print `newvalue`, type(newvalue)
+                                print '---- set value was:'
+                                print `value`, type(value)
+                               print '---- FAILED'
+                               print
+                         except:
+                           print '====', classCmd.__name__, 'widget', \
+                             '\'' + option + '\'', 'option'
+                           print '---- could not set option'
+                           print '---- FAILED'
+                           print
+                   except KeyError:
+                       print '====', classCmd.__name__, 'widget', \
+                           '\'' + option + '\'', 'option'
+                       print '---- unknown option'
+                       print '---- FAILED'
+                       print
+
+       if hasattr(classCmd, 'geometry'):
+           w.geometry('+100+100')
+           w.title(classCmd.__name__)
+    else:
+       w = apply(classCmd, (), kw)
+    return w
+
+def _destructor(widget, isWidget):
+    if _verbose > 0:
+        print '====', widget.__class__.__name__, 'destruction'
+    if isWidget:
+       if dont_even_try:
+           widget.destroy()
+       else:
+           try:
+               widget.destroy()
+                ref = sys.getrefcount(widget)
+                if ref != refcountafterdestroy:
+                    print '====', widget.__class__.__name__, 'destructor'
+                    print '---- refcount', ref, 'not zero after destruction'
+                    print '---- FAILED'
+                    print
+           except:
+               print 'Could not destroy', widget.__class__.__name__
+               traceback.print_exc()
+               print 'Can not continue'
+               print 'Bye'
+               return None
+    return 1
+
+# Structure of allTestData:
+# (
+#   (
+#     'ButtonBox', 
+#     (
+#       (
+#         Pmw.ButtonBox,
+#         {},
+#         (
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           ...
+#         )
+#       ),
+#       (
+#         Pmw.ButtonBox,
+#         {},
+#         (
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           ...
+#         )
+#       ),
+#       ...
+#     )
+#   ),
+#   (
+#     'ButtonBox', 
+#     (
+#       (
+#         Pmw.ButtonBox,
+#         {},
+#         (
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           ...
+#         )
+#       ),
+#       (
+#         Pmw.ButtonBox,
+#         {},
+#         (
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           (c.pack, ()),
+#           ...
+#         )
+#       ),
+#       ...
+#     )
+#   ),
+#   ...
+# )
+
+def _runTest(top, w, allTestData, index0, index1, index2):
+    if index0 >= len(allTestData):
+       root.quit()
+       return
+    classCmd, fileTests = allTestData[index0]
+    if classCmd == Tkinter.Menu:
+       isToplevel = 1
+    else:
+       isToplevel = hasattr(classCmd, 'userdeletefunc')
+    isWidget = hasattr(classCmd, 'cget')
+    title = classCmd.__name__
+
+    if index1 == -1:
+       if isToplevel:
+           top = None
+       else:
+           top = _Toplevel(title)
+       global _currentToplevel
+       _currentToplevel = top
+       index1 = 0
+    elif index1 >= len(fileTests):
+       if not isToplevel:
+           _destroyToplevel(top, title)
+       index1 = -1
+       index0 = index0 + 1
+    else:
+       methodTests, kw = fileTests[index1]
+       if index2 == -1:
+           w = _constructor(isWidget, top, classCmd, kw)
+           if w is None:
+               root.quit()
+               return
+           global _currentWidget
+           _currentWidget = w
+           index2 = 0
+       elif index2 >= len(methodTests):
+           if _destructor(w, isWidget) is None:
+               root.quit()
+               return
+           index2 = -1
+           index1 = index1 + 1
+       else:
+           methodTestData = methodTests[index2]
+           if type(methodTestData[0]) == types.StringType:
+               _configureTest(w, methodTestData)
+           else:
+               _methodTest(w, methodTestData)
+           index2 = index2 + 1
+    root.update()
+    root.after(_delay, _runTest, top, w, allTestData, index0, index1, index2)
+
+def _configureTest(w, testData):
+    option = testData[0]
+    value = testData[1]
+    if dont_even_try:
+       apply(w.configure, (), {option: value})
+       result = w.cget(option)
+    else:
+       try:
+           apply(w.configure, (), {option: value})
+           result = w.cget(option)
+       except:
+           result = _getErrorValue()
+    if len(testData) > 2:
+       expected = testData[2]
+    else:
+       expected = value
+    _print_results(result, expected, \
+       w.__class__.__name__ + ' option ' + str(testData))
+
+def _getErrorValue():
+    exc_type, exc_value, exc_traceback = sys.exc_info()
+    if type(exc_type) == types.ClassType:
+       # Handle python 1.5 class exceptions.
+       exc_type = exc_type.__name__
+    if type(exc_value) == types.StringType:
+       return exc_type + ': ' + exc_value
+    else:
+        exc_value_str = str(exc_value)
+        if exc_value_str[:1] == "'" and exc_value_str[-1:] == "'":
+            exc_value_str = exc_value_str[1:-1]
+        return exc_type + ': ' + exc_value_str
+
+def _methodTest(w, testData):
+    func = testData[0]
+    args = testData[1]
+    kw = {}
+    expected = None
+    if len(testData) == 3:
+       if type(testData[2]) == types.DictionaryType:
+           kw = testData[2]
+       else:
+           expected = testData[2]
+    elif len(testData) > 3:
+       kw = testData[2]
+       expected = testData[3]
+    if type(args) != types.TupleType:
+       args = (args,)
+    if func is num_options:
+       args = (w,) + args
+    origArgs = args
+    if type(func) == types.MethodType and func.im_self is None:
+       args = (w,) + args
+    if dont_even_try:
+       result = apply(func, args, kw)
+    else:
+       try:
+           result = apply(func, args, kw)
+       except:
+           result = _getErrorValue()
+    if hasattr(func, 'im_func'):
+       name = w.__class__.__name__ + ' method ' + \
+           func.im_func.func_code.co_name
+    else:
+       name = 'function ' + func.__name__
+    name = name + ' ' + str(origArgs)
+    if kw:
+       name = name + ' ' + str(kw)
+    _print_results(result, expected, name)
diff --git a/Pmw/Pmw_1_2/tests/TestVersion.py b/Pmw/Pmw_1_2/tests/TestVersion.py
new file mode 100644 (file)
index 0000000..265c065
--- /dev/null
@@ -0,0 +1,19 @@
+# Set the version of Pmw to use for the tests based on the directory
+# name.
+
+import imp
+import os
+import string
+import Pmw
+
+file = imp.find_module(__name__)[1]
+if not os.path.isabs(file):
+    file = os.path.join(os.getcwd(), file)
+file = os.path.normpath(file)
+
+dir = os.path.dirname(file)
+dir = os.path.dirname(dir)
+dir = os.path.basename(dir)
+
+version = string.replace(dir[4:], '_', '.')
+Pmw.setversion(version)
diff --git a/Pmw/Pmw_1_2/tests/TextDialog_test.py b/Pmw/Pmw_1_2/tests/TextDialog_test.py
new file mode 100644 (file)
index 0000000..5736e8e
--- /dev/null
@@ -0,0 +1,53 @@
+import Tkinter
+import Test
+import Pmw
+
+Test.initialise()
+
+c = Pmw.TextDialog
+
+kw_1 = {
+    'scrolledtext_labelpos': 'n',
+    'label_text' : 'Here is the news',
+    'buttons' : ('OK', 'Cancel'),
+    'buttonbox_padx': 30,
+}
+tests_1 = (
+  (Test.num_options, (), 11),
+  ('text_wrap', 'none'),
+  ('text_state', 'disabled'),
+  ('hull_background', '#d9d9d9'),
+  ('label_bitmap', 'warning'),
+  ('hull_cursor', 'gumby'),
+  ('label_image', Test.flagup),
+  ('text_font', Test.font['variable']),
+  ('text_foreground', 'red'),
+  ('text_padx', 15),
+  ('text_pady', 15),
+  ('label_image', ''),
+  ('label_bitmap', ''),
+  (c.title, 'TextDialog 1: new title', ''),
+  (c.interior, (), Tkinter.Frame),
+  ('defaultbutton', 'OK'), 
+  (c.clear, ()),
+  (c.get, (), '\n'),
+)
+
+kw_2 = {
+    'buttons' : ('OK', 'Cancel'),
+    'buttonboxpos': 'e',
+    'scrolledtext_labelpos': 'n',
+}
+tests_2 = (
+  (c.title, 'TextDialog 2', ''),
+)
+
+alltests = (
+  (tests_1, kw_1),
+  (tests_2, kw_2),
+)
+
+testData = ((c, alltests),)
+
+if __name__ == '__main__':
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/Tkinter_test.py b/Pmw/Pmw_1_2/tests/Tkinter_test.py
new file mode 100644 (file)
index 0000000..7e5d8f5
--- /dev/null
@@ -0,0 +1,393 @@
+# Tests for basic Tkinter widgets.
+
+import Tkinter
+import Test
+
+Test.initialise()
+testData = ()
+
+if Tkinter.TkVersion >= 8.0:
+  button_num = 31
+  frame_num = 16
+  menu_num = 20
+  menubutton_num = 32
+else:
+  button_num = 30
+  frame_num = 15
+  menu_num = 19
+  menubutton_num = 31
+
+c = Tkinter.Button
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), button_num),
+  ('text', 'Hello World'),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  ('command', Test.callback),
+  (c.flash, ()),
+  (c.invoke, (), '1'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Canvas
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 27),
+  ('background', 'aliceblue'),
+  (c.create_oval, (100, 100, 200, 200),
+      {'fill' : 'lightsteelblue1', 'tags' : 'circle'}, 1),
+  (c.create_rectangle, (200, 100, 300, 200),
+      {'fill' : 'lightsteelblue2', 'tags' : 'square'}, 2),
+  (c.create_text, (0, 200),
+      {'text' : 'Hello, world', 'tags' : 'words', 'anchor' : 'w'}, 3),
+  (c.addtag_withtag, ('lightsteelblue1', 'circle')),
+  (c.bbox, ('circle', 'square'), (99, 99, 301, 201)),
+  (c.tag_bind, ('circle', '<1>', Test.callback)),
+  (c.tag_bind, 'circle', '<Button-1>'),
+  (c.tag_unbind, ('circle', '<1>')),
+  (c.canvasx, 100, 100.0),
+  (c.canvasy, 100, 100.0),
+  (c.coords, 'circle', [100.0, 100.0, 200.0, 200.0]),
+  (c.coords, ('circle', 0, 0, 300, 300), []),
+  (c.coords, 'circle', [0.0, 0.0, 300.0, 300.0]),
+  (c.find_withtag, 'lightsteelblue1', (1,)),
+  (c.focus, 'circle', ''),
+  (c.gettags, 'circle', ('circle', 'lightsteelblue1')),
+  (c.icursor, ('words', 7)),
+  (c.index, ('words', 'insert'), 7),
+  (c.insert, ('words', 'insert', 'cruel ')),
+  (c.itemconfigure, 'circle', {'fill': 'seagreen4'}),
+  (c.itemcget, ('circle', 'fill'), 'seagreen4'),
+  (c.lower, 'words'),
+  (c.move, ('square', -50, -50)),
+  (c.tkraise, ('words', 'circle')),
+  (c.scale, ('circle', 150, 150, 1.0, 0.5)),
+  (c.select_from, ('words', 0)),
+  (c.select_to, ('words', 'end')),
+  (c.delete, 'square'),
+  (c.type, 'circle', 'oval'),
+  (c.dtag, 'lightsteelblue1'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Checkbutton
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 36),
+  ('text', 'Hello World'),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  ('command', Test.callback),
+  (c.flash, ()),
+  (c.invoke, (), '1'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Entry
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 28),
+  ('background', 'lightsteelblue1'),
+  (c.insert, ('insert', 'Hello, Brian!')),
+  (c.delete, (7, 12)),
+  (c.icursor, 7),
+  (c.insert, ('insert', 'world')),
+  (c.get, (), 'Hello, world!'),
+  (c.index, 'insert', 12),
+  (c.selection_from, 7),
+  (c.selection_to, '12'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Frame
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), frame_num),
+  ('background', 'lightsteelblue1'),
+  ('width', 300),
+  ('height', 50),
+  ('background', 'lightsteelblue1'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Label
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 25),
+  ('text', 'Hello World'),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  ('image', Test.earthris),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Listbox
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 23),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  (c.insert, (0, 'ABC', 'DEF', 'GHI', 'XXXXXXXXXXXX')),
+  (c.activate, 1),
+  (c.select_set, (2, 3)),
+  (c.curselection, (), ('2', '3')),
+  (c.delete, 1),
+  (c.get, 1, 'GHI'),
+  (c.get, (0, 1), ('ABC', 'GHI')),
+  (c.index, 'end', 3),
+  (c.nearest, 1, 0),
+  (c.see, 1),
+  (c.size, (), 3),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Menu
+tests = (
+  (Test.num_options, (), menu_num),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  (c.add_command, (),
+      {'background': 'lightsteelblue2', 'label': 'Hello World'}),
+  (c.add_checkbutton, (),
+      {'background': 'lightsteelblue2', 'label': 'Charm'}),
+  (c.post, (100, 100)),
+  (c.activate, 1),
+  (c.entryconfigure, 'Hello World', {'background': 'aliceblue'}),
+  (c.entrycget, ('Hello World', 'background'), 'aliceblue'),
+  (c.index, 'end', 2),
+  ('tearoff', 0),
+  (c.index, 'end', 1),
+  (c.insert_radiobutton, 'Charm',
+      {'background': 'lightsteelblue2', 'label': 'Niceness',
+          'command': Test.callback}),
+  (c.invoke, 'Niceness', '1'),
+  (c.delete, 'Charm'),
+  (c.type, 'Hello World', 'command'),
+  (c.yposition, 'Hello World', 2),
+  (c.unpost, ()),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Menubutton
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), menubutton_num),
+  ('text', 'Hello World'),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Message
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 21),
+  ('text', 'Hello World'),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  ('text', 'Hello\nCruel Cruel World'),
+  ('borderwidth', 100),
+  ('justify', 'center'),
+  ('justify', 'right'),
+  ('justify', 'left'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Radiobutton
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 35),
+  ('text', 'Hello World'),
+  ('value', 'Foo Bar'),
+  ('variable', Test.stringvar),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  ('text', 'Hello\nCruel Cruel World'),
+  ('command', Test.callback),
+  (c.select, ()),
+  (Test.stringvar.get, (), 'Foo Bar'),
+  (c.flash, ()),
+  (c.invoke, (), '1'),
+  (c.deselect, ()),
+  (Test.stringvar.get, (), ''),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Scale
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 33),
+  ('showvalue', 1),
+  ('orient', 'horizontal'),
+  ('from', 100.0),
+  ('to', 200.0),
+  ('variable', Test.floatvar),
+  ('background', 'lightsteelblue1'),
+  ('foreground', 'seagreen4'),
+  ('command', Test.callback1),
+  (c.set, 150.0),
+  (c.get, (), 150.0),
+  (c.get, 123, 'TypeError: too many arguments; expected 1, got 2'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Scrollbar
+tests = (
+  (c.pack, (), {'fill': 'x'}),
+  (Test.num_options, (), 20),
+  ('orient', 'horizontal'),
+  (Test.set_geom, (300, 50)),
+  (c.set, (0.3, 0.7)),
+  ('background', 'lightsteelblue1'),
+  ('troughcolor', 'aliceblue'),
+  (c.get, (), (0.3, 0.7)),
+  (c.activate, 'slider'),
+  (c.set, (0.5, 0.9)),
+  (c.delta, (0, 0), 0),
+  (c.fraction, (0, 0), 0),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+c = Tkinter.Text
+tests = (
+  (c.pack, ()),
+  (Test.num_options, (), 35),
+  ('background', 'lightsteelblue1'),
+  (c.insert, ('end', 'This little piggy is bold.', 'bold', '\n')),
+  (c.insert, ('end', 'This little piggy is in green.', 'green', '\n')),
+  (c.insert, ('end', 'This line is a mistake.\n')),
+  (c.insert, ('end', 'This little piggy is crossed out.', 'overstrike', '\n')),
+  (c.insert, ('end', 'This little piggy is raised.', 'raised', '\n')),
+  (c.insert, ('end', 'This little piggy is underlined.', 'underline', '\n')),
+  (c.tag_configure, 'bold', {'font': Test.font['variable']}),
+  (c.tag_configure, 'green', {'background': 'seagreen1'}),
+  (c.tag_configure, 'overstrike', {'overstrike': 1}),
+  (c.tag_configure, 'raised',
+      {'background': 'aliceblue', 'borderwidth': 2, 'relief': 'raised'}),
+  (c.tag_configure, 'underline', {'underline': 1}),
+  (c.compare, ('2.0', '<', 'end'), 1),
+  (c.delete, ('3.0', '4.0')),
+  (c.get, ('1.0', '1.4'), 'This'),
+  (c.index, 'end', '7.0'),
+  (c.mark_set, ('my_mark', '4.9')),
+  (c.mark_gravity, ('my_mark', 'right'), ''),
+  (c.mark_gravity, 'my_mark', 'right'),
+  (c.mark_names, (), ('my_mark', 'insert', 'current')),
+  (c.mark_unset, 'my_mark'),
+  (c.insert, ('end', '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n')),
+  (c.insert, ('end', 'This is the last line.')),
+  (c.scan_mark, (0, 20)),
+  (c.scan_dragto, (0, 0)),
+  (c.scan_dragto, (0, 20)),
+  (c.tag_add, ('green', '1.0', '1.4')),
+  (c.tag_cget, ('raised', 'background'), 'aliceblue'),
+  (c.tag_lower, 'green'),
+  (c.tag_names, (),
+      ('green', 'sel', 'bold', 'overstrike', 'raised', 'underline')),
+  (c.tag_nextrange, ('raised', '0.0'), ('4.0', '4.28')),
+  (c.tag_raise, 'green'),
+  (c.tag_ranges, 'green', ('1.0', '1.4', '2.0', '2.30')),
+  (c.tag_remove, ('green', '1.0', '1.4')),
+  (c.tag_ranges, 'green', ('2.0', '2.30')),
+  (c.tag_delete, 'green'),
+  (c.search, ('Gre.n', '0.0'), {'regexp': 1, 'nocase': 1}, '2.24'),
+  (c.search, ('Gre.n', '3.0', 'end'), {'regexp': 1, 'nocase': 1}, ''),
+  (c.see, 'end'),
+  (c.see, '0.0'),
+)
+testData = testData + ((c, ((tests, {}),)),)
+
+#=============================================================================
+
+# Grid command
+
+def _makeGridButtons():
+  w = Test.currentWidget()
+  b1 = Tkinter.Button(w, text = 'Button 1')
+  b2 = Tkinter.Button(w, text = 'Button 2')
+  b3 = Tkinter.Button(w, text = 'Button 3')
+  b4 = Tkinter.Button(w, text = 'Button 4')
+  b5 = Tkinter.Button(w, text = 'Button 5')
+  b6 = Tkinter.Button(w, text = 'Button 6')
+  b7 = Tkinter.Button(w, text = 'Button 7')
+  b8 = Tkinter.Button(w, text = 'Button 8')
+
+  b1.grid(column=0, row=0)
+  b2.grid(column=1, row=0)
+  b3.grid(column=2, row=0, ipadx=50, ipady=50, padx=50, pady=50, sticky='nsew')
+  b4.grid(column=3, row=0)
+  b5.grid(column=0, row=1)
+  b6.grid(column=2, row=1, columnspan=2, rowspan=2, sticky='nsew')
+  b7.grid(column=0, row=2)
+  b8.grid(column=0, row=3, columnspan=4, padx=50, sticky='ew')
+
+def _checkGridSlaves():
+  w = Test.currentWidget()
+  return len(w.grid_slaves())
+
+def _checkGridInfo():
+  w = Test.currentWidget()
+  b8 = w.grid_slaves(column=0, row=3)[0]
+  info = b8.grid_info()
+  if info['in'] == w:
+    rtn = {}
+    for key, value in info.items():
+      if key != 'in':
+        rtn[key] = value
+    return rtn
+  return 'BAD'
+
+def _checkGridForget():
+  w = Test.currentWidget()
+  b8 = w.grid_slaves(column=0, row=3)[0]
+  b8.grid_forget()
+  return w.grid_size()
+
+# The -pad grid option was added in Tk 4.2.
+# Could not do columnconfigure(0) before Tk 4.2.
+if Tkinter.TkVersion >= 4.2:
+  padTest = {'pad': 25}
+  colTest = {'minsize': 100, 'pad': 25, 'weight': 1}
+  rowTest = {'minsize': 100, 'pad': 0, 'weight': 1}
+else:
+  padTest = {'minsize': 100}
+  colTest = 'TclError: wrong # args: should be "grid columnconfigure master index ?-option value...?"'
+  rowTest = 'TclError: wrong # args: should be "grid rowconfigure master index ?-option value...?"'
+
+c = Tkinter.Frame
+tests = (
+  (c.pack, (), {'fill': 'both', 'expand': 1}),
+  (_makeGridButtons, ()),
+  # (c.grid_bbox, (1, 2), (85, 268, 85, 34)),
+  (c.grid_columnconfigure, (0, 'minsize'), 0),
+  (c.grid_columnconfigure, (0, 'weight'), 0),
+  (c.grid_columnconfigure, 0, {'minsize': 100, 'weight': 1}),
+  (c.grid_columnconfigure, 0, padTest),
+  (c.grid_columnconfigure, 0, {}, colTest),
+  (c.grid_columnconfigure, (0, 'minsize'), 100),
+  (c.grid_columnconfigure, (0, 'weight'), 1),
+  (c.location, (200, 100), (2, 0)),
+  (c.grid_propagate, (), 1),
+  (c.grid_propagate, 0),
+  (c.grid_propagate, (), 0),
+  (c.grid_rowconfigure, (0, 'minsize'), 0),
+  (c.grid_rowconfigure, (0, 'weight'), 0),
+  (c.grid_rowconfigure, 0, {'minsize': 100, 'weight': 1}),
+  (c.grid_rowconfigure, 0, {}, rowTest),
+  (c.grid_size, (), (4, 4)),
+  (_checkGridSlaves, (), 8),
+  (_checkGridInfo, (), {}, {'column': '0', 'columnspan': '4',
+    'ipadx': '0', 'ipady': '0', 'padx': '50', 'pady': '0',
+    'row': '3', 'rowspan': '1', 'sticky': 'ew',
+  }),
+  (_checkGridForget, (), (4, 3)),
+  (_checkGridSlaves, (), 7),
+)
+    
+testData = testData + ((c, ((tests, {}),)),)
+
+if __name__ == '__main__':
+    #Test.setverbose(1)
+    #Test.setdelay(1000)
+    Test.runTests(testData)
diff --git a/Pmw/Pmw_1_2/tests/earthris.gif b/Pmw/Pmw_1_2/tests/earthris.gif
new file mode 100644 (file)
index 0000000..c4ee473
Binary files /dev/null and b/Pmw/Pmw_1_2/tests/earthris.gif differ
diff --git a/Pmw/Pmw_1_2/tests/flagup.bmp b/Pmw/Pmw_1_2/tests/flagup.bmp
new file mode 100644 (file)
index 0000000..6eb0d84
--- /dev/null
@@ -0,0 +1,27 @@
+#define flagup_width 48
+#define flagup_height 48
+static char flagup_bits[] = {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00,
+   0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xef, 0x6a, 0x00,
+   0x00, 0x00, 0xc0, 0x7b, 0x75, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0x6a, 0x00,
+   0x00, 0x00, 0x30, 0x60, 0x75, 0x00, 0x00, 0x00, 0x18, 0xe0, 0x7f, 0x00,
+   0x00, 0x00, 0x0c, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x06, 0xe0, 0x04, 0x00,
+   0x00, 0x00, 0x03, 0xe0, 0x04, 0x00, 0x00, 0x80, 0x01, 0xe0, 0x06, 0x00,
+   0x00, 0xc0, 0x1f, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x7f, 0xe0, 0x07, 0x00,
+   0x00, 0x70, 0xe0, 0xe0, 0x05, 0x00, 0x00, 0x38, 0x80, 0xe1, 0x04, 0x00,
+   0x00, 0x18, 0x80, 0xf1, 0x04, 0x00, 0x00, 0x0c, 0x00, 0xfb, 0x04, 0x00,
+   0x00, 0x0c, 0x00, 0xff, 0x04, 0x00, 0x00, 0x86, 0x1f, 0xee, 0x04, 0x00,
+   0x00, 0x06, 0x06, 0xe6, 0x04, 0x00, 0x00, 0x06, 0x00, 0xe6, 0x04, 0x00,
+   0x00, 0x06, 0x00, 0xe6, 0x04, 0x00, 0x00, 0x06, 0x00, 0x66, 0x04, 0x00,
+   0x7f, 0x56, 0x52, 0x06, 0xe4, 0xff, 0x00, 0x76, 0x55, 0x06, 0x04, 0x00,
+   0x00, 0x56, 0x57, 0x06, 0x04, 0x00, 0x00, 0x56, 0x55, 0x06, 0x06, 0x00,
+   0x00, 0x56, 0xd5, 0x06, 0x03, 0x00, 0x00, 0x06, 0x00, 0x86, 0x01, 0x00,
+   0x54, 0x06, 0x00, 0xc6, 0x54, 0x55, 0xaa, 0x06, 0x00, 0x66, 0xaa, 0x2a,
+   0x54, 0x06, 0x00, 0x36, 0x55, 0x55, 0xaa, 0x06, 0x00, 0xbe, 0xaa, 0x2a,
+   0x54, 0xfe, 0xff, 0x6f, 0x55, 0x55, 0xaa, 0xfc, 0xff, 0xa7, 0xaa, 0x2a,
+   0x54, 0x01, 0x88, 0x60, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa0, 0xaa, 0x2a,
+   0x54, 0x55, 0x8d, 0x60, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa0, 0xaa, 0x2a,
+   0x54, 0x55, 0x8d, 0x60, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa0, 0xaa, 0x2a,
+   0x54, 0x55, 0x8d, 0x50, 0x55, 0x55, 0xaa, 0xaa, 0x8a, 0xa8, 0xaa, 0x2a,
+   0x54, 0x55, 0x95, 0x54, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a,
+   0x54, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/Pmw/README b/Pmw/README
new file mode 100644 (file)
index 0000000..eb03c25
--- /dev/null
@@ -0,0 +1,10 @@
+
+                       Python megawidgets
+
+    Pmw is a toolkit for building high-level compound widgets in
+    Python using the Tkinter module.
+
+    All documentation about Pmw is in the form of html files stored in
+    the 'doc' directory of each release of Pmw.  Please use your Web
+    browser to view the file 'doc/index.html' in the directory
+    containing the most recent release.
diff --git a/Pmw/__init__.py b/Pmw/__init__.py
new file mode 100644 (file)
index 0000000..158705c
--- /dev/null
@@ -0,0 +1,40 @@
+# This file is executed when the Pmw package is imported.  It creates
+# a lazy importer/dynamic loader for Pmw and replaces the Pmw module
+# with it.  Even though the loader from the most recent installed
+# version of Pmw is used, the user is able to specify which version of
+# Pmw megawidgets to load by using the setversion() function of the
+# loader.
+
+# This is the only file in Pmw which is not part of a particular Pmw
+# release.
+
+import sys
+import os
+import re
+
+def _hasLoader(dir):
+    # Only accept Pmw_V_R_P with single digits, since ordering will
+    # not work correctly with multiple digits (for example, Pmw_10_0
+    # will be before Pmw_9_9).
+    if re.search('^Pmw_[0-9]_[0-9](_[0-9])?$', dir) is not None:
+        for suffix in ('.py', '.pyc', '.pyo'):
+            path = os.path.join(_dir, dir, 'lib', 'PmwLoader' + suffix)
+            if os.path.isfile(path):
+                return 1
+    return 0
+
+# First get a list of all subdirectories containing versions of Pmw.
+_dir = __path__[0]
+_listdir = os.listdir(_dir)
+_instdirs = filter(_hasLoader, _listdir)
+_instdirs.sort()
+_instdirs.reverse()
+
+# Using the latest version import the dynamic loader.
+_loader = 'Pmw.' + _instdirs[0] + '.lib.PmwLoader'
+__import__(_loader)
+_mod = sys.modules[_loader]
+
+# Create the dynamic loader and install it into sys.modules.
+sys.modules['_Pmw'] = sys.modules['Pmw']
+sys.modules['Pmw'] = _mod.PmwLoader(_dir, _instdirs, _listdir)