1 /*
2  *  color-combo-menu.c
3  *  Copyright (C) 2008  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include "color-combo-menu.h"
24 
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27 
28 #include "color-combo-color-menu-item.h"
29 #include "color-history-model.h"
30 #include "color.h"
31 #include "marshal.h"
32 
33 
34 /*===========================================*/
35 /* Private macros and constants.             */
36 /*===========================================*/
37 
38 #define PALETTE_COLS     7
39 #define PALETTE_ROWS    (G_N_ELEMENTS(color_table)/PALETTE_COLS + (G_N_ELEMENTS(color_table)%PALETTE_COLS ? 1 : 0))
40 
41 #define ROW_DEFAULT (0)
42 #define ROW_SEP_1   (ROW_DEFAULT + 1)
43 #define ROW_PALETTE (ROW_SEP_1   + 1)
44 #define ROW_SEP_2   (ROW_PALETTE + PALETTE_ROWS)
45 #define ROW_HISTORY (ROW_SEP_2   + 1)
46 #define ROW_SEP_3   (ROW_HISTORY + 1)
47 #define ROW_CUSTOM  (ROW_SEP_3   + 1)
48 
49 /*===========================================*/
50 /* Private types                             */
51 /*===========================================*/
52 
53 struct _glColorComboMenuPrivate {
54 
55         GtkWidget *default_menu_item;
56         GtkWidget *custom_menu_item;
57 
58         GtkWidget *history_menu_item[PALETTE_COLS];
59 
60         guint      color;
61 };
62 
63 enum {
64         COLOR_CHANGED,
65         LAST_SIGNAL
66 };
67 
68 typedef struct {
69         guint  color;
70         gchar *name;
71 } ColorTableEntry;
72 
73 
74 /*===========================================*/
75 /* Private globals                           */
76 /*===========================================*/
77 
78 static guint signals[LAST_SIGNAL] = {0};
79 
80 static ColorTableEntry color_table[] =
81 {
82 
83         { GL_COLOR (139,   0,   0), N_("Dark Red") },
84         { GL_COLOR (165,  42,  42), N_("Brown") },
85         { GL_COLOR (205, 149,  12), N_("Dark Goldenrod") },
86         { GL_COLOR (  0, 100,   0), N_("Dark Green") },
87         { GL_COLOR (  0, 139, 139), N_("Dark Cyan") },
88         { GL_COLOR (  0,   0, 128), N_("Navy Blue") },
89         { GL_COLOR (148,   0, 211), N_("Dark Violet") },
90 
91         { GL_COLOR (255,   0,   0), N_("Red") },
92         { GL_COLOR (255, 165,   0), N_("Orange") },
93         { GL_COLOR (205, 205,   0), N_("Dark Yellow") },
94         { GL_COLOR (  0, 205,   0), N_("Medium green") },
95         { GL_COLOR ( 64, 224, 208), N_("Turquoise") },
96         { GL_COLOR (  0,   0, 255), N_("Blue") },
97         { GL_COLOR (160,  32, 240), N_("Purple") },
98 
99         { GL_COLOR (250, 128, 114), N_("Salmon") },
100         { GL_COLOR (255, 215,   0), N_("Gold") },
101         { GL_COLOR (255, 255,   0), N_("Yellow") },
102         { GL_COLOR (  0, 255,   0), N_("Green") },
103         { GL_COLOR (  0, 255, 255), N_("Cyan") },
104         { GL_COLOR (135, 206, 235), N_("SkyBlue") },
105         { GL_COLOR (238, 130, 238), N_("Violet") },
106 
107         { GL_COLOR (255, 192, 203), N_("Pink") },
108         { GL_COLOR (255, 246, 143), N_("Khaki") },
109         { GL_COLOR (255, 255, 224), N_("Light Yellow") },
110         { GL_COLOR (144, 238, 144), N_("Light Green") },
111         { GL_COLOR (224, 255, 255), N_("Light Cyan") },
112         { GL_COLOR (198, 226, 255), N_("Slate Gray") },
113         { GL_COLOR (216, 191, 216), N_("Thistle") },
114 
115         { GL_COLOR (255, 255, 255), N_("White") },
116         /* xgettext: no-c-format */
117         { GL_COLOR (230, 230, 230), N_("10% Gray") },
118         /* xgettext: no-c-format */
119         { GL_COLOR (192, 192, 192), N_("25% Gray") },
120         /* xgettext: no-c-format */
121         { GL_COLOR (153, 153, 153), N_("40% Gray") },
122         /* xgettext: no-c-format */
123         { GL_COLOR (128, 128, 128), N_("50% Gray") },
124         /* xgettext: no-c-format */
125         { GL_COLOR (102, 102, 102), N_("60% Gray") },
126         { GL_COLOR (  0,   0,   0), N_("Black") },
127 
128 };
129 
130 static glColorHistoryModel *custom_color_history = NULL;
131 
132 
133 /*===========================================*/
134 /* Local function prototypes                 */
135 /*===========================================*/
136 
137 static void gl_color_combo_menu_finalize  (GObject          *object);
138 
139 static void load_custom_color_history     (glColorComboMenu *this);
140 
141 static gboolean map_event_cb              (GtkWidget    *widget,
142                                            GdkEventAny  *event);
143 
144 static void default_menu_item_activate_cb (glColorComboMenu *this);
145 static void custom_menu_item_activate_cb  (glColorComboMenu *this);
146 
147 static void palette_menu_item_activate_cb (GtkMenuItem      *item,
148                                            glColorComboMenu *this);
149 
150 static void history_menu_item_activate_cb (GtkMenuItem      *item,
151                                            glColorComboMenu *this);
152 
153 
154 /****************************************************************************/
155 /* Boilerplate Object stuff.                                                */
156 /****************************************************************************/
G_DEFINE_TYPE(glColorComboMenu,gl_color_combo_menu,GTK_TYPE_MENU)157 G_DEFINE_TYPE (glColorComboMenu, gl_color_combo_menu, GTK_TYPE_MENU)
158 
159 
160 /*****************************************************************************/
161 /* Class Init Function.                                                      */
162 /*****************************************************************************/
163 static void
164 gl_color_combo_menu_class_init (glColorComboMenuClass *class)
165 {
166 	GObjectClass   *gobject_class = G_OBJECT_CLASS (class);
167 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
168 
169         gl_color_combo_menu_parent_class = g_type_class_peek_parent (class);
170 
171 	gobject_class->finalize = gl_color_combo_menu_finalize;
172 
173         widget_class->map_event = map_event_cb;
174 
175         signals[COLOR_CHANGED] =
176                 g_signal_new ("color_changed",
177                               G_OBJECT_CLASS_TYPE (gobject_class),
178                               G_SIGNAL_RUN_LAST,
179                               G_STRUCT_OFFSET (glColorComboMenuClass, color_changed),
180                               NULL, NULL,
181                               gl_marshal_VOID__UINT_BOOLEAN,
182                               G_TYPE_NONE,
183                               2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
184 }
185 
186 
187 /*****************************************************************************/
188 /* Object Instance Init Function.                                            */
189 /*****************************************************************************/
190 static void
gl_color_combo_menu_init(glColorComboMenu * this)191 gl_color_combo_menu_init (glColorComboMenu *this)
192 {
193         GtkWidget *separator_menu_item;
194         gint       i, i_row, i_col;
195         GtkWidget *palette_menu_item;
196 
197 
198         /*
199          * Initialize history, if needed.
200          */
201         if ( !custom_color_history )
202         {
203                 custom_color_history = gl_color_history_model_new (PALETTE_COLS);
204         }
205 
206 
207 	this->priv = g_new0 (glColorComboMenuPrivate, 1);
208 
209         this->priv->default_menu_item = gtk_menu_item_new_with_label ("");
210         gtk_menu_attach (GTK_MENU (this), this->priv->default_menu_item,
211                          0, PALETTE_COLS, ROW_DEFAULT, ROW_DEFAULT+1);
212 
213         separator_menu_item = gtk_separator_menu_item_new ();
214         gtk_menu_attach (GTK_MENU (this), separator_menu_item,
215                          0, PALETTE_COLS, ROW_SEP_1, ROW_SEP_1+1);
216 
217         for ( i=0; i < G_N_ELEMENTS(color_table); i++ )
218         {
219 
220                 i_row = i / PALETTE_COLS;
221                 i_col = i % PALETTE_COLS;
222 
223                 palette_menu_item = gl_color_combo_color_menu_item_new (i,
224                                                                         color_table[i].color,
225                                                                         gettext (color_table[i].name));
226                 g_signal_connect (palette_menu_item, "activate",
227                                   G_CALLBACK (palette_menu_item_activate_cb), this);
228 
229                 gtk_menu_attach (GTK_MENU (this), palette_menu_item,
230                                  i_col, i_col+1,
231                                  ROW_PALETTE+i_row, ROW_PALETTE+i_row+1);
232         }
233 
234         separator_menu_item = gtk_separator_menu_item_new ();
235         gtk_menu_attach (GTK_MENU (this), separator_menu_item,
236                          0, PALETTE_COLS, ROW_SEP_2, ROW_SEP_2+1);
237 
238         for ( i=0; i < PALETTE_COLS; i++ )
239         {
240                 this->priv->history_menu_item[i] =
241                         gl_color_combo_color_menu_item_new (i, 0, NULL);
242                 gtk_widget_set_sensitive (this->priv->history_menu_item[i], FALSE);
243                 g_signal_connect (this->priv->history_menu_item[i], "activate",
244                                   G_CALLBACK (history_menu_item_activate_cb), this);
245                 gtk_menu_attach (GTK_MENU (this), this->priv->history_menu_item[i],
246                                  i, i+1,
247                                  ROW_HISTORY, ROW_HISTORY+1);
248         }
249 
250         separator_menu_item = gtk_separator_menu_item_new ();
251         gtk_menu_attach (GTK_MENU (this), separator_menu_item,
252                          0, PALETTE_COLS, ROW_SEP_3, ROW_SEP_3+1);
253 
254         this->priv->custom_menu_item = gtk_menu_item_new_with_label (_("Custom Color"));
255         gtk_menu_attach (GTK_MENU (this), this->priv->custom_menu_item,
256                          0, PALETTE_COLS, ROW_CUSTOM, ROW_CUSTOM+1);
257 
258         g_signal_connect_swapped (this->priv->default_menu_item, "activate",
259                                   G_CALLBACK (default_menu_item_activate_cb), this);
260         g_signal_connect_swapped (this->priv->custom_menu_item, "activate",
261                                   G_CALLBACK (custom_menu_item_activate_cb), this);
262 
263 }
264 
265 
266 /*****************************************************************************/
267 /* Finalize Method.                                                          */
268 /*****************************************************************************/
269 static void
gl_color_combo_menu_finalize(GObject * object)270 gl_color_combo_menu_finalize (GObject *object)
271 {
272 	glColorComboMenu *this = GL_COLOR_COMBO_MENU (object);
273 
274 	g_return_if_fail (object != NULL);
275 	g_return_if_fail (GL_IS_COLOR_COMBO_MENU (object));
276 
277 	g_free (this->priv);
278 
279 	G_OBJECT_CLASS (gl_color_combo_menu_parent_class)->finalize (object);
280 }
281 
282 
283 /*****************************************************************************/
284 /** New Object Generator.                                                    */
285 /*****************************************************************************/
286 GtkWidget *
gl_color_combo_menu_new(const gchar * default_label,guint color)287 gl_color_combo_menu_new (const gchar *default_label,
288                          guint        color)
289 {
290 	glColorComboMenu *this;
291 
292 	this = g_object_new (gl_color_combo_menu_get_type (), NULL);
293 
294         gtk_label_set_text ( GTK_LABEL (gtk_bin_get_child (GTK_BIN (this->priv->default_menu_item))),
295                             default_label);
296 
297         this->priv->color = color;
298 
299 	return GTK_WIDGET (this);
300 }
301 
302 
303 /*****************************************************************************/
304 /* Load menu with custom color history.                                      */
305 /*****************************************************************************/
306 static void
load_custom_color_history(glColorComboMenu * this)307 load_custom_color_history (glColorComboMenu *this)
308 {
309         guint  i;
310         guint  color;
311         gchar *tip;
312 
313         for ( i=0; i < PALETTE_COLS; i++ )
314         {
315                 color = gl_color_history_model_get_color (custom_color_history, i);
316 
317                 if (color)
318                 {
319                         tip = g_strdup_printf (_("Custom Color #%u"), i+1);
320 
321                         gl_color_combo_color_menu_item_set_color (GL_COLOR_COMBO_COLOR_MENU_ITEM (this->priv->history_menu_item[i]),
322                                                                   i,
323                                                                   color,
324                                                                   tip);
325                         g_free (tip);
326                         gtk_widget_set_sensitive (this->priv->history_menu_item[i], TRUE);
327                 }
328         }
329 }
330 
331 
332 /*****************************************************************************/
333 /* Map event callback.                                                       */
334 /*****************************************************************************/
335 static gboolean
map_event_cb(GtkWidget * widget,GdkEventAny * event)336 map_event_cb (GtkWidget    *widget,
337               GdkEventAny  *event)
338 {
339         glColorComboMenu *this = GL_COLOR_COMBO_MENU (widget);
340 
341         load_custom_color_history (this);
342 
343         return FALSE;
344 }
345 
346 
347 /*****************************************************************************/
348 /* "Default" menu_item activate callback.                                    */
349 /*****************************************************************************/
350 static void
default_menu_item_activate_cb(glColorComboMenu * this)351 default_menu_item_activate_cb (glColorComboMenu *this)
352 {
353         g_signal_emit (this, signals[COLOR_CHANGED], 0,
354                       NULL, TRUE);
355 
356         gtk_widget_hide (GTK_WIDGET (this));
357 }
358 
359 
360 /*****************************************************************************/
361 /* "Custom color" menu_item activate callback.                               */
362 /*****************************************************************************/
363 static void
custom_menu_item_activate_cb(glColorComboMenu * this)364 custom_menu_item_activate_cb (glColorComboMenu *this)
365 {
366         GtkWidget *custom_dialog;
367         GtkWidget *colorsel;
368         gint       response;
369         GdkColor   color;
370 
371         gtk_widget_hide (GTK_WIDGET (this));
372 
373         custom_dialog = gtk_color_selection_dialog_new (_("Custom Color"));
374 
375         colorsel = gtk_color_selection_dialog_get_color_selection (GTK_COLOR_SELECTION_DIALOG (custom_dialog));
376         color.red   = GL_COLOR_F_RED   (this->priv->color) * 65535;
377         color.green = GL_COLOR_F_GREEN (this->priv->color) * 65535;
378         color.blue  = GL_COLOR_F_BLUE  (this->priv->color) * 65535;
379 
380         gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (colorsel),
381                                                &color);
382 
383         response = gtk_dialog_run (GTK_DIALOG (custom_dialog));
384 
385         switch (response) {
386 
387         case GTK_RESPONSE_OK:
388                 gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (colorsel),
389                                                        &color);
390                 this->priv->color = GL_COLOR ((color.red   >>8),
391                                               (color.green >>8),
392                                               (color.blue  >>8));
393 
394                 gl_color_history_model_add_color (custom_color_history,
395                                                   this->priv->color);
396 
397                 g_signal_emit (this, signals[COLOR_CHANGED], 0,
398                                this->priv->color, FALSE);
399 
400                 gtk_widget_destroy (custom_dialog);
401                 break;
402         default:
403                 gtk_widget_destroy (custom_dialog);
404                 break;
405         }
406 }
407 
408 
409 /*****************************************************************************/
410 /* Palette color changed callback.                                           */
411 /*****************************************************************************/
412 static void
palette_menu_item_activate_cb(GtkMenuItem * item,glColorComboMenu * this)413 palette_menu_item_activate_cb (GtkMenuItem      *item,
414                                glColorComboMenu *this)
415 {
416         gint i;
417 
418         i = gl_color_combo_color_menu_item_get_id (GL_COLOR_COMBO_COLOR_MENU_ITEM (item));
419 
420         this->priv->color = color_table[i].color;
421 
422         g_signal_emit (this, signals[COLOR_CHANGED], 0,
423                        this->priv->color, FALSE);
424 
425         gtk_widget_hide (GTK_WIDGET (this));
426 }
427 
428 /*****************************************************************************/
429 /* History color menu item callback.                                         */
430 /*****************************************************************************/
431 static void
history_menu_item_activate_cb(GtkMenuItem * item,glColorComboMenu * this)432 history_menu_item_activate_cb (GtkMenuItem      *item,
433                                glColorComboMenu *this)
434 {
435         gint i;
436 
437         i = gl_color_combo_color_menu_item_get_id (GL_COLOR_COMBO_COLOR_MENU_ITEM (item));
438 
439         this->priv->color = gl_color_history_model_get_color (custom_color_history, i);
440 
441         g_signal_emit (this, signals[COLOR_CHANGED], 0,
442                        this->priv->color, FALSE);
443 
444         gtk_widget_hide (GTK_WIDGET (this));
445 }
446 
447 
448 
449 /*
450  * Local Variables:       -- emacs
451  * mode: C                -- emacs
452  * c-basic-offset: 8      -- emacs
453  * tab-width: 8           -- emacs
454  * indent-tabs-mode: nil  -- emacs
455  * End:                   -- emacs
456  */
457