led.py
1 # vim: sts=4 sw=4 et 2 import gtk 3 import gobject 4 import cairo 5 import math 6 import gtk.glade 7 8 # This creates the custom LED widget 9 10 from hal_widgets import _HalSensitiveBase, hal_pin_changed_signal 11 12 class HAL_LED(gtk.DrawingArea, _HalSensitiveBase): 13 __gtype_name__ = 'HAL_LED' 14 __gsignals__ = dict([hal_pin_changed_signal]) 15 __gproperties__ = { 16 'is_on' : ( gobject.TYPE_BOOLEAN, 'Is on', 'How to display LED in editor', 17 False, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 18 'has_hal_pin' : ( gobject.TYPE_BOOLEAN, 'Create HAL pin', 'Whether to create a HAL pin', 19 True, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 20 'led_shape' : ( gobject.TYPE_INT, 'Shape', '0: round 1:oval 2:square 3:horizonal 4: vertical', 21 0, 4, 0, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 22 'led_size' : ( gobject.TYPE_INT, 'Size', 'size of LED', 23 5, 30, 10, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 24 'led_blink_rate' : ( gobject.TYPE_INT, 'Blink rate', 'Led blink rate (ms)', 25 0, 1000, 0, gobject.PARAM_READWRITE), 26 'led_shiny' : ( gobject.TYPE_BOOLEAN, 'Shiny', 'Makes the Led shiny', 27 False, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 28 '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', 29 False, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 30 'blink_when_off' : ( gobject.TYPE_BOOLEAN, 'Blink when off', 'Choose to blink while in on state (No) or off state (Yes)', 31 False, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 32 'pick_color_on' : ( gtk.gdk.Color.__gtype__, 'Pick on color', "", 33 gobject.PARAM_READWRITE), 34 'pick_color_off' : ( gtk.gdk.Color.__gtype__, 'Pick off color', "", 35 gobject.PARAM_READWRITE), 36 'pick_color_blink' : ( gtk.gdk.Color.__gtype__, 'Pick blink color', "", 37 gobject.PARAM_READWRITE), 38 'on_color' : ( gobject.TYPE_STRING, 'LED On color', 'Use any valid Gdk color', 39 "green", gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 40 'off_color' : ( gobject.TYPE_STRING, 'LED OFF color', 'Use any valid Gdk color or "dark"', 41 "red", gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT), 42 'blink_color' : ( gobject.TYPE_STRING, 'LED blink color', 'Use any valid Gdk color or "dark"', 43 "black", gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT) 44 } 45 __gproperties = __gproperties__ 46 47 def post_create(self, obj, reason): 48 print "\nhola\n" 49 50 def __init__(self): 51 super(HAL_LED, self).__init__() 52 self._dia = 10 53 self._blink_active = False 54 self._blink_state = False 55 self._blink_invert = False 56 self._blink_magic = 0 57 self.set_size_request(25, 25) 58 self.connect("expose-event", self.expose) 59 60 self.led_blink_rate = 0 61 self.pick_color_on = self.pick_color_off = self.pick_color_blink = None 62 self.on_color = 'green' 63 self.off_color = 'red' 64 self.blink_color = 'black' 65 self.has_hal_pin = True 66 67 self.set_color('on', self.on_color) 68 self.set_color('off', self.off_color) 69 self.set_color('blink', self.blink_color) 70 71 # This method draws our widget 72 # depending on self.state, self.blink_active, self.blink_state and the sensitive state of the parent 73 # sets the fill as the on or off colour. 74 def expose(self, widget, event): 75 cr = widget.window.cairo_create() 76 sensitive = self.flags() & gtk.PARENT_SENSITIVE 77 if not sensitive: alpha = .3 78 else: alpha = 1 79 cr.set_line_width(3) 80 cr.set_source_rgba(0, 0, 0, alpha) 81 82 if self.is_on: 83 if self._blink_active == False: 84 color = self._on_color 85 elif self._blink_invert == True: 86 color = self._on_color 87 elif self._blink_state == False: 88 color = self._blink_color 89 else: 90 color = self._on_color 91 92 elif self._blink_active == False: 93 color = self._off_color 94 elif self._blink_invert == False: 95 color = self._off_color 96 elif self._blink_state == True: 97 color = self._blink_color 98 else: 99 color = self._off_color 100 101 # square led 102 if self.led_shape == 2: 103 self.set_size_request(self._dia*2+5, self._dia*2+5) 104 w = self.allocation.width 105 h = self.allocation.height 106 cr.translate(w/2, h/2) 107 cr.rectangle(-self._dia, -self._dia, self._dia*2, self._dia*2) 108 cr.stroke_preserve() 109 cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha) 110 #cr.fill() 111 cr.fill_preserve() 112 113 # now make it shiny 114 if self.led_shiny: 115 #cr.rectangle(0, 0, w, h) 116 lg = cairo.LinearGradient(0, -self._dia, 0, self._dia) 117 lg.add_color_stop_rgba(0, color.red/65535., color.green/65535., color.blue/65535., alpha) 118 lg.add_color_stop_rgba(.4, 1, 1, 1, .75) 119 lg.add_color_stop_rgba(.6, color.red/65535., color.green/65535., color.blue/65535., alpha) 120 lg.add_color_stop_rgba(1, .6, .6, .6, .5) 121 cr.set_source(lg) 122 cr.fill() 123 124 # horizontal led 125 elif self.led_shape == 3: 126 self.set_size_request(self._dia*5+5, self._dia+5) 127 w = self.allocation.width 128 h = self.allocation.height 129 cr.translate(w/2, h/2) 130 cr.rectangle(-self._dia*5/2, -self._dia/2, self._dia*5, self._dia) 131 cr.stroke_preserve() 132 cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha) 133 #cr.fill() 134 cr.fill_preserve() 135 136 # now make it shiny 137 if self.led_shiny: 138 #cr.rectangle(0, 0, w, h) 139 lg = cairo.LinearGradient(0, -self._dia, 0, self._dia) 140 lg.add_color_stop_rgba(0, color.red/65535., color.green/65535., color.blue/65535., alpha) 141 lg.add_color_stop_rgba(.4, 1, 1, 1, .75) 142 lg.add_color_stop_rgba(.6, color.red/65535., color.green/65535., color.blue/65535., alpha) 143 lg.add_color_stop_rgba(1, .6, .6, .6, .5) 144 cr.set_source(lg) 145 cr.fill() 146 147 # vertical led 148 elif self.led_shape == 4: 149 self.set_size_request(self._dia+5, self._dia*5+5) 150 w = self.allocation.width 151 h = self.allocation.height 152 cr.translate(w/2, h/2) 153 cr.rectangle(-self._dia/2, -self._dia*5/2, self._dia, self._dia*5) 154 cr.stroke_preserve() 155 cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha) 156 #cr.fill() 157 cr.fill_preserve() 158 159 # now make it shiny 160 if self.led_shiny: 161 #cr.rectangle(0, 0, w, h) 162 lg = cairo.LinearGradient(0, -self._dia, 0, self._dia) 163 lg.add_color_stop_rgba(0, color.red/65535., color.green/65535., color.blue/65535., alpha) 164 lg.add_color_stop_rgba(.3, 1, 1, 1, .75) 165 lg.add_color_stop_rgba(.7, color.red/65535., color.green/65535., color.blue/65535., alpha) 166 lg.add_color_stop_rgba(1, .6, .6, .6, .5) 167 cr.set_source(lg) 168 cr.fill() 169 170 171 # oval led 172 elif self.led_shape == 1: 173 if self.led_shiny: 174 self.set_size_request(self._dia*2+5, self._dia*2) 175 w = self.allocation.width 176 h = self.allocation.height 177 cr.translate(w/2, h/2) 178 cr.scale( 1, 0.7); 179 180 radius = self._dia 181 linewidth = math.sqrt(radius) * 1.25 182 cr.set_line_width(linewidth) 183 184 #cr.arc(0, 0, radius-(linewidth/4), 0, 2*math.pi) 185 cr.arc(0, 0, radius, 0, 2*math.pi) 186 r0 = cairo.RadialGradient(0, 0, radius-(linewidth/2), 0, 0, radius+(linewidth/2)) 187 r0.add_color_stop_rgb(0, .75, .75, .75) 188 r0.add_color_stop_rgb(1.0, .15, .15, .15) 189 cr.set_source(r0) 190 cr.stroke_preserve() 191 192 r1 = cairo.RadialGradient(0, 0, radius/8, 0, 0, radius) 193 r1.add_color_stop_rgb(0.4, color.red/65535., color.green/65535., color.blue/65535.) 194 r1.add_color_stop_rgb(0.95, color.red/65535.*0.85, color.green/65535.*0.85, color.blue/65535.*0.85) 195 r1.add_color_stop_rgb(1.0, color.red/65535., color.green/65535., color.blue/65535.) 196 cr.set_source(r1) 197 cr.fill() 198 199 cr.arc(0, 0, radius, 0, 2*math.pi) 200 if self.is_on or self.led_bicolor: 201 r2 = cairo.RadialGradient(0, 0, 0, 0, 0, radius) 202 #r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius) 203 else: 204 r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius/2 - radius/8) 205 r2.add_color_stop_rgba(0, 1, 1, 1, 1) 206 r2.add_color_stop_rgba(1, 1, 1, 1, 0) 207 cr.set_source(r2) 208 cr.fill() 209 else: 210 self.set_size_request(self._dia*2+5, self._dia*2) 211 w = self.allocation.width 212 h = self.allocation.height 213 cr.translate(w/2, h/2) 214 cr.scale( 1, 0.7); 215 cr.arc(0, 0, self._dia, 0, 2*math.pi) 216 cr.stroke_preserve() 217 cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha) 218 cr.fill() 219 220 # round led 221 else: 222 if self.led_shiny: 223 self.set_size_request(self._dia*2+5, self._dia*2+5) 224 w = self.allocation.width 225 h = self.allocation.height 226 cr.translate(w/2, h/2) 227 228 radius = self._dia 229 linewidth = math.sqrt(radius) * 1.25 230 cr.set_line_width(linewidth) 231 232 #cr.arc(0, 0, radius-(linewidth/4), 0, 2*math.pi) 233 cr.arc(0, 0, radius, 0, 2*math.pi) 234 r0 = cairo.RadialGradient(0, 0, radius-(linewidth/2), 0, 0, radius+(linewidth/2)) 235 r0.add_color_stop_rgb(0, .75, .75, .75) 236 r0.add_color_stop_rgb(1.0, .15, .15, .15) 237 cr.set_source(r0) 238 cr.stroke_preserve() 239 240 r1 = cairo.RadialGradient(0, 0, radius/8, 0, 0, radius) 241 r1.add_color_stop_rgb(0.4, color.red/65535., color.green/65535., color.blue/65535.) 242 r1.add_color_stop_rgb(0.95, color.red/65535.*0.85, color.green/65535.*0.85, color.blue/65535.*0.85) 243 r1.add_color_stop_rgb(1.0, color.red/65535., color.green/65535., color.blue/65535.) 244 cr.set_source(r1) 245 cr.fill() 246 247 cr.arc(0, 0, radius, 0, 2*math.pi) 248 if self.is_on or self.led_bicolor: 249 r2 = cairo.RadialGradient(0, 0, 0, 0, 0, radius) 250 #r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius) 251 else: 252 r2 = cairo.RadialGradient(-radius/6, -radius/6, 0, -radius/6, -radius/6, radius/2 - radius/8) 253 r2.add_color_stop_rgba(0, 1, 1, 1, 1) 254 r2.add_color_stop_rgba(1, 1, 1, 1, 0) 255 cr.set_source(r2) 256 cr.fill() 257 else: 258 self.set_size_request(self._dia*2+5, self._dia*2+5) 259 w = self.allocation.width 260 h = self.allocation.height 261 cr.translate(w/2, h/2) 262 lg2 = cairo.RadialGradient(0, 0, self._dia-2, 0, 0, self._dia+1) 263 lg2.add_color_stop_rgba(0.0, 0., 0., 0., 0.) 264 lg2.add_color_stop_rgba(.99, 0., 0., 0., 1.) 265 lg2.add_color_stop_rgba(1.0, 0., 0., 0., 0.) 266 cr.arc(0, 0, self._dia, 0, 2*math.pi) 267 cr.mask(lg2) 268 cr.stroke_preserve() 269 cr.set_source_rgba(color.red/65535., color.green/65535., color.blue/65535., alpha) 270 cr.fill() 271 272 return False 273 274 # This sets the LED on or off color 275 # and then redraws it 276 # Usage: ledname.set_active(True) 277 def set_active(self, data): 278 self.is_on = data 279 self.queue_draw() 280 281 def set_sensitive(self, data ): 282 self.set_active(data) 283 284 #FIXME the gobject timers are never explicly destroyed 285 def set_blink_rate(self,rate): 286 if rate == 0: 287 self._blink_active = False 288 else: 289 if rate < 100:rate = 100 290 self._blink_active = True 291 self._blink_magic += 1 292 self._blink_timer = gobject.timeout_add(rate, self.blink, self._blink_magic) 293 294 def blink(self, magic=None): 295 if not self._blink_active: 296 return False 297 if magic is not None and self._blink_magic != magic: 298 return False 299 if self._blink_state == True: 300 self._blink_state = False 301 else: self._blink_state = True 302 self.queue_draw() 303 return True # keep running this event 304 305 # This allows setting of the on and off colour 306 # red,green and blue are float numbers beteen 0 and 1 307 # if color = None uses colorname. only a few names supported 308 # Usage: ledname.set_color("off",[r,g,b],"colorname") 309 def set_color(self, state, color): 310 if isinstance(color, gtk.gdk.Color): 311 pass 312 elif color != 'dark': 313 color = gtk.gdk.Color(color) 314 else: 315 r = 0.4 * self._on_color.red 316 g = 0.4 * self._on_color.green 317 b = 0.4 * self._on_color.blue 318 color = gtk.gdk.Color(int(r), int(g), int(b)) 319 if state == "off": 320 self._off_color = color 321 elif state == "on": 322 self._on_color = color 323 elif state == "blink": 324 self._blink_color = color 325 326 if state == 'on' and getattr(self, 'off_color') == 'dark': 327 self.set_color('off', 'dark') 328 329 # This alows setting the diameter of the LED 330 # Usage: ledname.set_dia(10) 331 def set_dia(self, dia): 332 self._dia = dia 333 self.queue_draw() 334 335 # This sets the shape round oval or square 336 def set_shape(self, shape): 337 self.led_shape = shape 338 self.queue_draw() 339 340 def do_get_property(self, property): 341 name = property.name.replace('-', '_') 342 if name == 'led_size': 343 return self._dia 344 elif name in self.__gproperties.keys(): 345 return getattr(self, name) 346 else: 347 raise AttributeError('unknown property %s' % property.name) 348 349 def do_set_property(self, property, value): 350 name = property.name.replace('-', '_') 351 if name in ['on_color', 'off_color','blink_color']: 352 mode = name.split('_')[0] 353 if getattr(self, 'pick_color_%s' % mode, None): 354 return False 355 try: 356 self.set_color(mode, value) 357 except: 358 print "Invalid %s color value: %s" % (mode, value) 359 return False 360 elif name in ['pick_color_on', 'pick_color_off','pick_color_blink']: 361 mode = name.split('_')[-1] 362 if not value: 363 return False 364 self.set_color(mode, value) 365 elif name == 'led_blink_rate': 366 self.set_blink_rate(value) 367 elif name == 'blink_when_off': 368 self._blink_invert = value 369 if name == 'led_size': 370 self._dia = value 371 elif name in self.__gproperties.keys(): 372 setattr(self, name, value) 373 else: 374 raise AttributeError('unknown property %s' % property.name) 375 self.queue_draw() 376 return True 377 378 def _hal_init(self): 379 if self.has_hal_pin: 380 _HalSensitiveBase._hal_init(self) 381 self.set_color('on', self.pick_color_on or self.on_color) 382 self.set_color('off', self.pick_color_off or self.off_color) 383 self.set_color('blink', self.pick_color_blink or self.blink_color) 384 if self.led_blink_rate>100: 385 self.set_blink_rate(self.led_blink_rate)