/ lib / python / gladevcp / led.py
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)