3 * Copyright (C) 2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
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.
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.
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/>.
23 #include "field-button.h"
25 #include <glib/gi18n.h>
28 #include "field-button-menu.h"
33 /*========================================================*/
35 /*========================================================*/
37 /** GL_FIELD_BUTTON Private fields */
38 struct _glFieldButtonPrivate {
40 gboolean label_is_key;
55 /*========================================================*/
56 /* Private globals. */
57 /*========================================================*/
59 static guint signals[LAST_SIGNAL] = {0};
62 /*========================================================*/
63 /* Private function prototypes. */
64 /*========================================================*/
66 static void gl_field_button_finalize (GObject *object);
69 button_press_event_cb (GtkWidget *widget,
70 GdkEventButton *event,
74 menu_key_selected_cb (glFieldButtonMenu *menu,
79 menu_selection_done_cb (GtkMenuShell *object,
83 /*****************************************************************************/
84 /* Object infrastructure. */
85 /*****************************************************************************/
86 G_DEFINE_TYPE (glFieldButton, gl_field_button, GTK_TYPE_TOGGLE_BUTTON)
89 /*****************************************************************************/
90 /* Class Init Function. */
91 /*****************************************************************************/
93 gl_field_button_class_init (glFieldButtonClass *class)
95 GObjectClass *gobject_class = (GObjectClass *) class;
97 gl_field_button_parent_class = g_type_class_peek_parent (class);
99 gobject_class->finalize = gl_field_button_finalize;
101 signals[KEY_SELECTED] =
102 g_signal_new ("key_selected",
103 G_OBJECT_CLASS_TYPE (gobject_class),
105 G_STRUCT_OFFSET (glFieldButtonClass, key_selected),
107 gl_marshal_VOID__STRING,
108 G_TYPE_NONE, 1, G_TYPE_STRING);
111 g_signal_new ("changed",
112 G_OBJECT_CLASS_TYPE (gobject_class),
114 G_STRUCT_OFFSET (glFieldButtonClass, changed),
116 gl_marshal_VOID__VOID,
121 /*****************************************************************************/
122 /* Object Instance Init Function. */
123 /*****************************************************************************/
125 gl_field_button_init (glFieldButton *this)
130 this->priv = g_new0 (glFieldButtonPrivate, 1);
132 hbox = gtk_hbox_new (FALSE, 3);
133 gtk_container_add (GTK_CONTAINER (this), hbox);
135 this->priv->label = gtk_label_new ("");
136 gtk_misc_set_alignment (GTK_MISC (this->priv->label), 0.0, 0.5);
137 gtk_box_pack_start (GTK_BOX (hbox), this->priv->label, TRUE, TRUE, 0);
139 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
140 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
142 g_signal_connect (this, "button_press_event",
143 G_CALLBACK(button_press_event_cb), this);
147 /*****************************************************************************/
148 /* Finalize Method. */
149 /*****************************************************************************/
151 gl_field_button_finalize (GObject *object)
155 g_return_if_fail (object && IS_GL_FIELD_BUTTON (object));
156 this = GL_FIELD_BUTTON (object);
158 g_object_ref_sink (this->priv->menu);
161 G_OBJECT_CLASS (gl_field_button_parent_class)->finalize (object);
165 /*****************************************************************************/
166 /** New Object Generator. */
167 /*****************************************************************************/
169 gl_field_button_new (const gchar *name)
173 this = g_object_new (TYPE_GL_FIELD_BUTTON, NULL);
177 gtk_label_set_text (GTK_LABEL (this->priv->label), name);
181 this->priv->label_is_key = TRUE;
184 this->priv->menu = gl_field_button_menu_new ();
186 gtk_widget_show_all (this->priv->menu);
188 g_signal_connect (this->priv->menu, "key_selected",
189 G_CALLBACK (menu_key_selected_cb), this);
190 g_signal_connect (this->priv->menu, "selection_done",
191 G_CALLBACK (menu_selection_done_cb), this);
193 return GTK_WIDGET (this);
197 /*****************************************************************************/
199 /*****************************************************************************/
201 gl_field_button_set_keys (glFieldButton *this,
204 gl_field_button_menu_set_keys (GL_FIELD_BUTTON_MENU (this->priv->menu),
206 this->priv->key = g_strdup (key_list->data);
207 if ( this->priv->label_is_key )
209 gtk_label_set_text (GTK_LABEL (this->priv->label), key_list->data);
212 gtk_widget_show_all (this->priv->menu);
216 /*****************************************************************************/
217 /* Set current key. */
218 /*****************************************************************************/
220 gl_field_button_set_key (glFieldButton *this,
223 g_free (this->priv->key);
224 this->priv->key = g_strdup (key);
226 if ( this->priv->label_is_key )
228 gtk_label_set_text (GTK_LABEL (this->priv->label), key);
233 /*****************************************************************************/
234 /* Get current key. */
235 /*****************************************************************************/
237 gl_field_button_get_key (glFieldButton *this)
239 return g_strdup (this->priv->key);
243 /*****************************************************************************/
244 /* Menu positioning function. */
245 /*****************************************************************************/
247 menu_position_function (GtkMenu *menu,
254 gint w_screen, h_screen;
256 gint x_window, y_window;
257 GtkAllocation allocation;
258 gint x_this, y_this, h_this;
259 GtkRequisition menu_requisition;
265 screen = gtk_widget_get_screen (GTK_WIDGET (this));
266 w_screen = gdk_screen_get_width (screen);
267 h_screen = gdk_screen_get_height (screen);
270 * Absolute position of "this" window on screen.
272 window = gtk_widget_get_window (GTK_WIDGET (this));
273 gdk_window_get_origin (window, &x_window, &y_window);
276 * Position and size of "this" inside window
278 gtk_widget_get_allocation (GTK_WIDGET (this), &allocation);
279 x_this = allocation.x;
280 y_this = allocation.y;
281 h_this = allocation.height;
286 gtk_widget_size_request (this->priv->menu, &menu_requisition);
287 h_menu = menu_requisition.height;
288 w_menu = menu_requisition.width;
291 * Default position anchored to lower left corner of "this".
293 *x = x_window + x_this;
294 *y = y_window + y_this + h_this;
297 * Adjust vertical position if menu if extends past bottom of screen.
299 if ( (*y + h_menu) > h_screen )
301 *y = y_window + y_this - h_menu;
305 *y = h_screen - h_menu;
310 * Adjust horizontal position if menu if extends past edge of screen.
312 if ( (*x + w_menu) > w_screen )
314 *x = w_screen - w_menu;
322 /*****************************************************************************/
323 /* Button "button_press_event" callback. */
324 /*****************************************************************************/
326 button_press_event_cb (GtkWidget *widget,
327 GdkEventButton *event,
330 switch (event->button)
334 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this), TRUE);
336 gtk_menu_popup (GTK_MENU (this->priv->menu),
338 (GtkMenuPositionFunc)menu_position_function, this,
339 event->button, event->time);
351 /*****************************************************************************/
352 /* Menu "key selected" callback. */
353 /*****************************************************************************/
355 menu_key_selected_cb (glFieldButtonMenu *menu,
359 if (this->priv->label_is_key)
361 gtk_label_set_text (GTK_LABEL (this->priv->label), key);
364 g_free (this->priv->key);
365 this->priv->key = g_strdup (key);
367 g_signal_emit (this, signals[KEY_SELECTED], 0, key);
368 g_signal_emit (this, signals[CHANGED], 0);
372 /*****************************************************************************/
373 /* Menu "selection done" callback. */
374 /*****************************************************************************/
376 menu_selection_done_cb (GtkMenuShell *object,
379 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (this), FALSE);
385 * Local Variables: -- emacs
387 * c-basic-offset: 8 -- emacs
388 * tab-width: 8 -- emacs
389 * indent-tabs-mode: nil -- emacs