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/.
63 #define _(msgid) gettext (msgid)
66 #include <gtk/gtksignal.h>
67 #include <gtk/gtkentry.h>
68 #include "customentry.h"
71 static void psppire_custom_entry_class_init (PsppireCustomEntryClass *klass);
72 static void psppire_custom_entry_init (PsppireCustomEntry *ce);
74 static GtkEntryClass *parent_class = NULL;
84 static guint custom_entry_signals[n_SIGNALS] = {0};
88 psppire_custom_entry_get_type (void)
90 static GType ce_type = 0;
94 static const GTypeInfo ce_info =
96 sizeof (PsppireCustomEntryClass),
98 NULL, /* base_finalize */
99 (GClassInitFunc) psppire_custom_entry_class_init,
100 NULL, /* class_finalize */
101 NULL, /* class_data */
102 sizeof (PsppireCustomEntry),
104 (GInstanceInitFunc) psppire_custom_entry_init,
107 ce_type = g_type_register_static (GTK_TYPE_ENTRY, "PsppireCustomEntry",
116 psppire_custom_entry_map (GtkWidget *widget)
118 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
120 GTK_WIDGET_CLASS (parent_class)->map (widget);
121 gdk_window_show (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
126 psppire_custom_entry_unmap (GtkWidget *widget)
128 if (GTK_WIDGET_MAPPED (widget))
130 gdk_window_hide (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
131 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
135 static gint psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry);
138 psppire_custom_entry_realize (GtkWidget *widget)
140 PsppireCustomEntry *custom_entry;
141 GdkWindowAttr attributes;
142 gint attributes_mask;
146 custom_entry = PSPPIRE_CUSTOM_ENTRY (widget);
148 button_size = psppire_custom_entry_get_button_width (custom_entry);
150 real_width = widget->allocation.width;
151 widget->allocation.width -= button_size + 2 * widget->style->xthickness;
152 gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
153 GDK_KEY_RELEASE_MASK);
154 GTK_WIDGET_CLASS (parent_class)->realize (widget);
156 widget->allocation.width = real_width;
158 attributes.window_type = GDK_WINDOW_CHILD;
159 attributes.wclass = GDK_INPUT_OUTPUT;
160 attributes.visual = gtk_widget_get_visual (widget);
161 attributes.colormap = gtk_widget_get_colormap (widget);
162 attributes.event_mask = gtk_widget_get_events (widget);
163 attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
164 | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
165 | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
167 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
169 attributes.x = (widget->allocation.x +
170 widget->allocation.width - button_size -
171 2 * widget->style->xthickness);
172 attributes.y = widget->allocation.y + (widget->allocation.height -
173 widget->requisition.height) / 2;
174 attributes.width = button_size + 2 * widget->style->xthickness;
175 attributes.height = widget->requisition.height;
177 custom_entry->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
178 &attributes, attributes_mask);
179 gdk_window_set_user_data (custom_entry->panel, widget);
181 gtk_style_set_background (widget->style, custom_entry->panel, GTK_STATE_NORMAL);
184 gtk_widget_queue_resize (GTK_WIDGET (custom_entry));
188 #define MIN_BUTTON_WIDTH 6
191 psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry)
193 const gint size = pango_font_description_get_size
194 (GTK_WIDGET (custom_entry)->style->font_desc);
196 gint button_width = MAX (PANGO_PIXELS (size), MIN_BUTTON_WIDTH);
198 return button_width - button_width % 2; /* force even */
202 * custom_entry_get_shadow_type:
203 * @custom_entry: a #PsppireCustomEntry
205 * Convenience function to Get the shadow type from the underlying widget's
208 * Return value: the #GtkShadowType
211 psppire_custom_entry_get_shadow_type (PsppireCustomEntry *custom_entry)
213 GtkShadowType rc_shadow_type;
215 gtk_widget_style_get (GTK_WIDGET (custom_entry), "shadow_type", &rc_shadow_type, NULL);
217 return rc_shadow_type;
222 psppire_custom_entry_unrealize (GtkWidget *widget)
224 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
226 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
230 gdk_window_set_user_data (ce->panel, NULL);
231 gdk_window_destroy (ce->panel);
238 psppire_custom_entry_redraw (PsppireCustomEntry *custom_entry)
242 widget = GTK_WIDGET (custom_entry);
244 if (GTK_WIDGET_DRAWABLE (widget))
246 gtk_widget_queue_draw (widget);
248 /* We must invalidate the panel window ourselves, because it
249 * is not a child of widget->window
251 gdk_window_invalidate_rect (custom_entry->panel, NULL, TRUE);
257 psppire_custom_entry_expose (GtkWidget *widget,
258 GdkEventExpose *event)
260 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY(widget);
262 g_return_val_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget), FALSE);
263 g_return_val_if_fail (event != NULL, FALSE);
265 if (GTK_WIDGET_DRAWABLE (widget))
267 GtkShadowType shadow_type;
273 if (event->window != ce->panel)
274 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
276 gdk_drawable_get_size (ce->panel, &rect.width, &rect.height);
278 gdk_window_begin_paint_rect (ce->panel, &rect);
281 shadow_type = psppire_custom_entry_get_shadow_type (ce);
283 if (shadow_type != GTK_SHADOW_NONE)
285 gtk_paint_box (widget->style, ce->panel,
286 GTK_STATE_NORMAL, shadow_type,
287 NULL, widget, "customentry",
288 rect.x, rect.y, rect.width, rect.height);
292 gdk_window_end_paint (ce->panel);
300 psppire_custom_entry_button_press (GtkWidget *widget,
301 GdkEventButton *event);
304 psppire_custom_entry_size_allocate (GtkWidget *widget,
305 GtkAllocation *allocation);
310 psppire_custom_entry_class_init (PsppireCustomEntryClass *klass)
312 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
314 GtkWidgetClass *widget_class;
315 GtkEntryClass *entry_class;
317 parent_class = g_type_class_peek_parent (klass);
319 widget_class = (GtkWidgetClass*) klass;
320 entry_class = (GtkEntryClass*) klass;
322 widget_class->map = psppire_custom_entry_map;
323 widget_class->unmap = psppire_custom_entry_unmap;
325 widget_class->realize = psppire_custom_entry_realize;
326 widget_class->unrealize = psppire_custom_entry_unrealize;
328 widget_class->expose_event = psppire_custom_entry_expose;
329 widget_class->button_press_event = psppire_custom_entry_button_press;
331 widget_class->size_allocate = psppire_custom_entry_size_allocate;
334 gtk_widget_class_install_style_property_parser
336 g_param_spec_enum ("shadow_type",
338 _("Style of bevel around the custom entry button"),
339 GTK_TYPE_SHADOW_TYPE,
340 GTK_SHADOW_ETCHED_IN,
342 gtk_rc_property_parse_enum);
344 custom_entry_signals[CLICKED] =
345 g_signal_new ("clicked",
346 G_TYPE_FROM_CLASS(gobject_class),
350 g_cclosure_marshal_VOID__VOID,
358 psppire_custom_entry_init (PsppireCustomEntry *ce)
363 psppire_custom_entry_new ()
365 return GTK_WIDGET (g_object_new (psppire_custom_entry_get_type (), NULL));
371 psppire_custom_entry_button_press (GtkWidget *widget,
372 GdkEventButton *event)
374 PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
376 if (event->window == ce->panel)
378 if (!GTK_WIDGET_HAS_FOCUS (widget))
379 gtk_widget_grab_focus (widget);
381 if ( event->button == 1)
382 g_signal_emit (widget, custom_entry_signals[CLICKED], 0);
386 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
394 psppire_custom_entry_size_allocate (GtkWidget *widget,
395 GtkAllocation *allocation)
397 PsppireCustomEntry *ce;
398 GtkAllocation entry_allocation;
399 GtkAllocation panel_allocation;
403 g_return_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget));
404 g_return_if_fail (allocation != NULL);
406 ce = PSPPIRE_CUSTOM_ENTRY (widget);
407 button_width = psppire_custom_entry_get_button_width(ce);
408 panel_width = button_width + 2 * widget->style->xthickness;
410 widget->allocation = *allocation;
412 entry_allocation = *allocation;
413 entry_allocation.width -= panel_width;
415 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
417 entry_allocation.x += panel_width;
418 panel_allocation.x = allocation->x;
422 panel_allocation.x = allocation->x + allocation->width - panel_width;
425 panel_allocation.width = panel_width;
426 panel_allocation.height = MIN (widget->requisition.height, allocation->height);
428 panel_allocation.y = allocation->y + (allocation->height -
429 panel_allocation.height) / 2;
431 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
433 if (GTK_WIDGET_REALIZED (widget))
435 gdk_window_move_resize (PSPPIRE_CUSTOM_ENTRY (widget)->panel,
438 panel_allocation.width,
439 panel_allocation.height);
442 psppire_custom_entry_redraw (ce);