Code

Filter effects dialog:
[inkscape.git] / src / helper / unit-tracker.cpp
1 /*
2  * Inkscape::UnitTracker - Simple mediator to synchronize changes to a set
3  *   of possible units
4  *
5  * Authors:
6  *   Jon A. Cruz <jon@joncruz.org>
7  *
8  * Copyright (C) 2007 Jon A. Cruz
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #include <gtk/gtkliststore.h>
15 #include "unit-tracker.h"
16 #include "ege-select-one-action.h"
18 namespace Inkscape {
20 enum {
21     COLUMN_STRING,
22     COLUMN_SPUNIT,
23     N_COLUMNS
24 };
26 UnitTracker::UnitTracker( guint bases ) :
27     _active(0),
28     _isUpdating(false),
29     _activeUnit(0),
30     _store(0),
31     _unitList(0),
32     _actionList(0),
33     _adjList(0),
34     _priorValues()
35 {
36     _store = gtk_list_store_new( N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER );
37     setBase( bases );
38 }
40 UnitTracker::~UnitTracker()
41 {
42     if ( _unitList ) {
43         sp_unit_free_list( _unitList );
44     }
46     // Unhook weak references to GtkActions
47     while ( _actionList ) {
48         g_signal_handlers_disconnect_by_func( G_OBJECT(_actionList->data), (gpointer)_unitChangedCB, this );
49         g_object_weak_unref( G_OBJECT(_actionList->data), _actionFinalizedCB, this );
50         _actionList = g_slist_delete_link( _actionList, _actionList );
51     }
53     // Unhook wek references to GtkAdjustments
54     while ( _adjList ) {
55         g_object_weak_unref( G_OBJECT(_adjList->data), _adjustmentFinalizedCB, this );
56         _adjList = g_slist_delete_link( _adjList, _adjList );
57     }
58 }
60 void UnitTracker::setBase( guint bases )
61 {
62     GtkTreeIter iter;
63     _unitList = sp_unit_get_list( bases );
64     for ( GSList* cur = _unitList; cur; cur = g_slist_next(cur) ) {
65         SPUnit* unit = static_cast<SPUnit*>(cur->data);
66         gtk_list_store_append( _store, &iter );
67         gtk_list_store_set( _store, &iter, COLUMN_STRING, unit->abbr, COLUMN_SPUNIT, unit, -1 );
68     }
69     gint count = gtk_tree_model_iter_n_children( GTK_TREE_MODEL(_store), 0 );
70     if ( (count > 0) && (_active > count) ) {
71         _setActive( count - 1 );
72     }
73 }
75 void UnitTracker::addUnit( SPUnitId id, gint index )
76 {
77     GtkTreeIter iter;
78     const SPUnit* percentUnit = &sp_unit_get_by_id( id );
79     gtk_list_store_insert( _store, &iter, index );
80     gtk_list_store_set( _store, &iter, COLUMN_STRING, percentUnit->abbr, COLUMN_SPUNIT, percentUnit, -1 );
81 }
83 bool UnitTracker::isUpdating() const
84 {
85     return _isUpdating;
86 }
88 SPUnit const* UnitTracker::getActiveUnit() const
89 {
90     return _activeUnit;
91 }
93 void UnitTracker::setActiveUnit( SPUnit const *unit )
94 {
95     if ( unit ) {
96         GtkTreeIter iter;
97         int index = 0;
98         gboolean found = gtk_tree_model_get_iter_first( GTK_TREE_MODEL(_store), &iter );
99         while ( found ) {
100             SPUnit* storedUnit = 0;
101             gtk_tree_model_get( GTK_TREE_MODEL(_store), &iter, COLUMN_SPUNIT, &storedUnit, -1 );
102             if ( storedUnit && (storedUnit->unit_id == unit->unit_id) ) {
103                 _setActive(index);
104                 break;
105             }
107             found = gtk_tree_model_iter_next( GTK_TREE_MODEL(_store), &iter );
108             index++;
109         }
110     }
113 void UnitTracker::addAdjustment( GtkAdjustment* adj )
115     if ( !g_slist_find( _adjList, adj ) ) {
116         g_object_weak_ref( G_OBJECT(adj), _adjustmentFinalizedCB, this );
117         _adjList = g_slist_append( _adjList, adj );
118     }
121 void UnitTracker::setFullVal( GtkAdjustment* adj, gdouble val )
123     _priorValues[adj] = val;
126 GtkAction* UnitTracker::createAction( gchar const* name, gchar const* label, gchar const* tooltip )
128     EgeSelectOneAction* act1 = ege_select_one_action_new( name, label, tooltip, NULL, GTK_TREE_MODEL(_store) );
129     ege_select_one_action_set_label_column( act1, COLUMN_STRING );
130     if ( _active ) {
131         ege_select_one_action_set_active( act1, _active );
132     }
134     g_object_weak_ref( G_OBJECT(act1), _actionFinalizedCB, this );
135     g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK( _unitChangedCB ), this );
136     _actionList = g_slist_append( _actionList, act1 );
138     return GTK_ACTION(act1);
141 void UnitTracker::_unitChangedCB( GtkAction* action, gpointer data )
143     if ( action && data ) {
144         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(action);
145         gint active = ege_select_one_action_get_active( act );
146         UnitTracker* self = reinterpret_cast<UnitTracker*>(data);
147         self->_setActive(active);
148     }
151 void UnitTracker::_actionFinalizedCB( gpointer data, GObject *where_the_object_was )
153     if ( data && where_the_object_was ) {
154         UnitTracker* self = reinterpret_cast<UnitTracker*>(data);
155         self->_actionFinalized( where_the_object_was );
156     }
159 void UnitTracker::_adjustmentFinalizedCB( gpointer data, GObject *where_the_object_was )
161     if ( data && where_the_object_was ) {
162         UnitTracker* self = reinterpret_cast<UnitTracker*>(data);
163         self->_adjustmentFinalized( where_the_object_was );
164     }
167 void UnitTracker::_actionFinalized( GObject *where_the_object_was )
169     GSList* target = g_slist_find( _actionList, where_the_object_was );
170     if ( target ) {
171         _actionList = g_slist_remove( _actionList, where_the_object_was );
172     } else {
173         g_warning("Received a finalization callback for unknown object %p", where_the_object_was );
174     }
177 void UnitTracker::_adjustmentFinalized( GObject *where_the_object_was )
179     GSList* target = g_slist_find( _adjList, where_the_object_was );
180     if ( target ) {
181         _adjList = g_slist_remove( _adjList, where_the_object_was );
182     } else {
183         g_warning("Received a finalization callback for unknown object %p", where_the_object_was );
184     }
187 void UnitTracker::_setActive( gint active )
189     if ( active != _active ) {
190         gint oldActive = _active;
192         GtkTreeIter iter;
193         gboolean found = gtk_tree_model_iter_nth_child( GTK_TREE_MODEL(_store), &iter, NULL, oldActive );
194         if ( found ) {
195             SPUnit* unit = 0;
196             gtk_tree_model_get( GTK_TREE_MODEL(_store), &iter, COLUMN_SPUNIT, &unit, -1 );
198             found = gtk_tree_model_iter_nth_child( GTK_TREE_MODEL(_store), &iter, NULL, active );
199             if ( found ) {
200                 SPUnit* newUnit = 0;
201                 gtk_tree_model_get( GTK_TREE_MODEL(_store), &iter, COLUMN_SPUNIT, &newUnit, -1 );
202                 _activeUnit = newUnit;
204                 if ( _adjList ) {
205                     _fixupAdjustments( unit, newUnit );
206                 }
208             } else {
209                 g_warning("Did not find new unit");
210             }
211         } else {
212             g_warning("Did not find old unit");
213         }
215         _active = active;
217         for ( GSList* cur = _actionList; cur; cur = g_slist_next(cur) ) {
218             if ( IS_EGE_SELECT_ONE_ACTION( cur->data ) ) {
219                 EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION( cur->data );
220                 ege_select_one_action_set_active( act, active );
221             }
222         }
223     }
226 void UnitTracker::_fixupAdjustments( SPUnit const* oldUnit, SPUnit const *newUnit )
228     _isUpdating = true;
229     for ( GSList* cur = _adjList; cur; cur = g_slist_next(cur) ) {
230         GtkAdjustment* adj = GTK_ADJUSTMENT(cur->data);
231         gdouble oldVal = gtk_adjustment_get_value(adj);
232         gdouble val = oldVal;
234         if ((oldUnit->base == SP_UNIT_ABSOLUTE || oldUnit->base == SP_UNIT_DEVICE)
235             && (newUnit->base == SP_UNIT_DIMENSIONLESS))
236         {
237             val = 1.0 / newUnit->unittobase;
238             _priorValues[adj] = sp_units_get_pixels( oldVal, *oldUnit );
239         } else if ((oldUnit->base == SP_UNIT_DIMENSIONLESS)
240                    && (newUnit->base == SP_UNIT_ABSOLUTE || newUnit->base == SP_UNIT_DEVICE)) {
241             if ( _priorValues.find(adj) != _priorValues.end() ) {
242                 val = sp_pixels_get_units( _priorValues[adj], *newUnit );
243             }
244         } else {
245             val = sp_convert_distance_full( oldVal, *oldUnit, *newUnit );
246         }
248         gtk_adjustment_set_value( adj, val );
249     }
250     _isUpdating = false;
255 /*
256   Local Variables:
257   mode:c++
258   c-file-style:"stroustrup"
259   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
260   indent-tabs-mode:nil
261   fill-column:99
262   End:
263 */
264 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :