diff --git a/direct/src/directtools/DirectSession.py b/direct/src/directtools/DirectSession.py index 3e7376b87d..6f36eedeb2 100644 --- a/direct/src/directtools/DirectSession.py +++ b/direct/src/directtools/DirectSession.py @@ -160,8 +160,10 @@ class DirectSession(PandaObject): '[', '{', ']', '}', 'shift-a', 'b', 'l', 'shift-l', 'o', 'p', 'r', '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'] if base.wantTk: @@ -324,11 +326,13 @@ class DirectSession(PandaObject): def inputHandler(self, 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') elif input == 'mouse1-up': 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') elif input == 'mouse2-up': messenger.send('DIRECT_mouse2Up') diff --git a/direct/src/directtools/DirectUtil.py b/direct/src/directtools/DirectUtil.py index bcb7581c90..4d6167adc0 100644 --- a/direct/src/directtools/DirectUtil.py +++ b/direct/src/directtools/DirectUtil.py @@ -1,5 +1,18 @@ 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 ## def setBackgroundColor(r,g,b): base.win.getGsg().setColorClearValue(VBase4(r, g, b, 1.0)) diff --git a/direct/src/tkwidgets/Dial.py b/direct/src/tkwidgets/Dial.py index aa5377a8a0..9e3ec7aeb7 100644 --- a/direct/src/tkwidgets/Dial.py +++ b/direct/src/tkwidgets/Dial.py @@ -49,7 +49,7 @@ class Dial(Valuator): style = self['style'], command = self.setEntry, value = self['value']) - self._valuator._canvas.bind('', self.mouseReset) + self._valuator._widget.bind('', self.mouseReset) def packValuator(self): if self['style'] == VALUATOR_FULL: @@ -209,41 +209,41 @@ class DialWidget(Pmw.MegaWidget): inner_radius = max(3,radius * INNER_SF) # The canvas - self._canvas = self.createcomponent('canvas', (), None, + self._widget = self.createcomponent('canvas', (), None, Canvas, (interior,), width = size, height = size, background = self['background'], highlightthickness = 0, scrollregion = (-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) - self._canvas.create_oval(-radius, -radius, radius, radius, + self._widget.create_oval(-radius, -radius, radius, radius, outline = '', tags = ('dial',)) # 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')) # The central knob - self._canvas.create_oval(-inner_radius, -inner_radius, + self._widget.create_oval(-inner_radius, -inner_radius, inner_radius, inner_radius, - fill = '#A0A0A0', + fill = 'grey50', tags = ('knob',)) # Add event bindings - self._canvas.tag_bind('dial', '', self.mouseDown) - self._canvas.tag_bind('dial', '', self.mouseMotion) - self._canvas.tag_bind('dial', '', + self._widget.tag_bind('dial', '', self.mouseDown) + self._widget.tag_bind('dial', '', self.mouseMotion) + self._widget.tag_bind('dial', '', self.shiftMouseMotion) - self._canvas.tag_bind('dial', '', self.mouseUp) - self._canvas.tag_bind('knob', '', self.knobMouseDown) - self._canvas.tag_bind('knob', '', self.updateDialSF) - self._canvas.tag_bind('knob', '', self.knobMouseUp) - self._canvas.tag_bind('knob', '', self.highlightKnob) - self._canvas.tag_bind('knob', '', self.restoreKnob) + self._widget.tag_bind('dial', '', self.mouseUp) + self._widget.tag_bind('knob', '', self.knobMouseDown) + self._widget.tag_bind('knob', '', self.updateDialSF) + self._widget.tag_bind('knob', '', self.knobMouseUp) + self._widget.tag_bind('knob', '', self.highlightKnob) + self._widget.tag_bind('knob', '', self.restoreKnob) # Make sure input variables processed self.initialiseoptions(DialWidget) @@ -289,8 +289,8 @@ class DialWidget(Pmw.MegaWidget): self.computeValueFromAngle(dialAngle) 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) # Snap to grid # Convert to dial coords to do snapping @@ -328,7 +328,7 @@ class DialWidget(Pmw.MegaWidget): endx = math.cos(rawAngle) * self.radius endy = math.sin(rawAngle) * self.radius # 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) # Knob velocity controller @@ -347,8 +347,8 @@ class DialWidget(Pmw.MegaWidget): return Task.cont 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) if offset == 0: return 0 @@ -377,10 +377,10 @@ class DialWidget(Pmw.MegaWidget): self.interior()['borderwidth'] = self['borderwidth'] def setBackground(self): - self._canvas['background'] = self['background'] + self._widget['background'] = self['background'] def setNumSegments(self): - self._canvas.delete('ticks') + self._widget.delete('ticks') # Based upon input snap angle, how many ticks numSegments = self['numSegments'] # Compute snapAngle (radians) @@ -400,14 +400,14 @@ class DialWidget(Pmw.MegaWidget): sf = 0.8 endx = startx * sf endy = starty * sf - self._canvas.create_line(startx, starty, endx, endy, + self._widget.create_line(startx, starty, endx, endy, tags = ('ticks','dial')) def highlightKnob(self, event): - self._canvas.itemconfigure('knob', fill = 'black') + self._widget.itemconfigure('knob', fill = 'black') def restoreKnob(self, event): - self._canvas.itemconfigure('knob', fill = '#A0A0A0') + self._widget.itemconfigure('knob', fill = 'grey50') # To call user callbacks def _onButtonPress(self, *args): diff --git a/direct/src/tkwidgets/Floater.py b/direct/src/tkwidgets/Floater.py index b2c55b45fc..7644ada2f3 100644 --- a/direct/src/tkwidgets/Floater.py +++ b/direct/src/tkwidgets/Floater.py @@ -34,7 +34,7 @@ class Floater(Valuator): (self.interior(),), command = self.setEntry, value = self['value']) - self._valuator._canvas.bind('', self.mouseReset) + self._valuator._widget.bind('', self.mouseReset) def packValuator(self): # Position components @@ -85,7 +85,7 @@ class FloaterWidget(Pmw.MegaWidget): # The canvas width = self['width'] height = self['height'] - self._canvas = self.createcomponent('canvas', (), None, + self._widget = self.createcomponent('canvas', (), None, Canvas, (interior,), width = width, height = height, @@ -95,24 +95,24 @@ class FloaterWidget(Pmw.MegaWidget): -height/2.0, width/2.0, height/2.0)) - self._canvas.pack(expand = 1, fill = BOTH) + self._widget.pack(expand = 1, fill = BOTH) # 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, - fill = '#A0A0A0', + fill = 'grey50', 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, - fill = '#A0A0A0', + fill = 'grey50', tags = ('floater',)) # Add event bindings - self._canvas.bind('', self.mouseDown) - self._canvas.bind('', self.updateFloaterSF) - self._canvas.bind('', self.mouseUp) - self._canvas.bind('', self.highlightWidget) - self._canvas.bind('', self.restoreWidget) + self._widget.bind('', self.mouseDown) + self._widget.bind('', self.updateFloaterSF) + self._widget.bind('', self.mouseUp) + self._widget.bind('', self.highlightWidget) + self._widget.bind('', self.restoreWidget) # Make sure input variables processed self.initialiseoptions(FloaterWidget) @@ -167,8 +167,8 @@ class FloaterWidget(Pmw.MegaWidget): """ 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) if offset == 0: return 0 @@ -203,13 +203,13 @@ class FloaterWidget(Pmw.MegaWidget): self.interior()['borderwidth'] = self['borderwidth'] def setBackground(self): - self._canvas['background'] = self['background'] + self._widget['background'] = self['background'] def highlightWidget(self, event): - self._canvas.itemconfigure('floater', fill = 'black') + self._widget.itemconfigure('floater', fill = 'black') def restoreWidget(self, event): - self._canvas.itemconfigure('floater', fill = '#A0A0A0') + self._widget.itemconfigure('floater', fill = 'grey50') class FloaterGroup(Pmw.MegaToplevel): diff --git a/direct/src/tkwidgets/Slider.py b/direct/src/tkwidgets/Slider.py index 54496809f6..87d1b039ca 100644 --- a/direct/src/tkwidgets/Slider.py +++ b/direct/src/tkwidgets/Slider.py @@ -27,7 +27,7 @@ class Slider(Valuator): ) self.defineoptions(kw, optiondefs) 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']['help'] = 'Minimum allowable value.' self.propertyDict['max']['fNone'] = 0 @@ -44,7 +44,7 @@ class Slider(Valuator): style = self['style'], command = self.setEntry, value = self['value']) - self._valuator._canvas.bind('', self.mouseReset) + self._valuator._widget.bind('', self.mouseReset) # Add popup bindings to slider widget try: @@ -89,12 +89,12 @@ class SliderWidget(Pmw.MegaWidget): INITOPT = Pmw.INITOPT optiondefs = ( # Appearance + ('style', VALUATOR_MINI, INITOPT), ('relief', RAISED, self.setRelief), ('borderwidth', 2, self.setBorderwidth), ('background', 'SystemButtonFace', self.setBackground), ('fliparrow', 0, INITOPT), # Behavior - ('style', VALUATOR_MINI, INITOPT), # Bounds ('min', 0.0, self.setMin), ('max', 100.0, self.setMax), @@ -125,91 +125,99 @@ class SliderWidget(Pmw.MegaWidget): self.increment = 0.01 # Interaction flags - self._fUpdate = 0 - self._fUnpost = 0 - self._fPressInsde = 0 self._isPosted = 0 - if self['style'] == VALUATOR_MINI: - self._firstPress = 1 - else: - self._firstPress = 0 + self._fUnpost = 0 + self._fUpdate = 0 + self._firstPress = 1 + self._fPressInsde = 0 # Slider dimensions width = 100 self.xPad = xPad = 10 - canvasWidth = width + 2 * xPad + sliderWidth = width + 2 * xPad height = 20 self.left = left = -(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 self._minLabel = Label(parent, text = self['min'], width = 8, - anchor = E) + anchor = W) 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: - 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 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('', self._decrementValue) - self._canvas.bind('', self._incrementValue) - self._canvas.bind('', self._bigDecrementValue) - self._canvas.bind('', self._bigIncrementValue) - self._canvas.bind('', self._goToMin) - self._canvas.bind('', self._goToMax) - - # Create slider 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.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') - self._arrowRelief = self._arrowBtn.cget('relief') - + self._arrowBtn.create_line(-5, 5, 5, 5, + fill = 'grey50', + tags = 'arrow') # Create the dropdown window. self._popup = self.createcomponent( 'popup', @@ -219,31 +227,34 @@ class SliderWidget(Pmw.MegaWidget): self._popup.withdraw() self._popup.overrideredirect(1) - _createSlider(self._popup) + # Create popup slider + createSlider(self._popup) # Bind events to the arrow button. - self._arrowBtn.bind('<1>', self._postCanvas) + self._arrowBtn.bind('<1>', self._postSlider) self._arrowBtn.bind('', self.highlightWidget) self._arrowBtn.bind('', 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 slider is # displayed. - self._arrowBtn.bind('', self._unpostCanvas) + self._arrowBtn.bind('', self._unpostSlider) # Bind events to the dropdown window. - self._popup.bind('', self._unpostCanvas) - self._popup.bind('', self._sliderBtnRelease) - self._popup.bind('', self._sliderBtnPress) - self._popup.bind('', self._sliderMove) + self._popup.bind('', self._unpostSlider) + self._popup.bind('', self._widgetBtnRelease) + self._popup.bind('', self._widgetBtnPress) + self._popup.bind('', self._widgetMove) + + self._widget.bind('', self._decrementValue) + self._widget.bind('', self._incrementValue) + self._widget.bind('', self._bigDecrementValue) + self._widget.bind('', self._bigIncrementValue) + self._widget.bind('', self._goToMin) + self._widget.bind('', self._goToMax) else: - # Create the slider directly in the interior - _createSlider(interior) - self._canvas.bind('', self._sliderBtnRelease) - self._canvas.bind('', self._sliderBtnPress) - self._canvas.bind('', self._sliderMove) - self._canvas.bind('', self._changeConfiguration) - - + createSlider(interior) + self._widget['command'] = self._firstScaleCommand + # Check keywords and initialise options. self.initialiseoptions(SliderWidget) @@ -252,6 +263,8 @@ class SliderWidget(Pmw.MegaWidget): if self['style'] == VALUATOR_FULL: self['relief'] = FLAT + self.updateIndicator(self['value']) + def destroy(self): if (self['style'] == VALUATOR_MINI) and self._isPosted: Pmw.popgrab(self._popup) @@ -280,58 +293,67 @@ class SliderWidget(Pmw.MegaWidget): 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) + 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. - def _postCanvas(self, event = None): + def _postSlider(self, event = None): self._isPosted = 1 self._fUpdate = 0 - if self['style'] == VALUATOR_MINI: - self.interior()['relief'] = SUNKEN # Make sure that the arrow is displayed sunken. + self.interior()['relief'] = SUNKEN 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() + # Popup border width + bd = string.atoi(self._popup['bd']) + # Get width of label 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() # Compensate if too close to edge of screen if y + ch > sh and y > sh / 2: 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 - # set focus to the canvas, to make keyboard navigation + # set focus to the slider, to make keyboard navigation # 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 - # dropdown canvas, unless the mouse enters the dropdown canvas. + # dropdown slider, unless the mouse enters the dropdown slider. self._fUpdate = 0 self._fUnpost = 0 self._firstPress = 1 self._fPressInsde = 0 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: mouseX = self.left if mouseX > self.right: @@ -341,16 +363,13 @@ class SliderWidget(Pmw.MegaWidget): newVal = sf * (self['max'] - self['min']) + self['min'] self.set(newVal) - def _sliderBtnPress(self, event): + def _widgetBtnPress(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 + 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 if fInside: self._fPressInside = 1 @@ -360,20 +379,20 @@ class SliderWidget(Pmw.MegaWidget): self._fPressInside = 0 self._fUpdate = 0 - def _sliderMove(self, event): + def _widgetMove(self, event): 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: self._fUpdate = 1 self._unpostOnNextRelease() elif self._fUpdate: self._updateValue(event) - def _sliderBtnRelease(self, event): + def _widgetBtnRelease(self, event): if (self._fUnpost or (not (self._firstPress or self._fPressInside))): - self._unpostCanvas() + self._unpostSlider() # Otherwise, continue self._fUpdate = 0 self._firstPress = 0 @@ -382,7 +401,7 @@ class SliderWidget(Pmw.MegaWidget): def _unpostOnNextRelease(self, event = None): self._fUnpost = 1 - def _unpostCanvas(self, event=None): + def _unpostSlider(self, event=None): if not self._isPosted: # It is possible to get events on an unposted popup. For # example, by repeatedly pressing the space key to post @@ -401,8 +420,8 @@ class SliderWidget(Pmw.MegaWidget): self._isPosted = 0 - if self['style'] == VALUATOR_MINI: - self.interior()['relief'] = RAISED + # Raise up arrow button + self.interior()['relief'] = RAISED def _incrementValue(self, event): self.set(self.value + self.increment) @@ -417,13 +436,24 @@ class SliderWidget(Pmw.MegaWidget): def _goToMax(self, event): 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 def setMin(self): self._minLabel['text'] = self.formatString % self['min'] + if self['style'] == VALUATOR_FULL: + self._widget['from_'] = self['min'] self.updateIndicator(self.value) def setMax(self): self._maxLabel['text'] = self.formatString % self['max'] + if self['style'] == VALUATOR_FULL: + self._widget['to'] = self['max'] self.updateIndicator(self.value) def setNumDigits(self): @@ -433,18 +463,9 @@ class SliderWidget(Pmw.MegaWidget): 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): # 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 return c[4] @@ -455,11 +476,11 @@ class SliderWidget(Pmw.MegaWidget): self.interior()['borderwidth'] = self['borderwidth'] def setBackground(self): - self._canvas['background'] = self['background'] + self._widget['background'] = self['background'] def highlightWidget(self, event): self._arrowBtn.itemconfigure('arrow', fill = 'black') def restoreWidget(self, event): - self._arrowBtn.itemconfigure('arrow', fill = '#A0A0A0') + self._arrowBtn.itemconfigure('arrow', fill = 'grey50') diff --git a/direct/src/tkwidgets/Valuator.py b/direct/src/tkwidgets/Valuator.py index f732bdab02..9f09557382 100644 --- a/direct/src/tkwidgets/Valuator.py +++ b/direct/src/tkwidgets/Valuator.py @@ -1,8 +1,10 @@ from PandaObject import * from Tkinter import * import Pmw +import tkColorChooser import WidgetPropertiesDialog import string +from DirectUtil import getTkColorString VALUATOR_MINI = 'mini' VALUATOR_FULL = 'full' @@ -103,7 +105,7 @@ class Valuator(Pmw.MegaWidget): '', self._popupValuatorMenu) self._entry.bind( '', self._popupValuatorMenu) - self._valuator._canvas.bind( + self._valuator._widget.bind( '', self._popupValuatorMenu) # A Dictionary of dictionaries for the popup property dialog @@ -265,11 +267,11 @@ class Valuator(Pmw.MegaWidget): if self['state'] == NORMAL: self._entry['state'] = NORMAL self._entry['background'] = self._entryBackground - self._valuator._canvas['state'] = NORMAL + self._valuator._widget['state'] = NORMAL elif self['state'] == DISABLED: self._entry['background'] = 'grey75' self._entry['state'] = DISABLED - self._valuator._canvas['state'] = DISABLED + self._valuator._widget['state'] = DISABLED def setLabel(self): """ Update label's text """ @@ -295,7 +297,7 @@ class Valuator(Pmw.MegaWidget): Reset valuator to resetValue """ # If not over any canvas item - #if not self._canvas.find_withtag(CURRENT): + #if not self._widget.find_withtag(CURRENT): self.reset() # Popup dialog to adjust widget properties @@ -582,20 +584,30 @@ class ValuatorGroupPanel(Pmw.MegaToplevel): 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 if nodePath.hasColor(): initColor = nodePath.getColor() * 255.0 else: initColor = Vec4(255) # Create entry scale group - esg = ValuatorGroupPanel(title = 'RGBA Panel: ' + nodePath.getName(), + vgp = ValuatorGroupPanel(title = 'RGBA Panel: ' + nodePath.getName(), dim = 4, labels = ['R','G','B','A'], value = [int(initColor[0]), @@ -608,44 +620,50 @@ def rgbPanel(nodePath, callback = None, style = 'full'): valuator_max = 255, valuator_resolution = 1, # Destroy not withdraw panel on dismiss - fDestroy = 1, - command = setNodePathColor) + fDestroy = 1) # Update menu button - esg.component('menubar').component('Valuator Group-button')['text'] = ( + vgp.component('menubar').component('Valuator Group-button')['text'] = ( '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 - menu = esg.component('menubar').component('Valuator Group-menu') + menu = vgp.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()) + command = lambda: nodePath.clearColor()) # Set Clear Transparency menu.insert_command(index = 2, label = 'Set Transparency', - command = lambda np = nodePath: np.setTransparency(1)) + command = lambda: nodePath.setTransparency(1)) menu.insert_command( index = 3, label = 'Clear Transparency', - command = lambda np = nodePath: np.clearTransparency()) + command = lambda: nodePath.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 + + 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 + + return vgp