1 /*
2 * color-combo.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.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
34 #define IMAGE_W 24
35 #define IMAGE_H 24
36
37
38 /*========================================================*/
39 /* Private types. */
40 /*========================================================*/
41
42 /** GL_COLOR_COMBO Private fields */
43 struct _glColorComboPrivate {
44
45 guint color;
46 gboolean is_default_flag;
47
48 guint default_color;
49
50 GtkWidget *swatch;
51
52 GtkWidget *menu;
53 };
54
55 enum {
56 COLOR_CHANGED,
57 LAST_SIGNAL
58 };
59
60
61 /*========================================================*/
62 /* Private globals. */
63 /*========================================================*/
64
65 static guint signals[LAST_SIGNAL] = {0};
66
67
68 /*========================================================*/
69 /* Private function prototypes. */
70 /*========================================================*/
71
72 static void gl_color_combo_finalize (GObject *object);
73
74 static gboolean
75 button_press_event_cb (GtkWidget *widget,
76 GdkEventButton *event,
77 glColorCombo *this);
78
79 static void
80 menu_color_changed_cb (glColorComboMenu *object,
81 guint color,
82 gboolean is_default,
83 glColorCombo *this);
84
85 static void
86 menu_selection_done_cb (GtkMenuShell *object,
87 glColorCombo *this);
88
89
90 /*****************************************************************************/
91 /* Object infrastructure. */
92 /*****************************************************************************/
G_DEFINE_TYPE(glColorCombo,gl_color_combo,GTK_TYPE_TOGGLE_BUTTON)93 G_DEFINE_TYPE (glColorCombo, gl_color_combo, GTK_TYPE_TOGGLE_BUTTON)
94
95
96 /*****************************************************************************/
97 /* Class Init Function. */
98 /*****************************************************************************/
99 static void
100 gl_color_combo_class_init (glColorComboClass *class)
101 {
102 GObjectClass *gobject_class = (GObjectClass *) class;
103
104 gl_color_combo_parent_class = g_type_class_peek_parent (class);
105
106 gobject_class->finalize = gl_color_combo_finalize;
107
108 signals[COLOR_CHANGED] =
109 g_signal_new ("color_changed",
110 G_OBJECT_CLASS_TYPE (gobject_class),
111 G_SIGNAL_RUN_LAST,
112 G_STRUCT_OFFSET (glColorComboClass, color_changed),
113 NULL, NULL,
114 gl_marshal_VOID__UINT_BOOLEAN,
115 G_TYPE_NONE,
116 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
117
118 }
119
120
121 /*****************************************************************************/
122 /* Object Instance Init Function. */
123 /*****************************************************************************/
124 static void
gl_color_combo_init(glColorCombo * this)125 gl_color_combo_init (glColorCombo *this)
126 {
127 GtkWidget *hbox;
128 GtkWidget *arrow;
129
130 this->priv = g_new0 (glColorComboPrivate, 1);
131
132 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
133 gtk_container_add (GTK_CONTAINER (this), hbox);
134
135 this->priv->swatch = gl_color_swatch_new (IMAGE_W, IMAGE_H, GL_COLOR_NONE);
136 gtk_box_pack_start (GTK_BOX (hbox), this->priv->swatch, TRUE, TRUE, 0);
137
138 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
139 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
140
141 g_signal_connect (this, "button_press_event",
142 G_CALLBACK(button_press_event_cb), this);
143 }
144
145
146 /*****************************************************************************/
147 /* Finalize Method. */
148 /*****************************************************************************/
149 static void
gl_color_combo_finalize(GObject * object)150 gl_color_combo_finalize (GObject *object)
151 {
152 glColorCombo *this;
153
154 g_return_if_fail (object && IS_GL_COLOR_COMBO (object));
155 this = GL_COLOR_COMBO (object);
156
157 g_object_ref_sink (this->priv->menu);
158 g_free (this->priv);
159
160 G_OBJECT_CLASS (gl_color_combo_parent_class)->finalize (object);
161 }
162
163
164 /*****************************************************************************/
165 /** New Object Generator. */
166 /*****************************************************************************/
167 GtkWidget *
gl_color_combo_new(const gchar * default_label,guint default_color,guint color)168 gl_color_combo_new (const gchar *default_label,
169 guint default_color,
170 guint color)
171 {
172 glColorCombo *this;
173
174 this = g_object_new (TYPE_GL_COLOR_COMBO, NULL);
175
176 if (!default_label)
177 {
178 default_label = _("Default Color");
179 }
180
181 this->priv->default_color = default_color;
182 this->priv->color = color;
183
184 gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch), color);
185
186 this->priv->menu = gl_color_combo_menu_new (default_label,
187 color);
188 gtk_widget_show_all (this->priv->menu);
189
190 g_signal_connect (this->priv->menu, "color_changed",
191 G_CALLBACK (menu_color_changed_cb), this);
192 g_signal_connect (this->priv->menu, "selection_done",
193 G_CALLBACK (menu_selection_done_cb), this);
194
195 return GTK_WIDGET (this);
196 }
197
198
199 /*****************************************************************************/
200 /* Set color. */
201 /*****************************************************************************/
202 void
gl_color_combo_set_color(glColorCombo * this,guint color)203 gl_color_combo_set_color (glColorCombo *this,
204 guint color)
205 {
206 this->priv->color = color;
207
208 gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch), color);
209 }
210
211
212 /*****************************************************************************/
213 /* Set to default color. */
214 /*****************************************************************************/
215 void
gl_color_combo_set_to_default(glColorCombo * this)216 gl_color_combo_set_to_default (glColorCombo *this)
217 {
218 gl_color_combo_set_color (this, this->priv->default_color);
219 }
220
221 /*****************************************************************************/
222 /* Get color. */
223 /*****************************************************************************/
224 guint
gl_color_combo_get_color(glColorCombo * this,gboolean * is_default)225 gl_color_combo_get_color (glColorCombo *this,
226 gboolean *is_default)
227 {
228 if (is_default)
229 {
230 *is_default = this->priv->is_default_flag;
231 }
232
233 return this->priv->color;
234 }
235
236
237 /*****************************************************************************/
238 /* Menu positioning function. */
239 /*****************************************************************************/
240 static void
menu_position_function(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,glColorCombo * this)241 menu_position_function (GtkMenu *menu,
242 gint *x,
243 gint *y,
244 gboolean *push_in,
245 glColorCombo *this)
246 {
247 GdkScreen *screen;
248 gint w_screen, h_screen;
249 GdkWindow *window;
250 gint x_window, y_window;
251 GtkAllocation allocation;
252 gint x_this, y_this, h_this;
253 GtkRequisition menu_requisition;
254 gint h_menu, w_menu;
255
256 /*
257 * Screen size
258 */
259 screen = gtk_widget_get_screen (GTK_WIDGET (this));
260 w_screen = gdk_screen_get_width (screen);
261 h_screen = gdk_screen_get_height (screen);
262
263 /*
264 * Absolute position of "this" window on screen.
265 */
266 window = gtk_widget_get_window (GTK_WIDGET (this));
267 gdk_window_get_origin (window, &x_window, &y_window);
268
269 /*
270 * Position and size of "this" inside window
271 */
272 gtk_widget_get_allocation (GTK_WIDGET (this), &allocation);
273 x_this = allocation.x;
274 y_this = allocation.y;
275 h_this = allocation.height;
276
277 /*
278 * Size of menu.
279 */
280 gtk_widget_get_preferred_size (this->priv->menu, NULL, &menu_requisition);
281 h_menu = menu_requisition.height;
282 w_menu = menu_requisition.width;
283
284 /*
285 * Default position anchored to lower left corner of "this".
286 */
287 *x = x_window + x_this;
288 *y = y_window + y_this + h_this;
289
290 /*
291 * Adjust vertical position if menu if extends past bottom of screen.
292 */
293 if ( (*y + h_menu) > h_screen )
294 {
295 *y = y_window + y_this - h_menu;
296
297 if ( *y < 0 )
298 {
299 *y = h_screen - h_menu;
300 }
301 }
302
303 /*
304 * Adjust horizontal position if menu if extends past edge of screen.
305 */
306 if ( (*x + w_menu) > w_screen )
307 {
308 *x = w_screen - w_menu;
309 }
310
311
312 *push_in = TRUE;
313 }
314
315
316 /*****************************************************************************/
317 /* Button "button_press_event" callback. */
318 /*****************************************************************************/
319 static gboolean
button_press_event_cb(GtkWidget * widget,GdkEventButton * event,glColorCombo * this)320 button_press_event_cb (GtkWidget *widget,
321 GdkEventButton *event,
322 glColorCombo *this)
323 {
324 switch (event->button)
325 {
326
327 case 1:
328 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this), TRUE);
329
330 gtk_menu_popup (GTK_MENU (this->priv->menu),
331 NULL, NULL,
332 (GtkMenuPositionFunc)menu_position_function, this,
333 event->button, event->time);
334 break;
335
336 default:
337 break;
338
339 }
340
341 return FALSE;
342 }
343
344
345 /*****************************************************************************/
346 /* Menu "color changed" callback. */
347 /*****************************************************************************/
348 static void
menu_color_changed_cb(glColorComboMenu * object,guint color,gboolean is_default,glColorCombo * this)349 menu_color_changed_cb (glColorComboMenu *object,
350 guint color,
351 gboolean is_default,
352 glColorCombo *this)
353 {
354 if (is_default)
355 {
356 this->priv->color = this->priv->default_color;
357 }
358 else
359 {
360 this->priv->color = color;
361 }
362 this->priv->is_default_flag = is_default;
363
364 gl_color_swatch_set_color (GL_COLOR_SWATCH (this->priv->swatch),
365 this->priv->color);
366
367 g_signal_emit (this, signals[COLOR_CHANGED], 0,
368 this->priv->color,
369 this->priv->is_default_flag);
370 }
371
372
373 /*****************************************************************************/
374 /* Menu "color changed" callback. */
375 /*****************************************************************************/
376 static void
menu_selection_done_cb(GtkMenuShell * object,glColorCombo * this)377 menu_selection_done_cb (GtkMenuShell *object,
378 glColorCombo *this)
379 {
380 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this), FALSE);
381 }
382
383
384
385 /*
386 * Local Variables: -- emacs
387 * mode: C -- emacs
388 * c-basic-offset: 8 -- emacs
389 * tab-width: 8 -- emacs
390 * indent-tabs-mode: nil -- emacs
391 * End: -- emacs
392 */
393