diff options
-rw-r--r-- | src/user-widget.c | 434 |
1 files changed, 386 insertions, 48 deletions
diff --git a/src/user-widget.c b/src/user-widget.c index 172c645..13f7d0b 100644 --- a/src/user-widget.c +++ b/src/user-widget.c @@ -3,7 +3,8 @@ Copyright 2011 Canonical Ltd. Authors: Conor Curran <conor.curran@canonical.com> - + Mirco Müller <mirco.mueller@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. @@ -24,6 +25,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib/gi18n.h> #include <gtk/gtk.h> #include <glib.h> +#include <math.h> #include <libindicator/indicator-image-helper.h> #include "user-widget.h" #include "dbus-shared-names.h" @@ -44,6 +46,13 @@ struct _UserWidgetPrivate #define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate)) +typedef struct +{ + double r; + double g; + double b; +} CairoColorRGB; + /* Prototypes */ static void user_widget_class_init (UserWidgetClass *klass); static void user_widget_init (UserWidget *self); @@ -60,10 +69,25 @@ static void user_widget_property_update (DbusmenuMenuitem* item, gchar* property, GVariant* value, gpointer userdata); + + +static void _color_shade (const CairoColorRGB *a, + float k, + CairoColorRGB *b); + +static void draw_album_border (GtkWidget *widget, gboolean selected); + #if GTK_CHECK_VERSION(3, 0, 0) +/*static void user_widget_get_preferred_height (GtkWidget* self, + gint* minimum_height, + gint* natural_height);*/ static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, cairo_t* cr, gpointer user_data); +static gboolean user_widget_draw_usericon_gtk_3 (GtkWidget *widget, + cairo_t* cr, + gpointer user_data); + #else static gboolean user_widget_primitive_draw_cb (GtkWidget *image, GdkEventExpose *event, @@ -79,6 +103,7 @@ user_widget_class_init (UserWidgetClass *klass) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); widget_class->button_release_event = user_widget_button_release_event; + //widget_class->get_preferred_height = user_widget_get_preferred_height; g_type_class_add_private (klass, sizeof (UserWidgetPrivate)); @@ -106,6 +131,8 @@ user_widget_init (UserWidget *self) // Create the UI elements. priv->user_image = gtk_image_new (); + gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); + gtk_misc_set_padding (GTK_MISC(priv->user_image),0, 4.0); priv->user_name = gtk_label_new (""); priv->container = gtk_hbox_new (FALSE, 0); @@ -129,18 +156,23 @@ user_widget_init (UserWidget *self) FALSE, FALSE, 5); - gtk_widget_show_all (priv->container); - gtk_container_add (GTK_CONTAINER (self), priv->container); - + 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. #if GTK_CHECK_VERSION(3, 0, 0) g_signal_connect_after (GTK_WIDGET(self), "draw", G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), GTK_WIDGET(self)); + + g_signal_connect_after (GTK_WIDGET(priv->user_image), "draw", + G_CALLBACK(user_widget_draw_usericon_gtk_3), + GTK_WIDGET(self)); + #else g_signal_connect_after (GTK_WIDGET(self), "expose-event", G_CALLBACK(user_widget_primitive_draw_cb), @@ -163,9 +195,20 @@ user_widget_finalize (GObject *object) G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); } + +/*****************************************************************/ + #if GTK_CHECK_VERSION(3, 0, 0) -// Draw the radio dot and/or green check mark +/*static void user_widget_get_preferred_height (GtkWidget* self, + gint* minimum_height, + gint* natural_height) +{ + minimum_height = *natural_height = 60; +} +*/ + + // TODO handle drawing of green check mark static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, @@ -184,15 +227,13 @@ user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, } GtkStyle *style; - gdouble x, y; - gdouble offset = 15.0; - + gdouble x, y; style = gtk_widget_get_style (widget); GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); x = allocation.x + 13; - y = offset; + y = allocation.height / 2; cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI);; @@ -204,68 +245,359 @@ user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, return FALSE; } +static gboolean +user_widget_draw_usericon_gtk_3 (GtkWidget *widget, + cairo_t* cr, + gpointer user_data) +{ + /*g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); + UserWidget* meta = USER_WIDGET(user_data); + UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + */ + draw_album_border (widget, FALSE); + return TRUE; +} +/** + * TODO: + * Sort out gtk2 + */ // GTK 2 Expose handler #else - -// Draw the triangle if the player is running ... static gboolean user_widget_primitive_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { - /* g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); UserWidget* meta = USER_WIDGET(user_data); UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); + // Draw dot only when user is the current user. + if (!dbusmenu_menuitem_property_get_bool (priv->twin_item, + USER_ITEM_PROP_IS_CURRENT_USER)){ + return FALSE; + } + GtkStyle *style; cairo_t *cr; - int x, y, arrow_width, arrow_height; - - gint offset = 3; - arrow_width = 5; - arrow_height = 9; + cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget)); + gdouble x, y; style = gtk_widget_get_style (widget); - - cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget)); - GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); - x = allocation.x; - y = allocation.y; - - // Draw player icon - if (priv->icon_buf != NULL){ - gdk_cairo_set_source_pixbuf (cr, - priv->icon_buf, - x + arrow_width + 1, - y + offset); - cairo_paint (cr); - } - - // Draw triangle but only if the player is running. - if (dbusmenu_menuitem_property_get_bool (priv->twin_item, - DBUSMENU_METADATA_MENUITEM_PLAYER_RUNNING)){ - y += (double)arrow_height/2.0 + offset; - cairo_set_line_width (cr, 1.0); - - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + arrow_height); - cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); - cairo_close_path (cr); - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - } + x = allocation.x + 13; + y = allocation.height / 2; - cairo_destroy (cr);*/ + cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI);; + + cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, + style->fg[gtk_widget_get_state(widget)].green/65535.0, + style->fg[gtk_widget_get_state(widget)].blue/65535.0); + cairo_fill (cr); + cairo_destroy (cr); + return FALSE; } #endif +static void +draw_album_border(GtkWidget *widg, gboolean selected) +{ + cairo_t *cr; + cr = gdk_cairo_create (gtk_widget_get_window (widg)); + #if GTK_CHECK_VERSION(3, 0, 0) + gtk_style_context_add_class (gtk_widget_get_style_context (widg), + "menu"); + #endif + + GtkStyle *style; + style = gtk_widget_get_style (widg); + + GtkAllocation alloc; + gtk_widget_get_allocation (widg, &alloc); + gint offset = 0; + gint v_offset = 4; + + alloc.width = alloc.width + (offset * 2); + alloc.height = alloc.height - v_offset - 2; + alloc.x = alloc.x - offset; + alloc.y = alloc.y + v_offset/2 +1; + + CairoColorRGB bg_normal, fg_normal; + + bg_normal.r = style->bg[0].red/65535.0; + bg_normal.g = style->bg[0].green/65535.0; + bg_normal.b = style->bg[0].blue/65535.0; + + gint state = selected ? 5 : 0; + + fg_normal.r = style->fg[state].red/65535.0; + fg_normal.g = style->fg[state].green/65535.0; + fg_normal.b = style->fg[state].blue/65535.0; + + CairoColorRGB dark_top_color; + CairoColorRGB light_bottom_color; + CairoColorRGB background_color; + + _color_shade ( &bg_normal, 0.93, &background_color ); + _color_shade ( &bg_normal, 0.23, &dark_top_color ); + _color_shade ( &fg_normal, 0.55, &light_bottom_color ); + + cairo_rectangle (cr, + alloc.x, alloc.y, + alloc.width, alloc.height); + + cairo_set_line_width (cr, 1.0); + + cairo_clip ( cr ); + + cairo_move_to (cr, alloc.x, alloc.y ); + cairo_line_to (cr, alloc.x + alloc.width, + alloc.y ); + cairo_line_to ( cr, alloc.x + alloc.width, + alloc.y + alloc.height ); + cairo_line_to ( cr, alloc.x, alloc.y + alloc.height ); + cairo_line_to ( cr, alloc.x, alloc.y); + cairo_close_path (cr); + + cairo_set_source_rgba ( cr, + background_color.r, + background_color.g, + background_color.b, + 1.0 ); + + cairo_stroke ( cr ); + + cairo_move_to (cr, alloc.x, alloc.y ); + cairo_line_to (cr, alloc.x + alloc.width, + alloc.y ); + + cairo_close_path (cr); + cairo_set_source_rgba ( cr, + dark_top_color.r, + dark_top_color.g, + dark_top_color.b, + 1.0 ); + + cairo_stroke ( cr ); + + cairo_move_to ( cr, alloc.x + alloc.width, + alloc.y + alloc.height ); + cairo_line_to ( cr, alloc.x, alloc.y + alloc.height ); + + cairo_close_path (cr); + cairo_set_source_rgba ( cr, + light_bottom_color.r, + light_bottom_color.g, + light_bottom_color.b, + 1.0); + + cairo_stroke ( cr ); + cairo_destroy (cr); +} + +static void +_color_rgb_to_hls (gdouble *r, + gdouble *g, + gdouble *b) +{ + gdouble min; + gdouble max; + gdouble red; + gdouble green; + gdouble blue; + gdouble h = 0; + gdouble l; + gdouble s; + gdouble delta; + + red = *r; + green = *g; + blue = *b; + + if (red > green) + { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } + else + { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + l = (max+min)/2; + if (fabs (max-min) < 0.0001) + { + h = 0; + s = 0; + } + else + { + if (l <= 0.5) + s = (max-min)/(max+min); + else + s = (max-min)/(2-max-min); + + delta = (max -min) != 0 ? (max -min) : 1; + + if(delta == 0) + delta = 1; + if (red == max) + h = (green-blue)/delta; + else if (green == max) + h = 2+(blue-red)/delta; + else if (blue == max) + h = 4+(red-green)/delta; + + h *= 60; + if (h < 0.0) + h += 360; + } + + *r = h; + *g = l; + *b = s; +} + +static void +_color_hls_to_rgb (gdouble *h, + gdouble *l, + gdouble *s) +{ + gdouble hue; + gdouble lightness; + gdouble saturation; + gdouble m1, m2; + gdouble r, g, b; + + lightness = *l; + saturation = *s; + + if (lightness <= 0.5) + m2 = lightness*(1+saturation); + else + m2 = lightness+saturation-lightness*saturation; + + m1 = 2*lightness-m2; + + if (saturation == 0) + { + *h = lightness; + *l = lightness; + *s = lightness; + } + else + { + hue = *h+120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + r = m1+(m2-m1)*hue/60; + else if (hue < 180) + r = m2; + else if (hue < 240) + r = m1+(m2-m1)*(240-hue)/60; + else + r = m1; + + hue = *h; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + g = m1+(m2-m1)*hue/60; + else if (hue < 180) + g = m2; + else if (hue < 240) + g = m1+(m2-m1)*(240-hue)/60; + else + g = m1; + + hue = *h-120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + b = m1+(m2-m1)*hue/60; + else if (hue < 180) + b = m2; + else if (hue < 240) + b = m1+(m2-m1)*(240-hue)/60; + else + b = m1; + + *h = r; + *l = g; + *s = b; + } +} + +void +_color_shade (const CairoColorRGB *a, float k, CairoColorRGB *b) +{ + double red; + double green; + double blue; + + red = a->r; + green = a->g; + blue = a->b; + + if (k == 1.0) + { + b->r = red; + b->g = green; + b->b = blue; + return; + } + + _color_rgb_to_hls (&red, &green, &blue); + + green *= k; + if (green > 1.0) + green = 1.0; + else if (green < 0.0) + green = 0.0; + + blue *= k; + if (blue > 1.0) + blue = 1.0; + else if (blue < 0.0) + blue = 0.0; + + _color_hls_to_rgb (&red, &green, &blue); + + b->r = red; + b->g = green; + b->b = blue; +} + + +/*****************************************************************/ + /* Suppress/consume keyevents */ static gboolean user_widget_button_release_event (GtkWidget *menuitem, @@ -274,6 +606,10 @@ user_widget_button_release_event (GtkWidget *menuitem, return FALSE; } + +/** + * TODO, be sensitive to UI updates + * */ static void user_widget_property_update (DbusmenuMenuitem* item, gchar* property, GVariant* value, gpointer userdata) @@ -283,6 +619,8 @@ user_widget_property_update (DbusmenuMenuitem* item, gchar* property, } + + static void user_widget_set_twin_item (UserWidget* self, DbusmenuMenuitem* twin_item) |