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