Browse Source

*** empty log message ***

Mark Mine 24 years ago
parent
commit
c6178a4d81

+ 2 - 2
direct/src/directtools/DirectSession.py

@@ -12,7 +12,7 @@ from ClusterServer import *
 from ClusterConfig import *
 from ClusterConfig import *
 from tkSimpleDialog import askstring
 from tkSimpleDialog import askstring
 import Placer
 import Placer
-import EntryScale
+import Slider
 import SceneGraphExplorer
 import SceneGraphExplorer
 import OnscreenText
 import OnscreenText
 import types
 import types
@@ -149,7 +149,7 @@ class DirectSession(PandaObject):
             ['SGE_Show All', self.showAllDescendants],
             ['SGE_Show All', self.showAllDescendants],
             ['SGE_Fit', self.fitOnNodePath],
             ['SGE_Fit', self.fitOnNodePath],
             ['SGE_Place', Placer.place],
             ['SGE_Place', Placer.place],
-            ['SGE_Set Color', EntryScale.rgbPanel],
+            ['SGE_Set Color', Slider.rgbPanel],
             ['SGE_Explore', SceneGraphExplorer.explore],
             ['SGE_Explore', SceneGraphExplorer.explore],
             ['SGE_Delete', self.removeNodePath],
             ['SGE_Delete', self.removeNodePath],
             ['SGE_Set Name', self.getAndSetName],
             ['SGE_Set Name', self.getAndSetName],

+ 2 - 2
direct/src/extensions/NodePath-extensions.py

@@ -803,8 +803,8 @@
         base.wantTk = 1
         base.wantTk = 1
         base.wantDIRECT = 1
         base.wantDIRECT = 1
         import TkGlobal
         import TkGlobal
-        import EntryScale
-        return EntryScale.rgbPanel(self, cb)
+        import Slider
+        return Slider.rgbPanel(self, cb)
 
 
     def select(self):
     def select(self):
         base.wantTk = 1
         base.wantTk = 1

+ 0 - 1
direct/src/leveleditor/LevelEditor.py

@@ -10,7 +10,6 @@ from tkFileDialog import *
 from whrandom import *
 from whrandom import *
 import Pmw
 import Pmw
 import Floater
 import Floater
-import EntryScale
 import VectorWidgets
 import VectorWidgets
 import string
 import string
 import os
 import os

+ 3 - 3
direct/src/showbase/PythonUtil.py

@@ -276,7 +276,7 @@ def adjust(command = None, parent = None, **kw):
     adjust(command = None, parent = None, **kw)
     adjust(command = None, parent = None, **kw)
     Popup and entry scale to adjust a parameter
     Popup and entry scale to adjust a parameter
     
     
-    Accepts any EntryScale keyword argument.  Typical arguments include:
+    Accepts any Slider keyword argument.  Typical arguments include:
     command: The one argument command to execute
     command: The one argument command to execute
     min: The min value of the slider
     min: The min value of the slider
     max: The max value of the slider
     max: The max value of the slider
@@ -294,7 +294,7 @@ def adjust(command = None, parent = None, **kw):
     # Make sure we enable Tk
     # Make sure we enable Tk
     import TkGlobal
     import TkGlobal
     import Tkinter
     import Tkinter
-    import EntryScale
+    import Slider
     import Pmw
     import Pmw
     # Create toplevel if needed
     # Create toplevel if needed
     if not parent:
     if not parent:
@@ -303,7 +303,7 @@ def adjust(command = None, parent = None, **kw):
     # Set command if specified
     # Set command if specified
     if command:
     if command:
         kw['command'] = command
         kw['command'] = command
-    es = apply(EntryScale.EntryScale, (parent,), kw)
+    es = apply(Slider.Slider, (parent,), kw)
     es.pack(expand = 1, fill = 'x')
     es.pack(expand = 1, fill = 'x')
     es.parent = parent
     es.parent = parent
     return es
     return es

+ 28 - 35
direct/src/tkpanels/DirectSessionPanel.py

@@ -8,7 +8,7 @@ import string
 import Pmw
 import Pmw
 import Dial
 import Dial
 import Floater
 import Floater
-import EntryScale
+import Slider
 import VectorWidgets
 import VectorWidgets
 import SceneGraphExplorer
 import SceneGraphExplorer
 from TaskManagerPanel import TaskManagerWidget
 from TaskManagerPanel import TaskManagerWidget
@@ -24,8 +24,8 @@ class DirectSessionPanel(AppShell):
     # Override class variables here
     # Override class variables here
     appname = 'Direct Session Panel'
     appname = 'Direct Session Panel'
     frameWidth      = 600
     frameWidth      = 600
-    frameHeight     = 502
-    usecommandarea = 1
+    frameHeight     = 365
+    usecommandarea = 0
     usestatusarea  = 0
     usestatusarea  = 0
 
 
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
@@ -102,6 +102,17 @@ class DirectSessionPanel(AppShell):
                                  label = 'Enable Grid',
                                  label = 'Enable Grid',
                                  variable = self.directGridEnabled,
                                  variable = self.directGridEnabled,
                                  command = self.toggleDirectGrid)
                                  command = self.toggleDirectGrid)
+
+        self.menuBar.addmenuitem('DIRECT', 'command',
+                                 'Toggle Object Handles Visability',
+                                 label = 'Toggle Widget Viz',
+                                 command = direct.toggleWidgetVis)
+
+        self.menuBar.addmenuitem(
+            'DIRECT', 'command',
+            'Toggle Widget Move/COA Mode',
+            label = 'Toggle Widget Mode',
+            command = direct.manipulationControl.toggleObjectHandlesMode)
         
         
         # Get a handle to the menu frame
         # Get a handle to the menu frame
         menuFrame = self.menuFrame
         menuFrame = self.menuFrame
@@ -150,7 +161,7 @@ class DirectSessionPanel(AppShell):
         self.SGE = SceneGraphExplorer.SceneGraphExplorer(
         self.SGE = SceneGraphExplorer.SceneGraphExplorer(
             sgeFrame, nodePath = render,
             sgeFrame, nodePath = render,
             scrolledCanvas_hull_width = 250,
             scrolledCanvas_hull_width = 250,
-            scrolledCanvas_hull_height = 400)
+            scrolledCanvas_hull_height = 300)
         self.SGE.pack(fill = BOTH, expand = 0)
         self.SGE.pack(fill = BOTH, expand = 0)
         sgeFrame.pack(side = LEFT, fill = 'both', expand = 0)
         sgeFrame.pack(side = LEFT, fill = 'both', expand = 0)
 
 
@@ -212,7 +223,7 @@ class DirectSessionPanel(AppShell):
 
 
         fovFrame = Frame(drFrame)
         fovFrame = Frame(drFrame)
         fovFloaterFrame = Frame(fovFrame)
         fovFloaterFrame = Frame(fovFrame)
-        self.hFov = EntryScale.EntryScale(
+        self.hFov = Slider.Slider(
             fovFloaterFrame,
             fovFloaterFrame,
             text = 'Horizontal FOV',
             text = 'Horizontal FOV',
             min = 0.01, max = 170.0)
             min = 0.01, max = 170.0)
@@ -220,7 +231,7 @@ class DirectSessionPanel(AppShell):
         self.hFov.pack(fill = X, expand = 0)
         self.hFov.pack(fill = X, expand = 0)
         self.bind(self.hFov, 'Set horizontal field of view')
         self.bind(self.hFov, 'Set horizontal field of view')
            
            
-        self.vFov = EntryScale.EntryScale(
+        self.vFov = Slider.Slider(
             fovFloaterFrame,
             fovFloaterFrame,
             text = 'Vertical FOV',
             text = 'Vertical FOV',
             min = 0.01, max = 170.0)
             min = 0.01, max = 170.0)
@@ -366,7 +377,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.pSpecularColor,
         self.bind(self.pSpecularColor,
                   'Set point light specular color')
                   'Set point light specular color')
 
 
-        self.pConstantAttenuation = EntryScale.EntryScale(
+        self.pConstantAttenuation = Slider.Slider(
             pointPage,
             pointPage,
             text = 'Constant Attenuation',
             text = 'Constant Attenuation',
             min = 0.0, max = 1.0, value = 1.0)
             min = 0.0, max = 1.0, value = 1.0)
@@ -375,7 +386,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.pConstantAttenuation,
         self.bind(self.pConstantAttenuation,
                   'Set point light constant attenuation')
                   'Set point light constant attenuation')
            
            
-        self.pLinearAttenuation = EntryScale.EntryScale(
+        self.pLinearAttenuation = Slider.Slider(
             pointPage,
             pointPage,
             text = 'Linear Attenuation',
             text = 'Linear Attenuation',
             min = 0.0, max = 1.0, value = 0.0)
             min = 0.0, max = 1.0, value = 0.0)
@@ -384,7 +395,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.pLinearAttenuation,
         self.bind(self.pLinearAttenuation,
                   'Set point light linear attenuation')
                   'Set point light linear attenuation')
            
            
-        self.pQuadraticAttenuation = EntryScale.EntryScale(
+        self.pQuadraticAttenuation = Slider.Slider(
             pointPage,
             pointPage,
             text = 'Quadratic Attenuation',
             text = 'Quadratic Attenuation',
             min = 0.0, max = 1.0, value = 0.0)
             min = 0.0, max = 1.0, value = 0.0)
@@ -401,7 +412,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.sSpecularColor,
         self.bind(self.sSpecularColor,
                   'Set spot light specular color')
                   'Set spot light specular color')
 
 
-        self.sConstantAttenuation = EntryScale.EntryScale(
+        self.sConstantAttenuation = Slider.Slider(
             spotPage,
             spotPage,
             text = 'Constant Attenuation',
             text = 'Constant Attenuation',
             min = 0.0, max = 1.0, value = 1.0)
             min = 0.0, max = 1.0, value = 1.0)
@@ -410,7 +421,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.sConstantAttenuation,
         self.bind(self.sConstantAttenuation,
                   'Set spot light constant attenuation')
                   'Set spot light constant attenuation')
            
            
-        self.sLinearAttenuation = EntryScale.EntryScale(
+        self.sLinearAttenuation = Slider.Slider(
             spotPage,
             spotPage,
             text = 'Linear Attenuation',
             text = 'Linear Attenuation',
             min = 0.0, max = 1.0, value = 0.0)
             min = 0.0, max = 1.0, value = 0.0)
@@ -419,7 +430,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.sLinearAttenuation,
         self.bind(self.sLinearAttenuation,
                   'Set spot light linear attenuation')
                   'Set spot light linear attenuation')
            
            
-        self.sQuadraticAttenuation = EntryScale.EntryScale(
+        self.sQuadraticAttenuation = Slider.Slider(
             spotPage,
             spotPage,
             text = 'Quadratic Attenuation',
             text = 'Quadratic Attenuation',
             min = 0.0, max = 1.0, value = 0.0)
             min = 0.0, max = 1.0, value = 0.0)
@@ -428,7 +439,7 @@ class DirectSessionPanel(AppShell):
         self.bind(self.sQuadraticAttenuation,
         self.bind(self.sQuadraticAttenuation,
                   'Set spot light quadratic attenuation')
                   'Set spot light quadratic attenuation')
            
            
-        self.sExponent = EntryScale.EntryScale(
+        self.sExponent = Slider.Slider(
             spotPage,
             spotPage,
             text = 'Exponent',
             text = 'Exponent',
             min = 0.0, max = 1.0, value = 0.0)
             min = 0.0, max = 1.0, value = 0.0)
@@ -493,7 +504,7 @@ class DirectSessionPanel(AppShell):
         self.gridSnapAngle = Dial.AngleDial(
         self.gridSnapAngle = Dial.AngleDial(
             gridPage,
             gridPage,
             text = 'Snap Angle',
             text = 'Snap Angle',
-            style = Dial.DIAL_MINI,
+            style = 'mini',
             value = direct.grid.getSnapAngle())
             value = direct.grid.getSnapAngle())
         self.gridSnapAngle['command'] = direct.grid.setSnapAngle
         self.gridSnapAngle['command'] = direct.grid.setSnapAngle
         self.gridSnapAngle.pack(fill = X, expand = 0)
         self.gridSnapAngle.pack(fill = X, expand = 0)
@@ -542,7 +553,7 @@ class DirectSessionPanel(AppShell):
             self.bind(self.jbNodePathMenu,
             self.bind(self.jbNodePathMenu,
                       'Select node path to manipulate using the joybox')
                       'Select node path to manipulate using the joybox')
 
 
-            self.jbXyzSF = EntryScale.EntryScale(
+            self.jbXyzSF = Slider.Slider(
                 joyboxFrame,
                 joyboxFrame,
                 text = 'XYZ Scale Factor',
                 text = 'XYZ Scale Factor',
                 value = 1.0,
                 value = 1.0,
@@ -553,7 +564,7 @@ class DirectSessionPanel(AppShell):
             self.jbXyzSF.pack(fill = X, expand = 0)
             self.jbXyzSF.pack(fill = X, expand = 0)
             self.bind(self.jbXyzSF, 'Set joybox XYZ speed multiplier')
             self.bind(self.jbXyzSF, 'Set joybox XYZ speed multiplier')
 
 
-            self.jbHprSF = EntryScale.EntryScale(
+            self.jbHprSF = Slider.Slider(
                 joyboxFrame,
                 joyboxFrame,
                 text = 'HPR Scale Factor',
                 text = 'HPR Scale Factor',
                 value = 1.0,
                 value = 1.0,
@@ -568,31 +579,13 @@ class DirectSessionPanel(AppShell):
         Label(tasksPage, text = 'TASKS',
         Label(tasksPage, text = 'TASKS',
               font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
               font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
         self.taskMgrPanel = TaskManagerWidget(tasksPage, taskMgr)
         self.taskMgrPanel = TaskManagerWidget(tasksPage, taskMgr)
+        self.taskMgrPanel.taskListBox['listbox_height'] = 10
 
 
         notebook.setnaturalsize()
         notebook.setnaturalsize()
 
 
         framePane.pack(expand = 1, fill = BOTH)
         framePane.pack(expand = 1, fill = BOTH)
         mainFrame.pack(fill = 'both', expand = 1)
         mainFrame.pack(fill = 'both', expand = 1)
 
 
-        # Create some buttons in the bottom tray
-        self.createButtons()
-
-    def createButtons(self):
-        # Grid: enable/disable, xyz/hpr snap, snap to plane
-        # Render mode: wireframe, lights, texture
-        self.buttonAdd('Toggle Widget Viz',
-                       helpMessage='Toggle Object Handles Visability',
-                       statusMessage='Toggle Object Handles Visability',
-                       command=direct.toggleWidgetVis)
-        self.buttonAdd(
-            'Toggle Widget Mode',
-            helpMessage='Toggle Widget Move/COA Mode',
-            statusMessage='Toggle Widget Move/COA Mode',
-            command=direct.manipulationControl.toggleObjectHandlesMode)
-        
-        # Make all buttons as wide as widest
-        self.alignbuttons()
-
     def toggleDirect(self):
     def toggleDirect(self):
         if self.directEnabled.get():
         if self.directEnabled.get():
             direct.enable()
             direct.enable()

+ 32 - 13
direct/src/tkpanels/MopathRecorder.py

@@ -13,6 +13,7 @@ import string
 import Pmw
 import Pmw
 import Dial
 import Dial
 import Floater
 import Floater
+import Slider
 import EntryScale
 import EntryScale
 import VectorWidgets
 import VectorWidgets
 import __builtin__
 import __builtin__
@@ -365,7 +366,7 @@ class MopathRecorder(AppShell, PandaObject):
             self.resamplePage, relief = SUNKEN, borderwidth = 2)
             self.resamplePage, relief = SUNKEN, borderwidth = 2)
         label = Label(resampleFrame, text = 'RESAMPLE CURVE',
         label = Label(resampleFrame, text = 'RESAMPLE CURVE',
                       font=('MSSansSerif', 12, 'bold')).pack()
                       font=('MSSansSerif', 12, 'bold')).pack()
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             resampleFrame, 'Resample', 'Num. Samples',
             resampleFrame, 'Resample', 'Num. Samples',
             'Number of samples in resampled curve',
             'Number of samples in resampled curve',
             resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
             resolution = 1, min = 2, max = 1000, command = self.setNumSamples)
@@ -389,7 +390,7 @@ class MopathRecorder(AppShell, PandaObject):
             self.resamplePage, relief = SUNKEN, borderwidth = 2)
             self.resamplePage, relief = SUNKEN, borderwidth = 2)
         Label(desampleFrame, text = 'DESAMPLE CURVE',
         Label(desampleFrame, text = 'DESAMPLE CURVE',
               font=('MSSansSerif', 12, 'bold')).pack()
               font=('MSSansSerif', 12, 'bold')).pack()
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             desampleFrame, 'Resample', 'Points Between Samples',
             desampleFrame, 'Resample', 'Points Between Samples',
             'Specify number of points to skip between samples',
             'Specify number of points to skip between samples',
             min = 1, max = 100, resolution = 1,
             min = 1, max = 100, resolution = 1,
@@ -405,28 +406,28 @@ class MopathRecorder(AppShell, PandaObject):
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
         label.pack(fill = X)
         label.pack(fill = X)
 
 
-        widget = self.createEntryScale(refineFrame,
+        widget = self.createSlider(refineFrame,
                                        'Refine Page', 'Refine From',
                                        'Refine Page', 'Refine From',
                                        'Begin time of refine pass',
                                        'Begin time of refine pass',
                                        resolution = 0.01,
                                        resolution = 0.01,
                                        command = self.setRecordStart)
                                        command = self.setRecordStart)
         widget['preCallback'] = self.setRefineMode
         widget['preCallback'] = self.setRefineMode
         widget['postCallback'] = lambda s = self: s.getPrePoints('Refine')
         widget['postCallback'] = lambda s = self: s.getPrePoints('Refine')
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             refineFrame, 'Refine Page',
             refineFrame, 'Refine Page',
             'Control Start',
             'Control Start',
             'Time when full control of node path is given during refine pass',
             'Time when full control of node path is given during refine pass',
             resolution = 0.01,
             resolution = 0.01,
             command = self.setControlStart)
             command = self.setControlStart)
         widget['preCallback'] = self.setRefineMode
         widget['preCallback'] = self.setRefineMode
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             refineFrame, 'Refine Page',
             refineFrame, 'Refine Page',
             'Control Stop',
             'Control Stop',
             'Time when node path begins transition back to original curve',
             'Time when node path begins transition back to original curve',
             resolution = 0.01,
             resolution = 0.01,
             command = self.setControlStop)
             command = self.setControlStop)
         widget['preCallback'] = self.setRefineMode
         widget['preCallback'] = self.setRefineMode
-        widget = self.createEntryScale(refineFrame, 'Refine Page', 'Refine To',
+        widget = self.createSlider(refineFrame, 'Refine Page', 'Refine To',
                                        'Stop time of refine pass',
                                        'Stop time of refine pass',
                                        resolution = 0.01,
                                        resolution = 0.01,
                                        command = self.setRefineStop)
                                        command = self.setRefineStop)
@@ -441,14 +442,14 @@ class MopathRecorder(AppShell, PandaObject):
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
         label.pack(fill = X)
         label.pack(fill = X)
 
 
-        widget = self.createEntryScale(extendFrame,
+        widget = self.createSlider(extendFrame,
                                        'Extend Page', 'Extend From',
                                        'Extend Page', 'Extend From',
                                        'Begin time of extend pass',
                                        'Begin time of extend pass',
                                        resolution = 0.01,
                                        resolution = 0.01,
                                        command = self.setRecordStart)
                                        command = self.setRecordStart)
         widget['preCallback'] = self.setExtendMode
         widget['preCallback'] = self.setExtendMode
         widget['postCallback'] = lambda s = self: s.getPrePoints('Extend')
         widget['postCallback'] = lambda s = self: s.getPrePoints('Extend')
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             extendFrame, 'Extend Page',
             extendFrame, 'Extend Page',
             'Control Start',
             'Control Start',
             'Time when full control of node path is given during extend pass',
             'Time when full control of node path is given during extend pass',
@@ -464,14 +465,14 @@ class MopathRecorder(AppShell, PandaObject):
                       font=('MSSansSerif', 12, 'bold'))
                       font=('MSSansSerif', 12, 'bold'))
         label.pack(fill = X)
         label.pack(fill = X)
 
 
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             cropFrame,
             cropFrame,
             'Crop Page', 'Crop From',
             'Crop Page', 'Crop From',
             'Delete all curve points before this time',
             'Delete all curve points before this time',
             resolution = 0.01,
             resolution = 0.01,
             command = self.setCropFrom)
             command = self.setCropFrom)
 
 
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             cropFrame,
             cropFrame,
             'Crop Page', 'Crop To',
             'Crop Page', 'Crop To',
             'Delete all curve points after this time',
             'Delete all curve points after this time',
@@ -523,21 +524,21 @@ class MopathRecorder(AppShell, PandaObject):
             side = LEFT, fill = X, expand = 1)
             side = LEFT, fill = X, expand = 1)
         frame.pack(fill = X, expand = 1)
         frame.pack(fill = X, expand = 1)
         # Sliders
         # Sliders
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             sfFrame, 'Style', 'Num Segs',
             sfFrame, 'Style', 'Num Segs',
             'Set number of segments used to approximate each parametric unit',
             'Set number of segments used to approximate each parametric unit',
             min = 1.0, max = 400, resolution = 1.0,
             min = 1.0, max = 400, resolution = 1.0,
             value = 40, 
             value = 40, 
             command = self.setNumSegs, side = TOP)
             command = self.setNumSegs, side = TOP)
         widget.component('hull')['relief'] = RIDGE
         widget.component('hull')['relief'] = RIDGE
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             sfFrame, 'Style', 'Num Ticks',
             sfFrame, 'Style', 'Num Ticks',
             'Set number of tick marks drawn for each unit of time',
             'Set number of tick marks drawn for each unit of time',
             min = 0.0, max = 10.0, resolution = 1.0,
             min = 0.0, max = 10.0, resolution = 1.0,
             value = 0.0,
             value = 0.0,
             command = self.setNumTicks, side = TOP)
             command = self.setNumTicks, side = TOP)
         widget.component('hull')['relief'] = RIDGE
         widget.component('hull')['relief'] = RIDGE
-        widget = self.createEntryScale(
+        widget = self.createSlider(
             sfFrame, 'Style', 'Tick Scale',
             sfFrame, 'Style', 'Tick Scale',
             'Set visible size of time tick marks',
             'Set visible size of time tick marks',
             min = 0.01, max = 100.0, resolution = 0.01,
             min = 0.01, max = 100.0, resolution = 0.01,
@@ -1760,6 +1761,24 @@ class MopathRecorder(AppShell, PandaObject):
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
 
 
+    def createSlider(self, parent, category, text, balloonHelp,
+                         command = None, min = 0.0, max = 1.0,
+                         resolution = None,
+                         side = TOP, fill = X, expand = 1, **kw):
+        kw['text'] = text
+        kw['min'] = min
+        kw['max'] = max
+        kw['resolution'] = resolution
+        #widget = apply(EntryScale.EntryScale, (parent,), kw)
+        import Slider
+        widget = apply(Slider.Slider, (parent,), kw)
+        # Do this after the widget so command isn't called on creation
+        widget['command'] = command
+        widget.pack(side = side, fill = fill, expand = expand)
+        self.bind(widget, balloonHelp)
+        self.widgetDict[category + '-' + text] = widget
+        return widget
+
     def createEntryScale(self, parent, category, text, balloonHelp,
     def createEntryScale(self, parent, category, text, balloonHelp,
                          command = None, min = 0.0, max = 1.0,
                          command = None, min = 0.0, max = 1.0,
                          resolution = None,
                          resolution = None,

+ 12 - 12
direct/src/tkpanels/ParticlePanel.py

@@ -9,7 +9,7 @@ import os
 import Pmw
 import Pmw
 import Dial
 import Dial
 import Floater
 import Floater
-import EntryScale
+import Slider
 import VectorWidgets
 import VectorWidgets
 import Placer
 import Placer
 import ForceGroup
 import ForceGroup
@@ -279,23 +279,23 @@ class ParticlePanel(AppShell):
         zSpinPage = self.factoryNotebook.add('ZSpinParticleFactory')
         zSpinPage = self.factoryNotebook.add('ZSpinParticleFactory')
         self.createAngleDial(zSpinPage, 'Z Spin Factory', 'Initial Angle',
         self.createAngleDial(zSpinPage, 'Z Spin Factory', 'Initial Angle',
                              'Starting angle in degrees',
                              'Starting angle in degrees',
-                             dial_fRollover = 1,
+                             fRollover = 1,
                              command = self.setFactoryZSpinInitialAngle)
                              command = self.setFactoryZSpinInitialAngle)
         self.createAngleDial(
         self.createAngleDial(
             zSpinPage, 'Z Spin Factory',
             zSpinPage, 'Z Spin Factory',
             'Initial Angle Spread',
             'Initial Angle Spread',
             'Spread of the initial angle',
             'Spread of the initial angle',
-            dial_fRollover = 1,
+            fRollover = 1,
             command = self.setFactoryZSpinInitialAngleSpread)
             command = self.setFactoryZSpinInitialAngleSpread)
         self.createAngleDial(zSpinPage, 'Z Spin Factory', 'Final Angle',
         self.createAngleDial(zSpinPage, 'Z Spin Factory', 'Final Angle',
                              'Final angle in degrees',
                              'Final angle in degrees',
-                             dial_fRollover = 1,
+                             fRollover = 1,
                              command = self.setFactoryZSpinFinalAngle)
                              command = self.setFactoryZSpinFinalAngle)
         self.createAngleDial(
         self.createAngleDial(
             zSpinPage, 'Z Spin Factory',
             zSpinPage, 'Z Spin Factory',
             'Final Angle Spread',
             'Final Angle Spread',
             'Spread of the final angle',
             'Spread of the final angle',
-            dial_fRollover = 1,
+            fRollover = 1,
             command = self.setFactoryZSpinFinalAngleSpread)
             command = self.setFactoryZSpinFinalAngleSpread)
         # Oriented page #
         # Oriented page #
         orientedPage = self.factoryNotebook.add('OrientedParticleFactory')
         orientedPage = self.factoryNotebook.add('OrientedParticleFactory')
@@ -472,7 +472,7 @@ class ParticlePanel(AppShell):
                               ('NO_ALPHA','ALPHA_OUT','ALPHA_IN','ALPHA_USER'),
                               ('NO_ALPHA','ALPHA_OUT','ALPHA_IN','ALPHA_USER'),
                               self.setRendererAlphaMode)
                               self.setRendererAlphaMode)
         
         
-        self.createEntryScale(
+        self.createSlider(
             rendererPage, 'Renderer', 'User Alpha',
             rendererPage, 'Renderer', 'User Alpha',
             'alpha value for ALPHA_USER alpha mode',
             'alpha value for ALPHA_USER alpha mode',
             command = self.setRendererUserAlpha)
             command = self.setRendererUserAlpha)
@@ -739,7 +739,7 @@ class ParticlePanel(AppShell):
                       numDigits = 3, **kw):
                       numDigits = 3, **kw):
         kw['text'] = text
         kw['text'] = text
         kw['min'] = min
         kw['min'] = min
-        kw['floater_resolution'] = resolution
+        kw['resolution'] = resolution
         kw['numDigits'] = numDigits
         kw['numDigits'] = numDigits
         widget = apply(Floater.Floater, (parent,), kw)
         widget = apply(Floater.Floater, (parent,), kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
@@ -752,7 +752,7 @@ class ParticlePanel(AppShell):
     def createAngleDial(self, parent, category, text, balloonHelp,
     def createAngleDial(self, parent, category, text, balloonHelp,
                         command = None, **kw):
                         command = None, **kw):
         kw['text'] = text
         kw['text'] = text
-        kw['style'] = Dial.DIAL_MINI
+        kw['style'] = 'mini'
         widget = apply(Dial.AngleDial,(parent,), kw)
         widget = apply(Dial.AngleDial,(parent,), kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
@@ -761,14 +761,14 @@ class ParticlePanel(AppShell):
         self.widgetDict[category + '-' + text] = widget
         self.widgetDict[category + '-' + text] = widget
         return widget
         return widget
 
 
-    def createEntryScale(self, parent, category, text, balloonHelp,
-                         command = None, min = 0.0, max = 1.0,
-                         resolution = 0.001, **kw):
+    def createSlider(self, parent, category, text, balloonHelp,
+                     command = None, min = 0.0, max = 1.0,
+                     resolution = 0.001, **kw):
         kw['text'] = text
         kw['text'] = text
         kw['min'] = min
         kw['min'] = min
         kw['max'] = max
         kw['max'] = max
         kw['resolution'] = resolution
         kw['resolution'] = resolution
-        widget = apply(EntryScale.EntryScale, (parent,), kw)
+        widget = apply(Slider.Slider, (parent,), kw)
         # Do this after the widget so command isn't called on creation
         # Do this after the widget so command isn't called on creation
         widget['command'] = command
         widget['command'] = command
         widget.pack(fill = X)
         widget.pack(fill = X)

+ 3 - 3
direct/src/tkpanels/Placer.py

@@ -233,7 +233,7 @@ class Placer(AppShell):
         # Create the dials
         # Create the dials
         self.hprH = self.createcomponent('hprH', (), None,
         self.hprH = self.createcomponent('hprH', (), None,
                                          Dial.AngleDial, (hprInterior,),
                                          Dial.AngleDial, (hprInterior,),
-                                         style = Dial.DIAL_MINI,
+                                         style = 'mini',
                                          text = 'H', value = 0.0,
                                          text = 'H', value = 0.0,
                                          relief = FLAT,
                                          relief = FLAT,
                                          label_foreground = 'blue')
                                          label_foreground = 'blue')
@@ -246,7 +246,7 @@ class Placer(AppShell):
         
         
         self.hprP = self.createcomponent('hprP', (), None,
         self.hprP = self.createcomponent('hprP', (), None,
                                          Dial.AngleDial, (hprInterior,),
                                          Dial.AngleDial, (hprInterior,),
-                                         style = Dial.DIAL_MINI,
+                                         style = 'mini',
                                          text = 'P', value = 0.0,
                                          text = 'P', value = 0.0,
                                          relief = FLAT,
                                          relief = FLAT,
                                          label_foreground = 'red')
                                          label_foreground = 'red')
@@ -259,7 +259,7 @@ class Placer(AppShell):
         
         
         self.hprR = self.createcomponent('hprR', (), None,
         self.hprR = self.createcomponent('hprR', (), None,
                                          Dial.AngleDial, (hprInterior,),
                                          Dial.AngleDial, (hprInterior,),
-                                         style = Dial.DIAL_MINI,
+                                         style = 'mini',
                                          text = 'R', value = 0.0,
                                          text = 'R', value = 0.0,
                                          relief = FLAT,
                                          relief = FLAT,
                                          label_foreground = '#00A000')
                                          label_foreground = '#00A000')

+ 10 - 0
direct/src/tkwidgets/AppShell.py

@@ -10,6 +10,7 @@ from tkFileDialog import *
 import Pmw
 import Pmw
 import Dial
 import Dial
 import Floater
 import Floater
+import Slider
 import EntryScale
 import EntryScale
 import VectorWidgets
 import VectorWidgets
 import sys, string
 import sys, string
@@ -411,6 +412,15 @@ class AppShell(Pmw.MegaWidget, PandaObject):
                                    help, command, side, fill, expand, kw)
                                    help, command, side, fill, expand, kw)
         return widget
         return widget
 
 
+    def newCreateSider(self, parent, category, text,
+                       help = '', command = None,
+                       side = LEFT, fill = X, expand = 0, **kw):
+        # Create the widget
+        widget = self.createWidget(parent, category, text,
+                                   Slider.Slider,
+                                   help, command, side, fill, expand, kw)
+        return widget
+
     def newCreateEntryScale(self, parent, category, text,
     def newCreateEntryScale(self, parent, category, text,
                             help = '', command = None,
                             help = '', command = None,
                             side = LEFT, fill = X, expand = 0, **kw):
                             side = LEFT, fill = X, expand = 0, **kw):

+ 4 - 8
direct/src/tkwidgets/Dial.py

@@ -16,15 +16,11 @@ ONEPOINTFIVE_PI = 1.5 * math.pi
 POINTFIVE_PI = 0.5 * math.pi
 POINTFIVE_PI = 0.5 * math.pi
 INNER_SF = 0.2
 INNER_SF = 0.2
 
 
-DIAL_FULL = 'full'
-DIAL_MINI = 'mini'
-
 DIAL_FULL_SIZE = 45
 DIAL_FULL_SIZE = 45
 DIAL_MINI_SIZE = 30
 DIAL_MINI_SIZE = 30
 
 
 globalClock = ClockObject.getGlobalClock()
 globalClock = ClockObject.getGlobalClock()
 
 
-
 class Dial(Valuator):
 class Dial(Valuator):
     """
     """
     Valuator widget which includes an angle dial and an entry for setting
     Valuator widget which includes an angle dial and an entry for setting
@@ -33,7 +29,7 @@ class Dial(Valuator):
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
         INITOPT = Pmw.INITOPT
         INITOPT = Pmw.INITOPT
         optiondefs = (
         optiondefs = (
-            ('style',             DIAL_FULL,      INITOPT),
+            ('style',             VALUATOR_FULL,  INITOPT),
             ('base',              0.0,            self.setBase),
             ('base',              0.0,            self.setBase),
             ('delta',             1.0,            self.setDelta),
             ('delta',             1.0,            self.setDelta),
             ('fSnap',             0,              self.setSnap),
             ('fSnap',             0,              self.setSnap),
@@ -56,7 +52,7 @@ class Dial(Valuator):
         self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
         self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
 
 
     def packValuator(self):
     def packValuator(self):
-        if self['style'] == DIAL_FULL:
+        if self['style'] == VALUATOR_FULL:
             self._valuator.grid(rowspan = 2, columnspan = 2,
             self._valuator.grid(rowspan = 2, columnspan = 2,
                                 padx = 2, pady = 2)
                                 padx = 2, pady = 2)
             if self._label:
             if self._label:
@@ -155,7 +151,7 @@ class DialWidget(Pmw.MegaWidget):
         INITOPT = Pmw.INITOPT
         INITOPT = Pmw.INITOPT
         optiondefs = (
         optiondefs = (
             # Appearance
             # Appearance
-            ('style',           DIAL_FULL,      INITOPT),
+            ('style',           VALUATOR_FULL,      INITOPT),
             ('size',            None,           INITOPT),
             ('size',            None,           INITOPT),
             ('relief',          SUNKEN,         self.setRelief),
             ('relief',          SUNKEN,         self.setRelief),
             ('borderwidth',     2,              self.setBorderwidth),
             ('borderwidth',     2,              self.setBorderwidth),
@@ -200,7 +196,7 @@ class DialWidget(Pmw.MegaWidget):
 
 
         # Base dial size on style, if size not specified, 
         # Base dial size on style, if size not specified, 
         if not self['size']:
         if not self['size']:
-            if self['style'] == DIAL_FULL:
+            if self['style'] == VALUATOR_FULL:
                 size = DIAL_FULL_SIZE
                 size = DIAL_FULL_SIZE
             else:
             else:
                 size = DIAL_MINI_SIZE
                 size = DIAL_MINI_SIZE

+ 4 - 1
direct/src/tkwidgets/Floater.py

@@ -17,7 +17,10 @@ FLOATER_HEIGHT = 18
 
 
 class Floater(Valuator):
 class Floater(Valuator):
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
-        optiondefs = ()
+        INITOPT = Pmw.INITOPT
+        optiondefs = (
+            ('style',  VALUATOR_MINI,   INITOPT),
+            )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
         # Initialize the superclass
         # Initialize the superclass
         Valuator.__init__(self, parent)
         Valuator.__init__(self, parent)

+ 235 - 495
direct/src/tkwidgets/Slider.py

@@ -11,18 +11,8 @@ import string
 import operator
 import operator
 from PandaModules import ClockObject
 from PandaModules import ClockObject
 
 
-SLIDER_FULL = 'full'
-SLIDER_MINI = 'mini'
-
-SLIDER_FULL_WIDTH = 50
-SLIDER_FULL_HEIGHT = 25
-
-SLIDER_MINI_WIDTH = 16
-SLIDER_MINI_HEIGHT = 16
-
 globalClock = ClockObject.getGlobalClock()
 globalClock = ClockObject.getGlobalClock()
 
 
-
 class Slider(Valuator):
 class Slider(Valuator):
     """
     """
     Valuator widget which includes an min/max slider and an entry for setting
     Valuator widget which includes an min/max slider and an entry for setting
@@ -31,10 +21,17 @@ class Slider(Valuator):
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
         INITOPT = Pmw.INITOPT
         INITOPT = Pmw.INITOPT
         optiondefs = (
         optiondefs = (
-            ('style',             SLIDER_FULL,    INITOPT),
+            ('min',        0.0,           self.setMin),
+            ('max',        100.0,         self.setMax),
+            ('style',      VALUATOR_MINI,   INITOPT),
             )
             )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
         Valuator.__init__(self, parent)
         Valuator.__init__(self, parent)
+        # Can not enter none for min or max
+        self.propertyDict['min']['fNone'] = 0
+        self.propertyDict['min']['help'] = 'Minimum allowable value.'
+        self.propertyDict['max']['fNone'] = 0
+        self.propertyDict['max']['help'] = 'Maximum allowable value.'
         self.initialiseoptions(Slider)
         self.initialiseoptions(Slider)
 
 
     def createValuator(self):
     def createValuator(self):
@@ -49,13 +46,24 @@ class Slider(Valuator):
             value = self['value'])
             value = self['value'])
         self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
         self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
 
 
+        # Add popup bindings to slider widget
+        try:
+            self._valuator._arrowBtn.bind(
+                '<ButtonPress-3>', self._popupValuatorMenu)
+        except AttributeError:
+            pass
+        self._valuator._minLabel.bind(
+            '<ButtonPress-3>', self._popupValuatorMenu)
+        self._valuator._maxLabel.bind(
+            '<ButtonPress-3>', self._popupValuatorMenu)
+
     def packValuator(self):
     def packValuator(self):
-        if self['style'] == SLIDER_FULL:
+        if self['style'] == VALUATOR_FULL:
             if self._label:
             if self._label:
                 self._label.grid(row = 0, col = 0, sticky = EW)
                 self._label.grid(row = 0, col = 0, sticky = EW)
             self._entry.grid(row = 0, col = 1, sticky = EW)
             self._entry.grid(row = 0, col = 1, sticky = EW)
             self._valuator.grid(row = 1, columnspan = 2,
             self._valuator.grid(row = 1, columnspan = 2,
-                                padx = 2, pady = 2)
+                                padx = 2, pady = 2, sticky = 'ew')
             self.interior().columnconfigure(0, weight = 1)
             self.interior().columnconfigure(0, weight = 1)
         else:
         else:
             if self._label:
             if self._label:
@@ -64,351 +72,35 @@ class Slider(Valuator):
             self._valuator.grid(row=0,col=2, padx = 2, pady = 2)
             self._valuator.grid(row=0,col=2, padx = 2, pady = 2)
             self.interior().columnconfigure(0, weight = 1)
             self.interior().columnconfigure(0, weight = 1)
 
 
+    def setMin(self):
+        if self['min'] is not None:
+            self._valuator['min'] = self['min']
 
 
-class SliderWidget(Pmw.MegaWidget):
-    def __init__(self, parent = None, **kw):
-        #define the megawidget options
-        INITOPT = Pmw.INITOPT
-        optiondefs = (
-            # Appearance
-            ('style',           SLIDER_MINI,    INITOPT),
-            ('width',           SLIDER_MINI_WIDTH,   INITOPT),
-            ('height',          SLIDER_MINI_HEIGHT,  INITOPT),
-            ('relief',          SUNKEN,         self.setRelief),
-            ('borderwidth',     2,              self.setBorderwidth),
-            ('background',      'white',        self.setBackground),
-            # Behavior
-            # Initial value of slider, use self.set to change value
-            ('value',           0.0,            INITOPT),
-            ('numDigits',       2,              self.setNumDigits),
-            # Command to execute on slider updates
-            ('command',         None,           None),
-            # Extra data to be passed to command function
-            ('commandData',     [],             None),
-            # Callback's to execute during mouse interaction
-            ('preCallback',     None,           None),
-            ('postCallback',    None,           None),
-            # Extra data to be passed to callback function, needs to be a list
-            ('callbackData',    [],             None),
-            )
-        self.defineoptions(kw, optiondefs)
-        
-        # Initialize the superclass
-        Pmw.MegaWidget.__init__(self, parent)
-
-        # Set up some local and instance variables        
-        # Create the components
-        interior = self.interior()
-
-        # Current value
-        self.value = self['value']
-
-        # Base slider size on style, if size not specified, 
-        if not self['width']:
-            if self['style'] == SLIDER_FULL_SIZE:
-                width = SLIDER_FULL_WIDTH
-            else:
-                width = SLIDER_MINI_WIDTH
-        else:
-            width = self['width']
-
-        if not self['height']:
-            if self['style'] == SLIDER_FULL_SIZE:
-                height = SLIDER_FULL_HEIGHT
-            else:
-                height = SLIDER_MINI_HEIGHT
-        else:
-            height = self['height']
-
-        halfWidth = width/2.0
-        halfHeight = height/2.0
-        left = -(halfWidth - 2)
-        right = halfWidth - 2
-        top = -(halfHeight - 2)
-        bottom = halfHeight - 2
-
-        # The canvas 
-        self._canvas = self.createcomponent('canvas', (), None,
-                                            Canvas, (interior,),
-                                            width = width,
-                                            height = height,
-                                            background = self['background'],
-                                            highlightthickness = 0,
-                                            scrollregion = (-halfWidth,
-                                                            -halfHeight,
-                                                            halfWidth,
-                                                            halfHeight))
-        self._canvas.pack(expand = 1, fill = BOTH)
-
-        self._canvas.create_polygon(left,top,
-                                    0, bottom,
-                                    right, top,
-                                    fill = '#A0A0A0',
-                                    tags = ('slider',))
-
-        # The indicator
-        self._canvas.create_line(left, bottom,
-                                 right, bottom,
-                                 width = 2)
-
-        # Add event bindings
-        self._canvas.bind('<ButtonPress-1>', self.mouseDown)
-        self._canvas.bind('<B1-Motion>', self.updateSliderSF)
-        self._canvas.bind('<ButtonRelease-1>', self.mouseUp)
-        self._canvas.bind('<Enter>', self.highlightWidget)
-        self._canvas.bind('<Leave>', self.restoreWidget)
-
-        # Make sure input variables processed 
-        self.initialiseoptions(SliderWidget)
-
-    def set(self, value, fCommand = 1):
-        """
-        self.set(value, fCommand = 1)
-        Set slider to new value, execute command if fCommand == 1
-        """
-        # Send command if any
-        if fCommand and (self['command'] != None):
-            apply(self['command'], [value] + self['commandData'])
-        # Record value
-        self.value = value
-
-    def updateIndicator(self, value):
-        # Nothing visible to update on this type of widget
-        pass
-    
-    def get(self):
-        """
-        self.get()
-        Get current slider value
-        """
-        return self.value
-
-    ## Canvas callback functions
-    # Slider velocity controller
-    def mouseDown(self,event):
-        """ Begin mouse interaction """
-        # Exectute user redefinable callback function (if any)
-        if self['preCallback']:
-            apply(self['preCallback'], self['callbackData'])
-        self.velocitySF = 0.0
-        self.updateTask = taskMgr.add(self.updateSliderTask,
-                                        'updateSlider')
-        self.updateTask.lastTime = globalClock.getFrameTime()
-
-    def updateSliderTask(self, state):
-        """
-        Update sliderWidget value based on current scaleFactor
-        Adjust for time to compensate for fluctuating frame rates
-        """
-        currT = globalClock.getFrameTime()
-        dt = currT - state.lastTime
-        self.set(self.value + self.velocitySF * dt)
-        state.lastTime = currT
-        return Task.cont
-
-    def updateSliderSF(self, event):
-        """
-        Update velocity scale factor based of mouse distance from origin
-        """
-        x = self._canvas.canvasx(event.x)
-        y = self._canvas.canvasy(event.y)
-        offset = max(0, abs(x) - Valuator.deadband)
-        if offset == 0:
-            return 0
-        sf = math.pow(Valuator.sfBase,
-                      self.minExp + offset/Valuator.sfDist)
-        if x > 0:
-            self.velocitySF = sf
-        else:
-            self.velocitySF = -sf
-
-    def mouseUp(self, event):
-        taskMgr.remove(self.updateTask)
-        self.velocitySF = 0.0
-        # Execute user redefinable callback function (if any)
-        if self['postCallback']:
-            apply(self['postCallback'], self['callbackData'])
-
-    def setNumDigits(self):
-        """
-        Adjust minimum exponent to use in velocity task based
-        upon the number of digits to be displayed in the result
-        """
-        self.minExp = math.floor(-self['numDigits']/
-                                 math.log10(Valuator.sfBase))        
-
-    # Methods to modify slider characteristics    
-    def setRelief(self):
-        self.interior()['relief'] = self['relief']
-
-    def setBorderwidth(self):
-        self.interior()['borderwidth'] = self['borderwidth']
-
-    def setBackground(self):
-        self._canvas['background'] = self['background']
-
-    def highlightWidget(self, event):
-        self._canvas.itemconfigure('slider', fill = 'black')
-
-    def restoreWidget(self, event):
-        self._canvas.itemconfigure('slider', fill = '#A0A0A0')
-  
-if __name__ == '__main__':
-    tl = Toplevel()
-    d = Slider(tl)
-    d2 = Slider(tl, slider_numSegments = 12, max = 360,
-              slider_fRollover = 0, value = 180)
-    d3 = Slider(tl, slider_numSegments = 12, max = 90, min = -90,
-              slider_fRollover = 0)
-    d4 = Slider(tl, slider_numSegments = 16, max = 256,
-              slider_fRollover = 0)
-    d.pack(expand = 1, fill = X)
-    d2.pack(expand = 1, fill = X)
-    d3.pack(expand = 1, fill = X)
-    d4.pack(expand = 1, fill = X)
-
-
-
-class PopupSliderWidget(Pmw.MegaToplevel):
-    def __init__(self, parent = None, **kw):
-        optiondefs = (
-            ('width',                    150,            None),
-            ('height',                   25,             None),
-            ('xoffset',                  0,              None), # pixels
-            ('yoffset',                  1,              None), # pixels
-            )
-        self.defineoptions(kw, optiondefs)
-        Pmw.MegaToplevel.__init__(self, parent)
-        interior = self.interior()
-        self.withdraw()
-        self.overrideredirect(1)
-        interior['relief'] = RAISED
-        interior['borderwidth'] = 2
-        left = -self['width']/2.0
-        right = self['width']/2.0
-        top = -10
-        bottom = top + self['height']
-        self._canvas = self.createcomponent('canvas', (), None,
-                                            Canvas, (interior,),
-                                            relief = FLAT,
-                                            width = self['width'],
-                                            height = self['height'],
-                                            highlightthickness = 0,
-                                            scrollregion = (left, top,
-                                                            right, bottom)
-                                            )
-        self._canvas.pack(expand = 1, fill = BOTH)
-        self.marker = self._canvas.create_polygon(-6.9 + 1,12,
-                                    6.9+1,12,
-                                    1, 0,
-                                    fill = 'black',
-                                    tags = ('slider',))
-        self._canvas.create_polygon(-5.75,10,
-                                    5.75,10,
-                                    0, 0,
-                                    fill = 'grey85',
-                                    outline = 'black',
-                                    tags = ('slider',))
-        # The indicator
-        self.lineLeft = lineLeft = left + 10
-        self.lineRight = lineRight = right -10
-        self._canvas.create_line(lineLeft, 1,
-                                 lineRight, 1,
-                                 width = 2)
-
-        self.b = Button(interior, text = 'hello')
-        self.b['command'] = self.withdraw
-        self.b.pack()
-        self.initialiseoptions(PopupSliderWidget)
-        
-    def showPopup(self, widget):
-        x = widget.winfo_rootx() + widget.winfo_width() - self['width']
-        y = widget.winfo_rooty() + widget.winfo_height()
-        Pmw.setgeometryanddeiconify(self, '%dx%d+%d+%d' %
-                                    (self['width'], self['height'],x,y))
-
-"""
-
-pw = PopupSliderWidget()
-tl = Toplevel()
-b = Button(tl, text = 'V')
-b.pack()
-
-fCrossedLine = 0
-def move(event):
-    global fCrossedLine
-    if fCrossedLine:
-        newX = pw._canvas.canvasx(event.x_root) - pw.winfo_rootx()
-        if newX < pw.lineLeft:
-            newX = pw.lineLeft
-        elif newX > pw.lineRight:
-            newX = pw.lineRight
-        print (newX - pw.lineLeft)/(pw.lineRight - pw.lineLeft)
-        startX = getX()
-        dx = newX - startX
-        pw._canvas.move('slider', dx, 0)
-    else:
-        if event.y_root >= pw.winfo_rooty() + 10:
-            fCrossedLine = 1
-
-def getX():
-    c = pw._canvas.coords(pw.marker)
-    return c[4]
-
-def press(event):
-    global fCrossedLine
-    print 'press'
-    fCrossedLine = 0
-    pw.showPopup(b)
-    b.bind('<Motion>', move)
-
-def unpostCanvas(event):
-    print 'unpostCanvas', event.x_root, pw._canvas.winfo_rootx()
-    if event.x_root < pw._canvas.winfo_rootx():
-        print 'blah'
-    Pmw.popgrab(pw._canvas)
-    pw._canvas.withdraw()
-
-def popupPress(event):
-    global fCrossedLine
-    print 'popupPress'
-    fCrossedLine = 1
-    pw._canvas.bind('<Motion>', move)
-
-def release(event):
-    if fCrossedLine:
-        pw.withdraw()
-        b.unbind('<Motion>')
-        pw._canvas.unbind('<Motion>')
-    else:
-        Pmw.pushgrab(pw._canvas, 1, unpostCanvas)
-        pw._canvas.focus_set()
-
-b.bind('<ButtonPress-1>', press)
-b.bind('<ButtonRelease-1>', release)
-pw._canvas.bind('<ButtonPress-1>', popupPress)
-pw._canvas.bind('<ButtonRelease-1>', release)
-
-
-"""
+    def setMax(self):
+        if self['max'] is not None:
+            self._valuator['max'] = self['max']
 
 
 
 
 # Based on Pmw ComboBox code.
 # Based on Pmw ComboBox code.
-class PopupSlider(Pmw.MegaWidget):
+class SliderWidget(Pmw.MegaWidget):
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
 
 
 	# Define the megawidget options.
 	# Define the megawidget options.
 	INITOPT = Pmw.INITOPT
 	INITOPT = Pmw.INITOPT
 	optiondefs = (
 	optiondefs = (
-	    ('dropdown',           1,          INITOPT),
-	    ('buttonaspect',       1.0,        INITOPT),
-	    ('fliparrow',          0,          INITOPT),
-	    ('labelmargin',        0,          INITOPT),
-	    ('labelpos',           None,       INITOPT),
+            # Appearance
+            ('relief',          RAISED,             self.setRelief),
+            ('borderwidth',     2,                  self.setBorderwidth),
+            ('background',      'SystemButtonFace', self.setBackground),
+	    ('fliparrow',       0,                  INITOPT),
             # Behavior
             # Behavior
+	    ('style',           VALUATOR_MINI,        INITOPT),
+            # Bounds
+            ('min',             0.0,            self.setMin),
+            ('max',             100.0,          self.setMax),
             # Initial value of slider, use self.set to change value
             # Initial value of slider, use self.set to change value
             ('value',           0.0,            INITOPT),
             ('value',           0.0,            INITOPT),
-            ('numDigits',       2,              self._setNumDigits),
+            ('numDigits',       2,              self.setNumDigits),
             # Command to execute on slider updates
             # Command to execute on slider updates
             ('command',         None,           None),
             ('command',         None,           None),
             # Extra data to be passed to command function
             # Extra data to be passed to command function
@@ -429,47 +121,95 @@ class PopupSlider(Pmw.MegaWidget):
 
 
         # Current value
         # Current value
         self.value = self['value']
         self.value = self['value']
+        self.formatString = '%2f'
+        self.increment = 0.01
 
 
         # Interaction flags
         # Interaction flags
         self._fUpdate = 0
         self._fUpdate = 0
         self._fUnpost = 0
         self._fUnpost = 0
-        self._firstPress = 1
         self._fPressInsde = 0
         self._fPressInsde = 0
-
-	self._entryfield = self.createcomponent('entryfield',
-		(('entry', 'entryfield_entry'),), None,
-		Pmw.EntryField, (interior,))
-	self._entryfield.grid(column=2, row=2, sticky='nsew')
-	interior.grid_columnconfigure(2, weight = 1)
-	self._entryWidget = self._entryfield.component('entry')
+        self._isPosted = 0
+        if self['style'] == VALUATOR_MINI:
+            self._firstPress = 1
+        else:
+            self._firstPress = 0
 
 
         # Slider dimensions
         # Slider dimensions
         width = 100
         width = 100
-        xPad = 10
+        self.xPad = xPad = 10
         canvasWidth = width + 2 * xPad
         canvasWidth = width + 2 * xPad
         height = 20
         height = 20
         self.left = left = -(width/2.0)
         self.left = left = -(width/2.0)
         self.right = right = (width/2.0)
         self.right = right = (width/2.0)
-        top = -5
-        bottom = top + height
+        self.top = top = -5
+        self.bottom = bottom = top + height
+
+        def _createSlider(parent):
+            # Create the canvas inside the dropdown window.
+            # Min label
+            self._minLabel = Label(parent, text = self['min'], width = 8,
+                                   anchor = E)
+            self._minLabel.pack(side = LEFT)
+            # Slider
+            self._canvas = self.createcomponent(
+                'canvas', (), None,
+                Canvas, (parent,),
+                width = canvasWidth,
+                height = height,
+                bd = 2,
+                highlightthickness = 0,
+                scrollregion = (left - xPad, top, right + xPad, bottom))
+            self._canvas.pack(side = LEFT, expand=1, fill=X)
+            if self['style'] == VALUATOR_FULL:
+                self._canvas.configure(relief = SUNKEN, bd = 2)
+            # Max label
+            self._maxLabel = Label(parent, text = self['max'], width = 8,
+                                   anchor = W)
+            self._maxLabel.pack(side = LEFT)
+
+            # Interaction marker
+            xShift = 1
+            # Shadow arrow
+            self._marker = self._canvas.create_polygon(-7 + xShift, 12,
+                                                       7 + xShift, 12,
+                                                       xShift, 0,
+                                                       fill = 'black',
+                                                       tags = ('slider',))
+            # Arrow
+            self._canvas.create_polygon(-6.0, 10,
+                                        6.0, 10,
+                                        0, 0,
+                                        fill = 'grey85',
+                                        outline = 'black',
+                                        tags = ('slider',))
+            # The indicator
+            self._canvas.create_line(left, 0,
+                                     right, 0,
+                                     width = 2,
+                                     tags = ('line',))
+            
+            self._canvas.bind('<Left>', self._decrementValue)
+            self._canvas.bind('<Right>', self._incrementValue)
+            self._canvas.bind('<Shift-Left>', self._bigDecrementValue)
+            self._canvas.bind('<Shift-Right>', self._bigIncrementValue)
+            self._canvas.bind('<Home>', self._goToMin)
+            self._canvas.bind('<End>', self._goToMax)
+            
 
 
         # Create slider
         # Create slider
-	if self['dropdown']:
+	if self['style'] == VALUATOR_MINI:
 	    self._isPosted = 0
 	    self._isPosted = 0
-            interior.grid_rowconfigure(2, weight = 1)
 
 
 	    # Create the arrow button.
 	    # Create the arrow button.
 	    self._arrowBtn = self.createcomponent('arrowbutton',
 	    self._arrowBtn = self.createcomponent('arrowbutton',
 		    (), None,
 		    (), None,
-		    Canvas, (interior,), borderwidth = 2,
-		    relief = 'raised',
-		    width = 16, height = 16)
-	    self._arrowBtn.grid(column=3, row=2)
+		    Canvas, (interior,), borderwidth = 0,
+		    relief = FLAT, width = 14, height = 14)
+	    self._arrowBtn.pack(expand = 1, fill = BOTH)
+            self._arrowBtn.create_polygon(2.5, 4.5, 12.5, 4.5, 7.5, 12.5,
+                                          tags = 'arrow')
 	    self._arrowRelief = self._arrowBtn.cget('relief')
 	    self._arrowRelief = self._arrowBtn.cget('relief')
 
 
-	    # Create the label.
-	    self.createlabel(interior, childCols=2)
-
 	    # Create the dropdown window.
 	    # Create the dropdown window.
 	    self._popup = self.createcomponent(
 	    self._popup = self.createcomponent(
                 'popup',
                 'popup',
@@ -479,87 +219,41 @@ class PopupSlider(Pmw.MegaWidget):
 	    self._popup.withdraw()
 	    self._popup.withdraw()
 	    self._popup.overrideredirect(1)
 	    self._popup.overrideredirect(1)
 
 
-	    # Create the canvas inside the dropdown window.
-            # Min label
-            self._minLabel = Label(self._popup, text = 'MINAAAAAA')
-            self._minLabel.pack(side = LEFT)
-            # Slider
-            self._canvas = self.createcomponent(
-                'canvas', (), None,
-                Canvas, (self._popup,),
-                width = canvasWidth,
-                height = height,
-                bd = 3,
-                highlightthickness = 0,
-                scrollregion = (left - xPad, top, right + xPad, bottom))
-	    self._canvas.pack(side = LEFT, expand=1, fill='both')
-            # Max label
-            self._maxLabel = Label(self._popup, text = 'MAX')
-            self._maxLabel.pack(side = LEFT)
-            
+            _createSlider(self._popup)
+
 	    # Bind events to the arrow button.
 	    # Bind events to the arrow button.
 	    self._arrowBtn.bind('<1>', self._postCanvas)
 	    self._arrowBtn.bind('<1>', self._postCanvas)
-	    self._arrowBtn.bind('<Configure>', self._drawArrow)
-
-	    # Bind events to the dropdown window.
-	    self._popup.bind('<Escape>', self._unpostCanvas)
-	    self._popup.bind('<ButtonRelease-1>', self._dropdownBtnRelease)
-	    self._popup.bind('<ButtonPress-1>', self._dropdownBtnPress)
-            self._popup.bind('<Motion>', self._dropdownMove)
-
-	    # Bind events to the Tk listbox.
-	    #self._canvas.bind('<Enter>', self._unpostOnNextRelease)
-
-	    # Bind events to the Tk entry widget.
-	    self._entryWidget.bind('<Configure>', self._resizeArrow)
-
-            # Need to unpost the popup if the entryfield is unmapped (eg: 
+            self._arrowBtn.bind('<Enter>', self.highlightWidget)
+            self._arrowBtn.bind('<Leave>', self.restoreWidget)
+            # Need to unpost the popup if the arrow Button is unmapped (eg: 
             # its toplevel window is withdrawn) while the popup canvas is
             # its toplevel window is withdrawn) while the popup canvas is
             # displayed.
             # displayed.
-            self._entryWidget.bind('<Unmap>', self._unpostCanvas)
+            self._arrowBtn.bind('<Unmap>', self._unpostCanvas)
+            
+	    # Bind events to the dropdown window.
+	    self._popup.bind('<Escape>', self._unpostCanvas)
+	    self._popup.bind('<ButtonRelease-1>', self._sliderBtnRelease)
+	    self._popup.bind('<ButtonPress-1>', self._sliderBtnPress)
+            self._popup.bind('<Motion>', self._sliderMove)
 	else:
 	else:
-	    # Create the slider below the entry field.
-            self._canvas = self.createcomponent(
-                'canvas', (), None,
-                Canvas, (interior,),
-                width = canvasWidth,
-                height = height,
-                highlightthickness = 0,
-                scrollregion = (left - xPad, top, right + xPad, bottom))
-	    self._canvas.grid(column=2, row=3, sticky='nsew')
-
-	    # The scrolled canvas should expand vertically.
-	    interior.grid_rowconfigure(3, weight = 1)
-
-	    # Create the label.
-	    self.createlabel(interior, childRows=2)
-
-        # Interaction marker
-        xShift = 1
-        # Shadow arrow
-        self._marker = self._canvas.create_polygon(-7 + xShift, 12,
-                                                   7 + xShift, 12,
-                                                   xShift, 0,
-                                                   fill = 'black',
-                                                   tags = ('slider',))
-        # Arrow
-        self._canvas.create_polygon(-6.0, 10,
-                                    6.0, 10,
-                                    0, 0,
-                                    fill = 'grey85',
-                                    outline = 'black',
-                                    tags = ('slider',))
-        # The indicator
-        self._canvas.create_line(left, 0,
-                                 right, 0,
-                                 width = 2)
+	    # Create the slider directly in the interior
+            _createSlider(interior)
+	    self._canvas.bind('<ButtonRelease-1>', self._sliderBtnRelease)
+	    self._canvas.bind('<ButtonPress-1>', self._sliderBtnPress)
+            self._canvas.bind('<Motion>', self._sliderMove)
+            self._canvas.bind('<Configure>', self._changeConfiguration)
 
 
         
         
 	# Check keywords and initialise options.
 	# Check keywords and initialise options.
-	self.initialiseoptions(PopupSlider)
+	self.initialiseoptions(SliderWidget)
+
+        # Adjust relief
+        if not kw.has_key('relief'):
+            if self['style'] == VALUATOR_FULL:
+                self['relief'] = FLAT
 
 
     def destroy(self):
     def destroy(self):
-	if self['dropdown'] and self._isPosted:
+	if (self['style'] == VALUATOR_MINI) and self._isPosted:
             Pmw.popgrab(self._popup)
             Pmw.popgrab(self._popup)
         Pmw.MegaWidget.destroy(self)
         Pmw.MegaWidget.destroy(self)
 
 
@@ -578,10 +272,6 @@ class PopupSlider(Pmw.MegaWidget):
         # Record value
         # Record value
         self.value = value
         self.value = value
 
 
-    def updateIndicator(self, value):
-        # Nothing visible to update on this type of widget
-        pass
-    
     def get(self):
     def get(self):
         """
         """
         self.get()
         self.get()
@@ -589,50 +279,42 @@ class PopupSlider(Pmw.MegaWidget):
         """
         """
         return self.value
         return self.value
 
 
+    def updateIndicator(self, value):
+        # Get current marker position
+        markerX = self._getMarkerX()
+        percentX = (value - self['min'])/(self['max'] - self['min'])
+        newX = percentX * (self.right - self.left) + self.left
+        dx = newX - markerX
+        self._canvas.move('slider', dx, 0)
+    
     #======================================================================
     #======================================================================
 
 
-    # Private methods for dropdown canvas.
-
-    def _setNumDigits(self):
-        pass
-
-    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')
+    # Private methods for slider.
 
 
     def _postCanvas(self, event = None):
     def _postCanvas(self, event = None):
         self._isPosted = 1
         self._isPosted = 1
         self._fUpdate = 0
         self._fUpdate = 0
-        self._drawArrow(sunken=1)
+        if self['style'] == VALUATOR_MINI:
+            self.interior()['relief'] = SUNKEN
 
 
         # Make sure that the arrow is displayed sunken.
         # Make sure that the arrow is displayed sunken.
         self.update_idletasks()
         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()
+        x = self._arrowBtn.winfo_rootx() + self._arrowBtn.winfo_width()/2.0
+        y = self._arrowBtn.winfo_rooty() + self._arrowBtn.winfo_height()
         minW = self._minLabel.winfo_width()
         minW = self._minLabel.winfo_width()
         cw =  self._canvas.winfo_width()
         cw =  self._canvas.winfo_width()
         maxW = self._maxLabel.winfo_width()
         maxW = self._maxLabel.winfo_width()
-        pw = minW + cw + maxW
+        #pw = minW + cw + maxW
+        pw = maxW + cw/2.0
         ch =  self._canvas.winfo_height()
         ch =  self._canvas.winfo_height()
         sh = self.winfo_screenheight()
         sh = self.winfo_screenheight()
 
 
         # Compensate if too close to edge of screen
         # Compensate if too close to edge of screen
         if y + ch > sh and y > sh / 2:
         if y + ch > sh and y > sh / 2:
-            y = self._entryfield.winfo_rooty() - ch
+            y = self._arrowBtn.winfo_rooty() - ch
 
 
-        Pmw.setgeometryanddeiconify(self._popup, '+%d+%d' % (x + w - pw, y))
+        Pmw.setgeometryanddeiconify(self._popup, '+%d+%d' % (x - pw, y))
 
 
         # Grab the popup, so that all events are delivered to it, and
         # Grab the popup, so that all events are delivered to it, and
         # set focus to the canvas, to make keyboard navigation
         # set focus to the canvas, to make keyboard navigation
@@ -640,8 +322,6 @@ class PopupSlider(Pmw.MegaWidget):
         Pmw.pushgrab(self._popup, 1, self._unpostCanvas)
         Pmw.pushgrab(self._popup, 1, self._unpostCanvas)
         self._canvas.focus_set()
         self._canvas.focus_set()
 
 
-        self._drawArrow()
-
         # Ignore the first release of the mouse button after posting the
         # Ignore the first release of the mouse button after posting the
         # dropdown canvas, unless the mouse enters the dropdown canvas.
         # dropdown canvas, unless the mouse enters the dropdown canvas.
         self._fUpdate = 0
         self._fUpdate = 0
@@ -650,23 +330,37 @@ class PopupSlider(Pmw.MegaWidget):
         self._fPressInsde = 0
         self._fPressInsde = 0
 
 
     def _updateValue(self,event):
     def _updateValue(self,event):
-        canvasX = self._canvas.canvasx(
+        mouseX = self._canvas.canvasx(
             event.x_root - self._canvas.winfo_rootx())
             event.x_root - self._canvas.winfo_rootx())
-        if canvasX < self.left:
-            canvasX = self.left
-        if canvasX > self.right:
-            canvasX = self.right
-        # Get current marker position
-        currX = self._getMarkerX()
-        dx = canvasX - currX
-        self._canvas.move('slider', dx, 0)
-
-    def _dropdownBtnPress(self, event):
-        self._fUpdate = 1
-        self._fPressInside = 1
-        self._updateValue(event)
+        if mouseX < self.left:
+            mouseX = self.left
+        if mouseX > self.right:
+            mouseX = self.right
+        # Update value
+        sf = (mouseX - self.left)/(self.right - self.left)
+        newVal = sf * (self['max'] - self['min']) + self['min']
+        self.set(newVal)
+
+    def _sliderBtnPress(self, event):
+        # Check behavior for this button press
+        if self['style'] == VALUATOR_MINI:
+            widget = self._popup
+            xPos = event.x_root - widget.winfo_rootx()
+            yPos = event.y_root - widget.winfo_rooty()
+            fInside = ((xPos > 0) and (xPos < widget.winfo_width()) and
+                       (yPos > 0) and (yPos < widget.winfo_height()))
+        else:
+            fInside = 1
+        # Set flags based upon result
+        if fInside:
+            self._fPressInside = 1
+            self._fUpdate = 1
+            self._updateValue(event)
+        else:
+            self._fPressInside = 0
+            self._fUpdate = 0
             
             
-    def _dropdownMove(self, event):
+    def _sliderMove(self, event):
         if self._firstPress and not self._fUpdate:
         if self._firstPress and not self._fUpdate:
             canvasY = self._canvas.canvasy(
             canvasY = self._canvas.canvasy(
                 event.y_root - self._canvas.winfo_rooty())
                 event.y_root - self._canvas.winfo_rooty())
@@ -676,7 +370,7 @@ class PopupSlider(Pmw.MegaWidget):
         elif self._fUpdate:
         elif self._fUpdate:
             self._updateValue(event)
             self._updateValue(event)
 
 
-    def _dropdownBtnRelease(self, event):
+    def _sliderBtnRelease(self, event):
         if (self._fUnpost or
         if (self._fUnpost or
             (not (self._firstPress or self._fPressInside))):
             (not (self._firstPress or self._fPressInside))):
             self._unpostCanvas()
             self._unpostCanvas()
@@ -688,14 +382,6 @@ class PopupSlider(Pmw.MegaWidget):
     def _unpostOnNextRelease(self, event = None):
     def _unpostOnNextRelease(self, event = None):
 	self._fUnpost = 1
 	self._fUnpost = 1
 
 
-    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 _unpostCanvas(self, event=None):
     def _unpostCanvas(self, event=None):
 	if not self._isPosted:
 	if not self._isPosted:
             # It is possible to get events on an unposted popup.  For
             # It is possible to get events on an unposted popup.  For
@@ -714,12 +400,66 @@ class PopupSlider(Pmw.MegaWidget):
 	self._popup.withdraw()
 	self._popup.withdraw()
 
 
 	self._isPosted = 0
 	self._isPosted = 0
-	self._drawArrow()
+
+        if self['style'] == VALUATOR_MINI:
+            self.interior()['relief'] = RAISED
+
+    def _incrementValue(self, event):
+        self.set(self.value + self.increment)
+    def _bigIncrementValue(self, event):
+        self.set(self.value + self.increment * 10.0)
+    def _decrementValue(self, event):
+        self.set(self.value - self.increment)
+    def _bigDecrementValue(self, event):
+        self.set(self.value - self.increment * 10.0)
+    def _goToMin(self, event):
+        self.set(self['min'])
+    def _goToMax(self, event):
+        self.set(self['max'])
+
+    # Methods to modify floater characteristics    
+    def setMin(self):
+        self._minLabel['text'] = self.formatString % self['min']
+        self.updateIndicator(self.value)
+
+    def setMax(self):
+        self._maxLabel['text'] = self.formatString % self['max']
+        self.updateIndicator(self.value)
+
+    def setNumDigits(self):
+        self.formatString = '%0.' + ('%d' % self['numDigits']) + 'f'
+        self._minLabel['text'] = self.formatString % self['min']
+        self._maxLabel['text'] = self.formatString % self['max']
+        self.updateIndicator(self.value)
+        self.increment = pow(10, -self['numDigits'])
+
+    def _changeConfiguration(self, event):
+        newWidth = self._canvas.winfo_width()
+        self.left = -newWidth/2.0 + self.xPad
+        self.right = newWidth/2.0 - self.xPad
+        self._canvas.configure(scrollregion = (-newWidth/2.0, self.top,
+                                               newWidth/2.0, self.bottom))
+        self._canvas.coords('line', self.left, 0, self.right, 0)
+        self.updateIndicator(self.value)
 
 
     def _getMarkerX(self):
     def _getMarkerX(self):
         # Get marker triangle coordinates
         # Get marker triangle coordinates
         c = self._canvas.coords(self._marker)
         c = self._canvas.coords(self._marker)
         # Marker postion defined as X position of third vertex
         # Marker postion defined as X position of third vertex
         return c[4]
         return c[4]
-        
-Pmw.forwardmethods(PopupSlider, Pmw.EntryField, '_entryfield')
+
+    def setRelief(self):
+        self.interior()['relief'] = self['relief']
+
+    def setBorderwidth(self):
+        self.interior()['borderwidth'] = self['borderwidth']
+
+    def setBackground(self):
+        self._canvas['background'] = self['background']
+
+    def highlightWidget(self, event):
+        self._arrowBtn.itemconfigure('arrow', fill = 'black')
+
+    def restoreWidget(self, event):
+        self._arrowBtn.itemconfigure('arrow', fill = '#A0A0A0')
+

+ 117 - 2
direct/src/tkwidgets/Valuator.py

@@ -4,6 +4,9 @@ import Pmw
 import WidgetPropertiesDialog
 import WidgetPropertiesDialog
 import string
 import string
 
 
+VALUATOR_MINI = 'mini'
+VALUATOR_FULL = 'full'
+
 class Valuator(Pmw.MegaWidget):
 class Valuator(Pmw.MegaWidget):
     sfBase = 3.0
     sfBase = 3.0
     sfDist = 7
     sfDist = 7
@@ -357,6 +360,11 @@ class ValuatorGroup(Pmw.MegaWidget):
             ('labels',          DEFAULT_LABELS,         self._updateLabels),
             ('labels',          DEFAULT_LABELS,         self._updateLabels),
             # The command to be executed when one of the valuators is updated
             # The command to be executed when one of the valuators is updated
             ('command',         None,                   None),
             ('command',         None,                   None),
+            # Callbacks to execute when updating widget's value
+            ('preCallback',       None,                 None),
+            ('postCallback',      None,                 None),
+            # Extra data to be passed to callback function, needs to be a list
+            ('callbackData',      [],                   None),
             )
             )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
 
 
@@ -376,6 +384,9 @@ class ValuatorGroup(Pmw.MegaWidget):
             if self['type'] == DIAL:
             if self['type'] == DIAL:
                 import Dial
                 import Dial
                 valuatorType = Dial.Dial
                 valuatorType = Dial.Dial
+            elif self['type'] == SLIDER:
+                import Slider
+                valuatorType = Slider.Slider
             else:
             else:
                 import Floater
                 import Floater
                 valuatorType = Floater.Floater
                 valuatorType = Floater.Floater
@@ -383,7 +394,10 @@ class ValuatorGroup(Pmw.MegaWidget):
                 'valuator%d' % index, (), 'valuator', valuatorType,
                 'valuator%d' % index, (), 'valuator', valuatorType,
                 (interior,), value = self._value[index],
                 (interior,), value = self._value[index],
                 text = self['labels'][index],
                 text = self['labels'][index],
-                command = lambda val, i = index: self._valuatorSetAt(i, val)
+                command = lambda val, i = index: self._valuatorSetAt(i, val),
+                preCallback = self._preCallback,
+                postCallback = self._postCallback,
+                callbackData = [self],
                 )
                 )
             f.pack(side = self['side'], expand = 1, fill = X)
             f.pack(side = self['side'], expand = 1, fill = X)
             self._valuatorList.append(f)
             self._valuatorList.append(f)
@@ -428,6 +442,16 @@ class ValuatorGroup(Pmw.MegaWidget):
             for index in range(self['dim']):
             for index in range(self['dim']):
                 self._valuatorList[index]['text'] = self['labels'][index]
                 self._valuatorList[index]['text'] = self['labels'][index]
 
 
+    def _preCallback(self, valGroup):
+        # Execute pre callback
+        if self['preCallback']:
+            apply(self['preCallback'], valGroup.get())
+        
+    def _postCallback(self, valGroup):
+        # Execute post callback
+        if self['postCallback']:
+            apply(self['postCallback'], valGroup.get())
+
     def __len__(self):
     def __len__(self):
         return self['dim']
         return self['dim']
     
     
@@ -464,6 +488,13 @@ class ValuatorGroupPanel(Pmw.MegaToplevel):
             ('numDigits',       2,                      self._setNumDigits),
             ('numDigits',       2,                      self._setNumDigits),
             # The command to be executed when one of the floaters is updated
             # The command to be executed when one of the floaters is updated
             ('command',         None,                   self._setCommand),
             ('command',         None,                   self._setCommand),
+            # Callbacks to execute when updating widget's value
+            ('preCallback',       None,                 self._setPreCallback),
+            ('postCallback',      None,                 self._setPostCallback),
+            # Extra data to be passed to callback function, needs to be a list
+            ('callbackData',      [],                   self._setCallbackData),
+            # Destroy or withdraw
+            ('fDestroy',        0,                      INITOPT)
             )
             )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
 
 
@@ -486,9 +517,15 @@ class ValuatorGroupPanel(Pmw.MegaToplevel):
             'Valuator Group', 'command', 'Reset the Valuator Group panel',
             'Valuator Group', 'command', 'Reset the Valuator Group panel',
             label = 'Reset',
             label = 'Reset',
             command = lambda s = self: s.reset())
             command = lambda s = self: s.reset())
+
+        if self['fDestroy']:
+            dismissCommand = self.destroy
+        else:
+            dismissCommand = self.withdraw
+
         menubar.addmenuitem(
         menubar.addmenuitem(
             'Valuator Group', 'command', 'Dismiss Valuator Group panel',
             'Valuator Group', 'command', 'Dismiss Valuator Group panel',
-            label = 'Dismiss', command = self.withdraw)
+            label = 'Dismiss', command = dismissCommand)
         
         
         menubar.addmenu('Help', 'Valuator Group Help Operations')
         menubar.addmenu('Help', 'Valuator Group Help Operations')
         self.toggleBalloonVar = IntVar()
         self.toggleBalloonVar = IntVar()
@@ -530,7 +567,85 @@ class ValuatorGroupPanel(Pmw.MegaToplevel):
     def _setCommand(self):
     def _setCommand(self):
         self.valuatorGroup['command'] = self['command']
         self.valuatorGroup['command'] = self['command']
 
 
+    def _setPreCallback(self):
+        self.valuatorGroup['preCallback'] = self['preCallback']
+
+    def _setPostCallback(self):
+        self.valuatorGroup['postCallback'] = self['postCallback']
+
+    def _setCallbackData(self):
+        self.valuatorGroup['callbackData'] = self['callbackData']
+
     def reset(self):
     def reset(self):
         self.set(self['value'])
         self.set(self['value'])
 
 
 Pmw.forwardmethods(ValuatorGroupPanel, ValuatorGroup, 'valuatorGroup')
 Pmw.forwardmethods(ValuatorGroupPanel, ValuatorGroup, 'valuatorGroup')
+
+
+def rgbPanel(nodePath, callback = None, style = 'full'):
+    def setNodePathColor(color, np = nodePath, cb = callback):
+        np.setColor(color[0]/255.0, color[1]/255.0,
+                    color[2]/255.0, color[3]/255.0)
+        # Execute callback to pass along color info
+        if cb:
+            cb(color)
+    # Check init color
+    if nodePath.hasColor():
+        initColor = nodePath.getColor() * 255.0
+    else:
+        initColor = Vec4(255)
+    # Create entry scale group
+    esg = ValuatorGroupPanel(title = 'RGBA Panel: ' + nodePath.getName(),
+                             dim = 4,
+                             labels = ['R','G','B','A'],
+                             value = [int(initColor[0]),
+                                      int(initColor[1]),
+                                      int(initColor[2]),
+                                      int(initColor[3])],
+                             type = 'slider',
+                             valuator_style = style,
+                             valuator_min = 0,
+                             valuator_max = 255,
+                             valuator_resolution = 1,
+                             # Destroy not withdraw panel on dismiss
+                             fDestroy = 1,
+                             command = setNodePathColor)
+    # Update menu button
+    esg.component('menubar').component('Valuator Group-button')['text'] = (
+        'RGBA Panel')
+    # Update menu
+    menu = esg.component('menubar').component('Valuator Group-menu')
+    # Some helper functions
+    # Clear color
+    menu.insert_command(index = 1, label = 'Clear Color',
+                        command = lambda np = nodePath: np.clearColor())
+    # Set Clear Transparency
+    menu.insert_command(index = 2, label = 'Set Transparency',
+                        command = lambda np = nodePath: np.setTransparency(1))
+    menu.insert_command(
+        index = 3, label = 'Clear Transparency',
+        command = lambda np = nodePath: np.clearTransparency())
+
+    # System color picker
+    def popupColorPicker(esg = esg):
+        # Can pass in current color with: color = (255, 0, 0)
+        color = tkColorChooser.askcolor(
+            parent = esg.interior(),
+            # Initialize it to current color
+            initialcolor = tuple(esg.get()[:3]))[0]
+        if color:
+            esg.set((color[0], color[1], color[2], esg.getAt(3)))
+    menu.insert_command(index = 4, label = 'Popup Color Picker',
+                        command = popupColorPicker)
+    def printToLog(nodePath=nodePath):
+        c=nodePath.getColor()
+        print "Vec4(%.3f, %.3f, %.3f, %.3f)"%(c[0], c[1], c[2], c[3])
+    menu.insert_command(index = 5, label = 'Print to log',
+                        command = printToLog)
+    
+    # Set callback
+    def onRelease(r,g,b,a, nodePath = nodePath):
+        messenger.send('RGBPanel_setColor', [nodePath, r,g,b,a])
+    esg['postCallback'] = onRelease
+    return esg
+

+ 22 - 22
direct/src/tkwidgets/VectorWidgets.py

@@ -2,7 +2,7 @@ from Tkinter import *
 import Pmw
 import Pmw
 import Valuator
 import Valuator
 import Floater
 import Floater
-import EntryScale
+import Slider
 import string
 import string
 import tkColorChooser
 import tkColorChooser
 
 
@@ -15,7 +15,6 @@ class VectorEntry(Pmw.MegaWidget):
         DEFAULT_VALUE = [0.0] * kw.get('dim', DEFAULT_DIM)
         DEFAULT_VALUE = [0.0] * kw.get('dim', DEFAULT_DIM)
         DEFAULT_LABELS = map(lambda x: 'v[%d]' % x,
         DEFAULT_LABELS = map(lambda x: 'v[%d]' % x,
                              range(kw.get('dim', DEFAULT_DIM)))
                              range(kw.get('dim', DEFAULT_DIM)))
-        VALUATOR = kw.get('valuatorType', Floater.FloaterGroup)
 
 
         # Process options
         # Process options
         INITOPT = Pmw.INITOPT
         INITOPT = Pmw.INITOPT
@@ -31,8 +30,8 @@ class VectorEntry(Pmw.MegaWidget):
             ('text',                'Vector:',      self._updateText),
             ('text',                'Vector:',      self._updateText),
             ('min',                 None,           self._updateValidate),
             ('min',                 None,           self._updateValidate),
             ('max',                 None,           self._updateValidate),
             ('max',                 None,           self._updateValidate),
-            ('numDigits',   2,              self._setSigDigits),
-            ('valuatorType',        VALUATOR,       None),
+            ('numDigits',           2,              self._setSigDigits),
+            ('type',                'floater',      None),
             ('state',               'normal',       self._setState),
             ('state',               'normal',       self._setState),
             )
             )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
@@ -92,9 +91,11 @@ class VectorEntry(Pmw.MegaWidget):
         self._floaters = self.createcomponent(
         self._floaters = self.createcomponent(
             'floaterGroup',
             'floaterGroup',
             (('fGroup', 'floaterGroup'),
             (('fGroup', 'floaterGroup'),
-             ('Valuator', 'floaterGroup_Valuator'),), None,
-            self['valuatorType'], (self.interior(),),
-            dim = self['dim'], title = self['text'],
+             ('valuator', 'floaterGroup_valuator'),), None,
+            Valuator.ValuatorGroupPanel, (self.interior(),),
+            dim = self['dim'],
+            #title = self['text'],
+            type = self['type'],
             command = self.set)
             command = self.set)
         # Note: This means the 'X' on the menu bar doesn't really destroy
         # Note: This means the 'X' on the menu bar doesn't really destroy
         # the panel, just withdraws it.  This is to avoid problems which occur
         # the panel, just withdraws it.  This is to avoid problems which occur
@@ -145,7 +146,7 @@ class VectorEntry(Pmw.MegaWidget):
     def _setSigDigits(self):
     def _setSigDigits(self):
         sd = self['numDigits']
         sd = self['numDigits']
         self.entryFormat = '%.' + '%d' % sd + 'f'
         self.entryFormat = '%.' + '%d' % sd + 'f'
-        self.configure(Valuator_numDigits = sd)
+        self.configure(valuator_numDigits = sd)
         # And refresh value to reflect change
         # And refresh value to reflect change
         for index in range(self['dim']):
         for index in range(self['dim']):
             self._refreshEntry(index)
             self._refreshEntry(index)
@@ -159,8 +160,8 @@ class VectorEntry(Pmw.MegaWidget):
             'minstrict' : 0,
             'minstrict' : 0,
             'maxstrict' : 0})
             'maxstrict' : 0})
         # Reflect changes in floaters
         # Reflect changes in floaters
-        self.configure(Valuator_min = self['min'],
-                       Valuator_max = self['max'])            
+        self.configure(valuator_min = self['min'],
+                       valuator_max = self['max'])            
 
 
     def get(self):
     def get(self):
         return self._value
         return self._value
@@ -234,24 +235,24 @@ class VectorEntry(Pmw.MegaWidget):
             self.configure(Entry_entry_background = '#C0C0C0')
             self.configure(Entry_entry_background = '#C0C0C0')
             # Disable floater Group scale
             # Disable floater Group scale
             self.component('fGroup').configure(
             self.component('fGroup').configure(
-                Valuator_state = 'disabled')
+                valuator_state = 'disabled')
             # Disable floater group entry
             # Disable floater group entry
             self.component('fGroup').configure(
             self.component('fGroup').configure(
-                Valuator_entry_state = 'disabled')
+                valuator_entry_state = 'disabled')
             self.component('fGroup').configure(
             self.component('fGroup').configure(
-                Valuator_entry_background = '#C0C0C0')
+                valuator_entry_background = '#C0C0C0')
         else:
         else:
             # Disable entry
             # Disable entry
             self.configure(Entry_entry_state = 'normal')
             self.configure(Entry_entry_state = 'normal')
             self.configure(Entry_entry_background = self.entryBackground)
             self.configure(Entry_entry_background = self.entryBackground)
             # Disable floater Group scale
             # Disable floater Group scale
             self.component('fGroup').configure(
             self.component('fGroup').configure(
-                Valuator_state = 'normal')
+                valuator_state = 'normal')
             # Disable floater group entry
             # Disable floater group entry
             self.component('fGroup').configure(
             self.component('fGroup').configure(
-                Valuator_entry_state = 'normal')
+                valuator_entry_state = 'normal')
             self.component('fGroup').configure(
             self.component('fGroup').configure(
-                Valuator_entry_background = self.entryBackground)
+                valuator_entry_background = self.entryBackground)
 
 
 class Vector2Entry(VectorEntry):
 class Vector2Entry(VectorEntry):
     def __init__(self, parent = None, **kw):
     def __init__(self, parent = None, **kw):
@@ -300,18 +301,17 @@ class ColorEntry(VectorEntry):
         # Initialize options for the class (overriding some superclass options)
         # Initialize options for the class (overriding some superclass options)
         optiondefs = (
         optiondefs = (
             ('dim',                     4,                  Pmw.INITOPT),
             ('dim',                     4,                  Pmw.INITOPT),
+            ('type',                    'slider',           Pmw.INITOPT),
             ('fGroup_labels',           ('R','G','B','A'),  None),
             ('fGroup_labels',           ('R','G','B','A'),  None),
             ('min',                     0.0,                None),
             ('min',                     0.0,                None),
             ('max',                     255.0,              None),
             ('max',                     255.0,              None),
-            ('nuDigits',       0,                  None),
-            ('Valuator_resolution',     1.0,                None),
+            ('nuDigits',                0,                  None),
+            ('valuator_resolution',     1.0,                None),
             )
             )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
-        #kw['valuatorType'] = EntryScale.EntryScaleGroup
-        #kw['dim'] = self['dim']
+
         # Initialize the superclass, make sure dim makes it to superclass
         # Initialize the superclass, make sure dim makes it to superclass
-        VectorEntry.__init__(self, parent, dim = self['dim'],
-                             valuatorType = EntryScale.EntryScaleGroup)
+        VectorEntry.__init__(self, parent, dim = self['dim'])
         # Add menu item to popup color picker
         # Add menu item to popup color picker
         self.addMenuItem(
         self.addMenuItem(
             'Popup color picker',
             'Popup color picker',

+ 8 - 2
direct/src/tkwidgets/WidgetPropertiesDialog.py

@@ -111,12 +111,18 @@ class WidgetPropertiesDialog(Toplevel):
             # Set up help string and validator based upon type
             # Set up help string and validator based upon type
             if entryType == 'real':
             if entryType == 'real':
                 # Only allow real numbers
                 # Only allow real numbers
-                entry['validate'] = { 'validator' : self.realOrNone }
+                if fAllowNone:
+                    entry['validate'] = { 'validator' : self.realOrNone }
+                else:
+                    entry['validate'] = { 'validator' : 'real' }
                 if helpString is None:
                 if helpString is None:
                     helpString = 'Enter a floating point number' + extra + '.'
                     helpString = 'Enter a floating point number' + extra + '.'
             elif entryType == 'integer':
             elif entryType == 'integer':
                 # Only allow integer values
                 # Only allow integer values
-                entry['validate'] = { 'validator' : self.intOrNone }
+                if fAllowNone:
+                    entry['validate'] = { 'validator' : self.intOrNone }
+                else:
+                    entry['validate'] = { 'validator' : 'integer' }
                 if helpString is None:
                 if helpString is None:
                     helpString = 'Enter an integer' + extra + '.'
                     helpString = 'Enter an integer' + extra + '.'
             else:
             else: