diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/helper/unit-menu.cpp | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/helper/unit-menu.cpp')
| -rw-r--r-- | src/helper/unit-menu.cpp | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/src/helper/unit-menu.cpp b/src/helper/unit-menu.cpp new file mode 100644 index 000000000..34a2b6344 --- /dev/null +++ b/src/helper/unit-menu.cpp @@ -0,0 +1,372 @@ +#define __SP_UNIT_MENU_C__ + +/* + * Unit selector with autupdate capability + * + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * + * Copyright (C) 2000-2002 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#define noUNIT_SELECTOR_VERBOSE + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <gtk/gtksignal.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include "helper/sp-marshal.h" +#include "helper/units.h" +#include "unit-menu.h" +#include "widgets/spw-utilities.h" + +struct SPUnitSelector { + GtkHBox box; + + GtkWidget *menu; + + guint bases; + GSList *units; + SPUnit const *unit; + gdouble ctmscale; + guint plural : 1; + guint abbr : 1; + + guint update : 1; + + GSList *adjustments; +}; + +struct SPUnitSelectorClass { + GtkHBoxClass parent_class; + + gboolean (* set_unit)(SPUnitSelector *us, SPUnit const *old, SPUnit const *new_unit); +}; + +enum {SET_UNIT, LAST_SIGNAL}; + +static void sp_unit_selector_class_init(SPUnitSelectorClass *klass); +static void sp_unit_selector_init(SPUnitSelector *selector); +static void sp_unit_selector_finalize(GObject *object); + +static GtkHBoxClass *unit_selector_parent_class; +static guint signals[LAST_SIGNAL] = {0}; + +GtkType +sp_unit_selector_get_type(void) +{ + static GtkType type = 0; + if (!type) { + static GtkTypeInfo const info = { + "SPUnitSelector", + sizeof(SPUnitSelector), + sizeof(SPUnitSelectorClass), + (GtkClassInitFunc) sp_unit_selector_class_init, + (GtkObjectInitFunc) sp_unit_selector_init, + NULL, NULL, NULL + }; + type = gtk_type_unique(GTK_TYPE_HBOX, &info); + } + return type; +} + +static void +sp_unit_selector_class_init(SPUnitSelectorClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = G_OBJECT_CLASS(klass); + widget_class = GTK_WIDGET_CLASS(klass); + + unit_selector_parent_class = (GtkHBoxClass*)gtk_type_class(GTK_TYPE_HBOX); + + signals[SET_UNIT] = g_signal_new("set_unit", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(SPUnitSelectorClass, set_unit), + NULL, NULL, + sp_marshal_BOOLEAN__POINTER_POINTER, + G_TYPE_BOOLEAN, 2, + G_TYPE_POINTER, G_TYPE_POINTER); + + object_class->finalize = sp_unit_selector_finalize; +} + +static void +sp_unit_selector_init(SPUnitSelector *us) +{ + us->ctmscale = 1.0; + us->abbr = FALSE; + us->plural = TRUE; + + us->menu = gtk_option_menu_new(); + + gtk_widget_show(us->menu); + gtk_box_pack_start(GTK_BOX(us), us->menu, TRUE, TRUE, 0); +} + +static void +sp_unit_selector_finalize(GObject *object) +{ + SPUnitSelector *selector = SP_UNIT_SELECTOR(object); + + if (selector->menu) { + selector->menu = NULL; + } + + while (selector->adjustments) { + gtk_object_unref(GTK_OBJECT(selector->adjustments->data)); + selector->adjustments = g_slist_remove(selector->adjustments, selector->adjustments->data); + } + + if (selector->units) { + sp_unit_free_list(selector->units); + } + + selector->unit = NULL; + + G_OBJECT_CLASS(unit_selector_parent_class)->finalize(object); +} + +GtkWidget * +sp_unit_selector_new(guint bases) +{ + SPUnitSelector *us = (SPUnitSelector*)gtk_type_new(SP_TYPE_UNIT_SELECTOR); + + sp_unit_selector_set_bases(us, bases); + + return (GtkWidget *) us; +} + +void +sp_unit_selector_setsize(GtkWidget *us, guint w, guint h) +{ + gtk_widget_set_size_request(((SPUnitSelector *) us)->menu, w, h); +} + +SPUnit const * +sp_unit_selector_get_unit(SPUnitSelector const *us) +{ + g_return_val_if_fail(us != NULL, NULL); + g_return_val_if_fail(SP_IS_UNIT_SELECTOR(us), NULL); + + return us->unit; +} + +static void +spus_unit_activate(GtkWidget *widget, SPUnitSelector *us) +{ + SPUnit const *unit = (SPUnit const *) gtk_object_get_data(GTK_OBJECT(widget), "unit"); + g_return_if_fail(unit != NULL); + +#ifdef UNIT_SELECTOR_VERBOSE + g_print("Old unit %s new unit %s\n", us->unit->name, unit->name); +#endif + + SPUnit const *old = us->unit; + us->unit = unit; + + us->update = TRUE; + + gboolean consumed = FALSE; + g_signal_emit(G_OBJECT(us), signals[SET_UNIT], 0, old, unit, &consumed); + + if ( !consumed + && ( unit->base == old->base + || ( unit->base == SP_UNIT_ABSOLUTE && old->base == SP_UNIT_DEVICE ) + || ( old->base == SP_UNIT_ABSOLUTE && unit->base == SP_UNIT_DEVICE ) ) ) { + // Either the same base, or absolute<->device: + /* Recalculate adjustments. */ + for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) { + GtkAdjustment *adj = GTK_ADJUSTMENT(l->data); + gdouble val = adj->value; +#ifdef UNIT_SELECTOR_VERBOSE + g_print("Old val %g ... ", val); +#endif + val = sp_convert_distance_full(val, *old, *unit); +#ifdef UNIT_SELECTOR_VERBOSE + g_print("new val %g\n", val); +#endif + adj->value = val; + } + /* need to separate the value changing from the notification + * or else the unit changes can break the calculations */ + for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) { + gtk_adjustment_value_changed(GTK_ADJUSTMENT(l->data)); + } + } else if (!consumed && unit->base != old->base) { + /* when the base changes, signal all the adjustments to get them + * to recalculate */ + for (GSList *l = us->adjustments; l != NULL; l = g_slist_next(l)) { + gtk_signal_emit_by_name(GTK_OBJECT(l->data), "value_changed"); + } + } + + us->update = FALSE; +} + +static void +spus_rebuild_menu(SPUnitSelector *us) +{ + if (GTK_OPTION_MENU(us->menu)->menu) { + gtk_option_menu_remove_menu(GTK_OPTION_MENU(us->menu)); + } + + GtkWidget *m = gtk_menu_new(); + + gtk_widget_show(m); + + gint pos = 0; + gint p = 0; + for (GSList *l = us->units; l != NULL; l = l->next) { + SPUnit const *u = (SPUnit*)l->data; + + // use only abbreviations in the menu + // i = gtk_menu_item_new_with_label((us->abbr) ? (us->plural) ? u->abbr_plural : u->abbr : (us->plural) ? u->plural : u->name); + GtkWidget *i = gtk_menu_item_new_with_label( u->abbr ); + + gtk_object_set_data(GTK_OBJECT(i), "unit", (gpointer) u); + gtk_signal_connect(GTK_OBJECT(i), "activate", GTK_SIGNAL_FUNC(spus_unit_activate), us); + + sp_set_font_size_smaller (i); + + gtk_widget_show(i); + + gtk_menu_shell_append(GTK_MENU_SHELL(m), i); + if (u == us->unit) pos = p; + p += 1; + } + + gtk_option_menu_set_menu(GTK_OPTION_MENU(us->menu), m); + + gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos); +} + +void +sp_unit_selector_set_bases(SPUnitSelector *us, guint bases) +{ + g_return_if_fail(us != NULL); + g_return_if_fail(SP_IS_UNIT_SELECTOR(us)); + + if (bases == us->bases) return; + + GSList *units = sp_unit_get_list(bases); + g_return_if_fail(units != NULL); + sp_unit_free_list(us->units); + us->units = units; + us->unit = (SPUnit*)units->data; + + spus_rebuild_menu(us); +} + +void +sp_unit_selector_add_unit(SPUnitSelector *us, SPUnit const *unit, int position) +{ + if (!g_slist_find(us->units, (gpointer) unit)) { + us->units = g_slist_insert(us->units, (gpointer) unit, position); + + spus_rebuild_menu(us); + } +} + +void +sp_unit_selector_set_unit(SPUnitSelector *us, SPUnit const *unit) +{ + g_return_if_fail(us != NULL); + g_return_if_fail(SP_IS_UNIT_SELECTOR(us)); + + if (unit == NULL) { + return; // silently return, by default a newly created selector uses pt + } + if (unit == us->unit) { + return; + } + + gint const pos = g_slist_index(us->units, (gpointer) unit); + g_return_if_fail(pos >= 0); + + gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos); + + SPUnit const *old = us->unit; + us->unit = unit; + + /* Recalculate adjustments */ + for (GSList *l = us->adjustments; l != NULL; l = l->next) { + GtkAdjustment *adj = GTK_ADJUSTMENT(l->data); + gdouble const val = sp_convert_distance_full(adj->value, *old, *unit); + gtk_adjustment_set_value(adj, val); + } +} + +void +sp_unit_selector_add_adjustment(SPUnitSelector *us, GtkAdjustment *adj) +{ + g_return_if_fail(us != NULL); + g_return_if_fail(SP_IS_UNIT_SELECTOR(us)); + g_return_if_fail(adj != NULL); + g_return_if_fail(GTK_IS_ADJUSTMENT(adj)); + + g_return_if_fail(!g_slist_find(us->adjustments, adj)); + + gtk_object_ref(GTK_OBJECT(adj)); + us->adjustments = g_slist_prepend(us->adjustments, adj); +} + +void +sp_unit_selector_remove_adjustment(SPUnitSelector *us, GtkAdjustment *adj) +{ + g_return_if_fail(us != NULL); + g_return_if_fail(SP_IS_UNIT_SELECTOR(us)); + g_return_if_fail(adj != NULL); + g_return_if_fail(GTK_IS_ADJUSTMENT(adj)); + + g_return_if_fail(g_slist_find(us->adjustments, adj)); + + us->adjustments = g_slist_remove(us->adjustments, adj); + gtk_object_unref(GTK_OBJECT(adj)); +} + +gboolean +sp_unit_selector_update_test(SPUnitSelector const *selector) +{ + g_return_val_if_fail(selector != NULL, FALSE); + g_return_val_if_fail(SP_IS_UNIT_SELECTOR(selector), FALSE); + + return selector->update; +} + +double +sp_unit_selector_get_value_in_pixels(SPUnitSelector const *selector, GtkAdjustment *adj) +{ + g_return_val_if_fail(selector != NULL, adj->value); + g_return_val_if_fail(SP_IS_UNIT_SELECTOR(selector), adj->value); + + return sp_units_get_pixels(adj->value, *(selector->unit)); +} + +void +sp_unit_selector_set_value_in_pixels(SPUnitSelector *selector, GtkAdjustment *adj, double value) +{ + g_return_if_fail(selector != NULL); + g_return_if_fail(SP_IS_UNIT_SELECTOR(selector)); + + gtk_adjustment_set_value(adj, sp_pixels_get_units(value, *(selector->unit))); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : |
