1 /* === S Y N F I G ========================================================= */
2 /*!	\file keyframetree.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 **	Copyright (c) 2012-2013 Konstantin Dmitriev
11 **
12 **	This package is free software; you can redistribute it and/or
13 **	modify it under the terms of the GNU General Public License as
14 **	published by the Free Software Foundation; either version 2 of
15 **	the License, or (at your option) any later version.
16 **
17 **	This package is distributed in the hope that it will be useful,
18 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 **	General Public License for more details.
21 **	\endlegal
22 */
23 /* ========================================================================= */
24 
25 /* === H E A D E R S ======================================================= */
26 
27 #ifdef USING_PCH
28 #	include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #	include <config.h>
32 #endif
33 
34 #include <synfig/general.h>
35 
36 #include "app.h"
37 #include "trees/keyframetree.h"
38 #include "cellrenderer/cellrenderer_time.h"
39 #include <gtkmm/treemodelsort.h>
40 #include <ETL/misc>
41 
42 #include <gui/localization.h>
43 
44 #endif
45 
46 /* === U S I N G =========================================================== */
47 
48 using namespace std;
49 using namespace etl;
50 using namespace synfig;
51 using namespace studio;
52 
53 /* === M A C R O S ========================================================= */
54 
55 /* === G L O B A L S ======================================================= */
56 
57 /* === P R O C E D U R E S ================================================= */
58 
59 /* === M E T H O D S ======================================================= */
60 
KeyframeTree()61 KeyframeTree::KeyframeTree()
62 {
63 	const KeyframeTreeStore::Model model;
64 
65 	{	// --- O N / O F F ----------------------------------------------------
66 		Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_(" ")) );
67 
68 		// Set up the on/off cell-renderer
69 		Gtk::CellRendererToggle* cellrenderer = Gtk::manage( new Gtk::CellRendererToggle() );
70 		cellrenderer->signal_toggled().connect(sigc::mem_fun(*this, &studio::KeyframeTree::on_keyframe_toggle));
71 		column->pack_start(*cellrenderer,false);
72 		column->add_attribute(cellrenderer->property_active(), model.active);
73 		append_column(*column);
74 	}
75 	{
76 		Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_("Time")) );
77 
78 		cell_renderer_time = Gtk::manage( new CellRenderer_Time() );
79 		column->pack_start(*cell_renderer_time,true);
80 		column->add_attribute(cell_renderer_time->property_time(), model.time);
81 		cell_renderer_time->signal_edited().connect(sigc::mem_fun(*this,&studio::KeyframeTree::on_edited_time));
82 
83 		column->set_reorderable();
84 		column->set_resizable();
85 		column->set_clickable();
86 		column->set_sort_column(model.time);
87 
88 		append_column(*column);
89 	}
90 	{
91 		Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_("Length")) );
92 
93 		cell_renderer_time_delta = Gtk::manage( new CellRenderer_Time() );
94 		column->pack_start(*cell_renderer_time_delta,true);
95 		column->add_attribute(cell_renderer_time_delta->property_time(), model.time_delta);
96 		cell_renderer_time_delta->signal_edited().connect(sigc::mem_fun(*this,&studio::KeyframeTree::on_edited_time_delta));
97 
98 		column->set_reorderable();
99 		column->set_resizable();
100 		column->set_clickable(false);
101 		// column->set_sort_column(model.time_delta);
102 
103 		append_column(*column);
104 	}
105 	{
106 		Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_("Jump")) );
107 
108 		Gtk::CellRendererText* cell_renderer_jump=Gtk::manage(new Gtk::CellRendererText());
109 		column->pack_start(*cell_renderer_jump,true);
110 		cell_renderer_jump->property_text()=_("(JMP)");
111 		cell_renderer_jump->property_foreground()="#003a7f";
112 
113 		column->set_reorderable();
114 		column->set_resizable();
115 		column->set_clickable(false);
116 
117 		append_column(*column);
118 	}
119 	{
120 		Gtk::TreeView::Column* column = Gtk::manage( new Gtk::TreeView::Column(_("Description")) );
121 
122 		cell_renderer_description=Gtk::manage(new Gtk::CellRendererText());
123 		column->pack_start(*cell_renderer_description,true);
124 		column->add_attribute(cell_renderer_description->property_text(), model.description);
125 		cell_renderer_description->signal_edited().connect(sigc::mem_fun(*this,&studio::KeyframeTree::on_edited_description));
126 
127 		column->set_reorderable();
128 		column->set_resizable();
129 		column->set_clickable();
130 		column->set_sort_column(model.description);
131 
132 		append_column(*column);
133 	}
134 
135 	set_enable_search(true);
136 	set_search_column(model.description);
137 
138 	// This makes things easier to read.
139 	set_rules_hint();
140 
141 	// Make us more sensitive to several events
142 	add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
143 
144 	// Listen to the changed selection signal to perform kf synchro thrue canvas interface
145 	get_selection()->signal_changed().connect(sigc::mem_fun(*this, &studio::KeyframeTree::on_selection_changed));
146 	send_selection = false;
147 }
148 
~KeyframeTree()149 KeyframeTree::~KeyframeTree()
150 {
151 	keyframeselected.disconnect();
152 	if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
153 		synfig::info("KeyframeTree::~KeyframeTree(): Deleted");
154 }
155 
156 void
on_rend_desc_changed()157 KeyframeTree::on_rend_desc_changed()
158 {
159 	cell_renderer_time->property_fps().set_value(keyframe_tree_store_->canvas_interface()->get_canvas()->rend_desc().get_frame_rate());
160 	queue_draw();
161 }
162 
163 void
set_model(Glib::RefPtr<KeyframeTreeStore> keyframe_tree_store)164 KeyframeTree::set_model(Glib::RefPtr<KeyframeTreeStore> keyframe_tree_store)
165 {
166 	keyframe_tree_store_=keyframe_tree_store;
167 	KeyframeTreeStore::Model model;
168 
169 	if(true)
170 	{
171 		Glib::RefPtr<Gtk::TreeModelSort> sorted_store(Gtk::TreeModelSort::create(keyframe_tree_store_));
172 		sorted_store->set_default_sort_func(sigc::ptr_fun(&studio::KeyframeTreeStore::time_sorter));
173 		sorted_store->set_sort_func(model.time,			sigc::ptr_fun(&studio::KeyframeTreeStore::time_sorter));
174 		sorted_store->set_sort_func(model.description,	sigc::ptr_fun(&studio::KeyframeTreeStore::description_sorter));
175 		Gtk::TreeView::set_model(sorted_store);
176 	}
177 	else
178 		Gtk::TreeView::set_model(keyframe_tree_store);
179 
180 	keyframe_tree_store_->canvas_interface()->signal_rend_desc_changed().connect(
181 		sigc::mem_fun(
182 			*this,
183 			&studio::KeyframeTree::on_rend_desc_changed
184 		)
185 	);
186 	cell_renderer_time->property_fps().set_value(keyframe_tree_store_->canvas_interface()->get_canvas()->rend_desc().get_frame_rate());
187 	cell_renderer_time_delta->property_fps().set_value(keyframe_tree_store_->canvas_interface()->get_canvas()->rend_desc().get_frame_rate());
188 
189 	//Listen to kf selection change from canvas interface
190 	keyframeselected = keyframe_tree_store_->canvas_interface()->signal_keyframe_selected().connect(
191 		sigc::mem_fun(
192 			*this,
193 			&studio::KeyframeTree::on_keyframe_selected
194 		)
195 	);
196 }
197 
198 void
set_editable(bool x)199 KeyframeTree::set_editable(bool x)
200 {
201 	editable_=x;
202 
203 	if(editable_)
204 	{
205 		cell_renderer_time->property_editable()=true;
206 		cell_renderer_time_delta->property_editable()=true;
207 		cell_renderer_description->property_editable()=true;
208 	}
209 	else
210 	{
211 		cell_renderer_time->property_editable()=false;
212 		cell_renderer_time_delta->property_editable()=false;
213 		cell_renderer_description->property_editable()=false;
214 	}
215 }
216 
217 void
on_keyframe_toggle(const Glib::ustring & path_string)218 KeyframeTree::on_keyframe_toggle(const Glib::ustring& path_string)
219 {
220 	Gtk::TreePath path(path_string);
221 
222 	const Gtk::TreeRow row = *(get_model()->get_iter(path));
223 	bool active=static_cast<bool>(row[model.active]);
224 	row[model.active]=!active;
225 }
226 
227 void
on_edited_time(const Glib::ustring & path_string,synfig::Time time)228 KeyframeTree::on_edited_time(const Glib::ustring&path_string,synfig::Time time)
229 {
230 	Gtk::TreePath path(path_string);
231 
232 	const Gtk::TreeRow row(*(get_model()->get_iter(path)));
233 
234 	synfig::Keyframe keyframe(row[model.keyframe]);
235 	if(time!=keyframe.get_time())
236 	{
237 		row[model.time]=time;
238 		//keyframe.set_time(time);
239 		//signal_edited_time()(keyframe,time);
240 		//signal_edited()(keyframe);
241 	}
242 }
243 
244 void
on_edited_time_delta(const Glib::ustring & path_string,synfig::Time time)245 KeyframeTree::on_edited_time_delta(const Glib::ustring&path_string,synfig::Time time)
246 {
247 	Gtk::TreePath path(path_string);
248 
249 	const Gtk::TreeRow row(*(get_model()->get_iter(path)));
250 
251 	if(row)row[model.time_delta]=time;
252 }
253 
254 void
on_edited_description(const Glib::ustring & path_string,const Glib::ustring & desc)255 KeyframeTree::on_edited_description(const Glib::ustring&path_string,const Glib::ustring &desc)
256 {
257 	Gtk::TreePath path(path_string);
258 
259 	const Gtk::TreeRow row = *(get_model()->get_iter(path));
260 
261 	const synfig::String description(desc);
262 	synfig::Keyframe keyframe(row[model.keyframe]);
263 	if(description!=keyframe.get_description())
264 	{
265 		row[model.description]=desc;
266 		keyframe.set_description(description);
267 		signal_edited_description()(keyframe,description);
268 		signal_edited()(keyframe);
269 	}
270 }
271 
272 bool
on_event(GdkEvent * event)273 KeyframeTree::on_event(GdkEvent *event)
274 {
275     switch(event->type)
276     {
277 	case GDK_KEY_PRESS:
278 		{
279 			send_selection = true;
280 		}
281 		break;
282 	case GDK_BUTTON_PRESS:
283 		{
284 			if (event->button.button == 1)
285 			{
286 				Gtk::TreeModel::Path path;
287 				Gtk::TreeViewColumn *column;
288 				int cell_x, cell_y;
289 				int wx(round_to_int(event->button.x)),wy(round_to_int(event->button.y));
290 				//tree_to_widget_coords (,, wx, wy);
291 				send_selection = true;
292 
293 				if(!get_path_at_pos(
294 					wx,wy,	// x, y
295 					path, // TreeModel::Path&
296 					column, //TreeViewColumn*&
297 					cell_x,cell_y //int&cell_x,int&cell_y
298 					)
299 				) break;
300 				const Gtk::TreeRow row = *(get_model()->get_iter(path));
301 
302 				signal_user_click()(event->button.button,row,(ColumnID)column->get_sort_column_id());
303 				if (synfig::String(column->get_title ()) == _("Jump"))
304 				{
305 					keyframe_tree_store_->canvas_interface()->set_time(row[model.time]);
306 				}
307 			} else if (event->button.button == 3)
308 			{
309 				Gtk::Menu* menu = dynamic_cast<Gtk::Menu*>(App::ui_manager()->get_widget("/menu-keyframe"));
310 				if(menu)
311 				{
312 					menu->popup(event->button.button,gtk_get_current_event_time());
313 				}
314 			}
315 
316 		}
317 		break;
318 	case GDK_2BUTTON_PRESS:
319 		{
320 			Gtk::TreeModel::Path path;
321 			Gtk::TreeViewColumn *column;
322 			int cell_x, cell_y;
323 			if(!get_path_at_pos(
324 				int(event->button.x),int(event->button.y),	// x, y
325 				path, // TreeModel::Path&
326 				column, //TreeViewColumn*&
327 				cell_x,cell_y //int&cell_x,int&cell_y
328 				)
329 			) break;
330 			const Gtk::TreeRow row = *(get_model()->get_iter(path));
331 
332 			{
333 				keyframe_tree_store_->canvas_interface()->set_time(row[model.time]);
334 				return true;
335 			}
336 		}
337 		break;
338 
339 	case GDK_BUTTON_RELEASE:
340 		break;
341 	default:
342 		break;
343 	}
344 	return false;
345 }
346 
347 void
on_selection_changed()348 KeyframeTree::on_selection_changed()
349 {
350 	//Connected on treeview::selection::changed
351 
352 	//if(send_selection && has_focus () && get_selection()->count_selected_rows()==1)
353 	if(send_selection && get_selection()->count_selected_rows()==1)
354 	{
355 
356 		Keyframe keyframe((*get_selection()->get_selected())[model.keyframe]);
357 		if(keyframe && keyframe != selected_kf && keyframe_tree_store_)
358 		{
359 			selected_kf = keyframe;
360 			keyframe_tree_store_->canvas_interface()->signal_keyframe_selected()(keyframe, (void*)this);
361 		}
362 
363 	}
364 }
365 
366 void
on_keyframe_selected(synfig::Keyframe keyframe,void * emitter)367 KeyframeTree::on_keyframe_selected(synfig::Keyframe keyframe, void* emitter)
368 {
369 	Gtk::TreeModel::Path path;
370 
371 	if((void*)this == emitter)	return;
372 
373 	if(keyframe && keyframe != selected_kf)
374 	{
375 		selected_kf = keyframe;
376 		send_selection = false;
377 		if(keyframe_tree_store_ && keyframe_tree_store_->find_keyframe_path(keyframe,path))
378 			set_cursor (path);
379 	} else send_selection = true;
380 }
381