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 <gdk/gdkkeysyms.h>
42 #include <gconf/gconf-client.h>
44 #include "hildon-color-selector.h"
45 #include "hildon-color-popup.h"
48 #define _(String) dgettext(PACKAGE, String)
51 #define HILDON_BASE_COLOR_NUM 16
52 #define HILDON_CUSTOM_COLOR_NUM 8
53 #define HILDON_TOTAL_COLOR_NUM \
54 (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM)
60 #define HILDON_COLOR_SELECTOR_BOX_W 27
61 #define HILDON_COLOR_SELECTOR_BOX_H 27
62 #define HILDON_COLOR_SELECTOR_BOX_BORDER 2
63 #define HILDON_COLOR_SELECTOR_COLS 8
64 #define HILDON_COLOR_SELECTOR_ROWS 3
65 #define HILDON_COLOR_PALETTE_SIZE 120
66 #define HILDON_COLOR_CONTROLBAR_MAX 31
67 #define HILDON_COLOR_CONTROLBAR_MIN 0
68 #define HILDON_COLOR_LABELS_LEFT_PAD 35
69 #define HILDON_COLOR_PALETTE_POS_PAD 45
70 #define HILDON_COLOR_BAR_WIDTH 449
72 #define HILDON_MORE_BUTTON_RESPONSE 1234
74 /* gconf definitions */
75 #define HILDON_COLOR_GCONF_PATH "/system/osso/af/color_selector"
76 #define HILDON_COLOR_GCONF_KEYS "/system/osso/af/color_selector/custom_colors"
78 * Pointer parent class
80 static GtkDialogClass *parent_class;
82 struct _HildonColorSelectorPriv
85 GtkWidget *drawing_area;
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 hildon_color_selector_response (GtkWidget * widget,
113 key_pressed (GtkWidget * widget,
118 color_pressed (GtkWidget * widget,
119 GdkEventButton * event,
123 select_color (HildonColorSelector * selector,
128 color_moved (GtkWidget * widget,
129 GdkEventMotion * event,
133 hildon_color_selector_get_type(void)
135 static GType selector_type = 0;
139 static const GTypeInfo selector_info =
141 sizeof(HildonColorSelectorClass),
142 NULL, /* base_init */
143 NULL, /* base_finalize */
144 (GClassInitFunc) hildon_color_selector_class_init,
145 NULL, /* class_finalize */
146 NULL, /* class_data */
147 sizeof(HildonColorSelector),
149 (GInstanceInitFunc) hildon_color_selector_init,
151 selector_type = g_type_register_static(GTK_TYPE_DIALOG,
152 "HildonColorSelector",
155 return selector_type;
159 hildon_color_selector_destroy(GtkObject *obj)
161 HildonColorSelectorPriv *priv = HILDON_COLOR_SELECTOR(obj)->priv;
165 gconf_client_notify_remove(priv->client, priv->notify_id);
166 g_object_unref(priv->client);
170 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
174 hildon_color_selector_class_init(HildonColorSelectorClass * selector_class)
176 parent_class = g_type_class_peek_parent(selector_class);
178 g_type_class_add_private(selector_class,
179 sizeof(HildonColorSelectorPriv));
181 GTK_OBJECT_CLASS(selector_class)->destroy = hildon_color_selector_destroy;
186 * hildon_color_selector_new:
187 * @parent: The parent window. The X window ID of the parent window
188 * has to be the same as the X window ID of the application.
189 * @returns: new #HildonColorSelector.
191 * Creates a new #HildonColorSelector dialog with 3x8 layout of
192 * Windows base colors and 'OK', 'More..' and 'Cancel' buttons.
194 GtkWidget *hildon_color_selector_new(GtkWindow * parent)
196 GtkWidget *dialog = g_object_new(HILDON_TYPE_COLOR_SELECTOR, NULL);
202 gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
209 hildon_color_selector_set_custom_colors(
210 HildonColorSelector *selector,
216 g_assert(HILDON_IS_COLOR_SELECTOR(selector));
218 /* We have to be really carefull. At least gconftool's
219 stress test can generate pretty ugly value setups */
220 if (value == NULL || value->type != GCONF_VALUE_LIST ||
221 gconf_value_get_list_type(value) != GCONF_VALUE_STRING)
224 list = gconf_value_get_list(value);
226 for ( i = 0; i < HILDON_CUSTOM_COLOR_NUM; ++i)
228 const gchar *color_string = NULL;
231 color_string = gconf_value_get_string(list->data);
234 color_string = "#FFFFFF";
237 /* g_print("custom_color: %s\n", color_string); */
239 selector->priv->color[i].pixel = 0;
240 gdk_color_parse (color_string,
241 &(selector->priv->color[HILDON_BASE_COLOR_NUM+i]));
246 gconf_notify_func(GConfClient *client,
251 hildon_color_selector_set_custom_colors(HILDON_COLOR_SELECTOR(data),
252 gconf_entry_get_value(entry));
253 gtk_widget_queue_draw(GTK_WIDGET(data));
257 hildon_color_selector_init(HildonColorSelector * selector)
263 /* 16 standard Windows colors */
264 static char *base_colours[HILDON_BASE_COLOR_NUM] = {
265 "#000000", "#FFFFFF", "#FF0000", "#660000", "#0000FF", "#000066",
266 "#FF33FF", "#660066", "#33CC33", "#006600", "#FFCC00", "#CC9900",
267 "#999999", "#666666", "#00CCCC", "#006666"
271 G_TYPE_INSTANCE_GET_PRIVATE(selector,
272 HILDON_TYPE_COLOR_SELECTOR,
273 HildonColorSelectorPriv);
275 /* ***********test GConf*********** */
276 selector->priv->client = gconf_client_get_default ();
277 gconf_client_set_error_handling (selector->priv->client,
278 GCONF_CLIENT_HANDLE_UNRETURNED);
280 /* Add our directory to the list of directories the GConfClient will
282 gconf_client_add_dir (selector->priv->client, HILDON_COLOR_GCONF_PATH,
283 GCONF_CLIENT_PRELOAD_NONE,
286 value = gconf_client_get(selector->priv->client,
287 HILDON_COLOR_GCONF_KEYS, NULL);
289 hildon_color_selector_set_custom_colors(selector, value);
292 gconf_value_free(value);
295 /* Listen to changes to our key. */
296 selector->priv->notify_id = gconf_client_notify_add (selector->priv->client,
297 HILDON_COLOR_GCONF_KEYS, gconf_notify_func, selector, NULL, NULL);
299 /* ************************************ */
301 selector->priv->index = GREYIND;
303 /* init base colors for color boxes */
304 for (i = 0; i < HILDON_BASE_COLOR_NUM; ++i)
306 selector->priv->color[i].pixel = 0;
307 gdk_color_parse (base_colours[i], &(selector->priv->color[i]));
310 gtk_dialog_set_has_separator(GTK_DIALOG(selector), FALSE);
312 /* create drawing area */
313 hbox = gtk_hbox_new(TRUE, 0);
314 selector->priv->drawing_area = gtk_drawing_area_new();
316 /* receive focus from dialog buttons */
317 GTK_WIDGET_SET_FLAGS (selector->priv->drawing_area, GTK_CAN_FOCUS);
319 gtk_widget_add_events (selector->priv->drawing_area,
320 GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
322 gtk_widget_set_size_request (selector->priv->drawing_area,
323 (HILDON_COLOR_SELECTOR_BOX_W *
324 HILDON_COLOR_SELECTOR_COLS) +
325 (HILDON_COLOR_SELECTOR_BOX_BORDER *
326 2*HILDON_COLOR_SELECTOR_COLS),
327 (HILDON_COLOR_SELECTOR_BOX_H *
328 HILDON_COLOR_SELECTOR_ROWS) +
329 HILDON_COLOR_SELECTOR_BOX_BORDER *
330 2 * HILDON_COLOR_SELECTOR_ROWS);
332 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(selector)->vbox),
333 hbox, FALSE, FALSE, 0);
334 gtk_box_pack_start (GTK_BOX(hbox), selector->priv->drawing_area,
337 g_signal_connect (selector->priv->drawing_area, "expose_event",
338 G_CALLBACK(hildon_color_selector_expose), selector);
339 g_signal_connect (selector->priv->drawing_area, "button_press_event",
340 G_CALLBACK(color_pressed), selector);
341 g_signal_connect (selector->priv->drawing_area, "motion-notify-event",
342 G_CALLBACK(color_moved), selector);
343 g_signal_connect (selector, "key-press-event",
344 G_CALLBACK(key_pressed), selector);
347 gtk_dialog_add_button (GTK_DIALOG(selector),
348 _("ecdg_bd_colour_selector_ok"), GTK_RESPONSE_OK);
349 gtk_dialog_add_button (GTK_DIALOG(selector),
350 _("ecdg_ti_5bit_colour_selector"),
351 HILDON_MORE_BUTTON_RESPONSE);
352 gtk_dialog_add_button (GTK_DIALOG(selector),
353 _("ecdg_bd_colour_selector_cancel"),
354 GTK_RESPONSE_CANCEL);
356 gtk_dialog_set_default_response (GTK_DIALOG(selector), GTK_RESPONSE_OK);
358 g_signal_connect (G_OBJECT(selector), "response",
359 G_CALLBACK(hildon_color_selector_response), selector);
361 gtk_window_set_title ( GTK_WINDOW(selector),
362 _("ecdg_ti_colour_selector") );
363 gtk_widget_show_all (GTK_DIALOG(selector)->vbox);
367 hildon_color_selector_expose(GtkWidget * widget,
368 GdkEventExpose * event,
371 HildonColorSelector *selector;
376 g_return_val_if_fail (GTK_IS_WIDGET(widget), FALSE);
377 g_return_val_if_fail (event, FALSE);
378 g_return_val_if_fail (HILDON_IS_COLOR_SELECTOR(data), FALSE);
380 if (!GTK_WIDGET_DRAWABLE(widget))
383 selector = HILDON_COLOR_SELECTOR(data);
384 gc = gdk_gc_new (widget->window);
386 /* draw the color boxes and a focus for one of them */
387 for (x = 0; x < HILDON_COLOR_SELECTOR_COLS; ++x)
389 for (y = 0; y < HILDON_COLOR_SELECTOR_ROWS; ++y)
391 color.pixel = color.red = color.green = color.blue = 0;
392 gdk_gc_set_rgb_fg_color(gc, &color);
394 /* focus around the selected color box */
395 if ( (y * HILDON_COLOR_SELECTOR_COLS + x) ==
396 selector->priv->index)
399 gdk_draw_rectangle(widget->window, gc, TRUE,
400 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
401 HILDON_COLOR_SELECTOR_BOX_W) * x,
402 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
403 HILDON_COLOR_SELECTOR_BOX_H) * y,
404 HILDON_COLOR_SELECTOR_BOX_W +
405 HILDON_COLOR_SELECTOR_BOX_BORDER * 2,
406 HILDON_COLOR_SELECTOR_BOX_H +
407 HILDON_COLOR_SELECTOR_BOX_BORDER * 2);
410 /* frames on color box */
411 gdk_draw_rectangle(widget->window, gc, FALSE,
412 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
413 HILDON_COLOR_SELECTOR_BOX_W) * x + 1,
414 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
415 HILDON_COLOR_SELECTOR_BOX_H) * y + 1,
416 HILDON_COLOR_SELECTOR_BOX_W + 1,
417 HILDON_COLOR_SELECTOR_BOX_H + 1);
419 gdk_gc_set_rgb_fg_color(gc,
420 &(selector->priv->color[y * HILDON_COLOR_SELECTOR_COLS + x]));
423 gdk_draw_rectangle(widget->window, gc,
425 HILDON_COLOR_SELECTOR_BOX_BORDER +
426 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
427 HILDON_COLOR_SELECTOR_BOX_W) * x,
428 HILDON_COLOR_SELECTOR_BOX_BORDER +
429 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
430 HILDON_COLOR_SELECTOR_BOX_H) * y,
431 HILDON_COLOR_SELECTOR_BOX_W,
432 HILDON_COLOR_SELECTOR_BOX_H);
441 * hildon_color_selector_get_color:
442 * @selector: a #HildonColorSelector
444 * Gets the currently selected base color as #GdkColor.
446 * Returns: A copy of the currently selected #GdkColor.
448 GdkColor *hildon_color_selector_get_color(HildonColorSelector * selector)
450 g_return_val_if_fail(HILDON_IS_COLOR_SELECTOR(selector), NULL);
451 return &(selector->priv->color[selector->priv->index]);
455 * hildon_color_selector_set_color:
456 * @selector: #HildonColorSelector
457 * @color: #Gdkcolor to set.
459 * Select the color specified. Does nothing if the color does not
460 * exists among the standard colors.
462 void hildon_color_selector_set_color(HildonColorSelector * selector,
467 g_return_if_fail(HILDON_IS_COLOR_SELECTOR(selector));
468 g_return_if_fail(color);
471 i < (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM);
474 if (selector->priv->color[i].red == color->red &&
475 selector->priv->color[i].green == color->green &&
476 selector->priv->color[i].blue == color->blue)
478 selector->priv->index = i;
479 gtk_widget_queue_draw(selector->priv->drawing_area);
486 color_pressed(GtkWidget * widget, GdkEventButton * event,
489 select_color(HILDON_COLOR_SELECTOR(user_data), event->x, event->y);
493 static gboolean key_pressed(GtkWidget * widget,
494 GdkEventKey * event, gpointer user_data)
496 HildonColorSelector *selector;
499 g_return_val_if_fail(widget, FALSE);
500 g_return_val_if_fail(user_data, FALSE);
502 selector = HILDON_COLOR_SELECTOR(user_data);
503 index = selector->priv->index;
505 /* if dialog buttons has the focus */
506 if (GTK_WIDGET_HAS_FOCUS(selector->priv->drawing_area) == FALSE)
509 /* go for if available index otherwise stop keypress handler because
510 wrapping around is not allowed. */
511 switch (event->keyval) {
514 if (index == (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM - 1)
515 || index == (HILDON_CUSTOM_COLOR_NUM - 1)
516 || index == (2*HILDON_CUSTOM_COLOR_NUM - 1))
525 || index == (HILDON_CUSTOM_COLOR_NUM)
526 || index == (2*HILDON_CUSTOM_COLOR_NUM))
534 if (index > (HILDON_COLOR_SELECTOR_COLS - 1))
536 index -= HILDON_COLOR_SELECTOR_COLS;
545 if (index < (HILDON_COLOR_SELECTOR_COLS + HILDON_CUSTOM_COLOR_NUM))
547 index += HILDON_COLOR_SELECTOR_COLS;
558 if (index < (HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM))
560 selector->priv->index = index;
564 selector->priv->index =
565 HILDON_BASE_COLOR_NUM + HILDON_CUSTOM_COLOR_NUM - 1;
568 gtk_widget_queue_draw(selector->priv->drawing_area);
574 select_color(HildonColorSelector * selector, int event_x, int event_y)
578 g_return_if_fail(HILDON_IS_COLOR_SELECTOR(selector));
580 x = ( (event_x - HILDON_COLOR_SELECTOR_BOX_BORDER) /
581 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
582 HILDON_COLOR_SELECTOR_BOX_W)
585 HILDON_COLOR_SELECTOR_BOX_BORDER) /
586 (HILDON_COLOR_SELECTOR_BOX_BORDER * 2 +
587 HILDON_COLOR_SELECTOR_BOX_H)
590 if (x > (HILDON_COLOR_SELECTOR_COLS + HILDON_CUSTOM_COLOR_NUM - 1))
592 x = HILDON_COLOR_SELECTOR_COLS + HILDON_CUSTOM_COLOR_NUM - 1;
598 if (y > (HILDON_COLOR_SELECTOR_ROWS - 1))
600 y = HILDON_COLOR_SELECTOR_ROWS - 1;
607 selector->priv->index = (x + y * HILDON_COLOR_SELECTOR_COLS);
609 gtk_widget_queue_draw(selector->priv->drawing_area);
613 color_moved(GtkWidget * widget, GdkEventMotion * event, gpointer data)
616 (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK) )
618 select_color(HILDON_COLOR_SELECTOR(data), event->x, event->y);
625 hildon_color_selector_response(GtkWidget * widget,
629 HildonColorSelector * colselector;
630 HildonColorPopup popupdata;
633 g_return_if_fail (HILDON_IS_COLOR_SELECTOR(data));
635 if (response_id != HILDON_MORE_BUTTON_RESPONSE)
638 g_signal_stop_emission_by_name (widget, "response");
639 colselector = HILDON_COLOR_SELECTOR(data);
641 popup = hildon_color_popup_new(GTK_WINDOW(GTK_WIDGET(colselector)->window),
642 hildon_color_selector_get_color(colselector), &popupdata);
644 if ( gtk_dialog_run(GTK_DIALOG(popup) ) == GTK_RESPONSE_OK)
648 /* We cannot modify a base color */
649 if (colselector->priv->index < HILDON_BASE_COLOR_NUM)
651 colselector->priv->color[HILDON_TOTAL_COLOR_NUM] =
652 colselector->priv->color[colselector->priv->index];
653 colselector->priv->index = HILDON_TOTAL_COLOR_NUM;
656 color = hildon_color_selector_get_color(colselector);
657 hildon_color_popup_set_color_from_sliders(color, &popupdata);
659 /* If we modified a base color we just accept the dialog */
660 if( colselector->priv->index >= HILDON_TOTAL_COLOR_NUM)
662 gtk_dialog_response(GTK_DIALOG(colselector), GTK_RESPONSE_OK);
664 else /* If we mofied custom colors we have to save to gconf */
670 value = gconf_value_new(GCONF_VALUE_LIST);
671 gconf_value_set_list_type(value, GCONF_VALUE_STRING);
674 for ( i = HILDON_BASE_COLOR_NUM; i < HILDON_TOTAL_COLOR_NUM; i++)
679 g_snprintf(buffer, sizeof(buffer), "#%.2X%.2X%.2X",
680 (colselector->priv->color[i].red>>8)&0xFF,
681 (colselector->priv->color[i].green>>8)&0xFF,
682 (colselector->priv->color[i].blue>>8)&0xFF );
684 item = gconf_value_new(GCONF_VALUE_STRING);
685 gconf_value_set_string(item, buffer);
686 list = g_slist_append (list, item);
689 gconf_value_set_list_nocopy(value, list);
691 /* gconf client handles the possible error */
692 gconf_client_set(colselector->priv->client,
693 HILDON_COLOR_GCONF_KEYS, value, NULL);
695 gconf_value_free(value);
699 gtk_widget_destroy (popup);
700 gtk_window_present (GTK_WINDOW(colselector));