Add actions (add to group, ,remove from group, export, un-export, set layer descripti...
[synfig.git] / synfig-studio / src / gtkmm / duck.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file duck.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **      Copyright (c) 2009 Nikita Kitaev
11 **
12 **      This package is free software; you can redistribute it and/or
13 **      modify it under the terms of the GNU General Public License as
14 **      published by the Free Software Foundation; either version 2 of
15 **      the License, or (at your option) any later version.
16 **
17 **      This package is distributed in the hope that it will be useful,
18 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 **      General Public License for more details.
21 **      \endlegal
22 */
23 /* ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #ifdef USING_PCH
28 #       include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #       include <config.h>
32 #endif
33
34 #include "duck.h"
35 #include <ETL/misc>
36
37 #include <synfig/valuenode_bline.h>
38 #include <synfig/valuenode_blinecalctangent.h>
39 #include <synfig/valuenode_blinecalcvertex.h>
40 #include <synfig/valuenode_blinecalcwidth.h>
41 #include <synfig/valuenode_composite.h>
42
43 #include "general.h"
44 #endif
45
46 /* === U S I N G =========================================================== */
47
48 using namespace std;
49 using namespace etl;
50 using namespace synfig;
51 using namespace studio;
52
53 /* === M A C R O S ========================================================= */
54
55 /* === G L O B A L S ======================================================= */
56
57 int studio::Duck::duck_count(0);
58
59 struct _DuckCounter
60 {
61         static int counter;
62         ~_DuckCounter()
63         {
64                 if(counter)
65                         synfig::error("%d ducks not yet deleted!",counter);
66         }
67 } _duck_counter;
68
69 int _DuckCounter::counter(0);
70
71
72 /* === P R O C E D U R E S ================================================= */
73
74 /* === M E T H O D S ======================================================= */
75
76 Duck::Duck():
77         rotations(synfig::Angle::deg(0)),
78         origin(0,0),
79         scalar(1),
80         editable(false),
81         radius_(false),
82         tangent_(false),
83         hover_(false),
84         ignore_(false)
85 { duck_count++; _DuckCounter::counter++; }
86
87 Duck::Duck(const synfig::Point &point):
88         type_(TYPE_NONE),
89         point(point),
90         rotations(synfig::Angle::deg(0)),
91         origin(0,0),
92         scalar(1),
93         guid_(0),
94         editable(false),
95         radius_(false),
96         tangent_(false),
97         hover_(false),
98         ignore_(false)
99 { duck_count++; _DuckCounter::counter++;}
100
101 Duck::Duck(const synfig::Point &point,const synfig::Point &origin):
102         point(point),
103         rotations(synfig::Angle::deg(0)),
104         origin(origin),
105         scalar(1),
106         guid_(0),
107         editable(false),
108         radius_(true),
109         tangent_(false),
110         hover_(false),
111         ignore_(false)
112 { duck_count++; _DuckCounter::counter++;}
113
114 Duck::~Duck() { duck_count--; _DuckCounter::counter--;}
115
116 synfig::GUID
117 Duck::get_data_guid()const
118 {
119         if(value_desc_.is_value_node())
120                 return value_desc_.get_value_node()->get_guid();
121         return synfig::GUID::hasher(get_name());
122 }
123
124 void
125 Duck::set_name(const synfig::String &x)
126 {
127         name=x;
128         if(guid_==synfig::GUID::zero())
129         {
130                 guid_=synfig::GUID::hasher(name);
131         }
132 }
133
134
135 bool
136 Duck::operator==(const Duck &rhs)const
137 {
138         if(this==&rhs)
139                 return true;
140         return
141                 name==rhs.name &&
142                 scalar==rhs.scalar &&
143                 type_==rhs.type_ &&
144                 transform_stack_.size()==rhs.transform_stack_.size();
145                 //true;
146                 //(origin_duck?*origin_duck==*rhs.origin_duck:origin==rhs.origin) &&
147                 //(shared_point?*shared_point==*rhs.shared_point:point==rhs.point) ;
148 }
149
150 synfig::Point
151 Duck::get_trans_point()const
152 {
153         return transform_stack_.perform(get_sub_trans_point());
154 }
155
156 void
157 Duck::set_trans_point(const synfig::Point &x)
158 {
159         set_sub_trans_point(transform_stack_.unperform(x));
160 }
161
162 void
163 Duck::set_trans_point(const synfig::Point &x, const synfig::Time &time)
164 {
165         set_sub_trans_point(transform_stack_.unperform(x), time);
166 }
167
168 //! Sets the origin point.
169 void
170 Duck::set_origin(const synfig::Point &x)
171 {
172         origin=x; origin_duck=0;
173 }
174
175 //! Sets the origin point as another duck
176 void
177 Duck::set_origin(const etl::handle<Duck> &x)
178 {
179         origin_duck=x;
180 }
181
182 //! Retrieves the origin location
183 synfig::Point
184 Duck::get_origin()const
185 {
186         return origin_duck?origin_duck->get_point():origin;
187 }
188
189 //! Retrieves the origin duck
190 const etl::handle<Duck> &
191 Duck::get_origin_duck() const
192 {
193         return origin_duck;
194 }
195
196 //! Retrieves the origin location
197 synfig::Point
198 Duck::get_trans_origin()const
199 {
200         return transform_stack_.perform(get_sub_trans_origin());
201 }
202
203 synfig::Point
204 Duck::get_sub_trans_point()const
205 {
206         return get_point()*get_scalar()+get_sub_trans_origin();
207 }
208
209 void
210 Duck::set_sub_trans_point(const synfig::Point &x, const synfig::Time &time)
211 {
212         if (get_type() == Duck::TYPE_TANGENT ||
213                 get_type() == Duck::TYPE_ANGLE)
214         {
215                 Angle old_angle = get_point().angle();
216                 set_point((x-get_sub_trans_origin())/get_scalar());
217                 Angle change = get_point().angle() - old_angle;
218                 while (change < Angle::deg(-180)) change += Angle::deg(360);
219                 while (change > Angle::deg(180)) change -= Angle::deg(360);
220                 int old_halves = round_to_int(Angle::deg(rotations).get()/180);
221                 rotations += change;
222                 int new_halves = round_to_int(Angle::deg(rotations).get()/180);
223                 if (old_halves != new_halves &&
224                         (new_halves > 1 || new_halves < -1 ||
225                          old_halves > 1 || old_halves < -1))
226                         synfig::info("rotation: %.2f turns", new_halves/2.0);
227         } else if(get_type() == Duck::TYPE_VERTEX || get_type() == Duck::TYPE_POSITION)
228         {
229                 set_point((x-get_sub_trans_origin())/get_scalar());
230
231                 ValueNode_BLineCalcVertex::Handle bline_vertex;
232                 ValueNode_Composite::Handle composite;
233
234                 if ((bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(get_value_desc().get_value_node())) ||
235                         ((composite = ValueNode_Composite::Handle::cast_dynamic(get_value_desc().get_value_node())) &&
236                          composite->get_type() == ValueBase::TYPE_BLINEPOINT &&
237                          (bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(composite->get_link("point")))))
238                 {
239                         synfig::Point closest_point = get_point();
240                         synfig::Real radius = 0.0;
241                         ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link(bline_vertex->get_link_index_from_name("bline")));
242                         synfig::find_closest_point(
243                                 (*bline)(time),
244                                 get_point(),
245                                 radius,
246                                 bline->get_loop(),
247                                 &closest_point);
248                         set_point(closest_point);
249                 }
250         }
251         else set_point((x-get_sub_trans_origin())/get_scalar());
252 }
253
254 void
255 Duck::set_sub_trans_point(const synfig::Point &x)
256 {
257         if (get_type() == Duck::TYPE_TANGENT ||
258                 get_type() == Duck::TYPE_ANGLE)
259         {
260                 Angle old_angle = get_point().angle();
261                 set_point((x-get_sub_trans_origin())/get_scalar());
262                 Angle change = get_point().angle() - old_angle;
263                 while (change < Angle::deg(-180)) change += Angle::deg(360);
264                 while (change > Angle::deg(180)) change -= Angle::deg(360);
265                 int old_halves = round_to_int(Angle::deg(rotations).get()/180);
266                 rotations += change;
267                 int new_halves = round_to_int(Angle::deg(rotations).get()/180);
268                 if (old_halves != new_halves &&
269                         (new_halves > 1 || new_halves < -1 ||
270                          old_halves > 1 || old_halves < -1))
271                         synfig::info("rotation: %.2f turns", new_halves/2.0);
272         }
273         else set_point((x-get_sub_trans_origin())/get_scalar());
274 }
275
276 synfig::Point
277 Duck::get_sub_trans_origin()const
278 {
279         return origin_duck?origin_duck->get_sub_trans_point():origin;
280 }
281
282 #ifdef _DEBUG
283 synfig::String
284 Duck::type_name(Type id)
285 {
286         String ret;
287
288         if (id & TYPE_POSITION) { if (!ret.empty()) ret += ", "; ret += "position"; }
289         if (id & TYPE_TANGENT ) { if (!ret.empty()) ret += ", "; ret += "tangent" ; }
290         if (id & TYPE_RADIUS  ) { if (!ret.empty()) ret += ", "; ret += "radius"  ; }
291         if (id & TYPE_WIDTH       ) { if (!ret.empty()) ret += ", "; ret += "width"   ; }
292         if (id & TYPE_ANGLE       ) { if (!ret.empty()) ret += ", "; ret += "angle"   ; }
293         if (id & TYPE_VERTEX  ) { if (!ret.empty()) ret += ", "; ret += "vertex"  ; }
294
295         if (ret.empty())
296                 ret = "none";
297
298         return ret;
299 }
300 #endif  // _DEBUG