summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Seguin <guillaume@segu.in>2007-12-29 03:39:52 +0100
committerGuillaume Seguin <guillaume@segu.in>2007-12-29 03:39:52 +0100
commit82f9745764cbc6d4869d24e9cc46e2a69f2d2112 (patch)
tree7ca3e9d315bdff425ec63078f019df15fd9deadd
parent18fed8ef43e08311417997b11ef6623af2c743de (diff)
downloadgnome-about-82f9745764cbc6d4869d24e9cc46e2a69f2d2112.tar.gz
gnome-about-82f9745764cbc6d4869d24e9cc46e2a69f2d2112.tar.bz2
* Add mirroring effect to contributors animated label
-rwxr-xr-xgnome-about.py139
1 files changed, 134 insertions, 5 deletions
diff --git a/gnome-about.py b/gnome-about.py
index 8cd6613..90a9f24 100755
--- a/gnome-about.py
+++ b/gnome-about.py
@@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Authors:
Guillaume Seguin <guillaume@segu.in>
Vincent Untz <vuntz@gnome.org> (get_language_names () helper function)
+ Mirco Müller <mirco.mueller@ubuntu.com> (C code for the mirror effect)
'''
import pygtk
@@ -514,7 +515,7 @@ class HorzAnimatedLabel (AnimatedLabel):
def on_style_set (self, *args):
'''Update Layout height if a style change (such as a font change)
made the label bigger than the container'''
- label_height = self.label.get_layout ().get_pixel_size ()[1] + 10
+ label_height = self.label.get_layout ().get_pixel_size ()[1]
height = self.size_request ()[1]
if height < label_height:
self.set_size_request (self.size_request ()[0], label_height)
@@ -920,6 +921,129 @@ first)'''
gobject.type_register (GnomeAboutHeader)
+def cairo_set_source_window (cr, window, x, y):
+ '''Workaround current PyGTK bindings: set_source_pixmap should accept any
+ kind of gtk.gdk.Drawable and not just gtk.gdk.Pixmap as the C function
+ does (hackily?)'''
+ try:
+ cr.set_source_pixmap (window, x, y)
+ except TypeError:
+ cr.set_source_surface (window.cairo_create().get_target(), x, y)
+
+class GtkMirroredWidget (gtk.Bin):
+ '''Add a pretty reflection effect to a GTK widget'''
+
+ widget = None
+
+ def __init__ (self, widget):
+ '''Initialize object and apply compositing tricks'''
+ gtk.Bin.__init__ (self)
+ self.widget = gtk.EventBox ()
+ '''Set the colormap for the EventBox, which must be done before the
+ widget is realised.'''
+ screen = self.widget.get_screen ()
+ colormap = screen.get_rgba_colormap ()
+ self.widget.set_colormap (colormap)
+ alignment = gtk.Alignment (0.5, 0, 1, 0)
+ alignment.add (widget)
+ self.widget.add (alignment)
+ '''Make the EventBox background fully transparent'''
+ self.widget.set_app_paintable (True)
+ widget.connect ("expose-event", self.transparent_expose)
+ self.add (self.widget)
+
+ self.connect ("show", self.on_show)
+
+ def on_show (self, widget):
+ '''Realize child widget and plug compositing stuff'''
+ self.widget.show_all ()
+ self.widget.realize ()
+
+ '''Set the EventBox gdk.Window to be composited, which can only be
+ done after the window has been created, i.e. the widget has been
+ realised'''
+ self.widget.window.set_composited (True)
+
+ '''Connect our custom expose event handler'''
+ self.connect ("expose-event", self.expose)
+
+ def do_size_request (self, requisition):
+ '''Request twice as much (height-wise) space as the child widget'''
+ request = self.widget.size_request ()
+ requisition.width = request[0]
+ requisition.height = 2 * request[1]
+
+ def do_size_allocate (self, allocation):
+ '''Allocate top half of the allocated size to the child widget'''
+ self.allocation = allocation
+ child_alloc = gtk.gdk.Rectangle ()
+ child_alloc.x = allocation.x
+ child_alloc.y = allocation.y
+ request = self.widget.size_request ()
+ child_alloc.width = allocation.width
+ child_alloc.height = min (request[1], allocation.height / 2)
+ self.widget.size_allocate (child_alloc)
+
+ def expose (self, widget, event):
+ '''Expose event handler for the whole widget'''
+ cr = self.window.cairo_create ()
+ cr.set_operator (cairo.OPERATOR_OVER)
+ '''Clip to event area'''
+ cr.rectangle (event.area)
+ cr.clip ()
+
+ '''Clear the surface to the background color'''
+ cr.set_source_color (self.get_style ().bg[gtk.STATE_NORMAL])
+ cr.paint ()
+
+ height = self.widget.allocation.height
+ if event.area.y < self.widget.allocation.y + height:
+ '''We are painting on the top (i.e. original) part of the widget,
+ damage the corresponding mirrored part and do the painting'''
+ y0 = self.widget.allocation.y + height \
+ + max (0, height - event.area.y - event.area.height)
+ rect = gtk.gdk.Rectangle (event.area.x, y0,
+ event.area.width, event.area.height)
+ self.window.invalidate_rect (rect, False)
+
+ cairo_set_source_window (cr, self.widget.window,
+ self.widget.allocation.x,
+ self.widget.allocation.y)
+ cr.paint ()
+ else:
+ '''Transform context to do the mirror effect'''
+ y0 = 2 * (self.widget.allocation.y + height)
+ matrix = cairo.Matrix (yy = -1, y0 = y0)
+ cr.transform (matrix)
+
+ cairo_set_source_window (cr, self.widget.window,
+ self.widget.allocation.x,
+ self.widget.allocation.y)
+ '''Paint the mirrored widget with a linear gradient mask'''
+ y0 = self.widget.allocation.y + height
+ mask = cairo.LinearGradient (0, self.widget.allocation.y, 0, y0)
+ mask.add_color_stop_rgba (0, 0, 0, 0, 0)
+ mask.add_color_stop_rgba (0.25, 0, 0, 0, 0.01)
+ mask.add_color_stop_rgba (0.5, 0, 0, 0, 0.25)
+ mask.add_color_stop_rgba (0.75, 0, 0, 0, 0.5)
+ mask.add_color_stop_rgba (1, 0, 0, 0, 0.6)
+ cr.mask (mask)
+
+ return True
+
+ def transparent_expose (self, widget, event):
+ '''Clear the child widget's pixmap'''
+ cr = self.widget.window.cairo_create ()
+
+ cr.set_operator (cairo.OPERATOR_CLEAR)
+
+ cr.rectangle (event.area)
+ cr.fill ()
+
+ return False
+
+gobject.type_register (GtkMirroredWidget)
+
class GnomeAbout (gtk.Dialog):
'''Super pretty About Dialog for the GNOME Desktop'''
@@ -998,18 +1122,23 @@ class GnomeAbout (gtk.Dialog):
by_label.set_markup ("<big><b>%s</b></big>" % _("Brought to you by:"))
main_box.pack_start (by_label)
- alignment = gtk.Alignment (0.5, 0.5)
'''Realize the header right now to get everything (especially the
contributors list) correctly positionned and sized.'''
self.header.realize ()
width = self.header.width
label = HorzAnimatedLabel (self.contributors, width,
- 30, CONTRIBUTOR_DELAY, "<b>%s</b>")
+ -1, CONTRIBUTOR_DELAY, "<b>%s</b>")
by_label.connect ("button-press-event", label.on_button_press)
label.show_all ()
- alignment.add (label)
+ widget = GtkMirroredWidget (label)
+ alignment = gtk.Alignment (0.5, 0.5)
+ alignment.set_padding (10, 10, 0, 0)
+ alignment.add (widget)
+ box = gtk.EventBox ()
+ box.add (alignment)
+ box.connect ("button-press-event", label.on_button_press)
- main_box.pack_start (alignment)
+ main_box.pack_start (box)
'''System info labels'''
def make_info_label (info):