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