1218037fe94c30a6fee137f39f79ea3bfd425866
[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 <gtk/gtkbutton.h>
28 #include <gtk/gtkalignment.h>
29 #include <gtk/gtkdrawingarea.h>
30 #include <gtk/gtksignal.h>
31
32 #include "hildon-color-button.h"
33 #include "hildon-color-selector.h"
34
35 #define HILDON_COLOR_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE\
36               ((obj), HILDON_TYPE_COLOR_BUTTON, HildonColorButtonPrivate))
37
38 #define COLOR_FILLED_HEIGHT 22
39 #define COLOR_FILLED_WIDTH 22
40 #define COLOR_BUTTON_WIDTH 48
41 #define COLOR_BUTTON_HEIGHT 40
42
43 /* the outer border color */
44 #define OUTER_BORDER_RED   0
45 #define OUTER_BORDER_BLUE  0
46 #define OUTER_BORDER_GREEN 0
47 #define OUTER_BORDER_THICKNESS 1
48
49 /* the inner border color */
50 #define INNER_BORDER_RED   65535
51 #define INNER_BORDER_BLUE  65535
52 #define INNER_BORDER_GREEN 65535
53 #define INNER_BORDER_THICKNESS 1
54
55 struct _HildonColorButtonPrivate 
56 {
57   GtkWidget *dialog;
58
59   GdkColor color;
60   GdkGC *gc;
61 };
62
63 enum 
64 {
65   PROP_NONE,
66   PROP_COLOR
67 };
68
69 static void
70 hildon_color_button_class_init(HildonColorButtonClass *klass);
71 static void
72 hildon_color_button_init(HildonColorButton *color_button);
73
74 static void
75 hildon_color_button_finalize(GObject *object);
76 static void
77 hildon_color_button_set_property(GObject *object, guint param_id,
78                                  const GValue *value, GParamSpec *pspec);
79 static void
80 hildon_color_button_get_property(GObject *object, guint param_id,
81                                  GValue *value, GParamSpec *pspec);
82 static void
83 hildon_color_button_realize(GtkWidget *widget);
84 static void
85 hildon_color_button_unrealize(GtkWidget *widget);
86 static void
87 hildon_color_button_clicked(GtkButton *button);
88 static gint
89 hildon_color_field_expose_event(GtkWidget *widget, GdkEventExpose *event,
90                                 HildonColorButton *cb);
91
92 static gboolean
93 hildon_color_button_mnemonic_activate( GtkWidget *widget,
94                                        gboolean group_cycling );
95
96
97 static gpointer parent_class = NULL;
98
99 GType
100 hildon_color_button_get_type(void)
101 {
102   static GType color_button_type = 0;
103   
104   if (!color_button_type)
105     {
106       static const GTypeInfo color_button_info =
107       {
108         sizeof (HildonColorButtonClass),
109         NULL,           /* base_init */
110         NULL,           /* base_finalize */
111         (GClassInitFunc) hildon_color_button_class_init,
112         NULL,           /* class_finalize */
113         NULL,           /* class_data */
114         sizeof (HildonColorButton),
115         0,              /* n_preallocs */
116         (GInstanceInitFunc) hildon_color_button_init,
117       };
118       
119       color_button_type =
120         g_type_register_static (GTK_TYPE_BUTTON, "HildonColorButton",
121                                 &color_button_info, 0);
122     }
123   
124   return color_button_type;
125 }
126
127 static void
128 hildon_color_button_class_init(HildonColorButtonClass *klass)
129 {
130   GObjectClass *gobject_class;
131   GtkButtonClass *button_class;
132   GtkWidgetClass *widget_class;
133   
134   gobject_class = G_OBJECT_CLASS (klass);
135   button_class = GTK_BUTTON_CLASS (klass);
136   widget_class = GTK_WIDGET_CLASS (klass);
137   
138   parent_class = g_type_class_peek_parent (klass);
139
140   gobject_class->get_property = hildon_color_button_get_property;
141   gobject_class->set_property = hildon_color_button_set_property;
142   gobject_class->finalize = hildon_color_button_finalize;
143   widget_class->realize = hildon_color_button_realize;
144   widget_class->unrealize = hildon_color_button_unrealize;
145   button_class->clicked = hildon_color_button_clicked;
146   widget_class->mnemonic_activate = hildon_color_button_mnemonic_activate;
147   
148   /**
149    * HildonColorButton:color:
150    *
151    * The selected color.
152    */
153   g_object_class_install_property (gobject_class, PROP_COLOR,
154                                    g_param_spec_boxed ("color",
155                                      "Current Color",
156                                      "The selected color",
157                                      GDK_TYPE_COLOR,
158                                      G_PARAM_READWRITE));
159
160   g_type_class_add_private (gobject_class, sizeof (HildonColorButtonPrivate));
161 }
162
163 /* Handle exposure events for the color picker's drawing area */
164 static gint
165 hildon_color_field_expose_event(GtkWidget *widget, GdkEventExpose *event,
166                                 HildonColorButton *cb)
167 {
168     GdkColor outer_border, inner_border;
169
170     /* Create the outer border color */
171     outer_border.pixel = 0;
172     outer_border.red   = OUTER_BORDER_RED;
173     outer_border.blue  = OUTER_BORDER_BLUE;
174     outer_border.green = OUTER_BORDER_GREEN;
175
176     /* Create the inner border color */
177     inner_border.pixel = 0;
178     inner_border.red   = INNER_BORDER_RED;
179     inner_border.blue  = INNER_BORDER_BLUE;
180     inner_border.green = INNER_BORDER_GREEN;
181
182     /* serve the outer border color to the Graphic Context */
183     gdk_gc_set_rgb_fg_color(cb->priv->gc, &outer_border);
184     /* draw the outer border as a filled rectangle */
185     gdk_draw_rectangle(widget->window,
186             cb->priv->gc,
187             TRUE,
188             event->area.x,
189             event->area.y,
190             event->area.width,
191             event->area.height);
192
193     /* serve the inner border color to the Graphic Context */
194     gdk_gc_set_rgb_fg_color(cb->priv->gc, &inner_border);
195     /* draw the inner border as a filled rectangle */
196     gdk_draw_rectangle(widget->window,
197             cb->priv->gc,
198             TRUE,
199             event->area.x + OUTER_BORDER_THICKNESS,
200             event->area.y + OUTER_BORDER_THICKNESS,
201             event->area.width  - (OUTER_BORDER_THICKNESS*2),
202             event->area.height - (OUTER_BORDER_THICKNESS*2));
203
204     /* serve the actual color to the Graphic Context */
205     gdk_gc_set_rgb_fg_color(cb->priv->gc, &cb->priv->color);
206     /* draw the actual rectangle */
207     gdk_draw_rectangle(widget->window,
208             cb->priv->gc,
209             TRUE,
210             event->area.x + (INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS),
211             event->area.y + (INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS),
212             event->area.height - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2),
213             event->area.width  - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2));
214
215     return FALSE;
216 }
217
218 static void
219 hildon_color_button_init(HildonColorButton *cb)
220 {
221   GtkWidget *align;
222   GtkWidget *drawing_area;
223   
224   cb->priv = HILDON_COLOR_BUTTON_GET_PRIVATE(cb);
225
226   cb->priv->dialog = NULL;
227   cb->priv->gc = NULL;
228
229   gtk_widget_push_composite_child();
230   
231   /* create widgets and pixbuf */
232   align = gtk_alignment_new(0.5, 0.5, 0, 0); /*composite widget*/
233
234   drawing_area = gtk_drawing_area_new(); /*composite widget*/
235
236   /* setting minimum sizes */
237   gtk_widget_set_size_request(GTK_WIDGET(cb), COLOR_BUTTON_WIDTH,
238                               COLOR_BUTTON_HEIGHT);
239   gtk_widget_set_size_request(GTK_WIDGET(drawing_area),
240                               COLOR_FILLED_WIDTH, COLOR_FILLED_HEIGHT);
241
242   /* Connect the callback function for exposure event */
243   g_signal_connect(drawing_area, "expose-event",
244                    G_CALLBACK(hildon_color_field_expose_event), cb);
245
246   /* packing */
247   gtk_container_add(GTK_CONTAINER(align), drawing_area);
248   gtk_container_add(GTK_CONTAINER(cb), align);
249   
250   gtk_widget_show_all(align);
251   
252   gtk_widget_pop_composite_child();
253 }
254
255 /* Free memory used by HildonColorButton */
256 static void
257 hildon_color_button_finalize(GObject *object)
258 {
259   HildonColorButton *cb = HILDON_COLOR_BUTTON(object);
260
261   if (cb->priv->dialog)
262   {
263     gtk_widget_destroy(cb->priv->dialog);
264     cb->priv->dialog = NULL;
265   }
266
267   if( G_OBJECT_CLASS(parent_class)->finalize )
268     G_OBJECT_CLASS(parent_class)->finalize(object);
269 }
270
271 static void
272 hildon_color_button_realize(GtkWidget *widget)
273 {
274   HildonColorButton *cb = HILDON_COLOR_BUTTON(widget);
275
276   GTK_WIDGET_CLASS(parent_class)->realize(widget);
277
278   cb->priv->gc = gdk_gc_new(widget->window);
279 }
280
281 static void
282 hildon_color_button_unrealize(GtkWidget *widget)
283 {
284   HildonColorButton *cb = HILDON_COLOR_BUTTON(widget);
285
286   g_object_unref(cb->priv->gc);
287   cb->priv->gc = NULL;
288
289   GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
290 }
291
292 /* Make the widget sensitive with the keyboard event */
293 static gboolean
294 hildon_color_button_mnemonic_activate( GtkWidget *widget,
295                                        gboolean group_cycling )
296 {
297   gtk_widget_grab_focus( widget );
298   return TRUE;
299 }
300
301 /* Popup a color selector dialog on button click */
302 static void
303 hildon_color_button_clicked(GtkButton *button)
304 {
305   HildonColorButton *cb = HILDON_COLOR_BUTTON(button);
306   HildonColorSelector *cs_dialog = HILDON_COLOR_SELECTOR(cb->priv->dialog);
307
308   /* Popup the color selector dialog */
309   if (!cs_dialog)
310   {
311     /* The dialog hasn't been created yet, do it. */
312     GtkWidget *parent = gtk_widget_get_toplevel(GTK_WIDGET(cb));
313     cb->priv->dialog = hildon_color_selector_new(GTK_WINDOW(parent));
314     cs_dialog = HILDON_COLOR_SELECTOR(cb->priv->dialog);
315     
316     if (parent)
317       gtk_window_set_transient_for(GTK_WINDOW(cs_dialog), GTK_WINDOW(parent));
318   }
319   
320   /* Set the initial color for the color selector dialog */
321   hildon_color_selector_set_color(cs_dialog, &cb->priv->color);
322   
323   /* Update the color for color button if selection was made */
324   if (gtk_dialog_run(GTK_DIALOG(cs_dialog)) == GTK_RESPONSE_OK)
325   {
326     cb->priv->color = *hildon_color_selector_get_color(cs_dialog);
327     hildon_color_button_set_color( HILDON_COLOR_BUTTON( button ), 
328             &(cb->priv->color) );
329   }
330   gtk_widget_hide(GTK_WIDGET(cs_dialog));
331 }
332
333 /* Set_property function for HildonColorButtonClass initialization */
334 static void
335 hildon_color_button_set_property(GObject *object, guint param_id,
336                                  const GValue *value, GParamSpec *pspec)
337 {
338   HildonColorButton *cb = HILDON_COLOR_BUTTON(object);
339
340   switch (param_id) 
341     {
342     case PROP_COLOR:
343       cb->priv->color = *(GdkColor*)g_value_get_boxed(value);
344       gtk_widget_queue_draw(GTK_WIDGET(cb));
345       break;
346     default:
347       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
348       break;
349     }
350 }
351
352 /* Get_property function for HildonColorButtonClass initialization */
353 static void
354 hildon_color_button_get_property(GObject *object, guint param_id,
355                                  GValue *value, GParamSpec *pspec)
356 {
357   HildonColorButton *cb = HILDON_COLOR_BUTTON(object);
358
359   switch (param_id) 
360     {
361     case PROP_COLOR:
362       g_value_set_boxed(value, &cb->priv->color);
363       break;
364     default:
365       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
366       break;
367     }
368 }
369
370 /**
371  * hildon_color_button_new:
372  *
373  * Creates a new color button. This returns a widget in the form of
374  * a small button containing a swatch representing the current selected 
375  * color. When the button is clicked, a color-selection dialog will open, 
376  * allowing the user to select a color. The swatch will be updated to reflect 
377  * the new color when the user finishes.
378  *
379  * Return value: a new color button.
380  */
381 GtkWidget *
382 hildon_color_button_new(void)
383 {
384   return g_object_new( HILDON_TYPE_COLOR_BUTTON, NULL );
385 }
386
387 /**
388  * hildon_color_button_new_with_color:
389  * @color: A #GdkColor to set the current color with.
390  *
391  * Creates a new color button. 
392  *
393  * Return value: a new color button.
394  */
395 GtkWidget *
396 hildon_color_button_new_with_color(const GdkColor *color)
397 {
398   return g_object_new( HILDON_TYPE_COLOR_BUTTON, "color", color, NULL );
399 }
400
401 /**
402  * hildon_color_button_set_color:
403  * @button: A #HildonColorButton
404  * @color: A color to be set
405  *
406  * Sets a color to the button.
407  */
408 void
409 hildon_color_button_set_color( HildonColorButton *button, GdkColor *color )
410 {
411   g_object_set( G_OBJECT(button), "color", color, NULL );
412 }
413
414 /**
415  * hildon_color_button_get_color:
416  * @button: A #HildonColorButton
417  *
418  * Gets a color from the button.
419  *
420  * Return value: The color set to a current button.
421  */
422 GdkColor *
423 hildon_color_button_get_color( HildonColorButton *button )
424 {
425   GdkColor *color = NULL;
426   g_object_get( G_OBJECT(button), "color", &color, NULL );
427   return color;
428 }