diff options
-rw-r--r-- | example/menus.c | 45 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/idousermenuitem.c | 357 | ||||
-rw-r--r-- | src/idousermenuitem.h | 66 |
4 files changed, 470 insertions, 2 deletions
diff --git a/example/menus.c b/example/menus.c index 5687b8e..1675f45 100644 --- a/example/menus.c +++ b/example/menus.c @@ -4,6 +4,7 @@ #include "idocalendarmenuitem.h" #include "idoentrymenuitem.h" #include "idoswitchmenuitem.h" +#include "idousermenuitem.h" #include "config.h" static void @@ -92,10 +93,52 @@ main (int argc, char *argv[]) image = ido_scale_menu_item_get_secondary_image (IDO_SCALE_MENU_ITEM (menuitem)); gtk_image_set_from_stock (GTK_IMAGE (image), GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - g_signal_connect (menuitem, "slider-grabbed", G_CALLBACK (slider_grabbed), NULL); g_signal_connect (menuitem, "slider-released", G_CALLBACK (slider_released), NULL); + /** + *** Users + **/ + + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, + "label", "Guest", + "icon-filename", NULL, + "is-logged-in", FALSE, + "is-current-user", FALSE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, + "label", "Bobby Fischer", + "icon-filename", "/usr/share/pixmaps/faces/chess.jpg", + "is-logged-in", FALSE, + "is-current-user", FALSE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, + "label", "Linus Torvalds", + "icon-filename", "/usr/share/pixmaps/faces/penguin.jpg", + "is-logged-in", TRUE, + "is-current-user", FALSE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = ido_user_menu_item_new (); + g_object_set (menuitem, "label", "Mark Shuttleworth", + "icon-filename", "/usr/share/pixmaps/faces/astronaut.jpg", + "is-logged-in", TRUE, + "is-current-user", TRUE, + NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + /* Add the menubar */ gtk_menu_shell_append (GTK_MENU_SHELL (menubar), root); diff --git a/src/Makefile.am b/src/Makefile.am index a2a82da..0a4dbab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ sources_h = \ idorange.h \ idoscalemenuitem.h \ idoswitchmenuitem.h \ + idousermenuitem.h \ idotimeline.h \ libido.h \ idoactionhelper.h @@ -70,7 +71,8 @@ libido_0_1_la_SOURCES = \ idoswitchmenuitem.c \ idotimeline.c \ idomenuitemfactory.c \ - idoactionhelper.c + idoactionhelper.c \ + idousermenuitem.c libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES) diff --git a/src/idousermenuitem.c b/src/idousermenuitem.c new file mode 100644 index 0000000..cb405e8 --- /dev/null +++ b/src/idousermenuitem.c @@ -0,0 +1,357 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + Mirco Müller <mirco.mueller@canonical.com> + Charles Kerr <charles.kerr@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <gtk/gtk.h> + +#include "idousermenuitem.h" + +#define FALLBACK_ICON_NAME "avatar-default" + +enum +{ + PROP_0, + PROP_LABEL, + PROP_ICON_FILENAME, + PROP_IS_LOGGED_IN, + PROP_IS_CURRENT_USER, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +struct _IdoUserMenuItemPrivate +{ + GtkWidget* user_image; + GtkWidget* user_name; + GtkWidget* container; + GtkWidget* tick_icon; + gboolean is_logged_in; + gboolean is_current_user; + gchar * label; + gchar * icon_filename; +}; + +G_DEFINE_TYPE (IdoUserMenuItem, ido_user_menu_item, GTK_TYPE_MENU_ITEM); + +/* Prototypes */ +static gboolean ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * image, + cairo_t * cr, + gpointer gself); + + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IdoUserMenuItem * self = IDO_USER_MENU_ITEM (o); + + switch (property_id) + { + case PROP_LABEL: + g_value_set_string (value, self->priv->label); + break; + + case PROP_ICON_FILENAME: + g_value_set_string (value, self->priv->icon_filename); + break; + + case PROP_IS_LOGGED_IN: + g_value_set_boolean (value, self->priv->is_logged_in); + break; + + case PROP_IS_CURRENT_USER: + g_value_set_boolean (value, self->priv->is_current_user); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + break; + } +} + +static void +my_set_property (GObject * o, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + IdoUserMenuItem * self = IDO_USER_MENU_ITEM (o); + + switch (property_id) + { + case PROP_LABEL: + ido_user_menu_item_set_label (self, g_value_get_string (value)); + break; + + case PROP_ICON_FILENAME: + ido_user_menu_item_set_icon (self, g_value_get_string (value)); + break; + + case PROP_IS_LOGGED_IN: + ido_user_menu_item_set_logged_in (self, g_value_get_boolean (value)); + break; + + case PROP_IS_CURRENT_USER: + self->priv->is_current_user = g_value_get_boolean (value); + gtk_widget_queue_draw (GTK_WIDGET(self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + break; + } +} + +static void +my_dispose (GObject *object) +{ + G_OBJECT_CLASS (ido_user_menu_item_parent_class)->dispose (object); +} + +static void +my_finalize (GObject *object) +{ + IdoUserMenuItem * self = IDO_USER_MENU_ITEM (object); + + g_free (self->priv->label); + g_free (self->priv->icon_filename); + + G_OBJECT_CLASS (ido_user_menu_item_parent_class)->finalize (object); +} + +static void +ido_user_menu_item_class_init (IdoUserMenuItemClass *klass) +{ + GParamFlags prop_flags; + GObjectClass * gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (IdoUserMenuItemPrivate)); + + gobject_class->get_property = my_get_property; + gobject_class->set_property = my_set_property; + gobject_class->dispose = my_dispose; + gobject_class->finalize = my_finalize; + + prop_flags = G_PARAM_CONSTRUCT + | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS; + + properties[PROP_LABEL] = g_param_spec_string ("label", + "The user's name", + "The name to display", + "J. Random User", + prop_flags); + + properties[PROP_ICON_FILENAME] = g_param_spec_string ("icon-filename", + "The icon's filename", + "The icon to display", + NULL, + prop_flags); + + properties[PROP_IS_LOGGED_IN] = g_param_spec_boolean ("is-logged-in", + "is logged in", + "is user logged in?", + FALSE, + prop_flags); + + properties[PROP_IS_CURRENT_USER] = g_param_spec_boolean ("is-current-user", + "is current user", + "is user current?", + FALSE, + prop_flags); + + g_object_class_install_properties (gobject_class, PROP_LAST, properties); +} + +static void +ido_user_menu_item_init (IdoUserMenuItem *self) +{ + IdoUserMenuItemPrivate * priv; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + IDO_USER_MENU_ITEM_TYPE, + IdoUserMenuItemPrivate); + + priv = self->priv; + + // Create the UI elements. + priv->user_image = gtk_image_new (); + gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); + + priv->user_name = gtk_label_new (NULL); + + priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); + + priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", + GTK_ICON_SIZE_MENU); + gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); + + // Pack it together + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_image, + FALSE, + FALSE, + 0); + gtk_box_pack_start (GTK_BOX (priv->container), + priv->user_name, + FALSE, + FALSE, + 3); + gtk_box_pack_end (GTK_BOX(priv->container), + priv->tick_icon, + FALSE, + FALSE, 5); + + gtk_widget_show_all (priv->container); + gtk_container_add (GTK_CONTAINER (self), priv->container); + gtk_widget_show_all (priv->tick_icon); + gtk_widget_set_no_show_all (priv->tick_icon, TRUE); + gtk_widget_hide (priv->tick_icon); + + + // Fetch the drawing context. + g_signal_connect_after (GTK_WIDGET(self), "draw", + G_CALLBACK(ido_user_menu_item_primitive_draw_cb_gtk_3), + GTK_WIDGET(self)); +} + + +/*****************************************************************/ + +static gboolean +ido_user_menu_item_primitive_draw_cb_gtk_3 (GtkWidget * widget, + cairo_t * cr, + gpointer user_data) +{ + IdoUserMenuItemPrivate * priv; + + g_return_val_if_fail(IS_IDO_USER_MENU_ITEM(user_data), FALSE); + + priv = IDO_USER_MENU_ITEM(user_data)->priv; + + /* Draw dot only when user is the current user. */ + if (priv->is_current_user) + { + GtkStyleContext * style_context; + GtkStateFlags state_flags; + GdkRGBA color; + gdouble x, y; + + /* get the foreground color */ + style_context = gtk_widget_get_style_context (widget); + state_flags = gtk_widget_get_state_flags (widget); + gtk_style_context_get_color (style_context, state_flags, &color); + + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + x = allocation.x + 13; + y = allocation.height / 2; + + cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); + + gdk_cairo_set_source_rgba (cr, &color); + + cairo_fill (cr); + } + + return FALSE; +} + +/*** +**** PUBLIC API +***/ + +void +ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_filename) +{ + gboolean updated = FALSE; + IdoUserMenuItemPrivate * p = self->priv; + GtkImage * image = GTK_IMAGE (p->user_image); + + /* make a private copy of the icon name */ + g_free (p->icon_filename); + self->priv->icon_filename = g_strdup (icon_filename); + + /* now try to use it */ + if (icon_filename && *icon_filename) + { + int width = 18; /* arbitrary default values */ + int height = 18; + GError * err = NULL; + GdkPixbuf * pixbuf = NULL; + + /* load the image */ + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); + pixbuf = gdk_pixbuf_new_from_file_at_size (icon_filename, + width, height, &err); + if (err == NULL) + { + gtk_image_set_from_pixbuf (image, pixbuf); + g_object_unref (pixbuf); + updated = TRUE; + } + else + { + g_warning ("Couldn't load the image \"%s\": %s", + icon_filename, err->message); + g_clear_error (&err); + } + } + + /* as a fallback, use the default user icon */ + if (!updated) + { + gtk_image_set_from_icon_name (image, + FALLBACK_ICON_NAME, + GTK_ICON_SIZE_MENU); + } +} + +void +ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean is_logged_in) +{ + gtk_widget_set_visible (self->priv->tick_icon, is_logged_in); +} + +void +ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user) +{ + self->priv->is_current_user = is_current_user; + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +void +ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label) +{ + gtk_label_set_label (GTK_LABEL(self->priv->user_name), label); +} + +GtkWidget* +ido_user_menu_item_new (void) +{ + return GTK_WIDGET (g_object_new (IDO_USER_MENU_ITEM_TYPE, NULL)); +} diff --git a/src/idousermenuitem.h b/src/idousermenuitem.h new file mode 100644 index 0000000..b9a3d00 --- /dev/null +++ b/src/idousermenuitem.h @@ -0,0 +1,66 @@ +/* +Copyright 2011 Canonical Ltd. + +Authors: + Conor Curran <conor.curran@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __IDO_USER_MENU_ITEM_H__ +#define __IDO_USER_MENU_ITEM_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define IDO_USER_MENU_ITEM_TYPE (ido_user_menu_item_get_type ()) +#define IDO_USER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItem)) +#define IDO_USER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemClass)) +#define IS_IDO_USER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_USER_MENU_ITEM_TYPE)) +#define IS_IDO_USER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_USER_MENU_ITEM_TYPE)) +#define IDO_USER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_USER_MENU_ITEM_TYPE, IdoUserMenuItemClass)) + +typedef struct _IdoUserMenuItem IdoUserMenuItem; +typedef struct _IdoUserMenuItemClass IdoUserMenuItemClass; +typedef struct _IdoUserMenuItemPrivate IdoUserMenuItemPrivate; + +/* property keys */ +#define IDO_USER_MENU_ITEM_PROP_LABEL "label" +#define IDO_USER_MENU_ITEM_PROP_ICON_FILENAME "icon-filename" +#define IDO_USER_MENU_ITEM_PROP_IS_LOGGED_IN "is-logged-in" +#define IDO_USER_MENU_ITEM_PROP_IS_CURRENT_USER "is-current-user" + +struct _IdoUserMenuItemClass +{ + GtkMenuItemClass parent_class; +}; + +struct _IdoUserMenuItem +{ + /*< private >*/ + GtkMenuItem parent; + IdoUserMenuItemPrivate * priv; +}; + +GType ido_user_menu_item_get_type (void) G_GNUC_CONST; + +GtkWidget* ido_user_menu_item_new(void); + +void ido_user_menu_item_set_icon (IdoUserMenuItem * self, const char * icon_name); +void ido_user_menu_item_set_logged_in (IdoUserMenuItem * self, gboolean is_logged_in); +void ido_user_menu_item_set_current_user (IdoUserMenuItem * self, gboolean is_current_user); +void ido_user_menu_item_set_label (IdoUserMenuItem * self, const char * label); + +G_END_DECLS + +#endif |