]> git.sur5r.net Git - glabels/blob - src/color-combo-button.c
Imported Upstream version 3.2.0
[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_box_new (GTK_ORIENTATION_VERTICAL, 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 (const gchar  *icon_name,
186                            const gchar  *default_label,
187                            guint         default_color,
188                            guint         color)
189 {
190         glColorComboButton *this;
191         GtkWidget          *wimage;
192         GdkPixbuf          *pixbuf1, *pixbuf2;
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_name)
205         {
206                 pixbuf1 = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
207                                                     icon_name, IMAGE_W, 0, NULL);
208                 pixbuf2 = gdk_pixbuf_new_subpixbuf (pixbuf1, 0, 0, IMAGE_W, IMAGE_H-SWATCH_H);
209
210                 wimage = gtk_image_new_from_pixbuf (pixbuf2);
211                 g_object_unref (G_OBJECT (pixbuf1));
212                 g_object_unref (G_OBJECT (pixbuf2));
213                 gtk_box_pack_start (GTK_BOX (this->priv->button_vbox), wimage, FALSE, FALSE, 0);
214
215                 this->priv->swatch = gl_color_swatch_new (IMAGE_W, SWATCH_H, color);
216         }
217         else
218         {
219                 this->priv->swatch = gl_color_swatch_new (IMAGE_W, IMAGE_H, color);
220         }
221         gtk_box_pack_start (GTK_BOX (this->priv->button_vbox), this->priv->swatch, FALSE, FALSE, 0);
222
223         this->priv->menu = gl_color_combo_menu_new (default_label, color);
224         gtk_widget_show_all (this->priv->menu);
225
226         g_signal_connect (this->priv->menu, "color_changed",
227                           G_CALLBACK (menu_color_changed_cb), this);
228         g_signal_connect (this->priv->menu, "selection_done",
229                           G_CALLBACK (menu_selection_done_cb), this);
230
231         return GTK_WIDGET (this);
232 }
233
234
235 /*****************************************************************************/
236 /* Set color.                                                                */
237 /*****************************************************************************/
238 void
239 gl_color_combo_button_set_color (glColorComboButton  *this,
240                                  guint                color)
241 {
242         this->priv->color = color;
243
244         gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch), color);
245 }
246
247
248 /*****************************************************************************/
249 /* Set to default color.                                                     */
250 /*****************************************************************************/
251 void
252 gl_color_combo_button_set_to_default (glColorComboButton  *this)
253 {
254         gl_color_combo_button_set_color (this, this->priv->default_color);
255 }
256
257 /*****************************************************************************/
258 /* Get color.                                                                */
259 /*****************************************************************************/
260 guint
261 gl_color_combo_button_get_color (glColorComboButton  *this,
262                                  gboolean            *is_default)
263 {
264         if (is_default)
265         {
266                 *is_default = this->priv->is_default_flag;
267         }
268
269         return this->priv->color;
270 }
271
272
273 /*****************************************************************************/
274 /** Set relief style.                                                        */
275 /*****************************************************************************/
276 void
277 gl_color_combo_button_set_relief( glColorComboButton  *this,
278                                   GtkReliefStyle       relief )
279 {
280         gtk_button_set_relief (GTK_BUTTON (this->priv->button), relief);
281 }
282
283
284 /*****************************************************************************/
285 /* Color button "clicked" callback.                                          */
286 /*****************************************************************************/
287 static void
288 button_clicked_cb( glColorComboButton *this )
289 {
290         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->button),
291                                       FALSE);
292
293         g_signal_emit (this, signals[COLOR_CHANGED], 0,
294                        this->priv->color,
295                        this->priv->is_default_flag);
296 }
297
298
299 /*****************************************************************************/
300 /* Menu positioning function.                                                */
301 /*****************************************************************************/
302 static void
303 menu_position_function (GtkMenu            *menu,
304                         gint               *x,
305                         gint               *y,
306                         gboolean           *push_in,
307                         glColorComboButton *this)
308 {
309         GdkScreen          *screen;
310         gint                w_screen, h_screen;
311         GdkWindow          *window;
312         gint                x_window, y_window;
313         GtkAllocation       allocation;
314         gint                x_this, y_this, h_this;
315         GtkRequisition      menu_requisition;
316         gint                h_menu, w_menu;
317
318         /*
319          * Screen size
320          */
321         screen = gtk_widget_get_screen (GTK_WIDGET (this));
322         w_screen = gdk_screen_get_width (screen);
323         h_screen = gdk_screen_get_height (screen);
324
325         /*
326          * Absolute position of "this" window on screen.
327          */
328         window = gtk_widget_get_window (GTK_WIDGET (this));
329         gdk_window_get_origin (window, &x_window, &y_window);
330
331         /*
332          *  Position and size of "this" inside window
333          */
334         gtk_widget_get_allocation (GTK_WIDGET (this), &allocation);
335         x_this = allocation.x;
336         y_this = allocation.y;
337         h_this = allocation.height;
338
339         /*
340          * Size of menu.
341          */
342         gtk_widget_get_preferred_size (this->priv->menu, NULL, &menu_requisition);
343         h_menu = menu_requisition.height;
344         w_menu = menu_requisition.width;
345
346         /*
347          * Default position anchored to lower left corner of "this".
348          */
349         *x = x_window + x_this;
350         *y = y_window + y_this + h_this;
351                 
352         /*
353          * Adjust vertical position if menu if extends past bottom of screen.
354          */
355         if ( (*y + h_menu) > h_screen )
356         {
357                 *y = y_window + y_this - h_menu;
358
359                 if ( *y < 0 )
360                 {
361                         *y = h_screen - h_menu;
362                 }
363         }
364
365         /*
366          * Adjust horizontal position if menu if extends past edge of screen.
367          */
368         if ( (*x + w_menu) > w_screen )
369         {
370                 *x = w_screen - w_menu;
371         }
372
373
374         *push_in = TRUE;
375 }
376
377
378 /*****************************************************************************/
379 /* Dropdown button "button_press_event" callback.                            */
380 /*****************************************************************************/
381 static gboolean
382 dropdown_button_press_event_cb (GtkWidget          *widget,
383                                 GdkEventButton     *event,
384                                 glColorComboButton *this)
385 {
386         switch (event->button)
387         {
388
389         case 1:
390                 g_signal_handlers_block_by_func (G_OBJECT (this->priv->button),
391                                                  button_clicked_cb, this);
392                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->button),
393                                               TRUE);
394                 g_signal_handlers_unblock_by_func (G_OBJECT (this->priv->button),
395                                                    button_clicked_cb, this);
396                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->dropdown_button),
397                                               TRUE);
398
399                 gtk_menu_popup (GTK_MENU (this->priv->menu),
400                                 NULL, NULL,
401                                 (GtkMenuPositionFunc)menu_position_function, this,
402                                 event->button, event->time);
403                 break;
404
405         default:
406                 break;
407
408         }
409
410         return FALSE;
411 }
412
413
414 /*****************************************************************************/
415 /* Menu "color changed" callback.                                            */
416 /*****************************************************************************/
417 static void
418 menu_color_changed_cb (glColorComboMenu   *object,
419                        guint               color,
420                        gboolean            is_default,
421                        glColorComboButton *this)
422 {
423         if (is_default)
424         {
425                 this->priv->color = this->priv->default_color;
426         }
427         else
428         {
429                 this->priv->color = color;
430         }
431         this->priv->is_default_flag = is_default;
432
433         gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch),
434                                    this->priv->color);
435
436         g_signal_emit (this, signals[COLOR_CHANGED], 0,
437                        this->priv->color,
438                        this->priv->is_default_flag);
439 }
440
441
442 /*****************************************************************************/
443 /* Menu "color changed" callback.                                            */
444 /*****************************************************************************/
445 static void
446 menu_selection_done_cb (GtkMenuShell       *object,
447                         glColorComboButton *this)
448 {
449         g_signal_handlers_block_by_func (G_OBJECT (this->priv->button),
450                                          button_clicked_cb, this);
451         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->button),
452                                       FALSE);
453         g_signal_handlers_unblock_by_func (G_OBJECT (this->priv->button),
454                                            button_clicked_cb, this);
455
456         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this->priv->dropdown_button),
457                                       FALSE);
458 }
459
460
461
462 /*
463  * Local Variables:       -- emacs
464  * mode: C                -- emacs
465  * c-basic-offset: 8      -- emacs
466  * tab-width: 8           -- emacs
467  * indent-tabs-mode: nil  -- emacs
468  * End:                   -- emacs
469  */