*** empty log message ***

This commit is contained in:
Mark Mine 2002-02-22 02:38:13 +00:00
parent 7a9b7ca5d4
commit e3df94a036
6 changed files with 273 additions and 217 deletions

View File

@ -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', self.mouseEvents = ['mouse1', 'shift-mouse1', 'control-mouse1',
'mouse2', 'mouse2-up', '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')

View File

@ -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))

View File

@ -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._widget.tag_bind('dial', '<ButtonPress-1>', self.mouseDown)
self._canvas.tag_bind('dial', '<B1-Motion>', self.mouseMotion) self._widget.tag_bind('dial', '<B1-Motion>', self.mouseMotion)
self._canvas.tag_bind('dial', '<Shift-B1-Motion>', self._widget.tag_bind('dial', '<Shift-B1-Motion>',
self.shiftMouseMotion) self.shiftMouseMotion)
self._canvas.tag_bind('dial', '<ButtonRelease-1>', self.mouseUp) self._widget.tag_bind('dial', '<ButtonRelease-1>', self.mouseUp)
self._canvas.tag_bind('knob', '<ButtonPress-1>', self.knobMouseDown) self._widget.tag_bind('knob', '<ButtonPress-1>', self.knobMouseDown)
self._canvas.tag_bind('knob', '<B1-Motion>', self.updateDialSF) self._widget.tag_bind('knob', '<B1-Motion>', self.updateDialSF)
self._canvas.tag_bind('knob', '<ButtonRelease-1>', self.knobMouseUp) self._widget.tag_bind('knob', '<ButtonRelease-1>', self.knobMouseUp)
self._canvas.tag_bind('knob', '<Enter>', self.highlightKnob) self._widget.tag_bind('knob', '<Enter>', self.highlightKnob)
self._canvas.tag_bind('knob', '<Leave>', self.restoreKnob) 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) x = self._widget.canvasx(event.x)
y = self._canvas.canvasy(event.y) 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) x = self._widget.canvasx(event.x)
y = self._canvas.canvasy(event.y) 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):

View File

@ -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._widget.bind('<ButtonPress-1>', self.mouseDown)
self._canvas.bind('<B1-Motion>', self.updateFloaterSF) self._widget.bind('<B1-Motion>', self.updateFloaterSF)
self._canvas.bind('<ButtonRelease-1>', self.mouseUp) self._widget.bind('<ButtonRelease-1>', self.mouseUp)
self._canvas.bind('<Enter>', self.highlightWidget) self._widget.bind('<Enter>', self.highlightWidget)
self._canvas.bind('<Leave>', self.restoreWidget) 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) x = self._widget.canvasx(event.x)
y = self._canvas.canvasy(event.y) 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):

View File

@ -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._fUnpost = 0
self._fPressInsde = 0
self._isPosted = 0 self._isPosted = 0
if self['style'] == VALUATOR_MINI: self._fUnpost = 0
self._fUpdate = 0
self._firstPress = 1 self._firstPress = 1
else: self._fPressInsde = 0
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 top = -5
self.bottom = bottom = top + height bottom = top + height
def _createSlider(parent): def createSlider(parent):
# Create the canvas inside the dropdown window. # 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 # Slider widget
self._canvas = self.createcomponent( if self['style'] == VALUATOR_FULL:
'canvas', (), None, # 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,), Canvas, (parent,),
width = canvasWidth, width = sliderWidth,
height = height, height = height,
bd = 2, bd = 2,
highlightthickness = 0, highlightthickness = 0,
scrollregion = (left - xPad, top, right + xPad, bottom)) scrollregion = (left - xPad, top, right + xPad, bottom))
self._canvas.pack(side = LEFT, expand=1, fill=X) # Interaction marker
if self['style'] == VALUATOR_FULL: xShift = 1
self._canvas.configure(relief = SUNKEN, bd = 2) # 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. # Create the arrow button to invoke slider
self._arrowBtn = self.createcomponent('arrowbutton', self._arrowBtn = self.createcomponent(
'arrowbutton',
(), None, (), None,
Canvas, (interior,), borderwidth = 0, Canvas, (interior,), borderwidth = 0,
relief = FLAT, width = 14, height = 14) 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')
self._arrowBtn.create_line(-5, 5, 5, 5,
fill = 'grey50',
tags = 'arrow') tags = 'arrow')
self._arrowRelief = self._arrowBtn.cget('relief')
# Create the dropdown window. # Create the dropdown window.
self._popup = self.createcomponent( self._popup = self.createcomponent(
'popup', 'popup',
@ -219,30 +227,33 @@ 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('<Escape>', self._unpostSlider)
self._popup.bind('<ButtonRelease-1>', self._sliderBtnRelease) self._popup.bind('<ButtonRelease-1>', self._widgetBtnRelease)
self._popup.bind('<ButtonPress-1>', self._sliderBtnPress) self._popup.bind('<ButtonPress-1>', self._widgetBtnPress)
self._popup.bind('<Motion>', self._sliderMove) self._popup.bind('<Motion>', self._widgetMove)
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)
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:
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):
if self['style'] == VALUATOR_MINI:
# Get current marker position # Get current marker position
markerX = self._getMarkerX() markerX = self._getMarkerX()
percentX = (value - self['min'])/(self['max'] - self['min']) percentX = (value - self['min'])/(self['max'] - self['min'])
newX = percentX * (self.right - self.left) + self.left newX = percentX * (self.right - self.left) + self.left
dx = newX - markerX dx = newX - markerX
self._canvas.move('slider', dx, 0) 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()
# Position popup so that marker is immediately below center of
x = self._arrowBtn.winfo_rootx() + self._arrowBtn.winfo_width()/2.0 # 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() # Width of canvas to adjust for
maxW = self._maxLabel.winfo_width() cw = (self._getMarkerX() - self.left ) + self.xPad
#pw = minW + cw + maxW popupOffset = bd + minW + cw
pw = maxW + cw/2.0 ch = self._widget.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._arrowBtn.winfo_rooty() - ch y = self._arrowBtn.winfo_rooty() - ch
# Popup window
Pmw.setgeometryanddeiconify(self._popup, '+%d+%d' % (x - pw, y)) 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) Pmw.pushgrab(self._popup, 1, self._unpostSlider)
self._canvas.focus_set() 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( mouseX = self._widget.canvasx(
event.x_root - self._canvas.winfo_rootx()) 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 widget = self._popup
xPos = event.x_root - widget.winfo_rootx() xPos = event.x_root - widget.winfo_rootx()
yPos = event.y_root - widget.winfo_rooty() yPos = event.y_root - widget.winfo_rooty()
fInside = ((xPos > 0) and (xPos < widget.winfo_width()) and fInside = ((xPos > 0) and (xPos < widget.winfo_width()) and
(yPos > 0) and (yPos < widget.winfo_height())) (yPos > 0) and (yPos < widget.winfo_height()))
else:
fInside = 1
# 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( canvasY = self._widget.canvasy(
event.y_root - self._canvas.winfo_rooty()) 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,7 +420,7 @@ class SliderWidget(Pmw.MegaWidget):
self._isPosted = 0 self._isPosted = 0
if self['style'] == VALUATOR_MINI: # Raise up arrow button
self.interior()['relief'] = RAISED self.interior()['relief'] = RAISED
def _incrementValue(self, event): def _incrementValue(self, event):
@ -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')

View File

@ -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 rgbPanel(nodePath, callback = None, style = 'mini'):
def setNodePathColor(color, np = nodePath, cb = callback): def onRelease(r,g,b,a, nodePath = nodePath):
np.setColor(color[0]/255.0, color[1]/255.0, messenger.send('RGBPanel_setColor', [nodePath, r,g,b,a])
color[2]/255.0, color[3]/255.0)
# Execute callback to pass along color info def popupColorPicker():
if cb: # Can pass in current color with: color = (255, 0, 0)
cb(color) 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, fDestroy = 1)
command = setNodePathColor)
# 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)
# Set callback def setNodePathColor(color):
def onRelease(r,g,b,a, nodePath = nodePath): nodePath.setColor(color[0]/255.0, color[1]/255.0,
messenger.send('RGBPanel_setColor', [nodePath, r,g,b,a]) color[2]/255.0, color[3]/255.0)
esg['postCallback'] = onRelease # Update color chip button
return esg pButton['bg'] = getTkColorString(color)
# Execute callback to pass along color info
if callback:
callback(color)
vgp['command'] = setNodePathColor
return vgp