[accounts-dialog: 2/2] Fancy tooltips



commit 806970d0b3d8ea05a1e2436eb53e4508e7b2b0ab
Merge: 95276aa d693506
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Feb 2 10:08:30 2010 -0500

    Fancy tooltips
    
    Show tooltips that explain what to do when things are not editable.
    To make this less boring, work out how to embed icons in the label.

 AUTHORS        |    8 ++
 src/main.c     |   94 ++++++++++++++++++++++++++-
 src/um-utils.c |  201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/um-utils.h |    9 +++
 4 files changed, 310 insertions(+), 2 deletions(-)
---
diff --cc AUTHORS
index eca0fd7,eca0fd7..d11be76
--- a/AUTHORS
+++ b/AUTHORS
@@@ -1,1 -1,1 +1,9 @@@
  Matthias Clasen <mclasen redhat com>
++
++The webcam support was done by Bastien Nocera.
++
++The fancy tooltip code was inspired by a gtk-demo example
++by Behdad Esfahbod.
++
++The shortname completion code was adapted from
++similar code in gnome-system-tools by Milan Bouchet-Valat.
diff --cc src/um-utils.c
index 5e29228,3c75cf5..5bb06b7
--- a/src/um-utils.c
+++ b/src/um-utils.c
@@@ -25,4 -25,262 +25,205 @@@
  #include <glib/gi18n.h>
  
  #include "um-utils.h"
 -#include "um-user-manager.h"
 -
 -gchar *
 -um_compute_short_name (const gchar *name)
 -{
 -        gchar **names;
 -        gint len;
 -        gchar *shortname;
 -        gchar *res;
 -        gchar *tmp;
 -        gint i;
 -        UmUserManager *manager;
 -        UmUser *user;
 -
 -        /* TODO: pluggable algorithms for this */
 -        names = g_strsplit (name, " ", 0);
 -        len = g_strv_length (names);
 -
 -        if (len == 0) {
 -                shortname = g_strdup ("");
 -        }
 -        else if (len == 1) {
 -                shortname = g_strndup (names[0], 8);
 -        }
 -        else {
 -                gchar *first;
 -                gchar *suffix;
 -                first = g_strndup (names[0], 1);
 -                suffix = g_strndup (names[1], 7);
 -                shortname = g_strconcat (first, suffix, NULL);
 -                g_free (first);
 -                g_free (suffix);
 -        }
 -
 -        res = g_ascii_strdown (shortname, -1);
 -
 -        g_strfreev (names);
 -        g_free (shortname);
 -
 -        if (res && res[0]) {
 -                manager = um_user_manager_ref_default ();
 -                tmp = g_strdup (res);
 -                for (i = 2; i < 10; i++) {
 -                        user = um_user_manager_get_user (manager, tmp);
 -                        if (user == NULL) {
 -                                g_free (res);
 -                                res = tmp;
 -                                break;
 -                        }
 -                        g_free (tmp);
 -                        tmp = g_strdup_printf ("%s%d", res, i);
 -                }
 -                g_object_unref (manager);
 -        }
 -
 -        return res;
 -}
  
+ typedef struct {
 -        const gchar *text;
 -        const gchar *placeholder_str;
 -        const gchar *stock_id;
++        gchar *text;
++        gchar *placeholder_str;
++        gchar *stock_id;
+         gunichar placeholder;
+         gulong query_id;
+ } IconShapeData;
+ 
+ static IconShapeData *
+ icon_shape_data_new (const gchar *text,
+                      const gchar *placeholder,
+                      const gchar *stock_id)
+ {
+         IconShapeData *data;
+ 
+         data = g_new0 (IconShapeData, 1);
+ 
+         data->text = g_strdup (text);
+         data->placeholder_str = g_strdup (placeholder);
+         data->placeholder = g_utf8_get_char_validated (placeholder, -1);
+         data->stock_id = g_strdup (stock_id);
+ 
+         return data;
+ }
+ 
+ static void
 -icon_shape_data_free (IconShapeData *data)
++icon_shape_data_free (gpointer user_data)
+ {
++        IconShapeData *data = user_data;
++
+         g_free (data->text);
+         g_free (data->placeholder_str);
+         g_free (data->stock_id);
+         g_free (data);
+ }
+ 
+ static void
+ icon_shape_renderer (cairo_t        *cr,
+                      PangoAttrShape *attr,
+                      gboolean        do_path,
+                      gpointer        user_data)
+ {
+         IconShapeData *data = user_data;
+         gdouble x, y;
+ 
+         cairo_get_current_point (cr, &x, &y);
+         if (GPOINTER_TO_UINT (attr->data) == data->placeholder) {
+                 gdouble ascent;
+                 gdouble height;
+                 gdouble width;
+                 GdkPixbuf *pixbuf;
+ 
+                 ascent = pango_units_to_double (attr->ink_rect.y);
+                 height = pango_units_to_double (attr->ink_rect.height);
+                 width = pango_units_to_double (attr->ink_rect.width);
+                 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                                    data->stock_id,
+                                                    (gint)height,
+                                                    GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_USE_BUILTIN,
+                                                    NULL);
+ 
+                 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+                 cairo_reset_clip (cr);
+                 gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y + ascent);
+                 cairo_paint (cr);
+                 g_object_unref (pixbuf);
+         }
+ }
+ 
 -PangoAttrList *
++static PangoAttrList *
+ create_shape_attr_list_for_layout (PangoLayout   *layout,
+                                    IconShapeData *data)
+ {
+         PangoAttrList *attrs;
+         PangoFontMetrics *metrics;
+         gint ascent, descent;
+         PangoRectangle ink_rect, logical_rect;
+         const gchar *p;
+         const gchar *text;
+         gint placeholder_len;
+ 
+         /* Get font metrics and prepare fancy shape size */
+         metrics = pango_context_get_metrics (pango_layout_get_context (layout),
+                                              pango_layout_get_font_description (layout),
+                                              NULL);
+         ascent = pango_font_metrics_get_ascent (metrics);
+         descent = pango_font_metrics_get_descent (metrics);
+         pango_font_metrics_unref (metrics);
+ 
+         logical_rect.x = 0;
+         logical_rect.y = - ascent;
+         logical_rect.width = ascent + descent;
+         logical_rect.height = ascent + descent;
+ 
+         ink_rect = logical_rect;
+ 
+         attrs = pango_attr_list_new ();
+         text = pango_layout_get_text (layout);
+         placeholder_len = strlen (data->placeholder_str);
+         for (p = text; (p = strstr (p, data->placeholder_str)); p += placeholder_len) {
+                 PangoAttribute *attr;
+ 
+                 attr = pango_attr_shape_new_with_data (&ink_rect,
+                                                        &logical_rect,
+                                                        GUINT_TO_POINTER (g_utf8_get_char (p)),
+                                                        NULL, NULL);
+ 
+                 attr->start_index = p - text;
+                 attr->end_index = attr->start_index + placeholder_len;
+ 
+                 pango_attr_list_insert (attrs, attr);
+         }
+ 
+         return attrs;
+ }
+ 
+ static gboolean
+ query_unlock_tooltip (GtkWidget  *widget,
+                       gint        x,
+                       gint        y,
+                       gboolean    keyboard_tooltip,
+                       GtkTooltip *tooltip,
+                       gpointer    user_data)
+ {
+         GtkWidget *label;
+         PangoLayout *layout;
+         PangoAttrList *attrs;
+         IconShapeData *data;
+ 
+         data = g_object_get_data (G_OBJECT (widget), "icon-shape-data");
+         label = g_object_get_data (G_OBJECT (widget), "tooltip-label");
+         if (label == NULL) {
+                 label = gtk_label_new (data->text);
+                 g_object_ref_sink (label);
+                 g_object_set_data_full (G_OBJECT (widget),
+                                         "tooltip-label", label, g_object_unref);
+         }
+ 
+         layout = gtk_label_get_layout (GTK_LABEL (label));
+         pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
+                                                 icon_shape_renderer,
+                                                 data, NULL);
+ 
+         attrs = create_shape_attr_list_for_layout (layout, data);
+         gtk_label_set_attributes (GTK_LABEL (label), attrs);
+         pango_attr_list_unref (attrs);
+ 
+         gtk_tooltip_set_custom (tooltip, label);
+ 
+         return TRUE;
+ }
+ 
+ void
+ setup_tooltip_with_embedded_icon (GtkWidget   *widget,
+                                   const gchar *text,
+                                   const gchar *placeholder,
+                                   const gchar *stock_id)
+ {
 -        GtkWidget *label;
+         IconShapeData *data;
+ 
+         data = g_object_get_data (G_OBJECT (widget), "icon-shape-data");
+         if (data) {
+                 gtk_widget_set_has_tooltip (widget, FALSE);
+                 g_signal_handler_disconnect (widget, data->query_id);
+                 g_object_set_data (G_OBJECT (widget), "icon-shape-data", NULL);
+                 g_object_set_data (G_OBJECT (widget), "tooltip-label", NULL);
+         }
+ 
+         if (!placeholder) {
+                 gtk_widget_set_tooltip_text (widget, text);
+                 return;
+         }
+ 
+         data = icon_shape_data_new (text, placeholder, stock_id);
+         g_object_set_data_full (G_OBJECT (widget),
+                                 "icon-shape-data",
+                                 data,
+                                 icon_shape_data_free);
+ 
+         gtk_widget_set_has_tooltip (widget, TRUE);
+         data->query_id = g_signal_connect (widget, "query-tooltip",
+                                            G_CALLBACK (query_unlock_tooltip), NULL);
+ 
+ }
+ 
+ gboolean
+ show_tooltip_now (GtkWidget *widget,
+                   GdkEvent  *event)
+ {
+         GtkSettings *settings;
+         gint timeout;
+ 
+         settings = gtk_widget_get_settings (widget);
+ 
+         g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
+         g_object_set (settings, "gtk-tooltip-timeout", 1, NULL);
+         gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (widget));
+         g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL);
+ 
+         return FALSE;
+ }
 -
diff --cc src/um-utils.h
index 8fc9a80,5d49bf6..dec37d3
--- a/src/um-utils.h
+++ b/src/um-utils.h
@@@ -22,8 -22,20 +22,17 @@@
  #ifndef __UM_UTILS_H__
  #define __UM_UTILS_H__
  
+ #include <gtk/gtk.h>
+ 
  G_BEGIN_DECLS
  
 -gchar *um_compute_short_name (const gchar *name);
 -
+ void     setup_tooltip_with_embedded_icon (GtkWidget   *widget,
+                                            const gchar *text,
+                                            const gchar *placeholder,
+                                            const gchar *stock_id);
+ gboolean show_tooltip_now                 (GtkWidget   *widget,
+                                            GdkEvent    *event);
+ 
 -
  G_END_DECLS
  
  #endif



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