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
11 * the License, or (at your option) any later version.
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 );
48 #undef HILDON_DISABLE_DEPRECATED
54 #include <gdk/gdkkeysyms.h>
56 #include "hildon-color-button.h"
57 #include "hildon-defines.h"
58 #include "hildon-color-chooser-dialog.h"
59 #include "hildon-color-button-private.h"
61 #define COLOR_FILLED_HEIGHT 22
63 #define COLOR_FILLED_WIDTH 22
65 #define COLOR_BUTTON_WIDTH 52
67 #define COLOR_BUTTON_HEIGHT 48
69 #define OUTER_BORDER_RED 0
71 #define OUTER_BORDER_BLUE 0
73 #define OUTER_BORDER_GREEN 0
75 #define OUTER_BORDER_THICKNESS 1
77 #define INNER_BORDER_RED 65535
79 #define INNER_BORDER_BLUE 65535
81 #define INNER_BORDER_GREEN 65535
83 #define INNER_BORDER_THICKNESS 2
99 hildon_color_button_class_init (HildonColorButtonClass *klass);
102 hildon_color_button_init (HildonColorButton *color_button);
105 hildon_color_button_finalize (GObject *object);
108 hildon_color_button_set_property (GObject *object,
114 hildon_color_button_get_property (GObject *object,
120 hildon_color_button_realize (GtkWidget *widget);
123 hildon_color_button_unrealize (GtkWidget *widget);
126 hildon_color_button_clicked (GtkButton *button);
129 hildon_color_button_key_pressed (GtkWidget *button,
134 hildon_color_field_expose_event (GtkWidget *widget,
135 GdkEventExpose *event,
136 HildonColorButton *cb);
139 hildon_color_button_mnemonic_activate (GtkWidget *widget,
140 gboolean group_cycling);
143 draw_grid (GdkDrawable *drawable,
150 static gpointer parent_class = NULL;
151 static guint signals [LAST_SIGNAL] = { 0, };
154 * hildon_color_button_get_type:
156 * Initializes and returns the type of a hildon color button.
158 * @Returns: GType of #HildonColorButton.
161 hildon_color_button_get_type (void)
163 static GType color_button_type = 0;
165 if (! color_button_type)
167 static const GTypeInfo color_button_info =
169 sizeof (HildonColorButtonClass),
170 NULL, /* base_init */
171 NULL, /* base_finalize */
172 (GClassInitFunc) hildon_color_button_class_init,
173 NULL, /* class_finalize */
174 NULL, /* class_data */
175 sizeof (HildonColorButton),
177 (GInstanceInitFunc) hildon_color_button_init,
180 color_button_type = g_type_register_static (GTK_TYPE_BUTTON, "HildonColorButton",
181 &color_button_info, 0);
184 return color_button_type;
188 hildon_color_button_class_init (HildonColorButtonClass *klass)
190 GObjectClass *gobject_class;
191 GtkButtonClass *button_class;
192 GtkWidgetClass *widget_class;
194 gobject_class = G_OBJECT_CLASS (klass);
195 button_class = GTK_BUTTON_CLASS (klass);
196 widget_class = GTK_WIDGET_CLASS (klass);
198 parent_class = g_type_class_peek_parent (klass);
200 gobject_class->get_property = hildon_color_button_get_property;
201 gobject_class->set_property = hildon_color_button_set_property;
202 gobject_class->finalize = hildon_color_button_finalize;
203 widget_class->realize = hildon_color_button_realize;
204 widget_class->unrealize = hildon_color_button_unrealize;
205 button_class->clicked = hildon_color_button_clicked;
206 widget_class->mnemonic_activate = hildon_color_button_mnemonic_activate;
208 signals[SETUP_DIALOG] =
209 g_signal_new ("setup-dialog",
210 G_TYPE_FROM_CLASS (klass),
214 g_cclosure_marshal_VOID__OBJECT,
216 HILDON_TYPE_COLOR_CHOOSER_DIALOG);
219 * HildonColorButton:color:
221 * The currently selected color.
223 g_object_class_install_property (gobject_class, PROP_COLOR,
224 g_param_spec_boxed ("color",
226 "The selected color",
231 * HildonColorButton:popup-shown:
233 * If the color selection dialog is currently popped-up (visible)
235 g_object_class_install_property (gobject_class, PROP_POPUP_SHOWN,
236 g_param_spec_boolean ("popup-shown",
238 "If the color selection dialog is popped up",
242 g_type_class_add_private (gobject_class, sizeof (HildonColorButtonPrivate));
245 /* FIXME Draw a dotted grid over the specified area to make it look
246 * insensitive. Actually, we should generate that pixbuf once and
247 * just render it over later... */
249 draw_grid (GdkDrawable *drawable,
258 for (currenty = y; currenty <= h; currenty++)
259 for (currentx = ((currenty % 2 == 0) ? x : x + 1); currentx <= w; currentx += 2)
260 gdk_draw_point (drawable, gc, currentx, currenty);
263 /* Handle exposure events for the color picker's drawing area */
265 hildon_color_field_expose_event (GtkWidget *widget,
266 GdkEventExpose *event,
267 HildonColorButton *cb)
269 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
270 GdkColor outer_border, inner_border;
274 /* Create the outer border color */
275 outer_border.pixel = 0;
276 outer_border.red = OUTER_BORDER_RED;
277 outer_border.blue = OUTER_BORDER_BLUE;
278 outer_border.green = OUTER_BORDER_GREEN;
280 /* Create the inner border color */
281 inner_border.pixel = 0;
282 inner_border.red = INNER_BORDER_RED;
283 inner_border.blue = INNER_BORDER_BLUE;
284 inner_border.green = INNER_BORDER_GREEN;
286 /* serve the outer border color to the Graphic Context */
287 gdk_gc_set_rgb_fg_color (priv->gc, &outer_border);
288 /* draw the outer border as a filled rectangle */
289 gdk_draw_rectangle (widget->window,
290 (GTK_WIDGET_IS_SENSITIVE (widget)) ? priv->gc : widget->style->bg_gc [GTK_STATE_INSENSITIVE],
294 widget->allocation.width,
295 widget->allocation.height);
297 /* serve the inner border color to the Graphic Context */
298 gdk_gc_set_rgb_fg_color (priv->gc, &inner_border);
300 /* draw the inner border as a filled rectangle */
301 gdk_draw_rectangle (widget->window,
304 OUTER_BORDER_THICKNESS,
305 OUTER_BORDER_THICKNESS,
306 widget->allocation.width - (OUTER_BORDER_THICKNESS * 2),
307 widget->allocation.height - (OUTER_BORDER_THICKNESS * 2));
309 /* serve the actual color to the Graphic Context */
310 gdk_gc_set_rgb_fg_color(priv->gc, &priv->color);
312 /* draw the actual rectangle */
313 gdk_draw_rectangle(widget->window,
316 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
317 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
318 widget->allocation.width - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2),
319 widget->allocation.height - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2));
321 if (! GTK_WIDGET_IS_SENSITIVE (widget)) {
322 draw_grid (GDK_DRAWABLE (widget->window), widget->style->bg_gc [GTK_STATE_INSENSITIVE],
323 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
324 INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS,
325 widget->allocation.width - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2) + 2,
326 widget->allocation.height - ((INNER_BORDER_THICKNESS + OUTER_BORDER_THICKNESS)*2) + 2);
333 hildon_color_button_init (HildonColorButton *cb)
336 GtkWidget *drawing_area;
337 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
341 priv->popped = FALSE;
343 gtk_widget_push_composite_child ();
345 /* create widgets and pixbuf */
346 align = gtk_alignment_new (0.5, 0.5, 0, 0); /* composite widget */
348 drawing_area = gtk_drawing_area_new (); /* composite widget */
350 /* setting minimum sizes */
351 gtk_widget_set_size_request (GTK_WIDGET (cb), COLOR_BUTTON_WIDTH,
352 COLOR_BUTTON_HEIGHT);
354 gtk_widget_set_size_request (GTK_WIDGET(drawing_area),
355 COLOR_FILLED_WIDTH, COLOR_FILLED_HEIGHT);
357 /* Connect the callback function for exposure event */
358 g_signal_connect (drawing_area, "expose-event",
359 G_CALLBACK (hildon_color_field_expose_event), cb);
361 /* Connect to callback function for key press event */
362 g_signal_connect (G_OBJECT(cb), "key-press-event",
363 G_CALLBACK(hildon_color_button_key_pressed), cb);
366 gtk_container_add (GTK_CONTAINER (align), drawing_area);
367 gtk_container_add (GTK_CONTAINER (cb), align);
369 gtk_widget_show_all (align);
371 gtk_widget_pop_composite_child ();
374 /* Free memory used by HildonColorButton */
376 hildon_color_button_finalize (GObject *object)
378 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (object);
383 gtk_widget_destroy (priv->dialog);
387 if (G_OBJECT_CLASS (parent_class)->finalize)
388 G_OBJECT_CLASS (parent_class)->finalize (object);
392 hildon_color_button_realize (GtkWidget *widget)
394 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (widget);
397 GTK_WIDGET_CLASS (parent_class)->realize (widget);
399 priv->gc = gdk_gc_new (widget->window);
403 hildon_color_button_unrealize (GtkWidget *widget)
405 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (widget);
408 if (priv->gc != NULL) {
409 g_object_unref (priv->gc);
413 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
416 /* Make the widget sensitive with the keyboard event */
418 hildon_color_button_mnemonic_activate (GtkWidget *widget,
419 gboolean group_cycling)
421 gtk_widget_grab_focus (widget);
425 /* Popup a color selector dialog on button click */
427 hildon_color_button_clicked (GtkButton *button)
429 HildonColorButton *cb = HILDON_COLOR_BUTTON (button);
430 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
431 HildonColorChooserDialog *cs_dialog;
435 cs_dialog = (HildonColorChooserDialog *) priv->dialog;
437 /* Popup the color selector dialog */
440 /* The dialog hasn't been created yet, do it */
441 GtkWidget *parent = gtk_widget_get_toplevel (GTK_WIDGET(cb));
442 priv->dialog = hildon_color_chooser_dialog_new ();
443 cs_dialog = HILDON_COLOR_CHOOSER_DIALOG (priv->dialog);
445 gtk_window_set_transient_for (GTK_WINDOW (cs_dialog), GTK_WINDOW (parent));
447 g_signal_emit (button, signals[SETUP_DIALOG], 0, priv->dialog);
450 /* Set the initial color for the color selector dialog */
451 hildon_color_chooser_dialog_set_color (cs_dialog, &priv->color);
453 /* Update the color for color button if selection was made */
455 if (gtk_dialog_run (GTK_DIALOG (cs_dialog)) == GTK_RESPONSE_OK)
457 hildon_color_chooser_dialog_get_color (cs_dialog, &priv->color);
458 hildon_color_button_set_color (HILDON_COLOR_BUTTON (button), &priv->color);
459 // FIXME A queue-draw should be enough here (not set needed)
462 gtk_widget_hide (GTK_WIDGET(cs_dialog));
463 priv->popped = FALSE;
466 /* Popup a color selector dialog on hardkey Select press.
467 * FIXME This is a bit hacky, should work without thi. Check. */
469 hildon_color_button_key_pressed (GtkWidget *button,
473 g_return_val_if_fail (HILDON_IS_COLOR_BUTTON (button), FALSE);
475 if (event->keyval == HILDON_HARDKEY_SELECT)
477 hildon_color_button_clicked (GTK_BUTTON (button));
485 hildon_color_button_set_property (GObject *object,
490 HildonColorButton *cb = HILDON_COLOR_BUTTON (object);
491 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
498 priv->color = *(GdkColor *) g_value_get_boxed (value);
499 gtk_widget_queue_draw (GTK_WIDGET (cb));
503 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
509 hildon_color_button_get_property (GObject *object,
514 HildonColorButton *cb = HILDON_COLOR_BUTTON (object);
515 HildonColorButtonPrivate *priv = HILDON_COLOR_BUTTON_GET_PRIVATE (cb);
522 g_value_set_boxed (value, &priv->color);
525 case PROP_POPUP_SHOWN:
526 g_value_set_boolean (value, priv->popped);
529 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
535 * hildon_color_button_new:
537 * Creates a new color button. This returns a widget in the form of a
538 * small button containing a swatch representing the selected color.
539 * When the button is clicked, a color-selection dialog will open,
540 * allowing the user to select a color. The swatch will be updated to
541 * reflect the new color when the user finishes.
543 * Returns: a new color button
546 hildon_color_button_new (void)
548 return g_object_new (HILDON_TYPE_COLOR_BUTTON, NULL);
552 * hildon_color_button_new_with_color:
553 * @color: a #GdkColor for the initial color
555 * Creates a new color button with @color as the initial color.
557 * Returns: a new color button
560 hildon_color_button_new_with_color (const GdkColor *color)
562 return g_object_new (HILDON_TYPE_COLOR_BUTTON, "color", color, NULL);
566 * hildon_color_button_set_color:
567 * @button: a #HildonColorButton
568 * @color: a color to be set
570 * Sets the color selected by the button.
573 hildon_color_button_set_color (HildonColorButton *button,
576 g_return_if_fail (HILDON_IS_COLOR_BUTTON (button));
578 g_object_set (G_OBJECT (button), "color", color, NULL);
582 * hildon_color_button_get_popup_shown
583 * @button: a #HildonColorButton
585 * This function checks if the color button has the color
586 * selection dialog currently popped-up.
588 * Returns: TRUE if the dialog is popped-up (visible to user).
592 hildon_color_button_get_popup_shown (HildonColorButton *button)
594 HildonColorButtonPrivate *priv = NULL;
595 g_return_val_if_fail (HILDON_IS_COLOR_BUTTON (button), FALSE);
597 priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
604 * hildon_color_button_popdown
605 * @button: a #HildonColorButton
607 * If the color selection dialog is currently popped-up (visible)
608 * it will be popped-down (hidden).
612 hildon_color_button_popdown (HildonColorButton *button)
614 HildonColorButtonPrivate *priv = NULL;
615 g_return_if_fail (HILDON_IS_COLOR_BUTTON (button));
617 priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
620 if (priv->popped && priv->dialog) {
621 gtk_dialog_response (GTK_DIALOG (priv->dialog), GTK_RESPONSE_CANCEL);
626 * hildon_color_button_get_color:
627 * @button: a #HildonColorButton
628 * @color: a color #GdkColor to be fillled with the current color
632 hildon_color_button_get_color (HildonColorButton *button,
635 HildonColorButtonPrivate *priv = NULL;
636 g_return_if_fail (HILDON_IS_COLOR_BUTTON (button));
637 g_return_if_fail (color != NULL);
639 priv = HILDON_COLOR_BUTTON_GET_PRIVATE (button);
642 color->red = priv->color.red;
643 color->green = priv->color.green;
644 color->blue = priv->color.blue;
645 color->pixel = priv->color.pixel;