|
|
@@ -1,17 +1,20 @@
|
|
|
+"""
|
|
|
+Dial Class: Velocity style controller for floating point values with
|
|
|
+ a label, entry (validated), and scale
|
|
|
+"""
|
|
|
from Tkinter import *
|
|
|
-from PandaModules import ClockObject
|
|
|
-import WidgetPropertiesDialog
|
|
|
+from Valuator import *
|
|
|
import Pmw
|
|
|
import Task
|
|
|
import math
|
|
|
import string
|
|
|
import operator
|
|
|
+from PandaModules import ClockObject
|
|
|
|
|
|
TWO_PI = 2.0 * math.pi
|
|
|
ONEPOINTFIVE_PI = 1.5 * math.pi
|
|
|
POINTFIVE_PI = 0.5 * math.pi
|
|
|
INNER_SF = 0.2
|
|
|
-MAX_EXP = 5
|
|
|
|
|
|
DIAL_FULL = 'full'
|
|
|
DIAL_MINI = 'mini'
|
|
|
@@ -21,178 +24,113 @@ DIAL_MINI_SIZE = 30
|
|
|
|
|
|
globalClock = ClockObject.getGlobalClock()
|
|
|
|
|
|
-from tkSimpleDialog import Dialog
|
|
|
-
|
|
|
-
|
|
|
|
|
|
-class Dial(Pmw.MegaWidget):
|
|
|
+class Dial(Valuator):
|
|
|
+ """
|
|
|
+ Valuator widget which includes an angle dial and an entry for setting
|
|
|
+ floating point values
|
|
|
+ """
|
|
|
def __init__(self, parent = None, **kw):
|
|
|
- #define the megawidget options
|
|
|
INITOPT = Pmw.INITOPT
|
|
|
optiondefs = (
|
|
|
('style', DIAL_FULL, INITOPT),
|
|
|
- # Widget relief
|
|
|
- ('relief', GROOVE, None),
|
|
|
- # Widget borderwidth
|
|
|
- ('borderwidth', 2, None),
|
|
|
- ('value', 0.0, INITOPT),
|
|
|
- ('resetValue', 0.0, self.setResetValue),
|
|
|
- ('text', 'Dial Widget', self.setLabel),
|
|
|
- ('numDigits', 2, self.setEntryFormat),
|
|
|
- ('command', None, None),
|
|
|
- ('commandData', [], None),
|
|
|
- ('min', None, self.setMin),
|
|
|
- ('max', None, self.setMax),
|
|
|
('base', 0.0, self.setBase),
|
|
|
('delta', 1.0, self.setDelta),
|
|
|
- # Callbacks to execute when updating widget's value
|
|
|
- ('preCallback', None, self.setPreCallbackCmd),
|
|
|
- ('postCallback', None, self.setPostCallbackCmd),
|
|
|
- # Extra data to be passed to callback function, needs to be a list
|
|
|
- ('callbackData', [], self.setCallbackData),
|
|
|
+ ('fSnap', 0, self.setSnap),
|
|
|
+ ('fRollover', 1, self.setRollover),
|
|
|
)
|
|
|
self.defineoptions(kw, optiondefs)
|
|
|
-
|
|
|
- # Initialize the superclass
|
|
|
- Pmw.MegaWidget.__init__(self, parent)
|
|
|
-
|
|
|
- # Override size if style specified by size is not
|
|
|
- if not kw.has_key('dial_size'):
|
|
|
- if self['style'] == DIAL_FULL:
|
|
|
- dialSize = DIAL_FULL_SIZE
|
|
|
- else:
|
|
|
- dialSize = DIAL_MINI_SIZE
|
|
|
- else:
|
|
|
- dialSize = DIAL_FULL_SIZE
|
|
|
-
|
|
|
- # Create the components
|
|
|
- interior = self.interior()
|
|
|
- interior.configure(relief = self['relief'], bd = self['borderwidth'])
|
|
|
-
|
|
|
- # The Dial
|
|
|
- self._dial = self.createcomponent('dial', (), None,
|
|
|
- DialWidget, (interior,),
|
|
|
- size = dialSize,
|
|
|
- command = self.setEntry,
|
|
|
- value = self['value'])
|
|
|
-
|
|
|
- self._dial.addPropertyToDialog(
|
|
|
- 'text',
|
|
|
- {'widget' : self,
|
|
|
- 'type' : 'string',
|
|
|
- 'help' : 'Enter label text for Dial.'
|
|
|
- }
|
|
|
- )
|
|
|
- self._dial.addPropertyToDialog(
|
|
|
- 'numDigits',
|
|
|
- {'widget' : self,
|
|
|
- 'type' : 'integer',
|
|
|
- 'help' : 'Enter number of digits after decimal point.'
|
|
|
- }
|
|
|
- )
|
|
|
-
|
|
|
- # The Label
|
|
|
- self._label = self.createcomponent('label', (), None,
|
|
|
- Label, (interior,),
|
|
|
- text = self['text'],
|
|
|
- font = ('MS Sans Serif',12,'bold'),
|
|
|
- anchor = CENTER)
|
|
|
- self._label.bind('<ButtonPress-3>', self._dial.popupDialMenu)
|
|
|
-
|
|
|
- # The entry
|
|
|
- self._entryVal = StringVar()
|
|
|
- self._entry = self.createcomponent('entry', (), None,
|
|
|
- Entry, (interior,),
|
|
|
- justify = RIGHT,
|
|
|
- width = 12,
|
|
|
- textvariable = self._entryVal)
|
|
|
- self._entry.bind('<Return>', self.validateEntryInput)
|
|
|
- self._entry.bind('<ButtonPress-3>', self._dial.popupDialMenu)
|
|
|
- self._entryBackground = self._entry.cget('background')
|
|
|
+ Valuator.__init__(self, parent)
|
|
|
+ self.initialiseoptions(Dial)
|
|
|
|
|
|
+ def createValuator(self):
|
|
|
+ self._valuator = self.createcomponent(
|
|
|
+ 'valuator',
|
|
|
+ (('dial', 'valuator'),),
|
|
|
+ None,
|
|
|
+ DialWidget,
|
|
|
+ (self.interior(),),
|
|
|
+ style = self['style'],
|
|
|
+ command = self.setEntry,
|
|
|
+ value = self['value'])
|
|
|
+ self._valuator._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
|
|
|
+
|
|
|
+ def packValuator(self):
|
|
|
if self['style'] == DIAL_FULL:
|
|
|
- # Attach dial to entry
|
|
|
- self._dial.grid(rowspan = 2, columnspan = 2, padx = 2, pady = 2)
|
|
|
- self._label.grid(row = 0, col = 2, sticky = EW)
|
|
|
+ self._valuator.grid(rowspan = 2, columnspan = 2,
|
|
|
+ padx = 2, pady = 2)
|
|
|
+ if self._label:
|
|
|
+ self._label.grid(row = 0, col = 2, sticky = EW)
|
|
|
self._entry.grid(row = 1, col = 2, sticky = EW)
|
|
|
- interior.columnconfigure(2, weight = 1)
|
|
|
+ self.interior().columnconfigure(2, weight = 1)
|
|
|
else:
|
|
|
- self._label.grid(row=0,col=0, sticky = EW)
|
|
|
+ if self._label:
|
|
|
+ self._label.grid(row=0,col=0, sticky = EW)
|
|
|
self._entry.grid(row=0,col=1, sticky = EW)
|
|
|
- self._dial.grid(row=0,col=2, padx = 2, pady = 2)
|
|
|
- interior.columnconfigure(0, weight = 1)
|
|
|
-
|
|
|
- # Make sure input variables processed
|
|
|
- self.initialiseoptions(Dial)
|
|
|
-
|
|
|
- def set(self, value, fCommand = 1):
|
|
|
- # Pass fCommand to dial which will return it to self.setEntry
|
|
|
- self._dial['commandData'] = [fCommand]
|
|
|
- self._dial.set(value)
|
|
|
-
|
|
|
- def get(self):
|
|
|
- return self._dial.get()
|
|
|
-
|
|
|
- def setEntry(self, value, fCommand = 1):
|
|
|
- self._entryVal.set(self.entryFormat % value)
|
|
|
- # Execute command
|
|
|
- if fCommand and (self['command'] != None):
|
|
|
- apply(self['command'], [value] + self['commandData'])
|
|
|
-
|
|
|
- def setEntryFormat(self):
|
|
|
- self.entryFormat = "%." + "%df" % self['numDigits']
|
|
|
- self.setEntry(self.get())
|
|
|
- self._dial['numDigits'] = self['numDigits']
|
|
|
-
|
|
|
- def validateEntryInput(self, event):
|
|
|
- input = self._entryVal.get()
|
|
|
- try:
|
|
|
- self._onReturnPress()
|
|
|
- self._entry.configure(background = self._entryBackground)
|
|
|
- newValue = string.atof(input)
|
|
|
- self.set(newValue)
|
|
|
- self._onReturnRelease()
|
|
|
- except ValueError:
|
|
|
- self._entry.configure(background = 'Pink')
|
|
|
-
|
|
|
- def _onReturnPress(self, *args):
|
|
|
- """ User redefinable callback executed on <Return> in entry """
|
|
|
- if self['preCallback']:
|
|
|
- apply(self['preCallback'], self['callbackData'])
|
|
|
-
|
|
|
- def _onReturnRelease(self, *args):
|
|
|
- """ User redefinable callback executed on <Return> release in entry """
|
|
|
- if self['postCallback']:
|
|
|
- apply(self['postCallback'], self['callbackData'])
|
|
|
-
|
|
|
- # Pass settings down to dial
|
|
|
- def setCallbackData(self):
|
|
|
- # Pass callback data down to dial
|
|
|
- self._dial['callbackData'] = self['callbackData']
|
|
|
-
|
|
|
- def setResetValue(self):
|
|
|
- self._dial['resetValue'] = self['resetValue']
|
|
|
-
|
|
|
- def setMin(self):
|
|
|
- self._dial['min'] = self['min']
|
|
|
-
|
|
|
- def setMax(self):
|
|
|
- self._dial['max'] = self['max']
|
|
|
-
|
|
|
+ self._valuator.grid(row=0,col=2, padx = 2, pady = 2)
|
|
|
+ self.interior().columnconfigure(0, weight = 1)
|
|
|
+
|
|
|
+ def addValuatorPropertiesToDialog(self):
|
|
|
+ self.addPropertyToDialog(
|
|
|
+ 'base',
|
|
|
+ { 'widget' : self._valuator,
|
|
|
+ 'type' : 'real',
|
|
|
+ 'help' : 'Dial value = base + delta * numRevs'})
|
|
|
+ self.addPropertyToDialog(
|
|
|
+ 'delta',
|
|
|
+ { 'widget' : self._valuator,
|
|
|
+ 'type' : 'real',
|
|
|
+ 'help' : 'Dial value = base + delta * numRevs'})
|
|
|
+ self.addPropertyToDialog(
|
|
|
+ 'numSegments',
|
|
|
+ { 'widget' : self._valuator,
|
|
|
+ 'type' : 'integer',
|
|
|
+ 'help' : 'Number of segments to divide dial into.'})
|
|
|
+
|
|
|
+ def addValuatorMenuEntries(self):
|
|
|
+ # The popup menu
|
|
|
+ self._fSnap = IntVar()
|
|
|
+ self._fSnap.set(self['fSnap'])
|
|
|
+ self._popupMenu.add_checkbutton(label = 'Snap',
|
|
|
+ variable = self._fSnap,
|
|
|
+ command = self._setSnap)
|
|
|
+ self._fRollover = IntVar()
|
|
|
+ self._fRollover.set(self['fRollover'])
|
|
|
+ if self['fAdjustable']:
|
|
|
+ self._popupMenu.add_checkbutton(label = 'Rollover',
|
|
|
+ variable = self._fRollover,
|
|
|
+ command = self._setRollover)
|
|
|
+
|
|
|
def setBase(self):
|
|
|
- self._dial['base'] = self['base']
|
|
|
+ """ Set Dial base value: value = base + delta * numRevs """
|
|
|
+ self._valuator['base'] = self['base']
|
|
|
|
|
|
def setDelta(self):
|
|
|
- self._dial['delta'] = self['delta']
|
|
|
+ """ Set Dial delta value: value = base + delta * numRevs """
|
|
|
+ self._valuator['delta'] = self['delta']
|
|
|
|
|
|
- def setLabel(self):
|
|
|
- self._label['text'] = self['text']
|
|
|
+ def _setSnap(self):
|
|
|
+ """ Menu command to turn Dial angle snap on/off """
|
|
|
+ self._valuator['fSnap'] = self._fSnap.get()
|
|
|
+
|
|
|
+ def setSnap(self):
|
|
|
+ """ Turn Dial angle snap on/off """
|
|
|
+ self._fSnap.set(self['fSnap'])
|
|
|
+ # Call menu command to send down to valuator
|
|
|
+ self._setSnap()
|
|
|
|
|
|
- def setPreCallbackCmd(self):
|
|
|
- self._dial['preCallback'] = self['preCallback']
|
|
|
+ def _setRollover(self):
|
|
|
+ """
|
|
|
+ Menu command to turn Dial rollover on/off (i.e. does value accumulate
|
|
|
+ every time you complete a revolution of the dial?)
|
|
|
+ """
|
|
|
+ self._valuator['fRollover'] = self._fRollover.get()
|
|
|
|
|
|
- def setPostCallbackCmd(self):
|
|
|
- self._dial['postCallback'] = self['postCallback']
|
|
|
+ def setRollover(self):
|
|
|
+ """ Turn Dial rollover (accumulation of a sum) on/off """
|
|
|
+ self._fRollover.set(self['fRollover'])
|
|
|
+ # Call menu command to send down to valuator
|
|
|
+ self._setRollover()
|
|
|
|
|
|
|
|
|
class AngleDial(Dial):
|
|
|
@@ -200,7 +138,7 @@ class AngleDial(Dial):
|
|
|
# Set the typical defaults for a 360 degree angle dial
|
|
|
optiondefs = (
|
|
|
('delta', 360.0, None),
|
|
|
- ('dial_fRollover', 0, None),
|
|
|
+ ('fRollover', 0, None),
|
|
|
('dial_numSegments', 12, None),
|
|
|
)
|
|
|
self.defineoptions(kw, optiondefs)
|
|
|
@@ -212,37 +150,25 @@ class AngleDial(Dial):
|
|
|
|
|
|
|
|
|
class DialWidget(Pmw.MegaWidget):
|
|
|
- sfBase = 3.0
|
|
|
- sfDist = 15
|
|
|
- deadband = 10
|
|
|
def __init__(self, parent = None, **kw):
|
|
|
#define the megawidget options
|
|
|
INITOPT = Pmw.INITOPT
|
|
|
optiondefs = (
|
|
|
- ## Appearance
|
|
|
- # Edge size of the dial
|
|
|
- ('size', DIAL_FULL_SIZE, INITOPT),
|
|
|
- # Widget relief
|
|
|
+ # Appearance
|
|
|
+ ('style', DIAL_FULL, INITOPT),
|
|
|
+ ('size', None, INITOPT),
|
|
|
('relief', SUNKEN, self.setRelief),
|
|
|
- # Widget borderwidth
|
|
|
('borderwidth', 2, self.setBorderwidth),
|
|
|
- ('background', 'white', INITOPT),
|
|
|
+ ('background', 'white', self.setBackground),
|
|
|
# Number of segments the dial is divided into
|
|
|
('numSegments', 10, self.setNumSegments),
|
|
|
- ## Values
|
|
|
+ # Behavior
|
|
|
# Initial value of dial, use self.set to change value
|
|
|
('value', 0.0, INITOPT),
|
|
|
+ ('numDigits', 2, self.setNumDigits),
|
|
|
+ # Dial specific options
|
|
|
('base', 0.0, None),
|
|
|
('delta', 1.0, None),
|
|
|
- ('min', None, None),
|
|
|
- ('max', None, None),
|
|
|
- ('resolution', None, None),
|
|
|
- ('numDigits', 2, self.setNumDigits),
|
|
|
- # Value dial jumps to on reset
|
|
|
- ('resetValue', 0.0, None),
|
|
|
- ## Behavior
|
|
|
- # Able to adjust max/min
|
|
|
- ('fAdjustable', 1, None),
|
|
|
# Snap to angle on/off
|
|
|
('fSnap', 0, None),
|
|
|
# Do values rollover (i.e. accumulate) with multiple revolutions
|
|
|
@@ -263,24 +189,33 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
Pmw.MegaWidget.__init__(self, parent)
|
|
|
|
|
|
# Set up some local and instance variables
|
|
|
+ # Create the components
|
|
|
+ interior = self.interior()
|
|
|
|
|
|
- # Running total which increments/decrements every time around dial
|
|
|
- self.rollCount = 0
|
|
|
# Current value
|
|
|
self.value = self['value']
|
|
|
|
|
|
- # Create the components
|
|
|
- interior = self.interior()
|
|
|
- dim = self['size']
|
|
|
+ # Running total which increments/decrements every time around dial
|
|
|
+ self.rollCount = 0
|
|
|
+
|
|
|
+ # Base dial size on style, if size not specified,
|
|
|
+ if not self['size']:
|
|
|
+ if self['style'] == DIAL_FULL:
|
|
|
+ size = DIAL_FULL_SIZE
|
|
|
+ else:
|
|
|
+ size = DIAL_MINI_SIZE
|
|
|
+ else:
|
|
|
+ size = self['size']
|
|
|
+
|
|
|
# Radius of the dial
|
|
|
- radius = self.radius = int(dim/2.0)
|
|
|
+ radius = self.radius = int(size/2.0)
|
|
|
# Radius of the inner knob
|
|
|
inner_radius = max(3,radius * INNER_SF)
|
|
|
|
|
|
# The canvas
|
|
|
self._canvas = self.createcomponent('canvas', (), None,
|
|
|
Canvas, (interior,),
|
|
|
- width = dim, height = dim,
|
|
|
+ width = size, height = size,
|
|
|
background = self['background'],
|
|
|
highlightthickness = 0,
|
|
|
scrollregion = (-radius,-radius,
|
|
|
@@ -302,53 +237,6 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
fill = '#A0A0A0',
|
|
|
tags = ('knob',))
|
|
|
|
|
|
- # A Dictionary of dictionaries used for the popup property dialog
|
|
|
- self.propertyDict = {
|
|
|
- 'min' : { 'widget' : self,
|
|
|
- 'type' : 'real',
|
|
|
- 'fNone' : 1,
|
|
|
- 'help' : 'Minimum allowable dial value, Enter None for no minimum'},
|
|
|
- 'max' : { 'widget' : self,
|
|
|
- 'type' : 'real',
|
|
|
- 'fNone' : 1,
|
|
|
- 'help' : 'Maximum allowable dial value, Enter None for no maximum'},
|
|
|
- 'base' : { 'widget' : self,
|
|
|
- 'type' : 'real',
|
|
|
- 'help' : 'Dial value = base + delta * numRevs'},
|
|
|
- 'delta' : { 'widget' : self,
|
|
|
- 'type' : 'real',
|
|
|
- 'help' : 'Dial value = base + delta * numRevs'},
|
|
|
- 'numSegments' : { 'widget' : self,
|
|
|
- 'type' : 'integer',
|
|
|
- 'help' : 'Number of segments to divide dial into'},
|
|
|
- 'resetValue' : { 'widget' : self,
|
|
|
- 'type' : 'real',
|
|
|
- 'help' : 'Enter value to set dial to on reset.'}
|
|
|
- }
|
|
|
- self.propertyList = ['min', 'max', 'base', 'delta',
|
|
|
- 'resetValue', 'numSegments']
|
|
|
-
|
|
|
- # The popup menu
|
|
|
- self._popupMenu = Menu(interior, tearoff = 0)
|
|
|
- self._fSnap = IntVar()
|
|
|
- self._fSnap.set(self['fSnap'])
|
|
|
- self._popupMenu.add_checkbutton(label = 'Snap',
|
|
|
- variable = self._fSnap,
|
|
|
- command = self.setSnap)
|
|
|
- self._fRollover = IntVar()
|
|
|
- self._fRollover.set(self['fRollover'])
|
|
|
- if self['fAdjustable']:
|
|
|
- self._popupMenu.add_checkbutton(label = 'Rollover',
|
|
|
- variable = self._fRollover,
|
|
|
- command = self.setRollover)
|
|
|
- self._popupMenu.add_command(
|
|
|
- label = 'Properties...',
|
|
|
- command = self.popupPropertiesDialog)
|
|
|
- self._popupMenu.add_command(label = 'Zero Dial',
|
|
|
- command = self.zero)
|
|
|
- self._popupMenu.add_command(label = 'Reset Dial',
|
|
|
- command = self.reset)
|
|
|
-
|
|
|
# Add event bindings
|
|
|
self._canvas.tag_bind('dial', '<ButtonPress-1>', self.mouseDown)
|
|
|
self._canvas.tag_bind('dial', '<B1-Motion>', self.mouseMotion)
|
|
|
@@ -356,12 +244,10 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
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.knobMouseMotion)
|
|
|
+ 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._canvas.bind('<Double-ButtonPress-1>', self.mouseReset)
|
|
|
- self._canvas.bind('<ButtonPress-3>', self.popupDialMenu)
|
|
|
|
|
|
# Make sure input variables processed
|
|
|
self.initialiseoptions(DialWidget)
|
|
|
@@ -371,49 +257,16 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
self.set(value, fCommand = 1)
|
|
|
Set dial to new value, execute command if fCommand == 1
|
|
|
"""
|
|
|
- # Clamp value
|
|
|
- if self['min'] is not None:
|
|
|
- if value < self['min']:
|
|
|
- value = self['min']
|
|
|
- if self['max'] is not None:
|
|
|
- if value > self['max']:
|
|
|
- value = self['max']
|
|
|
- # Round by resolution
|
|
|
- if self['resolution'] is not None:
|
|
|
- value = round(value / self['resolution']) * self['resolution']
|
|
|
# Adjust for rollover
|
|
|
if not self['fRollover']:
|
|
|
if value > self['delta']:
|
|
|
self.rollCount = 0
|
|
|
value = self['base'] + ((value - self['base']) % self['delta'])
|
|
|
- # Update indicator to reflect adjusted value
|
|
|
- self.updateIndicator(value)
|
|
|
# Send command if any
|
|
|
if fCommand and (self['command'] != None):
|
|
|
apply(self['command'], [value] + self['commandData'])
|
|
|
# Record value
|
|
|
self.value = value
|
|
|
-
|
|
|
- # Set floater to zero
|
|
|
- def zero(self):
|
|
|
- """
|
|
|
- self.reset()
|
|
|
- Set dial to zero
|
|
|
- """
|
|
|
- self.set(0.0)
|
|
|
-
|
|
|
- # Reset dial to reset value
|
|
|
- def reset(self):
|
|
|
- """
|
|
|
- self.reset()
|
|
|
- Reset dial to reset value
|
|
|
- """
|
|
|
- self.set(self['resetValue'])
|
|
|
-
|
|
|
- def mouseReset(self,event):
|
|
|
- # If not over any canvas item
|
|
|
- if not self._canvas.find_withtag(CURRENT):
|
|
|
- self.reset()
|
|
|
|
|
|
def get(self):
|
|
|
"""
|
|
|
@@ -486,10 +339,10 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
def knobMouseDown(self,event):
|
|
|
self._onButtonPress()
|
|
|
self.knobSF = 0.0
|
|
|
- t = taskMgr.add(self.knobComputeVelocity, 'cv')
|
|
|
- t.lastTime = globalClock.getFrameTime()
|
|
|
+ self.updateTask = taskMgr.add(self.updateDialTask, 'updateDial')
|
|
|
+ self.updateTask.lastTime = globalClock.getFrameTime()
|
|
|
|
|
|
- def knobComputeVelocity(self, state):
|
|
|
+ def updateDialTask(self, state):
|
|
|
# Update value
|
|
|
currT = globalClock.getFrameTime()
|
|
|
dt = currT - state.lastTime
|
|
|
@@ -497,35 +350,39 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
state.lastTime = currT
|
|
|
return Task.cont
|
|
|
|
|
|
- def knobMouseMotion(self, event):
|
|
|
- # What is the current knob angle
|
|
|
- self.knobSF = self.computeKnobSF(event)
|
|
|
-
|
|
|
- def computeKnobSF(self, event):
|
|
|
+ def updateDialSF(self, event):
|
|
|
x = self._canvas.canvasx(event.x)
|
|
|
y = self._canvas.canvasy(event.y)
|
|
|
- offset = max(0, abs(x) - DialWidget.deadband)
|
|
|
+ offset = max(0, abs(x) - Valuator.deadband)
|
|
|
if offset == 0:
|
|
|
return 0
|
|
|
- sf = math.pow(DialWidget.sfBase,
|
|
|
- self.minExp + offset/DialWidget.sfDist)
|
|
|
+ sf = math.pow(Valuator.sfBase,
|
|
|
+ self.minExp + offset/Valuator.sfDist)
|
|
|
if x > 0:
|
|
|
- return sf
|
|
|
+ self.knobSF = sf
|
|
|
else:
|
|
|
- return -sf
|
|
|
+ self.knobSF = -sf
|
|
|
|
|
|
def knobMouseUp(self, event):
|
|
|
- taskMgr.remove('cv')
|
|
|
+ taskMgr.remove(self.updateTask)
|
|
|
self.knobSF = 0.0
|
|
|
self._onButtonRelease()
|
|
|
|
|
|
- def highlightKnob(self, event):
|
|
|
- self._canvas.itemconfigure('knob', fill = 'black')
|
|
|
-
|
|
|
- def restoreKnob(self, event):
|
|
|
- self._canvas.itemconfigure('knob', fill = '#A0A0A0')
|
|
|
+ def setNumDigits(self):
|
|
|
+ # Set minimum exponent to use in velocity task
|
|
|
+ self.minExp = math.floor(-self['numDigits']/
|
|
|
+ math.log10(Valuator.sfBase))
|
|
|
|
|
|
# Methods to modify dial characteristics
|
|
|
+ def setRelief(self):
|
|
|
+ self.interior()['relief'] = self['relief']
|
|
|
+
|
|
|
+ def setBorderwidth(self):
|
|
|
+ self.interior()['borderwidth'] = self['borderwidth']
|
|
|
+
|
|
|
+ def setBackground(self):
|
|
|
+ self._canvas['background'] = self['background']
|
|
|
+
|
|
|
def setNumSegments(self):
|
|
|
self._canvas.delete('ticks')
|
|
|
# Based upon input snap angle, how many ticks
|
|
|
@@ -550,44 +407,13 @@ class DialWidget(Pmw.MegaWidget):
|
|
|
self._canvas.create_line(startx, starty, endx, endy,
|
|
|
tags = ('ticks','dial'))
|
|
|
|
|
|
- def setRelief(self):
|
|
|
- self.interior()['relief'] = self['relief']
|
|
|
-
|
|
|
- def setBorderwidth(self):
|
|
|
- self.interior()['borderwidth'] = self['borderwidth']
|
|
|
-
|
|
|
- def setNumDigits(self):
|
|
|
- # Set minimum exponent to use in velocity task
|
|
|
- self.minExp = math.floor(-self['numDigits']/
|
|
|
- math.log10(DialWidget.sfBase))
|
|
|
-
|
|
|
- # The following methods are used to handle the popup menu
|
|
|
- def popupDialMenu(self,event):
|
|
|
- self._popupMenu.post(event.widget.winfo_pointerx(),
|
|
|
- event.widget.winfo_pointery())
|
|
|
+ def highlightKnob(self, event):
|
|
|
+ self._canvas.itemconfigure('knob', fill = 'black')
|
|
|
|
|
|
- # Turn angle snap on/off
|
|
|
- def setSnap(self):
|
|
|
- self['fSnap'] = self._fSnap.get()
|
|
|
+ def restoreKnob(self, event):
|
|
|
+ self._canvas.itemconfigure('knob', fill = '#A0A0A0')
|
|
|
|
|
|
- # Turn rollover (accumulation of a sum) on/off
|
|
|
- def setRollover(self):
|
|
|
- self['fRollover'] = self._fRollover.get()
|
|
|
-
|
|
|
- # This handles the popup dial min dialog
|
|
|
- def popupPropertiesDialog(self):
|
|
|
- # Popup dialog to adjust widget properties
|
|
|
- WidgetPropertiesDialog.WidgetPropertiesDialog(
|
|
|
- self.propertyDict,
|
|
|
- propertyList = self.propertyList,
|
|
|
- title = 'Dial Widget Properties',
|
|
|
- parent = self._canvas)
|
|
|
-
|
|
|
- def addPropertyToDialog(self, property, pDict):
|
|
|
- self.propertyDict[property] = pDict
|
|
|
- self.propertyList.append(property)
|
|
|
-
|
|
|
- # User callbacks
|
|
|
+ # To call user callbacks
|
|
|
def _onButtonPress(self, *args):
|
|
|
""" User redefinable callback executed on button press """
|
|
|
if self['preCallback']:
|