2 PSPPIRE --- A Graphical User Interface for PSPP
3 Copyright (C) 2005 Free Software Foundation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 This widget is a subclass of GtkEntry. It's an entry widget with a
23 button on the right hand side.
25 This code is heavily based upon the GtkSpinButton widget. Therefore
26 the copyright notice of that code is pasted below.
28 Please note however, this code is covered by the GPL, not the LGPL.
31 /* GTK - The GIMP Toolkit
32 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
34 * GtkSpinButton widget for GTK+
35 * Copyright (C) 1998 Lars Hamann and Stefan Jeske
37 * This library is free software; you can redistribute it and/or
38 * modify it under the terms of the GNU Lesser General Public
39 * License as published by the Free Software Foundation; either
40 * version 2 of the License, or (at your option) any later version.
42 * This library is distributed in the hope that it will be useful,
43 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45 * Lesser General Public License for more details.
47 * You should have received a copy of the GNU Lesser General Public
48 * License along with this library; if not, write to the
49 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
50 * Boston, MA 02111-1307, USA.
54 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
55 * file for a list of people on the GTK+ Team. See the ChangeLog
56 * files for a list of changes. These files are distributed with
57 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
62 #define _(msgid) gettext (msgid)
65 #include <gtk/gtksignal.h>
66 #include <gtk/gtkentry.h>
67 #include "customentry.h"
70 static void psppire_custom_entry_class_init (PsppireCustomEntryClass *klass);
71 static void psppire_custom_entry_init (PsppireCustomEntry *ce);
73 static GtkEntryClass *parent_class = NULL;
83 static guint custom_entry_signals[n_SIGNALS] = {0};
87 psppire_custom_entry_get_type (void)
89 static GType ce_type = 0;
93 static const GTypeInfo ce_info =
95 sizeof (PsppireCustomEntryClass),
97 NULL, /* base_finalize */
98 (GClassInitFunc) psppire_custom_entry_class_init,
99 NULL, /* class_finalize */
100 NULL, /* class_data */
101 sizeof (PsppireCustomEntry),
103 (GInstanceInitFunc) psppire_custom_entry_init,
106 ce_type = g_type_register_static (GTK_TYPE_ENTRY, "PsppireCustomEntry",
115 psppire_custom_entry_map (GtkWidget *widget)
117 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
119 GTK_WIDGET_CLASS (parent_class)->map (widget);
120 gdk_window_show (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
125 psppire_custom_entry_unmap (GtkWidget *widget)
127 if (GTK_WIDGET_MAPPED (widget))
129 gdk_window_hide (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
130 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
134 static gint psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry);
137 psppire_custom_entry_realize (GtkWidget *widget)
139 PsppireCustomEntry *custom_entry;
140 GdkWindowAttr attributes;
141 gint attributes_mask;
145 custom_entry = PSPPIRE_CUSTOM_ENTRY (widget);
147 button_size = psppire_custom_entry_get_button_width (custom_entry);
149 real_width = widget->allocation.width;
150 widget->allocation.width -= button_size + 2 * widget->style->xthickness;
151 gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
152 GDK_KEY_RELEASE_MASK);
153 GTK_WIDGET_CLASS (parent_class)->realize (widget);
155 widget->allocation.width = real_width;
157 attributes.window_type = GDK_WINDOW_CHILD;
158 attributes.wclass = GDK_INPUT_OUTPUT;
159 attributes.visual = gtk_widget_get_visual (widget);
160 attributes.colormap = gtk_widget_get_colormap (widget);
161 attributes.event_mask = gtk_widget_get_events (widget);
162 attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
163 | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
164 | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
166 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
168 attributes.x = (widget->allocation.x +
169 widget->allocation.width - button_size -
170 2 * widget->style->xthickness);
171 attributes.y = widget->allocation.y + (widget->allocation.height -
172 widget->requisition.height) / 2;
173 attributes.width = button_size + 2 * widget->style->xthickness;
174 attributes.height = widget->requisition.height;
176 custom_entry->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
177 &attributes, attributes_mask);
178 gdk_window_set_user_data (custom_entry->panel, widget);
180 gtk_style_set_background (widget->style, custom_entry->panel, GTK_STATE_NORMAL);
183 gtk_widget_queue_resize (GTK_WIDGET (custom_entry));
187 #define MIN_BUTTON_WIDTH 6
190 psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry)
192 const gint size = pango_font_description_get_size
193 (GTK_WIDGET (custom_entry)->style->font_desc);
195 gint button_width = MAX (PANGO_PIXELS (size), MIN_BUTTON_WIDTH);
197 return button_width - button_width % 2; /* force even */
201 * custom_entry_get_shadow_type:
202 * @custom_entry: a #PsppireCustomEntry
204 * Convenience function to Get the shadow type from the underlying widget's
207 * Return value: the #GtkShadowType
210 psppire_custom_entry_get_shadow_type (PsppireCustomEntry *custom_entry)
212 GtkShadowType rc_shadow_type;
214 gtk_widget_style_get (GTK_WIDGET (custom_entry), "shadow_type", &rc_shadow_type, NULL);
216 return rc_shadow_type;
221 psppire_custom_entry_unrealize (GtkWidget *widget)
223 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
225 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
229 gdk_window_set_user_data (ce->panel, NULL);
230 gdk_window_destroy (ce->panel);
237 psppire_custom_entry_redraw (PsppireCustomEntry *custom_entry)
241 widget = GTK_WIDGET (custom_entry);
243 if (GTK_WIDGET_DRAWABLE (widget))
245 gtk_widget_queue_draw (widget);
247 /* We must invalidate the panel window ourselves, because it
248 * is not a child of widget->window
250 gdk_window_invalidate_rect (custom_entry->panel, NULL, TRUE);
256 psppire_custom_entry_expose (GtkWidget *widget,
257 GdkEventExpose *event)
259 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
261 g_return_val_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget), FALSE);
262 g_return_val_if_fail (event != NULL, FALSE);
264 if (GTK_WIDGET_DRAWABLE (widget))
266 GtkShadowType shadow_type;
272 if (event->window != ce->panel)
273 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
275 gdk_drawable_get_size (ce->panel, &rect.width, &rect.height);
277 gdk_window_begin_paint_rect (ce->panel, &rect);
280 shadow_type = psppire_custom_entry_get_shadow_type (ce);
282 if (shadow_type != GTK_SHADOW_NONE)
284 gtk_paint_box (widget->style, ce->panel,
285 GTK_STATE_NORMAL, shadow_type,
286 NULL, widget, "customentry",
287 rect.x, rect.y, rect.width, rect.height);
291 gdk_window_end_paint (ce->panel);
299 psppire_custom_entry_button_press (GtkWidget *widget,
300 GdkEventButton *event);
303 psppire_custom_entry_size_allocate (GtkWidget *widget,
304 GtkAllocation *allocation);
309 psppire_custom_entry_class_init (PsppireCustomEntryClass *klass)
311 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
313 GtkWidgetClass *widget_class;
314 GtkEntryClass *entry_class;
316 parent_class = g_type_class_peek_parent (klass);
318 widget_class = (GtkWidgetClass*) klass;
319 entry_class = (GtkEntryClass*) klass;
321 widget_class->map = psppire_custom_entry_map;
322 widget_class->unmap = psppire_custom_entry_unmap;
324 widget_class->realize = psppire_custom_entry_realize;
325 widget_class->unrealize = psppire_custom_entry_unrealize;
327 widget_class->expose_event = psppire_custom_entry_expose;
328 widget_class->button_press_event = psppire_custom_entry_button_press;
330 widget_class->size_allocate = psppire_custom_entry_size_allocate;
333 gtk_widget_class_install_style_property_parser
335 g_param_spec_enum ("shadow_type",
337 _("Style of bevel around the custom entry button"),
338 GTK_TYPE_SHADOW_TYPE,
339 GTK_SHADOW_ETCHED_IN,
341 gtk_rc_property_parse_enum);
343 custom_entry_signals[CLICKED] =
344 g_signal_new ("clicked",
345 G_TYPE_FROM_CLASS (gobject_class),
349 g_cclosure_marshal_VOID__VOID,
357 psppire_custom_entry_init (PsppireCustomEntry *ce)
362 psppire_custom_entry_new ()
364 return GTK_WIDGET (g_object_new (psppire_custom_entry_get_type (), NULL));
370 psppire_custom_entry_button_press (GtkWidget *widget,
371 GdkEventButton *event)
373 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
375 if (event->window == ce->panel)
377 if (!GTK_WIDGET_HAS_FOCUS (widget))
378 gtk_widget_grab_focus (widget);
380 if ( event->button == 1)
381 g_signal_emit (widget, custom_entry_signals[CLICKED], 0);
385 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
393 psppire_custom_entry_size_allocate (GtkWidget *widget,
394 GtkAllocation *allocation)
396 PsppireCustomEntry *ce;
397 GtkAllocation entry_allocation;
398 GtkAllocation panel_allocation;
402 g_return_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget));
403 g_return_if_fail (allocation != NULL);
405 ce = PSPPIRE_CUSTOM_ENTRY (widget);
406 button_width = psppire_custom_entry_get_button_width (ce);
407 panel_width = button_width + 2 * widget->style->xthickness;
409 widget->allocation = *allocation;
411 entry_allocation = *allocation;
412 entry_allocation.width -= panel_width;
414 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
416 entry_allocation.x += panel_width;
417 panel_allocation.x = allocation->x;
421 panel_allocation.x = allocation->x + allocation->width - panel_width;
424 panel_allocation.width = panel_width;
425 panel_allocation.height = MIN (widget->requisition.height, allocation->height);
427 panel_allocation.y = allocation->y + (allocation->height -
428 panel_allocation.height) / 2;
430 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
432 if (GTK_WIDGET_REALIZED (widget))
434 gdk_window_move_resize (PSPPIRE_CUSTOM_ENTRY (widget)->panel,
437 panel_allocation.width,
438 panel_allocation.height);
441 psppire_custom_entry_redraw (ce);