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