Added animation for icon rotation.
[drlaunch] / src / icon.py
1 #!/usr/bin/env python
2 # coding=UTF-8
3
4 # Copyright (C) 2010 Stefanos Harhalakis
5 #
6 # This file is part of wifieye.
7 #
8 # wifieye is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # wifieye is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with wifieye.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 # $Id: 0.py 2265 2010-02-21 19:16:26Z v13 $
22
23 __version__ = "$Id: 0.py 2265 2010-02-21 19:16:26Z v13 $"
24
25 import gtk
26 import gobject
27 import hildon
28 from hildondesktop import *
29 from gtk import gdk
30 from math import pi
31 import cairo
32 import time
33
34 from portrait import FremantleRotation
35 import launcher
36 from xdg.IconTheme import getIconPath
37
38
39 #import config
40 import apps
41
42 # Load an icon
43 # Fall-back to default/blue if not found or name==None
44 def getIcon(name, iconsize):
45     # Default icon
46     idef='tasklaunch_default_application'
47
48     # If name==None then use the default icon
49     if name==None or name=='':
50         iname=idef
51     else:
52         iname=name
53
54     ico=getIconPath(iname, iconsize)
55
56     # If not found then use the default icon
57     if ico==None:
58         ico=getIconPath(idef, iconsize)
59
60     ret=gtk.gdk.pixbuf_new_from_file_at_size(ico, iconsize, iconsize)
61
62     return(ret)
63
64 class Icon(gobject.GObject):
65     def __init__(self, isconfig, config):
66         self.__gobject_init__()
67
68         self.isconfig=isconfig
69         self.config=config
70
71         self.name=None
72         self.icon=None
73         self.lastpress=0
74         self.ispressed=False
75
76         self.x=0
77         self.y=0
78
79         self.presstime=0.25
80
81         self.window=None
82
83         self.clickcount=0
84
85         self.angle=0
86
87     def timePressed(self):
88         """ return how much time a button is pressed """
89         dt=time.time() - self.lastpress
90
91         return(dt)
92
93     def setApp(self, dt):
94         if dt==None:
95             self.name=None
96             self.icon=None
97         else:
98             self.name=dt['id']
99             self.icon=dt['icon2']
100         self.invalidate()
101
102     def getSize(self):
103         return(self.config.iconsize+self.config.iconspace)
104
105     def setAngle(self, angle):
106         if self.angle==angle:
107             print "Same angle"
108             return
109
110         self.angle=angle
111
112         # The caller should be responsible for redrawing.
113         # If we call invalidate() here there is the risk of having
114         # icons rotate individually using different angles
115 #       self.invalidate()
116
117     def draw(self, cr, x, y):
118         self.draw_queued=False
119         self.x=x
120         self.y=y
121
122         if self.icon==None and not self.isconfig:
123             return
124
125         cr.save()
126
127         cr.set_source_rgba(0.1, 0.1, 0.1, 1)
128         cr.set_line_width(5)
129
130         #if self.ispressed:
131         if self.timePressed() <= self.presstime or self.ispressed:
132             t=1.0 * min(self.timePressed(), self.presstime) / self.presstime
133             g=0.3+0.5*t
134             b=0.3+0.7*t
135             cr.set_source_rgba(0, g, b, 0.7)
136         else:
137             cr.set_source_rgba(0.3, 0.3, 0.3, 0.7)
138
139         x3=x + (self.config.iconspace/6)
140         y3=y + (self.config.iconspace/6)
141
142         r=10    # Radius
143         w=self.config.iconsize+(self.config.iconspace*2/3)
144
145         cr.move_to(x3+r, y3)
146         cr.arc(x3+w-r,  y3+r,   r,          pi*1.5, pi*2)
147         cr.arc(x3+w-r,  y3+w-r, r,          0,      pi*0.5)
148         cr.arc(x3+r,    y3+w-r, r,          pi*0.5, pi)
149         cr.arc(x3+r,    y3+r,   r,          pi,     pi*1.5)
150
151         cr.stroke_preserve()
152         cr.fill()
153         cr.clip()
154         cr.paint()
155         cr.restore()
156
157         if self.icon==None:
158             return
159
160         icon=self.icon
161
162         icon2=icon
163
164 # Old method. Faster rotation but without support for rotation
165 # animation
166
167 #       if mode=='l':
168 #           icon2=icon
169 #       else:
170 #           icon2=icon.rotate_simple(gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
171
172 #       cr.save()
173 #       x3=x + (self.config.iconspace/2)
174 #       y3=y + (self.config.iconspace/2)
175 #       cr.set_source_pixbuf(icon2, x3, y3)
176 #
177 #       cr.paint()
178 #       cr.restore()
179
180
181         # Width is the iconsize plus the empty border around the icon
182         w=self.config.iconsize + self.config.iconspace
183
184         # This is used to locate the center of the surface
185         dx=int(w/2)
186
187         # This is the delta from the center where icons are drawn
188         dx2=int(self.config.iconsize/2)
189
190         # A surface to draw on
191         t_s=cairo.ImageSurface(cairo.FORMAT_ARGB32, w, w)
192
193         # And a context to draw
194         t_cr0=cairo.Context(t_s)
195         t_cr=gtk.gdk.CairoContext(t_cr0)
196
197         # A transformation matrix with dx/dy set to point to the center
198         m=cairo.Matrix(1, 0, 0, 1, dx, dx)
199         t_cr.set_matrix(m)
200         # Transform degrees to rads
201         rot=-1 * pi * 2 * self.angle / 360
202         t_cr.rotate(rot)
203         # Draw the icon
204         t_cr.set_source_pixbuf(icon2, -dx2, -dx2)
205         t_cr.paint()
206
207         # Draw the rotated icon on the main cairo context
208         cr.save()
209         cr.set_source_surface(t_s, x, y)
210         cr.paint()
211         cr.restore()
212
213         return(False)
214
215     def timerPressed(self):
216 #       if not self.ispressed:
217 #           return(False)
218
219         self.invalidate()
220
221         if self.timePressed()>self.presstime:
222             ret=False
223         else:
224             ret=True
225
226         return(ret)
227
228     def doPress(self):
229         # Double-time: time for pressed and time for not-pressed
230         if time.time() - self.lastpress > self.presstime*2:
231             self.clickcount=0
232
233         self.lastpress=time.time()
234         self.ispressed=True
235         gobject.timeout_add(20, self.timerPressed)
236
237     def doRelease(self):
238         dt=time.time() - self.lastpress
239         self.ispressed=False
240         self.invalidate()
241         if dt<=self.presstime:
242             self.clickcount+=1
243             if self.clickcount==1:
244                 self.emit('click')
245             elif self.clickcount==2:
246                 self.emit('double-click')
247             if self.clickcount==3:
248                 self.emit('tripple-click')
249                 self.clickcount=0
250         elif dt>self.presstime and dt<2:
251             self.emit('long-press')
252
253     def doCancel(self):
254         self.ispressed=False
255
256     def setWindow(self, window):
257         self.window=window
258
259     def invalidate(self, window=None):
260         if window==None:
261             window=self.window
262         else:
263             self.window=window
264         
265         if window==None:
266             return
267
268         if self.draw_queued:
269             print "queued"
270             return
271         self.draw_queued=True
272         w=self.config.iconsize + self.config.iconspace
273         rect=gdk.Rectangle(self.x, self.y, w, w)
274         gdk.Window.invalidate_rect(window, rect, True)
275
276 gobject.type_register(Icon)
277 signals=['click', 'double-click', 'tripple-click', 'long-press']
278 for s in signals:
279     gobject.signal_new(s, Icon, gobject.SIGNAL_RUN_FIRST,
280         gobject.TYPE_NONE, ())
281
282 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
283