Faster icon rotation using various cachings
[drlaunch] / src / icongrid.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 #from xdg.IconTheme import getIconPath
36
37 #import config
38 import apps
39 import icon
40 from icon import Icon
41 from icons import Icons
42
43 #def getIcon(name, iconsize):
44 #    ico=getIconPath(name, iconsize)
45 #    ret=gtk.gdk.pixbuf_new_from_file_at_size(ico, iconsize, iconsize)
46 #
47 #    return(ret)
48
49 #class IconGrid(gtk.Widget, FremantleRotation):
50 class IconGrid(object): #(gobject.GObject):
51     def __init__(self, isconfig=False):
52 #       self.__gobject_init__()
53
54         self.init_done=False
55
56         self.size=(0,0)
57
58         self.isconfig=isconfig
59
60         self.icons=None
61         self.lasticon=None  # The last icon that got selected
62
63         self.draw_pending=False
64
65         self.mode=None
66
67     def do_realize(self, config):
68         self.config=config
69
70         self.icons=Icons(self.isconfig, self.config)
71         self.setMode('l')
72         self.setSize((4,4))
73         self.reloadIcons()
74
75     def connect(self, what, *args):
76         if what in icon.signals:
77             self.icons.connect(what, *args)
78         else:
79             super(IconGrid, self).connect(what, *args)
80
81     def setSize(self, size):
82         self.size=size
83         self.icons.setSize(size)
84
85     def getSize(self):
86         ret=self.icons.getSize()
87         return(ret)
88
89     def setMode(self, mode):
90         if self.mode==mode:
91             print "same mode"
92             return
93
94         self.mode=mode
95         if not isinstance(self, gtk.Widget):
96             return
97
98         do_draw=False
99
100         try:
101             v=self.get_property('is-on-current-desktop')
102             if v:
103                 do_draw=True
104             else:
105                 self.draw_pending=True
106         except TypeError:
107             do_draw=True
108
109         if do_draw:
110             #self.queue_draw()
111             self.angle_timer_start=time.time()
112             gobject.timeout_add(20, self.timerAngle)
113         else:
114             if self.mode=='l':
115                 self.setAngle(0)
116             else:
117                 self.setAngle(90)
118                 
119     def timerAngle(self):
120         if self.angle_timer_start==0:
121             self.angle_timer_start=time.time()-0.05
122
123         dt=time.time()-self.angle_timer_start
124
125         # Duration of the rotation effect
126         rotation_time=0.5
127
128         da=90.0*dt/rotation_time
129
130         if self.mode=='l':
131             angle=90-da
132         else:
133             angle=da
134
135         if angle>=90:
136             angle=90
137             ret=False
138         elif angle<0:
139             angle=0
140             ret=False
141         else:
142             ret=True
143
144         if self.setAngle(angle):
145             self.queue_draw()
146
147         if ret==False:
148             self.angle_timer_start=0
149
150         return(ret)
151
152     def iconAt(self, x, y):
153         """ Get icon at coordinates x,y. X and Y are in pixels """
154
155         w=self.config.iconsize + self.config.iconspace
156
157         if self.mode=='l' or self.config.getIndiv():
158             x2=int(x / w)
159             y2=int(y / w)
160         else:
161             x2=self.size[1] - int(y/w) - 1
162             y2=int(x/w)
163
164         ret=self.get(x2,y2)
165
166         return(ret)
167
168     def get(self, x, y):
169         ret=self.icons.get(x,y)
170
171         return(ret)
172
173     def _draw(self, cr, event):
174         self.draw_pending=False
175
176         w=self.config.iconsize + self.config.iconspace
177         for x,y in self.icons:
178             if self.mode=='l' or self.config.getIndiv():
179                 x2=x * (self.config.iconsize + self.config.iconspace)
180                 y2=y * (self.config.iconsize + self.config.iconspace)
181             else:
182                 x2=y * (self.config.iconsize + self.config.iconspace)
183                 y2=(self.size[1]-x-1) * \
184                         (self.config.iconsize + self.config.iconspace)
185
186             # Only repaint the needed icons
187             rect=gdk.Rectangle(x2, y2, w, w)
188             t=rect.intersect(event.area)
189             if t.width==0 and t.height==0:
190                 continue
191
192             ico=self.icons.get(x,y)
193             ico.draw(cr, x2, y2)
194
195     def setAngle(self, angle):
196         """ Return True/False indicating that angle has changed """
197         ret=False
198         for x,y in self.icons:
199             ic=self.icons.get(x,y)
200             if ic.setAngle(angle):
201                 ret=True
202
203         return(ret)
204
205     def do_expose_event(self, event):
206         cr=self.window.cairo_create()
207
208         cr.rectangle(event.area.x, event.area.y,
209             event.area.width, event.area.height)
210
211         cr.clip()
212
213         if not self.init_done:
214             self.icons.setWindow(self.window)
215             self.init_done=True
216
217         self._draw(cr, event)
218
219     def setLastIcon(self, icon):
220         if icon==self.lasticon:
221             return
222
223         if self.lasticon!=None:
224             self.lasticon.doCancel()
225             self.lasticon.invalidate(self.window)
226         self.lasticon=icon
227
228     def do_button_press_event(self, event):
229         icon=self.iconAt(event.x, event.y)
230         if icon==None:
231             return
232 #       rect=gdk.Rectangle(event.x,event.y,1,1)
233 #       rect=gdk.Rectangle(0, 0, 100, 100)
234         icon.doPress()
235         icon.invalidate(self.window)
236         self.setLastIcon(icon)
237
238 #       gdk.Window.invalidate_rect(self.window, rect, True)
239
240         return(True)
241
242     def do_button_release_event(self, event):
243         if self.lasticon!=None:
244             self.lasticon.invalidate(self.window)
245             self.lasticon.doRelease()
246
247         self.setLastIcon(None)
248
249         return(True)
250
251     def do_leave_notify_event(self, event):
252         self.setLastIcon(None)
253         return(True)
254
255     def do_pproperty_notify_event(self, event):
256         icon=self.iconAt(event.x, event.y)
257         if icon==None:
258             return
259         icon.doCancel()
260         icon.invalidate(self.window)
261         return(True)
262
263     def do_motion_notify_event(self, event):
264         icon=self.iconAt(event.x, event.y)
265         if self.lasticon==icon:
266             return(True)
267
268         self.setLastIcon(None)
269         icon.doCancel()
270         icon.invalidate(self.window)
271         return(True)
272
273     def do_button_press_event_old(self, event):
274         if event.type==gdk.BUTTON_PRESS:
275             if self.mode=='p':
276                 self.setMode('l')
277             else:
278                 self.setMode('p')
279             self.queue_draw()
280         return True
281
282     # For debugging
283     def do_event1(self, event):
284         print "event:", event, event.type
285
286     def reloadIcons(self):
287         self.icons.load()
288
289 #    def on_orientation_changed(self, orientation):
290 #       print "orch:", orientation
291 #       o=orientation[0]
292 #       self.setMode(o)
293
294 class IconGridWidget(IconGrid, gtk.Widget):
295     def __init__(self, isconfig, config):
296         IconGrid.__init__(self, isconfig)
297         gtk.Widget.__init__(self)
298
299         self.config=config
300
301         IconGrid.do_realize(self, self.config)
302
303         if isconfig:
304             maxsz=self.config.getMaxSize()
305             w=maxsz[0] * (self.config.iconsize + self.config.iconspace)
306             h=maxsz[1] * (self.config.iconsize + self.config.iconspace)
307         else:
308             w=self.size[0] * (self.config.iconsize + self.config.iconspace)
309             h=self.size[1] * (self.config.iconsize + self.config.iconspace)
310
311         self.set_size_request(w, h)
312
313     def do_realize(self):
314         screen=self.get_screen()
315         self.set_colormap(screen.get_rgba_colormap())
316         self.set_app_paintable(True)
317
318         self.set_flags(self.flags() | gtk.REALIZED)
319
320         self.window=gdk.Window(
321             self.get_parent_window(),
322             width=self.allocation.width,
323             height=self.allocation.height,
324             window_type=gdk.WINDOW_CHILD,
325             wclass=gdk.INPUT_OUTPUT,
326             event_mask=self.get_events() | gdk.EXPOSURE_MASK
327                 | gdk.BUTTON_PRESS_MASK 
328                 | gdk.BUTTON_RELEASE_MASK 
329                 | gdk.BUTTON_MOTION_MASK
330                 | gdk.POINTER_MOTION_MASK
331                 | gdk.POINTER_MOTION_HINT_MASK 
332                 | gdk.ENTER_NOTIFY_MASK
333                 | gdk.LEAVE_NOTIFY_MASK )
334
335         self.window.set_user_data(self)
336         self.style.attach(self.window)
337
338 #       self.style.set_background(self.window, gtk.STATE_NORMAL)
339         self.window.move_resize(*self.allocation)
340
341 #       self.pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
342 #             self.window, self.style.bg[gtk.STATE_NORMAL], STAR_PIXMAP)
343         
344 #       self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
345
346         #gtk.Widget.do_realize(self)
347         #HomePluginItem.do_realize(self)
348
349 #       screen=self.get_screen()
350 #       self.set_colormap(screen.get_rgba_colormap())
351 #       self.set_app_paintable(True)
352
353     def do_unrealize(self):
354         #self.window.set_user_data(None)
355         self.window.destroy()
356
357 #gobject.type_register(IconGrid)
358 gobject.type_register(IconGridWidget)
359
360
361 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
362