diff options
author | Matthias Clasen <mclasen@redhat.com> | 2011-01-05 16:30:57 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2011-01-05 16:33:15 -0500 |
commit | 7799fbf239b8953f3e41b78073584f1dcf2fb27b (patch) | |
tree | 1c0ade1dc5df637422fb24441c41a0f47cb0a4f8 | |
parent | 9a80100e9ab2430ecc4375ba6bd2f66784ce34a9 (diff) | |
download | gtk+-7799fbf239b8953f3e41b78073584f1dcf2fb27b.tar.gz |
Add GtkNumerableIcon
This is a subclass of GEmblemedIcon that can show a number or
short string as an emblem, overlayed on top of another emblem.
Written by Cosimo Cecchi
https://bugzilla.gnome.org/show_bug.cgi?id=637169
-rw-r--r-- | docs/reference/gtk/Makefile.am | 4 | ||||
-rw-r--r-- | docs/reference/gtk/gtk-docs.sgml | 1 | ||||
-rw-r--r-- | docs/reference/gtk/gtk3-sections.txt | 28 | ||||
-rw-r--r-- | docs/reference/gtk/gtk3.types | 1 | ||||
-rw-r--r-- | docs/reference/gtk/images/numerableicon.png | bin | 0 -> 2645 bytes | |||
-rw-r--r-- | docs/reference/gtk/images/numerableicon2.png | bin | 0 -> 2329 bytes | |||
-rw-r--r-- | gtk/Makefile.am | 3 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtk.symbols | 13 | ||||
-rw-r--r-- | gtk/gtkicontheme.c | 4 | ||||
-rw-r--r-- | gtk/gtknumerableicon.c | 1048 | ||||
-rw-r--r-- | gtk/gtknumerableicon.h | 89 | ||||
-rw-r--r-- | gtk/gtknumerableiconprivate.h | 32 | ||||
-rw-r--r-- | tests/Makefile.am | 7 | ||||
-rw-r--r-- | tests/testnumerableicon.c | 198 |
15 files changed, 1428 insertions, 1 deletions
diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am index 959e0b0a5e..82355f53b3 100644 --- a/docs/reference/gtk/Makefile.am +++ b/docs/reference/gtk/Makefile.am @@ -351,7 +351,9 @@ HTML_IMAGES = \ $(srcdir)/images/sliders.png \ $(srcdir)/images/focus.png \ $(srcdir)/images/handles.png \ - $(srcdir)/images/extensions.png + $(srcdir)/images/extensions.png \ + $(srcdir)/images/numerableicon.png \ + $(srcdir)/images/numerableicon2.png # Extra options to supply to gtkdoc-fixref FIXXREF_OPTIONS=--extra-dir=../gdk/html \ diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index ca98b8f6fa..a3344bb664 100644 --- a/docs/reference/gtk/gtk-docs.sgml +++ b/docs/reference/gtk/gtk-docs.sgml @@ -61,6 +61,7 @@ <xi:include href="xml/gtkgradient.xml" /> <xi:include href="xml/gtkicontheme.xml" /> <xi:include href="xml/gtkiconfactory.xml" /> + <xi:include href="xml/gtknumerableicon.xml" /> <xi:include href="xml/gtkrc.xml" /> <xi:include href="xml/gtkstyle.xml" /> </part> diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index d7b6838a13..0b8559f643 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -2270,6 +2270,34 @@ GtkNotebookPrivate </SECTION> <SECTION> +<FILE>gtknumerableicon</FILE> +<TITLE>GtkNumerableIcon</TITLE> +GtkNumerableIcon +gtk_numerable_icon_new +gtk_numerable_icon_new_with_style_context +gtk_numerable_icon_get_background_gicon +gtk_numerable_icon_set_background_gicon +gtk_numerable_icon_get_background_icon_name +gtk_numerable_icon_set_background_icon_name +gtk_numerable_icon_get_count +gtk_numerable_icon_set_count +gtk_numerable_icon_get_label +gtk_numerable_icon_set_label +gtk_numerable_icon_get_style_context +gtk_numerable_icon_set_style_context +<SUBSECTION Standard> +GTK_NUMERABLE_ICON +GTK_IS_NUMERABLE_ICON +GTK_TYPE_NUMERABLE_ICON +GTK_NUMERABLE_ICON_CLASS +GTK_IS_NUMERABLE_ICON_CLASS +GTK_NUMERABLE_ICON_GET_CLASS + +<SUBSECTION Private> +gtk_numerable_icon_get_type +</SECTION> + +<SECTION> <FILE>gtkoffscreenwindow</FILE> <TITLE>GtkOffscreenWindow</TITLE> GtkOffscreenWindow diff --git a/docs/reference/gtk/gtk3.types b/docs/reference/gtk/gtk3.types index fe0ff45f6b..47295b1679 100644 --- a/docs/reference/gtk/gtk3.types +++ b/docs/reference/gtk/gtk3.types @@ -101,6 +101,7 @@ gtk_message_dialog_get_type gtk_misc_get_type gtk_mount_operation_get_type gtk_notebook_get_type +gtk_numerable_icon_get_type gtk_offscreen_window_get_type gtk_orientable_get_type gtk_page_setup_get_type diff --git a/docs/reference/gtk/images/numerableicon.png b/docs/reference/gtk/images/numerableicon.png Binary files differnew file mode 100644 index 0000000000..fc94b61423 --- /dev/null +++ b/docs/reference/gtk/images/numerableicon.png diff --git a/docs/reference/gtk/images/numerableicon2.png b/docs/reference/gtk/images/numerableicon2.png Binary files differnew file mode 100644 index 0000000000..70ab765781 --- /dev/null +++ b/docs/reference/gtk/images/numerableicon2.png diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 6c541509df..e8c90e6716 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -252,6 +252,7 @@ gtk_public_h_sources = \ gtkmodules.h \ gtkmountoperation.h \ gtknotebook.h \ + gtknumerableicon.h \ gtkoffscreenwindow.h \ gtkorientable.h \ gtkpagesetup.h \ @@ -401,6 +402,7 @@ gtk_private_h_sources = \ gtkmnemonichash.h \ gtkmodifierstyle.h \ gtkmountoperationprivate.h \ + gtknumerableiconprivate.h \ gtkpango.h \ gtkpathbar.h \ gtkplugprivate.h \ @@ -565,6 +567,7 @@ gtk_base_c_sources = \ gtkmodules.c \ gtkmountoperation.c \ gtknotebook.c \ + gtknumerableicon.c \ gtkoffscreenwindow.c \ gtkorientable.c \ gtkpagesetup.c \ @@ -137,6 +137,7 @@ #include <gtk/gtkmodules.h> #include <gtk/gtkmountoperation.h> #include <gtk/gtknotebook.h> +#include <gtk/gtknumerableicon.h> #include <gtk/gtkoffscreenwindow.h> #include <gtk/gtkorientable.h> #include <gtk/gtkpagesetup.h> diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 2014f64e37..001c345ddb 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -1606,6 +1606,19 @@ gtk_notebook_set_tab_pos gtk_notebook_set_tab_reorderable gtk_notebook_tab_get_type G_GNUC_CONST gtk_number_up_layout_get_type G_GNUC_CONST +gtk_numerable_icon_get_background_gicon +gtk_numerable_icon_get_background_icon_name +gtk_numerable_icon_get_count +gtk_numerable_icon_get_label +gtk_numerable_icon_get_style_context +gtk_numerable_icon_get_type G_GNUC_CONST +gtk_numerable_icon_new +gtk_numerable_icon_new_with_style_context +gtk_numerable_icon_set_background_gicon +gtk_numerable_icon_set_background_icon_name +gtk_numerable_icon_set_count +gtk_numerable_icon_set_label +gtk_numerable_icon_set_style_context gtk_offscreen_window_get_pixbuf gtk_offscreen_window_get_surface gtk_offscreen_window_get_type G_GNUC_CONST diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 7099165267..a163c9cae8 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -45,6 +45,7 @@ #include "gtkbuiltincache.h" #include "gtkintl.h" #include "gtkmain.h" +#include "gtknumerableiconprivate.h" #include "gtksettings.h" #include "gtkprivate.h" @@ -3799,6 +3800,9 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme, GList *list, *l; GtkIconInfo *emblem_info; + if (GTK_IS_NUMERABLE_ICON (icon)) + _gtk_numerable_icon_set_background_icon_size (GTK_NUMERABLE_ICON (icon), size / 2); + base = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon)); info = gtk_icon_theme_lookup_by_gicon (icon_theme, base, size, flags); if (info) diff --git a/gtk/gtknumerableicon.c b/gtk/gtknumerableicon.c new file mode 100644 index 0000000000..622d793a27 --- /dev/null +++ b/gtk/gtknumerableicon.c @@ -0,0 +1,1048 @@ +/* + * gtknumerableicon.c: an emblemed icon with number emblems + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Cosimo Cecchi <cosimoc@redhat.com> + */ + +/** + * SECTION:gtknumerableicon + * @Title: GtkNumerableIcon + * @Short_description: A GIcon that allows numbered emblems + * + * GtkNumerableIcon is a subclass of #GEmblemedIcon that can + * show a number or short string as an emblem. The number can + * be overlayed on top of another emblem, if desired. + * + * It supports theming by taking font and color information + * from a provided #GtkStyleContext; see + * gtk_numerable_icon_set_style_context(). + * + * <example> + * <title>Typical numerable icons</title> + * <inlinegraphic fileref="numerableicon.png" format="PNG"/> + * <inlinegraphic fileref="numerableicon2.png" format="PNG"/> + * </example> + */ +#include <config.h> + +#include "gtknumerableicon.h" + +#include "gtkicontheme.h" +#include "gtkintl.h" +#include "gtkwidget.h" +#include "gtkwindow.h" + +#include <gdk/gdk.h> +#include <pango/pango.h> +#include <math.h> + +struct _GtkNumerableIconPrivate { + gint count; + gchar *label; + + GIcon *background_icon; + gchar *background_icon_name; + gint icon_size; + + GdkRGBA *background; + GdkRGBA *foreground; + + PangoFontDescription *font; + cairo_pattern_t *background_image; + gint border_size; + + GtkStyleContext *style; + gulong style_changed_id; + + gchar *rendered_string; +}; + +enum { + PROP_COUNT = 1, + PROP_LABEL, + PROP_STYLE, + PROP_BACKGROUND_ICON, + PROP_BACKGROUND_ICON_NAME, + NUM_PROPERTIES +}; + +#define DEFAULT_SURFACE_SIZE 256 +#define DEFAULT_BORDER_SIZE DEFAULT_SURFACE_SIZE * 0.06 +#define DEFAULT_RADIUS DEFAULT_SURFACE_SIZE / 2 + +#define DEFAULT_BACKGROUND "#000000" +#define DEFAULT_FOREGROUND "#ffffff" + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +G_DEFINE_TYPE (GtkNumerableIcon, gtk_numerable_icon, G_TYPE_EMBLEMED_ICON); + +static gint +get_surface_size (cairo_surface_t *surface) +{ + return MAX (cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface)); +} + +static gdouble +get_border_size (GtkNumerableIcon *self) +{ + return self->priv->border_size; +} + +static cairo_surface_t * +draw_default_surface (GtkNumerableIcon *self) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + DEFAULT_SURFACE_SIZE, DEFAULT_SURFACE_SIZE); + + cr = cairo_create (surface); + + cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2., + DEFAULT_RADIUS, 0., 2 * M_PI); + + gdk_cairo_set_source_rgba (cr, self->priv->background); + cairo_fill (cr); + + cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2., + DEFAULT_RADIUS - DEFAULT_BORDER_SIZE, 0., 2 * M_PI); + gdk_cairo_set_source_rgba (cr, self->priv->foreground); + cairo_fill (cr); + + cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2., + DEFAULT_RADIUS - 2 * DEFAULT_BORDER_SIZE, 0., 2 * M_PI); + gdk_cairo_set_source_rgba (cr, self->priv->background); + cairo_fill (cr); + + cairo_destroy (cr); + + return surface; +} + +static cairo_surface_t * +draw_from_gradient (cairo_pattern_t *pattern) +{ + cairo_surface_t *surface; + cairo_matrix_t matrix; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + DEFAULT_SURFACE_SIZE, DEFAULT_SURFACE_SIZE); + + cr = cairo_create (surface); + + /* scale the gradient points to the user space coordinates */ + cairo_matrix_init_scale (&matrix, + 1. / (double) DEFAULT_SURFACE_SIZE, + 1. / (double) DEFAULT_SURFACE_SIZE); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_arc (cr, DEFAULT_SURFACE_SIZE / 2., DEFAULT_SURFACE_SIZE / 2., + DEFAULT_RADIUS, 0., 2 * M_PI); + + cairo_set_source (cr, pattern); + cairo_fill (cr); + + cairo_destroy (cr); + + return surface; +} + +/* copy the surface */ +static cairo_surface_t * +draw_from_image (cairo_surface_t *image) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (image, CAIRO_CONTENT_COLOR_ALPHA, + cairo_image_surface_get_width (image), + cairo_image_surface_get_height (image)); + cr = cairo_create (surface); + + cairo_set_source_surface (cr, image, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + + return surface; +} + +static cairo_surface_t * +draw_from_gicon (GtkNumerableIcon *self) +{ + GtkIconTheme *theme; + GdkScreen *screen; + GtkIconInfo *info; + GdkPixbuf *pixbuf; + cairo_surface_t *surface; + cairo_t *cr; + + if (self->priv->style != NULL) + { + screen = gtk_style_context_get_screen (self->priv->style); + theme = gtk_icon_theme_get_for_screen (screen); + } + else + { + theme = gtk_icon_theme_get_default (); + } + + info = gtk_icon_theme_lookup_by_gicon (theme, self->priv->background_icon, + self->priv->icon_size, + GTK_ICON_LOOKUP_GENERIC_FALLBACK); + if (info == NULL) + return NULL; + + pixbuf = gtk_icon_info_load_icon (info, NULL); + gtk_icon_info_free (info); + + if (pixbuf == NULL) + return NULL; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + + cr = cairo_create (surface); + + gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + g_object_unref (pixbuf); + + return surface; +} + +static cairo_surface_t * +get_image_surface (GtkNumerableIcon *self) +{ + cairo_surface_t *retval = NULL, *image; + + if (self->priv->background_icon != NULL) + { + retval = draw_from_gicon (self); + self->priv->border_size = 0; + } + else if (self->priv->background_image != NULL) + { + if (cairo_pattern_get_surface (self->priv->background_image, &image) == CAIRO_STATUS_SUCCESS) + retval = draw_from_image (image); + else + retval = draw_from_gradient (self->priv->background_image); + + self->priv->border_size = 0; + } + + if (retval == NULL) + { + retval = draw_default_surface (self); + self->priv->border_size = DEFAULT_BORDER_SIZE; + } + + return retval; +} + +static PangoLayout * +get_pango_layout (GtkNumerableIcon *self) +{ + PangoContext *context; + GdkScreen *screen; + PangoLayout *layout; + + if (self->priv->style != NULL) + { + screen = gtk_style_context_get_screen (self->priv->style); + context = gdk_pango_context_get_for_screen (screen); + layout = pango_layout_new (context); + + if (self->priv->font != NULL) + pango_layout_set_font_description (layout, self->priv->font); + + pango_layout_set_text (layout, self->priv->rendered_string, -1); + + g_object_unref (context); + } + else + { + GtkWidget *fake; + + /* steal gtk text settings from the window */ + fake = gtk_window_new (GTK_WINDOW_TOPLEVEL); + layout = gtk_widget_create_pango_layout (fake, self->priv->rendered_string); + gtk_widget_destroy (fake); + } + + return layout; +} + +static void +gtk_numerable_icon_ensure_emblem (GtkNumerableIcon *self) +{ + cairo_t *cr; + cairo_surface_t *surface; + PangoLayout *layout; + GEmblem *emblem; + gint width, height; + gdouble scale; + PangoAttrList *attr_list; + PangoAttribute *attr; + GdkPixbuf *pixbuf; + + /* don't draw anything if the count is zero */ + if (self->priv->rendered_string == NULL) + { + g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (self)); + return; + } + + surface = get_image_surface (self); + cr = cairo_create (surface); + + layout = get_pango_layout (self); + pango_layout_get_pixel_size (layout, &width, &height); + + /* scale the layout to be 0.75 of the size still available for drawing */ + scale = ((get_surface_size (surface) - 2 * get_border_size (self)) * 0.75) / (MAX (height, width)); + attr_list = pango_attr_list_new (); + + attr = pango_attr_scale_new (scale); + pango_attr_list_insert (attr_list, attr); + + attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + pango_attr_list_insert (attr_list, attr); + + pango_layout_set_attributes (layout, attr_list); + + /* update these values */ + pango_layout_get_pixel_size (layout, &width, &height); + + /* move to the center */ + cairo_move_to (cr, + get_surface_size (surface) / 2. - (gdouble) width / 2., + get_surface_size (surface) / 2. - (gdouble) height / 2.); + + gdk_cairo_set_source_rgba (cr, self->priv->foreground); + pango_cairo_show_layout (cr, layout); + + cairo_destroy (cr); + + pixbuf = + gdk_pixbuf_get_from_surface (surface, 0, 0, + get_surface_size (surface), get_surface_size (surface)); + + emblem = g_emblem_new (G_ICON (pixbuf)); + g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (self)); + g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (self), emblem); + + g_object_unref (layout); + g_object_unref (emblem); + g_object_unref (pixbuf); + + cairo_surface_destroy (surface); + pango_attr_list_unref (attr_list); +} + +static void +gtk_numerable_icon_update_properties_from_style (GtkNumerableIcon *self) +{ + GtkStyleContext *style = self->priv->style; + GtkWidgetPath *path, *saved; + cairo_pattern_t *pattern = NULL; + GdkRGBA background, foreground; + PangoFontDescription *font = NULL; + + /* save an unmodified copy of the original widget path, in order + * to restore it later */ + path = gtk_widget_path_copy (gtk_style_context_get_path (style)); + saved = gtk_widget_path_copy (path); + + if (!gtk_widget_path_is_type (path, GTK_TYPE_NUMERABLE_ICON)) + { + /* append our GType to the style context to fetch appropriate colors */ + gtk_widget_path_append_type (path, GTK_TYPE_NUMERABLE_ICON); + gtk_style_context_set_path (style, path); + } + + gtk_style_context_get_background_color (style, gtk_style_context_get_state (style), + &background); + gtk_style_context_get_color (style, gtk_style_context_get_state (style), + &foreground); + + if (self->priv->background != NULL) + gdk_rgba_free (self->priv->background); + + self->priv->background = gdk_rgba_copy (&background); + + if (self->priv->foreground != NULL) + gdk_rgba_free (self->priv->foreground); + + self->priv->foreground = gdk_rgba_copy (&foreground); + + gtk_style_context_get (style, gtk_style_context_get_state (style), + GTK_STYLE_PROPERTY_BACKGROUND_IMAGE, &pattern, + NULL); + + if (pattern != NULL) + { + if (self->priv->background_image != NULL) + cairo_pattern_destroy (self->priv->background_image); + + self->priv->background_image = pattern; + } + + gtk_style_context_get (style, gtk_style_context_get_state (style), + GTK_STYLE_PROPERTY_FONT, &font, + NULL); + + if (font != NULL) + { + if (self->priv->font != NULL) + pango_font_description_free (self->priv->font); + + self->priv->font = font; + } + + gtk_numerable_icon_ensure_emblem (self); + + /* restore original widget path */ + gtk_style_context_set_path (style, saved); + + gtk_widget_path_free (path); + gtk_widget_path_free (saved); +} + +static void +gtk_numerable_icon_init_style (GtkNumerableIcon *self) +{ + GtkStyleContext *style = self->priv->style; + + if (style == NULL) + return; + + gtk_numerable_icon_update_properties_from_style (self); + + self->priv->style_changed_id = + g_signal_connect_swapped (style, "changed", + G_CALLBACK (gtk_numerable_icon_update_properties_from_style), self); +} + +static void +gtk_numerable_icon_ensure_and_replace_label (GtkNumerableIcon *self, + gint count, + const gchar *label) +{ + g_assert (!(label != NULL && count != 0)); + + g_free (self->priv->rendered_string); + self->priv->rendered_string = NULL; + + if (count != 0) + { + if (self->priv->label != NULL) + { + g_free (self->priv->label); + self->priv->label = NULL; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]); + } + + if (count > 99) + count = 99; + + if (count < -99) + count = -99; + + self->priv->count = count; + + /* Translators: the format here is used to build the string that will be rendered + * in the number emblem. + */ + self->priv->rendered_string = g_strdup_printf (C_("Number format", "%d"), count); + + return; + } + + if (label != NULL) + { + if (self->priv->count != 0) + { + self->priv->count = 0; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COUNT]); + } + + g_free (self->priv->label); + + if (g_strcmp0 (label, "") == 0) + { + self->priv->label = NULL; + return; + } + + self->priv->label = g_strdup (label); + self->priv->rendered_string = g_strdup (label); + } +} + +static gboolean +real_set_background_icon (GtkNumerableIcon *self, + GIcon *icon) +{ + if (!g_icon_equal (self->priv->background_icon, icon)) + { + g_clear_object (&self->priv->background_icon); + + if (icon != NULL) + self->priv->background_icon = g_object_ref (icon); + + gtk_numerable_icon_ensure_emblem (self); + + return TRUE; + } + + return FALSE; +} + +static void +gtk_numerable_icon_constructed (GObject *object) +{ + GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object); + + if (G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->constructed != NULL) + G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->constructed (object); + + gtk_numerable_icon_ensure_emblem (self); +} + +static void +gtk_numerable_icon_finalize (GObject *object) +{ + GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object); + + g_free (self->priv->label); + g_free (self->priv->rendered_string); + + gdk_rgba_free (self->priv->background); + gdk_rgba_free (self->priv->foreground); + + pango_font_description_free (self->priv->font); + + cairo_pattern_destroy (self->priv->background_image); + + G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->finalize (object); +} + +static void +gtk_numerable_icon_dispose (GObject *object) +{ + GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object); + + if (self->priv->style_changed_id != 0) + { + g_signal_handler_disconnect (self->priv->style, + self->priv->style_changed_id); + self->priv->style_changed_id = 0; + } + + g_clear_object (&self->priv->style); + g_clear_object (&self->priv->background_icon); + + G_OBJECT_CLASS (gtk_numerable_icon_parent_class)->dispose (object); +} + +static void +gtk_numerable_icon_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object); + + switch (property_id) + { + case PROP_COUNT: + gtk_numerable_icon_set_count (self, g_value_get_int (value)); + break; + case PROP_LABEL: + gtk_numerable_icon_set_label (self, g_value_get_string (value)); + break; + case PROP_STYLE: + gtk_numerable_icon_set_style_context (self, g_value_get_object (value)); + break; + case PROP_BACKGROUND_ICON: + gtk_numerable_icon_set_background_gicon (self, g_value_get_object (value)); + break; + case PROP_BACKGROUND_ICON_NAME: + gtk_numerable_icon_set_background_icon_name (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_numerable_icon_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkNumerableIcon *self = GTK_NUMERABLE_ICON (object); + + switch (property_id) + { + case PROP_COUNT: + g_value_set_int (value, self->priv->count); + break; + case PROP_LABEL: + g_value_set_string (value, self->priv->label); + break; + case PROP_STYLE: + g_value_set_object (value, self->priv->style); + break; + case PROP_BACKGROUND_ICON: + if (self->priv->background_icon != NULL) + g_value_set_object (value, self->priv->background_icon); + break; + case PROP_BACKGROUND_ICON_NAME: + g_value_set_string (value, self->priv->background_icon_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_numerable_icon_class_init (GtkNumerableIconClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->get_property = gtk_numerable_icon_get_property; + oclass->set_property = gtk_numerable_icon_set_property; + oclass->constructed = gtk_numerable_icon_constructed; + oclass->dispose = gtk_numerable_icon_dispose; + oclass->finalize = gtk_numerable_icon_finalize; + + g_type_class_add_private (klass, sizeof (GtkNumerableIconPrivate)); + + properties[PROP_COUNT] = + g_param_spec_int ("count", + P_("Icon's count"), + P_("The count of the emblem currently displayed"), + -99, 99, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_LABEL] = + g_param_spec_string ("label", + P_("Icon's label"), + P_("The label to be displayed over the icon"), + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_STYLE] = + g_param_spec_object ("style-context", + P_("Icon's style context"), + P_("The style context to theme the icon appearance"), + GTK_TYPE_STYLE_CONTEXT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_BACKGROUND_ICON] = + g_param_spec_object ("background-icon", + P_("Background icon"), + P_("The icon for the number emblem background"), + G_TYPE_ICON, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_BACKGROUND_ICON_NAME] = + g_param_spec_string ("background-icon-name", + P_("Background icon name"), + P_("The icon name for the number emblem background"), + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +static void +gtk_numerable_icon_init (GtkNumerableIcon *self) +{ + GdkRGBA bg; + GdkRGBA fg; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GTK_TYPE_NUMERABLE_ICON, + GtkNumerableIconPrivate); + + gdk_rgba_parse (&bg, DEFAULT_BACKGROUND); + gdk_rgba_parse (&fg, DEFAULT_FOREGROUND); + + self->priv->background = gdk_rgba_copy (&bg); + self->priv->foreground = gdk_rgba_copy (&fg); + + self->priv->icon_size = 48; +} + +/* private */ +void +_gtk_numerable_icon_set_background_icon_size (GtkNumerableIcon *self, + gint icon_size) +{ + if (self->priv->background_icon == NULL) + return; + + if (self->priv->icon_size != icon_size) + { + self->priv->icon_size = icon_size; + gtk_numerable_icon_ensure_emblem (self); + } +} + +/** + * gtk_numerable_icon_get_label: + * @self: a #GtkNumerableIcon + * + * Returns the currently displayed label of the icon, or %NULL. + * + * Returns: the currently displayed label + * + * Since: 3.0 + */ +const gchar * +gtk_numerable_icon_get_label (GtkNumerableIcon *self) +{ + g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL); + + return self->priv->label; +} + +/** + * gtk_numerable_icon_set_label: + * @self: a #GtkNumerableIcon + * @label: (allow-none): a short label, or %NULL + * + * Sets the currently displayed value of @self to the string + * in @label. Setting an empty label removes the emblem. + * + * Note that this is meant for displaying short labels, such as + * roman numbers, or single letters. For roman numbers, consider + * using the Unicode characters U+2160 - U+217F. Strings longer + * than two characters will likely not be rendered very well. + * + * If this method is called, and a number was already set on the + * icon, it will automatically be reset to zero before rendering + * the label, i.e. the last method called between + * gtk_numerable_icon_set_label() and gtk_numerable_icon_set_count() + * has always priority. + * + * Since: 3.0 + */ +void +gtk_numerable_icon_set_label (GtkNumerableIcon *self, + const gchar *label) +{ + g_return_if_fail (GTK_IS_NUMERABLE_ICON (self)); + + if (g_strcmp0 (label, self->priv->label) != 0) + { + gtk_numerable_icon_ensure_and_replace_label (self, 0, label); + gtk_numerable_icon_ensure_emblem (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]); + } +} + +/** + * gtk_numerable_icon_get_count: + * @self: a #GtkNumerableIcon + * + * Returns the value currently displayed by @self. + * + * Returns: the currently displayed value + * + * Since: 3.0 + */ +gint +gtk_numerable_icon_get_count (GtkNumerableIcon *self) +{ + g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), 0); + + return self->priv->count; +} + +/** + * gtk_numerable_icon_set_count: + * @self: a #GtkNumerableIcon + * @count: a number between -99 and 99 + * + * Sets the currently displayed value of @self to @count. + * + * The numeric value is always clamped to make it two digits, i.e. + * between -99 and 99. Setting a count of zero removes the emblem. + * If this method is called, and a label was already set on the icon, + * it will automatically be reset to %NULL before rendering the number, + * i.e. the last method called between gtk_numerable_icon_set_count() + * and gtk_numerable_icon_set_label() has always priority. + * + * Since: 3.0 + */ +void +gtk_numerable_icon_set_count (GtkNumerableIcon *self, + gint count) +{ + g_return_if_fail (GTK_IS_NUMERABLE_ICON (self)); + + if (count != self->priv->count) + { + gtk_numerable_icon_ensure_and_replace_label (self, count, NULL); + gtk_numerable_icon_ensure_emblem (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COUNT]); + } +} + +/** + * gtk_numerable_icon_get_style_context: + * @self: a #GtkNumerableIcon + * + * Returns the #GtkStyleContext used by the icon for theming, + * or %NULL if there's none. + * + * Returns: (transfer none): a #GtkStyleContext, or %NULL. + * This object is internal to GTK+ and should not be unreffed. + * Use g_object_ref() if you want to keep it around + * + * Since: 3.0 + */ +GtkStyleContext * +gtk_numerable_icon_get_style_context (GtkNumerableIcon *self) +{ + g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL); + + return self->priv->style; +} + +/** + * gtk_numerable_icon_set_style_context: + * @self: a #GtkNumerableIcon + * @style: a #GtkStyleContext + * + * Updates the icon to fetch theme information from the + * given #GtkStyleContext. + * + * Since: 3.0 + */ +void +gtk_numerable_icon_set_style_context (GtkNumerableIcon *self, + GtkStyleContext *style) +{ + g_return_if_fail (GTK_IS_NUMERABLE_ICON (self)); + g_return_if_fail (GTK_IS_STYLE_CONTEXT (style)); + + if (style != self->priv->style) + { + if (self->priv->style_changed_id != 0) + g_signal_handler_disconnect (self->priv->style, + self->priv->style_changed_id); + + if (self->priv->style != NULL) + g_object_unref (self->priv->style); + + self->priv->style = g_object_ref (style); + + gtk_numerable_icon_init_style (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STYLE]); + } +} + +/** + * gtk_numerable_icon_set_background_gicon: + * @self: a #GtkNumerableIcon + * @icon: (allow-none): a #GIcon, or %NULL + * + * Updates the icon to use @icon as the base background image. + * If @icon is %NULL, @self will go back using style information + * or default theming for its background image. + * + * If this method is called and an icon name was already set as + * background for the icon, @icon will be used, i.e. the last method + * called between gtk_numerable_icon_set_background_gicon() and + * #gtk_numerable_icon_set_background_icon_name() has always priority. + * + * Since: 3.0 + */ +void +gtk_numerable_icon_set_background_gicon (GtkNumerableIcon *self, + GIcon *icon) +{ + gboolean res; + + g_return_if_fail (GTK_IS_NUMERABLE_ICON (self)); + + if (self->priv->background_icon_name != NULL) + { + g_free (self->priv->background_icon_name); + self->priv->background_icon_name = NULL; + } + + res = real_set_background_icon (self, icon); + + if (res) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND_ICON]); +} + +/** + * gtk_numerable_icon_get_background_gicon: + * @self: a #GtkNumerableIcon + * + * Returns the #GIcon that was set as the base background image, or + * %NULL if there's none. The caller of this function does not own + * a reference to the returned #GIcon. + * + * Returns: (transfer none): a #GIcon, or %NULL + * + * Since: 3.0 + */ +GIcon * +gtk_numerable_icon_get_background_gicon (GtkNumerableIcon *self) +{ + GIcon *retval = NULL; + + g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL); + + /* return the GIcon only if it wasn't created from an icon name */ + if (self->priv->background_icon_name == NULL) + retval = self->priv->background_icon; + + return retval; +} + +/** + * gtk_numerable_icon_set_background_icon_name: + * @self: a #GtkNumerableIcon + * @icon_name: (allow-none): an icon name, or %NULL + * + * Updates the icon to use the icon named @icon_name from the + * current icon theme as the base background image. If @icon_name + * is %NULL, @self will go back using style information or default + * theming for its background image. + * + * If this method is called and a #GIcon was already set as + * background for the icon, @icon_name will be used, i.e. the + * last method called between gtk_numerable_icon_set_background_icon_name() + * and gtk_numerable_icon_set_background_gicon() has always priority. + * + * Since: 3.0 + */ +void +gtk_numerable_icon_set_background_icon_name (GtkNumerableIcon *self, + const gchar *icon_name) +{ + GIcon *icon = NULL; + gboolean res; + + g_return_if_fail (GTK_IS_NUMERABLE_ICON (self)); + + if (g_strcmp0 (icon_name, self->priv->background_icon_name) != 0) + { + g_free (self->priv->background_icon_name); + self->priv->background_icon_name = g_strdup (icon_name); + } + + if (icon_name != NULL) + icon = g_themed_icon_new_with_default_fallbacks (icon_name); + + res = real_set_background_icon (self, icon); + + if (res) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND_ICON_NAME]); + + if (icon != NULL) + g_object_unref (icon); +} + +/** + * gtk_numerable_icon_get_background_icon_name: + * @self: a #GtkNumerableIcon + * + * Returns the icon name used as the base background image, + * or %NULL if there's none. + * + * Returns: an icon name, or %NULL + * + * Since: 3.0 + */ +const gchar * +gtk_numerable_icon_get_background_icon_name (GtkNumerableIcon *self) +{ + g_return_val_if_fail (GTK_IS_NUMERABLE_ICON (self), NULL); + + return self->priv->background_icon_name; +} + +/** + * gtk_numerable_icon_new: + * @base_icon: a #GIcon to overlay on + * + * Creates a new unthemed #GtkNumerableIcon. + * + * Returns: a new #GIcon + * + * Since: 3.0 + */ +GIcon * +gtk_numerable_icon_new (GIcon *base_icon) +{ + g_return_val_if_fail (G_IS_ICON (base_icon), NULL); + + return g_object_new (GTK_TYPE_NUMERABLE_ICON, + "gicon", base_icon, + NULL); +} + +/** + * gtk_numerable_icon_new_with_style_context: + * @base_icon: a #GIcon to overlay on + * @context: a #GtkStyleContext + * + * Creates a new #GtkNumerableIcon which will themed according + * to the passed #GtkStyleContext. This is a convenience constructor + * that calls gtk_numerable_icon_set_style_context() internally. + * + * Returns: a new #GIcon + * + * Since: 3.0 + */ +GIcon * +gtk_numerable_icon_new_with_style_context (GIcon *base_icon, + GtkStyleContext *context) +{ + g_return_val_if_fail (G_IS_ICON (base_icon), NULL); + + return g_object_new (GTK_TYPE_NUMERABLE_ICON, + "gicon", base_icon, + "style-context", context, + NULL); +} diff --git a/gtk/gtknumerableicon.h b/gtk/gtknumerableicon.h new file mode 100644 index 0000000000..277d2dd465 --- /dev/null +++ b/gtk/gtknumerableicon.h @@ -0,0 +1,89 @@ +/* + * gtknumerableicon.h: an emblemed icon with number emblems + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Cosimo Cecchi <cosimoc@redhat.com> + */ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#ifndef __GTK_NUMERABLE_ICON_H__ +#define __GTK_NUMERABLE_ICON_H__ + +#include <gio/gio.h> +#include <gtk/gtkstylecontext.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_NUMERABLE_ICON (gtk_numerable_icon_get_type ()) +#define GTK_NUMERABLE_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_NUMERABLE_ICON, GtkNumerableIcon)) +#define GTK_NUMERABLE_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_NUMERABLE_ICON, GtkNumerableIconClass)) +#define GTK_IS_NUMERABLE_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_NUMERABLE_ICON)) +#define GTK_IS_NUMERABLE_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_NUMERABLE_ICON)) +#define GTK_NUMERABLE_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_NUMERABLE_ICON, GtkNumerableIconClass)) + +typedef struct _GtkNumerableIcon GtkNumerableIcon; +typedef struct _GtkNumerableIconClass GtkNumerableIconClass; +typedef struct _GtkNumerableIconPrivate GtkNumerableIconPrivate; + +struct _GtkNumerableIcon { + GEmblemedIcon parent; + + /*< private >*/ + GtkNumerableIconPrivate *priv; +}; + +struct _GtkNumerableIconClass { + GEmblemedIconClass parent_class; + + /* padding for future class expansion */ + gpointer padding[8]; +}; + +GType gtk_numerable_icon_get_type (void) G_GNUC_CONST; + +GIcon * gtk_numerable_icon_new (GIcon *base_icon); +GIcon * gtk_numerable_icon_new_with_style_context (GIcon *base_icon, + GtkStyleContext *context); + +GtkStyleContext * gtk_numerable_icon_get_style_context (GtkNumerableIcon *self); +void gtk_numerable_icon_set_style_context (GtkNumerableIcon *self, + GtkStyleContext *style); + +gint gtk_numerable_icon_get_count (GtkNumerableIcon *self); +void gtk_numerable_icon_set_count (GtkNumerableIcon *self, + gint count); + +const gchar * gtk_numerable_icon_get_label (GtkNumerableIcon *self); +void gtk_numerable_icon_set_label (GtkNumerableIcon *self, + const gchar *label); + +void gtk_numerable_icon_set_background_gicon (GtkNumerableIcon *self, + GIcon *icon); +GIcon * gtk_numerable_icon_get_background_gicon (GtkNumerableIcon *self); + +void gtk_numerable_icon_set_background_icon_name (GtkNumerableIcon *self, + const gchar *icon_name); +const gchar * gtk_numerable_icon_get_background_icon_name (GtkNumerableIcon *self); + +G_END_DECLS + +#endif /* __GTK_NUMERABLE_ICON_H__ */ diff --git a/gtk/gtknumerableiconprivate.h b/gtk/gtknumerableiconprivate.h new file mode 100644 index 0000000000..18323fb28a --- /dev/null +++ b/gtk/gtknumerableiconprivate.h @@ -0,0 +1,32 @@ +/* + * gtknumerableiconprivate.h: private methods for GtkNumerableIcon + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Cosimo Cecchi <cosimoc@redhat.com> + */ + +#ifndef __GTK_NUMERABLE_ICON_PRIVATE_H__ +#define __GTK_NUMERABLE_ICON_PRIVATE_H__ + +#include "gtknumerableicon.h" + +void _gtk_numerable_icon_set_background_icon_size (GtkNumerableIcon *self, + gint icon_size); + +#endif /* __GTK_NUMERABLE_ICON_PRIVATE_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 0932229c8c..c57426fbe1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -63,6 +63,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \ testmultidisplay \ testmultiscreen \ testnotebookdnd \ + testnumerableicon \ testnouiprint \ testoffscreen \ testoffscreenwindow \ @@ -158,6 +159,7 @@ testmultidisplay_DEPENDENCIES = $(TEST_DEPS) testmultiscreen_DEPENDENCIES = $(TEST_DEPS) testnotebookdnd_DEPENDENCIES = $(TEST_DEPS) testnouiprint_DEPENDENCIES = $(TEST_DEPS) +testnumerableicon_DEPENDENCIES = $(TEST_DEPS) testoffscreen_DEPENDENCIES = $(TEST_DEPS) testoffscreenwindow_DEPENDENCIES = $(TEST_DEPS) testappchooser_DEPENDENCIES = $(TEST_DEPS) @@ -236,6 +238,7 @@ testmultidisplay_LDADD = $(LDADDS) testmultiscreen_LDADD = $(LDADDS) testnotebookdnd_LDADD = $(LDADDS) testnouiprint_LDADD = $(LDADDS) +testnumerableicon_LDADD = $(LDADDS) testoffscreen_LDADD = $(LDADDS) testoffscreenwindow_LDADD = $(LDADDS) testappchooser_LDADD = $(LDADDS) @@ -363,6 +366,10 @@ testiconview_SOURCES = \ testiconview_keynav_SOURCES = \ testiconview-keynav.c +testnumerableicon_SOURCES = \ + testnumerableicon.c \ + prop-editor.c + testrecentchooser_SOURCES = \ prop-editor.c \ testrecentchooser.c diff --git a/tests/testnumerableicon.c b/tests/testnumerableicon.c new file mode 100644 index 0000000000..508357bfe1 --- /dev/null +++ b/tests/testnumerableicon.c @@ -0,0 +1,198 @@ +/* testnumerableicon.c + * Copyright (C) 2010 Red Hat, Inc. + * Authors: Cosimo Cecchi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <stdlib.h> +#include <gtk/gtk.h> +#include "prop-editor.h" + + +typedef struct { + GIcon *numerable; + GtkWidget *image; + gboolean odd; + GtkIconSize size; +} PackData; + +static void +button_clicked_cb (GtkButton *b, + gpointer user_data) +{ + PackData *d = user_data; + GtkCssProvider *provider; + GtkStyleContext *style; + GError *error = NULL; + gchar *data, *bg_str, *grad1, *grad2; + const gchar data_format[] = "GtkNumerableIcon { background-color: %s; color: #000000;" + "background-image: -gtk-gradient (linear, 0 0, 1 1, from(%s), to(%s));" + "font: Monospace 12;" + /* "background-image: url('apple-red.png');" */ + "}"; + + bg_str = g_strdup_printf ("rgb(%d,%d,%d)", g_random_int_range (0, 255), g_random_int_range (0, 255), g_random_int_range (0, 255)); + grad1 = g_strdup_printf ("rgb(%d,%d,%d)", g_random_int_range (0, 255), g_random_int_range (0, 255), g_random_int_range (0, 255)); + grad2 = g_strdup_printf ("rgb(%d,%d,%d)", g_random_int_range (0, 255), g_random_int_range (0, 255), g_random_int_range (0, 255)); + + data = g_strdup_printf (data_format, bg_str, grad1, grad2); + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, data, -1, &error); + + g_assert (error == NULL); + + style = gtk_widget_get_style_context (d->image); + gtk_style_context_add_provider (style, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); + + if (d->odd) { + gtk_numerable_icon_set_background_icon_name (GTK_NUMERABLE_ICON (d->numerable), NULL); + gtk_numerable_icon_set_count (GTK_NUMERABLE_ICON (d->numerable), g_random_int_range (-99, 99)); + } else { + gtk_numerable_icon_set_background_icon_name (GTK_NUMERABLE_ICON (d->numerable), + "emblem-favorite"); + gtk_numerable_icon_set_label (GTK_NUMERABLE_ICON (d->numerable), "IVX"); + } + + gtk_image_set_from_gicon (GTK_IMAGE (d->image), d->numerable, d->size); + + d->odd = !d->odd; + + g_free (data); + g_free (bg_str); + g_free (grad1); + g_free (grad2); + + g_object_unref (provider); +} + +static gboolean +delete_event_cb (GtkWidget *editor, + gint response, + gpointer user_data) +{ + gtk_widget_hide (editor); + + return TRUE; +} + +static void +properties_cb (GtkWidget *button, + GObject *entry) +{ + GtkWidget *editor; + + editor = g_object_get_data (entry, "properties-dialog"); + + if (editor == NULL) + { + editor = create_prop_editor (G_OBJECT (entry), G_TYPE_INVALID); + gtk_container_set_border_width (GTK_CONTAINER (editor), 12); + gtk_window_set_transient_for (GTK_WINDOW (editor), + GTK_WINDOW (gtk_widget_get_toplevel (button))); + g_signal_connect (editor, "delete-event", G_CALLBACK (delete_event_cb), NULL); + g_object_set_data (entry, "properties-dialog", editor); + } + + gtk_window_present (GTK_WINDOW (editor)); +} + +static void +refresh_cb (GtkWidget *button, + gpointer user_data) +{ + PackData *d = user_data; + + gtk_image_set_from_gicon (GTK_IMAGE (d->image), d->numerable, d->size); +} + +static void +pack_numerable (GtkWidget *parent, + GtkIconSize size) +{ + PackData *d; + GtkWidget *vbox, *label, *image, *button; + gchar *str; + GIcon *icon, *numerable; + + d = g_slice_new0 (PackData); + + image = gtk_image_new (); + icon = g_themed_icon_new ("system-file-manager"); + numerable = gtk_numerable_icon_new (icon); + + d->image = image; + d->numerable = numerable; + d->odd = FALSE; + d->size = size; + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_box_pack_start (GTK_BOX (parent), vbox, FALSE, FALSE, 0); + + gtk_numerable_icon_set_count (GTK_NUMERABLE_ICON (numerable), 42); + gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0); + gtk_numerable_icon_set_style_context (GTK_NUMERABLE_ICON (numerable), + gtk_widget_get_style_context (image)); + gtk_image_set_from_gicon (GTK_IMAGE (image), numerable, size); + + label = gtk_label_new (NULL); + str = g_strdup_printf ("Numerable icon, hash %u", g_icon_hash (numerable)); + gtk_label_set_label (GTK_LABEL (label), str); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change icon number"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + g_signal_connect (button, "clicked", + G_CALLBACK (button_clicked_cb), d); + + button = gtk_button_new_with_label ("Properties"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + g_signal_connect (button, "clicked", + G_CALLBACK (properties_cb), numerable); + + button = gtk_button_new_with_label ("Refresh"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + g_signal_connect (button, "clicked", + G_CALLBACK (refresh_cb), d); +} + +int +main (int argc, + char **argv) +{ + GtkWidget *hbox, *toplevel; + + gtk_init (&argc, &argv); + + toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + gtk_container_add (GTK_CONTAINER (toplevel), hbox); + + pack_numerable (hbox, GTK_ICON_SIZE_DIALOG); + pack_numerable (hbox, GTK_ICON_SIZE_BUTTON); + + gtk_widget_show_all (toplevel); + + g_signal_connect (toplevel, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + + gtk_main (); + + return 0; +} + |