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