Implements PXEGeek's http://wiki.synfig.com/Wish_list entry: "Optionally display...
[synfig.git] / synfig-studio / trunk / src / gtkmm / layeractionmanager.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file layeractionmanager.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 "layeractionmanager.h"
33 #include "layertree.h"
34 #include <synfigapp/action_param.h>
35 #include "instance.h"
36 #include <synfigapp/selectionmanager.h>
37
38 #endif
39
40 /* === U S I N G =========================================================== */
41
42 using namespace std;
43 using namespace etl;
44 using namespace synfig;
45 using namespace studio;
46
47 static const guint no_prev_popup((guint)-1);
48
49 /* === M A C R O S ========================================================= */
50
51 //#define ONE_ACTION_GROUP 1
52
53 /* === G L O B A L S ======================================================= */
54
55 /* === P R O C E D U R E S ================================================= */
56
57 /* === M E T H O D S ======================================================= */
58
59 LayerActionManager::LayerActionManager():
60         action_group_(Gtk::ActionGroup::create()),
61         action_group_copy_paste(Gtk::ActionGroup::create()),
62         popup_id_(no_prev_popup),
63         queued(false)
64 {
65         action_cut_=Gtk::Action::create(
66                 "cut",
67                 Gtk::StockID("gtk-cut")
68         );
69         action_cut_->signal_activate().connect(
70                 sigc::mem_fun(
71                         *this,
72                         &LayerActionManager::cut
73                 )
74         );
75         action_copy_=Gtk::Action::create(
76                 "copy",
77                 Gtk::StockID("gtk-copy")
78         );
79         action_copy_->signal_activate().connect(
80                 sigc::mem_fun(
81                         *this,
82                         &LayerActionManager::copy
83                 )
84         );
85         action_paste_=Gtk::Action::create(
86                 "paste",
87                 Gtk::StockID("gtk-paste")
88         );
89         action_paste_->signal_activate().connect(
90                 sigc::mem_fun(
91                         *this,
92                         &LayerActionManager::paste
93                 )
94         );
95
96
97         action_amount_inc_=Gtk::Action::create(
98                 "amount-inc",
99                 Gtk::StockID("gtk-add"),
100                 _("Increase Amount"),_("Increase Amount")
101         );
102         action_amount_inc_->signal_activate().connect(
103                 sigc::mem_fun(
104                         *this,
105                         &LayerActionManager::amount_inc
106                 )
107         );
108
109         action_amount_dec_=Gtk::Action::create(
110                 "amount-dec",
111                 Gtk::StockID("gtk-remove"),
112                 _("Decrease Amount"),_("Decrease Amount")
113         );
114         action_amount_dec_->signal_activate().connect(
115                 sigc::mem_fun(
116                         *this,
117                         &LayerActionManager::amount_dec
118                 )
119         );
120
121         action_amount_=Gtk::Action::create(
122                 "amount",
123                 Gtk::StockID("gtk-index"),
124                 _("Amount"),_("Amount")
125         );
126
127
128 }
129
130 LayerActionManager::~LayerActionManager()
131 {
132 }
133
134 void
135 LayerActionManager::set_ui_manager(const Glib::RefPtr<Gtk::UIManager> &x)
136 {
137         clear();
138
139 #ifdef ONE_ACTION_GROUP
140         if(ui_manager_) get_ui_manager()->remove_action_group(action_group_);
141         ui_manager_=x;
142         if(ui_manager_) get_ui_manager()->insert_action_group(action_group_);
143 #else
144         ui_manager_=x;
145 #endif
146 }
147
148 void
149 LayerActionManager::set_layer_tree(LayerTree* x)
150 {
151         selection_changed_connection.disconnect();
152         layer_tree_=x;
153         if(layer_tree_)
154         {
155                 selection_changed_connection=layer_tree_->get_selection()->signal_changed().connect(
156                         sigc::mem_fun(*this,&LayerActionManager::queue_refresh)
157                 );
158         }
159 }
160
161 void
162 LayerActionManager::set_canvas_interface(const etl::handle<synfigapp::CanvasInterface> &x)
163 {
164         canvas_interface_=x;
165 }
166
167 void
168 LayerActionManager::clear()
169 {
170         if(ui_manager_)
171         {
172                 // Clear out old stuff
173                 if(popup_id_!=no_prev_popup)
174                 {
175                         get_ui_manager()->remove_ui(popup_id_);
176                         if(action_group_)get_ui_manager()->ensure_update();
177                         popup_id_=no_prev_popup;
178                         if(action_group_)while(!action_group_->get_actions().empty())action_group_->remove(*action_group_->get_actions().begin());
179 #ifdef ONE_ACTION_GROUP
180 #else
181                         if(action_group_)get_ui_manager()->remove_action_group(action_group_);
182                         action_group_=Gtk::ActionGroup::create();
183 #endif
184                 }
185         }
186
187         while(!update_connection_list.empty())
188         {
189                 update_connection_list.front().disconnect();
190                 update_connection_list.pop_front();
191         }
192 }
193
194 void
195 LayerActionManager::queue_refresh()
196 {
197         if(queued)
198                 return;
199
200         //queue_refresh_connection.disconnect();
201         queue_refresh_connection=Glib::signal_idle().connect(
202                 sigc::bind_return(
203                         sigc::mem_fun(*this,&LayerActionManager::refresh),
204                         false
205                 )
206         );
207
208         queued=true;
209 }
210
211 void
212 LayerActionManager::refresh()
213 {
214         if(queued)
215         {
216                 queued=false;
217                 //queue_refresh_connection.disconnect();
218         }
219
220
221         clear();
222
223         // Make sure we are ready
224         if(!ui_manager_ || !layer_tree_ || !canvas_interface_)
225         {
226                 synfig::error("LayerActionManager::refresh(): Not ready!");
227                 return;
228         }
229
230
231         String ui_info;
232
233         action_paste_->set_sensitive(!clipboard_.empty());
234         action_group_->add(action_paste_);
235
236         if(layer_tree_->get_selection()->count_selected_rows()!=0)
237         {
238                 bool multiple_selected(layer_tree_->get_selection()->count_selected_rows()>1);
239                 Layer::Handle layer(layer_tree_->get_selected_layer());
240
241                 {
242                         bool canvas_set(false);
243                         synfigapp::Action::ParamList param_list;
244                         param_list.add("time",get_canvas_interface()->get_time());
245                         param_list.add("canvas_interface",get_canvas_interface());
246                         {
247                                 synfigapp::SelectionManager::LayerList layer_list(layer_tree_->get_selected_layers());
248                                 synfigapp::SelectionManager::LayerList::iterator iter;
249                                 action_copy_->set_sensitive(!layer_list.empty());
250                                 action_cut_->set_sensitive(!layer_list.empty());
251                                 action_group_->add(action_copy_);
252                                 action_group_->add(action_cut_);
253
254                                 action_amount_inc_->set_sensitive(!layer_list.empty());
255                                 action_amount_dec_->set_sensitive(!layer_list.empty());
256                                 action_amount_->set_sensitive(!layer_list.empty());
257                                 action_group_->add(action_amount_inc_);
258                                 action_group_->add(action_amount_dec_);
259                                 action_group_->add(action_amount_);
260
261                                 for(iter=layer_list.begin();iter!=layer_list.end();++iter)
262                                 {
263                                         update_connection_list.push_back(
264                                                 (*iter)->signal_changed().connect(
265                                                         sigc::mem_fun(*this, &LayerActionManager::queue_refresh)
266                                                 )
267                                         );
268
269                                         if(!canvas_set)
270                                         {
271                                                 param_list.add("canvas",Canvas::Handle((*iter)->get_canvas()));
272                                                 canvas_set=true;
273                                                 update_connection_list.push_back(
274                                                         (*iter)->get_canvas()->signal_changed().connect(
275                                                                 sigc::mem_fun(*this, &LayerActionManager::queue_refresh)
276                                                         )
277                                                 );
278                                         }
279                                         param_list.add("layer",Layer::Handle(*iter));
280                                 }
281                         }
282
283                         if(!multiple_selected && layer->get_name()=="PasteCanvas")
284                         {
285                                 action_group_->add(Gtk::Action::create(
286                                         "select-all-child-layers",
287                                         _("Select All Child Layers")
288                                 ),
289                                         sigc::bind(
290                                                 sigc::mem_fun(
291                                                         *layer_tree_,
292                                                         &studio::LayerTree::select_all_children_layers
293                                                 ),
294                                                 Layer::LooseHandle(layer)
295                                         )
296                                 );
297                                 ui_info+="<menuitem action='select-all-child-layers'/>";
298                         }
299                         handle<studio::Instance>::cast_static(get_canvas_interface()->get_instance())->
300                                 add_actions_to_group(action_group_, ui_info,   param_list, synfigapp::Action::CATEGORY_LAYER);
301                 }
302         }
303
304         ui_info="<ui><menubar action='menu-main'><menu action='menu-layer'>"+ui_info+"<separator/><menuitem action='cut' /><menuitem action='copy' /><menuitem action='paste' /><separator/></menu></menubar></ui>";
305         popup_id_=get_ui_manager()->add_ui_from_string(ui_info);
306 #ifdef ONE_ACTION_GROUP
307 #else
308         get_ui_manager()->insert_action_group(action_group_);
309 #endif
310         DEBUGPOINT();
311 }
312
313 void
314 LayerActionManager::cut()
315 {
316         copy();
317         if(action_group_->get_action("action-layer_remove"))
318                 action_group_->get_action("action-layer_remove")->activate();
319 }
320
321 void
322 LayerActionManager::copy()
323 {
324         synfigapp::SelectionManager::LayerList layer_list(layer_tree_->get_selected_layers());
325         clipboard_.clear();
326         synfig::GUID guid;
327
328         while(!layer_list.empty())
329         {
330                 clipboard_.push_back(layer_list.front()->clone(guid));
331                 layer_list.pop_front();
332         }
333
334         action_paste_->set_sensitive(!clipboard_.empty());
335
336         //queue_refresh();
337 }
338
339 void
340 LayerActionManager::paste()
341 {
342         synfig::GUID guid;
343
344         // Create the action group
345         synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Paste"));
346
347         Canvas::Handle canvas(get_canvas_interface()->get_canvas());
348         int depth(0);
349
350         // we are temporarily using the layer to hold something
351         Layer::Handle layer(layer_tree_->get_selected_layer());
352         if(layer)
353         {
354                 depth=layer->get_depth();
355                 canvas=layer->get_canvas();
356         }
357
358         synfigapp::SelectionManager::LayerList layer_selection;
359
360         for(std::list<synfig::Layer::Handle>::iterator iter=clipboard_.begin();iter!=clipboard_.end();++iter)
361         {
362                 layer=(*iter)->clone(guid);
363                 layer_selection.push_back(layer);
364                 synfigapp::Action::Handle       action(synfigapp::Action::create("layer_add"));
365
366                 assert(action);
367                 if(!action)
368                         return;
369
370                 action->set_param("canvas",canvas);
371                 action->set_param("canvas_interface",etl::loose_handle<synfigapp::CanvasInterface>(get_canvas_interface()));
372                 action->set_param("new",layer);
373
374                 if(!action->is_ready())
375                 {
376                         return;
377                 }
378
379                 if(!get_instance()->perform_action(action))
380                 {
381                         return;
382                 }
383
384                 synfig::info("DEPTH=%d",depth);
385                 // Action to move the layer (if necessary)
386                 if(depth>0)
387                 {
388                         synfigapp::Action::Handle       action(synfigapp::Action::create("layer_move"));
389
390                         assert(action);
391                         if(!action)
392                                 return;
393
394                         action->set_param("canvas",canvas);
395                         action->set_param("canvas_interface",etl::loose_handle<synfigapp::CanvasInterface>(get_canvas_interface()));
396                         action->set_param("layer",layer);
397                         action->set_param("new_index",depth);
398
399                         if(!action->is_ready())
400                         {
401                                 //get_ui_interface()->error(_("Move Action Not Ready"));
402                                 //return 0;
403                                 return;
404                         }
405
406                         if(!get_instance()->perform_action(action))
407                         {
408                                 //get_ui_interface()->error(_("Move Action Not Ready"));
409                                 //return 0;
410                                 return;
411                         }
412                 }
413                 depth++;
414         }
415         get_canvas_interface()->get_selection_manager()->clear_selected_layers();
416         get_canvas_interface()->get_selection_manager()->set_selected_layers(layer_selection);
417 }
418
419 void
420 LayerActionManager::amount_inc()
421 {
422         float adjust(0.1);
423
424         // Create the action group
425         synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Decrease Amount"));
426
427         if(adjust>0)
428                 group.set_name(_("Increase Amount"));
429
430         synfigapp::SelectionManager::LayerList layer_list(layer_tree_->get_selected_layers());
431
432         while(!layer_list.empty())
433         {
434                 ValueBase value(layer_list.front()->get_param("amount"));
435                 if(value.same_as(Real()))
436                 {
437                         get_canvas_interface()->change_value(synfigapp::ValueDesc(layer_list.front(),"amount"),value.get(Real())+adjust);
438                 }
439                 layer_list.pop_front();
440         }
441 }
442
443 void
444 LayerActionManager::amount_dec()
445 {
446         float adjust(-0.1);
447
448         // Create the action group
449         synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Decrease Amount"));
450
451         if(adjust>0)
452                 group.set_name(_("Increase Amount"));
453
454         synfigapp::SelectionManager::LayerList layer_list(layer_tree_->get_selected_layers());
455
456         while(!layer_list.empty())
457         {
458                 ValueBase value(layer_list.front()->get_param("amount"));
459                 if(value.same_as(Real()))
460                 {
461                         get_canvas_interface()->change_value(synfigapp::ValueDesc(layer_list.front(),"amount"),value.get(Real())+adjust);
462                 }
463                 layer_list.pop_front();
464         }
465 }