Fix most of the warnings from doxygen for synfig-studio sources.
[synfig.git] / synfig-studio / trunk / src / gtkmm / layerparamtreestore.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file layerparamtreestore.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "layerparamtreestore.h"
33 #include "iconcontroller.h"
34 #include <gtkmm/button.h>
35 #include <synfig/paramdesc.h>
36 #include "layertree.h"
37 #include <synfigapp/action_system.h>
38 #include <synfigapp/instance.h>
39 #include "app.h"
40 #include <ETL/clock>
41
42 #include "general.h"
43
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 class Profiler : private etl::clock
56 {
57         const std::string name;
58 public:
59         Profiler(const std::string& name):name(name) { reset(); }
60         ~Profiler() { float time(operator()()); synfig::info("%s: took %f msec",name.c_str(),time*1000); }
61 };
62
63 /* === G L O B A L S ======================================================= */
64
65 /* === P R O C E D U R E S ================================================= */
66
67 /* === M E T H O D S ======================================================= */
68
69 static LayerParamTreeStore::Model& ModelHack()
70 {
71         static LayerParamTreeStore::Model* model(0);
72         if(!model)model=new LayerParamTreeStore::Model;
73         return *model;
74 }
75
76 LayerParamTreeStore::LayerParamTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_,LayerTree* layer_tree):
77         Gtk::TreeStore                  (ModelHack()),
78         CanvasTreeStore                 (canvas_interface_),
79         layer_tree                              (layer_tree)
80 {
81         queued=false;
82         // Connect all the signals
83         canvas_interface()->signal_value_node_changed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_changed));
84         canvas_interface()->signal_value_node_renamed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_renamed));
85         canvas_interface()->signal_value_node_added().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_added));
86         canvas_interface()->signal_value_node_deleted().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_deleted));
87         canvas_interface()->signal_value_node_replaced().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_replaced));
88         canvas_interface()->signal_layer_param_changed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_layer_param_changed));
89
90         canvas_interface()->signal_value_node_child_added().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_child_added));
91         canvas_interface()->signal_value_node_child_removed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_child_removed));
92
93
94         layer_tree->get_selection()->signal_changed().connect(sigc::mem_fun(*this,&LayerParamTreeStore::queue_rebuild));
95
96         signal_changed().connect(sigc::mem_fun(*this,&LayerParamTreeStore::queue_refresh));
97         rebuild();
98 }
99
100 LayerParamTreeStore::~LayerParamTreeStore()
101 {
102         while(!changed_connection_list.empty())
103         {
104                 changed_connection_list.back().disconnect();
105                 changed_connection_list.pop_back();
106         }
107         synfig::info("LayerParamTreeStore::~LayerParamTreeStore(): Deleted");
108 }
109
110 Glib::RefPtr<LayerParamTreeStore>
111 LayerParamTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_, LayerTree*layer_tree)
112 {
113         return Glib::RefPtr<LayerParamTreeStore>(new LayerParamTreeStore(canvas_interface_,layer_tree));
114 }
115
116
117
118 void
119 LayerParamTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& iter, int column, Glib::ValueBase& value)const
120 {
121         if(column<0)
122         {
123                 synfig::error("LayerParamTreeStore::get_value_vfunc(): Bad column!");
124                 return;
125         }
126
127 /*      if(column==model.label.index())
128         {
129                 synfig::Layer::Handle layer((*iter)[model.layer]);
130
131                 if(!layer)return;
132
133                 Glib::Value<Glib::ustring> x;
134                 g_value_init(x.gobj(),x.value_type());
135
136
137                 if(!layer->get_description().empty())
138                         x.set(layer->get_description());
139                 else
140                         x.set(layer->get_local_name());
141
142                 g_value_init(value.gobj(),x.value_type());
143                 g_value_copy(x.gobj(),value.gobj());
144         }
145         else
146 */
147         if(column==model.label.index())
148         {
149                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
150                 Glib::ustring label;
151
152                 if(!(*iter)[model.is_toplevel])
153                         return CanvasTreeStore::get_value_vfunc(iter,column,value);
154                 synfig::ParamDesc param_desc((*iter)[model.param_desc]);
155                 label=param_desc.get_local_name();
156
157                 if(!(*iter)[model.is_inconsistent])
158                 if(value_desc.is_value_node() && value_desc.get_value_node()->is_exported())
159                 {
160                         label+=strprintf(" (%s)",value_desc.get_value_node()->get_id().c_str());
161                 }
162
163                 Glib::Value<Glib::ustring> x;
164                 g_value_init(x.gobj(),x.value_type());
165
166                 x.set(label);
167
168                 g_value_init(value.gobj(),x.value_type());
169                 g_value_copy(x.gobj(),value.gobj());
170         }
171         else
172         if(column==model.is_toplevel.index())
173         {
174                 Glib::Value<bool> x;
175                 g_value_init(x.gobj(),x.value_type());
176
177                 TreeModel::Path path(get_path(iter));
178
179                 x.set(path.get_depth()<=1);
180
181                 g_value_init(value.gobj(),x.value_type());
182                 g_value_copy(x.gobj(),value.gobj());
183         }
184         else
185         if(column==model.is_inconsistent.index())
186         {
187                 if((*iter)[model.is_toplevel])
188                 {
189                         CanvasTreeStore::get_value_vfunc(iter,column,value);
190                         return;
191                 }
192
193                 Glib::Value<bool> x;
194                 g_value_init(x.gobj(),x.value_type());
195
196                 x.set(false);
197
198                 g_value_init(value.gobj(),x.value_type());
199                 g_value_copy(x.gobj(),value.gobj());
200         }
201         else
202         CanvasTreeStore::get_value_vfunc(iter,column,value);
203 }
204
205
206
207 void
208 LayerParamTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
209 {
210         //if(!iterator_sane(row))
211         //      return;
212
213         if(column>=get_n_columns_vfunc())
214         {
215                 g_warning("LayerTreeStore::set_value_impl: Bad column (%d)",column);
216                 return;
217         }
218
219         if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
220         {
221                 g_warning("LayerTreeStore::set_value_impl: Bad value type");
222                 return;
223         }
224
225         try
226         {
227                 if(column==model.value.index())
228                 {
229                         Glib::Value<synfig::ValueBase> x;
230                         g_value_init(x.gobj(),model.value.type());
231                         g_value_copy(value.gobj(),x.gobj());
232
233                         if((bool)(*iter)[model.is_toplevel])
234                         {
235                                 synfigapp::Action::PassiveGrouper group(canvas_interface()->get_instance().get(),_("Set Layer Params"));
236
237                                 synfig::ParamDesc param_desc((*iter)[model.param_desc]);
238
239                                 LayerList::iterator iter2(layer_list.begin());
240
241                                 for(;iter2!=layer_list.end();++iter2)
242                                 {
243                                         if(!canvas_interface()->change_value(synfigapp::ValueDesc(*iter2,param_desc.get_name()),x.get()))
244                                         {
245                                                 // ERROR!
246                                                 group.cancel();
247                                                 App::dialog_error_blocking(_("Error"),_("Unable to set all layer parameters."));
248
249                                                 return;
250                                         }
251                                 }
252                         }
253                         else
254                         {
255                                 canvas_interface()->change_value((*iter)[model.value_desc],x.get());
256                         }
257                         return;
258                 }
259                 else
260 /*
261                 if(column==model.active.index())
262                 {
263                         synfig::Layer::Handle layer((*iter)[model.layer]);
264
265                         if(!layer)return;
266
267                         Glib::Value<bool> x;
268                         g_value_init(x.gobj(),model.active.type());
269                         g_value_copy(value.gobj(),x.gobj());
270
271                         synfigapp::Action::Handle action(synfigapp::Action::create("layer_activate"));
272
273                         if(!action)
274                                 return;
275
276                         action->set_param("canvas",canvas_interface()->get_canvas());
277                         action->set_param("canvas_interface",canvas_interface());
278                         action->set_param("layer",layer);
279                         action->set_param("new_status",bool(x.get()));
280
281                         canvas_interface()->get_instance()->perform_action(action);
282                         return;
283                 }
284                 else
285 */
286                 CanvasTreeStore::set_value_impl(iter,column, value);
287         }
288         catch(std::exception x)
289         {
290                 g_warning(x.what());
291         }
292 }
293
294
295
296
297
298
299
300
301
302
303 void
304 LayerParamTreeStore::rebuild()
305 {
306         Profiler profiler("LayerParamTreeStore::rebuild()");
307         if(queued)queued=false;
308         clear();
309         layer_list=layer_tree->get_selected_layers();
310
311         if(layer_list.size()<=0)
312                 return;
313
314         // Get rid of all the connections,
315         // and clear the connection map.
316         //while(!connection_map.empty())connection_map.begin()->second.disconnect(),connection_map.erase(connection_map.begin());
317         while(!changed_connection_list.empty())
318         {
319                 changed_connection_list.back().disconnect();
320                 changed_connection_list.pop_back();
321         }
322
323         struct REBUILD_HELPER
324         {
325                 ParamVocab vocab;
326
327                 static ParamVocab::iterator find_param_desc(ParamVocab& vocab, const synfig::String& x)
328                 {
329                         ParamVocab::iterator iter;
330
331                         for(iter=vocab.begin();iter!=vocab.end();++iter)
332                                 if(iter->get_name()==x)
333                                         break;
334                         return iter;
335                 }
336
337                 void process_vocab(ParamVocab x)
338                 {
339                         ParamVocab::iterator iter;
340
341                         for(iter=vocab.begin();iter!=vocab.end();++iter)
342                         {
343                                 ParamVocab::iterator iter2(find_param_desc(x,iter->get_name()));
344                                 if(iter2==x.end())
345                                 {
346                                         // remove it and start over
347                                         vocab.erase(iter);
348                                         iter=vocab.begin();
349                                         iter--;
350                                         continue;
351                                 }
352                         }
353                 }
354
355         } rebuild_helper;
356
357
358         {
359                 LayerList::iterator iter(layer_list.begin());
360                 rebuild_helper.vocab=(*iter)->get_param_vocab();
361
362                 for(++iter;iter!=layer_list.end();++iter)
363                 {
364                         rebuild_helper.process_vocab((*iter)->get_param_vocab());
365                         changed_connection_list.push_back(
366                                 (*iter)->signal_changed().connect(
367                                         sigc::mem_fun(
368                                                 *this,
369                                                 &LayerParamTreeStore::changed
370                                         )
371                                 )
372                         );
373                 }
374         }
375
376         ParamVocab::iterator iter;
377         for(iter=rebuild_helper.vocab.begin();iter!=rebuild_helper.vocab.end();++iter)
378         {
379                 if(iter->get_hidden())
380                         continue;
381
382                 /*
383                 if(iter->get_animation_only())
384                 {
385                         int length(layer_list.front()->get_canvas()->rend_desc().get_frame_end()-layer_list.front()->get_canvas()->rend_desc().get_frame_start());
386                         if(!length)
387                                 continue;
388                 }
389                 */
390                 Gtk::TreeRow row(*(append()));
391                 synfigapp::ValueDesc value_desc(layer_list.front(),iter->get_name());
392                 CanvasTreeStore::set_row(row,value_desc);
393                 if(value_desc.is_value_node())
394                 {
395                         changed_connection_list.push_back(
396                                 value_desc.get_value_node()->signal_changed().connect(
397                                         sigc::mem_fun(
398                                                 this,
399                                                 &LayerParamTreeStore::changed
400                                         )
401                                 )
402                         );
403                 }
404                 if(value_desc.get_value_type()==ValueBase::TYPE_CANVAS)
405                 {
406                         Canvas::Handle canvas_handle = value_desc.get_value().get(Canvas::Handle());
407                         if(canvas_handle) changed_connection_list.push_back(
408                                 canvas_handle->signal_changed().connect(
409                                         sigc::mem_fun(
410                                                 this,
411                                                 &LayerParamTreeStore::changed
412                                         )
413                                 )
414                         );
415                 }
416                 //row[model.label] = iter->get_local_name();
417                 row[model.param_desc] = *iter;
418                 row[model.canvas] = layer_list.front()->get_canvas();
419                 row[model.is_inconsistent] = false;
420                 //row[model.is_toplevel] = true;
421
422
423                 LayerList::iterator iter2(layer_list.begin());
424                 ValueBase value((*iter2)->get_param(iter->get_name()));
425                 for(++iter2;iter2!=layer_list.end();++iter2)
426                 {
427                         if(value!=((*iter2)->get_param(iter->get_name())))
428                         {
429                                 row[model.is_inconsistent] = true;
430                                 while(!row.children().empty() && erase(row.children().begin()));
431                                 break;
432                         }
433                 }
434         }
435 }
436
437 void
438 LayerParamTreeStore::queue_refresh()
439 {
440         if(queued)
441                 return;
442         queued=1;
443         queue_connection.disconnect();
444         queue_connection=Glib::signal_timeout().connect(
445                 sigc::bind_return(
446                         sigc::mem_fun(*this,&LayerParamTreeStore::refresh),
447                         false
448                 )
449         ,150);
450
451 }
452
453 void
454 LayerParamTreeStore::queue_rebuild()
455 {
456         if(queued==2)
457                 return;
458         queued=2;
459         queue_connection.disconnect();
460         queue_connection=Glib::signal_timeout().connect(
461                 sigc::bind_return(
462                         sigc::mem_fun(*this,&LayerParamTreeStore::rebuild),
463                         false
464                 )
465         ,150);
466
467 }
468
469 void
470 LayerParamTreeStore::refresh()
471 {
472         if(queued)queued=false;
473
474         Gtk::TreeModel::Children children_(children());
475
476         Gtk::TreeModel::Children::iterator iter;
477
478         if(!children_.empty())
479                 for(iter = children_.begin(); iter && iter != children_.end(); ++iter)
480                 {
481                         Gtk::TreeRow row=*iter;
482                         refresh_row(row);
483                 }
484 }
485
486 void
487 LayerParamTreeStore::refresh_row(Gtk::TreeModel::Row &row)
488 {
489         if(row[model.is_toplevel])
490         {
491                 row[model.is_inconsistent] = false;
492                 ParamDesc param_desc(row[model.param_desc]);
493
494                 LayerList::iterator iter2(layer_list.begin());
495                 ValueBase value((*iter2)->get_param(param_desc.get_name()));
496                 for(++iter2;iter2!=layer_list.end();++iter2)
497                 {
498                         if(value!=((*iter2)->get_param(param_desc.get_name())))
499                         {
500                                 row[model.is_inconsistent] = true;
501                                 while(!row.children().empty() && erase(row.children().begin()));
502                                 return;
503                         }
504                 }
505         }
506
507         //handle<ValueNode> value_node=row[model.value_node];
508         //if(value_node)
509         {
510                 CanvasTreeStore::refresh_row(row);
511                 return;
512         }
513 }
514
515 void
516 LayerParamTreeStore::set_row(Gtk::TreeRow row,synfigapp::ValueDesc value_desc)
517 {
518         Gtk::TreeModel::Children children = row.children();
519         while(!children.empty() && erase(children.begin()));
520
521         CanvasTreeStore::set_row(row,value_desc);
522 }
523
524 void
525 LayerParamTreeStore::on_value_node_added(synfig::ValueNode::Handle /*value_node*/)
526 {
527 //      queue_refresh();
528 }
529
530 void
531 LayerParamTreeStore::on_value_node_deleted(synfig::ValueNode::Handle /*value_node*/)
532 {
533 //      queue_refresh();
534 }
535
536 void
537 LayerParamTreeStore::on_value_node_child_added(synfig::ValueNode::Handle /*value_node*/,synfig::ValueNode::Handle /*child*/)
538 {
539         queue_rebuild();
540 }
541
542 void
543 LayerParamTreeStore::on_value_node_child_removed(synfig::ValueNode::Handle /*value_node*/,synfig::ValueNode::Handle /*child*/)
544 {
545         rebuild();
546 }
547
548 void
549 LayerParamTreeStore::on_value_node_changed(synfig::ValueNode::Handle /*value_node*/)
550 {
551         queue_refresh();
552 }
553
554 void
555 LayerParamTreeStore::on_value_node_renamed(synfig::ValueNode::Handle /*value_node*/)
556 {
557         rebuild();
558 }
559
560 void
561 LayerParamTreeStore::on_value_node_replaced(synfig::ValueNode::Handle /*replaced_value_node*/,synfig::ValueNode::Handle /*new_value_node*/)
562 {
563         queue_rebuild();
564 }
565
566 void
567 LayerParamTreeStore::on_layer_param_changed(synfig::Layer::Handle /*handle*/,synfig::String /*param_name*/)
568 {
569         queue_refresh();
570 }