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