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