linuxcnc/lib/python/pyvcp_widgets.py
Mick 91467a6f6a Bug in radio button pyvcp_widgets
initval field setting the correct widget to active at initialisation, but changes to prevent
unnecessary updates supressing initial setting of associated pin to match.

Explicitly setting pin associated with active button selection via initval at initialisation corrects this.

Signed-off-by: Mick Grant <arceye@mgware.co.uk>
2015-01-21 07:30:35 -07:00

1669 lines
57 KiB
Python

# This is a component of AXIS, a front-end for emc
# Copyright 2007 Anders Wallin <anders.wallin@helsinki.fi>
#
# TJP 12 04 2007
# Rugludallur saw that spinbuttons had no initial value until after thumbs inc'd or de'c
# TJP saw that if xml prescribed <value>1234</value> the spinbutton locked up after the inc/dec
# it seems a new term in the __init__ may fix this
# end TJP 12 04 2007
#
# Added initval to checkbutton/scale for initial values, Dallur 15 April 2007 (jarl stefansson) (jarl stefansson)
#
# Multiple additions and amendments as per notations - ArcEye 2013
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
""" A widget library for pyVCP
The layout and composition of a Python Virtual Control Panel is specified
with an XML file. The file must begin with <pyvcp>, and end with </pyvcp>
In the documentation for each widget, optional tags are shown bracketed:
[ <option>Something</option> ]
such a tag is not required for pyVCP to work, but may add functionality or
modify the behaviour of a widget.
Example XML file:
<pyvcp>
<led>
<size>40</size>
<halpin>"my-led"</halpin>
</led>
</pyvcp>
This will create a VCP with a single LED widget which indicates the value
of HAL pin compname.my-led
"""
from Tkinter import *
from hal import *
import math
import bwidget
import time
# -------------------------------------------
class pyvcp_dial(Canvas):
# Dial widget by tomp
""" A dial that outputs a HAL_FLOAT
reacts to both mouse-wheel and mouse dragging
<dial>
[ <size>376</size> ]
[ <dialcolor>"grey"</dialcolor> ]
[ <edgecolor>"pink"</edgecolor> ]
[ <dotcolor>"white"</dotcolor> ]
[ <cpr>100</cpr> ] number of changes per rev, is # of dial tick marks, beware hi values)
[ <min_>-33.123456</min_> ]
[ <max_>3.3</max_> ]
[ <text>"Gallons per Hour"</text> ] (knob label)
[ <initval>123</initval> ] (initial value a whole number must end in '.')
[ <resolution>.001</resolution> ] (scale value a whole number must end in '.')
[ <halpin>"anaout"</halpin> ]
[ <param_pin>1</param_pin>] creates param pin if > 0, set to initval, value can then be set externally, ArcEye 2013
</dial>
key bindings:
<Button-4> untested no wheel mouse
<Button-5> untested no wheel mouse
<Button1-Motion> used internally during drag
<ButtonPress> used internally to record beginning of drag
<ButtonRelease> used internally at end of drag
<Double-1> divides scale by 10
<Double-2> resets scale to original value
<Double-3> multiplies scale by 10
<Shift-1> shift-click resets original analog value
features:
text autoscales
"""
# FIXME:
# -jogging should be enabled only when the circle has focus
# TJP nocando: only widgets have events, not thier 'items', the circle is an item
# -circle should maintain focus when mouse over dot
# TJP nocando: ditto, the circle is an item, so focus & event are not aligned to it
# -jogging by dragging with the mouse could work better
# -add a scaled output, scale changes when alt/ctrl/shift is held down
# TJP dblLeftClick divides scale by 10 , dblRightClcik muxs by 10
n=0
#TJP TODO: let some artists look at it, butt ugly!
#TJP cpr is overloaded, now it means "chgs per rev" not "counts per rev"
#TJP the tik marks could get very fine, avoid high cpr to size ratios (easily seen)
def __init__(self,root,pycomp,halpin=None,halparam=None,param_pin=0,size=200,cpr=40,dialcolor="", \
edgecolor="",dotcolor="grey",min_=None,max_=None, \
text=None,initval=0,resolution=0.1, \
**kw):
pad=size/10
self.counts = int(round(initval/resolution))
self.out = self.counts * resolution # float output out
self.origValue=initval # in case user wants to reset the pot/valve/thingy
#self.text3=resolution
Canvas.__init__(self,root,width=size,height=size)
pad2=pad-size/15
self.circle2=self.create_oval(pad2,pad2,size-pad2,size-pad2,width=3)# edge circle
self.itemconfig(self.circle2,fill=edgecolor,activefill=edgecolor)
self.circle=self.create_oval(pad,pad,size-pad,size-pad) # dial circle
self.itemconfig(self.circle,fill=dialcolor,activefill=dialcolor)
self.itemconfig(self.circle)
self.mid=size/2
self.r=(size-2*pad)/2
self.alfa=0
self.d_alfa=2*math.pi/cpr
self.size=size
self.funit=resolution
self.origFunit=self.funit # allow restoration
self.mymin=min_
self.mymax=max_
self.dot = self.create_oval(self.dot_coords())
self.itemconfig(self.dot,fill=dotcolor,activefill="black")
self.line = self.create_line( self.mid+(self.r*1)*math.cos(self.alfa), \
self.mid+(self.r*1)*math.sin(self.alfa), \
self.mid+(self.r*1.1)*math.cos(self.alfa), \
self.mid+(self.r*1.1)*math.sin(self.alfa))
self.itemconfig(self.line,arrow="last",arrowshape=(10,10,10))
self.itemconfig(self.line,width=10)
#TJP items get rendered in order of creation, so the knob will be behind these texts
#TJP the font can be described with pixel size by using negative value
self.txtroom=size/6
# a title, if the user has supplied one
if text!=None:
self.title=self.create_text([self.mid,self.mid-self.txtroom],
text=text,font=('Arial',-self.txtroom))
# the output
self.dro=self.create_text([self.mid,self.mid],
text=str(self.out),font=('Arial',-self.txtroom))
# the scale
self.delta=self.create_text([self.mid,self.mid+self.txtroom],
text='x '+ str(self.funit),font=('Arial',-self.txtroom))
self.bind('<Button-4>',self.wheel_up) # untested no wheel mouse
self.bind('<Button-5>',self.wheel_down) # untested no wheel mouse
self.bind('<Button1-Motion>',self.motion) #during drag
self.bind('<ButtonPress>',self.bdown) #begin of drag
self.bind('<ButtonRelease>',self.bup) #end of drag
self.bind('<Double-1>',self.chgScaleDn) # doubleclick scales down
self.bind('<Double-2>',self.resetScale) # doubleclick resets scale
self.bind('<Double-3>',self.chgScaleUp) # doubleclick scales up
self.bind('<Shift-1>',self.resetValue) # shift resets value
self.draw_ticks(cpr)
self.dragstartx=0
self.dragstarty=0
self.dragstart=0
self.dotcolor=dotcolor
# create the hal pin
if halpin == None:
halpin = "dial."+str(pyvcp_dial.n)+".out"
self.halpin=halpin
if halparam == None:
self.param_pin = param_pin
if self.param_pin == 1:
halparam = "dial." + str(pyvcp_dial.n) + ".param_pin"
self.halparam=halparam
pycomp.newpin(halparam, HAL_FLOAT, HAL_IN)
pyvcp_dial.n += 1
self.pycomp=pycomp
pycomp.newpin(halpin, HAL_FLOAT, HAL_OUT)
pycomp[self.halparam] = self.origValue
self.oldValue = self.origValue
self.value = self.origValue
def chgScaleDn(self,event):
# reduces the scale by 10x
self.funit=self.funit/10.0
self.counts *= 10
self.update_scale()
self.update_dro()
self.update_dot()
def chgScaleUp(self,event):
# increases the scale by 10x
self.funit=self.funit*10.0
self.counts = (self.counts + 5) / 10
self.out = self.counts * self.funit
self.update_scale()
self.update_dro()
self.update_dot()
def resetScale(self,event):
# reset scale to original value
self.funit=self.origFunit
self.counts = int(round(self.out / self.funit))
self.out = self.counts * self.funit
self.update_scale()
def resetValue(self,event):
# reset output to orifinal value
self.counts = int(round(self.origValue / self.funit))
self.out= self.counts * self.funit
self.update_dot()
self.update_dro()
def dot_coords(self):
# calculate the coordinates for the dot
DOTR=0.04*self.size
DOTPOS=0.85
midx = self.mid+DOTPOS*self.r*math.cos(self.alfa)
midy = self.mid+DOTPOS*self.r*math.sin(self.alfa)
return midx-DOTR, midy-DOTR,midx+DOTR,midy+DOTR
def bdown(self,event):
self.dragstartx=event.x
self.dragstarty=event.y
self.dragstart=math.atan2((event.y-self.mid),(event.x-self.mid))
self.itemconfig(self.dot,fill="black",activefill="black")
def bup(self,event):
self.itemconfig(self.dot,fill=self.dotcolor)
def motion(self,event):
dragstop = math.atan2((event.y-self.mid),(event.x-self.mid))
delta = dragstop - self.dragstart
if delta>=self.d_alfa:
self.up()
self.dragstart=math.atan2((event.y-self.mid),(event.x-self.mid))
elif delta<=-self.d_alfa:
self.down()
self.dragstart=math.atan2((event.y-self.mid),(event.x-self.mid))
self.itemconfig(self.dot,fill="black",activefill="black")
def wheel_up(self,event):
self.up()
def wheel_down(self,event):
self.down()
def down(self):
self.alfa-=self.d_alfa
self.counts -= 1
self.out = self.counts * self.funit
#TJP clip down side
if self.mymin != None:
if self.out<self.mymin:
self.out=self.mymin
self.counts = self.mymin * self.funit
self.update_dot()
self.update_dro()
def up(self):
self.alfa+=self.d_alfa
self.counts += 1
self.out = self.counts * self.funit
#TJP clip up side
if self.mymax != None:
if self.out>self.mymax:
self.out=self.mymax
self.counts = self.mymax * self.funit
self.update_dot()
self.update_dro()
def update_dot(self):
self.coords(self.dot, self.dot_coords() )
self.coords(self.line, self.mid+(self.r*1)*math.cos(self.alfa),self.mid+(self.r*1)*math.sin(self.alfa), \
self.mid+(self.r*1.1)*math.cos(self.alfa), \
self.mid+(self.r*1.1)*math.sin(self.alfa))
def update_dro(self):
valtext = str(self.out)
self.itemconfig(self.dro,text=valtext)
def update_scale(self):
valtext = str(self.funit)
valtext = 'x ' + valtext
self.itemconfig(self.delta,text=valtext)
def draw_ticks(self,cpr):
for n in range(0,cpr,2):
for i in range(0,2):
startx=self.mid+self.r*math.cos((n+i)*self.d_alfa)
starty=self.mid+self.r*math.sin((n+i)*self.d_alfa)
if i == 0:
length = 1.15
width = 2
else:
length = 1.1
width = 1
stopx=self.mid+length*self.r*math.cos((n+i)*self.d_alfa)
stopy=self.mid+length*self.r*math.sin((n+i)*self.d_alfa)
self.create_line(startx,starty,stopx,stopy,width=width)
def update(self,pycomp):
self.pycomp[self.halpin] = self.out
self.value = pycomp[self.halparam]
if self.value != self.oldValue :
self.counts = int(round(self.value / self.funit))
self.out= self.counts * self.funit
self.update_dot()
self.update_dro()
self.oldValue = self.value
# -------------------------------------------
class pyvcp_meter(Canvas):
""" Meter - shows the value of a FLOAT with an analog meter
<meter>
[ <size>300</size> ]
[ <halpin>"mymeter"</halpin> ]
[ <text>"My Voltage"</text> ]
[ <subtext>"Volts"</subtext>
[ <min_>-22</min_> ]
[ <max_>123</max_> ]
[ <majorscale>10</majorscale> ]
[ <minorscale>5</minorscale> ]
[ <region1>(70,80,"green")</region1> ]
[ <region2>(80,100,"orange")</region2> ]
[ <region3>(100,123,"red")</region3> ]
</meter>
"""
# FIXME: logarithmic scale option
n=0
def __init__(self,root,pycomp,halpin=None, size=200,text=None,subtext=None,min_=0,max_=100,majorscale=None, minorscale=None,region1=None,region2=None,region3=None,**kw):
self.size = size
self.pad=10
Canvas.__init__(self,root,width=size,height=size)
self.halpin=halpin
self.min_=min_
self.max_=max_
range_=2.5
self.min_alfa=-math.pi/2-range_
self.max_alfa=-math.pi/2+range_
self.circle=self.create_oval(self.pad,self.pad,size-self.pad,size-self.pad, width=2)
self.itemconfig(self.circle,fill="white")
self.mid=size/2
self.r=(size-2*self.pad)/2
self.alfa=0
if minorscale==None:
self.minorscale=0
else:
self.minorscale=minorscale
if majorscale==None:
self.majorscale=float((self.max_-self.min_)/10)
else:
self.majorscale=majorscale
if text!=None: t=self.create_text([self.mid,self.mid-size/12],font="Arial %d bold" % (size/10),text=text)
if subtext!=None: t=self.create_text([self.mid,self.mid+size/12],font="Arial %d" % (size/30+5),text=subtext)
if region1!=None: self.draw_region(region1)
if region2!=None: self.draw_region(region2)
if region3!=None: self.draw_region(region3)
self.draw_ticks()
self.line = self.create_line([self.mid,self.mid, self.mid+self.r*math.cos(self.alfa), self.mid+self.r*math.sin(self.alfa)],fill="red", arrow="last", arrowshape=(0.9*self.r,self.r,self.r/20))
self.itemconfig(self.line,width=3)
# create the hal pin
if halpin == None:
self.halpin = "meter."+str(pyvcp_meter.n)+".value"
pyvcp_meter.n += 1
pycomp.newpin(self.halpin, HAL_FLOAT, HAL_IN)
self.value = pycomp[self.halpin]
def rad2deg(self, rad): return rad*180/math.pi
def value2angle(self, value):
#returns angle for a given value
scale = (self.max_-self.min_)/(self.max_alfa-self.min_alfa)
alfa = self.min_alfa + (value-self.min_)/scale
if alfa > self.max_alfa:
alfa = self.max_alfa
elif alfa < self.min_alfa:
alfa = self.min_alfa
return alfa
def p2c(self, radius, angle):
#returns the cathesian coordinates (x,y) for given polar coordinates
#radius in percent of self.r; angle in radians
return self.mid+radius*self.r*math.cos(angle), self.mid+radius*self.r*math.sin(angle)
def update(self,pycomp):
self.value = pycomp[self.halpin]
self.alfa = self.value2angle(self.value)
x,y = self.p2c(0.8, self.alfa)
self.coords(self.line,self.mid,self.mid,x,y)
def draw_region(self, (start, end, color)):
#Draws a colored region on the canvas between start and end
start = self.value2angle(start)
start = -self.rad2deg(start)
end = self.value2angle(end)
end = -self.rad2deg(end)
extent = end-start
halfwidth = math.floor(0.1*self.r/2)+1
xy = self.pad+halfwidth, self.pad+halfwidth, self.size-self.pad-halfwidth, self.size-self.pad-halfwidth
self.create_arc(xy, start=start, extent=extent, outline=color, width=(halfwidth-1)*2, style="arc")
def draw_ticks(self):
value = self.min_
while value <= self.max_:
alfa = self.value2angle(value)
xy1 = self.p2c(1,alfa)
xy2 = self.p2c(0.85,alfa)
xytext = self.p2c(0.75,alfa)
self.create_text(xytext,font="Arial %d" % (self.size/30+5), text="%g" % value)
self.create_line(xy1, xy2, width=2)
value = value + self.majorscale
#minor ticks
value = self.min_
if self.minorscale > 0:
while value <= self.max_:
if (value % self.majorscale) != 0:
alfa = self.value2angle(value)
xy1 = self.p2c(1,alfa)
xy2 = self.p2c(0.9,alfa)
self.create_line(xy1, xy2)
value = value + self.minorscale
# -------------------------------------------
class pyvcp_jogwheel(Canvas):
"""" A jogwheel that outputs a HAL_FLOAT count
reacts to both mouse-wheel and mouse dragging
<jogwheel>
[ <cpr>33</cpr> ] (counts per revolution)
[ <halpin>"myjogwheel"</halpin> ]
[ <size>300</size> ]
</jogwheel>
"""
# FIXME:
# -jogging should be enabled only when the circle has focus
# -circle should maintain focus when mouse over dot
# -jogging by dragging with the mouse could work better
# -add a scaled output, scale changes when alt/ctrl/shift is held down
n=0
def __init__(self,root,pycomp,halpin=None,size=200,cpr=40,**kw):
pad=size/10
self.count=0
Canvas.__init__(self,root,width=size,height=size)
pad2=pad-size/15
self.circle2=self.create_oval(pad2,pad2,size-pad2,size-pad2,width=3)# edge circle
self.circle=self.create_oval(pad,pad,size-pad,size-pad)
self.itemconfig(self.circle,fill="lightgrey",activefill="lightgrey")
self.mid=size/2
self.r=(size-2*pad)/2
self.alfa=0
self.d_alfa=2*math.pi/cpr
self.size=size
self.dot = self.create_oval(self.dot_coords())
self.itemconfig(self.dot,fill="black")
self.line = self.create_line( self.mid+(self.r*1)*math.cos(self.alfa), \
self.mid+(self.r*1)*math.sin(self.alfa), \
self.mid+(self.r*1.1)*math.cos(self.alfa), \
self.mid+(self.r*1.1)*math.sin(self.alfa))
self.itemconfig(self.line,arrow="last",arrowshape=(10,10,10))
self.itemconfig(self.line,width=8)
self.bind('<Button-4>',self.wheel_up)
self.bind('<Button-5>',self.wheel_down)
self.bind('<Button1-Motion>',self.motion)
self.bind('<ButtonPress>',self.bdown)
self.draw_ticks(cpr)
self.dragstartx=0
self.dragstarty=0
self.dragstart=0
# create the hal pin
if halpin == None:
halpin = "jogwheel."+str(pyvcp_jogwheel.n)+".count"
pyvcp_jogwheel.n += 1
pycomp.newpin(halpin, HAL_FLOAT, HAL_OUT)
self.halpin=halpin
pycomp[self.halpin] = self.count
self.pycomp=pycomp
def dot_coords(self):
DOTR=0.06*self.size
DOTPOS=0.85
midx = self.mid+DOTPOS*self.r*math.cos(self.alfa)
midy = self.mid+DOTPOS*self.r*math.sin(self.alfa)
return midx-DOTR, midy-DOTR,midx+DOTR,midy+DOTR
def bdown(self,event):
self.dragstartx=event.x
self.dragstarty=event.y
self.dragstart=math.atan2((event.y-self.mid),(event.x-self.mid))
def motion(self,event):
dragstop = math.atan2((event.y-self.mid),(event.x-self.mid))
delta = dragstop - self.dragstart
if delta>=self.d_alfa:
self.up()
self.dragstart=math.atan2((event.y-self.mid),(event.x-self.mid))
elif delta<=-self.d_alfa:
self.down()
self.dragstart=math.atan2((event.y-self.mid),(event.x-self.mid))
def wheel_up(self,event):
self.up()
def wheel_down(self,event):
self.down()
def down(self):
self.alfa-=self.d_alfa
self.count-=1
self.pycomp[self.halpin] = self.count
self.update_dot()
def up(self):
self.alfa+=self.d_alfa
self.count+=1
self.pycomp[self.halpin] = self.count
self.update_dot()
def update_dot(self):
self.coords(self.dot, self.dot_coords() )
self.coords(self.line, self.mid+(self.r*1)*math.cos(self.alfa),self.mid+(self.r*1)*math.sin(self.alfa), \
self.mid+(self.r*1.1)*math.cos(self.alfa), \
self.mid+(self.r*1.1)*math.sin(self.alfa))
def draw_ticks(self,cpr):
for n in range(0,cpr):
startx=self.mid+self.r*math.cos(n*self.d_alfa)
starty=self.mid+self.r*math.sin(n*self.d_alfa)
stopx=self.mid+1.15*self.r*math.cos(n*self.d_alfa)
stopy=self.mid+1.15*self.r*math.sin(n*self.d_alfa)
self.create_line([startx,starty,stopx,stopy])
def update(self,pycomp):
# this is stupid, but required for updating pin
# when first connected to a signal
self.pycomp[self.halpin] = self.count
# -------------------------------------------
## ArcEye - added - no example given and the one in docs misses out initval ##
"""" A radiobutton will set one of the halpins true. The other pins are set false.
<radiobutton>
<choices>["one","two","three"]</choices> labels next to each button
<halpin>"radio"</halpin> pin giving index of active button
<initval>0</initval> index of button pin to set true at start
</radiobutton>
"""
################################################################################
class pyvcp_radiobutton(Frame):
n=0
def __init__(self,master,pycomp,halpin=None,initval=0,choices=[],**kw):
f=Frame.__init__(self,master,bd=2,relief=GROOVE)
self.v = IntVar()
self.v.set(1)
self.choices=choices
if halpin == None:
halpin = "radiobutton."+str(pyvcp_radiobutton.n)
pyvcp_radiobutton.n += 1
self.halpins=[]
n=0
for c in choices:
b=Radiobutton(self,f, text=str(c),variable=self.v, value=pow(2,n))
b.pack()
if n==initval:
b.select()
c_halpin=halpin+"."+str(c)
pycomp.newpin(c_halpin, HAL_BIT, HAL_OUT)
self.halpins.append(c_halpin)
n+=1
self.selected = initval
pycomp[self.halpins[initval]]=1
## ArcEye - FIXED - only update the pins if changed ##
def update(self,pycomp):
index=int(math.log(self.v.get(),2))
if index != self.selected:
for pin in self.halpins:
pycomp[pin]=0;
pycomp[self.halpins[index]]=1;
self.selected = index
# FIXME
# this would be a much better way of updating the
# pins, but at the moment I can't get it to work
# this is never called even if I set command=self.update()
# in the call to Radiobutton above
def changed(self):
index=math.log(self.v.get(),2)
index=int(index)
print "active:",self.halpins[index]
# -------------------------------------------
class pyvcp_label(Label):
""" Static text label
<label>
<text>"My Label:"</text>
<halpin>"name"</halpin>
<disable_pin>True</disable_pin>
</label>
"""
n=0
def __init__(self,master,pycomp,halpin=None,disable_pin=False,**kw):
Label.__init__(self,master,**kw)
self.disable_pin=disable_pin
if disable_pin:
if halpin == None:
halpin = "label."+str(pyvcp_label.n)
pyvcp_label.n += 1
halpin_disable = halpin+".disable"
self.halpin_disable = halpin_disable
pycomp.newpin(halpin_disable, HAL_BIT, HAL_IN)
def update(self,pycomp):
if self.disable_pin:
is_disabled = pycomp[self.halpin_disable]
if is_disabled == 1: Label.config(self,state=DISABLED)
else: Label.config(self,state=NORMAL)
else:pass
# -------------------------------------------
### ArcEye 01052013 - added new widget #############################################
class pyvcp_multilabel(Label):
""" Selectable text label, can display up to 6 label legends
when associated bit pin is activated
<multilabel>
<legends>["Label1" "Label2" "Label3" "Label4" "Label5" "Label6"]</legends>
<font>("Helvetica", 20)</font>
<disable_pin>True</disable_pin>
<initval>0</initval> Which legend to display by default (make sure it matches initval for linked widget if any)
<halpin>None</halpin> Optional alternative name base for pins
</multilabel>
"""
n=0
def __init__(self,master,pycomp,halpin=None,disable_pin=False,legends=[],initval=0,**kw):
Label.__init__(self,master,**kw)
self.disable_pin=disable_pin
if halpin == None:
halpin = "multilabel."+str(pyvcp_multilabel.n)
pyvcp_multilabel.n += 1
self.halpins=[]
n=0
for c in legends:
c_halpin=halpin+".legend"+str(n)
pycomp.newpin(c_halpin, HAL_BIT, HAL_IN)
self.halpins.append(c_halpin)
n+=1
#limit to 6 legends
if n >= 6:
break
self.legends = legends
self.num_pins = n
if disable_pin:
halpin_disable = halpin+".disable"
self.halpin_disable = halpin_disable
pycomp.newpin(halpin_disable, HAL_BIT, HAL_IN)
# test for out of range initval number
if initval >= 0 and initval <= self.num_pins :
val = initval
else :
val = 0
Label.config(self,text= legends[val])
pycomp[self.halpins[val]] = 1
self.pin_index = val
def update(self,pycomp):
if self.disable_pin:
is_disabled = pycomp[self.halpin_disable]
if is_disabled == 1:
Label.config(self,state=DISABLED)
else:
Label.config(self,state=NORMAL)
# no telling how people will use this, so just break at first
# set pin that is not the existing set one
# if several pins are set one after another, the legend for the
# last one set will end up being displayed
index = -1
for x in xrange(0, self.num_pins):
state = pycomp[self.halpins[x]]
if state == 1 :
index = x
if index != self.pin_index :
break
if index > -1 and index != self.pin_index:
for x in xrange(0, self.num_pins):
pycomp[self.halpins[x]] = 0
pycomp[self.halpins[index]] = 1
Label.config(self,text= self.legends[index])
self.pin_index = index
class pyvcp_vbox(Frame):
""" Box in which widgets are packed vertically
<vbox>
<relief>GROOVE</relief> (FLAT, SUNKEN, RAISED, GROOVE, RIDGE)
<bd>3</bd> (border width)
place widgets here
</vbox>
"""
def __init__(self,master,pycomp,bd=0,relief=FLAT):
Frame.__init__(self,master,bd=bd,relief=relief)
self.fill = 'x'
self.side = 'top'
self.anchor = 'center'
self.expand = 'yes'
def update(self,pycomp):
pass
def add(self, container, widget):
if isinstance(widget, pyvcp_boxexpand):
self.expand = widget.expand
return
if isinstance(widget, pyvcp_boxfill):
self.fill = widget.fill
return
if isinstance(widget, pyvcp_boxanchor):
self.anchor = widget.anchor
return
widget.pack(side=self.side, anchor=self.anchor, fill=self.fill, expand=self.expand)
class pyvcp_boxfill:
def __init__(self, master, pycomp, fill):
self.fill = fill
def update(self, pycomp): pass
class pyvcp_boxanchor:
def __init__(self, master, pycomp, anchor):
self.anchor = anchor
def update(self, pycomp): pass
class pyvcp_boxexpand:
def __init__(self, master, pycomp, expand):
self.expand = expand
def update(self, pycomp): pass
# -------------------------------------------
class pyvcp_hbox(Frame):
""" Box in which widgets are packed horizontally
<vbox>
<relief>GROOVE</relief> (FLAT, SUNKEN, RAISED, GROOVE, RIDGE)
<bd>3</bd> (border width)
place widgets here
</vbox>
"""
def __init__(self,master,pycomp,bd=0,relief=FLAT):
Frame.__init__(self,master,bd=bd,relief=relief)
self.fill = 'y'
self.side = 'left'
self.anchor = 'center'
self.expand = 'yes'
def update(self,pycomp):
pass
def add(self, container, widget):
if isinstance(widget, pyvcp_boxexpand):
self.expand = widget.expand
return
if isinstance(widget, pyvcp_boxfill):
self.fill = widget.fill
return
if isinstance(widget, pyvcp_boxanchor):
self.anchor = widget.anchor
return
widget.pack(side=self.side, anchor=self.anchor, fill=self.fill)
class pyvcp_labelframe(LabelFrame):
"""
frame with a title
"""
def __init__(self,master,pycomp,**kw):
LabelFrame.__init__(self,master,**kw)
self.pack(expand=1,fill=BOTH)
def update(self,pycomp):
pass
def add(self, container, widget):
widget.pack(side="top", fill="both", expand="yes")
class pyvcp_tabs(bwidget.NoteBook):
def __init__(self, master, pycomp, cnf={}, **kw):
self.names = kw.pop("names", [])
self.idx = 0
self._require(master)
Widget.__init__(self, master, "NoteBook", cnf, kw)
def update(self, pycomp): pass
def add(self, container, child):
child.pack(side="top", fill="both", anchor="ne")
if self.idx == 1:
self.raise_page(self.names[0])
def getcontainer(self):
if len(self.names) < self.idx:
self.names.append("Tab-%d" % self.idx)
name = self.names[self.idx]
self.idx += 1
return self.insert("end", name, text=name)
# -------------------------------------------
class pyvcp_spinbox(Spinbox):
""" (control) controls a float, also shown as text
reacts to the mouse wheel
<spinbox>
[ <halpin>"my-spinbox"</halpin> ]
[ <min_>55</min_> ] sets the minimum value to 55
[ <max_>123</max_> ] sets the maximum value to 123
[ <initval>100</initval> ] sets intial value to 100 TJP 12 04 2007
[ <param_pin>1</param_pin>] creates param pin if > 0, set to initval, value can then be set externally, ArcEye 2013
</spinbox>
"""
# FIXME: scale resolution when shift/ctrl/alt is held down?
n=0
def __init__(self,master,pycomp,halpin=None, halparam=None,param_pin=0,
min_=0,max_=100,initval=0,resolution=1,format="2.1f",**kw):
self.v = DoubleVar()
if 'increment' not in kw: kw['increment'] = resolution
if 'from' not in kw: kw['from'] = min_
if 'to' not in kw: kw['to'] = max_
if 'format' not in kw: kw['format'] = "%" + format
kw['command'] = self.command
Spinbox.__init__(self,master,textvariable=self.v,**kw)
if halpin == None:
halpin = "spinbox."+str(pyvcp_spinbox.n)
self.halpin=halpin
if halparam == None:
self.param_pin = param_pin
if self.param_pin == 1:
halparam = "spinbox." + str(pyvcp_spinbox.n) + ".param_pin"
self.halparam=halparam
pycomp.newpin(halparam, HAL_FLOAT, HAL_IN)
pyvcp_spinbox.n += 1
if initval < min_:
self.value=min_
elif initval > max_:
self.value=max_
else:
self.value=initval
self.oldvalue=min_
if self.param_pin == 1:
self.init=self.value
self.oldinit=self.init
pycomp[self.halparam] = self.init
self.format = "%(b)"+format
self.max_=max_
self.min_=min_
self.resolution=resolution
self.v.set( str( self.format % {'b':self.value} ) )
pycomp.newpin(halpin, HAL_FLOAT, HAL_OUT)
self.bind('<Button-4>',self.wheel_up)
self.bind('<Button-5>',self.wheel_down)
self.bind('<Return>',self.return_pressed)
def return_pressed(self, event):
self.value = self.v.get()
if self.value < self.min_:
self.value = self.min_
if self.value > self.max_:
self.value = self.max_
def command(self):
self.value = self.v.get()
def update(self,pycomp):
pycomp[self.halpin] = self.value
if self.value != self.oldvalue:
self.v.set( str( self.format % {'b':self.value} ) )
self.oldvalue=self.value
if self.param_pin == 1:
self.init = pycomp[self.halparam]
if self.init != self.oldinit:
self.v.set( str( self.format % {'b':self.init} ) )
self.oldinit=self.init
self.value=self.init
def wheel_up(self,event):
self.value += self.resolution
if self.value > self.max_:
self.value = self.max_
def wheel_down(self,event):
self.value -= self.resolution
if self.value < self.min_:
self.value = self.min_
# -------------------------------------------
class pyvcp_number(Label):
""" (indicator) shows a float as text """
n=0
def __init__(self,master,pycomp,halpin=None,format="2.1f",**kw):
self.v = StringVar()
self.format=format
Label.__init__(self,master,textvariable=self.v,**kw)
if halpin == None:
halpin = "number."+str(pyvcp_number.n)
pyvcp_number.n += 1
self.halpin=halpin
self.value=0.0
dummy = "%(b)"+self.format
self.v.set( str( dummy % {'b':self.value} ) )
pycomp.newpin(halpin, HAL_FLOAT, HAL_IN)
def update(self,pycomp):
newvalue = pycomp[self.halpin]
if newvalue != self.value:
self.value=newvalue
dummy = "%(b)"+self.format
self.v.set( str( dummy % {'b':newvalue} ) )
class pyvcp_u32(Label):
""" (indicator) shows a u32 as text """
n=0
def __init__(self,master,pycomp,halpin=None,format="d",**kw):
self.v = StringVar()
self.format=format
Label.__init__(self,master,textvariable=self.v,**kw)
if halpin == None:
halpin = "number."+str(pyvcp_number.n)
pyvcp_number.n += 1
self.halpin=halpin
self.value=0.0
dummy = "%(b)"+self.format
self.v.set( str( dummy % {'b':self.value} ) )
pycomp.newpin(halpin, HAL_U32, HAL_IN)
def update(self,pycomp):
newvalue = pycomp[self.halpin]
if newvalue != self.value:
self.value=newvalue
dummy = "%(b)"+self.format
self.v.set( str( dummy % {'b':newvalue} ) )
class pyvcp_s32(Label):
""" (indicator) shows a s32 as text """
n=0
def __init__(self,master,pycomp,halpin=None,format="d",**kw):
self.v = StringVar()
self.format=format
Label.__init__(self,master,textvariable=self.v,**kw)
if halpin == None:
halpin = "number."+str(pyvcp_number.n)
pyvcp_number.n += 1
self.halpin=halpin
self.value=0.0
dummy = "%(b)"+self.format
self.v.set( str( dummy % {'b':self.value} ) )
pycomp.newpin(halpin, HAL_S32, HAL_IN)
def update(self,pycomp):
newvalue = pycomp[self.halpin]
if newvalue != self.value:
self.value=newvalue
dummy = "%(b)"+self.format
self.v.set( str( dummy % {'b':newvalue} ) )
class pyvcp_timer(Label):
""" (indicator) shows elapsed time as HH:MM:SS
two pins - run and reset
time advances whenever run is true
time holds whenever run is false
time resets to zero on a rising edge of reset
"""
n=0
def __init__(self,master,pycomp,halpin=None,**kw):
self.v = StringVar()
Label.__init__(self,master,textvariable=self.v,**kw)
if halpin == None:
halpin = "timer."+str(pyvcp_timer.n)
pyvcp_timer.n += 1
self.halpins=[]
c_halpin=halpin+".reset"
pycomp.newpin(c_halpin, HAL_BIT, HAL_IN)
self.halpins.append(c_halpin)
c_halpin=halpin+".run"
pycomp.newpin(c_halpin, HAL_BIT, HAL_IN)
self.halpins.append(c_halpin)
self.resetvalue=0
self.runvalue=0
# starttime is the time of the last rising edge of 'run'
self.starttime=0
# basetime is the sum of all prior 'run=1' periods
self.basetime=0
self.currtime=0
self.v.set( "00:00:00")
def update(self,pycomp):
resetvalue = pycomp[self.halpins[0]]
runvalue = pycomp[self.halpins[1]]
if resetvalue != self.resetvalue:
self.resetvalue=resetvalue
if resetvalue == 1:
self.basetime=0
self.starttime=time.time()
if runvalue != self.runvalue:
self.runvalue=runvalue
if runvalue == 1:
# rising edge
self.starttime = time.time()
else:
# falling edge
self.basetime += time.time() - self.starttime
if runvalue == 1:
total=self.basetime + time.time() - self.starttime
else:
total=self.basetime
hr = int(total / 3600)
remainder = total - hr*3600
mn = int(remainder / 60)
sec = int(remainder - mn*60)
self.v.set( str( "%02d:%02d:%02d" % (hr,mn,sec) ) )
# -------------------------------------------
class pyvcp_bar(Canvas):
## reworked by ArcEye 10022014
## allow value ranges in different colours
""" (indicator) a bar-indicator for a float
<bar>
<halpin>"my-bar"</halpin>
<min_>0</min_>
<max_>150</max_>
<bgcolor>"grey"</bgcolor>
<range1>(0,100,"green")</range1>
<range2>(101,129,"orange")</range2>
<range3>(130,150,"red")</range3>
<fillcolor>"green"</fillcolor>
</bar>
"""
n=0
def __init__(self,master,pycomp,fillcolor="green",bgcolor="grey",
halpin=None,min_=0.0,max_=100.0,range1=None,range2=None,range3=None,**kw):
self.cw=200 # canvas width
self.ch=50 # canvas height
self.bh=30 # bar height
self.bw=150 # bar width
self.pad=((self.cw-self.bw)/2)
Canvas.__init__(self,master,width=self.cw,height=self.ch)
if halpin == None:
halpin = "bar."+str(pyvcp_bar.n)
pyvcp_bar.n += 1
self.halpin=halpin
self.endval=max_
self.startval=min_
pycomp.newpin(halpin, HAL_FLOAT, HAL_IN)
self.value=0.0 # some dummy value to start with
pycomp[self.halpin] = self.value
# the border
border=self.create_rectangle(self.pad,1,self.pad+self.bw,self.bh)
self.itemconfig(border,fill=bgcolor)
# the bar
tmp=self.bar_coords()
start=tmp[0]
end=tmp[1]
self.bar=self.create_rectangle(start,2,end,self.bh-1)
# default fill unless overriden
self.itemconfig(self.bar,fill=fillcolor)
# start text
start_text=self.create_text(self.pad,self.bh+10,text=str(self.startval) )
#end text
end_text=self.create_text(self.pad+self.bw,self.bh+10,text=str(self.endval) )
# value text
self.val_text=self.create_text(self.pad+self.bw/2,
self.bh/2,text=str(self.value) )
if range1!=None and range2!=None and range3!=None:
self.range1 = range1
self.range2 = range2
self.range3 = range3
self.ranges = True
else:
self.ranges = False
def set_fill(self, (start1, end1, color1),(start2, end2, color2), (start3, end3, color3)):
if self.value:
if (self.value > start1) and (self.value <= end1):
self.itemconfig(self.bar,fill=color1)
else:
if (self.value > start2) and (self.value <= end2):
self.itemconfig(self.bar,fill=color2)
else:
if (self.value > start3) and (self.value <= end3):
self.itemconfig(self.bar,fill=color3)
def bar_coords(self):
""" calculates the coordinates in pixels for the bar """
# the bar should start at value = zero
# and extend to value = self.value
# it should not extend beyond the initial box reserved for the bar
min_pixels=self.pad
max_pixels=self.pad+self.bw
bar_end = min_pixels + ((float)(max_pixels-min_pixels)/(float)(self.endval-self.startval)) * (self.value-self.startval)
if bar_end>max_pixels:
bar_end = max_pixels
elif bar_end < min_pixels:
bar_end = min_pixels
bar_start = min_pixels + ((float)(max_pixels-min_pixels)/(float)(self.endval-self.startval)) * (0-self.startval)
if bar_start < min_pixels: # don't know if this is really needed
bar_start = min_pixels
return [bar_start, bar_end]
def update(self,pycomp):
# update value
newvalue=pycomp[self.halpin]
if newvalue != self.value:
self.value = newvalue
valtext = str( "%(b)3.1f" % {'b':self.value} )
self.itemconfig(self.val_text,text=valtext)
# set bar colour
if self.ranges:
self.set_fill(self.range1, self.range2, self.range3)
# set bar size
tmp=self.bar_coords()
start=tmp[0]
end=tmp[1]
self.coords(self.bar, start, 2,
end, self.bh-1)
# -------------------------------------------
class pyvcp_led(Canvas):
""" (indicator) a LED
<led>
<on_color>"colorname"</on_color> Default color red
<off_color>"colorname"</off_color> Default color green
<disable_pin>True</disable_pin> Optional halpin sets led to disable_color
<disable_color>"colorname"</disable_color> Default color gray80
</led>"""
n=0
def __init__(self,master,pycomp, halpin=None,disable_pin=False,
off_color="red",on_color="green",disabled_color="gray80",size=20,**kw):
Canvas.__init__(self,master,width=size,height=size,bd=0)
self.off_color=off_color
self.on_color=on_color
self.disabled_color=disabled_color
self.disable_pin = disable_pin
self.oh=self.create_oval(1,1,size,size)
self.state = 0
self.itemconfig(self.oh,fill=off_color)
if halpin == None:
halpin = "led."+str(pyvcp_led.n)
pyvcp_led.n+=1
self.halpin=halpin
pycomp.newpin(halpin, HAL_BIT, HAL_IN)
if disable_pin:
halpin_disable = halpin+".disable"
self.halpin_disable = halpin_disable
pycomp.newpin(halpin_disable, HAL_BIT, HAL_IN)
def update(self,pycomp):
newstate = pycomp[self.halpin]
if newstate == 1:
self.itemconfig(self.oh,fill=self.on_color)
self.state=1
else:
self.itemconfig(self.oh,fill=self.off_color)
self.state=0
if self.disable_pin:
is_disabled = pycomp[self.halpin_disable]
if is_disabled == 1:
self.itemconfig(self.oh,fill=self.disabled_color)
# -------------------------------------------
class pyvcp_rectled(Canvas):
""" (indicator) a LED
<rectled>
<on_color>"colorname"</on_color> Default color red
<off_color>"colorname"</off_color> Default color green
<disable_pin>True</disable_pin> Optional halpin sets led to disable_color
<disable_color>"somecolor"</disable_color> Default color light gray
</rectled>"""
n=0
def __init__(self,master,pycomp, halpin=None,disable_pin=False,
off_color="red",on_color="green",disabled_color="gray80",height=10,width=30,**kw):
Canvas.__init__(self,master,width=width,height=height,bd=2)
self.off_color=off_color
self.on_color=on_color
self.disabled_color=disabled_color
self.disable_pin = disable_pin
self.oh=self.create_rectangle(1,1,width,height)
self.state=0
self.itemconfig(self.oh,fill=off_color)
if halpin == None:
halpin = "led."+str(pyvcp_led.n)
pyvcp_led.n+=1
self.halpin=halpin
pycomp.newpin(halpin, HAL_BIT, HAL_IN)
if disable_pin:
halpin_disable = halpin+".disable"
self.halpin_disable = halpin_disable
pycomp.newpin(halpin_disable, HAL_BIT, HAL_IN)
def update(self,pycomp):
newstate = pycomp[self.halpin]
if newstate == 1:
self.itemconfig(self.oh,fill=self.on_color)
self.state=1
else:
self.itemconfig(self.oh,fill=self.off_color)
self.state=0
if self.disable_pin:
is_disabled = pycomp[self.halpin_disable]
if is_disabled == 1:
self.itemconfig(self.oh,fill=self.disabled_color)
# -------------------------------------------
## ArcEye - the initval field is missing from the docs, so few people aware it can be preselected
## 12022014 added changepin which allows toggling of value from HAL without GUI action
class pyvcp_checkbutton(Checkbutton):
""" (control) a check button
halpin is 1 when button checked, 0 otherwise
<checkbutton>
[ <halpin>"my-checkbutton"</halpin> ]
[ <text>"Name of Button"</text>] text set in widget
[ <initval>1</initval> ] sets intial value to 1, all values >=0.5 are assumed to be 1
</checkbutton>
"""
n=0
def __init__(self,master,pycomp,halpin=None,initval=0,**kw):
self.v = BooleanVar(master)
Checkbutton.__init__(self,master,variable=self.v,onvalue=1, offvalue=0,**kw)
if halpin == None:
halpin = "checkbutton."+str(pyvcp_checkbutton.n)
self.halpin=halpin
pycomp.newpin(halpin, HAL_BIT, HAL_OUT)
changepin = halpin + ".changepin"
self.changepin=changepin
pycomp.newpin(changepin, HAL_BIT, HAL_IN)
pycomp[self.changepin] = 0
pyvcp_checkbutton.n += 1
if initval >= 0.5:
self.value=1
else:
self.value=0
self.v.set(self.value)
self.reset = 0
def update(self,pycomp):
# prevent race condition if connected to permanently on pin
if pycomp[self.changepin] and not(self.reset):
self.v.set(not(self.v.get()))
self.reset = 1
pycomp[self.changepin] = 0 # try to reset, but may not work
if not(pycomp[self.changepin]) and(self.reset):
self.reset = 0
pycomp[self.changepin] = 0 # make sure is reset now
pycomp[self.halpin]=self.v.get()
# -------------------------------------------
class pyvcp_button(Button):
""" (control) a button
halpin is 1 when button pressed, 0 otherwise
optional halpin.disable disables the button
<button>
<halpin>"name"</halpin>
<disablepin>True</disablepin>
</button>"""
n=0
def __init__(self,master,pycomp,halpin=None,disable_pin=False,**kw):
Button.__init__(self,master,**kw)
if halpin == None:
halpin = "button."+str(pyvcp_button.n)
pyvcp_button.n += 1
self.halpin=halpin
pycomp.newpin(halpin, HAL_BIT, HAL_OUT)
self.disable_pin = disable_pin
if not disable_pin == False:
halpin_disable = halpin + ".disable"
pycomp.newpin(halpin_disable, HAL_BIT, HAL_IN)
self.halpin_disable=halpin_disable
self.state=0;
self.bind("<ButtonPress>", self.pressed)
self.bind("<ButtonRelease>", self.released)
self.pycomp = pycomp
def pressed(self,event):
if self.disable_pin:
is_disabled = self.pycomp[self.halpin_disable]
if is_disabled == 1: return
self.pycomp[self.halpin]=1
def released(self,event):
if self.disable_pin:
is_disabled = self.pycomp[self.halpin_disable]
if is_disabled == 1: return
self.pycomp[self.halpin]=0
def update(self,pycomp):
if self.disable_pin:
is_disabled = pycomp[self.halpin_disable]
if is_disabled == 1: Button.config(self,state=DISABLED)
else: Button.config(self,state=NORMAL)
else:pass
# -------------------------------------------
class pyvcp_scale(Scale):
""" (control) a slider
halpin-i is integer output
halpin-f is float output
<scale>
[ <halpin>"my-scale"</halpin> ]
[ <resolution>0.1</resolution> ] scale value a whole number must end in '.'
[ <orient>HORIZONTAL</orient> ] aligns the scale horizontal
[ <min_>-33</min_> ] sets the minimum value to -33
[ <max_>26</max_> ] sets the maximum value to 26
[ <initval>10</initval> ] sets intial value to 10
[ <param_pin>1</param_pin>] creates param pin if > 0, set to initval, value can then be set externally, ArcEye 2013
</scale>
"""
# FIXME scale resolution when ctrl/alt/shift is held down?
# FIXME allow user to specify size
n=0
def __init__(self,master,pycomp,
resolution=1,halpin=None,halparam=None,min_=0,max_=10,initval=0,param_pin=0,**kw):
self.resolution=resolution
Scale.__init__(self,master,resolution=self.resolution,
from_=min_,to=max_,**kw)
if halpin == None:
halpin = "scale."+str(pyvcp_scale.n)
self.halpin=halpin
if halparam == None:
self.param_pin = param_pin
if self.param_pin == 1:
halparam = "scale."+str(pyvcp_scale.n)+".param_pin"
self.halparam=halparam
pycomp.newpin(halparam, HAL_FLOAT, HAL_IN)
pyvcp_scale.n += 1
pycomp.newpin(halpin+"-i", HAL_S32, HAL_OUT)
pycomp.newpin(halpin+"-f", HAL_FLOAT, HAL_OUT)
self.bind('<Button-4>',self.wheel_up)
self.bind('<Button-5>',self.wheel_down)
if initval < min_:
self.value=min_
elif initval > max_:
self.value=max_
else:
self.value=initval
self.set(self.value)
if self.param_pin == 1:
self.oldInit=self.value
self.init=self.value
pycomp[self.halparam] = self.value
def update(self,pycomp):
pycomp[self.halpin+"-f"]=self.get()
pycomp[self.halpin+"-i"]=int(self.get())
if self.param_pin == 1:
self.init = pycomp[self.halparam]
if self.init != self.oldInit :
self.set(self.init)
self.value=self.init
self.oldInit=self.init
def wheel_up(self,event):
self.set(self.get()+self.resolution)
def wheel_down(self,event):
self.set(self.get()-self.resolution)
class pyvcp_table(Frame):
def __init__(self, master, pycomp, flexible_rows=[], flexible_columns=[], uniform_columns="", uniform_rows=""):
Frame.__init__(self, master)
for r in flexible_rows:
self.grid_rowconfigure(r, weight=1)
for c in flexible_columns:
self.grid_columnconfigure(c, weight=1)
for i, r in enumerate(uniform_rows):
self.grid_rowconfigure(i+1, uniform=r)
for i, c in enumerate(uniform_columns):
self.grid_columnconfigure(i+1, uniform=c)
self._r = self._c = 0
self.occupied = {}
self.span = (1,1)
self.sticky = "ne"
def add(self, container, child):
if isinstance(child, pyvcp_tablerow):
self._r += 1
self._c = 1
return
elif isinstance(child, pyvcp_tablespan):
self.span = child.span
return
elif isinstance(child, pyvcp_tablesticky):
self.sticky = child.sticky
return
r, c = self._r, self._c
while self.occupied.has_key((r, c)):
c = c + 1
rs, cs = self.span
child.grid(row=r, column=c, rowspan=rs, columnspan=cs,
sticky=self.sticky)
for ri in range(r, r+rs):
for ci in range(c, c+cs):
self.occupied[ri,ci] = True
self.span = 1,1
self._c = c+cs
def update(self, pycomp): pass
class pyvcp_tablerow:
def __init__(self, master, pycomp): pass
def update(self, pycomp): pass
class pyvcp_tablespan:
def __init__(self, master, pycomp, rows=1, columns=1):
self.span = rows, columns
def update(self, pycomp): pass
class pyvcp_tablesticky:
def __init__(self, master, pycomp, sticky):
self.sticky = sticky
def update(self, pycomp): pass
class pyvcp_include(Frame):
def __init__(self, master, pycomp, src, expand="yes", fill="both", anchor="center", prefix=None, **kw):
Frame.__init__(self,master,**kw)
self.master = master
self.fill = fill
self.anchor = anchor
self.expand = expand
if prefix is not None:
oldprefix = pycomp.getprefix()
pycomp.setprefix(prefix)
import vcpparse, xml.dom.minidom, xml.parsers.expat
try:
doc = xml.dom.minidom.parse(src)
except xml.parsers.expat.ExpatError, detail:
print "Error: could not open",src,"!"
print detail
sys.exit(1)
# find the pydoc element
for e in doc.childNodes:
if e.nodeType == e.ELEMENT_NODE and e.localName == "pyvcp":
break
if e.localName != "pyvcp":
print "Error: no pyvcp element in file!"
sys.exit()
pyvcproot=e
vcpparse.nodeiterator(pyvcproot,self)
if prefix is not None:
pycomp.setprefix(oldprefix)
def update(self, pycomp): pass
def add(self, container, widget):
widget.pack(fill=self.fill, anchor=self.anchor, expand=self.expand)
class _pyvcp_dummy:
def add(self, container, widget): pass
def update(self, pycomp): pass
def pack(self, *args, **kw): pass
class pyvcp_title(_pyvcp_dummy):
def __init__(self, master, pycomp, title, iconname=None):
master.wm_title(title)
if iconname: master.wm_iconname(iconname)
class pyvcp_axisoptions(_pyvcp_dummy):
def __init__(self, master, pycomp):
import rs274.options
rs274.options.install(master)
class pyvcp_option(_pyvcp_dummy):
def __init__(self, master, pycomp, pattern, value, priority=None):
master.option_add(pattern, value, priority)
class pyvcp_image(_pyvcp_dummy):
all_images = {}
def __init__(self, master, pycomp, name, **kw):
self.all_images[name] = PhotoImage(name, kw, master)
class _pyvcp_image(Label):
def __init__(self, master, pycomp, images, halpin=None, **kw):
Label.__init__(self, master, **kw)
if isinstance(images, basestring): images = images.split()
self.images = images
if halpin == None:
halpin = "number."+str(pyvcp_number.n)
pyvcp_number.n += 1
self.halpin = halpin
self.value = 0
self.last = None
pycomp.newpin(halpin, self.pintype, HAL_IN)
def update(self, pycomp):
l = pycomp[self.halpin]
if l != self.last:
try:
self.configure(image=self.images[l])
except (IndexError, KeyError):
print >>sys.stderr, "Unknown image #%d on %s" % (l, self.halpin)
self.last = l
class pyvcp_image_bit(_pyvcp_image):
pintype = HAL_BIT
class pyvcp_image_u32(_pyvcp_image):
pintype = HAL_U32
# This must come after all the pyvcp_xxx classes
elements = []
__all__ = []
for _key in globals().keys():
if _key.startswith("pyvcp_"):
elements.append(_key[6:])
__all__.append(_key)
if __name__ == '__main__':
print "You can't run pyvcp_widgets.py by itself..."
# vim:sts=4:sw=4:et: