2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@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; either 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 * @file hildon-color-selector.c
28 * This file contains the implementation of Hildon Color Selector
29 * widget containing the base color and custom color palette selector
30 * and popup for selecting different colors based on RGB values.
37 #include <gtk/gtktable.h>
38 #include <gtk/gtkhbox.h>
39 #include <gtk/gtklabel.h>
40 #include <gtk/gtkdrawingarea.h>
41 #include <gtk/gtkbutton.h>
42 #include <gdk/gdkkeysyms.h>
43 #include <gconf/gconf-client.h>
45 #include "hildon-color-selector.h"
46 #include "hildon-color-popup.h"
49 #define _(String) dgettext(PACKAGE, String)
52 #define HILDON_BASE_COLOR_NUM 16
53 #define HILDON_CUSTOM_COLOR_NUM 8
54 #define HILDON_TOTAL_COLOR_NUM \
55 (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM)
61 #define HILDON_COLOR_SELECTOR_BOX_W 27
62 #define HILDON_COLOR_SELECTOR_BOX_H 27
63 #define HILDON_COLOR_SELECTOR_BOX_BORDER 2
64 #define HILDON_COLOR_SELECTOR_COLS 8
65 #define HILDON_COLOR_SELECTOR_ROWS 3
66 #define HILDON_COLOR_PALETTE_SIZE 120
67 #define HILDON_COLOR_CONTROLBAR_MAX 31
68 #define HILDON_COLOR_CONTROLBAR_MIN 0
69 #define HILDON_COLOR_LABELS_LEFT_PAD 35
70 #define HILDON_COLOR_PALETTE_POS_PAD 45
71 #define HILDON_COLOR_BAR_WIDTH 449
73 /* gconf definitions */
74 #define HILDON_COLOR_GCONF_PATH "/system/osso/af/color_selector"
75 #define HILDON_COLOR_GCONF_KEYS "/system/osso/af/color_selector/custom_colors"
77 * Pointer parent class
79 static GtkDialogClass *parent_class;
81 struct _HildonColorSelectorPriv
84 GtkWidget *drawing_area;
85 GtkWidget *modify_button;
89 /* one extra place for the modified base color */
90 GdkColor color[HILDON_TOTAL_COLOR_NUM + 1];
94 * Private function prototype definitions
97 hildon_color_selector_class_init (HildonColorSelectorClass * selector_class);
100 hildon_color_selector_init (HildonColorSelector * selector);
103 hildon_color_selector_expose (GtkWidget * widget,
104 GdkEventExpose * event,
108 key_pressed (GtkWidget * widget,
109 GdkEventKey * event);
112 color_pressed (GtkWidget * widget,
113 GdkEventButton * event,
117 select_color (HildonColorSelector * selector,
123 color_moved (GtkWidget * widget,
124 GdkEventMotion * event,
128 modify_button_clicked (GtkWidget * button,
129 HildonColorSelector * selector);
132 modify_selected(HildonColorSelector * colselector);
135 hildon_color_selector_get_type(void)
137 static GType selector_type = 0;
141 static const GTypeInfo selector_info =
143 sizeof(HildonColorSelectorClass),
144 NULL, /* base_init */
145 NULL, /* base_finalize */
146 (GClassInitFunc) hildon_color_selector_class_init,
147 NULL, /* class_finalize */
148 NULL, /* class_data */
149 sizeof(HildonColorSelector),
151 (GInstanceInitFunc) hildon_color_selector_init,
153 selector_type = g_type_register_static(GTK_TYPE_DIALOG,
154 "HildonColorSelector",
157 return selector_type;
161 hildon_color_selector_destroy(GtkObject *obj)
163 HildonColorSelectorPriv *priv = HILDON_COLOR_SELECTOR(obj)->priv;
167 gconf_client_notify_remove(priv->client, priv->notify_id);
168 g_object_unref(priv->client);
172 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
176 hildon_color_selector_class_init(HildonColorSelectorClass * selector_class)
178 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(selector_class);
180 parent_class = g_type_class_peek_parent(selector_class);
182 widget_class->key_press_event = key_pressed;
184 g_type_class_add_private(selector_class,
185 sizeof(HildonColorSelectorPriv));
187 GTK_OBJECT_CLASS(selector_class)->destroy = hildon_color_selector_destroy;
192 * hildon_color_selector_new:
193 * @parent: The parent window. The X window ID of the parent window
194 * has to be the same as the X window ID of the application.
195 * @returns: new #HildonColorSelector.
197 * Creates a new #HildonColorSelector dialog with 3x8 layout of
198 * Windows base colors and 'OK', 'More..' and 'Cancel' buttons.
200 GtkWidget *hildon_color_selector_new(GtkWindow * parent)
202 GtkWidget *dialog = g_object_new(HILDON_TYPE_COLOR_SELECTOR, NULL);
208 gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
215 hildon_color_selector_set_custom_colors(
216 HildonColorSelector *selector,
222 g_assert(HILDON_IS_COLOR_SELECTOR(selector));
224 /* We have to be really carefull. At least gconftool's
225 stress test may generate unexpected value setups */
226 if (value == NULL || value->type != GCONF_VALUE_LIST ||
227 gconf_value_get_list_type(value) != GCONF_VALUE_STRING)
230 list = gconf_value_get_list(value);
232 for ( i = 0; i < HILDON_CUSTOM_COLOR_NUM; ++i)
234 const gchar *color_string = NULL;
237 color_string = gconf_value_get_string(list->data);
240 color_string = "#FFFFFF";
243 /* g_print("custom_color: %s\n", color_string); */
245 selector->priv->color[i].pixel = 0;
246 gdk_color_parse (color_string,
247 &(selector->priv->color[HILDON_BASE_COLOR_NUM+i]));
252 gconf_notify_func(GConfClient *client,
257 hildon_color_selector_set_custom_colors(HILDON_COLOR_SELECTOR(data),
258 gconf_entry_get_value(entry));
259 gtk_widget_queue_draw(GTK_WIDGET(data));
263 hildon_color_selector_init(HildonColorSelector * selector)
269 /* 16 standard Windows colors */
270 static char *base_colours[HILDON_BASE_COLOR_NUM] = {
271 "#000000", "#FFFFFF", "#FF0000", "#660000", "#0000FF", "#000066",
272 "#FF33FF", "#660066", "#33CC33", "#006600", "#FFCC00", "#CC9900",
273 "#999999", "#666666", "#00CCCC", "#006666"
277 G_TYPE_INSTANCE_GET_PRIVATE(selector,
278 HILDON_TYPE_COLOR_SELECTOR,
279 HildonColorSelectorPriv);
281 /* ***********test GConf*********** */
282 selector->priv->client = gconf_client_get_default ();
283 gconf_client_set_error_handling (selector->priv->client,
284 GCONF_CLIENT_HANDLE_UNRETURNED);
286 /* Add our directory to the list of directories the GConfClient will
288 gconf_client_add_dir (selector->priv->client, HILDON_COLOR_GCONF_PATH,
289 GCONF_CLIENT_PRELOAD_NONE,
292 value = gconf_client_get(selector->priv->client,
293 HILDON_COLOR_GCONF_KEYS, NULL);
295 hildon_color_selector_set_custom_colors(selector, value);
298 gconf_value_free(value);
301 /* Listen to changes to our key. */
302 selector->priv->notify_id = gconf_client_notify_add (selector->priv->client,
303 HILDON_COLOR_GCONF_KEYS, gconf_notify_func, selector, NULL, NULL);
305 /* ************************************ */
307 selector->priv->index = GREYIND;
309 /* init base colors for color boxes */
310 for (i = 0; i < HILDON_BASE_COLOR_NUM; ++i)
312 selector->priv->color[i].pixel = 0;
313 gdk_color_parse (base_colours[i], &(selector->priv->color[i]));
316 gtk_dialog_set_has_separator(GTK_DIALOG(selector), FALSE);
318 /* create drawing area */
319 hbox = gtk_hbox_new(TRUE, 0);
320 selector->priv->drawing_area = gtk_drawing_area_new();
322 /* receive focus from dialog buttons */
323 GTK_WIDGET_SET_FLAGS (selector->priv->drawing_area, GTK_CAN_FOCUS);
325 gtk_widget_add_events (selector->priv->drawing_area,
326 GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
328 gtk_widget_set_size_request (selector->priv->drawing_area,
329 (HILDON_COLOR_SELECTOR_BOX_W *
330 HILDON_COLOR_SELECTOR_COLS) +
331 (HILDON_COLOR_SELECTOR_BOX_BORDER *
332 2*HILDON_COLOR_SELECTOR_COLS),
333 (HILDON_COLOR_SELECTOR_BOX_H *
334 HILDON_COLOR_SELECTOR_ROWS) +
335 HILDON_COLOR_SELECTOR_BOX_BORDER *
336 2 * HILDON_COLOR_SELECTOR_ROWS);
338 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(selector)->vbox),
339 hbox, FALSE, FALSE, 0);
340 gtk_box_pack_start (GTK_BOX(hbox), selector->priv->drawing_area,
343 g_signal_connect (selector->priv->drawing_area, "expose_event",
344 G_CALLBACK(hildon_color_selector_expose), selector);
345 g_signal_connect (selector->priv->drawing_area, "button_press_event",
346 G_CALLBACK(color_pressed), selector);
347 g_signal_connect (selector->priv->drawing_area, "motion-notify-event",
348 G_CALLBACK(color_moved), selector);
350 gtk_dialog_add_button (GTK_DIALOG(selector),
351 _("ecdg_bd_colour_selector_ok"), GTK_RESPONSE_OK);
353 selector->priv->modify_button =
354 gtk_button_new_with_label(_("ecdg_bd_colour_selector_modify"));
355 gtk_widget_set_sensitive(selector->priv->modify_button, FALSE);
356 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(selector)->action_area),
357 selector->priv->modify_button, FALSE, TRUE, 0);
359 g_signal_connect(selector->priv->modify_button, "clicked",
360 G_CALLBACK(modify_button_clicked), selector);
362 gtk_dialog_add_button (GTK_DIALOG(selector),
363 _("ecdg_bd_colour_selector_cancel"),
364 GTK_RESPONSE_CANCEL);
366 gtk_dialog_set_default_response (GTK_DIALOG(selector), GTK_RESPONSE_OK);
368 gtk_window_set_title ( GTK_WINDOW(selector),
369 _("ecdg_ti_colour_selector") );
370 gtk_widget_show_all (GTK_DIALOG(selector)->vbox);
374 hildon_color_selector_expose(GtkWidget * widget,
375 GdkEventExpose * event,
378 HildonColorSelector *selector;
383 g_return_val_if_fail (GTK_IS_WIDGET(widget), FALSE);
384 g_return_val_if_fail (event, FALSE);
385 g_return_val_if_fail (HILDON_IS_COLOR_SELECTOR(data), FALSE);
387 if (!GTK_WIDGET_DRAWABLE(widget))
390 selector = HILDON_COLOR_SELECTOR(data);
391 gc = gdk_gc_new (widget->window);
393 /* draw the color boxes and a focus for one of them */
394 for (x = 0; x < HILDON_COLOR_SELECTOR_COLS; ++x)
396 for (y = 0; y < HILDON_COLOR_SELECTOR_ROWS; ++y)
398 color.pixel = color.red = color.green = color.blue = 0;
399 gdk_gc_set_rgb_fg_color(gc, &color);
401 /* focus around the selected color box */
402 if ( (y * HILDON_COLOR_SELECTOR_COLS + x) ==
403 selector->priv->index)
406 gdk_draw_rectangle(widget->window, gc, TRUE,
407 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
408 HILDON_COLOR_SELECTOR_BOX_W) * x,
409 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
410 HILDON_COLOR_SELECTOR_BOX_H) * y,
411 HILDON_COLOR_SELECTOR_BOX_W +
412 HILDON_COLOR_SELECTOR_BOX_BORDER * 2,
413 HILDON_COLOR_SELECTOR_BOX_H +
414 HILDON_COLOR_SELECTOR_BOX_BORDER * 2);
417 /* frames on color box */
418 gdk_draw_rectangle(widget->window, gc, FALSE,
419 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
420 HILDON_COLOR_SELECTOR_BOX_W) * x + 1,
421 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
422 HILDON_COLOR_SELECTOR_BOX_H) * y + 1,
423 HILDON_COLOR_SELECTOR_BOX_W + 1,
424 HILDON_COLOR_SELECTOR_BOX_H + 1);
426 gdk_gc_set_rgb_fg_color(gc,
427 &(selector->priv->color[y * HILDON_COLOR_SELECTOR_COLS + x]));
430 gdk_draw_rectangle(widget->window, gc,
432 HILDON_COLOR_SELECTOR_BOX_BORDER +
433 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
434 HILDON_COLOR_SELECTOR_BOX_W) * x,
435 HILDON_COLOR_SELECTOR_BOX_BORDER +
436 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
437 HILDON_COLOR_SELECTOR_BOX_H) * y,
438 HILDON_COLOR_SELECTOR_BOX_W,
439 HILDON_COLOR_SELECTOR_BOX_H);
448 * hildon_color_selector_get_color:
449 * @selector: a #HildonColorSelector
451 * Gets the currently selected base color as #GdkColor.
453 * Returns: A copy of the currently selected #GdkColor.
455 GdkColor *hildon_color_selector_get_color(HildonColorSelector * selector)
457 g_return_val_if_fail(HILDON_IS_COLOR_SELECTOR(selector), NULL);
458 return &(selector->priv->color[selector->priv->index]);
462 * hildon_color_selector_set_color:
463 * @selector: #HildonColorSelector
464 * @color: #Gdkcolor to set.
466 * Select the color specified. Does nothing if the color does not
467 * exists among the standard colors.
469 void hildon_color_selector_set_color(HildonColorSelector * selector,
474 g_return_if_fail(HILDON_IS_COLOR_SELECTOR(selector));
475 g_return_if_fail(color);
478 i < (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM);
481 if (selector->priv->color[i].red == color->red &&
482 selector->priv->color[i].green == color->green &&
483 selector->priv->color[i].blue == color->blue)
485 selector->priv->index = i;
486 gtk_widget_set_sensitive(selector->priv->modify_button,
487 selector->priv->index >= HILDON_BASE_COLOR_NUM);
488 gtk_widget_queue_draw(selector->priv->drawing_area);
495 color_pressed(GtkWidget * widget, GdkEventButton * event,
498 select_color(HILDON_COLOR_SELECTOR(user_data), event->x, event->y, FALSE);
502 static gboolean key_pressed(GtkWidget * widget,
505 HildonColorSelector *selector;
508 g_return_val_if_fail(widget, FALSE);
510 selector = HILDON_COLOR_SELECTOR(widget);
511 index = selector->priv->index;
513 /* if dialog buttons has the focus */
514 if (GTK_WIDGET_HAS_FOCUS(selector->priv->drawing_area) == FALSE)
515 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
517 /* go for if available index otherwise stop keypress handler because
518 wrapping around is not allowed. */
519 switch (event->keyval) {
522 if (index == (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM - 1)
523 || index == (HILDON_CUSTOM_COLOR_NUM - 1)
524 || index == (2*HILDON_CUSTOM_COLOR_NUM - 1))
533 || index == (HILDON_CUSTOM_COLOR_NUM)
534 || index == (2*HILDON_CUSTOM_COLOR_NUM))
542 if (index > (HILDON_COLOR_SELECTOR_COLS - 1))
544 index -= HILDON_COLOR_SELECTOR_COLS;
548 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
553 if (index < (HILDON_COLOR_SELECTOR_COLS + HILDON_CUSTOM_COLOR_NUM))
555 index += HILDON_COLOR_SELECTOR_COLS;
559 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
564 if (index < HILDON_BASE_COLOR_NUM)
565 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
567 modify_selected(selector);
569 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
572 if (index < (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM))
574 selector->priv->index = index;
578 selector->priv->index =
579 HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM - 1;
581 gtk_widget_set_sensitive(selector->priv->modify_button,
582 selector->priv->index >= HILDON_BASE_COLOR_NUM);
584 gtk_widget_queue_draw(selector->priv->drawing_area);
590 select_color(HildonColorSelector * selector, int event_x, int event_y,
595 g_return_if_fail(HILDON_IS_COLOR_SELECTOR(selector));
597 x = ( (event_x - HILDON_COLOR_SELECTOR_BOX_BORDER) /
598 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
599 HILDON_COLOR_SELECTOR_BOX_W)
602 HILDON_COLOR_SELECTOR_BOX_BORDER) /
603 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
604 HILDON_COLOR_SELECTOR_BOX_H)
607 if (x > (HILDON_COLOR_SELECTOR_COLS + HILDON_CUSTOM_COLOR_NUM - 1))
609 x = HILDON_COLOR_SELECTOR_COLS + HILDON_CUSTOM_COLOR_NUM - 1;
615 if (y > (HILDON_COLOR_SELECTOR_ROWS - 1))
617 y = HILDON_COLOR_SELECTOR_ROWS - 1;
625 selector->priv->index >= HILDON_BASE_COLOR_NUM &&
626 selector->priv->index == (x + y * HILDON_COLOR_SELECTOR_COLS))
627 modify_selected(selector);
629 selector->priv->index = (x + y * HILDON_COLOR_SELECTOR_COLS);
630 gtk_widget_set_sensitive(selector->priv->modify_button,
631 selector->priv->index >= HILDON_BASE_COLOR_NUM);
633 gtk_widget_queue_draw(selector->priv->drawing_area);
637 color_moved(GtkWidget * widget, GdkEventMotion * event, gpointer data)
640 (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK) )
642 select_color(HILDON_COLOR_SELECTOR(data), event->x, event->y, TRUE);
649 modify_button_clicked(GtkWidget * button, HildonColorSelector * selector)
651 modify_selected (selector);
655 modify_selected(HildonColorSelector * colselector)
657 HildonColorPopup popupdata;
660 popup = hildon_color_popup_new(GTK_WINDOW(GTK_WIDGET(colselector)->window),
661 hildon_color_selector_get_color(colselector), &popupdata);
663 if ( gtk_dialog_run(GTK_DIALOG(popup) ) == GTK_RESPONSE_OK)
667 /* We cannot modify a base color */
668 if (colselector->priv->index < HILDON_BASE_COLOR_NUM)
670 colselector->priv->color[HILDON_TOTAL_COLOR_NUM] =
671 colselector->priv->color[colselector->priv->index];
672 colselector->priv->index = HILDON_TOTAL_COLOR_NUM;
675 color = hildon_color_selector_get_color(colselector);
676 hildon_color_popup_set_color_from_sliders(color, &popupdata);
678 /* If we modified a base color we just accept the dialog */
679 if( colselector->priv->index >= HILDON_TOTAL_COLOR_NUM)
681 gtk_dialog_response(GTK_DIALOG(colselector), GTK_RESPONSE_OK);
683 else /* If we mofied custom colors we have to save to gconf */
689 value = gconf_value_new(GCONF_VALUE_LIST);
690 gconf_value_set_list_type(value, GCONF_VALUE_STRING);
693 for ( i = HILDON_BASE_COLOR_NUM; i < HILDON_TOTAL_COLOR_NUM; i++)
698 g_snprintf(buffer, sizeof(buffer), "#%.2X%.2X%.2X",
699 (colselector->priv->color[i].red>>8)&0xFF,
700 (colselector->priv->color[i].green>>8)&0xFF,
701 (colselector->priv->color[i].blue>>8)&0xFF );
703 item = gconf_value_new(GCONF_VALUE_STRING);
704 gconf_value_set_string(item, buffer);
705 list = g_slist_append (list, item);
708 gconf_value_set_list_nocopy(value, list);
710 /* gconf client handles the possible error */
711 gconf_client_set(colselector->priv->client,
712 HILDON_COLOR_GCONF_KEYS, value, NULL);
714 gconf_value_free(value);
718 gtk_widget_destroy (popup);
719 gtk_window_present (GTK_WINDOW(colselector));