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 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2011 Carlos López
11 ** Copyright (c) 2012-2013 Konstantin Dmitriev
12 **
13 ** This package is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU General Public License as
15 ** published by the Free Software Foundation; either version 2 of
16 ** the License, or (at your option) any later version.
17 **
18 ** This package is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ** General Public License for more details.
22 ** \endlegal
23 */
24 /* ========================================================================= */
25
26 /* === H E A D E R S ======================================================= */
27
28 #ifdef USING_PCH
29 # include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <synfig/general.h>
36
37 #include <glibmm/main.h>
38
39 #include "layerparamtreestore.h"
40 #include "iconcontroller.h"
41 #include <gtkmm/button.h>
42 #include <synfig/paramdesc.h>
43 #include <synfig/valuenodes/valuenode_bone.h>
44 #include <synfig/valuenodes/valuenode_composite.h>
45
46 #include "layertree.h"
47 #include <synfigapp/action_system.h>
48 #include <synfigapp/instance.h>
49 #include "app.h"
50 #include <ETL/clock>
51
52 #include <gui/localization.h>
53
54 #endif
55
56 /* === U S I N G =========================================================== */
57
58 using namespace std;
59 using namespace etl;
60 using namespace synfig;
61 using namespace studio;
62
63 /* === M A C R O S ========================================================= */
64
65 class Profiler : private etl::clock
66 {
67 const std::string name;
68 public:
Profiler(const std::string & name)69 Profiler(const std::string& name):name(name) { reset(); }
~Profiler()70 ~Profiler() { float time(operator()()); synfig::info("%s: took %f msec",name.c_str(),time*1000); }
71 };
72
73 /* === G L O B A L S ======================================================= */
74
75 /* === P R O C E D U R E S ================================================= */
76
77 /* === M E T H O D S ======================================================= */
78
ModelHack()79 static LayerParamTreeStore::Model& ModelHack()
80 {
81 static LayerParamTreeStore::Model* model(0);
82 if(!model)model=new LayerParamTreeStore::Model;
83 return *model;
84 }
85
LayerParamTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_,LayerTree * layer_tree)86 LayerParamTreeStore::LayerParamTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_,LayerTree* layer_tree):
87 Gtk::TreeStore (ModelHack()),
88 CanvasTreeStore (canvas_interface_),
89 layer_tree (layer_tree)
90 {
91 queued=0;
92 // Connect all the signals
93 canvas_interface()->signal_value_node_changed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_changed));
94 canvas_interface()->signal_value_node_renamed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_renamed));
95 canvas_interface()->signal_value_node_added().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_added));
96 canvas_interface()->signal_value_node_deleted().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_deleted));
97 canvas_interface()->signal_value_node_replaced().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_replaced));
98 canvas_interface()->signal_layer_param_changed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_layer_param_changed));
99
100 canvas_interface()->signal_value_node_child_added().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_child_added));
101 canvas_interface()->signal_value_node_child_removed().connect(sigc::mem_fun(*this,&studio::LayerParamTreeStore::on_value_node_child_removed));
102
103 // This is for updating timetrack when empty/disabled keyframe is moved/deleted
104 // Looks a bit hackish, but I don't know the other way to do that. --KD
105 canvas_interface()->signal_keyframe_changed().connect(sigc::hide_return(sigc::hide(sigc::mem_fun(*this,&studio::LayerParamTreeStore::queue_refresh))));
106 canvas_interface()->signal_keyframe_removed().connect(sigc::hide_return(sigc::hide(sigc::mem_fun(*this,&studio::LayerParamTreeStore::queue_refresh))));
107
108
109 layer_tree->get_selection()->signal_changed().connect(sigc::mem_fun(*this,&LayerParamTreeStore::queue_rebuild));
110
111 signal_changed().connect(sigc::mem_fun(*this,&LayerParamTreeStore::queue_refresh));
112 rebuild();
113 }
114
~LayerParamTreeStore()115 LayerParamTreeStore::~LayerParamTreeStore()
116 {
117 while(!changed_connection_list.empty())
118 {
119 changed_connection_list.back().disconnect();
120 changed_connection_list.pop_back();
121 }
122
123 if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
124 synfig::info("LayerParamTreeStore::~LayerParamTreeStore(): Deleted");
125 }
126
127 Glib::RefPtr<LayerParamTreeStore>
create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_,LayerTree * layer_tree)128 LayerParamTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_, LayerTree*layer_tree)
129 {
130 return Glib::RefPtr<LayerParamTreeStore>(new LayerParamTreeStore(canvas_interface_,layer_tree));
131 }
132
133
134
135 void
get_value_vfunc(const Gtk::TreeModel::iterator & iter,int column,Glib::ValueBase & value) const136 LayerParamTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& iter, int column, Glib::ValueBase& value)const
137 {
138 if(column<0)
139 {
140 synfig::error("LayerParamTreeStore::get_value_vfunc(): Bad column!");
141 return;
142 }
143
144 /* if(column==model.label.index())
145 {
146 synfig::Layer::Handle layer((*iter)[model.layer]);
147
148 if(!layer)return;
149
150 Glib::Value<Glib::ustring> x;
151 g_value_init(x.gobj(),x.value_type());
152
153 x.set(layer->get_non_empty_description());
154
155 g_value_init(value.gobj(),x.value_type());
156 g_value_copy(x.gobj(),value.gobj());
157 }
158 else
159 */
160 if(column==model.label.index())
161 {
162 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
163 Glib::ustring label;
164
165 if(!(*iter)[model.is_toplevel])
166 return CanvasTreeStore::get_value_vfunc(iter,column,value);
167 synfig::ParamDesc param_desc((*iter)[model.param_desc]);
168 label=param_desc.get_local_name();
169
170 if(!(*iter)[model.is_inconsistent])
171 if(value_desc.is_value_node() && value_desc.get_value_node()->is_exported())
172 {
173 label+=strprintf(" (%s)",value_desc.get_value_node()->get_id().c_str());
174 }
175
176 Glib::Value<Glib::ustring> x;
177 g_value_init(x.gobj(),x.value_type());
178
179 x.set(label);
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_toplevel.index())
186 {
187 Glib::Value<bool> x;
188 g_value_init(x.gobj(),x.value_type());
189
190 TreeModel::Path path(get_path(iter));
191
192 x.set(path.size()<=1);
193
194 g_value_init(value.gobj(),x.value_type());
195 g_value_copy(x.gobj(),value.gobj());
196 }
197 else
198 if(column==model.is_inconsistent.index())
199 {
200 if((*iter)[model.is_toplevel])
201 {
202 CanvasTreeStore::get_value_vfunc(iter,column,value);
203 return;
204 }
205
206 Glib::Value<bool> x;
207 g_value_init(x.gobj(),x.value_type());
208
209 x.set(false);
210
211 g_value_init(value.gobj(),x.value_type());
212 g_value_copy(x.gobj(),value.gobj());
213 }
214 else
215 CanvasTreeStore::get_value_vfunc(iter,column,value);
216 }
217
218
219
220 void
set_value_impl(const Gtk::TreeModel::iterator & iter,int column,const Glib::ValueBase & value)221 LayerParamTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
222 {
223 //if(!iterator_sane(row))
224 // return;
225
226 if(column>=get_n_columns_vfunc())
227 {
228 g_warning("LayerTreeStore::set_value_impl: Bad column (%d)",column);
229 return;
230 }
231
232 if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
233 {
234 g_warning("LayerTreeStore::set_value_impl: Bad value type");
235 return;
236 }
237
238 try
239 {
240 if(column==model.value.index())
241 {
242 Glib::Value<synfig::ValueBase> x;
243 g_value_init(x.gobj(),model.value.type());
244 g_value_copy(value.gobj(),x.gobj());
245
246 if((bool)(*iter)[model.is_toplevel])
247 {
248 synfigapp::Action::PassiveGrouper group(canvas_interface()->get_instance().get(),_("Set Layer Parameters"));
249
250 synfig::ParamDesc param_desc((*iter)[model.param_desc]);
251
252 LayerList::iterator iter2(layer_list.begin());
253
254 for(;iter2!=layer_list.end();++iter2)
255 {
256 if(!canvas_interface()->change_value(synfigapp::ValueDesc(*iter2,param_desc.get_name()),x.get()))
257 {
258 // ERROR!
259 group.cancel();
260 App::dialog_message_1b(
261 "ERROR",
262 _("Unable to set all layer parameters."),
263 "details",
264 _("Close"));
265
266 return;
267 }
268 }
269 }
270 else
271 {
272 canvas_interface()->change_value((*iter)[model.value_desc],x.get());
273 }
274 return;
275 }
276 else
277 /*
278 if(column==model.active.index())
279 {
280 synfig::Layer::Handle layer((*iter)[model.layer]);
281
282 if(!layer)return;
283
284 Glib::Value<bool> x;
285 g_value_init(x.gobj(),model.active.type());
286 g_value_copy(value.gobj(),x.gobj());
287
288 synfigapp::Action::Handle action(synfigapp::Action::create("LayerActivate"));
289
290 if(!action)
291 return;
292
293 action->set_param("canvas",canvas_interface()->get_canvas());
294 action->set_param("canvas_interface",canvas_interface());
295 action->set_param("layer",layer);
296 action->set_param("new_status",bool(x.get()));
297
298 canvas_interface()->get_instance()->perform_action(action);
299 return;
300 }
301 else
302 */
303 CanvasTreeStore::set_value_impl(iter,column, value);
304 }
305 catch(std::exception& x)
306 {
307 g_warning("%s", x.what());
308 }
309 }
310
311
312
313
314
315
316
317
318
319
320 void
rebuild()321 LayerParamTreeStore::rebuild()
322 {
323 // Profiler profiler("LayerParamTreeStore::rebuild()");
324 if(queued)queued=0;
325 clear();
326 layer_list=layer_tree->get_selected_layers();
327
328 if(layer_list.size()<=0)
329 return;
330
331 // Get rid of all the connections,
332 // and clear the connection map.
333 //while(!connection_map.empty())connection_map.begin()->second.disconnect(),connection_map.erase(connection_map.begin());
334 while(!changed_connection_list.empty())
335 {
336 changed_connection_list.back().disconnect();
337 changed_connection_list.pop_back();
338 }
339
340 struct REBUILD_HELPER
341 {
342 ParamVocab vocab;
343 Layer::Handle layer_0;
344
345 static ParamVocab::iterator find_param_desc(ParamVocab& vocab, const synfig::String& x)
346 {
347 ParamVocab::iterator iter;
348
349 for(iter=vocab.begin();iter!=vocab.end();++iter)
350 if(iter->get_name()==x)
351 break;
352 return iter;
353 }
354
355 void process_vocab(synfig::Layer::Handle layer_n)
356 {
357 ParamVocab x = layer_n->get_param_vocab();
358 ParamVocab::iterator iter;
359
360 for(iter=vocab.begin();iter!=vocab.end();++iter)
361 {
362 String name(iter->get_name());
363 ParamVocab::iterator iter2(find_param_desc(x,name));
364 if(iter2==x.end() ||
365 layer_0->get_param(name).get_type() != layer_n->get_param(name).get_type())
366 {
367 // remove it and start over
368 vocab.erase(iter);
369 iter=vocab.begin();
370 iter--;
371 continue;
372 }
373 }
374 }
375
376 } rebuild_helper;
377
378
379 {
380 LayerList::iterator iter(layer_list.begin());
381 rebuild_helper.vocab=(*iter)->get_param_vocab();
382 rebuild_helper.layer_0=*iter;
383
384 for(++iter;iter!=layer_list.end();++iter)
385 {
386 rebuild_helper.process_vocab(*iter);
387 changed_connection_list.push_back(
388 (*iter)->signal_changed().connect(
389 sigc::mem_fun(
390 *this,
391 &LayerParamTreeStore::changed
392 )
393 )
394 );
395 }
396 }
397
398 ParamVocab::iterator iter;
399 for(iter=rebuild_helper.vocab.begin();iter!=rebuild_helper.vocab.end();++iter)
400 {
401 if(iter->get_hidden())
402 continue;
403
404 /*
405 if(iter->get_animation_only())
406 {
407 int length(layer_list.front()->get_canvas()->rend_desc().get_frame_end()-layer_list.front()->get_canvas()->rend_desc().get_frame_start());
408 if(!length)
409 continue;
410 }
411 */
412 Gtk::TreeRow row(*(append()));
413 synfigapp::ValueDesc value_desc(layer_list.front(),iter->get_name());
414 CanvasTreeStore::set_row(row,value_desc);
415 if(value_desc.is_value_node())
416 {
417 changed_connection_list.push_back(
418 value_desc.get_value_node()->signal_changed().connect(
419 sigc::mem_fun(
420 this,
421 &LayerParamTreeStore::changed
422 )
423 )
424 );
425 }
426 if(value_desc.get_value_type()==type_canvas)
427 {
428 Canvas::Handle canvas_handle = value_desc.get_value().get(Canvas::Handle());
429 if(canvas_handle) changed_connection_list.push_back(
430 canvas_handle->signal_changed().connect(
431 sigc::mem_fun(
432 this,
433 &LayerParamTreeStore::changed
434 )
435 )
436 );
437 }
438 //row[model.label] = iter->get_local_name();
439 row[model.tooltip] = iter->get_local_name()+": "+iter->get_description();
440 row[model.param_desc] = *iter;
441 row[model.canvas] = layer_list.front()->get_canvas();
442 row[model.is_inconsistent] = false;
443 //row[model.is_toplevel] = true;
444
445
446 LayerList::iterator iter2(layer_list.begin());
447 ValueBase value((*iter2)->get_param(iter->get_name()));
448 for(++iter2;iter2!=layer_list.end();++iter2)
449 {
450 if(value!=((*iter2)->get_param(iter->get_name())))
451 {
452 row[model.is_inconsistent] = true;
453 while(!row.children().empty() && erase(row.children().begin()))
454 ;
455 break;
456 }
457 }
458 }
459 }
460
461 void
queue_refresh()462 LayerParamTreeStore::queue_refresh()
463 {
464 if(queued)
465 return;
466 queued=1;
467 queue_connection.disconnect();
468 queue_connection=Glib::signal_timeout().connect(
469 sigc::bind_return(
470 sigc::mem_fun(*this,&LayerParamTreeStore::refresh),
471 false
472 )
473 ,150);
474
475 }
476
477 void
queue_rebuild()478 LayerParamTreeStore::queue_rebuild()
479 {
480 if(queued==2)
481 return;
482 queued=2;
483 queue_connection.disconnect();
484 queue_connection=Glib::signal_timeout().connect(
485 sigc::bind_return(
486 sigc::mem_fun(*this,&LayerParamTreeStore::rebuild),
487 false
488 )
489 ,150);
490
491 }
492
493 void
refresh()494 LayerParamTreeStore::refresh()
495 {
496 if(queued)queued=0;
497
498 Gtk::TreeModel::Children children_(children());
499
500 Gtk::TreeModel::Children::iterator iter;
501
502 if(!children_.empty())
503 for(iter = children_.begin(); iter && iter != children_.end(); ++iter)
504 {
505 Gtk::TreeRow row=*iter;
506 refresh_row(row);
507 }
508 }
509
510 void
refresh_row(Gtk::TreeModel::Row & row)511 LayerParamTreeStore::refresh_row(Gtk::TreeModel::Row &row)
512 {
513 if(row[model.is_toplevel])
514 {
515 row[model.is_inconsistent] = false;
516 ParamDesc param_desc(row[model.param_desc]);
517
518 LayerList::iterator iter2(layer_list.begin());
519 ValueBase value((*iter2)->get_param(param_desc.get_name()));
520 for(++iter2;iter2!=layer_list.end();++iter2)
521 {
522 if(value!=((*iter2)->get_param(param_desc.get_name())))
523 {
524 row[model.is_inconsistent] = true;
525 while(!row.children().empty() && erase(row.children().begin()))
526 ;
527 return;
528 }
529 }
530 }
531
532 //handle<ValueNode> value_node=row[model.value_node];
533 //if(value_node)
534 {
535 CanvasTreeStore::refresh_row(row);
536 return;
537 }
538 }
539
540 void
set_row(Gtk::TreeRow row,synfigapp::ValueDesc value_desc)541 LayerParamTreeStore::set_row(Gtk::TreeRow row,synfigapp::ValueDesc value_desc)
542 {
543 Gtk::TreeModel::Children children = row.children();
544 while(!children.empty() && erase(children.begin()))
545 ;
546
547 CanvasTreeStore::set_row(row,value_desc);
548 }
549
550 void
on_value_node_added(synfig::ValueNode::Handle)551 LayerParamTreeStore::on_value_node_added(synfig::ValueNode::Handle /*value_node*/)
552 {
553 // queue_refresh();
554 }
555
556 void
on_value_node_deleted(synfig::ValueNode::Handle)557 LayerParamTreeStore::on_value_node_deleted(synfig::ValueNode::Handle /*value_node*/)
558 {
559 // queue_refresh();
560 }
561
562 void
on_value_node_child_added(synfig::ValueNode::Handle,synfig::ValueNode::Handle)563 LayerParamTreeStore::on_value_node_child_added(synfig::ValueNode::Handle /*value_node*/,synfig::ValueNode::Handle /*child*/)
564 {
565 queue_rebuild();
566 }
567
568 void
on_value_node_child_removed(synfig::ValueNode::Handle,synfig::ValueNode::Handle)569 LayerParamTreeStore::on_value_node_child_removed(synfig::ValueNode::Handle /*value_node*/,synfig::ValueNode::Handle /*child*/)
570 {
571 rebuild();
572 }
573
574 void
on_value_node_changed(synfig::ValueNode::Handle)575 LayerParamTreeStore::on_value_node_changed(synfig::ValueNode::Handle /*value_node*/)
576 {
577 queue_refresh();
578 }
579
580 void
on_value_node_renamed(synfig::ValueNode::Handle)581 LayerParamTreeStore::on_value_node_renamed(synfig::ValueNode::Handle /*value_node*/)
582 {
583 rebuild();
584 }
585
586 void
on_value_node_replaced(synfig::ValueNode::Handle,synfig::ValueNode::Handle)587 LayerParamTreeStore::on_value_node_replaced(synfig::ValueNode::Handle /*replaced_value_node*/,synfig::ValueNode::Handle /*new_value_node*/)
588 {
589 // this used to be "queue_refresh();" but it was crashing when we
590 // first animated a bone's parent parameter (if the params panel
591 // was quite large). the replaced_value_node handle was out of
592 // scope by the time the tree was rebuilt, and the tree code was
593 // failing as a result. not sure how the tree code has a pointer
594 // rather than a handle - maybe it has a loosehandle, that would
595 // cause the problem I was seeing
596 rebuild();
597 }
598
599 void
on_layer_param_changed(synfig::Layer::Handle,synfig::String)600 LayerParamTreeStore::on_layer_param_changed(synfig::Layer::Handle /*handle*/,synfig::String /*param_name*/)
601 {
602 queue_refresh();
603 }
604
605 bool
find_value_desc(const synfigapp::ValueDesc & value_desc,Gtk::TreeIter & iter)606 LayerParamTreeStore::find_value_desc(const synfigapp::ValueDesc& value_desc, Gtk::TreeIter& iter)
607 {
608 //! check level0
609 for(iter = children().begin(); iter && iter != children().end(); ++iter)
610 {
611 if(value_desc.is_value_node())
612 {
613 //! transformation handle is at level 0, force to inspect deeper if case.
614 if( (value_desc.get_value_node()==((synfigapp::ValueDesc)(*iter)[model.value_desc]).get_value_node()) &&
615 (value_desc.get_value_type() == type_transformation)
616 )
617 {
618 Gtk::TreeIter iter2 = iter->children().begin();
619 for( ; iter2 && iter2 != iter->children().end(); ++iter2)
620 {
621 if ( ((synfigapp::ValueDesc)(*iter2)[model.value_desc]).get_name() ==
622 value_desc.get_sub_name() )
623 {
624 iter = iter2;
625 return true;
626 }
627 }
628 }
629 }
630 //! something found
631 if (value_desc==(*iter)[model.value_desc])
632 return true;
633 }
634
635 //! let's go for deepness
636 Gtk::TreeIter iter2;
637 for(iter2 = children().begin(); iter2 && iter2 != children().end(); ++iter2)
638 {
639 if((*iter2).children().empty())
640 continue;
641
642 if(find_value_desc(value_desc,iter,iter2->children()))
643 return true;
644 }
645 return false;
646 }
647
648 bool
find_value_desc(const synfigapp::ValueDesc & value_desc,Gtk::TreeIter & iter,const Gtk::TreeNodeChildren child_iter)649 LayerParamTreeStore::find_value_desc(const synfigapp::ValueDesc& value_desc, Gtk::TreeIter& iter, const Gtk::TreeNodeChildren child_iter)
650 {
651 // actual level from child_iter
652 for(iter = child_iter.begin(); iter && iter != child_iter.end(); ++iter)
653 {
654 if(value_desc.is_value_node())
655 {
656 // for vertex handle force to inspect deeper
657 if( value_desc.get_value_node()==((synfigapp::ValueDesc)(*iter)[model.value_desc]).get_value_node() &&
658 (value_desc.get_value_type() == type_bline_point)
659 )
660 // seems to be not necessary to check the ValueNode
661 // if((ValueNode_Composite::Handle::cast_dynamic(
662 // ((synfigapp::ValueDesc)(*iter)[model.value_desc]).get_value_node()))
663 // )
664 {
665 //check iteratively spline point (bline) children for same name.
666 Gtk::TreeIter iter2 = iter->children().begin();
667 for( ; iter2 && iter2 != iter->children().end(); ++iter2)
668 {
669 if ( ((synfigapp::ValueDesc)(*iter2)[model.value_desc]).get_name() ==
670 value_desc.get_sub_name() )
671 {
672 iter = iter2;
673 return true;
674 }
675 }
676 }
677 }
678 if (value_desc==(*iter)[model.value_desc])
679 return true;
680 }
681
682 Gtk::TreeIter iter2 = child_iter.begin();
683
684 //! for bones, do not inspect recursively to don't get trapped in bones hierarchy
685 if( ((synfigapp::ValueDesc)(*iter2)[model.value_desc]).parent_is_value_node() )
686 {
687 if(ValueNode_Bone::Handle::cast_dynamic(
688 ((synfigapp::ValueDesc)(*iter2)[model.value_desc]).get_parent_value_node()))
689 return false;
690 }
691
692 for( ; iter2 && iter2 != child_iter.end(); ++iter2)
693 {
694 if((*iter2).children().empty())
695 continue;
696
697 if(find_value_desc(value_desc,iter,iter2->children()))
698 return true;
699 }
700
701 return false;
702 }
703