diff options
Diffstat (limited to 'src/ui/widget/unit-tracker.cpp')
| -rw-r--r-- | src/ui/widget/unit-tracker.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/ui/widget/unit-tracker.cpp b/src/ui/widget/unit-tracker.cpp new file mode 100644 index 000000000..5b2dc031b --- /dev/null +++ b/src/ui/widget/unit-tracker.cpp @@ -0,0 +1,263 @@ +/* + * Inkscape::UI::Widget::UnitTracker + * Simple mediator to synchronize changes to unit menus + * + * Authors: + * Jon A. Cruz <jon@joncruz.org> + * Matthew Petroff <matthew@mpetroff.net> + * + * Copyright (C) 2007 Jon A. Cruz + * Copyright (C) 2013 Matthew Petroff + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "unit-tracker.h" +#include "ege-select-one-action.h" + +#define COLUMN_STRING 0 + +using Inkscape::Util::UnitTable; +using Inkscape::Util::unit_table; + +namespace Inkscape { +namespace UI { +namespace Widget { + +UnitTracker::UnitTracker(UnitType unit_type) : + _active(0), + _isUpdating(false), + _activeUnitInitialized(false), + _store(0), + _unitList(0), + _actionList(0), + _adjList(0), + _priorValues() +{ + _store = gtk_list_store_new(1, G_TYPE_STRING); + + GtkTreeIter iter; + UnitTable::UnitMap m = unit_table.units(unit_type); + UnitTable::UnitMap::iterator m_iter = m.begin(); + while(m_iter != m.end()) { + Glib::ustring text = (*m_iter).first; + m_iter++; + gtk_list_store_append(_store, &iter); + gtk_list_store_set(_store, &iter, COLUMN_STRING, text.c_str(), -1); + } + gint count = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(_store), 0); + if ((count > 0) && (_active > count)) { + _setActive(--count); + } else { + _setActive(_active); + } +} + +UnitTracker::~UnitTracker() +{ + // Unhook weak references to GtkActions + while (_actionList) { + g_signal_handlers_disconnect_by_func(G_OBJECT(_actionList->data), (gpointer) _unitChangedCB, this); + g_object_weak_unref(G_OBJECT(_actionList->data), _actionFinalizedCB, this); + _actionList = g_slist_delete_link(_actionList, _actionList); + } + + // Unhook weak references to GtkAdjustments + while (_adjList) { + g_object_weak_unref(G_OBJECT(_adjList->data), _adjustmentFinalizedCB, this); + _adjList = g_slist_delete_link(_adjList, _adjList); + } +} + +bool UnitTracker::isUpdating() const +{ + return _isUpdating; +} + +Inkscape::Util::Unit UnitTracker::getActiveUnit() const +{ + return _activeUnit; +} + +void UnitTracker::setActiveUnit(Inkscape::Util::Unit const *unit) +{ + if (unit) { + GtkTreeIter iter; + int index = 0; + gboolean found = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(_store), &iter); + while (found) { + gchar *storedUnit = 0; + gtk_tree_model_get(GTK_TREE_MODEL(_store), &iter, COLUMN_STRING, &storedUnit, -1); + if (storedUnit && (!unit->abbr.compare(storedUnit))) { + _setActive(index); + break; + } + + found = gtk_tree_model_iter_next(GTK_TREE_MODEL(_store), &iter); + index++; + } + } +} + +void UnitTracker::setActiveUnitByAbbr(gchar const *abbr) +{ + Inkscape::Util::Unit u = unit_table.getUnit(abbr); + setActiveUnit(&u); +} + +void UnitTracker::addAdjustment(GtkAdjustment *adj) +{ + if (!g_slist_find(_adjList, adj)) { + g_object_weak_ref(G_OBJECT(adj), _adjustmentFinalizedCB, this); + _adjList = g_slist_append(_adjList, adj); + } +} + +void UnitTracker::addUnit(Inkscape::Util::Unit const &u) +{ + GtkTreeIter iter; + gtk_list_store_append(_store, &iter); + gtk_list_store_set(_store, &iter, COLUMN_STRING, u.abbr.c_str(), -1); +} + +void UnitTracker::setFullVal(GtkAdjustment *adj, gdouble val) +{ + _priorValues[adj] = val; +} + +GtkAction *UnitTracker::createAction(gchar const *name, gchar const *label, gchar const *tooltip) +{ + EgeSelectOneAction *act1 = ege_select_one_action_new(name, label, tooltip, NULL, GTK_TREE_MODEL(_store)); + ege_select_one_action_set_label_column(act1, COLUMN_STRING); + if (_active) { + ege_select_one_action_set_active(act1, _active); + } + + ege_select_one_action_set_appearance(act1, "minimal"); + g_object_weak_ref(G_OBJECT(act1), _actionFinalizedCB, this); + g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(_unitChangedCB), this); + _actionList = g_slist_append(_actionList, act1); + + return GTK_ACTION(act1); +} + +void UnitTracker::_unitChangedCB(GtkAction *action, gpointer data) +{ + if (action && data) { + EgeSelectOneAction *act = EGE_SELECT_ONE_ACTION(action); + gint active = ege_select_one_action_get_active(act); + UnitTracker *self = reinterpret_cast<UnitTracker *>(data); + self->_setActive(active); + } +} + +void UnitTracker::_actionFinalizedCB(gpointer data, GObject *where_the_object_was) +{ + if (data && where_the_object_was) { + UnitTracker *self = reinterpret_cast<UnitTracker *>(data); + self->_actionFinalized(where_the_object_was); + } +} + +void UnitTracker::_adjustmentFinalizedCB(gpointer data, GObject *where_the_object_was) +{ + if (data && where_the_object_was) { + UnitTracker *self = reinterpret_cast<UnitTracker *>(data); + self->_adjustmentFinalized(where_the_object_was); + } +} + +void UnitTracker::_actionFinalized(GObject *where_the_object_was) +{ + GSList *target = g_slist_find(_actionList, where_the_object_was); + if (target) { + _actionList = g_slist_remove(_actionList, where_the_object_was); + } else { + g_warning("Received a finalization callback for unknown object %p", where_the_object_was); + } +} + +void UnitTracker::_adjustmentFinalized(GObject *where_the_object_was) +{ + GSList *target = g_slist_find(_adjList, where_the_object_was); + if (target) { + _adjList = g_slist_remove(_adjList, where_the_object_was); + } else { + g_warning("Received a finalization callback for unknown object %p", where_the_object_was); + } +} + +void UnitTracker::_setActive(gint active) +{ + if ( active != _active || !_activeUnitInitialized ) { + gint oldActive = _active; + + GtkTreeIter iter; + gboolean found = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(_store), &iter, NULL, oldActive); + if (found) { + gchar *abbr; + gtk_tree_model_get(GTK_TREE_MODEL(_store), &iter, COLUMN_STRING, &abbr, -1); + Inkscape::Util::Unit unit = unit_table.getUnit(abbr); + + found = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(_store), &iter, NULL, active); + if (found) { + gchar *newAbbr; + gtk_tree_model_get(GTK_TREE_MODEL(_store), &iter, COLUMN_STRING, &newAbbr, -1); + Inkscape::Util::Unit newUnit = unit_table.getUnit(newAbbr); + _activeUnit = newUnit; + + if (_adjList) { + _fixupAdjustments(unit, newUnit); + } + + } else { + g_warning("Did not find new unit"); + } + } else { + g_warning("Did not find old unit"); + } + + _active = active; + + for ( GSList *cur = _actionList ; cur ; cur = g_slist_next(cur) ) { + if (IS_EGE_SELECT_ONE_ACTION(cur->data)) { + EgeSelectOneAction *act = EGE_SELECT_ONE_ACTION(cur->data); + ege_select_one_action_set_active(act, active); + } + } + + _activeUnitInitialized = true; + } +} + +void UnitTracker::_fixupAdjustments(Inkscape::Util::Unit const oldUnit, Inkscape::Util::Unit const newUnit) +{ + _isUpdating = true; + for ( GSList *cur = _adjList ; cur ; cur = g_slist_next(cur) ) { + GtkAdjustment *adj = GTK_ADJUSTMENT(cur->data); + gdouble oldVal = gtk_adjustment_get_value(adj); + gdouble val = oldVal; + + if ( (oldUnit.type != Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) + && (newUnit.type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) ) + { + val = newUnit.factor * 100; + _priorValues[adj] = Inkscape::Util::Quantity::convert(oldVal, oldUnit, "px"); + } else if ( (oldUnit.type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) + && (newUnit.type != Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) ) + { + if (_priorValues.find(adj) != _priorValues.end()) { + val = Inkscape::Util::Quantity::convert(_priorValues[adj], "px", newUnit); + } + } else { + val = Inkscape::Util::Quantity::convert(oldVal, oldUnit, newUnit); + } + + gtk_adjustment_set_value(adj, val); + } + _isUpdating = false; +} + +} // namespace Widget +} // namespace UI +} // namespace Inkscape |
