Refactor duck reverse manipulation into duckmatic
[synfig.git] / synfig-studio / src / gui / duckmatic.h
1 /* === S Y N F I G ========================================================= */
2 /*!     \file duckmatic.h
3 **      \brief Template Header
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 /* === S T A R T =========================================================== */
25
26 #ifndef __SYNFIG_STUDIO_DUCKMATIC_H
27 #define __SYNFIG_STUDIO_DUCKMATIC_H
28
29 /* === H E A D E R S ======================================================= */
30
31 #include <list>
32 #include <map>
33 #include <set>
34
35 #include <ETL/smart_ptr>
36 #include <ETL/handle>
37
38 #include <synfig/vector.h>
39 #include <synfig/string.h>
40 #include <synfig/real.h>
41 #include <sigc++/signal.h>
42 #include <sigc++/object.h>
43 #include <synfig/time.h>
44 #include <synfig/color.h>
45 #include <ETL/smart_ptr>
46
47 #include "duck.h"
48 #include <synfig/color.h>
49 #include <synfig/guidset.h>
50
51 /* === M A C R O S ========================================================= */
52
53 #ifdef HASH_MAP_H
54 #include HASH_MAP_H
55 #include FUNCTIONAL_H
56
57 #ifndef __STRING_HASH__
58 #define __STRING_HASH__
59 class StringHash
60 {
61 # ifdef FUNCTIONAL_HASH_ON_STRING
62         HASH_MAP_NAMESPACE::hash<synfig::String> hasher_;
63 # else  // FUNCTIONAL_HASH_ON_STRING
64         HASH_MAP_NAMESPACE::hash<const char*> hasher_;
65 # endif  // FUNCTIONAL_HASH_ON_STRING
66 public:
67         size_t operator()(const synfig::String& x)const
68         {
69 # ifdef FUNCTIONAL_HASH_ON_STRING
70                 return hasher_(x);
71 # else  // FUNCTIONAL_HASH_ON_STRING
72                 return hasher_(x.c_str());
73 # endif  // FUNCTIONAL_HASH_ON_STRING
74         }
75 };
76 #endif
77 #else
78 #include <map>
79 #endif
80
81 /* === T Y P E D E F S ===================================================== */
82
83 /* === C L A S S E S & S T R U C T S ======================================= */
84
85 namespace synfigapp { class ValueDesc; class CanvasInterface; }
86 namespace synfig { class ParamDesc; }
87
88 namespace studio
89 {
90
91 class CanvasView;
92 class Duckmatic;
93
94 class DuckDrag_Base : public etl::shared_object
95 {
96 public:
97         virtual void begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& begin)=0;
98         virtual bool end_duck_drag(Duckmatic* duckmatic)=0;
99         virtual void duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector)=0;
100 };
101
102 class DuckDrag_Translate : public DuckDrag_Base
103 {
104         synfig::Vector last_translate_;
105         synfig::Vector drag_offset_;
106         synfig::Vector snap;
107         std::vector<synfig::Vector> positions;
108
109 public:
110         void begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& begin);
111         bool end_duck_drag(Duckmatic* duckmatic);
112         void duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector);
113 };
114
115 /*! \class Duckmatic
116 **
117 **      This class helps organize any of the devices displayed in
118 **      the work area that the user may want to interact with.
119 **      This includes ducks, beziers, and strokes
120 **
121 */
122 class Duckmatic
123 {
124         friend class DuckDrag_Base;
125         friend class DuckDrag_Translate;
126
127         /*
128  -- ** -- P U B L I C   T Y P E S ---------------------------------------------
129         */
130
131 public:
132
133 #ifdef HASH_MAP_H
134 typedef HASH_MAP_CLASS<synfig::GUID,etl::smart_ptr<synfig::Point>,synfig::GUIDHash> DuckDataMap;
135 #else
136 typedef std::map<synfig::GUID,etl::smart_ptr<synfig::Point> > DuckDataMap;
137 #endif
138
139         typedef studio::DuckMap DuckMap;
140
141         typedef studio::Duck Duck;
142
143         struct Stroke;
144
145         struct Bezier;
146
147         class Push;
148
149         friend class Push;
150
151         typedef Duck::Type Type;
152
153         typedef std::list<float> GuideList;
154
155         /*
156  -- ** -- P R I V A T E   D A T A ---------------------------------------------
157         */
158
159 private:
160
161         etl::loose_handle<synfigapp::CanvasInterface> canvas_interface;
162
163         Type type_mask;
164
165         DuckMap duck_map;
166
167         DuckDataMap duck_data_share_map;
168
169         std::list<etl::handle<Stroke> > stroke_list_;
170
171         std::list<etl::handle<Stroke> > persistent_stroke_list_;
172
173         synfig::GUIDSet selected_ducks;
174
175         synfig::GUID last_duck_guid;
176
177         std::list<etl::handle<Bezier> > bezier_list_;
178
179         //! I cannot recall what this is for
180         //synfig::Vector snap;
181
182         etl::handle<DuckDrag_Base> duck_dragger_;
183
184         sigc::signal<void> signal_duck_selection_changed_;
185
186         sigc::signal<void> signal_strokes_changed_;
187
188         sigc::signal<void> signal_grid_changed_;
189
190         mutable sigc::signal<void> signal_sketch_saved_;
191
192         GuideList guide_list_x_;
193         GuideList guide_list_y_;
194
195         mutable synfig::String sketch_filename_;
196
197         /*
198  -- ** -- P R O T E C T E D   D A T A -----------------------------------------
199         */
200
201 protected:
202
203         etl::handle<Bezier> selected_bezier;
204
205         synfig::Time cur_time;
206
207         //! This flag is set if operations should snap to the grid
208         /*! \todo perhaps there should be two of these flags, one for each axis?
209         **      \see show_grid, grid_size */
210         bool grid_snap;
211
212         bool guide_snap;
213
214         //! This vector describes the grid size.
215         /*! \see grid_snap, show_grid */
216         synfig::Vector grid_size;
217
218         bool show_persistent_strokes;
219
220         bool axis_lock;
221
222         /*
223  -- ** -- P R I V A T E   M E T H O D S ---------------------------------------
224         */
225
226 private:
227
228         synfig::Vector last_translate_;
229         synfig::Vector drag_offset_;
230
231         //etl::handle<Duck> selected_duck;
232
233
234         /*
235  -- ** -- P U B L I C   M E T H O D S -----------------------------------------
236         */
237
238 public:
239
240         Duckmatic(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface);
241         virtual ~Duckmatic();
242
243         sigc::signal<void>& signal_duck_selection_changed() { return signal_duck_selection_changed_; }
244         sigc::signal<void>& signal_strokes_changed() { return signal_strokes_changed_; }
245         sigc::signal<void>& signal_grid_changed() { return signal_grid_changed_; }
246         sigc::signal<void>& signal_sketch_saved() { return signal_sketch_saved_; }
247
248         GuideList& get_guide_list_x() { return guide_list_x_; }
249         GuideList& get_guide_list_y() { return guide_list_y_; }
250         const GuideList& get_guide_list_x()const { return guide_list_x_; }
251         const GuideList& get_guide_list_y()const { return guide_list_y_; }
252
253         void set_guide_snap(bool x=true);
254         bool get_guide_snap()const { return guide_snap; }
255         void toggle_guide_snap() { set_guide_snap(!get_guide_snap()); }
256
257         //! Sets the state of the grid snap flag
258         void set_grid_snap(bool x=true);
259
260         //! Gets the state of the grid snap flag
261         bool get_grid_snap()const { return grid_snap; }
262
263         void enable_grid_snap() { set_grid_snap(true); }
264
265         void disable_grid_snap() { set_grid_snap(false); }
266
267         void toggle_grid_snap() { set_grid_snap(!grid_snap); }
268
269         synfig::Point snap_point_to_grid(const synfig::Point& x, float radius=0.1)const;
270
271         bool get_show_persistent_strokes()const { return show_persistent_strokes; }
272         void set_show_persistent_strokes(bool x);
273
274         //! Sets the size of the grid
275         void set_grid_size(const synfig::Vector &s);
276
277         //! Returns the size of the grid
278         const synfig::Vector &get_grid_size()const { return grid_size; }
279
280
281         const synfig::Time &get_time()const { return cur_time; }
282
283         bool get_axis_lock()const { return axis_lock; }
284         void set_axis_lock(bool x) { axis_lock=x; }
285
286         void set_time(synfig::Time x) { cur_time=x; }
287
288         bool is_duck_group_selectable(const etl::handle<Duck>& x)const;
289
290         //const DuckMap& duck_map()const { return duck_map; }
291         DuckList get_duck_list()const;
292
293         const std::list<etl::handle<Bezier> >& bezier_list()const { return bezier_list_; }
294
295         const std::list<etl::handle<Stroke> >& stroke_list()const { return stroke_list_; }
296
297         const std::list<etl::handle<Stroke> >& persistent_stroke_list()const { return persistent_stroke_list_; }
298
299         std::list<etl::handle<Stroke> >& persistent_stroke_list() { return persistent_stroke_list_; }
300
301         //! \todo We should modify this to support multiple selections
302         etl::handle<Duck> get_selected_duck()const;
303
304         DuckList get_selected_ducks()const;
305
306         //! Returns \a true if the given duck is currently selected
307         bool duck_is_selected(const etl::handle<Duck> &duck)const;
308
309
310         void refresh_selected_ducks();
311
312         void clear_selected_ducks();
313
314         int count_selected_ducks()const;
315
316         void toggle_select_duck(const etl::handle<Duck> &duck);
317
318         void select_duck(const etl::handle<Duck> &duck);
319
320         void toggle_select_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br);
321
322         void select_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br);
323
324         void unselect_duck(const etl::handle<Duck> &duck);
325
326         //! Begin dragging ducks
327         /*! \param offset Canvas coordinates of the mouse when the drag began */
328         void start_duck_drag(const synfig::Vector& offset);
329
330         //! Continue dragging the selected ducks
331         /*! The overall vector of the drag is vector-offset
332          *  (where offset was given in start_duck_drag)
333          *  \param vector Canvas coordinates of the mouse at this moment */
334         void translate_selected_ducks(const synfig::Vector& vector);
335
336         //! Update the coordinates of tangents and linked-to-bline ducks
337         void update_ducks();
338
339         //! Ends the duck drag
340         bool end_duck_drag();
341
342         //! Signals to each selected duck that it has been clicked
343         void signal_user_click_selected_ducks(int button);
344
345         //! Calls all of the ducks' edited signals
346         /*! Updates corresponding valuenodes after a drag */
347         void signal_edited_selected_ducks();
348
349         bool on_duck_changed(const synfig::Point &value,const synfigapp::ValueDesc& value_desc);
350         bool on_duck_angle_changed(const synfig::Angle &rotation,const synfigapp::ValueDesc& value_desc);
351
352         etl::handle<Duck> find_similar_duck(etl::handle<Duck> duck);
353         etl::handle<Duck> add_similar_duck(etl::handle<Duck> duck);
354
355         void add_stroke(etl::smart_ptr<std::list<synfig::Point> > stroke_point_list, const synfig::Color& color=synfig::Color(0,0,0));
356
357         void add_persistent_stroke(etl::smart_ptr<std::list<synfig::Point> > stroke_point_list, const synfig::Color& color=synfig::Color(0,0,0));
358
359         void clear_persistent_strokes();
360
361         void add_duck(const etl::handle<Duck> &duck);
362
363         void add_bezier(const etl::handle<Bezier> &bezier);
364
365         void erase_duck(const etl::handle<Duck> &duck);
366
367         void erase_bezier(const etl::handle<Bezier> &bezier);
368
369         //! Returns the last duck added
370         etl::handle<Duck> last_duck()const;
371
372         etl::handle<Bezier> last_bezier()const;
373
374         //! \note parameter is in canvas coordinates
375         /*!     A radius of "zero" will have an unlimited radius */
376         etl::handle<Duck> find_duck(synfig::Point pos, synfig::Real radius=0, Duck::Type type=Duck::TYPE_DEFAULT);
377
378         GuideList::iterator find_guide_x(synfig::Point pos, float radius=0.1);
379         GuideList::iterator find_guide_y(synfig::Point pos, float radius=0.1);
380         GuideList::const_iterator find_guide_x(synfig::Point pos, float radius=0.1)const { return const_cast<Duckmatic*>(this)->find_guide_x(pos,radius); }
381         GuideList::const_iterator find_guide_y(synfig::Point pos, float radius=0.1)const { return const_cast<Duckmatic*>(this)->find_guide_y(pos,radius); }
382
383         //! \note parameter is in canvas coordinates
384         /*!     A radius of "zero" will have an unlimited radius */
385         //etl::handle<Bezier> find_bezier(synfig::Point pos, synfig::Real radius=0);
386
387         //! \note parameter is in canvas coordinates
388         /*!     A radius of "zero" will have an unlimited radius */
389         etl::handle<Bezier> find_bezier(synfig::Point pos, synfig::Real radius=0, float* location=0);
390
391         etl::handle<Bezier> find_bezier(synfig::Point pos, synfig::Real scale, synfig::Real radius, float* location=0);
392
393         bool add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<CanvasView> canvas_view, const synfig::TransformStack& transform_stack_, synfig::ParamDesc *param_desc=0, int multiple=0);
394
395         //! Set the type mask, which determines what types of ducks are shown
396         void set_type_mask(Type x) { type_mask=x; }
397
398         //! Get the type mask, which determines what types of ducks are shown
399         Type get_type_mask()const { return type_mask; }
400
401         void select_all_ducks();
402         void unselect_all_ducks();
403
404         void clear_ducks();
405
406         bool save_sketch(const synfig::String& filename)const;
407         bool load_sketch(const synfig::String& filename);
408         const synfig::String& get_sketch_filename()const { return sketch_filename_; }
409
410         void set_duck_dragger(etl::handle<DuckDrag_Base> x) { duck_dragger_=x; }
411         etl::handle<DuckDrag_Base> get_duck_dragger()const { return duck_dragger_; }
412         void clear_duck_dragger() { duck_dragger_=new DuckDrag_Translate(); }
413 }; // END of class Duckmatic
414
415
416 /*! \class Duckmatic::Push
417 **      \writeme */
418 class Duckmatic::Push
419 {
420         Duckmatic *duckmatic_;
421         DuckMap duck_map;
422         std::list<etl::handle<Bezier> > bezier_list_;
423         std::list<etl::handle<Stroke> > stroke_list_;
424         DuckDataMap duck_data_share_map;
425         etl::handle<DuckDrag_Base> duck_dragger_;
426
427         bool needs_restore;
428
429 public:
430         Push(Duckmatic *duckmatic_);
431         ~Push();
432         void restore();
433 }; // END of class Duckmatic::Push
434
435 /*! \struct Duckmatic::Bezier
436 **      \writeme */
437 struct Duckmatic::Bezier : public etl::shared_object
438 {
439 private:
440         sigc::signal<void,float> signal_user_click_[5];
441 public:
442
443         etl::handle<Duck> p1,p2,c1,c2;
444         bool is_valid()const { return p1 && p2 && c1 && c2; }
445
446         sigc::signal<void,float> &signal_user_click(int i=0) { assert(i>=0); assert(i<5); return signal_user_click_[i]; }
447 }; // END of struct Duckmatic::Bezier
448
449 /*! \struct Duckmatic::Stroke
450 **      \writeme */
451 struct Duckmatic::Stroke : public etl::shared_object
452 {
453 private:
454         sigc::signal<void,float> signal_user_click_[5];
455 public:
456
457         etl::smart_ptr<std::list<synfig::Point> > stroke_data;
458
459         synfig::Color color;
460
461         bool is_valid()const { return (bool)stroke_data; }
462
463         sigc::signal<void,float> &signal_user_click(int i=0) { assert(i>=0); assert(i<5); return signal_user_click_[i]; }
464 }; // END of struct Duckmatic::Stroke
465
466 }; // END of namespace studio
467
468 /* === E N D =============================================================== */
469
470 #endif