It works!
[drlaunch] / src / icongrid.py
index 5924031..96588d5 100755 (executable)
@@ -34,7 +34,7 @@ import time
 from portrait import FremantleRotation
 #from xdg.IconTheme import getIconPath
 
-#import config
+from config import dump
 import apps
 import icon
 from icon import Icon
@@ -46,10 +46,20 @@ from icons import Icons
 #
 #    return(ret)
 
+# IconGrid is the main class that implements tha drawing of the grid
+# However, since it will be used both by the desktop plugin and the
+# configuration window, it cannot derive either gtk.Widget or HomePluginItem.
+# It is created here in a way that will allow it to work on both cases
+# and it is inherited by appropriate classes (one for the plugin and one
+# for the config widget)
+
 #class IconGrid(gtk.Widget, FremantleRotation):
-class IconGrid(object):        #(gobject.GObject):
+class IconGrid:        #(gobject.GObject):
     def __init__(self, isconfig=False):
 #      self.__gobject_init__()
+#      gtk.Widget.__init__(self)
+
+       self.init_done=False
 
        self.size=(0,0)
 
@@ -60,19 +70,56 @@ class IconGrid(object):     #(gobject.GObject):
 
        self.draw_pending=False
 
+       self.mode=None
+
+       # If this is False then animations are forcefully disabled
+       self.do_animations=True
+
+       self.angle_timer_start=0
+
+       # Duration of the rotation effect
+       self.rotation_time=0.8
+
+#      print "ig-init"
+
+#    def __del__(self):
+#      print "ig-del"
+
     def do_realize(self, config):
+#      print "ig-realize"
        self.config=config
 
+       if self.icons!=None:
+           print
+           print
+           print
+           print "WTF??????????????????????"
+           print
+           print
+           print
+
        self.icons=Icons(self.isconfig, self.config)
+       #print "self:", self
+       #self.icons.set_parent(self)
        self.setMode('l')
-       self.setSize((4,4))
+       self.setSize(config.getMaxSize())
        self.reloadIcons()
 
+    def do_unrealize(self):
+#      print "ig-unrealize"
+       self.config=None
+       self.icons.finish()
+       self.icons=None
+       self.lasticon=None
+
     def connect(self, what, *args):
-       if what in icon.signals:
-           self.icons.connect(what, *args)
+       if what in Icon.gsignals.keys():
+           ret=self.icons.connect(what, *args)
        else:
-           super(IconGrid, self).connect(what, *args)
+           ret=gobject.GObject.connect(self, what, *args)
+           #ret=super(IconGrid, self).connect(what, *args)
+
+       return(ret)
 
     def setSize(self, size):
        self.size=size
@@ -83,20 +130,94 @@ class IconGrid(object):    #(gobject.GObject):
        return(ret)
 
     def setMode(self, mode):
+       if self.mode==mode:
+#          print "same mode"
+           return
+
        self.mode=mode
        if not isinstance(self, gtk.Widget):
            return
 
-       v=self.get_property('is-on-current-desktop')
-       if v:
-           self.queue_draw()
+       do_draw=False
+
+       try:
+           v=self.get_property('is-on-current-desktop')
+           if v:
+               do_draw=True
+           else:
+               self.draw_pending=True
+       except TypeError:
+           do_draw=True
+
+       if do_draw and self.config.getAnimate() and self.do_animations:
+           #self.queue_draw()
+           # Don't start another timer
+           # Instead adjust the time start to produce a nice effect ;-)
+           if self.angle_timer_start==0:
+               self.angle_timer_start=time.time()
+               gobject.timeout_add(20, self.timerAngle)
+           else:
+               dt=time.time()-self.angle_timer_start
+               da=90.0*dt/self.rotation_time
+
+               da2=90.0-da
+               dt2=da2*self.rotation_time/90.0
+               self.angle_timer_start=time.time()-dt2
+        else:
+            if self.mode=='l':
+                self.setAngle(0)
+            else:
+                self.setAngle(90)
+
+           if do_draw:
+               self.queue_draw()
+
+    def disableAnimation(self):
+       self.do_animations=False
+
+    def enableAnimation(self):
+       self.do_animations=True
+
+    def setAnimationEnable(self, value):
+       if value:
+           self.enableAnimation()
+       else:
+           self.disableAnimation()
+
+    def timerAngle(self):
+       if self.angle_timer_start==0:
+           self.angle_timer_start=time.time()-0.05
+
+       dt=time.time()-self.angle_timer_start
+
+       da=90.0*dt/self.rotation_time
+
+       if self.mode=='l':
+           angle=90-da
+       else:
+           angle=da
+
+       if angle>=90:
+           angle=90
+           ret=False
+       elif angle<0:
+           angle=0
+           ret=False
        else:
-           self.draw_pending=True
+           ret=True
+
+       if self.setAngle(angle):
+           self.queue_draw()
+
+       if ret==False:
+           self.angle_timer_start=0
+
+       return(ret)
 
     def iconAt(self, x, y):
        """ Get icon at coordinates x,y. X and Y are in pixels """
 
-       w=self.config.iconsize + self.config.iconspace
+       w=self.config.getIconSizeFull()
 
        if self.mode=='l' or self.config.getIndiv():
            x2=int(x / w)
@@ -117,15 +238,19 @@ class IconGrid(object):   #(gobject.GObject):
     def _draw(self, cr, event):
        self.draw_pending=False
 
-       w=self.config.iconsize + self.config.iconspace
+       w=self.config.getIconSizeFull()
        for x,y in self.icons:
            if self.mode=='l' or self.config.getIndiv():
-               x2=x * (self.config.iconsize + self.config.iconspace)
-               y2=y * (self.config.iconsize + self.config.iconspace)
+               #x2=x * (self.config.iconsize + self.config.iconspace)
+               #y2=y * (self.config.iconsize + self.config.iconspace)
+               x2=x * self.config.getIconSizeFull()
+               y2=y * self.config.getIconSizeFull()
            else:
-               x2=y * (self.config.iconsize + self.config.iconspace)
-               y2=(self.size[1]-x-1) * \
-                       (self.config.iconsize + self.config.iconspace)
+               #x2=y * (self.config.iconsize + self.config.iconspace)
+               #y2=(self.size[1]-x-1) * \
+               #       (self.config.iconsize + self.config.iconspace)
+               x2=y * self.config.getIconSizeFull()
+               y2=(self.size[1]-x-1) * self.config.getIconSizeFull()
 
            # Only repaint the needed icons
            rect=gdk.Rectangle(x2, y2, w, w)
@@ -134,7 +259,29 @@ class IconGrid(object):    #(gobject.GObject):
                continue
 
            ico=self.icons.get(x,y)
-           ico.draw(cr, x2, y2, self.mode)
+           ico.draw(cr, x2, y2)
+
+    def setAngle(self, angle):
+       """ Return True/False indicating that angle has changed """
+       ret=False
+       for x,y in self.icons:
+           ic=self.icons.get(x,y)
+           if ic.setAngle(angle):
+               ret=True
+
+       return(ret)
+
+    def clearAnimationCache(self):
+       """ Clear animation cache, freeing memory """
+       for x,y in self.icons:
+           ic=self.icons.get(x,y)
+           ic.clearAnimationCache()
+
+    def clearBgCache(self):
+       """ Clear backgrounds cache """
+       for x,y in self.icons:
+           ic=self.icons.get(x,y)
+           ic.clearBgCache()
 
     def do_expose_event(self, event):
        cr=self.window.cairo_create()
@@ -144,6 +291,10 @@ class IconGrid(object):    #(gobject.GObject):
 
        cr.clip()
 
+       if not self.init_done:
+           self.icons.setWindow(self.window)
+           self.init_done=True
+
        self._draw(cr, event)
 
     def setLastIcon(self, icon):
@@ -215,6 +366,7 @@ class IconGrid(object):     #(gobject.GObject):
 
     def reloadIcons(self):
        self.icons.load()
+       self.lasticon=None
 
 #    def on_orientation_changed(self, orientation):
 #      print "orch:", orientation
@@ -222,25 +374,42 @@ class IconGrid(object):   #(gobject.GObject):
 #      self.setMode(o)
 
 class IconGridWidget(IconGrid, gtk.Widget):
-    def __init__(self, isconfig, config):
+    def __init__(self, isconfig, config, animation=True):
        IconGrid.__init__(self, isconfig)
        gtk.Widget.__init__(self)
 
+       # This must be called before do_realize
+       self.setAnimationEnable(animation)
+
        self.config=config
 
        IconGrid.do_realize(self, self.config)
 
-       if isconfig:
-           maxsz=self.config.getMaxSize()
-           w=maxsz[0] * (self.config.iconsize + self.config.iconspace)
-           h=maxsz[1] * (self.config.iconsize + self.config.iconspace)
-       else:
-           w=self.size[0] * (self.config.iconsize + self.config.iconspace)
-           h=self.size[1] * (self.config.iconsize + self.config.iconspace)
+       self.setSize(self.size)
+
+#      print "igw-init"
+
+#    def __del__(self):
+#      print "igw-del"
+
+    def setSize(self, size):
+       IconGrid.setSize(self, size)
+
+       w=self.size[0] * self.config.getIconSizeFull()
+       h=self.size[1] * self.config.getIconSizeFull()
 
        self.set_size_request(w, h)
 
+    def reconfig(self):
+       self.clearBgCache()
+       self.clearAnimationCache()
+       self.reloadIcons()
+       self.setSize(self.size)
+       self.icons.resizeMax()
+       self.queue_draw()
+
     def do_realize(self):
+#      print "igw-realize"
        screen=self.get_screen()
        self.set_colormap(screen.get_rgba_colormap())
        self.set_app_paintable(True)
@@ -263,9 +432,21 @@ class IconGridWidget(IconGrid, gtk.Widget):
                | gdk.LEAVE_NOTIFY_MASK )
 
        self.window.set_user_data(self)
-       self.style.attach(self.window)
 
-#      self.style.set_background(self.window, gtk.STATE_NORMAL)
+       # No matter what the pygtk widget demo says, this is NOT CORRECT!!!
+       # Don't call style.attach(self.window) or else the program will crash
+       # after some time! It seems that there is a style already.
+       # If we want to use the style the we use get_style() instead.
+       # This one was very hard to solve. Thanks to gnome2-globalmenu guys.
+       # It was solved by looking the commit 2666:
+       # see:
+       # svn diff -r2665:2666 http://gnome2-globalmenu.googlecode.com/svn/trunk
+       # which solved cse 490:
+       # http://code.google.com/p/gnome2-globalmenu/issues/detail?id=490
+#      self.style.attach(self.window)
+       style=self.get_style()
+
+#      style.set_background(self.window, gtk.STATE_NORMAL)
        self.window.move_resize(*self.allocation)
 
 #      self.pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
@@ -273,7 +454,6 @@ class IconGridWidget(IconGrid, gtk.Widget):
        
 #      self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
 
-       #gtk.Widget.do_realize(self)
        #HomePluginItem.do_realize(self)
 
 #      screen=self.get_screen()
@@ -281,8 +461,24 @@ class IconGridWidget(IconGrid, gtk.Widget):
 #      self.set_app_paintable(True)
 
     def do_unrealize(self):
-       #self.window.set_user_data(None)
+#      print "igw-unrealize", self
+       IconGrid.do_unrealize(self)
        self.window.destroy()
+       self.window.set_user_data(None)
+
+    def do_expose_event(self, event):
+       cr=self.window.cairo_create()
+
+       cr.rectangle(event.area.x, event.area.y,
+           event.area.width, event.area.height)
+       cr.clip()
+
+       style=self.get_style()
+       col=style.bg[gtk.STATE_NORMAL]
+       cr.set_source_color(col)
+       cr.paint()
+
+       IconGrid.do_expose_event(self, event)
 
 #gobject.type_register(IconGrid)
 gobject.type_register(IconGridWidget)