391 lines
17 KiB
Python
391 lines
17 KiB
Python
# vim: sts=4 sw=4 et
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk
|
|
from gi.repository import GObject
|
|
from gi.repository import Gdk
|
|
from gi.repository import GLib
|
|
import cairo
|
|
import math
|
|
|
|
# This creates the custom LED widget
|
|
|
|
if __name__ == "__main__":
|
|
from hal_widgets import _HalSensitiveBase, hal_pin_changed_signal
|
|
else:
|
|
from .hal_widgets import _HalSensitiveBase, hal_pin_changed_signal
|
|
|
|
class HAL_LED(Gtk.DrawingArea, _HalSensitiveBase):
|
|
__gtype_name__ = 'HAL_LED'
|
|
__gsignals__ = dict([hal_pin_changed_signal])
|
|
__gproperties__ = {
|
|
'is_on' : ( GObject.TYPE_BOOLEAN, 'Is on', 'How to display LED in editor',
|
|
False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'has_hal_pin' : ( GObject.TYPE_BOOLEAN, 'Create HAL pin', 'Whether to create a HAL pin',
|
|
True, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'led_shape' : ( GObject.TYPE_INT, 'Shape', '0: round 1:oval 2:square 3:horizontal 4: vertical',
|
|
0, 4, 0, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'led_size' : ( GObject.TYPE_INT, 'Size', 'size of LED',
|
|
5, 30, 10, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'led_blink_rate' : ( GObject.TYPE_INT, 'Blink rate', 'Led blink rate (ms)',
|
|
0, 1000, 0, GObject.ParamFlags.READWRITE),
|
|
'led_shiny' : ( GObject.TYPE_BOOLEAN, 'Shiny', 'Makes the Led shiny',
|
|
False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'led_bicolor' : ( GObject.TYPE_BOOLEAN, 'Bi-Color', 'If the Led is shiny, true tells it that the (off) state is actually (on) and should be shiny too',
|
|
False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'blink_when_off' : ( GObject.TYPE_BOOLEAN, 'Blink when off', 'Choose to blink while in on state (No) or off state (Yes)',
|
|
False, GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'pick_color_on' : ( Gdk.Color.__gtype__, 'Pick on color', "",
|
|
GObject.ParamFlags.READWRITE),
|
|
'pick_color_off' : ( Gdk.Color.__gtype__, 'Pick off color', "",
|
|
GObject.ParamFlags.READWRITE),
|
|
'pick_color_blink' : ( Gdk.Color.__gtype__, 'Pick blink color', "",
|
|
GObject.ParamFlags.READWRITE),
|
|
'on_color' : ( GObject.TYPE_STRING, 'LED On color', 'Use any valid Gdk color',
|
|
"green", GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'off_color' : ( GObject.TYPE_STRING, 'LED OFF color', 'Use any valid Gdk color or "dark"',
|
|
"red", GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT),
|
|
'blink_color' : ( GObject.TYPE_STRING, 'LED blink color', 'Use any valid Gdk color or "dark"',
|
|
"black", GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT)
|
|
}
|
|
__gproperties = __gproperties__
|
|
|
|
def post_create(self, obj, reason):
|
|
print("\nhola\n")
|
|
|
|
def __init__(self):
|
|
super(HAL_LED, self).__init__()
|
|
self._dia = 10
|
|
self._blink_active = False
|
|
self._blink_state = False
|
|
self._blink_invert = False
|
|
self._blink_magic = 0
|
|
self.set_size_request(25, 25)
|
|
self.connect("draw", self.expose)
|
|
|
|
self.led_blink_rate = 0
|
|
self.pick_color_on = self.pick_color_off = self.pick_color_blink = None
|
|
self.on_color = 'green'
|
|
self.off_color = 'red'
|
|
self.blink_color = 'black'
|
|
self.has_hal_pin = True
|
|
|
|
self.set_color('on', self.on_color)
|
|
self.set_color('off', self.off_color)
|
|
self.set_color('blink', self.blink_color)
|
|
|
|
# This method draws our widget
|
|
# depending on self.state, self.blink_active, self.blink_state and the sensitive state of the parent
|
|
# sets the fill as the on or off colour.
|
|
def expose(self, widget, event):
|
|
cr = widget.get_property('window').cairo_create()
|
|
sensitive = self.is_sensitive()
|
|
if not sensitive: alpha = .3
|
|
else: alpha = 1
|
|
cr.set_line_width(3)
|
|
cr.set_source_rgba(0, 0, 0, alpha)
|
|
|
|
if self.is_on:
|
|
if self._blink_active == False:
|
|
color = self._on_color
|
|
elif self._blink_invert == True:
|
|
color = self._on_color
|
|
elif self._blink_state == False:
|
|
color = self._blink_color
|
|
else:
|
|
color = self._on_color
|
|
|
|
elif self._blink_active == False:
|
|
color = self._off_color
|
|
elif self._blink_invert == False:
|
|
color = self._off_color
|
|
elif self._blink_state == True:
|
|
color = self._blink_color
|
|
else:
|
|
color = self._off_color
|
|
|
|
# square led
|
|
if self.led_shape == 2:
|
|
self.set_size_request(self._dia*2+5, self._dia*2+5)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
cr.rectangle(-self._dia, -self._dia, self._dia*2, self._dia*2)
|
|
cr.stroke_preserve()
|
|
cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
#cr.fill()
|
|
cr.fill_preserve()
|
|
|
|
# now make it shiny
|
|
if self.led_shiny:
|
|
#cr.rectangle(0, 0, w, h)
|
|
lg = cairo.LinearGradient(0, -self._dia, 0, self._dia)
|
|
lg.add_color_stop_rgba(0, color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
lg.add_color_stop_rgba(.4, 1, 1, 1, .75)
|
|
lg.add_color_stop_rgba(.6, color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
lg.add_color_stop_rgba(1, .6, .6, .6, .5)
|
|
cr.set_source(lg)
|
|
cr.fill()
|
|
|
|
# horizontal led
|
|
elif self.led_shape == 3:
|
|
self.set_size_request(self._dia*5+5, self._dia+5)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
cr.rectangle(-self._dia*5/2, -self._dia/2, self._dia*5, self._dia)
|
|
cr.stroke_preserve()
|
|
cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
#cr.fill()
|
|
cr.fill_preserve()
|
|
|
|
# now make it shiny
|
|
if self.led_shiny:
|
|
#cr.rectangle(0, 0, w, h)
|
|
lg = cairo.LinearGradient(0, -self._dia, 0, self._dia)
|
|
lg.add_color_stop_rgba(0, color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
lg.add_color_stop_rgba(.4, 1, 1, 1, .75)
|
|
lg.add_color_stop_rgba(.6, color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
lg.add_color_stop_rgba(1, .6, .6, .6, .5)
|
|
cr.set_source(lg)
|
|
cr.fill()
|
|
|
|
# vertical led
|
|
elif self.led_shape == 4:
|
|
self.set_size_request(self._dia+5, self._dia*5+5)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
cr.rectangle(-self._dia/2, -self._dia*5/2, self._dia, self._dia*5)
|
|
cr.stroke_preserve()
|
|
cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
#cr.fill()
|
|
cr.fill_preserve()
|
|
|
|
# now make it shiny
|
|
if self.led_shiny:
|
|
#cr.rectangle(0, 0, w, h)
|
|
lg = cairo.LinearGradient(0, -self._dia, 0, self._dia)
|
|
lg.add_color_stop_rgba(0, color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
lg.add_color_stop_rgba(.3, 1, 1, 1, .75)
|
|
lg.add_color_stop_rgba(.7, color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
lg.add_color_stop_rgba(1, .6, .6, .6, .5)
|
|
cr.set_source(lg)
|
|
cr.fill()
|
|
|
|
|
|
# oval led
|
|
elif self.led_shape == 1:
|
|
if self.led_shiny:
|
|
self.set_size_request(self._dia*2+5, self._dia*2)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
cr.scale( 1, 0.7);
|
|
|
|
radius = self._dia
|
|
linewidth = math.sqrt(radius) * 1.25
|
|
cr.set_line_width(linewidth)
|
|
|
|
#cr.arc(0, 0, radius-(linewidth/4), 0, 2*math.pi)
|
|
cr.arc(0, 0, radius, 0, 2*math.pi)
|
|
r0 = cairo.RadialGradient(0, 0, radius-(linewidth/2), 0, 0, radius+(linewidth/2))
|
|
r0.add_color_stop_rgb(0, .75, .75, .75)
|
|
r0.add_color_stop_rgb(1.0, .15, .15, .15)
|
|
cr.set_source(r0)
|
|
cr.stroke_preserve()
|
|
|
|
r1 = cairo.RadialGradient(0, 0, radius/8, 0, 0, radius)
|
|
r1.add_color_stop_rgb(0.4, color.red/65535., color.green/65535., color.blue/65535.)
|
|
r1.add_color_stop_rgb(0.95, color.red/65535.*0.85, color.green/65535.*0.85, color.blue/65535.*0.85)
|
|
r1.add_color_stop_rgb(1.0, color.red/65535., color.green/65535., color.blue/65535.)
|
|
cr.set_source(r1)
|
|
cr.fill()
|
|
|
|
cr.arc(0, 0, radius, 0, 2*math.pi)
|
|
if self.is_on or self.led_bicolor:
|
|
r2 = cairo.RadialGradient(0, 0, 0, 0, 0, radius)
|
|
#r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius)
|
|
else:
|
|
r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius/2 - radius/8)
|
|
r2.add_color_stop_rgba(0, 1, 1, 1, 1)
|
|
r2.add_color_stop_rgba(1, 1, 1, 1, 0)
|
|
cr.set_source(r2)
|
|
cr.fill()
|
|
else:
|
|
self.set_size_request(self._dia*2+5, self._dia*2)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
cr.scale( 1, 0.7);
|
|
cr.arc(0, 0, self._dia, 0, 2*math.pi)
|
|
cr.stroke_preserve()
|
|
cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
cr.fill()
|
|
|
|
# round led
|
|
else:
|
|
if self.led_shiny:
|
|
self.set_size_request(self._dia*2+5, self._dia*2+5)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
|
|
radius = self._dia
|
|
linewidth = math.sqrt(radius) * 1.25
|
|
cr.set_line_width(linewidth)
|
|
|
|
#cr.arc(0, 0, radius-(linewidth/4), 0, 2*math.pi)
|
|
cr.arc(0, 0, radius, 0, 2*math.pi)
|
|
r0 = cairo.RadialGradient(0, 0, radius-(linewidth/2), 0, 0, radius+(linewidth/2))
|
|
r0.add_color_stop_rgb(0, .75, .75, .75)
|
|
r0.add_color_stop_rgb(1.0, .15, .15, .15)
|
|
cr.set_source(r0)
|
|
cr.stroke_preserve()
|
|
|
|
r1 = cairo.RadialGradient(0, 0, radius/8, 0, 0, radius)
|
|
r1.add_color_stop_rgb(0.4, color.red/65535., color.green/65535., color.blue/65535.)
|
|
r1.add_color_stop_rgb(0.95, color.red/65535.*0.85, color.green/65535.*0.85, color.blue/65535.*0.85)
|
|
r1.add_color_stop_rgb(1.0, color.red/65535., color.green/65535., color.blue/65535.)
|
|
cr.set_source(r1)
|
|
cr.fill()
|
|
|
|
cr.arc(0, 0, radius, 0, 2*math.pi)
|
|
if self.is_on or self.led_bicolor:
|
|
r2 = cairo.RadialGradient(0, 0, 0, 0, 0, radius)
|
|
#r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius)
|
|
else:
|
|
r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius/2 - radius/8)
|
|
r2.add_color_stop_rgba(0, 1, 1, 1, 1)
|
|
r2.add_color_stop_rgba(1, 1, 1, 1, 0)
|
|
cr.set_source(r2)
|
|
cr.fill()
|
|
else:
|
|
self.set_size_request(self._dia*2+5, self._dia*2+5)
|
|
w = self.get_allocated_width()
|
|
h = self.get_allocated_height()
|
|
cr.translate(w/2, h/2)
|
|
lg2 = cairo.RadialGradient(0, 0, self._dia-2, 0, 0, self._dia+1)
|
|
lg2.add_color_stop_rgba(0.0, 0., 0., 0., 0.)
|
|
lg2.add_color_stop_rgba(.99, 0., 0., 0., 1.)
|
|
lg2.add_color_stop_rgba(1.0, 0., 0., 0., 0.)
|
|
cr.arc(0, 0, self._dia, 0, 2*math.pi)
|
|
cr.mask(lg2)
|
|
cr.stroke_preserve()
|
|
cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha)
|
|
cr.fill()
|
|
|
|
return False
|
|
|
|
# This sets the LED on or off color
|
|
# and then redraws it
|
|
# Usage: ledname.set_active(True)
|
|
def set_active(self, data):
|
|
self.is_on = data
|
|
self.queue_draw()
|
|
|
|
def set_sensitive(self, data ):
|
|
self.set_active(data)
|
|
|
|
#FIXME the GObject timers are never explicly destroyed
|
|
def set_blink_rate(self,rate):
|
|
if rate == 0:
|
|
self._blink_active = False
|
|
else:
|
|
if rate < 100:rate = 100
|
|
self._blink_active = True
|
|
self._blink_magic += 1
|
|
self._blink_timer = GLib.timeout_add(rate, self.blink, self._blink_magic)
|
|
|
|
def blink(self, magic=None):
|
|
if not self._blink_active:
|
|
return False
|
|
if magic is not None and self._blink_magic != magic:
|
|
return False
|
|
if self._blink_state == True:
|
|
self._blink_state = False
|
|
else: self._blink_state = True
|
|
self.queue_draw()
|
|
return True # keep running this event
|
|
|
|
# This allows setting of the on and off colour
|
|
# red,green and blue are float numbers between 0 and 1
|
|
# if color = None uses colorname. only a few names supported
|
|
# Usage: ledname.set_color("off",[r,g,b],"colorname")
|
|
def set_color(self, state, color):
|
|
if isinstance(color, Gdk.Color):
|
|
pass
|
|
elif color != 'dark':
|
|
color = Gdk.Color.parse(color)[1]
|
|
else:
|
|
r = 0.4 * self._on_color.red
|
|
g = 0.4 * self._on_color.green
|
|
b = 0.4 * self._on_color.blue
|
|
color = Gdk.Color(int(r), int(g), int(b))
|
|
if state == "off":
|
|
self._off_color = color
|
|
elif state == "on":
|
|
self._on_color = color
|
|
elif state == "blink":
|
|
self._blink_color = color
|
|
|
|
if state == 'on' and getattr(self, 'off_color') == 'dark':
|
|
self.set_color('off', 'dark')
|
|
|
|
# This allows setting the diameter of the LED
|
|
# Usage: ledname.set_dia(10)
|
|
def set_dia(self, dia):
|
|
self._dia = dia
|
|
self.queue_draw()
|
|
|
|
# This sets the shape round oval or square
|
|
def set_shape(self, shape):
|
|
self.led_shape = shape
|
|
self.queue_draw()
|
|
|
|
def do_get_property(self, property):
|
|
name = property.name.replace('-', '_')
|
|
if name == 'led_size':
|
|
return self._dia
|
|
elif name in list(self.__gproperties.keys()):
|
|
return getattr(self, name)
|
|
else:
|
|
raise AttributeError('unknown property %s' % property.name)
|
|
|
|
def do_set_property(self, property, value):
|
|
name = property.name.replace('-', '_')
|
|
if name in ['on_color', 'off_color','blink_color']:
|
|
mode = name.split('_')[0]
|
|
if getattr(self, 'pick_color_%s' % mode, None):
|
|
return False
|
|
try:
|
|
self.set_color(mode, value)
|
|
except:
|
|
print("Invalid %s color value: %s" % (mode, value))
|
|
return False
|
|
elif name in ['pick_color_on', 'pick_color_off','pick_color_blink']:
|
|
mode = name.split('_')[-1]
|
|
if not value:
|
|
return False
|
|
self.set_color(mode, value)
|
|
elif name == 'led_blink_rate':
|
|
self.set_blink_rate(value)
|
|
elif name == 'blink_when_off':
|
|
self._blink_invert = value
|
|
if name == 'led_size':
|
|
self._dia = value
|
|
elif name in list(self.__gproperties.keys()):
|
|
setattr(self, name, value)
|
|
else:
|
|
raise AttributeError('unknown property %s' % property.name)
|
|
self.queue_draw()
|
|
return True
|
|
|
|
def _hal_init(self):
|
|
if self.has_hal_pin:
|
|
_HalSensitiveBase._hal_init(self)
|
|
self.set_color('on', self.pick_color_on or self.on_color)
|
|
self.set_color('off', self.pick_color_off or self.off_color)
|
|
self.set_color('blink', self.pick_color_blink or self.blink_color)
|
|
if self.led_blink_rate>100:
|
|
self.set_blink_rate(self.led_blink_rate)
|