]> git.sur5r.net Git - glabels/blob - glabels2/src/color-combo-button.c
2009-09-08 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / color-combo-button.c
1 /*
2  *  color-combo-button.c
3  *  Copyright (C) 2008-2009  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-button.h"
24
25 #include "color-combo-menu.h"
26 #include <glib/gi18n.h>
27 #include <gtk/gtktogglebutton.h>
28 #include <gtk/gtkvbox.h>
29 #include "color-swatch.h"
30 #include <gtk/gtkarrow.h>
31 #include "marshal.h"
32 #include "color.h"
33
34
35 #define IMAGE_W 24
36 #define IMAGE_H 24
37
38 #define SWATCH_H 5
39
40
41 /*========================================================*/
42 /* Private types.                                         */
43 /*========================================================*/
44
45 /** GL_COLOR_COMBO_BUTTON Private fields */
46 struct _glColorComboButtonPrivate {
47
48         guint       color;
49         gboolean    is_default_flag;
50
51         guint       default_color;
52
53         GtkWidget  *button;
54         GtkWidget  *button_vbox;
55         GtkWidget  *swatch;
56         GtkWidget  *dropdown_button;
57
58         GtkWidget  *menu;
59 };
60
61 enum {
62         COLOR_CHANGED,
63         LAST_SIGNAL
64 };
65
66
67 /*========================================================*/
68 /* Private globals.                                       */
69 /*========================================================*/
70
71 static guint signals[LAST_SIGNAL] = {0};
72
73
74 /*========================================================*/
75 /* Private function prototypes.                           */
76 /*========================================================*/
77
78 static void
79 gl_color_combo_button_finalize (GObject *object);
80
81 static void
82 button_clicked_cb (glColorComboButton *this);
83
84 static gboolean
85 dropdown_button_press_event_cb (GtkWidget          *widget,
86                                 GdkEventButton     *event,
87                                 glColorComboButton *this);
88
89 static void
90 menu_color_changed_cb (glColorComboMenu            *object,
91                        guint                        color,
92                        gboolean                     is_default,
93                        glColorComboButton          *this);
94
95 static void
96 menu_selection_done_cb (GtkMenuShell               *object,
97                         glColorComboButton         *this);
98
99
100 /*****************************************************************************/
101 /* Object infrastructure.                                                    */
102 /*****************************************************************************/
103 G_DEFINE_TYPE (glColorComboButton, gl_color_combo_button, GTK_TYPE_HBOX);
104
105
106 /*****************************************************************************/
107 /* Class Init Function.                                                      */
108 /*****************************************************************************/
109 static void
110 gl_color_combo_button_class_init (glColorComboButtonClass *class)
111 {
112         GObjectClass            *gobject_class = (GObjectClass *) class;
113
114         gl_color_combo_button_parent_class = g_type_class_peek_parent (class);
115
116         gobject_class->finalize = gl_color_combo_button_finalize;
117
118         signals[COLOR_CHANGED] =
119                 g_signal_new ("color_changed",
120                               G_OBJECT_CLASS_TYPE (gobject_class),
121                               G_SIGNAL_RUN_LAST,
122                               G_STRUCT_OFFSET (glColorComboButtonClass, color_changed),
123                               NULL, NULL,
124                               gl_marshal_VOID__UINT_BOOLEAN,
125                               G_TYPE_NONE,
126                               2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
127
128 }
129
130
131 /*****************************************************************************/
132 /* Object Instance Init Function.                                            */
133 /*****************************************************************************/
134 static void
135 gl_color_combo_button_init (glColorComboButton *this)
136 {
137         GtkWidget *arrow;
138
139         gtk_box_set_spacing (GTK_BOX (this), 0);
140
141         this->priv = g_new0 (glColorComboButtonPrivate, 1);
142
143         this->priv->button_vbox = gtk_vbox_new (FALSE, 0);
144
145         this->priv->button = gtk_toggle_button_new ();
146         gtk_container_add (GTK_CONTAINER (this->priv->button), this->priv->button_vbox);
147         gtk_button_set_focus_on_click (GTK_BUTTON (this->priv->button), FALSE);
148         g_signal_connect_swapped (this->priv->button, "clicked",
149                           G_CALLBACK(button_clicked_cb), this);
150
151         gtk_box_pack_start (GTK_BOX (this), this->priv->button, FALSE, FALSE, 0);
152
153         this->priv->dropdown_button = gtk_toggle_button_new ();
154         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
155         gtk_container_add (GTK_CONTAINER (this->priv->dropdown_button), arrow);
156         gtk_button_set_relief (GTK_BUTTON (this->priv->dropdown_button), GTK_RELIEF_NONE);
157         gtk_button_set_focus_on_click (GTK_BUTTON (this->priv->dropdown_button), FALSE);
158         g_signal_connect (this->priv->dropdown_button, "button_press_event",
159                           G_CALLBACK(dropdown_button_press_event_cb), this);
160
161         gtk_box_pack_start (GTK_BOX (this), this->priv->dropdown_button, FALSE, FALSE, 0);
162 }
163
164
165 /*****************************************************************************/
166 /* Finalize Method.                                                          */
167 /*****************************************************************************/
168 static void
169 gl_color_combo_button_finalize (GObject *object)
170 {
171         glColorComboButton    *this;
172
173         g_return_if_fail (object && IS_GL_COLOR_COMBO_BUTTON (object));
174         this = GL_COLOR_COMBO_BUTTON (object);
175
176         g_object_ref_sink (this->priv->menu);
177         g_free (this->priv);
178
179         G_OBJECT_CLASS (gl_color_combo_button_parent_class)->finalize (object);
180 }
181
182
183 /*****************************************************************************/
184 /** New Object Generator.                                                    */
185 /*****************************************************************************/
186 GtkWidget *
187 gl_color_combo_button_new (GdkPixbuf    *icon,
188                            const gchar  *default_label,
189                            guint         default_color,
190                            guint         color)
191 {
192         glColorComboButton *this;
193         GdkPixbuf          *pixbuf;
194         GtkWidget          *wimage;
195
196         this = g_object_new (TYPE_GL_COLOR_COMBO_BUTTON, NULL);
197
198         if (!default_label)
199         {
200                 default_label = _("Default Color");
201         }
202
203         this->priv->default_color = default_color;
204         this->priv->color = color;
205
206         if (icon)
207         {
208                 pixbuf = gdk_pixbuf_new_subpixbuf (icon, 0, 0, IMAGE_W, IMAGE_H-SWATCH_H);
209                 wimage = gtk_image_new_from_pixbuf (pixbuf);
210                 g_object_unref (G_OBJECT (pixbuf));
211                 gtk_box_pack_start (GTK_BOX (this->priv->button_vbox), wimage, FALSE, FALSE, 0);
212
213                 this->priv->swatch = gl_color_swatch_new (IMAGE_W, SWATCH_H, color);
214         }
215         else
216         {
217                 this->priv->swatch = gl_color_swatch_new (IMAGE_W, IMAGE_H, color);
218         }
219         gtk_box_pack_start (GTK_BOX (this->priv->button_vbox), this->priv->swatch, FALSE, FALSE, 0);
220
221         this->priv->menu = gl_color_combo_menu_new (default_label, color);
222         gtk_widget_show_all (this->priv->menu);
223
224         g_signal_connect (this->priv->menu, "color_changed",
225                           G_CALLBACK (menu_color_changed_cb), this);
226         g_signal_connect (this->priv->menu, "selection_done",
227                           G_CALLBACK (menu_selection_done_cb), this);
228
229         return GTK_WIDGET (this);
230 }
231
232
233 /*****************************************************************************/
234 /* Set color.                                                                */
235 /*****************************************************************************/
236 void
237 gl_color_combo_button_set_color (glColorComboButton  *this,
238                                  guint                color)
239 {
240         this->priv->color = color;
241
242         gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch), color);
243 }
244
245
246 /*****************************************************************************/
247 /* Set to default color.                                                     */
248 /*****************************************************************************/
249 void
250 gl_color_combo_button_set_to_default (glColorComboButton  *this)
251 {
252         gl_color_combo_button_set_color (this, this->priv->default_color);
253 }
254
255 /*****************************************************************************/
256 /* Get color.                                                                */
257 /*****************************************************************************/
258 guint
259 gl_color_combo_button_get_color (glColorComboButton  *this,
260                                  gboolean            *is_default)
261 {
262         if (is_default)
263         {
264                 *is_default = this->priv->is_default_flag;
265         }
266
267         return this->priv->color;
268 }
269
270
271 /*****************************************************************************/
272 /** Set relief style.                                                        */
273 /*****************************************************************************/
274 void
275 gl_color_combo_button_set_relief( glColorComboButton  *this,
276                                   GtkReliefStyle       relief )
277 {
278         gtk_button_set_relief (GTK_BUTTON (this->priv->button), relief);
279 }
280
281
282 /*****************************************************************************/
283 /* Color button "clicked" callback.                                          */
284 /*****************************************************************************/
285 static void
286 button_clicked_cb( glColorComboButton *this )
287 {
288         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->button),
289                                       FALSE);
290
291         g_signal_emit (this, signals[COLOR_CHANGED], 0,
292                        this->priv->color,
293                        this->priv->is_default_flag);
294 }
295
296
297 /*****************************************************************************/
298 /* Menu positioning function.                                                */
299 /*****************************************************************************/
300 static void
301 menu_position_function (GtkMenu  *menu,
302                         gint     *x,
303                         gint     *y,
304                         gboolean *push_in,
305                         gpointer  user_data)
306 {
307         glColorComboButton *this = GL_COLOR_COMBO_BUTTON (user_data);
308         gint                x1, y1;
309         gint                menu_h, menu_w;
310
311         gdk_window_get_origin (GTK_WIDGET (this)->window, &x1, &y1);
312         *x = x1 + GTK_WIDGET (this)->allocation.x;
313         *y = y1 + GTK_WIDGET (this)->allocation.y +
314                 GTK_WIDGET (this)->allocation.height;
315                 
316         menu_h = this->priv->menu->allocation.height;
317         menu_w = this->priv->menu->allocation.width;
318
319         if ((*y + menu_h) > gdk_screen_height ())
320         {
321                 *y = y1 + GTK_WIDGET (this)->allocation.y - menu_h;
322                 if ( *y < 0 )
323                 {
324                         *y = gdk_screen_height () - menu_h;
325                 }
326         }
327
328         if ((*x + menu_w) > gdk_screen_width ())
329         {
330                 *x = gdk_screen_width () - menu_w;
331         }
332
333         *push_in = TRUE;
334 }
335
336
337 /*****************************************************************************/
338 /* Dropdown button "button_press_event" callback.                            */
339 /*****************************************************************************/
340 static gboolean
341 dropdown_button_press_event_cb (GtkWidget          *widget,
342                                 GdkEventButton     *event,
343                                 glColorComboButton *this)
344 {
345         switch (event->button)
346         {
347
348         case 1:
349                 g_signal_handlers_block_by_func (G_OBJECT (this->priv->button),
350                                                  button_clicked_cb, this);
351                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->button),
352                                               TRUE);
353                 g_signal_handlers_unblock_by_func (G_OBJECT (this->priv->button),
354                                                    button_clicked_cb, this);
355                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->dropdown_button),
356                                               TRUE);
357
358                 gtk_menu_popup (GTK_MENU (this->priv->menu),
359                                 NULL, NULL,
360                                 menu_position_function, this,
361                                 event->button, event->time);
362                 break;
363
364         default:
365                 break;
366
367         }
368
369         return FALSE;
370 }
371
372
373 /*****************************************************************************/
374 /* Menu "color changed" callback.                                            */
375 /*****************************************************************************/
376 static void
377 menu_color_changed_cb (glColorComboMenu   *object,
378                        guint               color,
379                        gboolean            is_default,
380                        glColorComboButton *this)
381 {
382         if (is_default)
383         {
384                 this->priv->color = this->priv->default_color;
385         }
386         else
387         {
388                 this->priv->color = color;
389         }
390         this->priv->is_default_flag = is_default;
391
392         gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch),
393                                    this->priv->color);
394
395         g_signal_emit (this, signals[COLOR_CHANGED], 0,
396                        this->priv->color,
397                        this->priv->is_default_flag);
398 }
399
400
401 /*****************************************************************************/
402 /* Menu "color changed" callback.                                            */
403 /*****************************************************************************/
404 static void
405 menu_selection_done_cb (GtkMenuShell       *object,
406                         glColorComboButton *this)
407 {
408         g_signal_handlers_block_by_func (G_OBJECT (this->priv->button),
409                                          button_clicked_cb, this);
410         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->button),
411                                       FALSE);
412         g_signal_handlers_unblock_by_func (G_OBJECT (this->priv->button),
413                                            button_clicked_cb, this);
414
415         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->dropdown_button),
416                                       FALSE);
417 }
418
419
420
421 /*
422  * Local Variables:       -- emacs
423  * mode: C                -- emacs
424  * c-basic-offset: 8      -- emacs
425  * tab-width: 8           -- emacs
426  * indent-tabs-mode: nil  -- emacs
427  * End:                   -- emacs
428  */