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