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