Code

Enable simultaneous knotholder and nodepath
[inkscape.git] / src / knot-holder-entity.cpp
1 #define __KNOT_HOLDER_ENTITY_C__
3 /** \file 
4  * KnotHolderEntity definition. 
5  * 
6  * Authors:
7  *   Mitsuru Oka <oka326@parkcity.ne.jp>
8  *   Maximilian Albert <maximilian.albert@gmail.com>
9  *
10  * Copyright (C) 1999-2001 Lauris Kaplinski
11  * Copyright (C) 2000-2001 Ximian, Inc.
12  * Copyright (C) 2001 Mitsuru Oka
13  * Copyright (C) 2004 Monash University
14  * Copyright (C) 2008 Maximilian Albert
15  *
16  * Released under GNU GPL
17  */
19 #include "knotholder.h"
20 #include "sp-item.h"
21 #include "style.h"
22 #include "prefs-utils.h"
23 #include "macros.h"
24 #include <libnr/nr-matrix-ops.h>
25 #include "sp-pattern.h"
28 int KnotHolderEntity::counter = 0;
30 void
31 KnotHolderEntity::create(SPDesktop *desktop, SPItem *item, KnotHolder *parent, const gchar *tip,
32                          SPKnotShapeType shape, SPKnotModeType mode, guint32 color)
33 {
34     knot = sp_knot_new(desktop, tip);
36     this->parent_holder = parent;
37     this->item = item; // TODO: remove the item either from here or from knotholder.cpp
39     my_counter = KnotHolderEntity::counter++;
41     g_object_set(G_OBJECT (knot->item), "shape", shape, NULL);
42     g_object_set(G_OBJECT (knot->item), "mode", mode, NULL);
44     knot->fill [SP_KNOT_STATE_NORMAL] = color;
45     g_object_set (G_OBJECT (knot->item), "fill_color", color, NULL);
47     update_knot();
48     sp_knot_show(knot);
50     _moved_connection = knot->_moved_signal.connect(sigc::mem_fun(*parent_holder, &KnotHolder::knot_moved_handler));
51     _click_connection = knot->_click_signal.connect(sigc::mem_fun(*parent_holder, &KnotHolder::knot_clicked_handler));
52     _ungrabbed_connection = knot->_ungrabbed_signal.connect(sigc::mem_fun(*parent_holder, &KnotHolder::knot_ungrabbed_handler));
53 }
56 KnotHolderEntity::~KnotHolderEntity()
57 {
58     /* unref should call destroy */
59     if (knot) {
60         g_object_unref(knot);
61     } else {
62         // FIXME: This shouldn't occur. Perhaps it is caused by LPE PointParams being knotholder entities, too
63         //        If so, it will likely be fixed with upcoming refactoring efforts.
64         g_return_if_fail(knot);
65     }
66 }
68 void
69 KnotHolderEntity::update_knot()
70 {
71     NR::Matrix const i2d(from_2geom(sp_item_i2d_affine(item)));
73     NR::Point dp(knot_get() * i2d);
75     _moved_connection.block();
76     sp_knot_set_position(knot, &dp, SP_KNOT_STATE_NORMAL); 
77     _moved_connection.unblock();
78 }
80 /* Pattern manipulation */
82 static gdouble sp_pattern_extract_theta(SPPattern *pat, gdouble scale)
83 {
84     gdouble theta = asin(pat->patternTransform[1] / scale);
85     if (pat->patternTransform[0] < 0) theta = M_PI - theta ;
86     return theta;
87 }
89 static gdouble sp_pattern_extract_scale(SPPattern *pat)
90 {
91     gdouble s = pat->patternTransform[1];
92     gdouble c = pat->patternTransform[0];
93     gdouble xscale = sqrt(c * c + s * s);
94     return xscale;
95 }
97 static NR::Point sp_pattern_extract_trans(SPPattern const *pat)
98 {
99     return NR::Point(pat->patternTransform[4], pat->patternTransform[5]);
102 void
103 PatternKnotHolderEntityXY::knot_set(NR::Point const &p, NR::Point const &origin, guint state)
105     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
107     NR::Point p_snapped = p;
109     if ( state & GDK_CONTROL_MASK ) {
110         if (fabs((p - origin)[NR::X]) > fabs((p - origin)[NR::Y])) {
111             p_snapped[NR::Y] = origin[NR::Y];
112         } else {
113             p_snapped[NR::X] = origin[NR::X];
114         }
115     }
117     if (state)  {
118         NR::Point const q = p_snapped - sp_pattern_extract_trans(pat);
119         sp_item_adjust_pattern(item, NR::Matrix(NR::translate(q)));
120     }
122     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
125 NR::Point
126 PatternKnotHolderEntityXY::knot_get()
128     SPPattern const *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
129     return sp_pattern_extract_trans(pat);
132 NR::Point
133 PatternKnotHolderEntityAngle::knot_get()
135     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
137     gdouble x = (pattern_width(pat)*0.5);
138     gdouble y = 0;
139     NR::Point delta = NR::Point(x,y);
140     gdouble scale = sp_pattern_extract_scale(pat);
141     gdouble theta = sp_pattern_extract_theta(pat, scale);
142     delta = delta * NR::Matrix(NR::rotate(theta))*NR::Matrix(NR::scale(scale,scale));
143     delta = delta + sp_pattern_extract_trans(pat);
144     return delta;
147 void
148 PatternKnotHolderEntityAngle::knot_set(NR::Point const &p, NR::Point const &/*origin*/, guint state)
150     int const snaps = prefs_get_int_attribute("options.rotationsnapsperpi", "value", 12);
152     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
154     // get the angle from pattern 0,0 to the cursor pos
155     NR::Point delta = p - sp_pattern_extract_trans(pat);
156     gdouble theta = atan2(delta);
158     if ( state & GDK_CONTROL_MASK ) {
159         theta = sp_round(theta, M_PI/snaps);
160     }
162     // get the scale from the current transform so we can keep it.
163     gdouble scl = sp_pattern_extract_scale(pat);
164     NR::Matrix rot =  NR::Matrix(NR::rotate(theta)) * NR::Matrix(NR::scale(scl,scl));
165     NR::Point const t = sp_pattern_extract_trans(pat);
166     rot[4] = t[NR::X];
167     rot[5] = t[NR::Y];
168     sp_item_adjust_pattern(item, rot, true);
169     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
172 void
173 PatternKnotHolderEntityScale::knot_set(NR::Point const &p, NR::Point const &/*origin*/, guint /*state*/)
175     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
177     // Get the scale from the position of the knotholder,
178     NR::Point d = p - sp_pattern_extract_trans(pat);
179     gdouble s = NR::L2(d);
180     gdouble pat_x = pattern_width(pat) * 0.5;
181     gdouble pat_y = pattern_height(pat) * 0.5;
182     gdouble pat_h = hypot(pat_x, pat_y);
183     gdouble scl = s / pat_h;
185     // get angle from current transform, (need get current scale first to calculate angle)
186     gdouble oldscale = sp_pattern_extract_scale(pat);
187     gdouble theta = sp_pattern_extract_theta(pat,oldscale);
189     NR::Matrix rot =  NR::Matrix(NR::rotate(theta)) * NR::Matrix(NR::scale(scl,scl));
190     NR::Point const t = sp_pattern_extract_trans(pat);
191     rot[4] = t[NR::X];
192     rot[5] = t[NR::Y];
193     sp_item_adjust_pattern(item, rot, true);
194     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
198 NR::Point
199 PatternKnotHolderEntityScale::knot_get()
201     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
203     gdouble x = pattern_width(pat)*0.5;
204     gdouble y = pattern_height(pat)*0.5;
205     NR::Point delta = NR::Point(x,y);
206     NR::Matrix a = pat->patternTransform;
207     a[4] = 0;
208     a[5] = 0;
209     delta = delta * a;
210     delta = delta + sp_pattern_extract_trans(pat);
211     return delta;
214 /*
215   Local Variables:
216   mode:c++
217   c-file-style:"stroustrup"
218   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
219   indent-tabs-mode:nil
220   fill-column:99
221   End:
222 */
223 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :