adb8998da6f6d962a9af7f80267bb6d7a2e617a9
[synfig.git] / synfig-studio / src / gui / docks / dock_timetrack.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file dock_timetrack.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 "docks/dock_timetrack.h"
34 #include "app.h"
35
36 #include <gtkmm/scrolledwindow.h>
37 #include <cassert>
38 #include "instance.h"
39 #include <sigc++/signal.h>
40 #include <sigc++/hide.h>
41 #include <sigc++/slot.h>
42 #include "canvasview.h"
43 #include "trees/layerparamtreestore.h"
44 #include "workarea.h"
45 #include "widgets/widget_timeslider.h"
46 #include "widgets/widget_keyframe_list.h"
47 #include "general.h"
48 #include <synfig/timepointcollect.h>
49
50 #endif
51
52 /* === U S I N G =========================================================== */
53
54 using namespace std;
55 using namespace etl;
56 using namespace synfig;
57 using namespace studio;
58
59 /* === M A C R O S ========================================================= */
60
61 /* === C L A S S E S ======================================================= */
62
63 class TimeTrackView : public Gtk::TreeView
64 {
65         CellRenderer_TimeTrack *cellrenderer_time_track;
66
67         Glib::RefPtr<LayerParamTreeStore> param_tree_store_;
68
69         Gtk::TreeView *mimic_tree_view;
70 public:
71
72         sigc::signal<void,synfigapp::ValueDesc,std::set<synfig::Waypoint, std::less<UniqueID> >,int> signal_waypoint_clicked_timetrackview;
73
74         LayerParamTreeStore::Model model;
75
76         void set_canvas_view(handle<CanvasView> canvas_view)
77         {
78                 cellrenderer_time_track->set_adjustment(canvas_view->time_adjustment());
79         }
80
81         TimeTrackView()
82         {
83                 int label_index(append_column_editable(_("Name"),model.label));
84                 Gtk::TreeView::Column* label_column = get_column(label_index-1);
85
86                 {       // --- T I M E   T R A C K --------------------------------------------
87                         Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_("Time Track")) );
88
89                         // Set up the value-node cell-renderer
90                         cellrenderer_time_track=LayerParamTreeStore::add_cell_renderer_value_node(column);
91                         cellrenderer_time_track->property_mode()=Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
92                         cellrenderer_time_track->signal_waypoint_clicked_cellrenderer().connect(sigc::mem_fun(*this, &TimeTrackView::on_waypoint_clicked_timetrackview));
93                         cellrenderer_time_track->signal_waypoint_changed().connect(sigc::mem_fun(*this, &TimeTrackView::on_waypoint_changed) );
94                         column->add_attribute(cellrenderer_time_track->property_value_desc(), model.value_desc);
95                         column->add_attribute(cellrenderer_time_track->property_canvas(), model.canvas);
96                         //column->add_attribute(cellrenderer_time_track->property_visible(), model.is_value_node);
97
98                         //column->pack_start(*cellrenderer_time_track);
99
100                         // Finish setting up the column
101                         column->set_reorderable();
102                         column->set_resizable();
103                         column->set_min_width(200);
104
105                         append_column(*column);
106                 }
107                 set_rules_hint();
108
109                 set_expander_column(*label_column);
110                 label_column->set_visible(false);
111                 set_headers_visible(false);
112                 set_size_request(-1,64);
113         }
114
115         bool
116         on_event(GdkEvent *event)
117         {
118                 switch(event->type)
119                 {
120                 case GDK_SCROLL:
121                         if(mimic_tree_view)
122                         {
123                                 if(event->scroll.direction==GDK_SCROLL_DOWN)
124                                 {
125                                         mimic_tree_view->get_vadjustment()->set_value(
126                                                 std::min(
127                                                         mimic_tree_view->get_vadjustment()->get_value()+
128                                                         mimic_tree_view->get_vadjustment()->get_step_increment(),
129                                                         mimic_tree_view->get_vadjustment()->get_upper()-
130                                                         mimic_tree_view->get_vadjustment()->get_page_size()
131                                                 )
132                                         );
133                                         mimic_tree_view->get_vadjustment()->value_changed();
134                                 }
135                                 else if(event->scroll.direction==GDK_SCROLL_UP)
136                                 {
137                                         mimic_tree_view->get_vadjustment()->set_value(
138                                                 std::max(
139                                                         mimic_tree_view->get_vadjustment()->get_value()-
140                                                         mimic_tree_view->get_vadjustment()->get_step_increment(),
141                                                         mimic_tree_view->get_vadjustment()->get_lower()
142                                                 )
143                                         );
144                                         mimic_tree_view->get_vadjustment()->value_changed();
145                                 }
146                         }
147                         break;
148                 case GDK_BUTTON_PRESS:
149                         {
150                                 Gtk::TreeModel::Path path;
151                                 Gtk::TreeViewColumn *column;
152                                 int cell_x, cell_y;
153                                 if(!get_path_at_pos(
154                                         int(event->button.x),int(event->button.y),      // x, y
155                                         path, // TreeModel::Path&
156                                         column, //TreeViewColumn*&
157                                         cell_x,cell_y //int&cell_x,int&cell_y
158                                         )
159                                 ) break;
160                                 const Gtk::TreeRow row = *(get_model()->get_iter(path));
161
162                                 if(column && column->get_first_cell_renderer()==cellrenderer_time_track)
163                                 {
164                                         Gdk::Rectangle rect;
165                                         get_cell_area(path,*column,rect);
166                                         cellrenderer_time_track->property_value_desc()=row[model.value_desc];
167                                         cellrenderer_time_track->property_canvas()=row[model.canvas];
168                                         cellrenderer_time_track->activate(event,*this,path.to_string(),rect,rect,Gtk::CellRendererState());
169                                         queue_draw_area(rect.get_x(),rect.get_y(),rect.get_width(),rect.get_height());
170                                         return true;
171                                         //return signal_param_user_click()(event->button.button,row,COLUMNID_TIME_TRACK);
172                                 }
173                         }
174                         break;
175
176                 case GDK_MOTION_NOTIFY:
177                         {
178                                 Gtk::TreeModel::Path path;
179                                 Gtk::TreeViewColumn *column;
180                                 int cell_x, cell_y;
181                                 if(!get_path_at_pos(
182                                         (int)event->motion.x,(int)event->motion.y,      // x, y
183                                         path, // TreeModel::Path&
184                                         column, //TreeViewColumn*&
185                                         cell_x,cell_y //int&cell_x,int&cell_y
186                                         )
187                                 ) break;
188
189                                 if(!get_model()->get_iter(path))
190                                         break;
191
192                                 Gtk::TreeRow row = *(get_model()->get_iter(path));
193
194                                 if ((event->motion.state&GDK_BUTTON1_MASK || event->motion.state&GDK_BUTTON3_MASK) &&
195                                         column &&
196                                         cellrenderer_time_track == column->get_first_cell_renderer())
197                                 {
198                                         Gdk::Rectangle rect;
199                                         get_cell_area(path,*column,rect);
200                                         cellrenderer_time_track->property_value_desc()=row[model.value_desc];
201                                         cellrenderer_time_track->property_canvas()=row[model.canvas];
202                                         cellrenderer_time_track->activate(event,*this,path.to_string(),rect,rect,Gtk::CellRendererState());
203                                         queue_draw();
204                                         //queue_draw_area(rect.get_x(),rect.get_y(),rect.get_width(),rect.get_height());
205                                         return true;
206                                 }
207 /*                              else
208                                 if(last_tooltip_path.get_depth()<=0 || path!=last_tooltip_path)
209                                 {
210                                         tooltips_.unset_tip(*this);
211                                         Glib::ustring tooltips_string(row[layer_model.tooltip]);
212                                         last_tooltip_path=path;
213                                         if(!tooltips_string.empty())
214                                         {
215                                                 tooltips_.set_tip(*this,tooltips_string);
216                                                 tooltips_.force_window();
217                                         }
218                                 }
219 */
220                                 return true;
221                         }
222                         break;
223                 case GDK_BUTTON_RELEASE:
224                         {
225                                 Gtk::TreeModel::Path path;
226                                 Gtk::TreeViewColumn *column;
227                                 int cell_x, cell_y;
228                                 if(!get_path_at_pos(
229                                         (int)event->button.x,(int)event->button.y,      // x, y
230                                         path, // TreeModel::Path&
231                                         column, //TreeViewColumn*&
232                                         cell_x,cell_y //int&cell_x,int&cell_y
233                                         )
234                                 ) break;
235
236                                 if(!get_model()->get_iter(path))
237                                         break;
238
239                                 Gtk::TreeRow row = *(get_model()->get_iter(path));
240
241                                 if(column && cellrenderer_time_track==column->get_first_cell_renderer())
242                                 {
243                                         Gdk::Rectangle rect;
244                                         get_cell_area(path,*column,rect);
245                                         cellrenderer_time_track->property_value_desc()=row[model.value_desc];
246                                         cellrenderer_time_track->property_canvas()=row[model.canvas];
247                                         cellrenderer_time_track->activate(event,*this,path.to_string(),rect,rect,Gtk::CellRendererState());
248                                         queue_draw();
249                                         queue_draw_area(rect.get_x(),rect.get_y(),rect.get_width(),rect.get_height());
250                                         return true;
251                                 }
252                         }
253                         break;
254                 default:
255                         break;
256                 }
257                 mimic_resync();
258                 return Gtk::TreeView::on_event(event);
259         }
260
261         void
262         queue_draw_msg()
263         {
264                 synfig::info("*************QUEUE_DRAW***************** (time track view)");
265                 Widget::queue_draw();
266         }
267         void set_model(Glib::RefPtr<LayerParamTreeStore> store)
268         {
269                 Gtk::TreeView::set_model(store);
270                 param_tree_store_=store;
271                 cellrenderer_time_track->set_canvas_interface(param_tree_store_->canvas_interface());
272                 store->signal_changed().connect(sigc::mem_fun(*this, &TimeTrackView::queue_draw));
273         }
274
275         void
276         on_waypoint_changed( synfig::Waypoint waypoint , synfig::ValueNode::Handle value_node)
277         {
278                 // \todo is this code used?
279                 assert(0);
280
281                 synfigapp::Action::ParamList param_list;
282                 param_list.add("canvas",param_tree_store_->canvas_interface()->get_canvas());
283                 param_list.add("canvas_interface",param_tree_store_->canvas_interface());
284                 param_list.add("value_node",value_node);
285                 param_list.add("waypoint",waypoint);
286         //      param_list.add("time",canvas_interface()->get_time());
287
288                 etl::handle<studio::Instance>::cast_static(param_tree_store_->canvas_interface()->get_instance())->process_action("WaypointSetSmart", param_list);
289         }
290
291         void mimic(Gtk::TreeView *param_tree_view)
292         {
293                 mimic_tree_view=param_tree_view;
294                 param_tree_view->signal_row_expanded().connect(
295                         sigc::hide<0>(
296                         sigc::hide_return(
297                                 sigc::bind<-1>(
298                                         sigc::mem_fun(
299                                                 *this,
300                                                 &Gtk::TreeView::expand_row
301                                         ),
302                                         false
303                                 )
304                         ))
305                 );
306                 param_tree_view->signal_row_collapsed().connect(
307                         sigc::hide<0>(
308                         sigc::hide_return(
309                                         sigc::mem_fun(
310                                                 *this,
311                                                 &Gtk::TreeView::collapse_row
312                                         )
313                         ))
314                 );
315                 mimic_resync();
316         }
317
318         void mimic_resync()
319         {
320                 if(mimic_tree_view)
321                 {
322                         Gtk::Adjustment &adjustment(*mimic_tree_view->get_vadjustment());
323                         set_vadjustment(adjustment);
324
325                         if(adjustment.get_page_size()>get_height())
326                                 adjustment.set_page_size(get_height());
327
328                         int row_height = 0;
329                         if(getenv("SYNFIG_TIMETRACK_ROW_HEIGHT"))
330                                 row_height = atoi(getenv("SYNFIG_TIMETRACK_ROW_HEIGHT"));
331                         if (row_height < 3)
332                                 row_height = 18;
333
334                         cellrenderer_time_track->set_fixed_size(-1,row_height);
335                 }
336         }
337
338         void
339         on_waypoint_clicked_timetrackview(const etl::handle<synfig::Node>& node,
340                                                                           const synfig::Time& time,
341                                                                           const synfig::Time& time_offset __attribute__ ((unused)),
342                                                                           int button)
343         {
344                 std::set<synfig::Waypoint, std::less<UniqueID> > waypoint_set;
345                 synfig::waypoint_collect(waypoint_set,time,node);
346
347                 synfigapp::ValueDesc value_desc;
348
349                 if (waypoint_set.size() == 1)
350                 {
351                         ValueNode::Handle value_node(waypoint_set.begin()->get_parent_value_node());
352                         assert(value_node);
353
354                         Gtk::TreeRow row;
355                         if (param_tree_store_->find_first_value_node(value_node, row) && row)
356                                 value_desc = static_cast<synfigapp::ValueDesc>(row[model.value_desc]);
357                 }
358
359                 if (!waypoint_set.empty())
360                         signal_waypoint_clicked_timetrackview(value_desc,waypoint_set,button);
361         }
362 };
363
364 /* === G L O B A L S ======================================================= */
365
366 /* === P R O C E D U R E S ================================================= */
367
368 /* === M E T H O D S ======================================================= */
369
370 Dock_Timetrack::Dock_Timetrack():
371         Dock_CanvasSpecific("timetrack",_("Timetrack"),Gtk::StockID("synfig-timetrack"))
372 {
373         table_=0;
374         widget_timeslider_= new Widget_Timeslider();
375         widget_kf_list_= new Widget_Keyframe_List();
376
377         int header_height = 0;
378         if(getenv("SYNFIG_TIMETRACK_HEADER_HEIGHT"))
379                 header_height = atoi(getenv("SYNFIG_TIMETRACK_HEADER_HEIGHT"));
380         if (header_height < 3)
381                 header_height = 24;
382
383         widget_timeslider_->set_size_request(-1,header_height-header_height/3+1);
384         widget_kf_list_->set_size_request(-1,header_height/3+1);
385
386         hscrollbar_=new Gtk::HScrollbar();
387         vscrollbar_=new Gtk::VScrollbar();
388 }
389
390 Dock_Timetrack::~Dock_Timetrack()
391 {
392         if(table_)delete table_;
393         delete hscrollbar_;
394         delete vscrollbar_;
395         delete widget_timeslider_;
396         delete widget_kf_list_;
397 }
398
399 void
400 Dock_Timetrack::init_canvas_view_vfunc(etl::loose_handle<CanvasView> canvas_view)
401 {
402         LayerParamTreeStore::Model model;
403
404         Glib::RefPtr<LayerParamTreeStore> tree_store(
405                 Glib::RefPtr<LayerParamTreeStore>::cast_dynamic(
406                         canvas_view->get_tree_model("params")
407                 )
408         );
409
410         TimeTrackView* tree_view(new TimeTrackView());
411         tree_view->set_canvas_view(canvas_view);
412         tree_view->set_model(tree_store);
413         Gtk::TreeView* param_tree_view(dynamic_cast<Gtk::TreeView*>(canvas_view->get_ext_widget("params")));
414         tree_view->mimic(param_tree_view);
415
416         tree_view->signal_waypoint_clicked_timetrackview.connect(sigc::mem_fun(*canvas_view, &studio::CanvasView::on_waypoint_clicked_canvasview));
417
418         canvas_view->time_adjustment().signal_value_changed().connect(sigc::mem_fun(*tree_view,&Gtk::TreeView::queue_draw));
419         canvas_view->time_adjustment().signal_changed().connect(sigc::mem_fun(*tree_view,&Gtk::TreeView::queue_draw));
420
421         canvas_view->set_ext_widget(get_name(),tree_view);
422 }
423
424 void
425 Dock_Timetrack::refresh_selected_param()
426 {
427 /*      Gtk::TreeView* tree_view(
428                 static_cast<Gtk::TreeView*>(get_canvas_view()->get_ext_widget(get_name()))
429         );
430         Gtk::TreeModel::iterator iter(tree_view->get_selection()->get_selected());
431
432         if(iter)
433         {
434                 LayerParamTreeStore::Model model;
435                 get_canvas_view()->work_area->set_selected_value_node(
436                         (synfig::ValueNode::Handle)(*iter)[model.value_node]
437                 );
438         }
439         else
440         {
441                 get_canvas_view()->work_area->set_selected_value_node(0);
442         }
443 */
444 }
445
446 void
447 Dock_Timetrack::changed_canvas_view_vfunc(etl::loose_handle<CanvasView> canvas_view)
448 {
449         if(table_)
450         {
451                 table_->hide();
452                 delete table_;
453                 hscrollbar_->unset_adjustment();
454                 vscrollbar_->unset_adjustment();
455                 //widget_timeslider_->unset_adjustment();
456                 table_=0;
457         }
458
459         if(canvas_view)
460         {
461                 TimeTrackView* tree_view(dynamic_cast<TimeTrackView*>(canvas_view->get_ext_widget(get_name())));
462         Gtk::TreeView* param_tree_view(dynamic_cast<Gtk::TreeView*>(canvas_view->get_ext_widget("params")));
463         tree_view->set_vadjustment(*param_tree_view->get_vadjustment());
464
465                 assert(tree_view);
466
467
468                 widget_timeslider_->set_time_adjustment(&canvas_view->time_adjustment());
469                 widget_timeslider_->set_bounds_adjustment(&canvas_view->time_window_adjustment());
470                 widget_timeslider_->set_global_fps(canvas_view->get_canvas()->rend_desc().get_frame_rate());
471
472                 widget_kf_list_->set_time_adjustment(&canvas_view->time_adjustment());
473                 widget_kf_list_->set_canvas_interface(canvas_view->canvas_interface());
474
475                 vscrollbar_->set_adjustment(*tree_view->get_vadjustment());
476                 hscrollbar_->set_adjustment(canvas_view->time_window_adjustment());
477                 table_=new Gtk::Table(2,3);
478                 table_->attach(*widget_timeslider_, 0, 1, 1, 2, Gtk::FILL|Gtk::SHRINK, Gtk::FILL|Gtk::SHRINK);
479                 table_->attach(*widget_kf_list_, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::SHRINK);
480                 table_->attach(*tree_view, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
481                 table_->attach(*hscrollbar_, 0, 1, 3, 4, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::SHRINK);
482                 table_->attach(*vscrollbar_, 1, 2, 0, 3, Gtk::FILL|Gtk::SHRINK, Gtk::FILL|Gtk::EXPAND);
483                 add(*table_);
484
485                 //add(*last_widget_curves_);
486                 table_->show_all();
487                 show_all();
488         }
489         else
490         {
491                 //clear_previous();
492         }
493 }