2 PSPPIRE --- A Graphical User Interface for PSPP
3 Copyright (C) 2005 Free Software Foundation
4 Written by John Darrington
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 This widget is a subclass of GtkEntry. It's an entry widget with a
24 button on the right hand side.
26 This code is heavily based upon the GtkSpinButton widget. Therefore
27 the copyright notice of that code is pasted below.
29 Please note however, this code is covered by the GPL, not the LGPL.
32 /* GTK - The GIMP Toolkit
33 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
35 * GtkSpinButton widget for GTK+
36 * Copyright (C) 1998 Lars Hamann and Stefan Jeske
38 * This library is free software; you can redistribute it and/or
39 * modify it under the terms of the GNU Lesser General Public
40 * License as published by the Free Software Foundation; either
41 * version 2 of the License, or (at your option) any later version.
43 * This library is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
46 * Lesser General Public License for more details.
48 * You should have received a copy of the GNU Lesser General Public
49 * License along with this library; if not, write to the
50 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
51 * Boston, MA 02111-1307, USA.
55 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
56 * file for a list of people on the GTK+ Team. See the ChangeLog
57 * files for a list of changes. These files are distributed with
58 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
61 #include <gtk/gtksignal.h>
62 #include <gtk/gtkentry.h>
63 #include "customentry.h"
67 static void psppire_custom_entry_class_init (PsppireCustomEntryClass *klass);
68 static void psppire_custom_entry_init (PsppireCustomEntry *ce);
70 static GtkEntryClass *parent_class = NULL;
80 static guint custom_entry_signals[n_SIGNALS] = {0};
84 psppire_custom_entry_get_type (void)
86 static GType ce_type = 0;
90 static const GTypeInfo ce_info =
92 sizeof (PsppireCustomEntryClass),
94 NULL, /* base_finalize */
95 (GClassInitFunc) psppire_custom_entry_class_init,
96 NULL, /* class_finalize */
97 NULL, /* class_data */
98 sizeof (PsppireCustomEntry),
100 (GInstanceInitFunc) psppire_custom_entry_init,
103 ce_type = g_type_register_static (GTK_TYPE_ENTRY, "PsppireCustomEntry",
112 psppire_custom_entry_map (GtkWidget *widget)
114 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
116 GTK_WIDGET_CLASS (parent_class)->map (widget);
117 gdk_window_show (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
122 psppire_custom_entry_unmap (GtkWidget *widget)
124 if (GTK_WIDGET_MAPPED (widget))
126 gdk_window_hide (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
127 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
131 static gint psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry);
134 psppire_custom_entry_realize (GtkWidget *widget)
136 PsppireCustomEntry *custom_entry;
137 GdkWindowAttr attributes;
138 gint attributes_mask;
142 custom_entry = PSPPIRE_CUSTOM_ENTRY (widget);
144 button_size = psppire_custom_entry_get_button_width (custom_entry);
146 real_width = widget->allocation.width;
147 widget->allocation.width -= button_size + 2 * widget->style->xthickness;
148 gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
149 GDK_KEY_RELEASE_MASK);
150 GTK_WIDGET_CLASS (parent_class)->realize (widget);
152 widget->allocation.width = real_width;
154 attributes.window_type = GDK_WINDOW_CHILD;
155 attributes.wclass = GDK_INPUT_OUTPUT;
156 attributes.visual = gtk_widget_get_visual (widget);
157 attributes.colormap = gtk_widget_get_colormap (widget);
158 attributes.event_mask = gtk_widget_get_events (widget);
159 attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
160 | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
161 | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
163 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
165 attributes.x = (widget->allocation.x +
166 widget->allocation.width - button_size -
167 2 * widget->style->xthickness);
168 attributes.y = widget->allocation.y + (widget->allocation.height -
169 widget->requisition.height) / 2;
170 attributes.width = button_size + 2 * widget->style->xthickness;
171 attributes.height = widget->requisition.height;
173 custom_entry->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
174 &attributes, attributes_mask);
175 gdk_window_set_user_data (custom_entry->panel, widget);
177 gtk_style_set_background (widget->style, custom_entry->panel, GTK_STATE_NORMAL);
180 gtk_widget_queue_resize (GTK_WIDGET (custom_entry));
184 #define MIN_BUTTON_WIDTH 6
187 psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry)
189 const gint size = pango_font_description_get_size
190 (GTK_WIDGET (custom_entry)->style->font_desc);
192 gint button_width = MAX (PANGO_PIXELS (size), MIN_BUTTON_WIDTH);
194 return button_width - button_width % 2; /* force even */
198 * custom_entry_get_shadow_type:
199 * @custom_entry: a #PsppireCustomEntry
201 * Convenience function to Get the shadow type from the underlying widget's
204 * Return value: the #GtkShadowType
207 psppire_custom_entry_get_shadow_type (PsppireCustomEntry *custom_entry)
209 GtkShadowType rc_shadow_type;
211 gtk_widget_style_get (GTK_WIDGET (custom_entry), "shadow_type", &rc_shadow_type, NULL);
213 return rc_shadow_type;
218 psppire_custom_entry_unrealize (GtkWidget *widget)
220 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
222 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
226 gdk_window_set_user_data (ce->panel, NULL);
227 gdk_window_destroy (ce->panel);
234 psppire_custom_entry_redraw (PsppireCustomEntry *custom_entry)
238 widget = GTK_WIDGET (custom_entry);
240 if (GTK_WIDGET_DRAWABLE (widget))
242 gtk_widget_queue_draw (widget);
244 /* We must invalidate the panel window ourselves, because it
245 * is not a child of widget->window
247 gdk_window_invalidate_rect (custom_entry->panel, NULL, TRUE);
253 psppire_custom_entry_expose (GtkWidget *widget,
254 GdkEventExpose *event)
256 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY(widget);
258 g_return_val_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget), FALSE);
259 g_return_val_if_fail (event != NULL, FALSE);
261 if (GTK_WIDGET_DRAWABLE (widget))
263 GtkShadowType shadow_type;
269 if (event->window != ce->panel)
270 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
272 gdk_drawable_get_size (ce->panel, &rect.width, &rect.height);
274 gdk_window_begin_paint_rect (ce->panel, &rect);
277 shadow_type = psppire_custom_entry_get_shadow_type (ce);
279 if (shadow_type != GTK_SHADOW_NONE)
281 gtk_paint_box (widget->style, ce->panel,
282 GTK_STATE_NORMAL, shadow_type,
283 NULL, widget, "customentry",
284 rect.x, rect.y, rect.width, rect.height);
288 gdk_window_end_paint (ce->panel);
296 psppire_custom_entry_button_press (GtkWidget *widget,
297 GdkEventButton *event);
300 psppire_custom_entry_size_allocate (GtkWidget *widget,
301 GtkAllocation *allocation);
306 psppire_custom_entry_class_init (PsppireCustomEntryClass *klass)
308 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
310 GtkWidgetClass *widget_class;
311 GtkEntryClass *entry_class;
313 parent_class = g_type_class_peek_parent (klass);
315 widget_class = (GtkWidgetClass*) klass;
316 entry_class = (GtkEntryClass*) klass;
318 widget_class->map = psppire_custom_entry_map;
319 widget_class->unmap = psppire_custom_entry_unmap;
321 widget_class->realize = psppire_custom_entry_realize;
322 widget_class->unrealize = psppire_custom_entry_unrealize;
324 widget_class->expose_event = psppire_custom_entry_expose;
325 widget_class->button_press_event = psppire_custom_entry_button_press;
327 widget_class->size_allocate = psppire_custom_entry_size_allocate;
330 gtk_widget_class_install_style_property_parser
332 g_param_spec_enum ("shadow_type",
334 P_("Style of bevel around the custom entry button"),
335 GTK_TYPE_SHADOW_TYPE,
336 GTK_SHADOW_ETCHED_IN,
338 gtk_rc_property_parse_enum);
340 custom_entry_signals[CLICKED] =
341 g_signal_new ("clicked",
342 G_TYPE_FROM_CLASS(gobject_class),
346 g_cclosure_marshal_VOID__VOID,
354 psppire_custom_entry_init (PsppireCustomEntry *ce)
359 psppire_custom_entry_new ()
361 return GTK_WIDGET (g_object_new (psppire_custom_entry_get_type (), NULL));
367 psppire_custom_entry_button_press (GtkWidget *widget,
368 GdkEventButton *event)
370 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
372 if (event->window == ce->panel)
374 if (!GTK_WIDGET_HAS_FOCUS (widget))
375 gtk_widget_grab_focus (widget);
377 if ( event->button == 1)
378 g_signal_emit (widget, custom_entry_signals[CLICKED], 0);
382 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
390 psppire_custom_entry_size_allocate (GtkWidget *widget,
391 GtkAllocation *allocation)
393 PsppireCustomEntry *ce;
394 GtkAllocation entry_allocation;
395 GtkAllocation panel_allocation;
399 g_return_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget));
400 g_return_if_fail (allocation != NULL);
402 ce = PSPPIRE_CUSTOM_ENTRY (widget);
403 button_width = psppire_custom_entry_get_button_width(ce);
404 panel_width = button_width + 2 * widget->style->xthickness;
406 widget->allocation = *allocation;
408 entry_allocation = *allocation;
409 entry_allocation.width -= panel_width;
411 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
413 entry_allocation.x += panel_width;
414 panel_allocation.x = allocation->x;
418 panel_allocation.x = allocation->x + allocation->width - panel_width;
421 panel_allocation.width = panel_width;
422 panel_allocation.height = MIN (widget->requisition.height, allocation->height);
424 panel_allocation.y = allocation->y + (allocation->height -
425 panel_allocation.height) / 2;
427 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
429 if (GTK_WIDGET_REALIZED (widget))
431 gdk_window_move_resize (PSPPIRE_CUSTOM_ENTRY (widget)->panel,
434 panel_allocation.width,
435 panel_allocation.height);
438 psppire_custom_entry_redraw (ce);