r6995 - in bigboard/trunk: . bigboard bigboard/libbig bigboard/stocks/self bigboard/themes



Author: walters
Date: 2007-12-07 18:37:43 -0600 (Fri, 07 Dec 2007)
New Revision: 6995

Added:
   bigboard/trunk/bigboard/libbig/signalobject.py
Modified:
   bigboard/trunk/bigboard/big_widgets.py
   bigboard/trunk/bigboard/stocks/self/SelfStock.py
   bigboard/trunk/bigboard/themes/default.py
   bigboard/trunk/bigboard/themes/fedora.py
   bigboard/trunk/main.py
Log:
More theming infrastructure.



Modified: bigboard/trunk/bigboard/big_widgets.py
===================================================================
--- bigboard/trunk/bigboard/big_widgets.py	2007-12-08 00:04:48 UTC (rev 6994)
+++ bigboard/trunk/bigboard/big_widgets.py	2007-12-08 00:37:43 UTC (rev 6995)
@@ -1,4 +1,4 @@
-import os, code, sys, traceback, logging, StringIO, threading, urlparse
+import os, code, sys, traceback, logging, StringIO, threading, urlparse, weakref
 
 import cairo
 import pango
@@ -11,8 +11,12 @@
 from libgimmie import DockWindow
 from libbig.imagecache import URLImageCache
 import libbig, stock, globals, bigboard
+from bigboard.libbig.signalobject import SignalObject
+from bigboard.libbig.singletonmixin import Singleton
 from table_layout import TableLayout
 
+_logger = logging.getLogger("bigboard.BigWidgets")
+
 class CanvasVBox(hippo.CanvasBox):
     def __init__(self, **kwargs):
         kwargs['orientation'] = hippo.ORIENTATION_VERTICAL
@@ -29,6 +33,74 @@
         self.spinner = gtk.SpinButton()
         self.set_property('widget', self.spinner)
 
+class ThemeManager(gobject.GObject):
+    __gsignals__ = {
+                    'theme-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+                   }
+    def __init__(self):
+        super(ThemeManager, self).__init__()
+        self.__class__.instance = weakref.ref(self)
+        self.__theme = None
+        gconf.client_get_default().notify_add('/apps/bigboard/theme', self.__sync_theme)
+        self.__sync_theme()
+        
+    @staticmethod
+    def getInstance():
+        needinst = False
+        if not hasattr(ThemeManager, 'instance'):
+            instvalue = None
+        else:
+            instref = getattr(ThemeManager, 'instance')
+            instvalue = instref()
+            needinst = instvalue is None
+        if instvalue is None:
+            inst = ThemeManager()
+        else:
+            inst = instvalue
+        return inst
+        
+    def get_theme(self):
+        return self.__theme
+        
+    def __sync_theme(self, *args):
+        _logger.debug("doing theme sync")
+        themename = gconf.client_get_default().get_string('/apps/bigboard/theme')
+        if themename == 'fedora':
+            from bigboard.themes.fedora import FedoraTheme
+            self.__theme = FedoraTheme.getInstance()
+        else:
+            from bigboard.themes.default import DefaultTheme
+            self.__theme = DefaultTheme.getInstance()        
+        self.emit('theme-changed')            
+         
+class ThemedWidgetMixin(object):
+    def __init__(self):
+        super(ThemedWidgetMixin, self).__init__()
+        mgr = ThemeManager.getInstance()
+        self.__boundprops = {}
+        mgr.connect('theme-changed', self.__sync_theme)
+        
+    def get_theme(self):
+        return ThemeManager.getInstance().get_theme()
+
+    def _theme_bind(self, bindings):
+        self.__boundprops.update(bindings)
+        self._on_theme_change(ThemeManager.getInstance())
+        
+    def _on_theme_change(self, tm):
+        print "tc, bindings: %s" % (self.__boundprops)
+        for binding,func in self.__boundprops.iteritems():
+            self.set_property(binding, func(tm.get_theme()))
+        
+    def __sync_theme(self, tm):
+        self._on_theme_change(tm)       
+        
+class ThemedText(hippo.CanvasText, ThemedWidgetMixin):
+    def __init__(self, **kwargs):
+        super(ThemedText, self).__init__(**kwargs)
+        ThemedWidgetMixin.__init__(self)
+        self._theme_bind({'color': lambda t: t.foreground})
+
 class CanvasCheckbox(hippo.CanvasWidget):
     def __init__(self, label):
         super(CanvasCheckbox, self).__init__()
@@ -52,7 +124,7 @@
         self.__layout.set_row_expand(row, expand)        
         
 
-class GradientHeader(hippo.CanvasGradient):
+class GradientHeader(hippo.CanvasGradient, ThemedWidgetMixin):
     def __init__(self, **kwargs):
         hippo.CanvasGradient.__init__(self, 
                                       orientation=hippo.ORIENTATION_HORIZONTAL,

Added: bigboard/trunk/bigboard/libbig/signalobject.py
===================================================================
--- bigboard/trunk/bigboard/libbig/signalobject.py	2007-12-08 00:04:48 UTC (rev 6994)
+++ bigboard/trunk/bigboard/libbig/signalobject.py	2007-12-08 00:37:43 UTC (rev 6995)
@@ -0,0 +1,77 @@
+import weakref
+
+## Adapted from:
+## http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056
+## by Patrick O'Brien, under the Python License
+
+class SignalObject(object):
+    """An object which can emit signals, similar in style
+    to GObject but usable as a non-meta class.  Not threadsafe."""
+    def __init__(self):
+        self.__weakmethods = weakref.WeakKeyDictionary()
+        self.__signal_handlers = {}
+        
+    def connect(self, signame, handler, *args):
+        if signame not in self.__class__.pysignals:
+            raise ValueError("Unknown signal %s", signame)
+        try:
+            handlers = self.__signal_handlers.get(signame)
+        except KeyError, e:
+            handlers = []
+            self.__signal_handlers[signame] = handlers
+        funcref = self.__get_method_ref(handler)
+        argref = weakref.ref(args)
+        handlers.append((funcref, argref))
+        
+    def emit(self, signame, *args):
+        dead = []
+        handlers = self.__signal_handlers.get(signame, [])
+        for funcref, argref in handlers:
+            func = funcref()
+            fargs = argref()
+            if (func is None) or (fargs is None):
+                dead.append((funcref, argref))
+                continue
+            func(self, *(args + fargs))
+        for pair in dead:
+            handlers.remove(pair)
+
+    def __get_method_ref(self, obj):
+        """Return a *safe* weak reference to a callable object."""
+        if hasattr(object, 'im_self'):
+            if object.im_self is not None:
+                # Turn a bound method into a BoundMethodWeakref instance.
+                # Keep track of these instances for lookup by disconnect().
+                selfkey = object.im_self
+                funckey = object.im_func
+                if selfkey not in self.__weakmethods:
+                    self.__weakmethods[selfkey] = weakref.WeakKeyDictionary()
+                if funckey not in self.__weakmethods[selfkey]:
+                    self.__weakmethods[selfkey][funckey] = BoundMethodWeakref(boundMethod=obj)
+                return self.__weakmethods[selfkey][funckey]
+        return weakref.ref(object)
+
+class BoundMethodWeakref:
+    """BoundMethodWeakref class."""
+    def __init__(self, boundMethod):
+        """Return a weak-reference-like instance for a bound method."""
+        self.isDead = False
+        self.weakSelf = weakref.ref(boundMethod.im_self, self.__set_dead)
+        self.weakFunc = weakref.ref(boundMethod.im_func, self.__set_dead)
+    
+    def __set_dead(self):
+        self.isDead = True    
+    
+    def __repr__(self):
+        """Return the closest representation."""
+        return repr(self.weakFunc)
+    def __call__(self):
+        """Return a strong reference to the bound method."""
+        if self.isDead:
+            return None
+        else:
+            object = self.weakSelf()
+            method = self.weakFunc().__name__
+            return getattr(object, method)
+ 
+__all__ = ['SignalObject']

Modified: bigboard/trunk/bigboard/stocks/self/SelfStock.py
===================================================================
--- bigboard/trunk/bigboard/stocks/self/SelfStock.py	2007-12-08 00:04:48 UTC (rev 6994)
+++ bigboard/trunk/bigboard/stocks/self/SelfStock.py	2007-12-08 00:37:43 UTC (rev 6995)
@@ -13,7 +13,8 @@
 import bigboard.libbig as libbig
 from bigboard.workboard import WorkBoard
 from bigboard.stock import Stock, AbstractMugshotStock
-from bigboard.big_widgets import CanvasMugshotURLImage, PhotoContentItem, CanvasVBox, CanvasHBox, ActionLink, IconLink, Separator
+from bigboard.big_widgets import CanvasMugshotURLImage, PhotoContentItem, CanvasVBox, CanvasHBox
+from bigboard.big_widgets import ActionLink, IconLink, Separator, ThemedText
 import bigboard.google
 
 import portfoliomanager
@@ -257,7 +258,7 @@
         self._namephoto_box.set_photo(self._photo)
         
         self._namephoto_box_child = CanvasHBox()
-        self._name = hippo.CanvasText(text="Nobody", size_mode=hippo.CANVAS_SIZE_ELLIPSIZE_END)
+        self._name = ThemedText(text="Nobody", size_mode=hippo.CANVAS_SIZE_ELLIPSIZE_END)
         self._name.set_property("font", "14px Bold")
         self._namephoto_box_child.append(self._name)  
 

Modified: bigboard/trunk/bigboard/themes/default.py
===================================================================
--- bigboard/trunk/bigboard/themes/default.py	2007-12-08 00:04:48 UTC (rev 6994)
+++ bigboard/trunk/bigboard/themes/default.py	2007-12-08 00:37:43 UTC (rev 6995)
@@ -6,6 +6,8 @@
         super(DefaultTheme, self).__init__()
         self.background = 0xFFFFFFFF
         self.foreground = 0x000000FF
+        self.header_start = 0xF4F4F4FF
+        self.header_end = 0xC7C7C7FF
         
     def draw_header(self, cr, area):
         cr.set_source_rgb(1.0, 1.0, 1.0)

Modified: bigboard/trunk/bigboard/themes/fedora.py
===================================================================
--- bigboard/trunk/bigboard/themes/fedora.py	2007-12-08 00:04:48 UTC (rev 6994)
+++ bigboard/trunk/bigboard/themes/fedora.py	2007-12-08 00:37:43 UTC (rev 6995)
@@ -5,9 +5,11 @@
 
 class FedoraTheme(DefaultTheme):
     def __init__(self):
-        super(DefaultTheme, self).__init__()
+        super(FedoraTheme, self).__init__()
         self.background = 0x345B75FF
         self.foreground = 0xFFFFFFFF
+        self.header_start = 0x436A85FF
+        self.header_end = 0x59809CFF
         
     def draw_header(self, cr, area):
         cr.set_source_rgb(1.0, 1.0, 1.0)

Modified: bigboard/trunk/main.py
===================================================================
--- bigboard/trunk/main.py	2007-12-08 00:04:48 UTC (rev 6994)
+++ bigboard/trunk/main.py	2007-12-08 00:37:43 UTC (rev 6995)
@@ -18,7 +18,8 @@
 
 import bigboard
 import bigboard.big_widgets
-from bigboard.big_widgets import Sidebar, CanvasHBox, CanvasVBox, ActionLink, Button, GradientHeader
+from bigboard.big_widgets import Sidebar, CanvasHBox, CanvasVBox, ActionLink
+from bigboard.big_widgets import Button, GradientHeader, ThemedWidgetMixin, ThemeManager
 from bigboard.stock import Stock
 import bigboard.libbig
 try:
@@ -273,21 +274,29 @@
         self.widget = ggadget.Gadget(metainfo, env)
         self.widget.show_all() 
         self.set_property('widget', self.widget)
+        
+class ThemedGradient(hippo.CanvasGradient, ThemedWidgetMixin):
+    def __init__(self):
+        super(ThemedGradient, self).__init__()
+        self._on_theme_change()
+    def _on_theme_change(self, *args):
+        theme = self.get_theme()
+        _logger.debug("changing gradient %s %s", theme.header_start, theme.header_end)
+        self.set_property('start-color', theme.header_start)
+        self.set_property('end-color', theme.header_end)
          
-class Exchange(hippo.CanvasBox):
+class Exchange(hippo.CanvasBox, ThemedWidgetMixin):
     """A renderer for stocks."""
     
     def __init__(self, metainfo, env, pymodule=None, is_notitle=False, panel=None):
         hippo.CanvasBox.__init__(self,  
                                  orientation=hippo.ORIENTATION_VERTICAL,
-                                 spacing=4)      
+                                 spacing=4)
         self.__size = None
         self.__metainfo = metainfo
         self.__env = env
         self.__pymodule = pymodule
         self.__panel = panel
-        self.__themehandler = self.__sync_theme 
-        self.__panel.add_theme_listener(self.__themehandler)
         self.__ticker_text = None
         self.__ticker_container = None
         self.__mini_more_button = None
@@ -295,7 +304,7 @@
         self.append(self.__sep)
         self.__expanded = True
         if not is_notitle:
-            self.__ticker_container = GradientHeader()
+            self.__ticker_container = ThemedGradient()
             self.__ticker_text = hippo.CanvasText(text=metainfo.title, font="14px", xalign=hippo.ALIGNMENT_START)
             self.__ticker_text.connect("button-press-event", lambda text, event: self.__toggle_expanded())  
             self.__ticker_container.append(self.__ticker_text, hippo.PACK_EXPAND)
@@ -313,15 +322,15 @@
             self.append(self.__ticker_container)
         self.__stockbox = hippo.CanvasBox()
         self.append(self.__stockbox)
-        self.__sync_theme()
+        self._on_theme_change()
         if pymodule:
             pymodule.connect('visible', self.__render_pymodule)
             self.__render_pymodule()
         else:
             self.__render_google_gadget()    
 
-    def __sync_theme(self, *args):
-        theme = self.__panel.get_theme()
+    def _on_theme_change(self, *args):
+        theme = self.get_theme()
         self.set_property('background-color', theme.background)
 
     def on_delisted(self):
@@ -425,8 +434,8 @@
         
         self._main_box.append(self._stocks_box)
         
-        gconf_client.notify_add(GCONF_PREFIX + 'theme', self.__sync_theme)
-        self.__theme_listeners = []
+        self.__theme_mgr = ThemeManager.getInstance()
+        self.__theme_mgr.connect('theme-changed', self.__sync_theme)
         self.__sync_theme()    
   
         gconf_client.notify_add(GCONF_PREFIX + 'expand', self._sync_size)
@@ -558,24 +567,8 @@
         _logger.debug("queuing strut complete")
         
     def __sync_theme(self, *args):
-        _logger.debug("doing theme sync")
-        themename = gconf.client_get_default().get_string(GCONF_PREFIX + 'theme')
-        if themename == 'fedora':
-            from bigboard.themes.fedora import FedoraTheme
-            self.__theme = FedoraTheme.getInstance()
-        else:
-            from bigboard.themes.default import DefaultTheme
-            self.__theme = DefaultTheme.getInstance()
-                  
-        self._canvas.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#%6X" % (self.__theme.background >> 8,)))            
-        for ref in self.__theme_listeners:
-            listener = ref()
-            if listener:
-                listener()
-                
-    # We have manual signals here because we can't subclass GObject
-    def add_theme_listener(self, listener):
-        self.__theme_listeners.append(weakref.ref(listener))
+        theme = self.__theme_mgr.get_theme()
+        self._canvas.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#%6X" % (theme.background >> 8,)))
         
     def get_theme(self):
         return self.__theme



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]