2006-08-30 Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
[hildon] / hildon-widgets / hildon-color-chooser-button.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation.
5  *
6  * Author: Kuisma Salonen <kuisma.salonen@nokia.com>
7  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; version 2.1 of
12  * the License.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  *
24  */
25
26
27 #include <gtk/gtk.h>
28
29
30 #include "hildon-color-chooser-button.h"
31
32 #include "hildon-color-chooser-dialog.h"
33
34
35 enum {
36   COLOR_CHANGED,
37   LAST_SIGNAL
38 };
39
40
41 static guint color_chooser_button_signals[LAST_SIGNAL] = { 0 };
42
43
44 static GtkButtonClass *parent_klass = NULL;
45
46
47 static void hildon_color_chooser_button_init(HildonColorChooserButton *object);
48 static void hildon_color_chooser_button_class_init(HildonColorChooserButtonClass *klass);
49
50
51 static void hildon_color_chooser_button_size_request(GtkWidget *widget, GtkRequisition *req);
52 static void hildon_color_chooser_button_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
53
54 static void hildon_color_chooser_button_realize(GtkWidget *widget);
55 static void hildon_color_chooser_button_unrealize(GtkWidget *widget);
56
57 static void hildon_color_chooser_button_style_set(GtkWidget *widget, GtkStyle *previous_style);
58
59 static void hildon_color_chooser_button_show(GtkWidget *widget);
60 static void hildon_color_chooser_button_show_all(GtkWidget *widget);
61
62 static void hildon_color_chooser_button_virtual_set_color(HildonColorChooserButton *button, GdkColor *color);
63 static void hildon_color_chooser_button_virtual_color_changed(HildonColorChooserButton *button, GdkColor *color);
64
65 static void hildon_color_chooser_button_clicked(GtkButton *button);
66
67
68 static gboolean hildon_color_chooser_button_area_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data);
69
70
71 static void hildon_color_chooser_button_helper_get_style_info(HildonColorChooserButton *button);
72
73
74 GtkType hildon_color_chooser_button_get_type ()
75 {
76   static GtkType button_type = 0;
77
78   if (!button_type)
79     {
80       static const GtkTypeInfo button_info =
81       {
82         "HildonColorChooserButton",
83         sizeof (HildonColorChooserButton),
84         sizeof (HildonColorChooserButtonClass),
85         (GtkClassInitFunc) hildon_color_chooser_button_class_init,
86         (GtkObjectInitFunc) hildon_color_chooser_button_init,
87         /* reserved_1 */ NULL,
88         /* reserved_1 */ NULL,
89         (GtkClassInitFunc) NULL
90       };
91
92       button_type = gtk_type_unique (GTK_TYPE_BUTTON, &button_info);
93     }
94
95   return button_type;
96 }
97
98
99   /* initializer functions */
100 static void hildon_color_chooser_button_init(HildonColorChooserButton *object)
101 {
102   object->color.red =   0x0000;
103   object->color.green = 0x0000;
104   object->color.blue =  0x0000;
105   object->color.pixel = 0x00000000;
106
107
108   object->area = gtk_drawing_area_new();
109
110   gtk_container_add(GTK_CONTAINER(object), object->area);
111
112
113   g_signal_connect(G_OBJECT(object->area), "expose-event",
114                    G_CALLBACK(hildon_color_chooser_button_area_expose), object);
115 }
116
117 static void hildon_color_chooser_button_class_init(HildonColorChooserButtonClass *klass)
118 {
119   GtkWidgetClass *widget_klass = GTK_WIDGET_CLASS(klass);
120   GtkButtonClass *button_klass = GTK_BUTTON_CLASS(klass);
121   GtkObjectClass *object_klass = GTK_OBJECT_CLASS(klass);
122
123
124   parent_klass = g_type_class_peek_parent(klass);
125
126
127   klass->set_color = hildon_color_chooser_button_virtual_set_color;
128   klass->color_changed = hildon_color_chooser_button_virtual_color_changed;
129
130
131   button_klass->clicked = hildon_color_chooser_button_clicked;
132
133
134   widget_klass->size_request = hildon_color_chooser_button_size_request;
135   widget_klass->size_allocate = hildon_color_chooser_button_size_allocate;
136
137   widget_klass->realize = hildon_color_chooser_button_realize;
138   widget_klass->unrealize = hildon_color_chooser_button_unrealize;
139
140   widget_klass->style_set = hildon_color_chooser_button_style_set;
141
142   widget_klass->show = hildon_color_chooser_button_show;
143   widget_klass->show_all = hildon_color_chooser_button_show_all;
144
145
146   gtk_widget_class_install_style_property(widget_klass,
147                                           g_param_spec_boxed("outer_border",
148                                                              "Outer border",
149                                                              "Size of the outer border",
150                                                              GTK_TYPE_BORDER,
151                                                              G_PARAM_READABLE));
152   gtk_widget_class_install_style_property(widget_klass,
153                                           g_param_spec_boxed("inner_border",
154                                                              "Inner border",
155                                                              "Size of the inner border",
156                                                              GTK_TYPE_BORDER,
157                                                              G_PARAM_READABLE));
158   gtk_widget_class_install_style_property(widget_klass,
159                                           g_param_spec_boxed("minimum_size",
160                                                              "minimum_size",
161                                                              "Minimum size of the color area",
162                                                              GTK_TYPE_BORDER,
163                                                              G_PARAM_READABLE));
164
165
166   color_chooser_button_signals[COLOR_CHANGED] = g_signal_new("color-changed", G_OBJECT_CLASS_TYPE (object_klass),
167                                                              G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (HildonColorChooserButtonClass, color_changed),
168                                                              NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, GDK_TYPE_COLOR);
169 }
170
171
172   /* virtual widget functions */
173 static void hildon_color_chooser_button_size_request(GtkWidget *widget, GtkRequisition *req)
174 {
175   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(widget);
176
177
178   req->width = button->style_info.outer.left + button->style_info.min.left + button->style_info.outer.right;
179   req->height = button->style_info.outer.top + button->style_info.min.right + button->style_info.outer.bottom;
180 }
181
182 static void hildon_color_chooser_button_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
183 {
184   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(widget);
185   GtkAllocation child_alloc;
186   GdkRectangle clip_rect;
187
188
189   GTK_WIDGET_CLASS(parent_klass)->size_allocate(widget, alloc);
190   child_alloc = *alloc;
191
192
193   child_alloc.x += button->style_info.outer.left;
194   child_alloc.y += button->style_info.outer.top;
195
196   child_alloc.width  -= (button->style_info.outer.left + button->style_info.outer.right);
197   child_alloc.height -= (button->style_info.outer.top + button->style_info.outer.bottom);
198
199
200   gtk_widget_size_allocate(button->area, &child_alloc);
201
202
203   if(GTK_WIDGET_REALIZED(widget)) {
204     clip_rect.x = button->style_info.inner.left;
205     clip_rect.y = button->style_info.inner.top;
206     clip_rect.width = button->area->allocation.width - button->style_info.inner.left - button->style_info.inner.right;
207     clip_rect.height = button->area->allocation.height - button->style_info.inner.top - button->style_info.inner.bottom;
208
209     gdk_gc_set_clip_rectangle(button->color_gc, &clip_rect);
210   }
211 }
212
213
214 static void hildon_color_chooser_button_realize(GtkWidget *widget)
215 {
216   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(widget);
217   GdkRectangle clip_rect;
218
219
220   GTK_WIDGET_CLASS(parent_klass)->realize(widget);
221
222
223   button->color_gc = gdk_gc_new(widget->window);
224   gdk_gc_set_rgb_fg_color(button->color_gc, &button->color);
225
226
227   clip_rect.x = button->style_info.inner.left;
228   clip_rect.y = button->style_info.inner.top;
229   clip_rect.width = button->area->allocation.width - button->style_info.inner.left - button->style_info.inner.right;
230   clip_rect.height = button->area->allocation.height - button->style_info.inner.top - button->style_info.inner.bottom;
231
232   gdk_gc_set_clip_rectangle(button->color_gc, &clip_rect);
233 }
234
235 static void hildon_color_chooser_button_unrealize(GtkWidget *widget)
236 {
237   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(widget);
238
239
240   g_object_unref(button->color_gc);
241   button->color_gc = NULL;
242
243
244   GTK_WIDGET_CLASS(parent_klass)->unrealize(widget);
245 }
246
247
248 static void hildon_color_chooser_button_style_set(GtkWidget *widget, GtkStyle *previous_style)
249 {
250   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(widget);
251   GdkRectangle clip_rect;
252
253
254   hildon_color_chooser_button_helper_get_style_info(button);
255
256
257   if(GTK_WIDGET_REALIZED(widget)) {
258     clip_rect.x = button->style_info.inner.left;
259     clip_rect.y = button->style_info.inner.top;
260     clip_rect.width = button->area->allocation.width - button->style_info.inner.left - button->style_info.inner.right;
261     clip_rect.height = button->area->allocation.height - button->style_info.inner.top - button->style_info.inner.bottom;
262
263     gdk_gc_set_clip_rectangle(button->color_gc, &clip_rect);
264   }
265 }
266
267
268 static void hildon_color_chooser_button_show(GtkWidget *widget)
269 {
270   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(widget);
271
272
273   gtk_widget_show(button->area);
274
275   GTK_WIDGET_CLASS(parent_klass)->show(widget);
276 }
277
278 static void hildon_color_chooser_button_show_all(GtkWidget *widget)
279 {
280   hildon_color_chooser_button_show(widget);
281 }
282
283
284 static void hildon_color_chooser_button_virtual_set_color(HildonColorChooserButton *button, GdkColor *color)
285 {
286   button->color = *color;
287
288   if(GTK_WIDGET_REALIZED(button)) {
289     gdk_gc_set_rgb_fg_color(button->color_gc, &button->color);
290
291     gtk_widget_queue_draw(button->area);
292   }
293
294
295   g_signal_emit(button, color_chooser_button_signals[COLOR_CHANGED], 0, &button->color);
296 }
297
298 static void hildon_color_chooser_button_virtual_color_changed(HildonColorChooserButton *button, GdkColor *color)
299 {
300 }
301
302
303 static void hildon_color_chooser_button_clicked(GtkButton *button)
304 {
305   HildonColorChooserButton *color_button = HILDON_COLOR_CHOOSER_BUTTON(button);
306   GtkWidget *dialog;
307   GdkColor color;
308   gint result = 0;
309
310
311   dialog = hildon_color_chooser_dialog_new();
312   gtk_widget_realize(dialog);
313   hildon_color_chooser_dialog_set_color(HILDON_COLOR_CHOOSER_DIALOG(dialog), &color_button->color);
314   gtk_widget_show(dialog);
315
316
317   result = gtk_dialog_run(GTK_DIALOG(dialog));
318
319
320   if(result == GTK_RESPONSE_OK) {
321     hildon_color_chooser_dialog_get_color(HILDON_COLOR_CHOOSER_DIALOG(dialog), &color);
322     hildon_color_chooser_button_virtual_set_color(color_button, &color);
323   }
324
325
326 /*g_object_unref(G_OBJECT(dialog));*/
327   gtk_widget_destroy(dialog);
328 }
329
330
331   /* signal handlers */
332 static gboolean hildon_color_chooser_button_area_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
333 {
334   HildonColorChooserButton *button = HILDON_COLOR_CHOOSER_BUTTON(data);
335   GtkWidget *button_widget = GTK_WIDGET(data);
336
337
338   if(button->style_info.inner.left > 0 || button->style_info.inner.right > 0 ||
339      button->style_info.inner.top > 0 || button->style_info.inner.bottom > 0) {
340     gtk_paint_box(gtk_widget_get_style(button_widget), widget->window, GTK_WIDGET_STATE(button_widget), GTK_SHADOW_NONE,
341                   &event->area, button_widget, "color-button", 0, 0, widget->allocation.width, widget->allocation.height);
342   }
343
344
345   gdk_draw_rectangle(widget->window, button->color_gc, TRUE, event->area.x, event->area.y, event->area.width, event->area.height);
346
347
348   return FALSE;
349 }
350
351
352   /* additional use-only-here functions */
353 static void hildon_color_chooser_button_helper_get_style_info(HildonColorChooserButton *button)
354 {
355   GtkBorder *in, *out, *min;
356
357   gtk_widget_style_get(GTK_WIDGET(button), "inner_border", &in,
358                                            "outer_border", &out,
359                                            "minimum_size", &min, NULL);
360
361
362   if(in) {
363     button->style_info.inner = *in;
364     g_free(in);
365   } else {
366     button->style_info.inner.left = 0;
367     button->style_info.inner.right = 0;
368     button->style_info.inner.top = 0;
369     button->style_info.inner.bottom = 0;
370   }
371
372   if(out) {
373     button->style_info.outer = *out;
374     g_free(out);
375   } else {
376     button->style_info.outer.left = 4;
377     button->style_info.outer.right = 4;
378     button->style_info.outer.top = 4;
379     button->style_info.outer.bottom = 4;
380   }
381
382   if(min) {
383     button->style_info.min = *min;
384     g_free(min);
385   } else {
386     button->style_info.min.left = 8;
387     button->style_info.min.right = 8;
388     button->style_info.min.top = 0;
389     button->style_info.min.bottom = 0;
390   }
391 }
392
393
394   /* public API */
395 GtkWidget *hildon_color_chooser_button_new()
396 {
397   return gtk_type_new(HILDON_TYPE_COLOR_CHOOSER_BUTTON);
398 }
399
400
401 void hildon_color_chooser_button_set_color(HildonColorChooserButton *button, GdkColor *color)
402 {
403   HILDON_COLOR_CHOOSER_BUTTON_CLASS(G_OBJECT_GET_CLASS(button))->set_color(button, color);
404 }
405
406 void hildon_color_chooser_button_get_color(HildonColorChooserButton *button, GdkColor *color)
407 {
408   *color = button->color;
409 }