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