2 * This file is a part of hildon
4 * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
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; version 2.1 of
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.
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
26 * SECTION:hildon-color-button
27 * @short_description: A widget to open HildonColorChooserDialog.
28 * @see_also: #HildonColorChooserDialog, #HildonColorPopup
30 * HildonColorButton is a widget to open a HildonColorChooserDialog.
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.
36 * <title>HildonColorButton example</title>
38 * HildonColorButton *cbutton;
41 * cbutton = hildon_color_button_new();
42 * gtk_object_get( GTK_OBJECT(cbutton), "color", color );
52 #include "hildon-color-button.h"
53 #include <gtk/gtkbutton.h>
54 #include <gtk/gtkalignment.h>
55 #include <gtk/gtkdrawingarea.h>
56 #include <gtk/gtksignal.h>
57 #include <gdk/gdkkeysyms.h>
58 #include "hildon-defines.h"
59 #include "hildon-color-chooser-dialog.h"
60 #include "hildon-color-button-private.h"
62 #define COLOR_FILLED_HEIGHT 22
64 #define COLOR_FILLED_WIDTH 22
66 #define COLOR_BUTTON_WIDTH 52
68 #define COLOR_BUTTON_HEIGHT 48
70 #define OUTER_BORDER_RED 0
72 #define OUTER_BORDER_BLUE 0
74 #define OUTER_BORDER_GREEN 0
76 #define OUTER_BORDER_THICKNESS 1
78 #define INNER_BORDER_RED 65535
80 #define INNER_BORDER_BLUE 65535
82 #define INNER_BORDER_GREEN 65535
84 #define INNER_BORDER_THICKNESS 2
94 hildon_color_button_class_init (HildonColorButtonClass *klass);
97 hildon_color_button_init (HildonColorButton *color_button);
100 hildon_color_button_finalize (GObject *object);
103 hildon_color_button_set_property (GObject *object,
109 hildon_color_button_get_property (GObject *object,
115 hildon_color_button_realize (GtkWidget *widget);
118 hildon_color_button_unrealize (GtkWidget *widget);
121 hildon_color_button_clicked (GtkButton *button);
124 hildon_color_button_key_pressed (GtkWidget *button,
129 hildon_color_field_expose_event (GtkWidget *widget,
130 GdkEventExpose *event,
131 HildonColorButton *cb);
134 hildon_color_button_mnemonic_activate (GtkWidget *widget,
135 gboolean group_cycling);
138 draw_grid (GdkDrawable *drawable,
145 static gpointer parent_class = NULL;
148 * hildon_color_button_get_type:
150 * Initializes and returns the type of a hildon color button.
152 * @Returns: GType of #HildonColorButton.
155 hildon_color_button_get_type (void)
157 static GType color_button_type = 0;
159 if (! color_button_type)
161 static const GTypeInfo color_button_info =
163 sizeof (HildonColorButtonClass),
164 NULL, /* base_init */
165 NULL, /* base_finalize */
166 (GClassInitFunc) hildon_color_button_class_init,
167 NULL, /* class_finalize */
168 NULL, /* class_data */
169 sizeof (HildonColorButton),
171 (GInstanceInitFunc) hildon_color_button_init,
174 color_button_type = g_type_register_static (GTK_TYPE_BUTTON, "HildonColorButton",
175 &color_button_info, 0);
178 return color_button_type;
182 hildon_color_button_class_init (HildonColorButtonClass *klass)
184 GObjectClass *gobject_class;
185 GtkButtonClass *button_class;
186 GtkWidgetClass *widget_class;
188 gobject_class = G_OBJECT_CLASS (klass);
189 button_class = GTK_BUTTON_CLASS (klass);
190 widget_class = GTK_WIDGET_CLASS (klass);
192 parent_class = g_type_class_peek_parent (klass);
194 gobject_class->get_property = hildon_color_button_get_property;
195 gobject_class->set_property = hildon_color_button_set_property;
196 gobject_class->finalize = hildon_color_button_finalize;
197 widget_class->realize = hildon_color_button_realize;
198 widget_class->unrealize = hildon_color_button_unrealize;
199 button_class->clicked = hildon_color_button_clicked;
200 widget_class->mnemonic_activate = hildon_color_button_mnemonic_activate;
203 * HildonColorButton:color:
205 * The currently selected color.
207 g_object_class_install_property (gobject_class, PROP_COLOR,
208 g_param_spec_boxed ("color",
210 "The selected color",
215 * HildonColorButton:popup-shown:
217 * If the color selection dialog is currently popped-up (visible)
219 g_object_class_install_property (gobject_class, PROP_POPUP_SHOWN,
220 g_param_spec_boolean ("popup-shown",
222 "If the color selection dialog is popped up",
226 g_type_class_add_private (gobject_class, sizeof (HildonColorButtonPrivate));
229 /* FIXME Draw a dotted grid over the specified area to make it look
230 * insensitive. Actually, we should generate that pixbuf once and
231 * just render it over later... */
233 draw_grid (GdkDrawable *drawable,
242 for (currenty = y; currenty <= h; currenty++)
243 for (currentx = ((currenty % 2 == 0) ? x : x + 1); currentx <= w; currentx += 2)
244 gdk_draw_point (drawable, gc, currentx, currenty);
247 /* Handle exposure events for the color picker's drawing area */
249 hildon_color_field_expose_event (GtkWidget *widget,
250 GdkEventExpose *event,
251 HildonColorButton *cb)
253 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
254 GdkColor outer_border, inner_border;
258 /* Create the outer border color */
259 outer_border.pixel = 0;
260 outer_border.red = OUTER_BORDER_RED;
261 outer_border.blue = OUTER_BORDER_BLUE;
262 outer_border.green = OUTER_BORDER_GREEN;
264 /* Create the inner border color */
265 inner_border.pixel = 0;
266 inner_border.red = INNER_BORDER_RED;
267 inner_border.blue = INNER_BORDER_BLUE;
268 inner_border.green = INNER_BORDER_GREEN;
270 /* serve the outer border color to the Graphic Context */
271 gdk_gc_set_rgb_fg_color (priv->gc, &outer_border);
272 /* draw the outer border as a filled rectangle */
273 gdk_draw_rectangle (widget->window,
274 (GTK_WIDGET_IS_SENSITIVE (widget)) ? priv->gc : widget->style->bg_gc [GTK_STATE_INSENSITIVE],
278 widget->allocation.width,
279 widget->allocation.height);
281 /* serve the inner border color to the Graphic Context */
282 gdk_gc_set_rgb_fg_color (priv->gc, &inner_border);
284 /* draw the inner border as a filled rectangle */
285 gdk_draw_rectangle (widget->window,
288 OUTER_BORDER_THICKNESS,
289 OUTER_BORDER_THICKNESS,
290 widget->allocation.width - (OUTER_BORDER_THICKNESS * 2),
291 widget->allocation.height - (OUTER_BORDER_THICKNESS * 2));
293 /* serve the actual color to the Graphic Context */
294 gdk_gc_set_rgb_fg_color(priv->gc, &priv->color);
296 /* draw the actual rectangle */
297 gdk_draw_rectangle(widget->window,
300 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
301 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
302 widget->allocation.width - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2),
303 widget->allocation.height - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2));
305 if (! GTK_WIDGET_IS_SENSITIVE (widget)) {
306 draw_grid (GDK_DRAWABLE (widget->window), widget->style->bg_gc [GTK_STATE_INSENSITIVE],
307 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
308 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
309 widget->allocation.width - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2) + 2,
310 widget->allocation.height - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2) + 2);
317 hildon_color_button_init (HildonColorButton *cb)
320 GtkWidget *drawing_area;
321 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
325 priv->popped = FALSE;
327 gtk_widget_push_composite_child ();
329 /* create widgets and pixbuf */
330 align = gtk_alignment_new (0.5, 0.5, 0, 0); /* composite widget */
332 drawing_area = gtk_drawing_area_new (); /* composite widget */
334 /* setting minimum sizes */
335 gtk_widget_set_size_request (GTK_WIDGET (cb), COLOR_BUTTON_WIDTH,
336 COLOR_BUTTON_HEIGHT);
338 gtk_widget_set_size_request (GTK_WIDGET(drawing_area),
339 COLOR_FILLED_WIDTH, COLOR_FILLED_HEIGHT);
341 /* Connect the callback function for exposure event */
342 g_signal_connect (drawing_area, "expose-event",
343 G_CALLBACK (hildon_color_field_expose_event), cb);
345 /* Connect to callback function for key press event */
346 g_signal_connect (G_OBJECT(cb), "key-press-event",
347 G_CALLBACK(hildon_color_button_key_pressed), cb);
350 gtk_container_add (GTK_CONTAINER (align), drawing_area);
351 gtk_container_add (GTK_CONTAINER (cb), align);
353 gtk_widget_show_all (align);
355 gtk_widget_pop_composite_child ();
358 /* Free memory used by HildonColorButton */
360 hildon_color_button_finalize (GObject *object)
362 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (object);
367 gtk_widget_destroy (priv->dialog);
371 if (G_OBJECT_CLASS (parent_class)->finalize)
372 G_OBJECT_CLASS (parent_class)->finalize (object);
376 hildon_color_button_realize (GtkWidget *widget)
378 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (widget);
381 GTK_WIDGET_CLASS (parent_class)->realize (widget);
383 priv->gc = gdk_gc_new (widget->window);
387 hildon_color_button_unrealize (GtkWidget *widget)
389 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (widget);
392 if (priv->gc != NULL) {
393 g_object_unref (priv->gc);
397 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
400 /* Make the widget sensitive with the keyboard event */
402 hildon_color_button_mnemonic_activate (GtkWidget *widget,
403 gboolean group_cycling)
405 gtk_widget_grab_focus (widget);
409 /* Popup a color selector dialog on button click */
411 hildon_color_button_clicked (GtkButton *button)
413 HildonColorButton *cb = HILDON_COLOR_BUTTON (button);
414 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
415 HildonColorChooserDialog *cs_dialog;
419 cs_dialog = (HildonColorChooserDialog *) priv->dialog;
421 /* Popup the color selector dialog */
424 /* The dialog hasn't been created yet, do it */
425 GtkWidget *parent = gtk_widget_get_toplevel (GTK_WIDGET(cb));
426 priv->dialog = hildon_color_chooser_dialog_new ();
427 cs_dialog = HILDON_COLOR_CHOOSER_DIALOG (priv->dialog);
429 gtk_window_set_transient_for (GTK_WINDOW (cs_dialog), GTK_WINDOW (parent));
432 /* Set the initial color for the color selector dialog */
433 hildon_color_chooser_dialog_set_color (cs_dialog, &priv->color);
435 /* Update the color for color button if selection was made */
437 if (gtk_dialog_run (GTK_DIALOG (cs_dialog)) == GTK_RESPONSE_OK)
439 hildon_color_chooser_dialog_get_color (cs_dialog, &priv->color);
440 hildon_color_button_set_color (HILDON_COLOR_BUTTON (button), &priv->color);
441 // FIXME A queue-draw should be enough here (not set needed)
444 gtk_widget_hide (GTK_WIDGET(cs_dialog));
445 priv->popped = FALSE;
448 /* Popup a color selector dialog on hardkey Select press.
449 * FIXME This is a bit hacky, should work without thi. Check. */
451 hildon_color_button_key_pressed (GtkWidget *button,
455 g_return_val_if_fail (HILDON_IS_COLOR_BUTTON (button), FALSE);
457 if (event->keyval == HILDON_HARDKEY_SELECT)
459 hildon_color_button_clicked (GTK_BUTTON (button));
467 hildon_color_button_set_property (GObject *object,
472 HildonColorButton *cb = HILDON_COLOR_BUTTON (object);
473 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
480 priv->color = *(GdkColor *) g_value_get_boxed (value);
481 gtk_widget_queue_draw (GTK_WIDGET (cb));
485 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
491 hildon_color_button_get_property (GObject *object,
496 HildonColorButton *cb = HILDON_COLOR_BUTTON (object);
497 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
504 g_value_set_boxed (value, &priv->color);
507 case PROP_POPUP_SHOWN:
508 g_value_set_boolean (value, priv->popped);
511 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
517 * hildon_color_button_new:
519 * Creates a new color button. This returns a widget in the form of a
520 * small button containing a swatch representing the selected color.
521 * When the button is clicked, a color-selection dialog will open,
522 * allowing the user to select a color. The swatch will be updated to
523 * reflect the new color when the user finishes.
525 * Returns: a new color button
528 hildon_color_button_new (void)
530 return g_object_new (HILDON_TYPE_COLOR_BUTTON, NULL);
534 * hildon_color_button_new_with_color:
535 * @color: a #GdkColor for the initial color
537 * Creates a new color button with @color as the initial color.
539 * Returns: a new color button
542 hildon_color_button_new_with_color (const GdkColor *color)
544 return g_object_new (HILDON_TYPE_COLOR_BUTTON, "color", color, NULL);
548 * hildon_color_button_set_color:
549 * @button: a #HildonColorButton
550 * @color: a color to be set
552 * Sets the color selected by the button.
555 hildon_color_button_set_color (HildonColorButton *button,
558 g_return_if_fail (HILDON_IS_COLOR_BUTTON (button));
560 g_object_set (G_OBJECT (button), "color", color, NULL);
564 * hildon_color_button_get_popup_shown
565 * @button: a #HildonColorButton
567 * This function checks if the color button has the color
568 * selection dialog currently popped-up.
570 * Returns: TRUE if the dialog is popped-up (visible to user).
574 hildon_color_button_get_popup_shown (HildonColorButton *button)
576 HildonColorButtonPrivate *priv = NULL;
577 g_return_val_if_fail (HILDON_IS_COLOR_BUTTON (button), FALSE);
579 priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
586 * hildon_color_button_popdown
587 * @button: a #HildonColorButton
589 * If the color selection dialog is currently popped-up (visible)
590 * it will be popped-down (hidden).
594 hildon_color_button_popdown (HildonColorButton *button)
596 HildonColorButtonPrivate *priv = NULL;
597 g_return_if_fail (HILDON_IS_COLOR_BUTTON (button));
599 priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
602 if (priv->popped && priv->dialog) {
603 gtk_dialog_response (GTK_DIALOG (priv->dialog), GTK_RESPONSE_CANCEL);
608 * hildon_color_button_get_color:
609 * @button: a #HildonColorButton
610 * @color: a color #GdkColor to be fillled with the current color
614 hildon_color_button_get_color (HildonColorButton *button,
617 HildonColorButtonPrivate *priv = NULL;
618 g_return_if_fail (HILDON_IS_COLOR_BUTTON (button));
619 g_return_if_fail (color != NULL);
621 priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
624 color->red = priv->color.red;
625 color->green = priv->color.green;
626 color->blue = priv->color.blue;
627 color->pixel = priv->color.pixel;