minor fix
[synfig.git] / synfig-studio / trunk / src / gtkmm / dockdialog.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file dockdialog.cpp
3 **      \brief Template File
4 **
5 **      $Id: dockdialog.cpp,v 1.1.1.1 2005/01/07 03:34:36 darco Exp $
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++/adaptors/hide.h>
34
35 #include "dockdialog.h"
36 #include "dockbook.h"
37 #include "dockmanager.h"
38 #include "widget_compselect.h"
39 #include <synfig/general.h>
40 #include <synfig/uniqueid.h>
41 #include <gtkmm/table.h>
42 #include <sigc++/hide.h>
43 #include <sigc++/slot.h>
44 #include <sigc++/retype_return.h>
45 #include <sigc++/retype.h>
46 #include "canvasview.h"
47 #include <gtkmm/paned.h>
48 #include <gtkmm/box.h>
49 #include <synfigapp/main.h>
50
51 #endif
52
53 /* === U S I N G =========================================================== */
54
55 using namespace std;
56 using namespace etl;
57 using namespace synfig;
58 using namespace studio;
59
60 /* === M A C R O S ========================================================= */
61
62 #define GRAB_HINT_DATA(y,default)       { \
63                 String x; \
64                 if(synfigapp::Main::settings().get_value(String("pref.")+y+"_hints",x)) \
65                 { \
66                         set_type_hint((Gdk::WindowTypeHint)atoi(x.c_str()));    \
67                 } else {\
68                         set_type_hint(default); \
69                 } \
70         }
71
72 /* === G L O B A L S ======================================================= */
73
74 /* === P R O C E D U R E S ================================================= */
75
76 /* === M E T H O D S ======================================================= */
77
78 DockDialog::DockDialog():
79         Gtk::Window(Gtk::WINDOW_TOPLEVEL)
80 {
81         composition_selector_=false;
82         is_deleting=false;
83         is_horizontal=false;
84         last_dock_book=0;
85         box=0;
86         
87         widget_comp_select=new Widget_CompSelect();
88         
89         // Give ourselves an ID that is most likely unique
90         set_id(synfig::UniqueID().get_uid()^reinterpret_cast<int>(this));
91         
92         set_role(strprintf("dock_dialog_%d",get_id()));
93         GRAB_HINT_DATA(
94                 "dock_dialog",
95 #ifdef __APPLE__
96                 Gdk::WINDOW_TYPE_HINT_NORMAL
97 #else
98                 Gdk::WINDOW_TYPE_HINT_UTILITY
99 #endif
100         );
101         set_keep_below(true);
102         set_keep_above(false);
103         
104         // Set up the window
105         //set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
106         set_title("Dock Dialog");
107         
108         // Register with the dock manager
109         App::dock_manager->dock_dialog_list_.push_back(this);
110
111         
112         // connect our signals  
113         signal_delete_event().connect(
114                 sigc::hide(
115                         sigc::mem_fun(*this,&DockDialog::close)
116                 )
117         );
118         
119 /*
120         App::signal_canvas_view_focus().connect(
121                 sigc::hide(
122                         sigc::mem_fun(
123                                 *this,
124                                 &DockDialog::refresh_accel_group
125                         )
126                 )
127         );
128 */
129
130         add_accel_group(App::ui_manager()->get_accel_group());
131         App::signal_present_all().connect(sigc::mem_fun(*this,&DockDialog::present));
132
133 }
134
135 DockDialog::~DockDialog()
136 {
137         empty_sig.disconnect();
138
139         is_deleting=true;
140
141         DEBUGPOINT();
142
143         // Remove all of the dock books
144         for(;!dock_book_list.empty();dock_book_list.pop_front())
145         {
146                 dock_book_list.front()->clear();
147
148                 // UGLY HACK
149                 // The following line really should be uncommented,
150                 // but it causes crashes. Without it, a small
151                 // memory hole is created--but at least it doesn't crash
152                 // delete dock_book_list.front();
153                 
154                 // Oddly enough, the following line should
155                 // theoreticly do the same thing after this
156                 // class is destroyed, but it doesn't seem to
157                 // caues a crash.
158                 manage(dock_book_list.front());
159         }
160
161         // Remove us from the dock manager
162         if(App::dock_manager)try{
163                 std::list<DockDialog*>::iterator iter;
164                 for(iter=App::dock_manager->dock_dialog_list_.begin();iter!=App::dock_manager->dock_dialog_list_.end();++iter)
165                         if(*iter==this)
166                         {
167                                 App::dock_manager->dock_dialog_list_.erase(iter);
168                                 break;
169                         }
170         }
171         catch(...)
172         {
173                 synfig::warning("DockDialog::~DockDialog(): Exception thrown when trying to remove from dock manager...?");
174         }
175
176         delete widget_comp_select;
177
178         DEBUGPOINT();
179 }
180
181 void
182 DockDialog::drop_on_prepend(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
183 {
184         if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
185         {
186                 Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
187                 prepend_dock_book()->add(dockable);
188                 context->drag_finish(true, false, time);
189                 return;
190         }
191         
192         context->drag_finish(false, false, time);
193 }
194
195 void
196 DockDialog::drop_on_append(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
197 {
198         if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
199         {
200                 Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
201                 append_dock_book()->add(dockable);
202                 context->drag_finish(true, false, time);
203                 return;
204         }
205         
206         context->drag_finish(false, false, time);
207 }
208
209
210 void
211 DockDialog::on_hide()
212 {
213         Gtk::Window::on_hide();
214         close();
215 }
216
217 DockBook*
218 DockDialog::prepend_dock_book()
219 {
220         if(is_deleting)return 0;
221                 
222         dock_book_list.push_front(new DockBook);
223         last_dock_book=dock_book_list.front();
224
225
226         last_dock_book->signal_empty().connect(
227                 sigc::bind(
228                         sigc::mem_fun(*this,&DockDialog::erase_dock_book),
229                         last_dock_book
230                 )
231         );
232
233         dock_book_sizes_.insert(dock_book_sizes_.begin(),225);
234         refresh();
235         return last_dock_book;
236 }
237
238 DockBook*
239 DockDialog::append_dock_book()
240 {
241         if(is_deleting)return 0;
242                 
243         dock_book_list.push_back(new DockBook);
244         last_dock_book=dock_book_list.back();
245         last_dock_book->signal_empty().connect(
246                 sigc::bind(
247                         sigc::mem_fun(*this,&DockDialog::erase_dock_book),
248                         last_dock_book
249                 )
250         );
251         last_dock_book->signal_changed().connect(
252                 sigc::mem_fun(*this,&DockDialog::refresh_title)
253         );
254         last_dock_book->signal_changed().connect(
255                 sigc::mem_fun(*this,&DockDialog::refresh_title)
256         );
257         dock_book_sizes_.push_back(225);
258
259         //last_dock_book->show();
260         refresh();
261         return last_dock_book;
262 }
263
264 void
265 DockDialog::erase_dock_book(DockBook* dock_book)
266 {
267         if(is_deleting)return;
268
269         std::list<DockBook*>::iterator iter;
270         for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
271                 if(*iter==dock_book)
272                 {
273                         dock_book_list.erase(iter);
274
275                         if(dock_book_list.empty())
276                         {
277                                 last_dock_book=0;
278                                 close();
279                                 return;
280                         }
281                         else
282                         {
283                                 if(last_dock_book==dock_book)
284                                         last_dock_book=dock_book_list.front();
285                         }
286                         
287                         refresh();
288                         
289                         return;
290                 }
291 }
292
293 void
294 DockDialog::refresh()
295 {
296         synfig::info("dock_book_list.size()=%d",dock_book_list.size());
297         //remove();
298
299         if(dock_book_list.empty())
300                 return;
301         
302         if(box)delete box;
303         box=(manage(is_horizontal?(Gtk::Box*)new Gtk::HBox:(Gtk::Box*)new Gtk::VBox));
304         add(*box);
305         
306         box->pack_start(*widget_comp_select,false,true);
307
308         Gtk::Button* append_button(manage(new Gtk::Button));
309         Gtk::Button* prepend_button(manage(new Gtk::Button));
310         
311         std::list<Gtk::TargetEntry> listTargets;
312         listTargets.push_back( Gtk::TargetEntry("DOCK") );
313
314         append_button->drag_dest_set(listTargets);
315         prepend_button->drag_dest_set(listTargets);
316
317         append_button->signal_drag_data_received().connect(
318                 sigc::mem_fun(*this,&DockDialog::drop_on_append)
319         );
320
321         prepend_button->signal_drag_data_received().connect(
322                 sigc::mem_fun(*this,&DockDialog::drop_on_prepend)
323         );
324         
325         box->pack_start(*prepend_button,false,true);
326         box->pack_end(*append_button,false,true);
327
328         //prepend_button->show();
329         //append_button->show();
330         pannels_.clear();
331         
332         if(dock_book_list.size()==1)
333         {
334                 box->pack_start(get_dock_book(),true,true);
335         }
336         else
337         {
338                 Gtk::Paned* parent(manage(is_horizontal?(Gtk::Paned*)new Gtk::HPaned:(Gtk::Paned*)new Gtk::VPaned));
339                 
340                 pannels_.push_back(parent);
341                 
342                 if(pannels_.size()<=dock_book_sizes_.size())
343                         pannels_.back()->set_position(dock_book_sizes_[pannels_.size()-1]);
344                 pannels_.back()->property_position().signal_changed().connect(
345                         sigc::mem_fun(*this,&DockDialog::rebuild_sizes)
346                 );
347                 //parent->show();
348                 parent->add1(*dock_book_list.front());
349                 //dock_book_list.front()->show();
350          
351                 box->pack_start(*parent,true,true);
352                 
353                 std::list<DockBook*>::iterator iter,next;
354                 for(next=dock_book_list.begin(),next++,iter=next++;next!=dock_book_list.end();iter=next++)
355                 {
356                         Gtk::Paned* current(manage(is_horizontal?(Gtk::Paned*)new Gtk::HPaned:(Gtk::Paned*)new Gtk::VPaned));
357                         pannels_.push_back(current);
358                         
359                         if(pannels_.size()<=dock_book_sizes_.size())
360                                 pannels_.back()->set_position(dock_book_sizes_[pannels_.size()-1]);
361                         pannels_.back()->property_position().signal_changed().connect(
362                                 sigc::mem_fun(*this,&DockDialog::rebuild_sizes)
363                         );
364
365
366                         parent->add2(*current);
367
368                         current->add1(**iter);
369                         //(*iter)->show();
370                         //current->show();
371                         
372                         parent=current;
373                 }
374                 parent->add2(**iter);
375                 //(*iter)->show();
376         }
377         
378         box->show_all();
379         if(!composition_selector_)
380                 widget_comp_select->hide();
381         rebuild_sizes();
382 }
383
384 void
385 DockDialog::rebuild_sizes()
386 {
387         unsigned int i=0;
388         dock_book_sizes_.clear();
389         for(i=0;i<pannels_.size();i++)
390         {
391                 dock_book_sizes_.push_back(pannels_[i]->get_position());
392         }
393 }
394
395 void
396 DockDialog::set_dock_book_sizes(const std::vector<int>& new_sizes)
397 {
398         unsigned int i=0;
399         for(i=0;i<pannels_.size() && i<new_sizes.size();i++)
400         {
401                 pannels_[i]->set_position(new_sizes[i]);
402         }
403         dock_book_sizes_=new_sizes;
404         //rebuild_sizes();
405 }
406
407 void
408 DockDialog::refresh_accel_group()
409 {
410 /*
411         if(last_accel_group_)
412         {
413                 last_accel_group_->unlock();
414                 remove_accel_group(last_accel_group_);
415                 last_accel_group_=Glib::RefPtr<Gtk::AccelGroup>();
416         }
417         
418         etl::loose_handle<CanvasView> canvas_view(App::get_selected_canvas_view());
419         if(canvas_view)
420         {
421                 last_accel_group_=canvas_view->get_accel_group();
422                 last_accel_group_->lock();
423                 add_accel_group(last_accel_group_);
424         }
425 */
426         etl::loose_handle<CanvasView> canvas_view(App::get_selected_canvas_view());
427         if(canvas_view)
428         {
429                 canvas_view->mainmenu.accelerate(*this);
430         }
431 }
432
433 bool
434 DockDialog::close()
435 {
436         synfig::info("DockDialog::close(): DELETED!");
437         empty_sig.disconnect();
438         //get_dock_book().clear();
439         delete this;    
440         return true;
441 }
442
443 DockBook&
444 DockDialog::get_dock_book()
445 {
446         if(!last_dock_book)
447                 return *append_dock_book();
448         return *last_dock_book;
449 }
450
451 const DockBook&
452 DockDialog::get_dock_book()const
453 {
454         return *last_dock_book;
455 }
456
457
458 synfig::String
459 DockDialog::get_contents()const
460 {
461         synfig::String ret;
462
463         std::list<DockBook*>::const_iterator iter;
464         for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
465         {
466                 if(!ret.empty())
467                         ret+=is_horizontal?" | ":" - ";
468                 ret+=(*iter)->get_contents();
469         }
470                 
471         
472         return ret;
473 }
474
475 void
476 DockDialog::set_contents(const synfig::String& z)
477 {
478         int x,y;
479         get_size(x,y);
480
481         synfig::String str(z);
482         while(!str.empty())
483         {
484                 unsigned int separator=str.find_first_of('-');
485                 {
486                         unsigned int sep2=str.find_first_of('|');
487                         if(separator!=synfig::String::npos || sep2!=synfig::String::npos)
488                         {
489                                 if((separator==synfig::String::npos || sep2<separator) && sep2!=synfig::String::npos)
490                                 {
491                                         separator=sep2;
492                                         is_horizontal=true;
493                                 }
494                                 else
495                                         is_horizontal=false;
496                         }
497                 }
498                 
499                 synfig::String book_contents;
500                 if(separator==synfig::String::npos)
501                 {
502                         book_contents=str;
503                         str.clear();
504                 }
505                 else
506                 {
507                         book_contents=String(str.begin(),str.begin()+separator);
508                         str=String(str.begin()+separator+1,str.end());
509                 }
510                 
511                 try
512                 {
513                         append_dock_book()->set_contents(book_contents);
514                 }catch(...) { }
515         }
516
517         resize(x,y);
518 }
519
520 void
521 DockDialog::set_composition_selector(bool x)
522 {
523         if(x==get_composition_selector())
524                 return;
525         composition_selector_=x;
526         if(x)
527                 widget_comp_select->show();
528         else
529                 widget_comp_select->hide();
530 }
531
532 void
533 DockDialog::refresh_title()
534 {
535         if(is_deleting)return;
536         if(dock_book_list.size())
537         {
538                 synfig::String title;
539
540                 std::list<DockBook*>::const_iterator iter;
541                 for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
542                 {
543                         if(!title.empty())
544                                 title+=", ";
545                         title+=(*iter)->get_local_contents();
546                 }
547                 set_title(title);
548         }
549         else
550                 set_title(_("Empty Dock Dialog"));
551 }