more leaks plugged and more *_OPTIONAL
[dia.git] / app / diaunitspinner.c
blob2234b50dda2cb1b0587b3a51ade15876aefb0e57
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998, 1999 Alexander Larsson
4 * diaunitspinner.[ch] -- a spin button widget for length measurements.
5 * Copyright (C) 1999 James Henstridge
7 * This program 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 2 of the License, or
10 * (at your option) any later version.
12 * This program 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 this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <config.h>
24 #include <ctype.h>
25 #include <string.h> /* strcmp */
26 #include "diaunitspinner.h"
27 #include "gdk/gdkkeysyms.h"
29 typedef struct _DiaUnitDef DiaUnitDef;
30 struct _DiaUnitDef {
31 char* name;
32 char* unit;
33 float factor;
36 /* from gnome-libs/libgnome/gnome-paper.c */
37 static const DiaUnitDef units[] =
39 /* XXX does anyone *really* measure paper size in feet? meters? */
41 /* human name, abreviation, points per unit */
42 { "Feet", "ft", 864 },
43 { "Meter", "m", 2834.6457 },
44 { "Decimeter", "dm", 283.46457 },
45 { "Millimeter", "mm", 2.8346457 },
46 { "Point", "pt", 1. },
47 { "Centimeter", "cm", 28.346457 },
48 { "Inch", "in", 72 },
49 { "Pica", "pi", 12 },
50 { 0 }
53 static GtkObjectClass *parent_class;
54 static GtkObjectClass *entry_class;
56 static void dia_unit_spinner_class_init(DiaUnitSpinnerClass *class);
57 static void dia_unit_spinner_init(DiaUnitSpinner *self);
59 GtkType
60 dia_unit_spinner_get_type(void)
62 static GtkType us_type = 0;
64 if (!us_type) {
65 GtkTypeInfo us_info = {
66 "DiaUnitSpinner",
67 sizeof(DiaUnitSpinner),
68 sizeof(DiaUnitSpinnerClass),
69 (GtkClassInitFunc) dia_unit_spinner_class_init,
70 (GtkObjectInitFunc) dia_unit_spinner_init,
71 NULL,
72 NULL,
73 (GtkClassInitFunc) NULL,
75 us_type = gtk_type_unique(gtk_spin_button_get_type(), &us_info);
77 return us_type;
80 static void
81 dia_unit_spinner_value_changed(GtkAdjustment *adjustment,
82 DiaUnitSpinner *spinner)
84 char buf[256];
85 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(spinner);
87 g_snprintf(buf, sizeof(buf), "%0.*f%s", sbutton->digits, adjustment->value,
88 units[spinner->unit_num].unit);
89 if (strcmp(buf, gtk_entry_get_text(GTK_ENTRY(spinner))))
90 gtk_entry_set_text(GTK_ENTRY(spinner), buf);
93 static gint dia_unit_spinner_focus_out(GtkWidget *widget, GdkEventFocus *ev);
94 static gint dia_unit_spinner_button_press(GtkWidget *widget,GdkEventButton*ev);
95 static gint dia_unit_spinner_key_press(GtkWidget *widget, GdkEventKey *event);
96 static void dia_unit_spinner_activate(GtkEntry *editable);
98 static void
99 dia_unit_spinner_class_init(DiaUnitSpinnerClass *class)
101 GtkObjectClass *object_class;
102 GtkWidgetClass *widget_class;
103 GtkEntryClass *editable_class;
105 object_class = (GtkObjectClass *)class;
106 widget_class = (GtkWidgetClass *)class;
107 editable_class = (GtkEntryClass *)class;
109 widget_class->focus_out_event = dia_unit_spinner_focus_out;
110 widget_class->button_press_event = dia_unit_spinner_button_press;
111 widget_class->key_press_event = dia_unit_spinner_key_press;
112 editable_class->activate = dia_unit_spinner_activate;
114 parent_class = gtk_type_class(GTK_TYPE_SPIN_BUTTON);
115 entry_class = gtk_type_class(GTK_TYPE_ENTRY);
118 static void
119 dia_unit_spinner_init(DiaUnitSpinner *self)
121 /* change over to our own print function that appends the unit name on the
122 * end */
123 if (self->parent.adjustment) {
124 gtk_signal_disconnect_by_data(GTK_OBJECT(self->parent.adjustment),
125 (gpointer) self);
126 g_signal_connect(GTK_OBJECT(self->parent.adjustment), "value_changed",
127 G_CALLBACK(dia_unit_spinner_value_changed),
128 (gpointer) self);
131 self->unit_num = DIA_UNIT_CENTIMETER;
134 GtkWidget *
135 dia_unit_spinner_new(GtkAdjustment *adjustment, guint digits, DiaUnit adj_unit)
137 DiaUnitSpinner *self = gtk_type_new(dia_unit_spinner_get_type());
139 gtk_spin_button_configure(GTK_SPIN_BUTTON(self), adjustment, 0.0, digits);
141 if (adjustment) {
142 gtk_signal_disconnect_by_data(GTK_OBJECT(adjustment),
143 (gpointer) self);
144 g_signal_connect(GTK_OBJECT(adjustment), "value_changed",
145 G_CALLBACK(dia_unit_spinner_value_changed),
146 (gpointer) self);
149 self->unit_num = adj_unit;
151 return GTK_WIDGET(self);
154 void
155 dia_unit_spinner_set_value(DiaUnitSpinner *self, gfloat val)
157 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
159 if (val < sbutton->adjustment->lower)
160 val = sbutton->adjustment->lower;
161 else if (val > sbutton->adjustment->upper)
162 val = sbutton->adjustment->upper;
163 if (val != sbutton->adjustment->value) {
164 sbutton->adjustment->value = val;
165 gtk_adjustment_value_changed(sbutton->adjustment);
169 gfloat
170 dia_unit_spinner_get_value(DiaUnitSpinner *self)
172 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
174 return sbutton->adjustment->value;
177 static void
178 dia_unit_spinner_update(DiaUnitSpinner *self)
180 GtkSpinButton *sbutton = GTK_SPIN_BUTTON(self);
181 gfloat val, factor = 1.0;
182 gchar *extra = NULL;
184 val = g_strtod(gtk_entry_get_text(GTK_ENTRY(self)), &extra);
186 /* get rid of extra white space after number */
187 while (*extra && isspace(*extra)) extra++;
188 if (*extra) {
189 int i;
191 for (i = 0; units[i].name != NULL; i++)
192 if (!g_strcasecmp(units[i].unit, extra)) {
193 factor = units[i].factor / units[self->unit_num].factor;
194 break;
197 /* convert to prefered units */
198 val *= factor;
199 if (val < sbutton->adjustment->lower)
200 val = sbutton->adjustment->lower;
201 else if (val > sbutton->adjustment->upper)
202 val = sbutton->adjustment->upper;
203 gtk_adjustment_set_value(sbutton->adjustment, val);
206 static gint
207 dia_unit_spinner_focus_out(GtkWidget *widget, GdkEventFocus *event)
209 if (GTK_ENTRY (widget)->editable)
210 dia_unit_spinner_update(DIA_UNIT_SPINNER(widget));
211 return GTK_WIDGET_CLASS(entry_class)->focus_out_event(widget, event);
214 static gint
215 dia_unit_spinner_button_press(GtkWidget *widget, GdkEventButton *event)
217 dia_unit_spinner_update(DIA_UNIT_SPINNER(widget));
218 return GTK_WIDGET_CLASS(parent_class)->button_press_event(widget, event);
221 static gint
222 dia_unit_spinner_key_press(GtkWidget *widget, GdkEventKey *event)
224 gint key = event->keyval;
226 if (GTK_ENTRY (widget)->editable &&
227 (key == GDK_Up || key == GDK_Down ||
228 key == GDK_Page_Up || key == GDK_Page_Down))
229 dia_unit_spinner_update (DIA_UNIT_SPINNER(widget));
230 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
233 static void
234 dia_unit_spinner_activate(GtkEntry *editable)
236 if (editable->editable)
237 dia_unit_spinner_update(DIA_UNIT_SPINNER(editable));