--- /dev/null
+/* === S Y N F I G ========================================================= */
+/*! \file dockdialog.cpp
+** \brief Template File
+**
+** $Id$
+**
+** \legal
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** Copyright (c) 2007, 2008 Chris Moore
+**
+** This package is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License as
+** published by the Free Software Foundation; either version 2 of
+** the License, or (at your option) any later version.
+**
+** This package is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** General Public License for more details.
+** \endlegal
+*/
+/* ========================================================================= */
+
+/* === H E A D E R S ======================================================= */
+
+#ifdef USING_PCH
+# include "pch.h"
+#else
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "app.h"
+#include <sigc++/adaptors/hide.h>
+
+#include "dockdialog.h"
+#include "dockbook.h"
+#include "dockmanager.h"
+#include "toolbox.h"
+#include "widget_compselect.h"
+#include <synfig/general.h>
+#include <synfig/uniqueid.h>
+#include <gtkmm/table.h>
+#include <sigc++/hide.h>
+#include <sigc++/slot.h>
+#include <sigc++/retype_return.h>
+#include <sigc++/retype.h>
+#include "canvasview.h"
+#include <gtkmm/paned.h>
+#include <gtkmm/box.h>
+#include <synfigapp/main.h>
+
+#include "general.h"
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+using namespace etl;
+using namespace synfig;
+using namespace studio;
+
+/* === M A C R O S ========================================================= */
+
+#define GRAB_HINT_DATA(y,default) { \
+ String x; \
+ if(synfigapp::Main::settings().get_value(String("pref.")+y+"_hints",x)) \
+ { \
+ set_type_hint((Gdk::WindowTypeHint)atoi(x.c_str())); \
+ } else {\
+ set_type_hint(default); \
+ } \
+ }
+
+/* === G L O B A L S ======================================================= */
+
+/* === P R O C E D U R E S ================================================= */
+
+/* === M E T H O D S ======================================================= */
+
+DockDialog::DockDialog():
+ Gtk::Window(Gtk::WINDOW_TOPLEVEL)
+{
+ composition_selector_=false;
+ is_deleting=false;
+ is_horizontal=false;
+ last_dock_book=0;
+ box=0;
+
+ widget_comp_select=new Widget_CompSelect();
+
+ // Give ourselves an ID that is most likely unique
+ set_id(synfig::UniqueID().get_uid()^reinterpret_cast<long>(this));
+
+ set_role(strprintf("dock_dialog_%d",get_id()));
+ GRAB_HINT_DATA(
+ "dock_dialog",
+#ifdef __APPLE__
+ Gdk::WINDOW_TYPE_HINT_NORMAL
+#else
+ Gdk::WINDOW_TYPE_HINT_UTILITY
+#endif
+ );
+ set_keep_above(false);
+
+ //! \todo can we set dialog windows transient for all normal windows, not just the toolbox?
+ //! paragraph 3 of http://standards.freedesktop.org/wm-spec/1.3/ar01s07.html suggests we can
+ // this seems to have bad effects on KDE, so leave it disabled by default
+ if(getenv("SYNFIG_TRANSIENT_DIALOGS"))
+ set_transient_for(*App::toolbox);
+
+ // Set up the window
+ //set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
+ set_title(_("Dock Panel"));
+
+ // Register with the dock manager
+ App::dock_manager->dock_dialog_list_.push_back(this);
+
+
+ // connect our signals
+ signal_delete_event().connect(
+ sigc::hide(
+ sigc::mem_fun(*this,&DockDialog::close)
+ )
+ );
+
+/*
+ App::signal_canvas_view_focus().connect(
+ sigc::hide(
+ sigc::mem_fun(
+ *this,
+ &DockDialog::refresh_accel_group
+ )
+ )
+ );
+*/
+
+ add_accel_group(App::ui_manager()->get_accel_group());
+ App::signal_present_all().connect(sigc::mem_fun0(*this,&DockDialog::present));
+
+}
+
+DockDialog::~DockDialog()
+{
+ empty_sig.disconnect();
+
+ is_deleting=true;
+
+ // Remove all of the dock books
+ for(;!dock_book_list.empty();dock_book_list.pop_front())
+ {
+ dock_book_list.front()->clear();
+
+ //! \todo Fix this UGLY HACK
+ // The following line really should be uncommented,
+ // but it causes crashes. Without it, a small
+ // memory hole is created--but at least it doesn't crash
+ // delete dock_book_list.front();
+
+ // Oddly enough, the following line should
+ // theoretically do the same thing after this
+ // class is destroyed, but it doesn't seem to
+ // cause a crash. It does, however, trigger this warning:
+ //
+ // A floating object was finalized. This means that someone
+ // called g_object_unref() on an object that had only a
+ // floating reference; the initial floating reference is not
+ // owned by anyone and must be removed with g_object_ref_sink().
+ //
+ // manage(dock_book_list.front());
+ }
+
+ // Remove us from the dock manager
+ if(App::dock_manager)try{
+ std::list<DockDialog*>::iterator iter;
+ for(iter=App::dock_manager->dock_dialog_list_.begin();iter!=App::dock_manager->dock_dialog_list_.end();++iter)
+ if(*iter==this)
+ {
+ App::dock_manager->dock_dialog_list_.erase(iter);
+ break;
+ }
+ }
+ catch(...)
+ {
+ synfig::warning("DockDialog::~DockDialog(): Exception thrown when trying to remove from dock manager...?");
+ }
+
+ delete widget_comp_select;
+}
+
+void
+DockDialog::drop_on_prepend(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
+{
+ if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
+ {
+ Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
+ prepend_dock_book()->add(dockable);
+ context->drag_finish(true, false, time);
+ return;
+ }
+
+ context->drag_finish(false, false, time);
+}
+
+void
+DockDialog::drop_on_append(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
+{
+ if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
+ {
+ Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
+ append_dock_book()->add(dockable);
+ context->drag_finish(true, false, time);
+ return;
+ }
+
+ context->drag_finish(false, false, time);
+}
+
+
+void
+DockDialog::on_hide()
+{
+ Gtk::Window::on_hide();
+ close();
+}
+
+DockBook*
+DockDialog::prepend_dock_book()
+{
+ if(is_deleting)return 0;
+
+ dock_book_list.push_front(new DockBook);
+ last_dock_book=dock_book_list.front();
+
+
+ last_dock_book->signal_empty().connect(
+ sigc::bind(
+ sigc::mem_fun(*this,&DockDialog::erase_dock_book),
+ last_dock_book
+ )
+ );
+
+ dock_book_sizes_.insert(dock_book_sizes_.begin(),225);
+ refresh();
+ return last_dock_book;
+}
+
+DockBook*
+DockDialog::append_dock_book()
+{
+ if(is_deleting)return 0;
+
+ dock_book_list.push_back(new DockBook);
+ last_dock_book=dock_book_list.back();
+ last_dock_book->signal_empty().connect(
+ sigc::bind(
+ sigc::mem_fun(*this,&DockDialog::erase_dock_book),
+ last_dock_book
+ )
+ );
+ last_dock_book->signal_changed().connect(
+ sigc::mem_fun(*this,&DockDialog::refresh_title)
+ );
+ last_dock_book->signal_changed().connect(
+ sigc::mem_fun(*this,&DockDialog::refresh_title)
+ );
+ dock_book_sizes_.push_back(225);
+
+ //last_dock_book->show();
+ refresh();
+ return last_dock_book;
+}
+
+void
+DockDialog::erase_dock_book(DockBook* dock_book)
+{
+ if(is_deleting)return;
+
+ std::list<DockBook*>::iterator iter;
+ for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
+ if(*iter==dock_book)
+ {
+ dock_book_list.erase(iter);
+
+ if(dock_book_list.empty())
+ {
+ last_dock_book=0;
+ close();
+ return;
+ }
+ else
+ {
+ if(last_dock_book==dock_book)
+ last_dock_book=dock_book_list.front();
+ }
+
+ refresh();
+
+ return;
+ }
+}
+
+void
+DockDialog::refresh()
+{
+ // synfig::info("dock_book_list.size()=%d",dock_book_list.size());
+ //remove();
+
+ if(dock_book_list.empty())
+ return;
+
+ if(box)delete box;
+ box=(manage(is_horizontal?(Gtk::Box*)new Gtk::HBox:(Gtk::Box*)new Gtk::VBox));
+ add(*box);
+
+ box->pack_start(*widget_comp_select,false,true);
+
+ Gtk::Button* append_button(manage(new Gtk::Button));
+ Gtk::Button* prepend_button(manage(new Gtk::Button));
+
+ std::list<Gtk::TargetEntry> listTargets;
+ listTargets.push_back( Gtk::TargetEntry("DOCK") );
+
+ append_button->drag_dest_set(listTargets);
+ prepend_button->drag_dest_set(listTargets);
+
+ append_button->signal_drag_data_received().connect(
+ sigc::mem_fun(*this,&DockDialog::drop_on_append)
+ );
+
+ prepend_button->signal_drag_data_received().connect(
+ sigc::mem_fun(*this,&DockDialog::drop_on_prepend)
+ );
+
+ box->pack_start(*prepend_button,false,true);
+ box->pack_end(*append_button,false,true);
+
+ //prepend_button->show();
+ //append_button->show();
+ panels_.clear();
+
+ if(dock_book_list.size()==1)
+ {
+ box->pack_start(get_dock_book(),true,true);
+ }
+ else
+ {
+ Gtk::Paned* parent(manage(is_horizontal?(Gtk::Paned*)new Gtk::HPaned:(Gtk::Paned*)new Gtk::VPaned));
+
+ panels_.push_back(parent);
+
+ if(panels_.size()<=dock_book_sizes_.size())
+ panels_.back()->set_position(dock_book_sizes_[panels_.size()-1]);
+ panels_.back()->property_position().signal_changed().connect(
+ sigc::mem_fun(*this,&DockDialog::rebuild_sizes)
+ );
+ //parent->show();
+ parent->add1(*dock_book_list.front());
+ //dock_book_list.front()->show();
+
+ box->pack_start(*parent,true,true);
+
+ std::list<DockBook*>::iterator iter,next;
+ for(next=dock_book_list.begin(),next++,iter=next++;next!=dock_book_list.end();iter=next++)
+ {
+ Gtk::Paned* current(manage(is_horizontal?(Gtk::Paned*)new Gtk::HPaned:(Gtk::Paned*)new Gtk::VPaned));
+ panels_.push_back(current);
+
+ if(panels_.size()<=dock_book_sizes_.size())
+ panels_.back()->set_position(dock_book_sizes_[panels_.size()-1]);
+ panels_.back()->property_position().signal_changed().connect(
+ sigc::mem_fun(*this,&DockDialog::rebuild_sizes)
+ );
+
+
+ parent->add2(*current);
+
+ current->add1(**iter);
+ //(*iter)->show();
+ //current->show();
+
+ parent=current;
+ }
+ parent->add2(**iter);
+ //(*iter)->show();
+ }
+
+ box->show_all();
+ if(!composition_selector_)
+ widget_comp_select->hide();
+ rebuild_sizes();
+}
+
+void
+DockDialog::rebuild_sizes()
+{
+ unsigned int i=0;
+ dock_book_sizes_.clear();
+ for(i=0;i<panels_.size();i++)
+ {
+ dock_book_sizes_.push_back(panels_[i]->get_position());
+ }
+}
+
+void
+DockDialog::set_dock_book_sizes(const std::vector<int>& new_sizes)
+{
+ unsigned int i=0;
+ for(i=0;i<panels_.size() && i<new_sizes.size();i++)
+ {
+ panels_[i]->set_position(new_sizes[i]);
+ }
+ dock_book_sizes_=new_sizes;
+ //rebuild_sizes();
+}
+
+void
+DockDialog::refresh_accel_group()
+{
+/*
+ if(last_accel_group_)
+ {
+ last_accel_group_->unlock();
+ remove_accel_group(last_accel_group_);
+ last_accel_group_=Glib::RefPtr<Gtk::AccelGroup>();
+ }
+
+ etl::loose_handle<CanvasView> canvas_view(App::get_selected_canvas_view());
+ if(canvas_view)
+ {
+ last_accel_group_=canvas_view->get_accel_group();
+ last_accel_group_->lock();
+ add_accel_group(last_accel_group_);
+ }
+*/
+ etl::loose_handle<CanvasView> canvas_view(App::get_selected_canvas_view());
+ if(canvas_view)
+ {
+ canvas_view->mainmenu.accelerate(*this);
+ }
+}
+
+bool
+DockDialog::close()
+{
+ if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
+ synfig::info("DockDialog::close(): Deleted");
+
+ empty_sig.disconnect();
+ //get_dock_book().clear();
+ delete this;
+ return true;
+}
+
+DockBook&
+DockDialog::get_dock_book()
+{
+ if(!last_dock_book)
+ return *append_dock_book();
+ return *last_dock_book;
+}
+
+const DockBook&
+DockDialog::get_dock_book()const
+{
+ return *last_dock_book;
+}
+
+
+synfig::String
+DockDialog::get_contents()const
+{
+ synfig::String ret;
+
+ std::list<DockBook*>::const_iterator iter;
+ for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
+ {
+ if(!ret.empty())
+ ret+=is_horizontal?" | ":" - ";
+ ret+=(*iter)->get_contents();
+ }
+
+
+ return ret;
+}
+
+void
+DockDialog::set_contents(const synfig::String& z)
+{
+ int x,y;
+ get_size(x,y);
+
+ synfig::String str(z);
+ while(!str.empty())
+ {
+ synfig::String::size_type separator=str.find_first_of('-');
+ {
+ synfig::String::size_type sep2=str.find_first_of('|');
+ if(separator!=synfig::String::npos || sep2!=synfig::String::npos)
+ {
+ if((separator==synfig::String::npos || sep2<separator) && sep2!=synfig::String::npos)
+ {
+ separator=sep2;
+ is_horizontal=true;
+ }
+ else
+ is_horizontal=false;
+ }
+ }
+
+ synfig::String book_contents;
+ if(separator==synfig::String::npos)
+ {
+ book_contents=str;
+ str.clear();
+ }
+ else
+ {
+ book_contents=String(str.begin(),str.begin()+separator);
+ str=String(str.begin()+separator+1,str.end());
+ }
+
+ try
+ {
+ append_dock_book()->set_contents(book_contents);
+ }catch(...) { }
+ }
+
+ resize(x,y);
+}
+
+void
+DockDialog::set_composition_selector(bool x)
+{
+ if(x==get_composition_selector())
+ return;
+ composition_selector_=x;
+ if(x)
+ widget_comp_select->show();
+ else
+ widget_comp_select->hide();
+}
+
+void
+DockDialog::refresh_title()
+{
+ if(is_deleting)return;
+ if(dock_book_list.size())
+ {
+ synfig::String title;
+
+ std::list<DockBook*>::const_iterator iter;
+ for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
+ {
+ if(!title.empty())
+ title+=", ";
+ title+=(*iter)->get_local_contents();
+ }
+ set_title(title);
+ }
+ else
+ set_title(_("Empty Dock Panel"));
+}