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