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