2005-08-30 Tommi Komulainen <tommi.komulainen@nokia.com>
[hildon] / hildon-widgets / hildon-color-button.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 #include <config.h>
26
27 #include <gdk-pixbuf/gdk-pixbuf.h>
28 #include <gtk/gtkbutton.h>
29 #include <gtk/gtkalignment.h>
30 #include <gtk/gtkdrawingarea.h>
31 #include <gtk/gtksignal.h>
32
33 #include "hildon-color-button.h"
34 #include "hildon-color-selector.h"
35
36 #include <libintl.h>
37 #define _(String) dgettext(PACKAGE, String)
38
39 #define HILDON_COLOR_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE\
40               ((obj), HILDON_TYPE_COLOR_BUTTON, HildonColorButtonPrivate))
41
42 #define COLOR_FIELD_HEIGHT 26
43 #define COLOR_FIELD_WIDTH 26
44 #define COLOR_BUTTON_WIDTH 48
45 #define COLOR_BUTTON_HEIGHT 40
46
47 struct _HildonColorButtonPrivate 
48 {
49   GtkWidget *dialog;
50
51   GtkWidget *drawing_area;
52   GdkPixbuf *pixbuf;
53   GdkColor color;
54   GdkGC *gc;
55 };
56
57 enum 
58 {
59   PROP_NONE,
60   PROP_COLOR
61 };
62
63 static void
64 hildon_color_button_class_init(HildonColorButtonClass *klass);
65 static void
66 hildon_color_button_init(HildonColorButton *color_button);
67
68 static void
69 hildon_color_button_finalize(GObject *object);
70 static void
71 hildon_color_button_set_property(GObject *object, guint param_id,
72                                                            const GValue *value, GParamSpec *pspec);
73 static void
74 hildon_color_button_get_property(GObject *object, guint param_id,
75                                                    GValue *value, GParamSpec *pspec);
76 static void
77 hildon_color_button_realize(GtkWidget *widget);
78 static void
79 hildon_color_button_clicked(GtkButton *button);
80 static gint
81 hildon_color_field_expose_event(GtkWidget *widget, GdkEventExpose *event,
82                                 HildonColorButton *cb);
83
84 static gboolean
85 hildon_color_button_mnemonic_activate( GtkWidget *widget,
86                                        gboolean group_cycling );
87 static void
88 hildon_color_button_recolor_pixbuf(HildonColorButton *cb);
89
90
91 static gpointer parent_class = NULL;
92
93 GType
94 hildon_color_button_get_type(void)
95 {
96   static GType color_button_type = 0;
97   
98   if (!color_button_type)
99     {
100       static const GTypeInfo color_button_info =
101       {
102         sizeof (HildonColorButtonClass),
103         NULL,           /* base_init */
104         NULL,           /* base_finalize */
105         (GClassInitFunc) hildon_color_button_class_init,
106         NULL,           /* class_finalize */
107         NULL,           /* class_data */
108         sizeof (HildonColorButton),
109         0,              /* n_preallocs */
110         (GInstanceInitFunc) hildon_color_button_init,
111       };
112       
113       color_button_type =
114         g_type_register_static (GTK_TYPE_BUTTON, "HildonColorButton",
115                                 &color_button_info, 0);
116     }
117   
118   return color_button_type;
119 }
120
121 static void
122 hildon_color_button_class_init(HildonColorButtonClass *klass)
123 {
124   GObjectClass *gobject_class;
125   GtkButtonClass *button_class;
126   GtkWidgetClass *widget_class;
127   
128   gobject_class = G_OBJECT_CLASS (klass);
129   button_class = GTK_BUTTON_CLASS (klass);
130   widget_class = GTK_WIDGET_CLASS (klass);
131   
132   parent_class = g_type_class_peek_parent (klass);
133
134   gobject_class->get_property = hildon_color_button_get_property;
135   gobject_class->set_property = hildon_color_button_set_property;
136   gobject_class->finalize = hildon_color_button_finalize;
137   widget_class->realize = hildon_color_button_realize;
138   button_class->clicked = hildon_color_button_clicked;
139   widget_class->mnemonic_activate = hildon_color_button_mnemonic_activate;
140   
141   /**
142    * HildonColorButton:color:
143    *
144    * The selected color.
145    */
146   g_object_class_install_property (gobject_class, PROP_COLOR,
147                                    g_param_spec_boxed ("color",
148                                      "Current Color",
149                                      "The selected color",
150                                      GDK_TYPE_COLOR, G_PARAM_READABLE | 
151                                      G_PARAM_WRITABLE));
152
153   g_type_class_add_private (gobject_class, sizeof (HildonColorButtonPrivate));
154 }
155
156 /* Handle exposure events for the color picker's drawing area */
157 static gint
158 hildon_color_field_expose_event(GtkWidget *widget, GdkEventExpose *event,
159                                 HildonColorButton *cb)
160 {
161   gdk_draw_pixbuf(widget->window, cb->priv->gc,
162                   cb->priv->pixbuf, event->area.x,
163                   event->area.y, event->area.x,
164                   event->area.y, event->area.width,
165                   event->area.height, GDK_RGB_DITHER_MAX,
166                   event->area.x, event->area.y);
167   return FALSE;
168 }
169
170 static void
171 hildon_color_button_init(HildonColorButton *cb)
172 {
173   GtkWidget *align;
174   
175   cb->priv = HILDON_COLOR_BUTTON_GET_PRIVATE(cb);
176
177   cb->priv->dialog = NULL;
178   cb->priv->gc = NULL;
179
180   gtk_widget_push_composite_child();
181   
182   align = gtk_alignment_new(0.5, 0.5, 0, 0);
183
184   cb->priv->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
185                                     COLOR_FIELD_WIDTH, COLOR_FIELD_HEIGHT);
186
187   cb->priv->drawing_area = gtk_drawing_area_new();
188
189   gtk_widget_set_size_request(GTK_WIDGET(cb), COLOR_BUTTON_WIDTH,
190                               COLOR_BUTTON_HEIGHT);
191   gtk_widget_set_size_request(GTK_WIDGET(cb->priv->drawing_area),
192                               COLOR_FIELD_WIDTH, COLOR_FIELD_HEIGHT);
193
194   g_signal_connect(G_OBJECT(cb->priv->drawing_area), "expose-event",
195                    G_CALLBACK(hildon_color_field_expose_event), cb);
196
197   gtk_container_add(GTK_CONTAINER(align), cb->priv->drawing_area);
198   gtk_container_add(GTK_CONTAINER(cb), align);
199   
200   hildon_color_button_recolor_pixbuf(cb);
201   
202   gtk_widget_show_all(align);
203   
204   gtk_widget_pop_composite_child();
205 }
206
207 static void
208 hildon_color_button_finalize(GObject *object)
209 {
210   HildonColorButton *cb = HILDON_COLOR_BUTTON(object);
211
212   if (cb->priv->dialog)
213   {
214     gtk_widget_destroy(cb->priv->dialog);
215     cb->priv->dialog = NULL;
216   }
217
218   if (cb->priv->pixbuf)
219   {
220     g_object_unref(G_OBJECT(cb->priv->pixbuf));
221     cb->priv->pixbuf = NULL;
222   }
223
224   if (cb->priv->gc)
225   {
226     g_object_unref(G_OBJECT(cb->priv->gc));
227     cb->priv->gc = NULL;
228   }
229   if( G_OBJECT_CLASS(parent_class)->finalize )
230     G_OBJECT_CLASS(parent_class)->finalize(object);
231 }
232
233 static void
234 hildon_color_button_realize(GtkWidget *widget)
235 {
236   HildonColorButton *cb = HILDON_COLOR_BUTTON(widget);
237
238   GTK_WIDGET_CLASS(parent_class)->realize(widget);
239
240   if (!cb->priv->gc)
241     cb->priv->gc = gdk_gc_new(widget->window);
242
243   hildon_color_button_recolor_pixbuf(cb);
244 }
245
246 static gboolean
247 hildon_color_button_mnemonic_activate( GtkWidget *widget,
248                                        gboolean group_cycling )
249 {
250   gtk_widget_grab_focus( widget );
251   return TRUE;
252 }
253
254 static void
255 hildon_color_button_recolor_pixbuf(HildonColorButton *cb)
256 {
257   gint i, j, rowstride;
258   guchar *pixels;
259   guint8 r, g, b;
260   GdkPixbuf *pb = cb->priv->pixbuf;
261   GdkColor *color = &cb->priv->color;
262   
263   r = (color->red >> 8);
264   g = (color->green >> 8);
265   b = (color->blue >> 8);
266   
267   pixels = gdk_pixbuf_get_pixels(pb);
268   rowstride = gdk_pixbuf_get_rowstride(pb);
269   
270   for (j=0; j<COLOR_FIELD_HEIGHT; j++)
271     for (i=0; i<COLOR_FIELD_WIDTH; i++)
272     {
273       *(j * rowstride + pixels + i * 3)     = r;
274       *(j * rowstride + pixels + i * 3 + 1) = g;
275       *(j * rowstride + pixels + i * 3 + 2) = b;
276     }
277   gtk_widget_queue_draw(GTK_WIDGET(cb));
278 }
279
280 static void
281 hildon_color_button_clicked(GtkButton *button)
282 {
283   gint result;
284   HildonColorButton *cb = HILDON_COLOR_BUTTON(button);
285   HildonColorSelector *csd = HILDON_COLOR_SELECTOR(cb->priv->dialog);
286
287   if (!csd)
288   {
289     GtkWidget *parent = gtk_widget_get_toplevel(GTK_WIDGET(cb));
290     cb->priv->dialog = hildon_color_selector_new(GTK_WINDOW(parent));
291     csd = HILDON_COLOR_SELECTOR(cb->priv->dialog);
292     
293     if (parent)
294       gtk_window_set_transient_for(GTK_WINDOW(csd), GTK_WINDOW(parent));
295   }
296   
297   hildon_color_selector_set_color(csd, &cb->priv->color);
298   
299   result = gtk_dialog_run(GTK_DIALOG(csd));
300   if (result == GTK_RESPONSE_OK)
301   {
302     cb->priv->color = *hildon_color_selector_get_color(csd);
303     g_object_set( G_OBJECT(cb), "color", &cb->priv->color, NULL );
304   }
305   gtk_widget_hide(GTK_WIDGET(csd));
306 }
307
308 static void
309 hildon_color_button_set_property(GObject *object, guint param_id,
310                                                    const GValue *value, GParamSpec *pspec)
311 {
312   HildonColorButton *cb = HILDON_COLOR_BUTTON(object);
313
314   switch (param_id) 
315     {
316     case PROP_COLOR:
317       cb->priv->color = *(GdkColor*)g_value_get_boxed(value);
318       hildon_color_button_recolor_pixbuf(cb);
319       break;
320     default:
321       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
322       break;
323     }
324 }
325
326 static void
327 hildon_color_button_get_property(GObject *object, guint param_id,
328                                                    GValue *value, GParamSpec *pspec)
329 {
330   HildonColorButton *cb = HILDON_COLOR_BUTTON(object);
331
332   switch (param_id) 
333     {
334     case PROP_COLOR:
335       g_value_set_boxed(value, &cb->priv->color);
336       break;
337     default:
338       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
339       break;
340     }
341 }
342
343 /**
344  * hildon_color_button_new:
345  *
346  * Creates a new color button. This returns a widget in the form of
347  * a small button containing a swatch representing the current selected 
348  * color. When the button is clicked, a color-selection dialog will open, 
349  * allowing the user to select a color. The swatch will be updated to reflect 
350  * the new color when the user finishes.
351  *
352  * Return value: a new color button.
353  */
354 GtkWidget *
355 hildon_color_button_new(void)
356 {
357   return g_object_new( HILDON_TYPE_COLOR_BUTTON, NULL );
358 }
359
360 /**
361  * hildon_color_button_new_with_color:
362  * @color: A #GdkColor to set the current color with.
363  *
364  * Creates a new color button. 
365  *
366  * Return value: a new color button.
367  */
368 GtkWidget *
369 hildon_color_button_new_with_color(const GdkColor *color)
370 {
371   return g_object_new( HILDON_TYPE_COLOR_BUTTON, "color", color, NULL );
372 }
373
374 /**
375  * hildon_color_button_set_color:
376  * @button: A #HildonColorButton
377  * @color: A color to be set
378  *
379  * Sets a color to the button.
380  */
381 void
382 hildon_color_button_set_color( HildonColorButton *button, GdkColor *color )
383 {
384   g_object_set( G_OBJECT(button), "color", color, NULL );
385 }
386
387 /**
388  * hildon_color_button_get_color:
389  * @button: A #HildonColorButton
390  *
391  * Gets a color from the button.
392  *
393  * Return value: The color set to a current button.
394  */
395 GdkColor *
396 hildon_color_button_get_color( HildonColorButton *button )
397 {
398   GdkColor *color = NULL;
399   g_object_get( G_OBJECT(button), "color", &color, NULL );
400   return color;
401 }