Browse Source

*** empty log message ***

Mark Mine 24 years ago
parent
commit
e3df94a036

+ 8 - 4
direct/src/directtools/DirectSession.py

@@ -160,8 +160,10 @@ class DirectSession(PandaObject):
                           '[', '{', ']', '}',
                           '[', '{', ']', '}',
                           'shift-a', 'b', 'l', 'shift-l', 'o', 'p', 'r',
                           'shift-a', 'b', 'l', 'shift-l', 'o', 'p', 'r',
                           'shift-r', 's', 't', 'v', 'w']
                           'shift-r', 's', 't', 'v', 'w']
-        self.mouseEvents = ['mouse1', 'mouse1-up',
-                            'mouse2', 'mouse2-up',
+        self.mouseEvents = ['mouse1', 'shift-mouse1', 'control-mouse1',
+                            'alt-mouse1', 'mouse1-up',
+                            'mouse2', 'shift-mouse2', 'control-mouse2',
+                            'alt-mouse2', 'mouse2-up',
                             'mouse3', 'mouse3-up']
                             'mouse3', 'mouse3-up']
 
 
         if base.wantTk:
         if base.wantTk:
@@ -324,11 +326,13 @@ class DirectSession(PandaObject):
 
 
     def inputHandler(self, input):
     def inputHandler(self, input):
         # Deal with keyboard and mouse input
         # Deal with keyboard and mouse input
-        if input == 'mouse1':
+        if ((input == 'mouse1') or (input == 'shift-mouse1') or
+            (input == 'control-mouse1') or (input == 'alt-mouse1')):
             messenger.send('DIRECT_mouse1')
             messenger.send('DIRECT_mouse1')
         elif input == 'mouse1-up':
         elif input == 'mouse1-up':
             messenger.send('DIRECT_mouse1Up')
             messenger.send('DIRECT_mouse1Up')
-        elif input == 'mouse2': 
+        elif ((input == 'mouse2') or (input == 'shift-mouse2') or
+              (input == 'control-mouse2') or (input == 'alt-mouse2')): 
             messenger.send('DIRECT_mouse2')
             messenger.send('DIRECT_mouse2')
         elif input == 'mouse2-up':
         elif input == 'mouse2-up':
             messenger.send('DIRECT_mouse2Up')
             messenger.send('DIRECT_mouse2Up')

+ 13 - 0
direct/src/directtools/DirectUtil.py

@@ -1,5 +1,18 @@
 from PandaObject import *
 from PandaObject import *
 
 
+# Create a tk compatible color string
+def getTkColorString(color):
+        def toHex(intVal):
+            val = int(round(intVal))
+            if val < 16:
+                return "0" + hex(val)[2:]
+            else:
+                return hex(val)[2:]
+        r = toHex(color[0])
+        g = toHex(color[1])
+        b = toHex(color[2])
+        return "#" + r + g + b
+
 ## Background Color ##
 ## Background Color ##
 def setBackgroundColor(r,g,b):
 def setBackgroundColor(r,g,b):
     base.win.getGsg().setColorClearValue(VBase4(r, g, b, 1.0))
     base.win.getGsg().setColorClearValue(VBase4(r, g, b, 1.0))

+ 26 - 26
direct/src/tkwidgets/Dial.py

@@ -49,7 +49,7 @@ class Dial(Valuator):
             style = self['style'],
             style = self['style'],
             command = self.setEntry,
             command = self.setEntry,
             value = self['value'])
             value = self['value'])
-        self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
+        self._valuator._widget.bind('<Double-ButtonPress-1>', self.mouseReset)
 
 
     def packValuator(self):
     def packValuator(self):
         if self['style'] == VALUATOR_FULL:
         if self['style'] == VALUATOR_FULL:
@@ -209,41 +209,41 @@ class DialWidget(Pmw.MegaWidget):
         inner_radius = max(3,radius * INNER_SF)
         inner_radius = max(3,radius * INNER_SF)
 
 
         # The canvas 
         # The canvas 
-        self._canvas = self.createcomponent('canvas', (), None,
+        self._widget = self.createcomponent('canvas', (), None,
                                             Canvas, (interior,),
                                             Canvas, (interior,),
                                             width = size, height = size,
                                             width = size, height = size,
                                             background = self['background'],
                                             background = self['background'],
                                             highlightthickness = 0,
                                             highlightthickness = 0,
                                             scrollregion = (-radius,-radius,
                                             scrollregion = (-radius,-radius,
                                                             radius, radius))
                                                             radius, radius))
-        self._canvas.pack(expand = 1, fill = BOTH)
+        self._widget.pack(expand = 1, fill = BOTH)
 
 
         # The dial face (no outline/fill, primarily for binding mouse events)
         # The dial face (no outline/fill, primarily for binding mouse events)
-        self._canvas.create_oval(-radius, -radius, radius, radius,
+        self._widget.create_oval(-radius, -radius, radius, radius,
                                  outline = '',
                                  outline = '',
                                  tags = ('dial',))
                                  tags = ('dial',))
 
 
         # The indicator
         # The indicator
-        self._canvas.create_line(0, 0, 0, -radius, width = 2,
+        self._widget.create_line(0, 0, 0, -radius, width = 2,
                                  tags = ('indicator', 'dial'))
                                  tags = ('indicator', 'dial'))
 
 
         # The central knob
         # The central knob
-        self._canvas.create_oval(-inner_radius, -inner_radius,
+        self._widget.create_oval(-inner_radius, -inner_radius,
                                  inner_radius, inner_radius,
                                  inner_radius, inner_radius,
-                                 fill = '#A0A0A0',
+                                 fill = 'grey50',
                                  tags = ('knob',))
                                  tags = ('knob',))
 
 
         # Add event bindings
         # Add event bindings
-        self._canvas.tag_bind('dial', '<ButtonPress-1>', self.mouseDown)
-        self._canvas.tag_bind('dial', '<B1-Motion>', self.mouseMotion)
-        self._canvas.tag_bind('dial', '<Shift-B1-Motion>',
+        self._widget.tag_bind('dial', '<ButtonPress-1>', self.mouseDown)
+        self._widget.tag_bind('dial', '<B1-Motion>', self.mouseMotion)
+        self._widget.tag_bind('dial', '<Shift-B1-Motion>',
                               self.shiftMouseMotion)
                               self.shiftMouseMotion)
-        self._canvas.tag_bind('dial', '<ButtonRelease-1>', self.mouseUp)
-        self._canvas.tag_bind('knob', '<ButtonPress-1>', self.knobMouseDown)
-        self._canvas.tag_bind('knob', '<B1-Motion>', self.updateDialSF)
-        self._canvas.tag_bind('knob', '<ButtonRelease-1>', self.knobMouseUp)
-        self._canvas.tag_bind('knob', '<Enter>', self.highlightKnob)
-        self._canvas.tag_bind('knob', '<Leave>', self.restoreKnob)
+        self._widget.tag_bind('dial', '<ButtonRelease-1>', self.mouseUp)
+        self._widget.tag_bind('knob', '<ButtonPress-1>', self.knobMouseDown)
+        self._widget.tag_bind('knob', '<B1-Motion>', self.updateDialSF)
+        self._widget.tag_bind('knob', '<ButtonRelease-1>', self.knobMouseUp)
+        self._widget.tag_bind('knob', '<Enter>', self.highlightKnob)
+        self._widget.tag_bind('knob', '<Leave>', self.restoreKnob)
 
 
         # Make sure input variables processed 
         # Make sure input variables processed 
         self.initialiseoptions(DialWidget)
         self.initialiseoptions(DialWidget)
@@ -289,8 +289,8 @@ class DialWidget(Pmw.MegaWidget):
         self.computeValueFromAngle(dialAngle)
         self.computeValueFromAngle(dialAngle)
         
         
     def computeDialAngle(self,event, fShift = 0):
     def computeDialAngle(self,event, fShift = 0):
-        x = self._canvas.canvasx(event.x)
-        y = self._canvas.canvasy(event.y)
+        x = self._widget.canvasx(event.x)
+        y = self._widget.canvasy(event.y)
         rawAngle = math.atan2(y,x)
         rawAngle = math.atan2(y,x)
         # Snap to grid
         # Snap to grid
         # Convert to dial coords to do snapping
         # Convert to dial coords to do snapping
@@ -328,7 +328,7 @@ class DialWidget(Pmw.MegaWidget):
         endx = math.cos(rawAngle) * self.radius
         endx = math.cos(rawAngle) * self.radius
         endy = math.sin(rawAngle) * self.radius
         endy = math.sin(rawAngle) * self.radius
         # Draw new indicator
         # Draw new indicator
-        self._canvas.coords('indicator', endx * INNER_SF, endy * INNER_SF,
+        self._widget.coords('indicator', endx * INNER_SF, endy * INNER_SF,
                             endx, endy)
                             endx, endy)
 
 
     # Knob velocity controller
     # Knob velocity controller
@@ -347,8 +347,8 @@ class DialWidget(Pmw.MegaWidget):
         return Task.cont
         return Task.cont
 
 
     def updateDialSF(self, event):
     def updateDialSF(self, event):
-        x = self._canvas.canvasx(event.x)
-        y = self._canvas.canvasy(event.y)
+        x = self._widget.canvasx(event.x)
+        y = self._widget.canvasy(event.y)
         offset = max(0, abs(x) - Valuator.deadband)
         offset = max(0, abs(x) - Valuator.deadband)
         if offset == 0:
         if offset == 0:
             return 0
             return 0
@@ -377,10 +377,10 @@ class DialWidget(Pmw.MegaWidget):
         self.interior()['borderwidth'] = self['borderwidth']
         self.interior()['borderwidth'] = self['borderwidth']
 
 
     def setBackground(self):
     def setBackground(self):
-        self._canvas['background'] = self['background']
+        self._widget['background'] = self['background']
 
 
     def setNumSegments(self):
     def setNumSegments(self):
-        self._canvas.delete('ticks')
+        self._widget.delete('ticks')
         # Based upon input snap angle, how many ticks
         # Based upon input snap angle, how many ticks
         numSegments = self['numSegments']
         numSegments = self['numSegments']
         # Compute snapAngle (radians)
         # Compute snapAngle (radians)
@@ -400,14 +400,14 @@ class DialWidget(Pmw.MegaWidget):
                 sf = 0.8
                 sf = 0.8
             endx = startx * sf
             endx = startx * sf
             endy = starty * sf
             endy = starty * sf
-            self._canvas.create_line(startx, starty, endx, endy,
+            self._widget.create_line(startx, starty, endx, endy,
                                      tags = ('ticks','dial'))
                                      tags = ('ticks','dial'))
 
 
     def highlightKnob(self, event):
     def highlightKnob(self, event):
-        self._canvas.itemconfigure('knob', fill = 'black')
+        self._widget.itemconfigure('knob', fill = 'black')
 
 
     def restoreKnob(self, event):
     def restoreKnob(self, event):
-        self._canvas.itemconfigure('knob', fill = '#A0A0A0')
+        self._widget.itemconfigure('knob', fill = 'grey50')
 
 
     # To call user callbacks
     # To call user callbacks
     def _onButtonPress(self, *args):
     def _onButtonPress(self, *args):

+ 17 - 17
direct/src/tkwidgets/Floater.py

@@ -34,7 +34,7 @@ class Floater(Valuator):
                                               (self.interior(),),
                                               (self.interior(),),
                                               command = self.setEntry,
                                               command = self.setEntry,
                                               value = self['value'])
                                               value = self['value'])
-        self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
+        self._valuator._widget.bind('<Double-ButtonPress-1>', self.mouseReset)
 
 
     def packValuator(self):
     def packValuator(self):
         # Position components
         # Position components
@@ -85,7 +85,7 @@ class FloaterWidget(Pmw.MegaWidget):
         # The canvas
         # The canvas
         width = self['width']
         width = self['width']
         height = self['height']
         height = self['height']
-        self._canvas = self.createcomponent('canvas', (), None,
+        self._widget = self.createcomponent('canvas', (), None,
                                             Canvas, (interior,),
                                             Canvas, (interior,),
                                             width = width,
                                             width = width,
                                             height = height,
                                             height = height,
@@ -95,24 +95,24 @@ class FloaterWidget(Pmw.MegaWidget):
                                                             -height/2.0,
                                                             -height/2.0,
                                                             width/2.0,
                                                             width/2.0,
                                                             height/2.0))
                                                             height/2.0))
-        self._canvas.pack(expand = 1, fill = BOTH)
+        self._widget.pack(expand = 1, fill = BOTH)
 
 
         # The floater icon
         # The floater icon
-        self._canvas.create_polygon(-width/2.0, 0, -2.0, -height/2.0,
+        self._widget.create_polygon(-width/2.0, 0, -2.0, -height/2.0,
                                     -2.0, height/2.0,
                                     -2.0, height/2.0,
-                                    fill = '#A0A0A0',
+                                    fill = 'grey50',
                                     tags = ('floater',))
                                     tags = ('floater',))
-        self._canvas.create_polygon(width/2.0, 0, 2.0, height/2.0,
+        self._widget.create_polygon(width/2.0, 0, 2.0, height/2.0,
                                     2.0, -height/2.0,
                                     2.0, -height/2.0,
-                                    fill = '#A0A0A0',
+                                    fill = 'grey50',
                                     tags = ('floater',))
                                     tags = ('floater',))
 
 
         # Add event bindings
         # Add event bindings
-        self._canvas.bind('<ButtonPress-1>', self.mouseDown)
-        self._canvas.bind('<B1-Motion>', self.updateFloaterSF)
-        self._canvas.bind('<ButtonRelease-1>', self.mouseUp)
-        self._canvas.bind('<Enter>', self.highlightWidget)
-        self._canvas.bind('<Leave>', self.restoreWidget)
+        self._widget.bind('<ButtonPress-1>', self.mouseDown)
+        self._widget.bind('<B1-Motion>', self.updateFloaterSF)
+        self._widget.bind('<ButtonRelease-1>', self.mouseUp)
+        self._widget.bind('<Enter>', self.highlightWidget)
+        self._widget.bind('<Leave>', self.restoreWidget)
 
 
         # Make sure input variables processed 
         # Make sure input variables processed 
         self.initialiseoptions(FloaterWidget)
         self.initialiseoptions(FloaterWidget)
@@ -167,8 +167,8 @@ class FloaterWidget(Pmw.MegaWidget):
         """
         """
         Update velocity scale factor based of mouse distance from origin
         Update velocity scale factor based of mouse distance from origin
         """
         """
-        x = self._canvas.canvasx(event.x)
-        y = self._canvas.canvasy(event.y)
+        x = self._widget.canvasx(event.x)
+        y = self._widget.canvasy(event.y)
         offset = max(0, abs(x) - Valuator.deadband)
         offset = max(0, abs(x) - Valuator.deadband)
         if offset == 0:
         if offset == 0:
             return 0
             return 0
@@ -203,13 +203,13 @@ class FloaterWidget(Pmw.MegaWidget):
         self.interior()['borderwidth'] = self['borderwidth']
         self.interior()['borderwidth'] = self['borderwidth']
 
 
     def setBackground(self):
     def setBackground(self):
-        self._canvas['background'] = self['background']
+        self._widget['background'] = self['background']
 
 
     def highlightWidget(self, event):
     def highlightWidget(self, event):
-        self._canvas.itemconfigure('floater', fill = 'black')
+        self._widget.itemconfigure('floater', fill = 'black')
 
 
     def restoreWidget(self, event):
     def restoreWidget(self, event):
-        self._canvas.itemconfigure('floater', fill = '#A0A0A0')
+        self._widget.itemconfigure('floater', fill = 'grey50')
 
 
 
 
 class FloaterGroup(Pmw.MegaToplevel):
 class FloaterGroup(Pmw.MegaToplevel):

+ 154 - 133
direct/src/tkwidgets/Slider.py

@@ -27,7 +27,7 @@ class Slider(Valuator):
             )
             )
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
         Valuator.__init__(self, parent)
         Valuator.__init__(self, parent)
-        # Can not enter none for min or max
+        # Can not enter None for min or max, update propertyDict to reflect
         self.propertyDict['min']['fNone'] = 0
         self.propertyDict['min']['fNone'] = 0
         self.propertyDict['min']['help'] = 'Minimum allowable value.'
         self.propertyDict['min']['help'] = 'Minimum allowable value.'
         self.propertyDict['max']['fNone'] = 0
         self.propertyDict['max']['fNone'] = 0
@@ -44,7 +44,7 @@ class Slider(Valuator):
             style = self['style'],
             style = self['style'],
             command = self.setEntry,
             command = self.setEntry,
             value = self['value'])
             value = self['value'])
-        self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
+        self._valuator._widget.bind('<Double-ButtonPress-1>', self.mouseReset)
 
 
         # Add popup bindings to slider widget
         # Add popup bindings to slider widget
         try:
         try:
@@ -89,12 +89,12 @@ class SliderWidget(Pmw.MegaWidget):
 	INITOPT = Pmw.INITOPT
 	INITOPT = Pmw.INITOPT
 	optiondefs = (
 	optiondefs = (
             # Appearance
             # Appearance
+	    ('style',           VALUATOR_MINI,      INITOPT),
             ('relief',          RAISED,             self.setRelief),
             ('relief',          RAISED,             self.setRelief),
             ('borderwidth',     2,                  self.setBorderwidth),
             ('borderwidth',     2,                  self.setBorderwidth),
             ('background',      'SystemButtonFace', self.setBackground),
             ('background',      'SystemButtonFace', self.setBackground),
 	    ('fliparrow',       0,                  INITOPT),
 	    ('fliparrow',       0,                  INITOPT),
             # Behavior
             # Behavior
-	    ('style',           VALUATOR_MINI,        INITOPT),
             # Bounds
             # Bounds
             ('min',             0.0,            self.setMin),
             ('min',             0.0,            self.setMin),
             ('max',             100.0,          self.setMax),
             ('max',             100.0,          self.setMax),
@@ -125,91 +125,99 @@ class SliderWidget(Pmw.MegaWidget):
         self.increment = 0.01
         self.increment = 0.01
 
 
         # Interaction flags
         # Interaction flags
-        self._fUpdate = 0
+        self._isPosted = 0
         self._fUnpost = 0
         self._fUnpost = 0
+        self._fUpdate = 0
+        self._firstPress = 1
         self._fPressInsde = 0
         self._fPressInsde = 0
-        self._isPosted = 0
-        if self['style'] == VALUATOR_MINI:
-            self._firstPress = 1
-        else:
-            self._firstPress = 0
 
 
         # Slider dimensions
         # Slider dimensions
         width = 100
         width = 100
         self.xPad = xPad = 10
         self.xPad = xPad = 10
-        canvasWidth = width + 2 * xPad
+        sliderWidth = 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)
-        self.top = top = -5
-        self.bottom = bottom = top + height
+        top = -5
+        bottom = top + height
 
 
-        def _createSlider(parent):
-            # Create the canvas inside the dropdown window.
+        def createSlider(parent):
+            # Create the slider inside the dropdown window.
             # Min label
             # Min label
             self._minLabel = Label(parent, text = self['min'], width = 8,
             self._minLabel = Label(parent, text = self['min'], width = 8,
-                                   anchor = E)
+                                   anchor = W)
             self._minLabel.pack(side = LEFT)
             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)
+            # Slider widget
             if self['style'] == VALUATOR_FULL:
             if self['style'] == VALUATOR_FULL:
-                self._canvas.configure(relief = SUNKEN, bd = 2)
+                # Use a scale slider
+                self._widgetVar = DoubleVar()
+                self._widgetVar.set(self['value'])
+                self._widget = self.createcomponent(
+                    'slider', (), None,
+                    Scale, (interior,),
+                    variable = self._widgetVar,
+                    from_ = self['min'], to = self['max'],
+                    width = 10,
+                    orient = 'horizontal',
+                    showvalue = 0,
+                    length = sliderWidth,
+                    relief = FLAT, bd = 2,
+                    highlightthickness = 0)
+            else:
+                # Use a canvas slider
+                self._widget = self.createcomponent(
+                    'slider', (), None,
+                    Canvas, (parent,),
+                    width = sliderWidth,
+                    height = height,
+                    bd = 2,
+                    highlightthickness = 0,
+                    scrollregion = (left - xPad, top, right + xPad, bottom))
+                # Interaction marker
+                xShift = 1
+                # Shadow arrow
+                self._marker = self._widget.create_polygon(-7 + xShift, 12,
+                                                           7 + xShift, 12,
+                                                           xShift, 0,
+                                                           fill = 'black',
+                                                           tags = ('marker',))
+                # Arrow
+                self._widget.create_polygon(-6.0, 10,
+                                            6.0, 10,
+                                            0, 0,
+                                            fill = 'grey85',
+                                            outline = 'black',
+                                            tags = ('marker',))
+                # The indicator
+                self._widget.create_line(left, 0,
+                                         right, 0,
+                                         width = 2,
+                                         tags = ('line',))
+
+            self._widget.pack(side = LEFT, expand=1, fill=X)
+
             # Max label
             # Max label
             self._maxLabel = Label(parent, text = self['max'], width = 8,
             self._maxLabel = Label(parent, text = self['max'], width = 8,
                                    anchor = W)
                                    anchor = W)
             self._maxLabel.pack(side = LEFT)
             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['style'] == VALUATOR_MINI:
 	if self['style'] == VALUATOR_MINI:
-	    self._isPosted = 0
 
 
-	    # Create the arrow button.
-	    self._arrowBtn = self.createcomponent('arrowbutton',
-		    (), None,
-		    Canvas, (interior,), borderwidth = 0,
-		    relief = FLAT, width = 14, height = 14)
+	    # Create the arrow button to invoke slider
+	    self._arrowBtn = self.createcomponent(
+                'arrowbutton',
+                (), None,
+                Canvas, (interior,), borderwidth = 0,
+                relief = FLAT, width = 14, height = 14,
+                scrollregion = (-7,-7,7,7))
 	    self._arrowBtn.pack(expand = 1, fill = BOTH)
 	    self._arrowBtn.pack(expand = 1, fill = BOTH)
-            self._arrowBtn.create_polygon(2.5, 4.5, 12.5, 4.5, 7.5, 12.5,
+            self._arrowBtn.create_polygon(-5, -5, 5, -5, 0, 5,
+                                          fill = 'grey50',
                                           tags = 'arrow')
                                           tags = 'arrow')
-	    self._arrowRelief = self._arrowBtn.cget('relief')
-
+            self._arrowBtn.create_line(-5, 5, 5, 5,
+                                       fill = 'grey50',
+                                       tags = 'arrow')
 	    # Create the dropdown window.
 	    # Create the dropdown window.
 	    self._popup = self.createcomponent(
 	    self._popup = self.createcomponent(
                 'popup',
                 'popup',
@@ -219,31 +227,34 @@ class SliderWidget(Pmw.MegaWidget):
 	    self._popup.withdraw()
 	    self._popup.withdraw()
 	    self._popup.overrideredirect(1)
 	    self._popup.overrideredirect(1)
 
 
-            _createSlider(self._popup)
+            # Create popup slider
+            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._postSlider)
             self._arrowBtn.bind('<Enter>', self.highlightWidget)
             self._arrowBtn.bind('<Enter>', self.highlightWidget)
             self._arrowBtn.bind('<Leave>', self.restoreWidget)
             self._arrowBtn.bind('<Leave>', self.restoreWidget)
             # Need to unpost the popup if the arrow Button is unmapped (eg: 
             # 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 slider is
             # displayed.
             # displayed.
-            self._arrowBtn.bind('<Unmap>', self._unpostCanvas)
+            self._arrowBtn.bind('<Unmap>', self._unpostSlider)
             
             
 	    # Bind events to the dropdown window.
 	    # 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)
+	    self._popup.bind('<Escape>', self._unpostSlider)
+	    self._popup.bind('<ButtonRelease-1>', self._widgetBtnRelease)
+	    self._popup.bind('<ButtonPress-1>', self._widgetBtnPress)
+            self._popup.bind('<Motion>', self._widgetMove)
+            
+            self._widget.bind('<Left>', self._decrementValue)
+            self._widget.bind('<Right>', self._incrementValue)
+            self._widget.bind('<Shift-Left>', self._bigDecrementValue)
+            self._widget.bind('<Shift-Right>', self._bigIncrementValue)
+            self._widget.bind('<Home>', self._goToMin)
+            self._widget.bind('<End>', self._goToMax)
 	else:
 	else:
-	    # 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)
-
-        
+            createSlider(interior)
+            self._widget['command'] = self._firstScaleCommand
+            
 	# Check keywords and initialise options.
 	# Check keywords and initialise options.
 	self.initialiseoptions(SliderWidget)
 	self.initialiseoptions(SliderWidget)
 
 
@@ -252,6 +263,8 @@ class SliderWidget(Pmw.MegaWidget):
             if self['style'] == VALUATOR_FULL:
             if self['style'] == VALUATOR_FULL:
                 self['relief'] = FLAT
                 self['relief'] = FLAT
 
 
+        self.updateIndicator(self['value'])
+
     def destroy(self):
     def destroy(self):
 	if (self['style'] == VALUATOR_MINI) and self._isPosted:
 	if (self['style'] == VALUATOR_MINI) and self._isPosted:
             Pmw.popgrab(self._popup)
             Pmw.popgrab(self._popup)
@@ -280,58 +293,67 @@ class SliderWidget(Pmw.MegaWidget):
         return self.value
         return self.value
 
 
     def updateIndicator(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)
+        if self['style'] == VALUATOR_MINI:
+            # 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._widget.move('marker', dx, 0)
+        else:
+            # Update scale's variable, which update scale without
+            # Calling scale's command
+            self._widgetVar.set(value)
     
     
     #======================================================================
     #======================================================================
 
 
     # Private methods for slider.
     # Private methods for slider.
 
 
-    def _postCanvas(self, event = None):
+    def _postSlider(self, event = None):
         self._isPosted = 1
         self._isPosted = 1
         self._fUpdate = 0
         self._fUpdate = 0
-        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.interior()['relief'] = SUNKEN
         self.update_idletasks()
         self.update_idletasks()
-
-        x = self._arrowBtn.winfo_rootx() + self._arrowBtn.winfo_width()/2.0
+        # Position popup so that marker is immediately below center of
+        # Arrow button
+        # Find screen space position of bottom/center of arrow button
+        x = (self._arrowBtn.winfo_rootx() + self._arrowBtn.winfo_width()/2.0 -
+             string.atoi(self.interior()['bd']))
         y = self._arrowBtn.winfo_rooty() + self._arrowBtn.winfo_height()
         y = self._arrowBtn.winfo_rooty() + self._arrowBtn.winfo_height()
+        # Popup border width
+        bd = string.atoi(self._popup['bd'])
+        # Get width of label
         minW = self._minLabel.winfo_width()
         minW = self._minLabel.winfo_width()
-        cw =  self._canvas.winfo_width()
-        maxW = self._maxLabel.winfo_width()
-        #pw = minW + cw + maxW
-        pw = maxW + cw/2.0
-        ch =  self._canvas.winfo_height()
+        # Width of canvas to adjust for
+        cw = (self._getMarkerX() - self.left ) + self.xPad
+        popupOffset = bd + minW + cw
+        ch =  self._widget.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._arrowBtn.winfo_rooty() - ch
             y = self._arrowBtn.winfo_rooty() - ch
-
-        Pmw.setgeometryanddeiconify(self._popup, '+%d+%d' % (x - pw, y))
+        # Popup window
+        Pmw.setgeometryanddeiconify(self._popup, '+%d+%d' % (x-popupOffset, 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 slider, to make keyboard navigation
         # easier.
         # easier.
-        Pmw.pushgrab(self._popup, 1, self._unpostCanvas)
-        self._canvas.focus_set()
+        Pmw.pushgrab(self._popup, 1, self._unpostSlider)
+        self._widget.focus_set()
 
 
         # 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 slider, unless the mouse enters the dropdown slider.
         self._fUpdate = 0
         self._fUpdate = 0
         self._fUnpost = 0
         self._fUnpost = 0
         self._firstPress = 1
         self._firstPress = 1
         self._fPressInsde = 0
         self._fPressInsde = 0
 
 
     def _updateValue(self,event):
     def _updateValue(self,event):
-        mouseX = self._canvas.canvasx(
-            event.x_root - self._canvas.winfo_rootx())
+        mouseX = self._widget.canvasx(
+            event.x_root - self._widget.winfo_rootx())
         if mouseX < self.left:
         if mouseX < self.left:
             mouseX = self.left
             mouseX = self.left
         if mouseX > self.right:
         if mouseX > self.right:
@@ -341,16 +363,13 @@ class SliderWidget(Pmw.MegaWidget):
         newVal = sf * (self['max'] - self['min']) + self['min']
         newVal = sf * (self['max'] - self['min']) + self['min']
         self.set(newVal)
         self.set(newVal)
 
 
-    def _sliderBtnPress(self, event):
+    def _widgetBtnPress(self, event):
         # Check behavior for this button press
         # 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
+        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()))
         # Set flags based upon result
         # Set flags based upon result
         if fInside:
         if fInside:
             self._fPressInside = 1
             self._fPressInside = 1
@@ -360,20 +379,20 @@ class SliderWidget(Pmw.MegaWidget):
             self._fPressInside = 0
             self._fPressInside = 0
             self._fUpdate = 0
             self._fUpdate = 0
             
             
-    def _sliderMove(self, event):
+    def _widgetMove(self, event):
         if self._firstPress and not self._fUpdate:
         if self._firstPress and not self._fUpdate:
-            canvasY = self._canvas.canvasy(
-                event.y_root - self._canvas.winfo_rooty())
+            canvasY = self._widget.canvasy(
+                event.y_root - self._widget.winfo_rooty())
             if canvasY > 0:
             if canvasY > 0:
                 self._fUpdate = 1
                 self._fUpdate = 1
                 self._unpostOnNextRelease()
                 self._unpostOnNextRelease()
         elif self._fUpdate:
         elif self._fUpdate:
             self._updateValue(event)
             self._updateValue(event)
 
 
-    def _sliderBtnRelease(self, event):
+    def _widgetBtnRelease(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._unpostSlider()
         # Otherwise, continue
         # Otherwise, continue
         self._fUpdate = 0
         self._fUpdate = 0
         self._firstPress = 0
         self._firstPress = 0
@@ -382,7 +401,7 @@ class SliderWidget(Pmw.MegaWidget):
     def _unpostOnNextRelease(self, event = None):
     def _unpostOnNextRelease(self, event = None):
 	self._fUnpost = 1
 	self._fUnpost = 1
 
 
-    def _unpostCanvas(self, event=None):
+    def _unpostSlider(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
             # example, by repeatedly pressing the space key to post
             # example, by repeatedly pressing the space key to post
@@ -401,8 +420,8 @@ class SliderWidget(Pmw.MegaWidget):
 
 
 	self._isPosted = 0
 	self._isPosted = 0
 
 
-        if self['style'] == VALUATOR_MINI:
-            self.interior()['relief'] = RAISED
+        # Raise up arrow button
+        self.interior()['relief'] = RAISED
 
 
     def _incrementValue(self, event):
     def _incrementValue(self, event):
         self.set(self.value + self.increment)
         self.set(self.value + self.increment)
@@ -417,13 +436,24 @@ class SliderWidget(Pmw.MegaWidget):
     def _goToMax(self, event):
     def _goToMax(self, event):
         self.set(self['max'])
         self.set(self['max'])
 
 
+    def _firstScaleCommand(self, val):
+        """ Hack to avoid calling command on instantiation of Scale """
+        self._widget['command'] = self._scaleCommand
+
+    def _scaleCommand(self, val):
+        self.set(string.atof(val))
+
     # Methods to modify floater characteristics    
     # Methods to modify floater characteristics    
     def setMin(self):
     def setMin(self):
         self._minLabel['text'] = self.formatString % self['min']
         self._minLabel['text'] = self.formatString % self['min']
+        if self['style'] == VALUATOR_FULL:
+            self._widget['from_'] = self['min']
         self.updateIndicator(self.value)
         self.updateIndicator(self.value)
 
 
     def setMax(self):
     def setMax(self):
         self._maxLabel['text'] = self.formatString % self['max']
         self._maxLabel['text'] = self.formatString % self['max']
+        if self['style'] == VALUATOR_FULL:
+            self._widget['to'] = self['max']
         self.updateIndicator(self.value)
         self.updateIndicator(self.value)
 
 
     def setNumDigits(self):
     def setNumDigits(self):
@@ -433,18 +463,9 @@ class SliderWidget(Pmw.MegaWidget):
         self.updateIndicator(self.value)
         self.updateIndicator(self.value)
         self.increment = pow(10, -self['numDigits'])
         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._widget.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]
 
 
@@ -455,11 +476,11 @@ class SliderWidget(Pmw.MegaWidget):
         self.interior()['borderwidth'] = self['borderwidth']
         self.interior()['borderwidth'] = self['borderwidth']
 
 
     def setBackground(self):
     def setBackground(self):
-        self._canvas['background'] = self['background']
+        self._widget['background'] = self['background']
 
 
     def highlightWidget(self, event):
     def highlightWidget(self, event):
         self._arrowBtn.itemconfigure('arrow', fill = 'black')
         self._arrowBtn.itemconfigure('arrow', fill = 'black')
 
 
     def restoreWidget(self, event):
     def restoreWidget(self, event):
-        self._arrowBtn.itemconfigure('arrow', fill = '#A0A0A0')
+        self._arrowBtn.itemconfigure('arrow', fill = 'grey50')
 
 

+ 53 - 35
direct/src/tkwidgets/Valuator.py

@@ -1,8 +1,10 @@
 from PandaObject import *
 from PandaObject import *
 from Tkinter import *
 from Tkinter import *
 import Pmw
 import Pmw
+import tkColorChooser
 import WidgetPropertiesDialog
 import WidgetPropertiesDialog
 import string
 import string
+from DirectUtil import getTkColorString
 
 
 VALUATOR_MINI = 'mini'
 VALUATOR_MINI = 'mini'
 VALUATOR_FULL = 'full'
 VALUATOR_FULL = 'full'
@@ -103,7 +105,7 @@ class Valuator(Pmw.MegaWidget):
                     '<ButtonPress-3>', self._popupValuatorMenu)
                     '<ButtonPress-3>', self._popupValuatorMenu)
             self._entry.bind(
             self._entry.bind(
                 '<ButtonPress-3>', self._popupValuatorMenu)
                 '<ButtonPress-3>', self._popupValuatorMenu)
-            self._valuator._canvas.bind(
+            self._valuator._widget.bind(
                 '<ButtonPress-3>', self._popupValuatorMenu)
                 '<ButtonPress-3>', self._popupValuatorMenu)
 
 
             # A Dictionary of dictionaries for the popup property dialog
             # A Dictionary of dictionaries for the popup property dialog
@@ -265,11 +267,11 @@ class Valuator(Pmw.MegaWidget):
         if self['state'] == NORMAL:
         if self['state'] == NORMAL:
             self._entry['state'] = NORMAL
             self._entry['state'] = NORMAL
             self._entry['background'] = self._entryBackground
             self._entry['background'] = self._entryBackground
-            self._valuator._canvas['state'] = NORMAL
+            self._valuator._widget['state'] = NORMAL
         elif self['state'] == DISABLED:
         elif self['state'] == DISABLED:
             self._entry['background'] = 'grey75'
             self._entry['background'] = 'grey75'
             self._entry['state'] = DISABLED
             self._entry['state'] = DISABLED
-            self._valuator._canvas['state'] = DISABLED
+            self._valuator._widget['state'] = DISABLED
 
 
     def setLabel(self):
     def setLabel(self):
         """ Update label's text """
         """ Update label's text """
@@ -295,7 +297,7 @@ class Valuator(Pmw.MegaWidget):
         Reset valuator to resetValue
         Reset valuator to resetValue
         """
         """
         # If not over any canvas item
         # If not over any canvas item
-        #if not self._canvas.find_withtag(CURRENT):
+        #if not self._widget.find_withtag(CURRENT):
         self.reset()
         self.reset()
         
         
     # Popup dialog to adjust widget properties
     # Popup dialog to adjust widget properties
@@ -582,20 +584,30 @@ class ValuatorGroupPanel(Pmw.MegaToplevel):
 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)
+def rgbPanel(nodePath, callback = None, style = 'mini'):
+    def onRelease(r,g,b,a, nodePath = nodePath):
+        messenger.send('RGBPanel_setColor', [nodePath, r,g,b,a])
+
+    def popupColorPicker():
+        # Can pass in current color with: color = (255, 0, 0)
+        color = tkColorChooser.askcolor(
+            parent = vgp.interior(),
+            # Initialize it to current color
+            initialcolor = tuple(vgp.get()[:3]))[0]
+        if color:
+            vgp.set((color[0], color[1], color[2], vgp.getAt(3)))
+
+    def printToLog():
+        c=nodePath.getColor()
+        print "Vec4(%.3f, %.3f, %.3f, %.3f)"%(c[0], c[1], c[2], c[3])
+
     # Check init color
     # Check init color
     if nodePath.hasColor():
     if nodePath.hasColor():
         initColor = nodePath.getColor() * 255.0
         initColor = nodePath.getColor() * 255.0
     else:
     else:
         initColor = Vec4(255)
         initColor = Vec4(255)
     # Create entry scale group
     # Create entry scale group
-    esg = ValuatorGroupPanel(title = 'RGBA Panel: ' + nodePath.getName(),
+    vgp = ValuatorGroupPanel(title = 'RGBA Panel: ' + nodePath.getName(),
                              dim = 4,
                              dim = 4,
                              labels = ['R','G','B','A'],
                              labels = ['R','G','B','A'],
                              value = [int(initColor[0]),
                              value = [int(initColor[0]),
@@ -608,44 +620,50 @@ def rgbPanel(nodePath, callback = None, style = 'full'):
                              valuator_max = 255,
                              valuator_max = 255,
                              valuator_resolution = 1,
                              valuator_resolution = 1,
                              # Destroy not withdraw panel on dismiss
                              # Destroy not withdraw panel on dismiss
-                             fDestroy = 1,
-                             command = setNodePathColor)
+                             fDestroy = 1)
     # Update menu button
     # Update menu button
-    esg.component('menubar').component('Valuator Group-button')['text'] = (
+    vgp.component('menubar').component('Valuator Group-button')['text'] = (
         'RGBA Panel')
         'RGBA Panel')
+
+    # Set callback
+    vgp['postCallback'] = onRelease
+    
+    # Add a print button which will also serve as a color tile
+    pButton = Button(vgp.interior(), text = 'Print to Log',
+                     bg = getTkColorString(initColor),
+                     command = printToLog)
+    pButton.pack(expand = 1, fill = BOTH)
+    
     # Update menu
     # Update menu
-    menu = esg.component('menubar').component('Valuator Group-menu')
+    menu = vgp.component('menubar').component('Valuator Group-menu')
     # Some helper functions
     # Some helper functions
     # Clear color
     # Clear color
     menu.insert_command(index = 1, label = 'Clear Color',
     menu.insert_command(index = 1, label = 'Clear Color',
-                        command = lambda np = nodePath: np.clearColor())
+                        command = lambda: nodePath.clearColor())
     # Set Clear Transparency
     # Set Clear Transparency
     menu.insert_command(index = 2, label = 'Set Transparency',
     menu.insert_command(index = 2, label = 'Set Transparency',
-                        command = lambda np = nodePath: np.setTransparency(1))
+                        command = lambda: nodePath.setTransparency(1))
     menu.insert_command(
     menu.insert_command(
         index = 3, label = 'Clear Transparency',
         index = 3, label = 'Clear Transparency',
-        command = lambda np = nodePath: np.clearTransparency())
+        command = lambda: nodePath.clearTransparency())
+
 
 
     # System color picker
     # 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',
     menu.insert_command(index = 4, label = 'Popup Color Picker',
                         command = popupColorPicker)
                         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',
     menu.insert_command(index = 5, label = 'Print to log',
                         command = printToLog)
                         command = printToLog)
+
+    def setNodePathColor(color):
+        nodePath.setColor(color[0]/255.0, color[1]/255.0,
+                          color[2]/255.0, color[3]/255.0)
+        # Update color chip button
+        pButton['bg'] = getTkColorString(color)
+        # Execute callback to pass along color info
+        if callback:
+            callback(color)
+    vgp['command'] = setNodePathColor
     
     
-    # Set callback
-    def onRelease(r,g,b,a, nodePath = nodePath):
-        messenger.send('RGBPanel_setColor', [nodePath, r,g,b,a])
-    esg['postCallback'] = onRelease
-    return esg
+    return vgp