Implements PXEGeek's http://wiki.synfig.com/Wish_list entry: "Optionally display...
[synfig.git] / synfig-studio / trunk / src / gtkmm / canvastreestore.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file canvastreestore.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 "canvastreestore.h"
33 #include <synfig/valuenode.h>
34 #include "iconcontroler.h"
35 #include <synfig/valuenode_timedswap.h>
36 #include <synfig/valuenode_animated.h>
37 #include <gtkmm/button.h>
38 #include <synfigapp/instance.h>
39 #include "cellrenderer_value.h"
40 #include "cellrenderer_timetrack.h"
41 #include <ETL/clock>
42
43 #endif
44
45 /* === U S I N G =========================================================== */
46
47 using namespace std;
48 using namespace etl;
49 using namespace synfig;
50 using namespace studio;
51
52 /* === M A C R O S ========================================================= */
53
54 /* === G L O B A L S ======================================================= */
55
56 /* === P R O C E D U R E S ================================================= */
57
58 /* === M E T H O D S ======================================================= */
59
60 static CanvasTreeStore::Model& ModelHack()
61 {
62         static CanvasTreeStore::Model* model(0);
63         if(!model)model=new CanvasTreeStore::Model;
64         return *model;
65 }
66
67 CanvasTreeStore::CanvasTreeStore(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface_):
68         Gtk::TreeStore(ModelHack()),
69         canvas_interface_               (canvas_interface_)
70 {
71 }
72
73 CanvasTreeStore::~CanvasTreeStore()
74 {
75 }
76
77 void
78 CanvasTreeStore::get_value_vfunc (const Gtk::TreeModel::iterator& iter, int column, Glib::ValueBase& value)const
79 {
80         if(column==model.value.index())
81         {
82                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
83
84                 Glib::Value<synfig::ValueBase> x;
85                 g_value_init(x.gobj(),x.value_type());
86
87                 if(!value_desc)
88                 {
89                         x.set(ValueBase());
90                 }
91                 else
92                 if(value_desc.is_const())
93                         x.set(value_desc.get_value());
94                 else
95                 if(value_desc.is_value_node())
96                         x.set((*value_desc.get_value_node())(canvas_interface()->get_time()));
97                 else
98                 {
99                         synfig::error(__FILE__":%d: Unable to figure out value",__LINE__);
100                         return;
101                 }
102
103                 g_value_init(value.gobj(),x.value_type());
104                 g_value_copy(x.gobj(),value.gobj());
105         }
106         else
107         if(column==model.is_value_node.index())
108         {
109                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
110
111                 Glib::Value<bool> x;
112                 g_value_init(x.gobj(),x.value_type());
113
114                 x.set(value_desc && value_desc.is_value_node());
115
116                 g_value_init(value.gobj(),x.value_type());
117                 g_value_copy(x.gobj(),value.gobj());
118         }
119         else
120         if(column==model.is_shared.index())
121         {
122                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
123
124                 Glib::Value<bool> x;
125                 g_value_init(x.gobj(),x.value_type());
126
127                 x.set(value_desc.is_value_node() && value_desc.get_value_node()->rcount()>1);
128
129                 g_value_init(value.gobj(),x.value_type());
130                 g_value_copy(x.gobj(),value.gobj());
131         }
132         else
133         if(column==model.is_exported.index())
134         {
135                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
136
137                 Glib::Value<bool> x;
138                 g_value_init(x.gobj(),x.value_type());
139
140                 x.set(value_desc.is_value_node() && value_desc.get_value_node()->is_exported());
141
142                 g_value_init(value.gobj(),x.value_type());
143                 g_value_copy(x.gobj(),value.gobj());
144         }
145         else
146         if(column==model.is_canvas.index())
147         {
148                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
149
150                 Glib::Value<bool> x;
151                 g_value_init(x.gobj(),x.value_type());
152
153                 x.set(!value_desc && (Canvas::Handle)(*iter)[model.canvas]);
154
155                 g_value_init(value.gobj(),x.value_type());
156                 g_value_copy(x.gobj(),value.gobj());
157         }
158         else
159         if(column==model.id.index())
160         {
161                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
162
163                 Glib::Value<Glib::ustring> x;
164                 g_value_init(x.gobj(),x.value_type());
165
166                 if(value_desc && value_desc.is_value_node())
167                         x.set(value_desc.get_value_node()->get_id());
168                 else if(!value_desc && Canvas::Handle((*iter)[model.canvas]))
169                         x.set(Canvas::Handle((*iter)[model.canvas])->get_id());
170                 else
171                         return Gtk::TreeStore::get_value_vfunc(iter,column,value);
172
173                 g_value_init(value.gobj(),x.value_type());
174                 g_value_copy(x.gobj(),value.gobj());
175         }
176         else
177         if(column==model.is_editable.index())
178         {
179                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
180
181                 Glib::Value<bool> x;
182                 g_value_init(x.gobj(),x.value_type());
183
184                 x.set(!value_desc.is_value_node() || synfigapp::is_editable(value_desc.get_value_node()));
185
186                 g_value_init(value.gobj(),x.value_type());
187                 g_value_copy(x.gobj(),value.gobj());
188         }
189         else
190         if(column==model.type.index())
191         {
192                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
193
194                 Glib::Value<Glib::ustring> x;
195                 g_value_init(x.gobj(),x.value_type());
196
197                 // Set the type
198                 if(!value_desc)
199                 {
200                         if((*iter)[model.is_canvas])
201                                 x.set(_("Canvas"));
202                 }
203                 else
204                 {
205                         if(!value_desc.is_value_node() || value_desc.get_value_node()->get_name()=="constant")
206                         {
207                                 x.set(ValueBase::type_name(value_desc.get_value_type()));
208                         }
209                         else
210                         {
211                                 x.set(value_desc.get_value_node()->get_local_name());
212                         }
213                 }
214
215                 g_value_init(value.gobj(),x.value_type());
216                 g_value_copy(x.gobj(),value.gobj());
217         }
218         else
219         if(column==model.label.index())
220         {
221                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
222
223                 Glib::Value<Glib::ustring> x;
224                 g_value_init(x.gobj(),x.value_type());
225
226                 // Set the type
227                 if(!value_desc)
228                 {
229                         Canvas::Handle canvas((*iter)[model.canvas]);
230                         if(canvas)
231                         {
232                                 if(!canvas->get_id().empty())
233                                         x.set(canvas->get_id());
234                                 else
235                                 if(!canvas->get_name().empty())
236                                         x.set(canvas->get_name());
237                                 else
238                                         x.set(_("[Unnamed]"));
239                                 x.set(_("Canvas"));
240                         }
241                         return Gtk::TreeStore::get_value_vfunc(iter,column,value);
242                 }
243                 else
244                 {
245                         ValueNode::Handle value_node=value_desc.get_value_node();
246
247                         // Setup the row's label
248                         if(value_node->get_id().empty())
249                                 x.set(Glib::ustring((*iter)[model.name]));
250                         else if(Glib::ustring((*iter)[model.name]).empty())
251                                 x.set(value_node->get_id());
252                         else
253                                 x.set(Glib::ustring((*iter)[model.name])+" ("+value_node->get_id()+')');
254                 }
255
256                 g_value_init(value.gobj(),x.value_type());
257                 g_value_copy(x.gobj(),value.gobj());
258         }
259         else
260         if(column==model.icon.index())
261         {
262                 synfigapp::ValueDesc value_desc((*iter)[model.value_desc]);
263                 if(!value_desc)
264                         return Gtk::TreeStore::get_value_vfunc(iter,column,value);
265
266                 Glib::Value<Glib::RefPtr<Gdk::Pixbuf> > x;
267                 g_value_init(x.gobj(),x.value_type());
268
269                 x.set(get_tree_pixbuf(value_desc.get_value_type()));
270
271                 g_value_init(value.gobj(),x.value_type());
272                 g_value_copy(x.gobj(),value.gobj());
273         }
274         else
275                 Gtk::TreeStore::get_value_vfunc(iter,column,value);
276 }
277
278 bool
279 CanvasTreeStore::find_first_value_desc(const synfigapp::ValueDesc& value_desc, Gtk::TreeIter& iter)
280 {
281         iter=children().begin();
282         while(iter && value_desc!=(*iter)[model.value_desc])
283         {
284                 if(!iter->children().empty())
285                 {
286                         Gtk::TreeIter iter2(iter->children().begin());
287                         if(iter2 && value_desc==(*iter2)[model.value_desc] || find_next_value_desc(value_desc, iter2))
288                         {
289                                 iter=iter2;
290                                 return true;
291                         }
292                 }
293                 Gtk::TreeIter iter2(++iter);
294                 if(!iter2)
295                         iter==iter->parent();
296                 else
297                         iter=iter2;
298         }
299         return (bool)iter && value_desc==(*iter)[model.value_desc];
300 }
301
302 bool
303 CanvasTreeStore::find_next_value_desc(const synfigapp::ValueDesc& value_desc, Gtk::TreeIter& iter)
304 {
305         if(!iter) return find_first_value_desc(value_desc,iter);
306
307         if(iter) do {
308                 if(!iter->children().empty())
309                 {
310                         Gtk::TreeIter iter2(iter->children().begin());
311                         if(iter2 && value_desc==(*iter2)[model.value_desc] || find_next_value_desc(value_desc, iter2))
312                         {
313                                 iter=iter2;
314                                 return true;
315                         }
316                 }
317                 Gtk::TreeIter iter2(++iter);
318                 if(!iter2)
319                 {
320                         iter==iter->parent();
321                         if(iter)++iter;
322                 }
323                 else
324                         iter=iter2;
325         } while(iter && value_desc!=(*iter)[model.value_desc]);
326         return (bool)iter && value_desc==(*iter)[model.value_desc];
327 }
328
329
330
331
332
333
334 bool
335 CanvasTreeStore::find_first_value_node(const ValueNode::Handle& value_node, Gtk::TreeIter& iter)
336 {
337         iter=children().begin();
338         while(iter && value_node!=(ValueNode::Handle)(*iter)[model.value_node])
339         {
340                 if(!iter->children().empty())
341                 {
342                         Gtk::TreeIter iter2(iter->children().begin());
343                         if(iter2 && value_node==(ValueNode::Handle)(*iter2)[model.value_node] || find_next_value_node(value_node, iter2))
344                         {
345                                 iter=iter2;
346                                 return true;
347                         }
348                 }
349                 Gtk::TreeIter iter2(++iter);
350                 if(!iter2)
351                         iter==iter->parent();
352                 else
353                         iter=iter2;
354         }
355         return (bool)iter && value_node==(ValueNode::Handle)(*iter)[model.value_node];
356 }
357
358 bool
359 CanvasTreeStore::find_next_value_node(const ValueNode::Handle& value_node, Gtk::TreeIter& iter)
360 {
361         if(!iter) return find_first_value_node(value_node,iter);
362
363         if(iter) do {
364                 if(!iter->children().empty())
365                 {
366                         Gtk::TreeIter iter2(iter->children().begin());
367                         if(iter2 && value_node==(ValueNode::Handle)(*iter2)[model.value_node] || find_next_value_node(value_node, iter2))
368                         {
369                                 iter=iter2;
370                                 return true;
371                         }
372                 }
373                 Gtk::TreeIter iter2(++iter);
374                 if(!iter2)
375                 {
376                         iter==iter->parent();
377                         if(iter)++iter;
378                 }
379                 else
380                         iter=iter2;
381         } while(iter && value_node!=(ValueNode::Handle)(*iter)[model.value_node]);
382         return (bool)iter && value_node==(ValueNode::Handle)(*iter)[model.value_node];
383 }
384
385 void
386 CanvasTreeStore::set_row(Gtk::TreeRow row,synfigapp::ValueDesc value_desc, bool do_children)
387 {
388         Gtk::TreeModel::Children children = row.children();
389         while(!children.empty() && erase(children.begin()));
390
391         row[model.value_desc]=value_desc;
392         try
393         {
394                 //row[model.icon] = get_tree_pixbuf(value_desc.get_value_type());
395
396                 if(value_desc.is_value_node())
397                 {
398                         ValueNode::Handle value_node=value_desc.get_value_node();
399
400                         assert(value_node);
401
402                         row[model.value_node] = value_node;
403                         //row[model.is_canvas] = false;
404                         //row[model.is_value_node] = true;
405                         //row[model.is_editable] = synfigapp::is_editable(value_node);
406                         //row[model.id]=value_node->get_id();
407
408                         // Set the canvas
409                         if(value_desc.parent_is_canvas())
410                                 row[model.canvas]=value_desc.get_canvas();
411                         else
412                                 row[model.canvas]=canvas_interface()->get_canvas();
413
414                         LinkableValueNode::Handle linkable;
415                         linkable=LinkableValueNode::Handle::cast_dynamic(value_node);
416
417                         if(linkable && do_children)
418                         {
419                                 row[model.link_count] = linkable->link_count();
420                                 for(int i=0;i<linkable->link_count();i++)
421                                 {
422                                         Gtk::TreeRow child_row=*(append(row.children()));
423                                         child_row[model.link_id] = i;
424                                         child_row[model.canvas] = static_cast<Canvas::Handle>(row[model.canvas]);
425                                         child_row[model.name] = linkable->link_local_name(i);
426                                         set_row(child_row,synfigapp::ValueDesc(linkable,i));
427                                 }
428                         }
429                         return;
430                 }
431                 else
432                 {
433                         //row[model.is_value_node] = false;
434                         //row[model.is_editable] = true;
435                         //row[model.label] = Glib::ustring(row[model.name]);
436                         return;
437                 }
438         }
439         catch(synfig::Exception::IDNotFound x)
440         {
441                 synfig::error(__FILE__":%d: IDNotFound thrown",__LINE__);
442                 erase(row);
443                 return;
444         }
445
446         // We should never get to this point
447         assert(0);
448 }
449
450 void
451 CanvasTreeStore::refresh_row(Gtk::TreeModel::Row &row, bool do_children)
452 {
453         synfigapp::ValueDesc value_desc=row[model.value_desc];
454
455         if(value_desc)
456         {
457                 if((bool)row[model.is_value_node] != value_desc.is_value_node() ||
458                         (!bool(row[model.is_value_node]) && row[model.link_count]!=0))
459                 {
460                         set_row(row,value_desc,do_children);
461                         return;
462                 }
463
464                 if(row[model.is_value_node])
465                 {
466                         ValueNode::Handle value_node(value_desc.get_value_node());
467
468                         if(ValueNode::Handle(row[model.value_node])!=value_node)
469                         {
470                                 rebuild_row(row,do_children);
471                                 return;
472                         }
473
474                         //row[model.id]=value_node->get_id();
475
476                         // Setup the row's label
477                         /*
478                         if(value_node->get_id().empty())
479                                 row[model.label] = Glib::ustring(row[model.name]);
480                         else if(Glib::ustring(row[model.name]).empty())
481                                 row[model.label] = value_node->get_id();
482                         else
483                                 row[model.label] = Glib::ustring(row[model.name])+" ("+value_node->get_id()+')';
484                         */
485
486                         LinkableValueNode::Handle linkable;
487                         linkable=LinkableValueNode::Handle::cast_dynamic(value_node);
488                         if(do_children && linkable && ((int)row[model.link_count] != linkable->link_count()))
489                         {
490         //                      Gtk::TreeModel::Children children = row.children();
491         //                      while(!children.empty() && erase(children.begin()));
492
493                                 set_row(row,value_desc);
494                                 return;
495                         }
496                 }
497                 else
498                 {
499                         //row[model.label] = Glib::ustring(row[model.name]);
500                         //row[model.is_value_node] = false;
501                         //row[model.is_editable] = true;
502                 }
503         }
504         if(!do_children)
505                 return;
506
507         Gtk::TreeModel::Children children = row.children();
508         Gtk::TreeModel::Children::iterator iter;
509
510         if(!children.empty())
511         for(iter = children.begin(); iter != children.end(); ++iter)
512         {
513                 Gtk::TreeRow row=*iter;
514                 refresh_row(row);
515         }
516 }
517
518 void
519 CanvasTreeStore::rebuild_row(Gtk::TreeModel::Row &row, bool do_children)
520 {
521         synfigapp::ValueDesc value_desc=(synfigapp::ValueDesc)row[model.value_desc];
522
523         if(value_desc && value_desc.get_value_node())
524         {
525                 ValueNode::Handle value_node;
526                 value_node=value_desc.get_value_node();
527
528                 assert(value_node);if(!value_node)return;
529
530                 if(value_node && value_node!=(ValueNode::Handle)row[model.value_node])
531                 {
532 //                      Gtk::TreeModel::Children children = row.children();
533 //                      while(!children.empty() && erase(children.begin()));
534
535                         set_row(row,value_desc,do_children);
536                         return;
537                 }
538
539                 LinkableValueNode::Handle linkable;
540                 linkable=LinkableValueNode::Handle::cast_dynamic(value_node);
541
542                 if( do_children && linkable && (int)row[model.link_count] != linkable->link_count())
543                 {
544 //                      Gtk::TreeModel::Children children = row.children();
545 //                      while(!children.empty() && erase(children.begin()));
546
547                         set_row(row,value_desc);
548                         return;
549                 }
550
551                 //if(!value_node)
552                 //      value_node=row[model.value_node];
553
554                 row[model.id]=value_node->get_id();
555
556                 // Setup the row's label
557                 if(value_node->get_id().empty())
558                         row[model.label] = Glib::ustring(row[model.name]);
559                 else if(Glib::ustring(row[model.name]).empty())
560                         row[model.label] = value_node->get_id();
561                 else
562                         row[model.label] = Glib::ustring(row[model.name])+" ("+value_node->get_id()+')';
563         }
564         else
565         {
566                 row[model.label] = Glib::ustring(row[model.name]);
567                 row[model.is_value_node] = false;
568                 row[model.is_editable] = true;
569                 Gtk::TreeModel::Children children = row.children();
570                 while(!children.empty() && erase(children.begin()));
571         }
572         if(!do_children)
573                 return;
574
575         Gtk::TreeModel::Children children = row.children();
576         Gtk::TreeModel::Children::iterator iter;
577         if(!children.empty())
578         for(iter = children.begin(); iter != children.end(); ++iter)
579         {
580                 Gtk::TreeRow row=*iter;
581                 rebuild_row(row);
582         }
583 }
584
585 CellRenderer_ValueBase*
586 CanvasTreeStore::add_cell_renderer_value(Gtk::TreeView::Column* column)
587 {
588         const CanvasTreeStore::Model model;
589
590         CellRenderer_ValueBase* ret;
591
592         ret=Gtk::manage( new CellRenderer_ValueBase() );
593
594         column->pack_start(*ret,true);
595         column->add_attribute(ret->property_value(), model.value);
596         column->add_attribute(ret->property_editable(), model.is_editable);
597         column->add_attribute(ret->property_canvas(), model.canvas);
598
599         return ret;
600 }
601
602 CellRenderer_TimeTrack*
603 CanvasTreeStore::add_cell_renderer_value_node(Gtk::TreeView::Column* column)
604 {
605         const CanvasTreeStore::Model model;
606
607         CellRenderer_TimeTrack* ret;
608
609         ret = Gtk::manage( new CellRenderer_TimeTrack() );
610
611         column->pack_start(*ret,true);
612         //column->add_attribute(ret->property_visible(), model.is_value_node);
613         column->add_attribute(ret->property_value_desc(), model.value_desc);
614         column->add_attribute(ret->property_canvas(), model.canvas);
615
616
617         return ret;
618 }