#!/usr/bin/env python
# coding=UTF-8
-#
+#
# Copyright (C) 2010 Stefanos Harhalakis
#
# This file is part of wifieye.
#import config
import apps
+# Background surface for icons
+iconbg=None
+
+# Load an icon
+# Fall-back to default/blue if not found or name==None
def getIcon(name, iconsize):
- ico=getIconPath(name, iconsize)
+ # Default icon
+ idef='tasklaunch_default_application'
+
+ # If name==None then use the default icon
+ if name==None or name=='':
+ iname=idef
+ else:
+ iname=name
+
+ ico=getIconPath(iname, iconsize)
+
+ # If not found then use the default icon
+ if ico==None:
+ ico=getIconPath(idef, iconsize)
+
ret=gtk.gdk.pixbuf_new_from_file_at_size(ico, iconsize, iconsize)
return(ret)
self.name=None
self.icon=None
+ self.sicon=None
self.lastpress=0
self.ispressed=False
self.clickcount=0
+ self.angle=0
+
+ self.cached_icons={}
+
def timePressed(self):
""" return how much time a button is pressed """
dt=time.time() - self.lastpress
if dt==None:
self.name=None
self.icon=None
+ self.sicon=None
else:
self.name=dt['id']
self.icon=dt['icon2']
+ self.sicon=None
+ self.clearAnimationCache()
self.invalidate()
+ def clearAnimationCache(self):
+ self.cached_icons={}
+
def getSize(self):
return(self.config.iconsize+self.config.iconspace)
- def draw(self, cr, x, y, mode):
- self.x=x
- self.y=y
+ def setAngle(self, angle):
+ """ Set the angle. Return True if the angle changed or False if it
+ didn't. The caller should invalidate the icon """
- if self.icon==None and not self.isconfig:
- return
+ # The step in degrees
+ step=9
- cr.save()
- cr.set_source_rgba(0.1, 0.1, 0.1, 1)
+ angle2=int(angle/step)*step
+
+ if angle2==self.angle:
+ return(False)
+
+ self.angle=angle2
+
+ # The caller should be responsible for redrawing.
+ # If we call invalidate() here there is the risk of having
+ # icons rotate individually using different angles
+# self.invalidate()
+
+ return(True)
+
+ def mkbg(self, t_pressed):
+ """ Create the background of the icon and cache it as a global
+ variable among all icons and widget instances """
+ global iconbg
+
+ if iconbg!=None and t_pressed<=0.001:
+ return(iconbg)
+
+ w=self.config.iconsize + self.config.iconspace
+ s=cairo.ImageSurface(cairo.FORMAT_ARGB32, w, w)
+ cr0=cairo.Context(s)
+ cr=gtk.gdk.CairoContext(cr0)
+
+ cr.set_source_rgba(0.1, 0.1, 0.1, 1)
cr.set_line_width(5)
#if self.ispressed:
- if self.timePressed() <= self.presstime or self.ispressed:
- t=1.0 * min(self.timePressed(), self.presstime) / self.presstime
+ if t_pressed>0.001 and \
+ (t_pressed <= self.presstime or self.ispressed):
+ t=1.0 * min(t_pressed, self.presstime) / self.presstime
g=0.3+0.5*t
b=0.3+0.7*t
cr.set_source_rgba(0, g, b, 0.7)
else:
cr.set_source_rgba(0.3, 0.3, 0.3, 0.7)
+ x=0
+ y=0
x3=x + (self.config.iconspace/6)
y3=y + (self.config.iconspace/6)
cr.fill()
cr.clip()
cr.paint()
- cr.restore()
+# cr.restore()
- if self.icon==None:
- return
+ if t_pressed<0.001:
+ iconbg=s
+
+ return(s)
+
+ def get_sicon(self):
+ """ Return the icon as a surface. Cache it. """
+ if self.sicon!=None:
+ return(self.sicon)
+
+ w=self.config.iconsize
+ s=cairo.ImageSurface(cairo.FORMAT_ARGB32, w, w)
+ cr0=cairo.Context(s)
+ cr=gtk.gdk.CairoContext(cr0)
+
+ cr.set_source_pixbuf(self.icon, 0, 0)
+ cr.paint()
- icon=self.icon
+ self.sicon=s
- if mode=='l':
- icon2=icon
+ return(s)
+
+ def get_paint_icon(self):
+ """ Return the icon to paint as a surface. The icon is rotated
+ as needed. The result is cached. """
+ angle=self.angle
+
+ if self.timePressed() <= self.presstime or self.ispressed:
+ t=self.timePressed()
+ pressed=True
else:
- icon2=icon.rotate_simple(gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
+ t=0
+ pressed=False
+
+ if not pressed and self.cached_icons.has_key(angle):
+ return(self.cached_icons[angle])
+ w=self.config.iconsize + self.config.iconspace
+ s=cairo.ImageSurface(cairo.FORMAT_ARGB32, w, w)
+ cr0=cairo.Context(s)
+ cr=gtk.gdk.CairoContext(cr0)
+
+ # Paint the background
+ s2=self.mkbg(t)
cr.save()
- x3=x + (self.config.iconspace/2)
- y3=y + (self.config.iconspace/2)
- cr.set_source_pixbuf(icon2, x3, y3)
+ cr.set_source_surface(s2, 0, 0)
cr.paint()
cr.restore()
+ # If there is no icon then don't do anything more
+ if self.icon!=None:
+ # Get the icon as a surface (get_sicon() will cache the surface)
+ sicon=self.get_sicon()
+
+ # Width is the iconsize plus the empty border around the icon
+ #w=self.config.iconsize + self.config.iconspace
+
+ # This is used to locate the center of the surface
+ dx=int(w/2)
+
+ # This is the delta from the center where icons are drawn
+ dx2=int(self.config.iconsize/2)
+
+# cr.save()
+
+ # A transformation matrix with dx/dy set to point to the center
+ m=cairo.Matrix(1, 0, 0, 1, dx, dx)
+ cr.set_matrix(m)
+ # Transform degrees to rads
+ rot=-1 * pi * 2 * self.angle / 360
+ cr.rotate(rot)
+ # Draw the icon
+ cr.set_source_surface(sicon, -dx2, -dx2) # Faster than pixbuf
+# cr.set_source_pixbuf(icon2, -dx2, -dx2)
+ cr.paint()
+
+# cr.restore()
+
+ if not pressed:
+ self.cached_icons[angle]=s
+
+ return(s)
+
+
+ def draw(self, cr, x, y):
+ self.draw_queued=False
+ self.x=x
+ self.y=y
+
+ if self.icon==None and not self.isconfig:
+ return
+
+ cr.save()
+ s=self.get_paint_icon()
+ cr.set_source_surface(s, x, y)
+ cr.paint()
+
+ cr.restore()
+
return(False)
def timerPressed(self):
def doCancel(self):
self.ispressed=False
+ def setWindow(self, window):
+ self.window=window
+
def invalidate(self, window=None):
if window==None:
window=self.window
else:
self.window=window
-
+
if window==None:
return
+ if self.draw_queued:
+ print "queued"
+ return
+ self.draw_queued=True
w=self.config.iconsize + self.config.iconspace
rect=gdk.Rectangle(self.x, self.y, w, w)
gdk.Window.invalidate_rect(window, rect, True)