Use the short form for toggle-onion-skin because we can.
[synfig.git] / synfig-studio / trunk / 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 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include "duck.h"
34 #include <ETL/misc>
35
36 #include "general.h"
37
38 #endif
39
40 /* === U S I N G =========================================================== */
41
42 using namespace std;
43 using namespace etl;
44 using namespace synfig;
45 using namespace studio;
46
47 /* === M A C R O S ========================================================= */
48
49 /* === G L O B A L S ======================================================= */
50
51 int studio::Duck::duck_count(0);
52
53 struct _DuckCounter
54 {
55         static int counter;
56         ~_DuckCounter()
57         {
58                 if(counter)
59                         synfig::error("%d ducks not yet deleted!",counter);
60         }
61 } _duck_counter;
62
63 int _DuckCounter::counter(0);
64
65
66 /* === P R O C E D U R E S ================================================= */
67
68 /* === M E T H O D S ======================================================= */
69
70 Duck::Duck():
71         rotations(synfig::Angle::deg(0)),
72         origin(0,0),
73         scalar(1),
74         editable(false),
75         radius_(false),
76         tangent_(false),
77         hover_(false),
78         ignore_(false)
79 { duck_count++; _DuckCounter::counter++; }
80
81 Duck::Duck(const synfig::Point &point):
82         type_(TYPE_NONE),
83         point(point),
84         rotations(synfig::Angle::deg(0)),
85         origin(0,0),
86         scalar(1),
87         guid_(0),
88         editable(false),
89         radius_(false),
90         tangent_(false),
91         hover_(false),
92         ignore_(false)
93 { duck_count++; _DuckCounter::counter++;}
94
95 Duck::Duck(const synfig::Point &point,const synfig::Point &origin):
96         point(point),
97         rotations(synfig::Angle::deg(0)),
98         origin(origin),
99         scalar(1),
100         guid_(0),
101         editable(false),
102         radius_(true),
103         tangent_(false),
104         hover_(false),
105         ignore_(false)
106 { duck_count++; _DuckCounter::counter++;}
107
108 Duck::~Duck() { duck_count--; _DuckCounter::counter--;}
109
110 synfig::GUID
111 Duck::get_data_guid()const
112 {
113         if(value_desc_.is_value_node())
114                 return value_desc_.get_value_node()->get_guid();
115         return synfig::GUID::hasher(get_name());
116 }
117
118 void
119 Duck::set_name(const synfig::String &x)
120 {
121         name=x;
122         if(guid_==synfig::GUID::zero())
123         {
124                 guid_=synfig::GUID::hasher(name);
125         }
126 }
127
128
129 bool
130 Duck::operator==(const Duck &rhs)const
131 {
132         if(this==&rhs)
133                 return true;
134         return
135                 name==rhs.name &&
136                 scalar==rhs.scalar &&
137                 type_==rhs.type_ &&
138                 transform_stack_.size()==rhs.transform_stack_.size();
139                 //true;
140                 //(origin_duck?*origin_duck==*rhs.origin_duck:origin==rhs.origin) &&
141                 //(shared_point?*shared_point==*rhs.shared_point:point==rhs.point) ;
142 }
143
144 synfig::Point
145 Duck::get_trans_point()const
146 {
147         return transform_stack_.perform(get_sub_trans_point());
148 }
149
150 void
151 Duck::set_trans_point(const synfig::Point &x)
152 {
153         set_sub_trans_point(transform_stack_.unperform(x));
154 }
155
156 //! Sets the origin point.
157 void
158 Duck::set_origin(const synfig::Point &x)
159 {
160         origin=x; origin_duck=0;
161 }
162
163 //! Sets the origin point as another duck
164 void
165 Duck::set_origin(const etl::handle<Duck> &x)
166 {
167         origin_duck=x;
168 }
169
170 //! Retrieves the origin location
171 synfig::Point
172 Duck::get_origin()const
173 {
174         return origin_duck?origin_duck->get_point():origin;
175 }
176
177 //! Retrieves the origin duck
178 const etl::handle<Duck> &
179 Duck::get_origin_duck() const
180 {
181         return origin_duck;
182 }
183
184 //! Retrieves the origin location
185 synfig::Point
186 Duck::get_trans_origin()const
187 {
188         return transform_stack_.perform(get_sub_trans_origin());
189 }
190
191 synfig::Point
192 Duck::get_sub_trans_point()const
193 {
194         return get_point()*get_scalar()+get_sub_trans_origin();
195 }
196
197 void
198 Duck::set_sub_trans_point(const synfig::Point &x)
199 {
200         if (get_type() == Duck::TYPE_TANGENT ||
201                 get_type() == Duck::TYPE_ANGLE)
202         {
203                 Angle old_angle = get_point().angle();
204                 set_point((x-get_sub_trans_origin())/get_scalar());
205                 Angle change = get_point().angle() - old_angle;
206                 while (change < Angle::deg(-180)) change += Angle::deg(360);
207                 while (change > Angle::deg(180)) change -= Angle::deg(360);
208                 int old_halves = round_to_int(Angle::deg(rotations).get()/180);
209                 rotations += change;
210                 int new_halves = round_to_int(Angle::deg(rotations).get()/180);
211                 if (old_halves != new_halves &&
212                         (new_halves > 1 || new_halves < -1 ||
213                          old_halves > 1 || old_halves < -1))
214                         synfig::info("rotation: %.2f turns", new_halves/2.0);
215         }
216         else
217                 set_point((x-get_sub_trans_origin())/get_scalar());
218 }
219
220 synfig::Point
221 Duck::get_sub_trans_origin()const
222 {
223         return origin_duck?origin_duck->get_sub_trans_point():origin;
224 }
225
226 #ifdef _DEBUG
227 synfig::String
228 Duck::type_name(Type id)
229 {
230         String ret;
231
232         if (id & TYPE_POSITION) { if (!ret.empty()) ret += ", "; ret += "position"; }
233         if (id & TYPE_TANGENT ) { if (!ret.empty()) ret += ", "; ret += "tangent" ; }
234         if (id & TYPE_RADIUS  ) { if (!ret.empty()) ret += ", "; ret += "radius"  ; }
235         if (id & TYPE_WIDTH       ) { if (!ret.empty()) ret += ", "; ret += "width"   ; }
236         if (id & TYPE_ANGLE       ) { if (!ret.empty()) ret += ", "; ret += "angle"   ; }
237         if (id & TYPE_VERTEX  ) { if (!ret.empty()) ret += ", "; ret += "vertex"  ; }
238
239         if (ret.empty())
240                 ret = "none";
241
242         return ret;
243 }
244 #endif  // _DEBUG