e90bd9dc9f5abd8baa8f547e8fd9436432065cd4
[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         # If this is False then animations are forcefully disabled
68         self.do_animations=True
69
70         self.angle_timer_start=0
71
72         # Duration of the rotation effect
73         self.rotation_time=0.8
74
75     def do_realize(self, config):
76         self.config=config
77
78         self.icons=Icons(self.isconfig, self.config)
79         self.setMode('l')
80         self.setSize(config.getMaxSize())
81         self.reloadIcons()
82
83     def connect(self, what, *args):
84         if what in icon.signals:
85             self.icons.connect(what, *args)
86         else:
87             super(IconGrid, self).connect(what, *args)
88
89     def setSize(self, size):
90         self.size=size
91         self.icons.setSize(size)
92
93     def getSize(self):
94         ret=self.icons.getSize()
95         return(ret)
96
97     def setMode(self, mode):
98         if self.mode==mode:
99             print "same mode"
100             return
101
102         self.mode=mode
103         if not isinstance(self, gtk.Widget):
104             return
105
106         do_draw=False
107
108         try:
109             v=self.get_property('is-on-current-desktop')
110             if v:
111                 do_draw=True
112             else:
113                 self.draw_pending=True
114         except TypeError:
115             do_draw=True
116
117         if do_draw and self.config.getAnimate() and self.do_animations:
118             #self.queue_draw()
119             # Don't start another timer
120             # Instead adjust the time start to produce a nice effect ;-)
121             if self.angle_timer_start==0:
122                 self.angle_timer_start=time.time()
123                 gobject.timeout_add(20, self.timerAngle)
124             else:
125                 dt=time.time()-self.angle_timer_start
126                 da=90.0*dt/self.rotation_time
127
128                 da2=90.0-da
129                 dt2=da2*self.rotation_time/90.0
130                 self.angle_timer_start=time.time()-dt2
131         else:
132             if self.mode=='l':
133                 self.setAngle(0)
134             else:
135                 self.setAngle(90)
136
137             if do_draw:
138                 self.queue_draw()
139
140     def disableAnimation(self):
141         self.do_animations=False
142
143     def enableAnimation(self):
144         self.do_animations=True
145
146     def setAnimationEnable(self, value):
147         if value:
148             self.enableAnimation()
149         else:
150             self.disableAnimation()
151
152     def timerAngle(self):
153         if self.angle_timer_start==0:
154             self.angle_timer_start=time.time()-0.05
155
156         dt=time.time()-self.angle_timer_start
157
158         da=90.0*dt/self.rotation_time
159
160         if self.mode=='l':
161             angle=90-da
162         else:
163             angle=da
164
165         if angle>=90:
166             angle=90
167             ret=False
168         elif angle<0:
169             angle=0
170             ret=False
171         else:
172             ret=True
173
174         if self.setAngle(angle):
175             self.queue_draw()
176
177         if ret==False:
178             self.angle_timer_start=0
179
180         return(ret)
181
182     def iconAt(self, x, y):
183         """ Get icon at coordinates x,y. X and Y are in pixels """
184
185         w=self.config.getIconSizeFull()
186
187         if self.mode=='l' or self.config.getIndiv():
188             x2=int(x / w)
189             y2=int(y / w)
190         else:
191             x2=self.size[1] - int(y/w) - 1
192             y2=int(x/w)
193
194         ret=self.get(x2,y2)
195
196         return(ret)
197
198     def get(self, x, y):
199         ret=self.icons.get(x,y)
200
201         return(ret)
202
203     def _draw(self, cr, event):
204         self.draw_pending=False
205
206         w=self.config.getIconSizeFull()
207         for x,y in self.icons:
208             if self.mode=='l' or self.config.getIndiv():
209                 #x2=x * (self.config.iconsize + self.config.iconspace)
210                 #y2=y * (self.config.iconsize + self.config.iconspace)
211                 x2=x * self.config.getIconSizeFull()
212                 y2=y * self.config.getIconSizeFull()
213             else:
214                 #x2=y * (self.config.iconsize + self.config.iconspace)
215                 #y2=(self.size[1]-x-1) * \
216                 #       (self.config.iconsize + self.config.iconspace)
217                 x2=y * self.config.getIconSizeFull()
218                 y2=(self.size[1]-x-1) * self.config.getIconSizeFull()
219
220             # Only repaint the needed icons
221             rect=gdk.Rectangle(x2, y2, w, w)
222             t=rect.intersect(event.area)
223             if t.width==0 and t.height==0:
224                 continue
225
226             ico=self.icons.get(x,y)
227             ico.draw(cr, x2, y2)
228
229     def setAngle(self, angle):
230         """ Return True/False indicating that angle has changed """
231         ret=False
232         for x,y in self.icons:
233             ic=self.icons.get(x,y)
234             if ic.setAngle(angle):
235                 ret=True
236
237         return(ret)
238
239     def clearAnimationCache(self):
240         """ Clear animation cache, freeing memory """
241         for x,y in self.icons:
242             ic=self.icons.get(x,y)
243             ic.clearAnimationCache()
244
245     def clearBgCache(self):
246         """ Clear backgrounds cache """
247         for x,y in self.icons:
248             ic=self.icons.get(x,y)
249             ic.clearBgCache()
250
251     def do_expose_event(self, event):
252         cr=self.window.cairo_create()
253
254         cr.rectangle(event.area.x, event.area.y,
255             event.area.width, event.area.height)
256
257         cr.clip()
258
259         if not self.init_done:
260             self.icons.setWindow(self.window)
261             self.init_done=True
262
263         self._draw(cr, event)
264
265     def setLastIcon(self, icon):
266         if icon==self.lasticon:
267             return
268
269         if self.lasticon!=None:
270             self.lasticon.doCancel()
271             self.lasticon.invalidate(self.window)
272         self.lasticon=icon
273
274     def do_button_press_event(self, event):
275         icon=self.iconAt(event.x, event.y)
276         if icon==None:
277             return
278 #       rect=gdk.Rectangle(event.x,event.y,1,1)
279 #       rect=gdk.Rectangle(0, 0, 100, 100)
280         icon.doPress()
281         icon.invalidate(self.window)
282         self.setLastIcon(icon)
283
284 #       gdk.Window.invalidate_rect(self.window, rect, True)
285
286         return(True)
287
288     def do_button_release_event(self, event):
289         if self.lasticon!=None:
290             self.lasticon.invalidate(self.window)
291             self.lasticon.doRelease()
292
293         self.setLastIcon(None)
294
295         return(True)
296
297     def do_leave_notify_event(self, event):
298         self.setLastIcon(None)
299         return(True)
300
301     def do_pproperty_notify_event(self, event):
302         icon=self.iconAt(event.x, event.y)
303         if icon==None:
304             return
305         icon.doCancel()
306         icon.invalidate(self.window)
307         return(True)
308
309     def do_motion_notify_event(self, event):
310         icon=self.iconAt(event.x, event.y)
311         if self.lasticon==icon:
312             return(True)
313
314         self.setLastIcon(None)
315         icon.doCancel()
316         icon.invalidate(self.window)
317         return(True)
318
319     def do_button_press_event_old(self, event):
320         if event.type==gdk.BUTTON_PRESS:
321             if self.mode=='p':
322                 self.setMode('l')
323             else:
324                 self.setMode('p')
325             self.queue_draw()
326         return True
327
328     # For debugging
329     def do_event1(self, event):
330         print "event:", event, event.type
331
332     def reloadIcons(self):
333         self.icons.load()
334
335 #    def on_orientation_changed(self, orientation):
336 #       print "orch:", orientation
337 #       o=orientation[0]
338 #       self.setMode(o)
339
340 class IconGridWidget(IconGrid, gtk.Widget):
341     def __init__(self, isconfig, config, animation=True):
342         IconGrid.__init__(self, isconfig)
343         gtk.Widget.__init__(self)
344
345         # This must be called before do_realize
346         self.setAnimationEnable(animation)
347
348         self.config=config
349
350         IconGrid.do_realize(self, self.config)
351
352         self.setSize(self.size)
353
354     def setSize(self, size):
355         IconGrid.setSize(self, size)
356
357         w=self.size[0] * self.config.getIconSizeFull()
358         h=self.size[1] * self.config.getIconSizeFull()
359
360         self.set_size_request(w, h)
361
362     def reconfig(self):
363         self.reloadIcons()
364         self.setSize(self.size)
365         self.icons.resizeMax()
366         self.queue_draw()
367
368     def do_realize(self):
369         screen=self.get_screen()
370         self.set_colormap(screen.get_rgba_colormap())
371         self.set_app_paintable(True)
372
373         self.set_flags(self.flags() | gtk.REALIZED)
374
375         self.window=gdk.Window(
376             self.get_parent_window(),
377             width=self.allocation.width,
378             height=self.allocation.height,
379             window_type=gdk.WINDOW_CHILD,
380             wclass=gdk.INPUT_OUTPUT,
381             event_mask=self.get_events() | gdk.EXPOSURE_MASK
382                 | gdk.BUTTON_PRESS_MASK 
383                 | gdk.BUTTON_RELEASE_MASK 
384                 | gdk.BUTTON_MOTION_MASK
385                 | gdk.POINTER_MOTION_MASK
386                 | gdk.POINTER_MOTION_HINT_MASK 
387                 | gdk.ENTER_NOTIFY_MASK
388                 | gdk.LEAVE_NOTIFY_MASK )
389
390         self.window.set_user_data(self)
391         self.style.attach(self.window)
392
393 #       self.style.set_background(self.window, gtk.STATE_NORMAL)
394         self.window.move_resize(*self.allocation)
395
396 #       self.pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
397 #             self.window, self.style.bg[gtk.STATE_NORMAL], STAR_PIXMAP)
398         
399 #       self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
400
401         #gtk.Widget.do_realize(self)
402         #HomePluginItem.do_realize(self)
403
404 #       screen=self.get_screen()
405 #       self.set_colormap(screen.get_rgba_colormap())
406 #       self.set_app_paintable(True)
407
408     def do_unrealize(self):
409         #self.window.set_user_data(None)
410         self.window.destroy()
411
412 #gobject.type_register(IconGrid)
413 gobject.type_register(IconGridWidget)
414
415
416 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
417