libegg r836 - in trunk: . libegg/toolpalette



Author: hasselmm
Date: Fri Jan 11 11:47:38 2008
New Revision: 836
URL: http://svn.gnome.org/viewvc/libegg?rev=836&view=rev

Log:
Implement composited expand/collapse animation.

* libegg/toolpalette/eggtoolitemgroup.h: Indent fixes.
* libegg/toolpalette/eggtoolitemgroup.c: Implement animation.
* libegg/toolpalette/eggtoolpalette.c: Draw composited
EggToolItemGroup. Delegate item group size calculation
to _egg_tool_item_group_get_height_for_width().
* libegg/toolpalette/eggtoolpaletteprivate.h:
Add _egg_tool_item_group_get_height_for_width() and
_egg_tool_item_group_paint().


Modified:
   trunk/ChangeLog
   trunk/libegg/toolpalette/eggtoolitemgroup.c
   trunk/libegg/toolpalette/eggtoolitemgroup.h
   trunk/libegg/toolpalette/eggtoolpalette.c
   trunk/libegg/toolpalette/eggtoolpaletteprivate.h

Modified: trunk/libegg/toolpalette/eggtoolitemgroup.c
==============================================================================
--- trunk/libegg/toolpalette/eggtoolitemgroup.c	(original)
+++ trunk/libegg/toolpalette/eggtoolitemgroup.c	Fri Jan 11 11:47:38 2008
@@ -30,8 +30,10 @@
 
 #include <string.h>
 
-#define DEFAULT_EXPANDER_SIZE   16
-#define DEFAULT_HEADER_SPACING  2
+#define ANIMATION_TIMEOUT        50
+#define ANIMATION_DURATION      (ANIMATION_TIMEOUT * 6)
+#define DEFAULT_EXPANDER_SIZE    16
+#define DEFAULT_HEADER_SPACING   2
 
 #define P_(msgid) _(msgid)
 
@@ -47,7 +49,8 @@
   GtkWidget        *header;
   GArray           *items;
 
-  guint             animation_timeout;
+  gint64            animation_start;
+  GSource          *animation_timeout;
   GtkExpanderStyle  expander_style;
   gint              expander_size;
   gint              header_spacing;
@@ -230,6 +233,18 @@
 }
 
 static void
+egg_tool_item_group_get_item_size (EggToolItemGroup *group,
+                                   GtkRequisition   *item_size)
+{
+  GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (group));
+
+  if (EGG_IS_TOOL_PALETTE (parent))
+    _egg_tool_palette_get_item_size (EGG_TOOL_PALETTE (parent), item_size);
+  else
+    _egg_tool_item_group_item_size_request (group, item_size);
+}
+
+static void
 egg_tool_item_group_size_allocate (GtkWidget     *widget,
                                    GtkAllocation *allocation)
 {
@@ -238,17 +253,10 @@
   GtkRequisition child_requistion;
   GtkAllocation child_allocation;
   GtkRequisition item_size;
-  GtkWidget *parent;
   guint i;
 
   GTK_WIDGET_CLASS (egg_tool_item_group_parent_class)->size_allocate (widget, allocation);
-
-  parent = gtk_widget_get_parent (widget);
-
-  if (EGG_IS_TOOL_PALETTE (parent))
-    _egg_tool_palette_get_item_size (EGG_TOOL_PALETTE (parent), &item_size);
-  else
-    _egg_tool_item_group_item_size_request (group, &item_size);
+  egg_tool_item_group_get_item_size (group, &item_size);
 
   child_allocation.x = border_width;
   child_allocation.y = border_width;
@@ -265,7 +273,7 @@
       child_allocation.y += child_allocation.height;
     }
 
-    if (group->priv->expanded)
+    if (group->priv->expanded || group->priv->animation_timeout)
       {
         for (i = 0; i < group->priv->items->len; ++i)
           {
@@ -308,6 +316,7 @@
   const gint border_width = GTK_CONTAINER (widget)->border_width;
   gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
   GdkWindowAttr attributes;
+  GdkDisplay *display;
 
   attributes.window_type = GDK_WINDOW_CHILD;
   attributes.x = widget->allocation.x + border_width;
@@ -324,6 +333,11 @@
   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
                                    &attributes, attributes_mask);
 
+  display = gdk_drawable_get_display (widget->window);
+
+  if (gdk_display_supports_composite (display))
+    gdk_window_set_composited (widget->window, TRUE);
+
   gdk_window_set_user_data (widget->window, widget);
   widget->style = gtk_style_attach (widget->style, widget->window);
   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
@@ -506,16 +520,24 @@
     }
 }
 
+static gint64
+egg_tool_item_group_get_animation_timestamp (EggToolItemGroup *group)
+{
+  GTimeVal now;
+  g_source_get_current_time (group->priv->animation_timeout, &now);
+  return (now.tv_sec * G_USEC_PER_SEC + now.tv_usec - group->priv->animation_start) / 1000;
+}
+
 static gboolean
 egg_tool_item_group_animation_cb (gpointer data)
 {
   EggToolItemGroup *group = EGG_TOOL_ITEM_GROUP (data);
-  gboolean finish = TRUE;
-  GdkRectangle area;
+  gint64 timestamp = egg_tool_item_group_get_animation_timestamp (group);
 
   if (GTK_WIDGET_REALIZED (group->priv->header))
     {
       GtkWidget *alignment = egg_tool_item_group_get_alignment (group);
+      GdkRectangle area;
 
       area.x = alignment->allocation.x;
       area.y = alignment->allocation.y + (alignment->allocation.height - group->priv->expander_size) / 2;
@@ -525,34 +547,47 @@
       gdk_window_invalidate_rect (group->priv->header->window, &area, TRUE);
     }
 
-  if (group->priv->expanded)
+  if (GTK_WIDGET_REALIZED (group))
     {
-      if (group->priv->expander_style == GTK_EXPANDER_COLLAPSED)
+      GtkWidget *widget = GTK_WIDGET (group);
+      GtkWidget *parent = gtk_widget_get_parent (widget);
+
+      gint width = widget->allocation.width;
+      gint height = widget->allocation.height;
+      gint x, y;
+
+      gtk_widget_translate_coordinates (widget, parent, 0, 0, &x, &y);
+
+      if (GTK_WIDGET_VISIBLE (group->priv->header))
         {
-          group->priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
-          finish = FALSE;
+          height -= group->priv->header->allocation.height;
+          y += group->priv->header->allocation.height;
         }
+
+      gtk_widget_queue_draw_area (parent, x, y, width, height);
+    }
+
+  if (group->priv->expanded)
+    {
+      if (group->priv->expander_style == GTK_EXPANDER_COLLAPSED)
+        group->priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
       else
         group->priv->expander_style = GTK_EXPANDER_EXPANDED;
     }
   else
     {
       if (group->priv->expander_style == GTK_EXPANDER_EXPANDED)
-        {
-          group->priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
-          finish = FALSE;
-        }
+        group->priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
       else
         group->priv->expander_style = GTK_EXPANDER_COLLAPSED;
     }
 
-  if (finish)
-    {
-      group->priv->animation_timeout = 0;
-      gtk_widget_queue_resize_no_redraw (GTK_WIDGET (group));
-    }
+  if (timestamp >= ANIMATION_DURATION)
+    group->priv->animation_timeout = NULL;
+
+  gtk_widget_queue_resize_no_redraw (GTK_WIDGET (group));
 
-  return !finish;
+  return (group->priv->animation_timeout != NULL);
 }
 
 void
@@ -563,12 +598,22 @@
 
   if (expanded != group->priv->expanded)
     {
+      GTimeVal now;
+
+      g_get_current_time (&now);
+
       if (group->priv->animation_timeout)
-        g_source_remove (group->priv->animation_timeout);
+        g_source_destroy (group->priv->animation_timeout);
 
       group->priv->expanded = expanded;
-      group->priv->animation_timeout = g_timeout_add (50, egg_tool_item_group_animation_cb, group);
+      group->priv->animation_start = (now.tv_sec * G_USEC_PER_SEC + now.tv_usec);
+      group->priv->animation_timeout = g_timeout_source_new (ANIMATION_TIMEOUT);
 
+      g_source_set_callback (group->priv->animation_timeout,
+                             egg_tool_item_group_animation_cb,
+                             group, NULL);
+
+      g_source_attach (group->priv->animation_timeout, NULL);
       g_object_notify (G_OBJECT (group), "expanded");
     }
 }
@@ -702,3 +747,84 @@
       item_size->height = MAX (item_size->height, child_requisition.height);
     }
 }
+
+void
+_egg_tool_item_group_paint (EggToolItemGroup *group,
+                            cairo_t          *cr)
+{
+  GtkWidget *widget = GTK_WIDGET (group);
+
+  gdk_cairo_set_source_pixmap (cr, widget->window,
+                               widget->allocation.x,
+                               widget->allocation.y);
+
+  if (group->priv->animation_timeout)
+    {
+      cairo_pattern_t *mask;
+      gdouble y0, y1;
+
+      y0 = widget->allocation.height - 256;
+      y1 = widget->allocation.height;
+
+      if (GTK_WIDGET_VISIBLE (group->priv->header))
+        y0 = MAX (y0, group->priv->header->allocation.height);
+      else
+        y0 = MAX (y0, 0);
+
+      y1 = MIN (y0 + 256, y1);
+
+      y0 += widget->allocation.y;
+      y1 += widget->allocation.y;
+
+      mask = cairo_pattern_create_linear (0.0, y0, 0.0, y1);
+
+      cairo_pattern_add_color_stop_rgba (mask, 0.00, 0.0, 0.0, 0.0, 1.00);
+      cairo_pattern_add_color_stop_rgba (mask, 0.25, 0.0, 0.0, 0.0, 0.25);
+      cairo_pattern_add_color_stop_rgba (mask, 0.50, 0.0, 0.0, 0.0, 0.10);
+      cairo_pattern_add_color_stop_rgba (mask, 0.75, 0.0, 0.0, 0.0, 0.01);
+      cairo_pattern_add_color_stop_rgba (mask, 1.00, 0.0, 0.0, 0.0, 0.00);
+
+      cairo_mask (cr, mask);
+      cairo_pattern_destroy (mask);
+    }
+  else
+    cairo_paint (cr);
+}
+
+gint
+_egg_tool_item_group_get_height_for_width (EggToolItemGroup *group,
+                                           gint              width)
+{
+  guint n_items = group->priv->items->len;
+  GtkRequisition child_requisition;
+
+  gtk_widget_size_request (GTK_WIDGET (group), &child_requisition);
+
+  if (n_items && (group->priv->expanded || group->priv->animation_timeout))
+    {
+      gint n_columns, n_rows, height;
+      GtkRequisition item_size;
+
+      egg_tool_item_group_get_item_size (group, &item_size);
+
+      n_columns = width / item_size.width;
+      n_rows = (n_items + n_columns - 1) / n_columns;
+      height = item_size.height * n_rows;
+
+      if (group->priv->animation_timeout)
+        {
+          gint64 timestamp = egg_tool_item_group_get_animation_timestamp (group);
+
+          timestamp = MIN (timestamp, ANIMATION_DURATION);
+
+          if (!group->priv->expanded)
+            timestamp = ANIMATION_DURATION - timestamp;
+
+          height = height * timestamp / ANIMATION_DURATION;
+        }
+
+      child_requisition.height += height;
+    }
+
+  return child_requisition.height;
+}

Modified: trunk/libegg/toolpalette/eggtoolitemgroup.h
==============================================================================
--- trunk/libegg/toolpalette/eggtoolitemgroup.h	(original)
+++ trunk/libegg/toolpalette/eggtoolitemgroup.h	Fri Jan 11 11:47:38 2008
@@ -50,7 +50,7 @@
 };
 
 GType                 egg_tool_item_group_get_type          (void) G_GNUC_CONST;
-GtkWidget*            egg_tool_item_group_new               (const gchar *name);
+GtkWidget*            egg_tool_item_group_new               (const gchar      *name);
 
 void                  egg_tool_item_group_set_name          (EggToolItemGroup *group,
                                                              const gchar      *name);

Modified: trunk/libegg/toolpalette/eggtoolpalette.c
==============================================================================
--- trunk/libegg/toolpalette/eggtoolpalette.c	(original)
+++ trunk/libegg/toolpalette/eggtoolpalette.c	Fri Jan 11 11:47:38 2008
@@ -245,7 +245,6 @@
 {
   const gint border_width = GTK_CONTAINER (widget)->border_width;
   EggToolPalette *palette = EGG_TOOL_PALETTE (widget);
-  GtkRequisition child_requisition;
   GtkAllocation child_allocation;
   gint offset = 0;
   guint i;
@@ -262,25 +261,18 @@
   for (i = 0; i < palette->priv->groups->len; ++i)
     {
       EggToolItemGroup *group = egg_tool_palette_get_group (palette, i);
-      gint n_items = egg_tool_item_group_get_n_items (group);
 
-      if (!n_items)
-        continue;
-
-      gtk_widget_size_request (GTK_WIDGET (group), &child_requisition);
-      child_allocation.height = child_requisition.height;
-
-      if (egg_tool_item_group_get_expanded (group))
+      if (egg_tool_item_group_get_n_items (group))
         {
-        /* TODO: Use gtk_widget_get_height_for_width */
-          gint n_columns = child_allocation.width / palette->priv->item_size.width;
-          gint n_rows = (n_items + n_columns - 1) / n_columns;
+          child_allocation.height = _egg_tool_item_group_get_height_for_width (group, child_allocation.width);
 
-          child_allocation.height += palette->priv->item_size.height * n_rows;
-        }
+          gtk_widget_size_allocate (GTK_WIDGET (group), &child_allocation);
+          gtk_widget_show (GTK_WIDGET (group));
 
-      gtk_widget_size_allocate (GTK_WIDGET (group), &child_allocation);
-      child_allocation.y += child_allocation.height;
+          child_allocation.y += child_allocation.height;
+        }
+      else
+          gtk_widget_hide (GTK_WIDGET (group));
     }
 
   child_allocation.y += border_width;
@@ -301,19 +293,31 @@
 egg_tool_palette_expose_event (GtkWidget      *widget,
                                GdkEventExpose *event)
 {
-  EggToolPalette *palette =  EGG_TOOL_PALETTE (widget);
+  EggToolPalette *palette = EGG_TOOL_PALETTE (widget);
+  GdkDisplay *display;
+  cairo_t *cr;
   guint i;
 
   if (GTK_WIDGET_CLASS (egg_tool_palette_parent_class)->expose_event (widget, event))
     return TRUE;
 
+  display = gdk_drawable_get_display (widget->window);
+  if (!gdk_display_supports_composite (display))
+    return FALSE;
+
+  cr = gdk_cairo_create (widget->window);
+  cairo_push_group (cr);
+
   for (i = 0; i < palette->priv->groups->len; ++i)
     {
-/* TODO: draw composited window
       EggToolItemGroup *group = egg_tool_palette_get_group (palette, i);
-*/
+      _egg_tool_item_group_paint (group, cr);
     }
 
+  cairo_pop_group_to_source (cr);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
   return FALSE;
 }
 

Modified: trunk/libegg/toolpalette/eggtoolpaletteprivate.h
==============================================================================
--- trunk/libegg/toolpalette/eggtoolpaletteprivate.h	(original)
+++ trunk/libegg/toolpalette/eggtoolpaletteprivate.h	Fri Jan 11 11:47:38 2008
@@ -25,12 +25,16 @@
 #include "eggtoolpalette.h"
 #include "eggtoolitemgroup.h"
 
-void _egg_tool_palette_get_item_size        (EggToolPalette   *palette,
-                                             GtkRequisition   *item_size);
-void _egg_tool_palette_item_set_drag_source (GtkWidget        *widget,
-                                             gpointer          data);
+void _egg_tool_palette_get_item_size           (EggToolPalette   *palette,
+                                                GtkRequisition   *item_size);
+void _egg_tool_palette_item_set_drag_source    (GtkWidget        *widget,
+                                                gpointer          data);
 
-void _egg_tool_item_group_item_size_request (EggToolItemGroup *group,
-                                             GtkRequisition   *item_size);
+void _egg_tool_item_group_item_size_request    (EggToolItemGroup *group,
+                                                GtkRequisition   *item_size);
+gint _egg_tool_item_group_get_height_for_width (EggToolItemGroup *group,
+                                                gint              width);
+void _egg_tool_item_group_paint                (EggToolItemGroup *group,
+                                                cairo_t          *cr);
 
 #endif /* __EGG_TOOL_PALETTE_PRIVATE_H__ */



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