Implements PXEGeek's http://wiki.synfig.com/Wish_list entry: "Optionally display...
[synfig.git] / synfig-studio / trunk / src / gtkmm / childrentreestore.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file childrentreestore.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 "childrentreestore.h"
33 #include "iconcontroler.h"
34 #include <gtkmm/button.h>
35 #include <synfig/paramdesc.h>
36 #include <ETL/clock>
37
38 class Profiler : private etl::clock
39 {
40         const std::string name;
41 public:
42         Profiler(const std::string& name):name(name) { reset(); }
43         ~Profiler() { float time(operator()()); synfig::info("%s: took %f msec",name.c_str(),time*1000); }
44 };
45
46 #endif
47
48 /* === U S I N G =========================================================== */
49
50 using namespace std;
51 using namespace etl;
52 using namespace synfig;
53 using namespace studio;
54
55 /* === M A C R O S ========================================================= */
56
57 /* === G L O B A L S ======================================================= */
58
59 /* === P R O C E D U R E S ================================================= */
60
61 /* === M E T H O D S ======================================================= */
62
63 static ChildrenTreeStore::Model& ModelHack()
64 {
65         static ChildrenTreeStore::Model* model(0);
66         if(!model)model=new ChildrenTreeStore::Model;
67         return *model;
68 }
69
70 ChildrenTreeStore::ChildrenTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
71         Gtk::TreeStore                  (ModelHack()),
72         CanvasTreeStore                 (canvas_interface_)
73 {
74         canvas_row=*append();
75         canvas_row[model.label]=_("Canvases");
76         canvas_row[model.is_canvas] = false;
77         canvas_row[model.is_value_node] = false;
78
79         value_node_row=*append();
80         value_node_row[model.label]=_("ValueBase Nodes");
81         value_node_row[model.is_canvas] = false;
82         value_node_row[model.is_value_node] = false;
83
84         // Connect all the signals
85         canvas_interface()->signal_value_node_changed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_changed));
86         canvas_interface()->signal_value_node_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_added));
87         canvas_interface()->signal_value_node_deleted().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_deleted));
88         canvas_interface()->signal_value_node_replaced().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_value_node_replaced));
89         canvas_interface()->signal_canvas_added().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_added));
90         canvas_interface()->signal_canvas_removed().connect(sigc::mem_fun(*this,&studio::ChildrenTreeStore::on_canvas_removed));
91
92         rebuild();
93 }
94
95 ChildrenTreeStore::~ChildrenTreeStore()
96 {
97 }
98
99 Glib::RefPtr<ChildrenTreeStore>
100 ChildrenTreeStore::create(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_)
101 {
102         return Glib::RefPtr<ChildrenTreeStore>(new ChildrenTreeStore(canvas_interface_));
103 }
104
105 void
106 ChildrenTreeStore::rebuild()
107 {
108         Profiler profiler("ChildrenTreeStore::rebuild()");
109         rebuild_value_nodes();
110         rebuild_canvases();
111 }
112
113 void
114 ChildrenTreeStore::refresh()
115 {
116         Profiler profiler("ChildrenTreeStore::refresh()");
117         refresh_value_nodes();
118         refresh_canvases();
119 }
120
121 void
122 ChildrenTreeStore::rebuild_value_nodes()
123 {
124         Gtk::TreeModel::Children children(value_node_row.children());
125
126         while(!children.empty())erase(children.begin());
127
128         clear_changed_queue();
129
130         std::for_each(
131                 canvas_interface()->get_canvas()->value_node_list().rbegin(), canvas_interface()->get_canvas()->value_node_list().rend(),
132                 sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_value_node_added)
133         );
134 }
135
136 void
137 ChildrenTreeStore::refresh_value_nodes()
138 {
139         Gtk::TreeModel::Children children(value_node_row.children());
140
141         Gtk::TreeModel::Children::iterator iter;
142
143         if(!children.empty())
144                 for(iter = children.begin(); iter != children.end(); ++iter)
145                 {
146                         Gtk::TreeRow row=*iter;
147                         //DEBUGPOINT();
148                         refresh_row(row);
149                 }
150 }
151
152 void
153 ChildrenTreeStore::rebuild_canvases()
154 {
155         Gtk::TreeModel::Children children(canvas_row.children());
156
157         while(!children.empty())erase(children.begin());
158
159         std::for_each(
160                 canvas_interface()->get_canvas()->children().rbegin(), canvas_interface()->get_canvas()->children().rend(),
161                 sigc::mem_fun(*this, &studio::ChildrenTreeStore::on_canvas_added)
162         );
163 }
164
165 void
166 ChildrenTreeStore::refresh_canvases()
167 {
168         rebuild_canvases();
169 }
170
171 void
172 ChildrenTreeStore::refresh_row(Gtk::TreeModel::Row &row, bool do_children)
173 {
174         CanvasTreeStore::refresh_row(row,false);
175
176         if((bool)row[model.is_value_node])
177         {
178                 changed_set_.erase(row[model.value_node]);
179         }
180
181 }
182
183 void
184 ChildrenTreeStore::on_canvas_added(Canvas::Handle canvas)
185 {
186         Gtk::TreeRow row = *(prepend(canvas_row.children()));
187
188         row[model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
189         row[model.id] = canvas->get_id();
190         row[model.name] = canvas->get_name();
191
192         if(!canvas->get_id().empty())
193                 row[model.label] = canvas->get_id();
194         else
195         if(!canvas->get_name().empty())
196                 row[model.label] = canvas->get_name();
197         else
198                 row[model.label] = _("[Unnamed]");
199
200         row[model.canvas] = canvas;
201         row[model.type] = _("Canvas");
202         //row[model.is_canvas] = true;
203         //row[model.is_value_node] = false;
204 }
205
206 void
207 ChildrenTreeStore::on_canvas_removed(Canvas::Handle canvas)
208 {
209         rebuild_canvases();
210 }
211
212 void
213 ChildrenTreeStore::on_value_node_added(ValueNode::Handle value_node)
214 {
215 //      if(value_node->get_id().find("Unnamed")!=String::npos)
216 //              return;
217
218         Gtk::TreeRow row = *prepend(value_node_row.children());
219
220         set_row(row,synfigapp::ValueDesc(canvas_interface()->get_canvas(),value_node->get_id()),false);
221 }
222
223 void
224 ChildrenTreeStore::on_value_node_deleted(etl::handle<ValueNode> value_node)
225 {
226         Gtk::TreeIter iter;
227         //int i(0);
228
229         if(find_first_value_node(value_node,iter))
230         {
231                 erase(iter);
232         }
233         //rebuild_value_nodes();
234 }
235
236 bool
237 ChildrenTreeStore::execute_changed_value_nodes()
238 {
239         Profiler profiler("ChildrenTreeStore::execute_changed_value_nodes()");
240         DEBUGPOINT();
241         if(!replaced_set_.empty())
242                 rebuild_value_nodes();
243
244         etl::clock timer;
245         timer.reset();
246
247         while(!changed_set_.empty())
248         {
249                 ValueNode::Handle value_node(*changed_set_.begin());
250                 changed_set_.erase(value_node);
251
252                 Gtk::TreeIter iter;
253
254                 try
255                 {
256                         Gtk::TreeIter iter;
257                         int i(0);
258
259                         if(!value_node->is_exported() && find_first_value_node(value_node,iter))
260                         {
261                                 rebuild_value_nodes();
262                                 continue;
263                         }
264
265                         if(value_node->is_exported() && find_first_value_node(value_node,iter)) do
266                         {
267                                 Gtk::TreeRow row(*iter);
268                                 i++;
269                                 refresh_row(row);
270                         }while(find_next_value_node(value_node,iter));
271
272                         if(!i)
273                         {
274                                 refresh_value_nodes();
275                                 return false;
276                         }
277
278                 }
279                 catch(...)
280                 {
281                         rebuild_value_nodes();
282                         return false;
283                 }
284
285                 // If we are taking too long...
286                 if(timer()>4)
287                 {
288                         refresh_value_nodes();
289                         return false;
290                 }
291         }
292
293         return false;
294 }
295
296 void
297 ChildrenTreeStore::on_value_node_changed(etl::handle<ValueNode> value_node)
298 {
299
300         if(value_node->get_name()=="constant" || !value_node->is_exported())
301                 return;
302         changed_connection.disconnect();
303 //      if(!execute_changed_queued())
304 //              changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
305         changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
306
307         changed_set_.insert(value_node);
308         /*
309         try
310         {
311                 Gtk::TreeIter iter;
312                 int i(0);
313                 while(find_next_value_node(value_node,iter))
314                 {
315                         Gtk::TreeRow row(*iter);
316                         i++;
317                         refresh_row(row);
318                 }
319                 if(!i)
320                 {
321                         refresh_value_nodes();
322                 }
323         }
324         catch(...)
325         {
326                 rebuild_value_nodes();
327         }
328         */
329 }
330
331 void
332 ChildrenTreeStore::on_value_node_replaced(synfig::ValueNode::Handle replaced_value_node,synfig::ValueNode::Handle new_value_node)
333 {
334         changed_connection.disconnect();
335         //if(!execute_changed_queued())
336 //              changed_connection=Glib::signal_idle().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes));
337                 changed_connection=Glib::signal_timeout().connect(sigc::mem_fun(*this,&ChildrenTreeStore::execute_changed_value_nodes),150);
338
339         replaced_set_.insert(replaced_value_node);
340 }
341
342 void
343 ChildrenTreeStore::set_value_impl(const Gtk::TreeModel::iterator& iter, int column, const Glib::ValueBase& value)
344 {
345         if(column>=get_n_columns_vfunc())
346         {
347                 g_warning("LayerTreeStore::set_value_impl: Bad column (%d)",column);
348                 return;
349         }
350
351         if(!g_value_type_compatible(G_VALUE_TYPE(value.gobj()),get_column_type_vfunc(column)))
352         {
353                 g_warning("LayerTreeStore::set_value_impl: Bad value type");
354                 return;
355         }
356
357         try
358         {
359                 if(column==model.value.index())
360                 {
361                         Glib::Value<synfig::ValueBase> x;
362                         g_value_init(x.gobj(),model.value.type());
363                         g_value_copy(value.gobj(),x.gobj());
364
365                         synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
366                         if(value_desc)
367                         {
368                                 canvas_interface()->change_value(value_desc,x.get());
369                                 row_changed(get_path(*iter),*iter);
370                         }
371
372                         return;
373                 }
374                 else
375                         CanvasTreeStore::set_value_impl(iter,column, value);
376         }
377         catch(std::exception x)
378         {
379                 g_warning(x.what());
380         }
381 }