move drlaunch in drlaunch
[drlaunch] / 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 from config import dump
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 # IconGrid is the main class that implements tha drawing of the grid
50 # However, since it will be used both by the desktop plugin and the
51 # configuration window, it cannot derive either gtk.Widget or HomePluginItem.
52 # It is created here in a way that will allow it to work on both cases
53 # and it is inherited by appropriate classes (one for the plugin and one
54 # for the config widget)
55
56 #class IconGrid(gtk.Widget, FremantleRotation):
57 class IconGrid: #(gobject.GObject):
58     def __init__(self, isconfig=False):
59 #       self.__gobject_init__()
60 #       gtk.Widget.__init__(self)
61
62         self.init_done=False
63
64         self.size=(0,0)
65
66         self.isconfig=isconfig
67
68         self.icons=None
69         self.lasticon=None  # The last icon that got selected
70
71         self.draw_pending=False
72
73         self.mode=None
74
75         # If this is False then animations are forcefully disabled
76         self.do_animations=True
77
78         self.angle_timer_start=0
79
80         # Duration of the rotation effect
81         self.rotation_time=0.8
82
83 #       print "ig-init"
84
85 #    def __del__(self):
86 #       print "ig-del"
87
88     def do_realize(self, config):
89 #       print "ig-realize"
90         self.config=config
91
92         if self.icons!=None:
93             print
94             print
95             print
96             print "WTF??????????????????????"
97             print
98             print
99             print
100
101         self.icons=Icons(self.isconfig, self.config)
102         #print "self:", self
103         #self.icons.set_parent(self)
104         self.setMode('l')
105         self.setSize(config.getMaxSize())
106         self.reloadIcons()
107
108     def do_unrealize(self):
109 #       print "ig-unrealize"
110         self.config=None
111         self.icons.finish()
112         self.icons=None
113         self.lasticon=None
114
115     def connect(self, what, *args):
116         if what in Icon.gsignals.keys():
117             ret=self.icons.connect(what, *args)
118         else:
119             ret=gobject.GObject.connect(self, what, *args)
120             #ret=super(IconGrid, self).connect(what, *args)
121
122         return(ret)
123
124     def setSize(self, size):
125         self.size=size
126         self.icons.setSize(size)
127
128     def getSize(self):
129         ret=self.icons.getSize()
130         return(ret)
131
132     def setMode(self, mode):
133         if self.mode==mode:
134 #           print "same mode"
135             return
136
137         self.mode=mode
138         if not isinstance(self, gtk.Widget):
139             return
140
141         do_draw=False
142
143         try:
144             v=self.get_property('is-on-current-desktop')
145             if v:
146                 do_draw=True
147             else:
148                 self.draw_pending=True
149         except TypeError:
150             do_draw=True
151
152         if do_draw and self.config.getAnimate() and self.do_animations:
153             #self.queue_draw()
154             # Don't start another timer
155             # Instead adjust the time start to produce a nice effect ;-)
156             if self.angle_timer_start==0:
157                 self.angle_timer_start=time.time()
158                 gobject.timeout_add(20, self.timerAngle)
159             else:
160                 dt=time.time()-self.angle_timer_start
161                 da=90.0*dt/self.rotation_time
162
163                 da2=90.0-da
164                 dt2=da2*self.rotation_time/90.0
165                 self.angle_timer_start=time.time()-dt2
166         else:
167             if self.mode=='l':
168                 self.setAngle(0)
169             else:
170                 self.setAngle(90)
171
172             if do_draw:
173                 self.queue_draw()
174
175     def disableAnimation(self):
176         self.do_animations=False
177
178     def enableAnimation(self):
179         self.do_animations=True
180
181     def setAnimationEnable(self, value):
182         if value:
183             self.enableAnimation()
184         else:
185             self.disableAnimation()
186
187     def timerAngle(self):
188         if self.angle_timer_start==0:
189             self.angle_timer_start=time.time()-0.05
190
191         dt=time.time()-self.angle_timer_start
192
193         da=90.0*dt/self.rotation_time
194
195         if self.mode=='l':
196             angle=90-da
197         else:
198             angle=da
199
200         if angle>=90:
201             angle=90
202             ret=False
203         elif angle<0:
204             angle=0
205             ret=False
206         else:
207             ret=True
208
209         if self.setAngle(angle):
210             self.queue_draw()
211
212         if ret==False:
213             self.angle_timer_start=0
214
215         return(ret)
216
217     def iconAt(self, x, y):
218         """ Get icon at coordinates x,y. X and Y are in pixels """
219
220         w=self.config.getIconSizeFull()
221
222         if self.mode=='l' or self.config.getIndiv():
223             x2=int(x / w)
224             y2=int(y / w)
225         else:
226             x2=self.size[1] - int(y/w) - 1
227             y2=int(x/w)
228
229         ret=self.get(x2,y2)
230
231         return(ret)
232
233     def get(self, x, y):
234         ret=self.icons.get(x,y)
235
236         return(ret)
237
238     def _draw(self, cr, event):
239         self.draw_pending=False
240
241         w=self.config.getIconSizeFull()
242         for x,y in self.icons:
243             if self.mode=='l' or self.config.getIndiv():
244                 #x2=x * (self.config.iconsize + self.config.iconspace)
245                 #y2=y * (self.config.iconsize + self.config.iconspace)
246                 x2=x * self.config.getIconSizeFull()
247                 y2=y * self.config.getIconSizeFull()
248             else:
249                 #x2=y * (self.config.iconsize + self.config.iconspace)
250                 #y2=(self.size[1]-x-1) * \
251                 #       (self.config.iconsize + self.config.iconspace)
252                 x2=y * self.config.getIconSizeFull()
253                 y2=(self.size[1]-x-1) * self.config.getIconSizeFull()
254
255             # Only repaint the needed icons
256             rect=gdk.Rectangle(x2, y2, w, w)
257             t=rect.intersect(event.area)
258             if t.width==0 and t.height==0:
259                 continue
260
261             ico=self.icons.get(x,y)
262             ico.draw(cr, x2, y2)
263
264     def setAngle(self, angle):
265         """ Return True/False indicating that angle has changed """
266         ret=False
267         for x,y in self.icons:
268             ic=self.icons.get(x,y)
269             if ic.setAngle(angle):
270                 ret=True
271
272         return(ret)
273
274     def clearAnimationCache(self):
275         """ Clear animation cache, freeing memory """
276         for x,y in self.icons:
277             ic=self.icons.get(x,y)
278             ic.clearAnimationCache()
279
280     def clearBgCache(self):
281         """ Clear backgrounds cache """
282         for x,y in self.icons:
283             ic=self.icons.get(x,y)
284             ic.clearBgCache()
285
286     def do_expose_event(self, event):
287         cr=self.window.cairo_create()
288
289         cr.rectangle(event.area.x, event.area.y,
290             event.area.width, event.area.height)
291
292         cr.clip()
293
294         if not self.init_done:
295             self.icons.setWindow(self.window)
296             self.init_done=True
297
298         self._draw(cr, event)
299
300     def setLastIcon(self, icon):
301         if icon==self.lasticon:
302             return
303
304         if self.lasticon!=None:
305             self.lasticon.doCancel()
306             self.lasticon.invalidate(self.window)
307         self.lasticon=icon
308
309     def do_button_press_event(self, event):
310         icon=self.iconAt(event.x, event.y)
311         if icon==None:
312             return
313 #       rect=gdk.Rectangle(event.x,event.y,1,1)
314 #       rect=gdk.Rectangle(0, 0, 100, 100)
315         icon.doPress()
316         icon.invalidate(self.window)
317         self.setLastIcon(icon)
318
319 #       gdk.Window.invalidate_rect(self.window, rect, True)
320
321         return(True)
322
323     def do_button_release_event(self, event):
324         if self.lasticon!=None:
325             self.lasticon.invalidate(self.window)
326             self.lasticon.doRelease()
327
328         self.setLastIcon(None)
329
330         return(True)
331
332     def do_leave_notify_event(self, event):
333         self.setLastIcon(None)
334         return(True)
335
336     def do_pproperty_notify_event(self, event):
337         icon=self.iconAt(event.x, event.y)
338         if icon==None:
339             return
340         icon.doCancel()
341         icon.invalidate(self.window)
342         return(True)
343
344     def do_motion_notify_event(self, event):
345         icon=self.iconAt(event.x, event.y)
346         if self.lasticon==icon:
347             return(True)
348
349         self.setLastIcon(None)
350         icon.doCancel()
351         icon.invalidate(self.window)
352         return(True)
353
354     def do_button_press_event_old(self, event):
355         if event.type==gdk.BUTTON_PRESS:
356             if self.mode=='p':
357                 self.setMode('l')
358             else:
359                 self.setMode('p')
360             self.queue_draw()
361         return True
362
363     # For debugging
364     def do_event1(self, event):
365         print "event:", event, event.type
366
367     def reloadIcons(self):
368         self.icons.load()
369         self.lasticon=None
370
371 #    def on_orientation_changed(self, orientation):
372 #       print "orch:", orientation
373 #       o=orientation[0]
374 #       self.setMode(o)
375
376 class IconGridWidget(IconGrid, gtk.Widget):
377     def __init__(self, isconfig, config, animation=True):
378         IconGrid.__init__(self, isconfig)
379         gtk.Widget.__init__(self)
380
381         # This must be called before do_realize
382         self.setAnimationEnable(animation)
383
384         self.config=config
385
386         IconGrid.do_realize(self, self.config)
387
388         self.setSize(self.size)
389
390 #       print "igw-init"
391
392 #    def __del__(self):
393 #       print "igw-del"
394
395     def setSize(self, size):
396         IconGrid.setSize(self, size)
397
398         w=self.size[0] * self.config.getIconSizeFull()
399         h=self.size[1] * self.config.getIconSizeFull()
400
401         self.set_size_request(w, h)
402
403     def reconfig(self):
404         self.clearBgCache()
405         self.clearAnimationCache()
406         self.reloadIcons()
407         self.setSize(self.size)
408         self.icons.resizeMax()
409         self.queue_draw()
410
411     def do_realize(self):
412 #       print "igw-realize"
413         screen=self.get_screen()
414         self.set_colormap(screen.get_rgba_colormap())
415         self.set_app_paintable(True)
416
417         self.set_flags(self.flags() | gtk.REALIZED)
418
419         self.window=gdk.Window(
420             self.get_parent_window(),
421             width=self.allocation.width,
422             height=self.allocation.height,
423             window_type=gdk.WINDOW_CHILD,
424             wclass=gdk.INPUT_OUTPUT,
425             event_mask=self.get_events() | gdk.EXPOSURE_MASK
426                 | gdk.BUTTON_PRESS_MASK 
427                 | gdk.BUTTON_RELEASE_MASK 
428                 | gdk.BUTTON_MOTION_MASK
429                 | gdk.POINTER_MOTION_MASK
430                 | gdk.POINTER_MOTION_HINT_MASK 
431                 | gdk.ENTER_NOTIFY_MASK
432                 | gdk.LEAVE_NOTIFY_MASK )
433
434         self.window.set_user_data(self)
435
436         # No matter what the pygtk widget demo says, this is NOT CORRECT!!!
437         # Don't call style.attach(self.window) or else the program will crash
438         # after some time! It seems that there is a style already.
439         # If we want to use the style the we use get_style() instead.
440         # This one was very hard to solve. Thanks to gnome2-globalmenu guys.
441         # It was solved by looking the commit 2666:
442         # see:
443         # svn diff -r2665:2666 http://gnome2-globalmenu.googlecode.com/svn/trunk
444         # which solved cse 490:
445         # http://code.google.com/p/gnome2-globalmenu/issues/detail?id=490
446 #       self.style.attach(self.window)
447         style=self.get_style()
448
449 #       style.set_background(self.window, gtk.STATE_NORMAL)
450         self.window.move_resize(*self.allocation)
451
452 #       self.pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
453 #             self.window, self.style.bg[gtk.STATE_NORMAL], STAR_PIXMAP)
454         
455 #       self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
456
457         #HomePluginItem.do_realize(self)
458
459 #       screen=self.get_screen()
460 #       self.set_colormap(screen.get_rgba_colormap())
461 #       self.set_app_paintable(True)
462
463     def do_unrealize(self):
464 #       print "igw-unrealize", self
465         IconGrid.do_unrealize(self)
466         self.window.destroy()
467         self.window.set_user_data(None)
468
469     def do_expose_event(self, event):
470         cr=self.window.cairo_create()
471
472         cr.rectangle(event.area.x, event.area.y,
473             event.area.width, event.area.height)
474         cr.clip()
475
476         style=self.get_style()
477         col=style.bg[gtk.STATE_NORMAL]
478         cr.set_source_color(col)
479         cr.paint()
480
481         IconGrid.do_expose_event(self, event)
482
483 #gobject.type_register(IconGrid)
484 gobject.type_register(IconGridWidget)
485
486
487 # vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
488