Code

dropper modes: replace undecipherable icons with text labels
[inkscape.git] / src / helper / unit-menu.cpp
1 #define __SP_UNIT_MENU_C__
3 /*
4  * Unit selector with autupdate capability
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 2000-2002 Authors
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #define noUNIT_SELECTOR_VERBOSE
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 #include <gtk/gtksignal.h>
21 #include <gtk/gtkhbox.h>
22 #include <gtk/gtkmenu.h>
23 #include <gtk/gtkmenuitem.h>
24 #include "helper/sp-marshal.h"
25 #include "helper/units.h"
26 #include "unit-menu.h"
27 #include "widgets/spw-utilities.h"
29 struct SPUnitSelector {
30     GtkHBox box;
32     GtkWidget *menu;
34     guint bases;
35     GSList *units;
36     SPUnit const *unit;
37     gdouble ctmscale;
38     guint plural : 1;
39     guint abbr : 1;
41     guint update : 1;
43     GSList *adjustments;
44 };
46 struct SPUnitSelectorClass {
47     GtkHBoxClass parent_class;
49     gboolean (* set_unit)(SPUnitSelector *us, SPUnit const *old, SPUnit const *new_unit);
50 };
52 enum {SET_UNIT, LAST_SIGNAL};
54 static void sp_unit_selector_class_init(SPUnitSelectorClass *klass);
55 static void sp_unit_selector_init(SPUnitSelector *selector);
56 static void sp_unit_selector_finalize(GObject *object);
58 static GtkHBoxClass *unit_selector_parent_class;
59 static guint signals[LAST_SIGNAL] = {0};
61 GtkType
62 sp_unit_selector_get_type(void)
63 {
64     static GtkType type = 0;
65     if (!type) {
66         static GtkTypeInfo const info = {
67             "SPUnitSelector",
68             sizeof(SPUnitSelector),
69             sizeof(SPUnitSelectorClass),
70             (GtkClassInitFunc) sp_unit_selector_class_init,
71             (GtkObjectInitFunc) sp_unit_selector_init,
72             NULL, NULL, NULL
73         };
74         type = gtk_type_unique(GTK_TYPE_HBOX, &info);
75     }
76     return type;
77 }
79 static void
80 sp_unit_selector_class_init(SPUnitSelectorClass *klass)
81 {
82     GObjectClass *object_class;
83     GtkWidgetClass *widget_class;
85     object_class = G_OBJECT_CLASS(klass);
86     widget_class = GTK_WIDGET_CLASS(klass);
88     unit_selector_parent_class = (GtkHBoxClass*)gtk_type_class(GTK_TYPE_HBOX);
90     signals[SET_UNIT] = g_signal_new("set_unit",
91                                      G_TYPE_FROM_CLASS(klass),
92                                      G_SIGNAL_RUN_LAST,
93                                      G_STRUCT_OFFSET(SPUnitSelectorClass, set_unit),
94                                      NULL, NULL,
95                                      sp_marshal_BOOLEAN__POINTER_POINTER,
96                                      G_TYPE_BOOLEAN, 2,
97                                      G_TYPE_POINTER, G_TYPE_POINTER);
99     object_class->finalize = sp_unit_selector_finalize;
102 static void
103 sp_unit_selector_init(SPUnitSelector *us)
105     us->ctmscale = 1.0;
106     us->abbr = FALSE;
107     us->plural = TRUE;
109     us->menu = gtk_option_menu_new();
111     gtk_widget_show(us->menu);
112     gtk_box_pack_start(GTK_BOX(us), us->menu, TRUE, TRUE, 0);
115 static void
116 sp_unit_selector_finalize(GObject *object)
118     SPUnitSelector *selector = SP_UNIT_SELECTOR(object);
120     if (selector->menu) {
121         selector->menu = NULL;
122     }
124     while (selector->adjustments) {
125         gtk_object_unref(GTK_OBJECT(selector->adjustments->data));
126         selector->adjustments = g_slist_remove(selector->adjustments, selector->adjustments->data);
127     }
129     if (selector->units) {
130         sp_unit_free_list(selector->units);
131     }
133     selector->unit = NULL;
135     G_OBJECT_CLASS(unit_selector_parent_class)->finalize(object);
138 GtkWidget *
139 sp_unit_selector_new(guint bases)
141     SPUnitSelector *us = (SPUnitSelector*)gtk_type_new(SP_TYPE_UNIT_SELECTOR);
143     sp_unit_selector_set_bases(us, bases);
145     return (GtkWidget *) us;
148 void
149 sp_unit_selector_setsize(GtkWidget *us, guint w, guint h)
151     gtk_widget_set_size_request(((SPUnitSelector *) us)->menu, w, h);
154 SPUnit const *
155 sp_unit_selector_get_unit(SPUnitSelector const *us)
157     g_return_val_if_fail(us != NULL, NULL);
158     g_return_val_if_fail(SP_IS_UNIT_SELECTOR(us), NULL);
160     return us->unit;
163 static void
164 spus_unit_activate(GtkWidget *widget, SPUnitSelector *us)
166     SPUnit const *unit = (SPUnit const *) gtk_object_get_data(GTK_OBJECT(widget), "unit");
167     g_return_if_fail(unit != NULL);
169 #ifdef UNIT_SELECTOR_VERBOSE
170     g_print("Old unit %s new unit %s\n", us->unit->name, unit->name);
171 #endif
173     SPUnit const *old = us->unit;
174     us->unit = unit;
176     us->update = TRUE;
178     gboolean consumed = FALSE;
179     g_signal_emit(G_OBJECT(us), signals[SET_UNIT], 0, old, unit, &consumed);
181     if ( !consumed
182          && ( unit->base == old->base
183               || ( unit->base == SP_UNIT_ABSOLUTE && old->base == SP_UNIT_DEVICE )
184               || ( old->base == SP_UNIT_ABSOLUTE && unit->base == SP_UNIT_DEVICE ) ) ) {
185         // Either the same base, or absolute<->device:
186         /* Recalculate adjustments. */
187         for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) {
188             GtkAdjustment *adj = GTK_ADJUSTMENT(l->data);
189             gdouble val = adj->value;
190 #ifdef UNIT_SELECTOR_VERBOSE
191             g_print("Old val %g ... ", val);
192 #endif
193             val = sp_convert_distance_full(val, *old, *unit);
194 #ifdef UNIT_SELECTOR_VERBOSE
195             g_print("new val %g\n", val);
196 #endif
197             adj->value = val;
198         }
199         /* need to separate the value changing from the notification
200          * or else the unit changes can break the calculations */
201         for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) {
202             gtk_adjustment_value_changed(GTK_ADJUSTMENT(l->data));
203         }
204     } else if (!consumed && unit->base != old->base) {
205         /* when the base changes, signal all the adjustments to get them
206          * to recalculate */
207         for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) {
208             gtk_signal_emit_by_name(GTK_OBJECT(l->data), "value_changed");
209         }
210     }
212     us->update = FALSE;
215 static void
216 spus_rebuild_menu(SPUnitSelector *us)
218     if (GTK_OPTION_MENU(us->menu)->menu) {
219         gtk_option_menu_remove_menu(GTK_OPTION_MENU(us->menu));
220     }
222     GtkWidget *m = gtk_menu_new();
224     gtk_widget_show(m);
226     gint pos = 0;
227     gint p = 0;
228     for (GSList *l = us->units; l != NULL; l = l->next) {
229         SPUnit const *u = (SPUnit*)l->data;
231         // use only abbreviations in the menu
232         //        i = gtk_menu_item_new_with_label((us->abbr) ? (us->plural) ? u->abbr_plural : u->abbr : (us->plural) ? u->plural : u->name);
233         GtkWidget *i = gtk_menu_item_new_with_label( u->abbr );
235         gtk_object_set_data(GTK_OBJECT(i), "unit", (gpointer) u);
236         gtk_signal_connect(GTK_OBJECT(i), "activate", GTK_SIGNAL_FUNC(spus_unit_activate), us);
238         sp_set_font_size_smaller (i);
240         gtk_widget_show(i);
242         gtk_menu_shell_append(GTK_MENU_SHELL(m), i);
243         if (u == us->unit) pos = p;
244         p += 1;
245     }
247     gtk_option_menu_set_menu(GTK_OPTION_MENU(us->menu), m);
249     gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos);
252 void
253 sp_unit_selector_set_bases(SPUnitSelector *us, guint bases)
255     g_return_if_fail(us != NULL);
256     g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
258     if (bases == us->bases) return;
260     GSList *units = sp_unit_get_list(bases);
261     g_return_if_fail(units != NULL);
262     sp_unit_free_list(us->units);
263     us->units = units;
264     us->unit = (SPUnit*)units->data;
266     spus_rebuild_menu(us);
269 void
270 sp_unit_selector_add_unit(SPUnitSelector *us, SPUnit const *unit, int position)
272     if (!g_slist_find(us->units, (gpointer) unit)) {
273         us->units = g_slist_insert(us->units, (gpointer) unit, position);
275         spus_rebuild_menu(us);
276     }
279 void
280 sp_unit_selector_set_unit(SPUnitSelector *us, SPUnit const *unit)
282     g_return_if_fail(us != NULL);
283     g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
285     if (unit == NULL) {
286         return; // silently return, by default a newly created selector uses pt
287     }
288     if (unit == us->unit) {
289         return;
290     }
292     gint const pos = g_slist_index(us->units, (gpointer) unit);
293     g_return_if_fail(pos >= 0);
295     gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos);
297     SPUnit const *old = us->unit;
298     us->unit = unit;
300     /* Recalculate adjustments */
301     for (GSList *l = us->adjustments; l != NULL; l = l->next) {
302         GtkAdjustment *adj = GTK_ADJUSTMENT(l->data);
303         gdouble const val = sp_convert_distance_full(adj->value, *old, *unit);
304         gtk_adjustment_set_value(adj, val);
305     }
308 void
309 sp_unit_selector_add_adjustment(SPUnitSelector *us, GtkAdjustment *adj)
311     g_return_if_fail(us != NULL);
312     g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
313     g_return_if_fail(adj != NULL);
314     g_return_if_fail(GTK_IS_ADJUSTMENT(adj));
316     g_return_if_fail(!g_slist_find(us->adjustments, adj));
318     gtk_object_ref(GTK_OBJECT(adj));
319     us->adjustments = g_slist_prepend(us->adjustments, adj);
322 void
323 sp_unit_selector_remove_adjustment(SPUnitSelector *us, GtkAdjustment *adj)
325     g_return_if_fail(us != NULL);
326     g_return_if_fail(SP_IS_UNIT_SELECTOR(us));
327     g_return_if_fail(adj != NULL);
328     g_return_if_fail(GTK_IS_ADJUSTMENT(adj));
330     g_return_if_fail(g_slist_find(us->adjustments, adj));
332     us->adjustments = g_slist_remove(us->adjustments, adj);
333     gtk_object_unref(GTK_OBJECT(adj));
336 gboolean
337 sp_unit_selector_update_test(SPUnitSelector const *selector)
339     g_return_val_if_fail(selector != NULL, FALSE);
340     g_return_val_if_fail(SP_IS_UNIT_SELECTOR(selector), FALSE);
342     return selector->update;
345 double
346 sp_unit_selector_get_value_in_pixels(SPUnitSelector const *selector, GtkAdjustment *adj)
348     g_return_val_if_fail(selector != NULL, adj->value);
349     g_return_val_if_fail(SP_IS_UNIT_SELECTOR(selector), adj->value);
351     return sp_units_get_pixels(adj->value, *(selector->unit));
354 void
355 sp_unit_selector_set_value_in_pixels(SPUnitSelector *selector, GtkAdjustment *adj, double value)
357     g_return_if_fail(selector != NULL);
358     g_return_if_fail(SP_IS_UNIT_SELECTOR(selector));
360     gtk_adjustment_set_value(adj, sp_pixels_get_units(value, *(selector->unit)));
363 /*
364   Local Variables:
365   mode:c++
366   c-file-style:"stroustrup"
367   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
368   indent-tabs-mode:nil
369   fill-column:99
370   End:
371 */
372 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :