Add actions (add to group, ,remove from group, export, un-export, set layer descripti...
[synfig.git] / synfig-studio / src / gtkmm / dockable.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file dockable.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 "app.h"
33 #include <sigc++/hide.h>
34
35 #include "dockable.h"
36 #include "dockmanager.h"
37 #include "dockbook.h"
38 #include "dockdialog.h"
39 #include <synfig/general.h>
40 #include <gtkmm/table.h>
41 #include <gtk/gtk.h>
42
43 #include "general.h"
44
45 #endif
46
47 /* === U S I N G =========================================================== */
48
49 using namespace std;
50 using namespace etl;
51 using namespace synfig;
52 using namespace studio;
53
54 /* === M A C R O S ========================================================= */
55
56 #ifdef WIN32
57 #       ifdef IMAGE_DIR
58 #               undef IMAGE_DIR
59 #               define IMAGE_DIR "share\\pixmaps"
60 #       endif
61 #endif
62
63 #ifndef IMAGE_DIR
64 #       define IMAGE_DIR "/usr/local/share/pixmaps"
65 #endif
66
67 #ifndef IMAGE_EXT
68 #       define IMAGE_EXT        "png"
69 #endif
70
71 /* === G L O B A L S ======================================================= */
72
73 /* === P R O C E D U R E S ================================================= */
74
75 /* === M E T H O D S ======================================================= */
76
77 Dockable::Dockable(const synfig::String& name,const synfig::String& local_name,Gtk::StockID stock_id_):
78 //      Gtk::Window(Gtk::WINDOW_TOPLEVEL),
79         name_(name),
80         local_name_(local_name),
81 //      dialog_settings(this,name),
82         title_label_(local_name,Gtk::ALIGN_LEFT),
83         stock_id_(stock_id_)
84 {
85         parent_=0;
86         scrolled_=0;
87
88         use_scrolled_=true;
89
90         //set_title(local_name);
91         //set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
92
93
94         title_label_.show();
95
96         attach_dnd_to(title_label_);
97
98         //scrolled_.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC);
99         //scrolled_.show();
100         //scrolled_.set_shadow_type(Gtk::SHADOW_NONE);
101
102         toolbar_=0;
103         //button_box_.show();
104
105         Gtk::Table* table(this);
106
107         {
108                 title_label_.set_padding(0,0);
109                 Gtk::EventBox* event_box(manage(new Gtk::EventBox()));
110                 event_box->set_border_width(0);
111                 event_box->add(title_label_);
112                 //table->attach(*event_box, 0, 1, 0,1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
113
114                 header_box_.pack_start(*event_box);
115
116                 attach_dnd_to(*event_box);
117                 event_box->show();
118         //      event_box->set_events(Gdk::ALL_EVENTS_MASK); //!< \todo change this to only allow what is necessary for DnD
119
120
121                 Gtk::Button* bttn_close(manage(new Gtk::Button(_("X"))));
122                 //table->attach(*bttn_close, 1, 2, 0,1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
123                 header_box_.pack_end(*bttn_close,false,false);
124                 bttn_close->show();
125                 bttn_close->set_relief(Gtk::RELIEF_NONE);
126                 bttn_close->signal_clicked().connect(sigc::mem_fun(*this,&Dockable::detach));
127                 bttn_close->set_border_width(0);
128                 dynamic_cast<Gtk::Misc*>(bttn_close->get_child())->set_padding(0,0);
129         }
130
131         prev_widget_=manage(new Gtk::Label(" "));
132
133         //table->attach(header_box_, 0, 1, 0,1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
134         table->attach(*prev_widget_, 0, 1, 1,2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
135         //table->attach(*toolbar_, 0, 1, 2,3, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
136         set_toolbar(*manage(new Gtk::Toolbar));
137         table->show();
138
139         prev_widget_->show();
140
141         set_size_request(175,120);
142         //scrolled_.set_shadow_type(Gtk::SHADOW_NONE);
143
144 }
145
146 Dockable::~Dockable()
147 {
148         if(scrolled_)
149         {
150                 delete scrolled_;
151                 scrolled_=0;
152         }
153
154         /*if(App::dock_manager)try{
155                 App::dock_manager->unregister_dockable(*this);
156                 std::list<Dockable*>::iterator iter;
157                 for(iter=App::dock_manager->dockable_list_.begin();iter!=App::dock_manager->dockable_list_.end();++iter)
158                         if(*iter==this)
159                         {
160                                 App::dock_manager->dockable_list_.erase(iter);
161                                 return;
162                         }
163         } catch(...) { }
164 */
165         //if(App::dock_manager)
166         //      App::dock_manager->dockable_list_.erase(this);
167 }
168
169 void
170 Dockable::attach_dnd_to(Gtk::Widget& widget)
171 {
172         std::list<Gtk::TargetEntry> listTargets;
173         listTargets.push_back( Gtk::TargetEntry("DOCK") );
174
175         widget.drag_source_set(listTargets);
176         widget.drag_source_set_icon(get_stock_id());
177         widget.drag_dest_set(listTargets);
178
179
180         widget.signal_drag_data_get().connect(sigc::mem_fun(*this,&Dockable::on_drag_data_get));
181         widget.signal_drag_end().connect(sigc::mem_fun(*this,&Dockable::on_drag_end));
182         widget.signal_drag_begin().connect(sigc::mem_fun(*this,&Dockable::on_drag_begin));
183         widget.signal_drag_data_received().connect(sigc::mem_fun(*this,&Dockable::on_drag_data_received));
184 }
185
186 void
187 Dockable::on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
188 {
189         if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
190         {
191                 Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
192
193                 if(dockable.parent_ != parent_)
194                         parent_->add(dockable,parent_->page_num(*this));
195                 else
196                         parent_->reorder_child(dockable,parent_->page_num(*this));
197                 dockable.present();
198                 context->drag_finish(true, false, time);
199                 return;
200         }
201
202         context->drag_finish(false, false, time);
203 }
204
205 void
206 Dockable::on_drag_end(const Glib::RefPtr<Gdk::DragContext>&/*context*/)
207 {
208         if(!dnd_success_)
209         {
210                 detach();
211                 present();
212         }
213 }
214
215 void
216 Dockable::on_drag_begin(const Glib::RefPtr<Gdk::DragContext>&/*context*/)
217 {
218         dnd_success_=false;
219 }
220
221 void
222 Dockable::on_drag_data_get(const Glib::RefPtr<Gdk::DragContext>&, Gtk::SelectionData& selection_data, guint /*info*/, guint /*time*/)
223 {
224         Dockable* tmp(this);
225         dnd_success_=true;
226
227         selection_data.set(8, reinterpret_cast<const guchar*>(&tmp), 4);
228 }
229
230 void
231 Dockable::set_local_name(const synfig::String& local_name)
232 {
233         //set_title(local_name);
234         title_label_.set_text(local_name);
235 }
236
237 void
238 Dockable::clear()
239 {
240         //if(!toolbar_->children().empty())
241         //      toolbar_->children().clear();
242         set_toolbar(*manage(new Gtk::Toolbar));
243
244 }
245
246 void
247 Dockable::set_toolbar(Gtk::Toolbar& toolbar)
248 {
249         if(toolbar_)remove(*toolbar_);
250         toolbar_=0;
251         toolbar_=&toolbar;
252         if(toolbar_)
253         {
254                 attach(*toolbar_, 0, 1, 2,3, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
255                 gtk_toolbar_set_icon_size(toolbar_->gobj(),GtkIconSize(1)/*GTK_ICON_SIZE_MENU*/);
256                 toolbar_->show();
257         }
258 }
259
260 bool
261 Dockable::clear_previous()
262 {
263         prev_widget_=0;
264         prev_widget_delete_connection.disconnect();
265         return false;
266 }
267
268 void
269 Dockable::add(Gtk::Widget& x)
270 {
271         if(prev_widget_)
272         {
273                 remove(*prev_widget_);
274                 //prev_widget_=0;
275                 clear_previous();
276         }
277
278         if(scrolled_)
279         {
280                 delete scrolled_;
281                 scrolled_=0;
282         }
283
284         if(use_scrolled_)
285         {
286                 scrolled_=new Gtk::ScrolledWindow;
287
288                 scrolled_->add(x);
289
290                 attach(*scrolled_, 0, 1, 1,2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
291
292                 x.show();
293
294                 scrolled_->show();
295
296                 scrolled_->set_shadow_type(Gtk::SHADOW_NONE);
297                 scrolled_->set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC);
298                 prev_widget_=scrolled_;
299         }
300         else
301         {
302                 attach(x, 0, 1, 1,2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
303                 x.show();
304                 prev_widget_=&x;
305         }
306         prev_widget_delete_connection=prev_widget_->signal_delete_event().connect(
307                 sigc::hide(
308                         sigc::mem_fun(
309                                 *this,
310                                 &Dockable::clear_previous
311                         )
312                 )
313         );
314 }
315
316 Gtk::ToolButton*
317 Dockable::add_button(const Gtk::StockID& stock_id, const synfig::String& tooltip)
318 {
319         if(!toolbar_)
320                 set_toolbar(*manage(new Gtk::Toolbar));
321
322         //Gtk::IconSize iconsize(4);
323         //Gtk::IconSize iconsize(Gtk::IconSize::from_name("synfig-small_icon"));
324
325         Gtk::ToolButton* ret(manage(new Gtk::ToolButton(stock_id)));
326         //Gtk::Image* icon(manage(new Gtk::Image(stock_id,iconsize)));
327         //ret->add(*icon);
328         //ret->set_relief(Gtk::RELIEF_HALF);
329         //ret->set_relief(Gtk::RELIEF_NONE);
330         ret->set_label(tooltip);
331         if (toolbar_->get_tooltips_object())
332                 toolbar_->get_tooltips_object()->set_tip(*ret,tooltip);
333
334         ret->show();
335         //icon->show();
336         toolbar_->set_tooltips(true);
337
338         toolbar_->append(*ret);
339         //button_box_.pack_start(*ret,false,false);
340         //get_action_area()->pack_start(*ret,false,false);
341         //add_action_widget(*ret,1);
342         return ret;
343 }
344
345
346 void
347 Dockable::detach()
348 {
349         if(parent_)
350                 parent_->remove(*this);
351 }
352
353 void
354 Dockable::present()
355 {
356         if(parent_)
357         {
358                 parent_->set_current_page(parent_->page_num(*this));
359                 parent_->present();
360         }
361         else
362         {
363                 DockDialog* dock_dialog(new DockDialog());
364                 dock_dialog->get_dock_book().add(*this);
365                 //if(get_name()=="canvases")
366                 //      dock_dialog->set_composition_selector(true);
367                 dock_dialog->present();
368         }
369 }
370
371 Gtk::Widget*
372 Dockable::create_tab_label()
373 {
374         Gtk::EventBox* event_box(manage(new Gtk::EventBox()));
375
376         attach_dnd_to(*event_box);
377
378         {
379                 Gtk::StockID stock_id(get_stock_id());
380                 Gtk::StockItem item;
381
382                 // Check to make sure the icon is valid
383                 if(Gtk::Stock::lookup(stock_id,item))
384                 {
385                         Gtk::Image* icon(manage(new Gtk::Image(stock_id,Gtk::IconSize(4))));
386                         event_box->add(*icon);
387                         tooltips_.set_tip(*event_box,get_local_name());
388                         icon->show();
389                 }
390                 else
391                 {
392                         // Bad icon, try to make a label
393
394                         Glib::ustring text(get_local_name());
395
396                         Gtk::Label* label(manage(new Gtk::Label(text)));
397                         event_box->add(*label);
398                         label->show();
399                 }
400         }
401
402         return event_box;
403 }