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