summaryrefslogtreecommitdiffstats
path: root/src/ui/widget
diff options
context:
space:
mode:
authorgustav_b <gustav_b@users.sourceforge.net>2007-08-29 21:27:07 +0000
committergustav_b <gustav_b@users.sourceforge.net>2007-08-29 21:27:07 +0000
commit731f2b5adbb6f9e9fc853a6506c695fd2fcec320 (patch)
tree6e7775c500ffc41d1376d7496c9334840b0f065f /src/ui/widget
parentDon't snap node handles to the parent path, plus a small string change (diff)
downloadinkscape-731f2b5adbb6f9e9fc853a6506c695fd2fcec320.tar.gz
inkscape-731f2b5adbb6f9e9fc853a6506c695fd2fcec320.zip
Dockable dialogs patch applied
(https://sourceforge.net/tracker/?func=detail&atid=604308&aid=1688508&group_id=93438) (bzr r3613)
Diffstat (limited to 'src/ui/widget')
-rw-r--r--src/ui/widget/Makefile_insert4
-rw-r--r--src/ui/widget/dock-item.cpp539
-rw-r--r--src/ui/widget/dock-item.h165
-rw-r--r--src/ui/widget/dock.cpp235
-rw-r--r--src/ui/widget/dock.h97
5 files changed, 1040 insertions, 0 deletions
diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert
index 178e954a4..7113857c8 100644
--- a/src/ui/widget/Makefile_insert
+++ b/src/ui/widget/Makefile_insert
@@ -15,6 +15,10 @@ ui_widget_libuiwidget_a_SOURCES = \
ui/widget/combo-enums.h \
ui/widget/combo-text.cpp \
ui/widget/combo-text.h \
+ ui/widget/dock.h \
+ ui/widget/dock.cpp \
+ ui/widget/dock-item.h \
+ ui/widget/dock-item.cpp \
ui/widget/entity-entry.cpp \
ui/widget/entity-entry.h \
ui/widget/entry.cpp \
diff --git a/src/ui/widget/dock-item.cpp b/src/ui/widget/dock-item.cpp
new file mode 100644
index 000000000..1e232cb4e
--- /dev/null
+++ b/src/ui/widget/dock-item.cpp
@@ -0,0 +1,539 @@
+/**
+ * \brief A custom Inkscape wrapper around gdl_dock_item
+ *
+ * Author:
+ * Gustav Broberg <broberg@kth.se>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#include "dock-item.h"
+#include "desktop.h"
+#include "inkscape.h"
+#include "ui/widget/dock.h"
+#include "widgets/icon.h"
+
+#include <gtk/gtk.h>
+
+#include <gtkmm/invisible.h>
+#include <gtkmm/stock.h>
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& long_name,
+ const Glib::ustring& icon_name, State state) :
+ _dock (dock),
+ _prev_state (state),
+ _window (NULL),
+ _dock_item_action_area (NULL)
+{
+ /* Add a "signal_response" signal to the GdlDockItem, make sure it is
+ * only done once for the class.
+ */
+ static guint response_signal = 0;
+
+ if (response_signal == 0) {
+ response_signal = g_signal_new ("signal_response",
+ GDL_TYPE_DOCK_ITEM,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ }
+
+
+ if (!icon_name.empty()) {
+ Gtk::Widget *icon = sp_icon_get_icon(icon_name, Inkscape::ICON_SIZE_MENU);
+ if (icon) {
+ // check icon type (inkscape, gtk, none)
+ if ( SP_IS_ICON(icon->gobj()) ) {
+ SPIcon* sp_icon = SP_ICON(icon->gobj());
+ sp_icon_fetch_pixbuf(sp_icon);
+ _icon_pixbuf = Glib::wrap(sp_icon->pb, true);
+ } else if ( GTK_IS_IMAGE(icon->gobj()) ) {
+ _icon_pixbuf = Gtk::Invisible().render_icon(Gtk::StockID(icon_name),
+ Gtk::ICON_SIZE_MENU);
+ }
+ delete icon;
+
+ _gdl_dock_item =
+ gdl_dock_item_new_with_pixbuf_icon(name.c_str(), long_name.c_str(), _icon_pixbuf->gobj(),
+ GDL_DOCK_ITEM_BEH_NORMAL);
+ }
+ } else {
+ _gdl_dock_item =
+ gdl_dock_item_new(name.c_str(), long_name.c_str(), GDL_DOCK_ITEM_BEH_NORMAL);
+ }
+
+ _frame.set_shadow_type(Gtk::SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (_gdl_dock_item), GTK_WIDGET (_frame.gobj()));
+ _frame.add(_dock_item_box);
+ _dock_item_box.set_border_width(3);
+
+ signal_drag_begin().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragBegin));
+ signal_drag_end().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDragEnd));
+ signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHide), false);
+ signal_show().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onShow), false);
+ signal_state_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onStateChanged));
+ signal_delete_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onDeleteEvent));
+
+ _dock.addItem(*this, (_prev_state == FLOATING_STATE ? FLOATING : TOP));
+
+ show_all();
+}
+
+DockItem::~DockItem()
+{
+ g_free(_gdl_dock_item);
+}
+
+Gtk::Widget&
+DockItem::getWidget()
+{
+ return *Glib::wrap(GTK_WIDGET(_gdl_dock_item));
+}
+
+GtkWidget *
+DockItem::gobj()
+{
+ return _gdl_dock_item;
+}
+
+Gtk::VBox *
+DockItem::get_vbox()
+{
+ return &_dock_item_box;
+}
+
+
+bool
+DockItem::isAttached() const
+{
+ return GDL_DOCK_OBJECT_ATTACHED (_gdl_dock_item);
+}
+
+
+bool
+DockItem::isFloating() const
+{
+ gboolean floating = FALSE;
+ if (GDL_IS_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (_gdl_dock_item)))) {
+ GdlDock* dock = GDL_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (_gdl_dock_item)));
+ g_object_get (dock,
+ "floating", &floating,
+ NULL);
+ }
+ return floating;
+}
+
+bool
+DockItem::isIconified() const
+{
+ return GDL_DOCK_ITEM_ICONIFIED (_gdl_dock_item);
+}
+
+DockItem::State
+DockItem::getState() const
+{
+ return (isAttached() ? (isFloating() ? FLOATING_STATE : DOCKED_STATE) : UNATTACHED);
+}
+
+DockItem::State
+DockItem::getPrevState() const
+{
+ return _prev_state;
+}
+
+DockItem::Placement
+DockItem::getPlacement() const
+{
+ GdlDockPlacement placement = (GdlDockPlacement)NONE;
+ gdl_dock_object_child_placement(gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT(_gdl_dock_item)),
+ GDL_DOCK_OBJECT(_gdl_dock_item),
+ &placement);
+ return (Placement)placement;
+}
+
+
+void
+DockItem::addButton(Gtk::Button* button, int response_id)
+{
+ // Create a button box for the response buttons if it's the first button to be added
+ if (!_dock_item_action_area) {
+ _dock_item_action_area = new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 6);
+ _dock_item_box.pack_end(*_dock_item_action_area, Gtk::PACK_SHRINK, 0);
+ _dock_item_action_area->set_border_width(6);
+ }
+
+ _dock_item_action_area->pack_start(*button);
+}
+
+void
+DockItem::hide()
+{
+ gdl_dock_item_hide_item (GDL_DOCK_ITEM(_gdl_dock_item));
+}
+
+void
+DockItem::show()
+{
+ gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
+}
+
+void
+DockItem::show_all()
+{
+ gtk_widget_show_all(_gdl_dock_item);
+}
+
+void
+DockItem::present()
+{
+ // iconified
+ if (isIconified()) {
+ show();
+ return;
+ }
+
+ // unattached
+ if (!isAttached()) {
+ gdl_dock_item_show_item (GDL_DOCK_ITEM(_gdl_dock_item));
+ return;
+ }
+
+ // tabbed
+ if (getPlacement() == CENTER) {
+ int i = gtk_notebook_page_num (GTK_NOTEBOOK (_gdl_dock_item->parent),
+ GTK_WIDGET (_gdl_dock_item));
+ if (i >= 0)
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (_gdl_dock_item->parent), i);
+ return;
+ }
+
+ // we're already present, do nothing
+}
+
+
+void
+DockItem::get_position(int& x, int& y)
+{
+ if (_getWindow()) {
+ _getWindow()->get_position(x, y);
+ } else {
+ x = _x;
+ y = _y;
+ }
+}
+
+void
+DockItem::get_size(int& width, int& height)
+{
+ if (_window) {
+ _window->get_size(width, height);
+ } else {
+ width = get_vbox()->get_width();
+ height = get_vbox()->get_height();
+ }
+}
+
+
+void
+DockItem::resize(int width, int height)
+{
+ if (_window)
+ _window->resize(width, height);
+}
+
+
+void
+DockItem::move(int x, int y)
+{
+ if (_window)
+ _window->move(x, y);
+}
+
+void
+DockItem::set_position(Gtk::WindowPosition position)
+{
+ if (_window)
+ _window->set_position(position);
+}
+
+void
+DockItem::set_size_request(int width, int height)
+{
+ getWidget().set_size_request(width, height);
+}
+
+void
+DockItem::size_request(Gtk::Requisition& requisition)
+{
+ getWidget().size_request(requisition);
+}
+
+
+void
+DockItem::set_title(Glib::ustring title)
+{
+ g_object_set (_gdl_dock_item,
+ "long-name", title.c_str(),
+ NULL);
+
+ gdl_dock_item_set_tablabel(GDL_DOCK_ITEM(_gdl_dock_item),
+ gtk_label_new (title.c_str()));
+}
+
+/* Signal wrappers */
+
+Glib::SignalProxy0<void>
+DockItem::signal_show()
+{
+ return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+ &_signal_show_proxy);
+}
+
+Glib::SignalProxy0<void>
+DockItem::signal_hide()
+{
+ return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+ &_signal_hide_proxy);
+}
+
+Glib::SignalProxy1<bool, GdkEventAny *>
+DockItem::signal_delete_event()
+{
+ return Glib::SignalProxy1<bool, GdkEventAny *>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+ &_signal_delete_event_proxy);
+}
+
+Glib::SignalProxy1<void, int>
+DockItem::signal_response()
+{
+ return Glib::SignalProxy1<void, int>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+ &_signal_response_proxy);
+}
+
+Glib::SignalProxy0<void>
+DockItem::signal_drag_begin()
+{
+ return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+ &_signal_drag_begin_proxy);
+}
+
+Glib::SignalProxy1<void, bool>
+DockItem::signal_drag_end()
+{
+ return Glib::SignalProxy1<void, bool>(Glib::wrap(GTK_WIDGET(_gdl_dock_item)),
+ &_signal_drag_end_proxy);
+}
+
+sigc::signal<void, DockItem::State, DockItem::State>
+DockItem::signal_state_changed()
+{
+ return _signal_state_changed;
+}
+
+void
+DockItem::_onHideWindow()
+{
+ if (_window)
+ _window->get_position(_x, _y);
+}
+
+void
+DockItem::_onHide()
+{
+ _signal_state_changed.emit(UNATTACHED, getState());
+}
+
+void
+DockItem::_onShow()
+{
+ _signal_state_changed.emit(UNATTACHED, getState());
+}
+
+void
+DockItem::_onDragBegin()
+{
+ _prev_state = getState();
+ if (_prev_state == FLOATING_STATE)
+ _dock.toggleDockable(getWidget().get_width(), getWidget().get_height());
+}
+
+void
+DockItem::_onDragEnd(bool)
+{
+ State state = getState();
+
+ if (state != _prev_state)
+ _signal_state_changed.emit(_prev_state, state);
+
+ if (state == FLOATING_STATE) {
+ if (_prev_state == FLOATING_STATE)
+ _dock.toggleDockable();
+ }
+
+ _prev_state = state;
+}
+
+bool
+DockItem::_onKeyPress(GdkEventKey *event)
+{
+ gboolean return_value;
+ g_signal_emit_by_name (_gdl_dock_item, "key_press_event", event, &return_value);
+ return return_value;
+}
+
+void
+DockItem::_onStateChanged(State prev_state, State new_state)
+{
+ _window = _getWindow();
+
+ if (new_state == FLOATING_STATE) {
+ _window->signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHideWindow));
+ _signal_key_press_event_connection =
+ _window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onKeyPress));
+ }
+}
+
+
+bool
+DockItem::_onDeleteEvent(GdkEventAny *event)
+{
+ hide();
+ return false;
+}
+
+
+Gtk::Window *
+DockItem::_getWindow()
+{
+ g_return_val_if_fail(_gdl_dock_item, 0);
+ Gtk::Container *parent = getWidget().get_parent();
+ parent = (parent ? parent->get_parent() : 0);
+ return (parent ? dynamic_cast<Gtk::Window *>(parent) : 0);
+}
+
+const Glib::SignalProxyInfo
+DockItem::_signal_show_proxy =
+{
+ "show",
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
+};
+
+const Glib::SignalProxyInfo
+DockItem::_signal_hide_proxy =
+{
+ "hide",
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
+};
+
+
+const Glib::SignalProxyInfo
+DockItem::_signal_delete_event_proxy =
+{
+ "delete_event",
+ (GCallback) &_signal_delete_event_callback,
+ (GCallback) &_signal_delete_event_callback
+};
+
+
+const Glib::SignalProxyInfo
+DockItem::_signal_response_proxy =
+{
+ "signal_response",
+ (GCallback) &_signal_response_callback,
+ (GCallback) &_signal_response_callback
+};
+
+const Glib::SignalProxyInfo
+DockItem::_signal_drag_begin_proxy =
+{
+ "dock-drag-begin",
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
+};
+
+
+const Glib::SignalProxyInfo
+DockItem::_signal_drag_end_proxy =
+{
+ "dock_drag_end",
+ (GCallback) &_signal_drag_end_callback,
+ (GCallback) &_signal_drag_end_callback
+};
+
+
+gboolean
+DockItem::_signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data)
+{
+ using namespace Gtk;
+ typedef sigc::slot<bool, GdkEventAny *> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
+ try {
+ if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
+ return static_cast<int>( (*static_cast<SlotType*>(slot))(event) );
+ } catch(...) {
+ Glib::exception_handlers_invoke();
+ }
+ }
+
+ typedef gboolean RType;
+ return RType();
+}
+
+void
+DockItem::_signal_response_callback(GtkWidget *self, gint response_id, void *data)
+{
+ using namespace Gtk;
+ typedef sigc::slot<void, int> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
+ try {
+ if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
+ (*static_cast<SlotType *>(slot))(response_id);
+ } catch(...) {
+ Glib::exception_handlers_invoke();
+ }
+ }
+}
+
+void
+DockItem::_signal_drag_end_callback(GtkWidget *self, gboolean cancelled, void *data)
+{
+ using namespace Gtk;
+ typedef sigc::slot<void, bool> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *) self)) {
+ try {
+ if(sigc::slot_base *const slot = Glib::SignalProxyNormal::data_to_slot(data))
+ (*static_cast<SlotType *>(slot))(cancelled);
+ } catch(...) {
+ Glib::exception_handlers_invoke();
+ }
+ }
+}
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/dock-item.h b/src/ui/widget/dock-item.h
new file mode 100644
index 000000000..38d13a579
--- /dev/null
+++ b/src/ui/widget/dock-item.h
@@ -0,0 +1,165 @@
+/**
+ * \brief A custom wrapper around gdl-dock-item
+ *
+ * Author:
+ * Gustav Broberg <broberg@kth.se>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+
+#ifndef INKSCAPE_UI_WIGET_DOCK_ITEM_H
+#define INKSCAPE_UI_WIGET_DOCK_ITEM_H
+
+#include <gtkmm/button.h>
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/paned.h>
+#include <gtkmm/window.h>
+
+#include "libgdl/libgdl.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class Dock;
+
+class DockItem {
+
+public:
+
+ enum State { UNATTACHED, FLOATING_STATE, DOCKED_STATE };
+
+ enum Placement {
+ NONE = GDL_DOCK_NONE,
+ TOP = GDL_DOCK_TOP,
+ BOTTOM = GDL_DOCK_BOTTOM,
+ RIGHT = GDL_DOCK_RIGHT,
+ LEFT = GDL_DOCK_LEFT,
+ CENTER = GDL_DOCK_CENTER,
+ FLOATING = GDL_DOCK_FLOATING
+ };
+
+ DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& long_name,
+ const Glib::ustring& icon_name, State state);
+
+ ~DockItem();
+
+ Gtk::Widget& getWidget();
+ GtkWidget *gobj();
+
+ Gtk::VBox *get_vbox();
+
+ void get_position(int& x, int& y);
+ void get_size(int& width, int& height);
+
+ void resize(int width, int height);
+ void move(int x, int y);
+ void set_position(Gtk::WindowPosition);
+ void set_size_request(int width, int height);
+ void size_request(Gtk::Requisition& requisition);
+ void set_title(Glib::ustring title);
+
+ bool isAttached() const;
+ bool isFloating() const;
+ bool isIconified() const;
+ State getState() const;
+ State getPrevState() const;
+ Placement getPlacement() const;
+
+ void addButton(Gtk::Button *button, int response_id);
+
+ void hide();
+ void show();
+ void show_all();
+
+ void present();
+
+ Glib::SignalProxy0<void> signal_show();
+ Glib::SignalProxy0<void> signal_hide();
+ Glib::SignalProxy1<bool, GdkEventAny *> signal_delete_event();
+ Glib::SignalProxy1<void, int> signal_response();
+ Glib::SignalProxy0<void> signal_drag_begin();
+ Glib::SignalProxy1<void, bool> signal_drag_end();
+
+ sigc::signal<void, State, State> signal_state_changed();
+
+private:
+ Dock &_dock; //< parent dock
+
+ State _prev_state; //< last known state
+
+ int _prev_position;
+
+ Gtk::Window *_window; //< reference to floating window, if any
+ int _x, _y; //< last known position of window, if floating
+
+ GtkWidget *_gdl_dock_item;
+ Glib::RefPtr<Gdk::Pixbuf> _icon_pixbuf;
+
+ /** Interface widgets, will be packed like
+ * gdl_dock_item -> _frame -> _dock_item_box -> (_dock_item_action_area)
+ */
+ Gtk::Frame _frame;
+ Gtk::VBox _dock_item_box;
+ Gtk::HButtonBox *_dock_item_action_area;
+
+ /** Internal signal handlers */
+ void _onHide();
+ void _onHideWindow();
+ void _onShow();
+ void _onResponse(int response_id);
+ void _onDragBegin();
+ void _onDragEnd(bool cancelled);
+ bool _onKeyPress(GdkEventKey *event);
+ void _onStateChanged(State prev_state, State new_state);
+ bool _onDeleteEvent(GdkEventAny *event);
+
+ void _onFoo();
+
+ sigc::connection _signal_key_press_event_connection;
+
+ /** GdlDockItem signal proxy structures */
+ static const Glib::SignalProxyInfo _signal_show_proxy;
+ static const Glib::SignalProxyInfo _signal_hide_proxy;
+ static const Glib::SignalProxyInfo _signal_delete_event_proxy;
+ static const Glib::SignalProxyInfo _signal_response_proxy;
+ static const Glib::SignalProxyInfo _signal_drag_begin_proxy;
+ static const Glib::SignalProxyInfo _signal_drag_end_proxy;
+
+ static gboolean _signal_delete_event_callback(GtkWidget *self, GdkEventAny *event, void *data);
+ static void _signal_drag_end_callback(GtkWidget* self, gboolean p0, void* data);
+
+ /** Internal helpers */
+ Gtk::Window *_getWindow(); //< gives the parent window, if the dock item has one (i.e. it's floating)
+
+ /** In order to emulate a signal_response signal like the one for Gtk::Dialog we inject a new
+ * signal into GdlDockItem. This signal will be emitted when a button in the dock item added
+ * through the addButton(..., response_id) method, is clicked.
+ */
+ static void _signal_response_callback(GtkWidget* self, gint p0, void* data);
+
+ sigc::signal<void, State, State> _signal_state_changed;
+
+ DockItem();
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif // INKSCAPE_UI_WIGET_DOCK_ITEM_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/dock.cpp b/src/ui/widget/dock.cpp
new file mode 100644
index 000000000..828b70451
--- /dev/null
+++ b/src/ui/widget/dock.cpp
@@ -0,0 +1,235 @@
+/**
+ * \brief A desktop dock pane to dock dialogs.
+ *
+ * Author:
+ * Gustav Broberg <broberg@kth.se>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#include "inkscape.h"
+#include "desktop.h"
+
+#include "dock.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+namespace {
+
+void hideCallback(GtkObject *object, gpointer dock_ptr)
+{
+ g_return_if_fail( dock_ptr != NULL );
+
+ Dock *dock = (Dock *)dock_ptr;
+ dock->hide();
+}
+
+void unhideCallback(GtkObject *object, gpointer dock_ptr)
+{
+ g_return_if_fail( dock_ptr != NULL );
+
+ Dock *dock = (Dock *)dock_ptr;
+ dock->show();
+}
+
+}
+
+const int Dock::_default_empty_width = 0;
+const int Dock::_default_dock_bar_width = 36;
+
+
+Dock::Dock(Gtk::Orientation orientation)
+ : _gdl_dock (GDL_DOCK (gdl_dock_new())),
+ _gdl_dock_bar (GDL_DOCK_BAR (gdl_dock_bar_new(GDL_DOCK(_gdl_dock)))),
+ _scrolled_window (Gtk::manage(new Gtk::ScrolledWindow))
+{
+ gdl_dock_bar_set_orientation(_gdl_dock_bar, static_cast<GtkOrientation>(orientation));
+
+ switch (orientation) {
+ case Gtk::ORIENTATION_VERTICAL:
+ _dock_box = Gtk::manage(new Gtk::HBox());
+ _paned = Gtk::manage(new Gtk::VPaned());
+ break;
+ case Gtk::ORIENTATION_HORIZONTAL:
+ _dock_box = Gtk::manage(new Gtk::VBox());
+ _paned = Gtk::manage(new Gtk::HPaned());
+ }
+
+ _scrolled_window->add(*_dock_box);
+ _scrolled_window->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+
+ _paned->pack1(*Glib::wrap(GTK_WIDGET(_gdl_dock)), false, false);
+ _paned->pack2(_filler, true, false);
+
+ _dock_box->pack_start(*_paned, Gtk::PACK_EXPAND_WIDGET);
+ _dock_box->pack_end(*Gtk::manage(Glib::wrap(GTK_WIDGET(_gdl_dock_bar))), Gtk::PACK_SHRINK);
+ _dock_box->get_parent()->set_resize_mode(Gtk::RESIZE_PARENT);
+
+ _scrolled_window->set_size_request(0);
+
+ g_object_set (GDL_DOCK_OBJECT(_gdl_dock)->master,
+ "switcher-style", GDL_SWITCHER_STYLE_BOTH,
+ NULL);
+
+ g_signal_connect(G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(hideCallback), (void *)this);
+ g_signal_connect(G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(unhideCallback), (void *)this);
+
+ signal_layout_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::Dock::_onLayoutChanged));
+}
+
+Dock::~Dock()
+{
+ g_free(_gdl_dock);
+ g_free(_gdl_dock_bar);
+}
+
+void
+Dock::addItem(DockItem& item, DockItem::Placement placement)
+{
+ _dock_items.push_back(&item);
+ gdl_dock_add_item(_gdl_dock, GDL_DOCK_ITEM(item.gobj()), (GdlDockPlacement)placement);
+
+ // FIXME: This is a hack to prevent the dock from expanding the main window, this can't be done
+ // initially as the paned doesn't exist.
+ if (Gtk::Paned *paned = getParentPaned())
+ paned->set_resize_mode(Gtk::RESIZE_QUEUE);
+}
+
+Gtk::Widget&
+Dock::getWidget()
+{
+ return *_scrolled_window;
+}
+
+Gtk::Paned *
+Dock::getParentPaned()
+{
+ g_return_val_if_fail(_dock_box, 0);
+ Gtk::Container *parent = getWidget().get_parent();
+ return (parent != 0 ? dynamic_cast<Gtk::Paned *>(parent) : 0);
+}
+
+
+Gtk::Paned *
+Dock::getPaned()
+{
+ return _paned;
+}
+
+
+bool
+Dock::isEmpty() const
+{
+ std::list<const DockItem *>::const_iterator
+ i = _dock_items.begin(),
+ e = _dock_items.end();
+
+ for (; i != e; ++i)
+ if ((*i)->getState() == DockItem::DOCKED_STATE)
+ return false;
+
+ return true;
+}
+
+bool
+Dock::hasIconifiedItems() const
+{
+ std::list<const DockItem *>::const_iterator
+ i = _dock_items.begin(),
+ e = _dock_items.end();
+
+ for (; i != e; ++i)
+ if ((*i)->isIconified())
+ return true;
+
+ return false;
+}
+
+void
+Dock::hide()
+{
+ getWidget().hide();
+}
+
+void
+Dock::show()
+{
+ getWidget().show();
+}
+
+void
+Dock::toggleDockable(int width, int height)
+{
+ static int prev_horizontal_position, prev_vertical_position;
+
+ Gtk::Paned *parent_paned = getParentPaned();
+
+ if (width > 0 && height > 0) {
+ prev_horizontal_position = parent_paned->get_position();
+ prev_vertical_position = _paned->get_position();
+
+ if (getWidget().get_width() < width)
+ parent_paned->set_position(parent_paned->get_width() - width);
+
+ if (_paned->get_position() < height)
+ _paned->set_position(height);
+
+ } else {
+ parent_paned->set_position(prev_horizontal_position);
+ _paned->set_position(prev_vertical_position);
+ }
+
+}
+
+Glib::SignalProxy0<void>
+Dock::signal_layout_changed()
+{
+ return Glib::SignalProxy0<void>(Glib::wrap(GTK_WIDGET(_gdl_dock)),
+ &_signal_layout_changed_proxy);
+}
+
+void
+Dock::_onLayoutChanged()
+{
+ if (isEmpty()) {
+
+ if (hasIconifiedItems())
+ _scrolled_window->set_size_request(_default_dock_bar_width);
+ else
+ _scrolled_window->set_size_request(_default_empty_width);
+
+ getParentPaned()->set_position(INT_MAX);
+ } else {
+ _scrolled_window->set_size_request(-1);
+ }
+}
+
+
+const Glib::SignalProxyInfo
+Dock::_signal_layout_changed_proxy =
+{
+ "layout-changed",
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback,
+ (GCallback) &Glib::SignalProxyNormal::slot0_void_callback
+};
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99
diff --git a/src/ui/widget/dock.h b/src/ui/widget/dock.h
new file mode 100644
index 000000000..be0c4ef1d
--- /dev/null
+++ b/src/ui/widget/dock.h
@@ -0,0 +1,97 @@
+/**
+ * \brief A desktop dock pane to dock dialogs, a custom wrapper around gdl-dock.
+ *
+ * Author:
+ * Gustav Broberg <broberg@kth.se>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_WIDGET_DOCK_H
+#define INKSCAPE_UI_WIDGET_DOCK_H
+
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/box.h>
+#include <gtkmm/paned.h>
+
+#include <list>
+
+#include "ui/widget/dock-item.h"
+
+#include "libgdl/libgdl.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class Dock {
+
+public:
+
+ Dock(Gtk::Orientation orientation=Gtk::ORIENTATION_VERTICAL);
+ ~Dock();
+
+ void addItem(DockItem& item, DockItem::Placement placement);
+
+ Gtk::Widget& getWidget(); //< return the top widget
+ Gtk::Paned *getParentPaned();
+
+ Gtk::Paned *getPaned();
+
+ bool isEmpty() const; //< true iff none of the dock's items are in state != UNATTACHED
+ bool hasIconifiedItems() const;
+
+ Glib::SignalProxy0<void> signal_layout_changed();
+
+ void hide();
+ void show();
+
+ /** Toggle size of dock between the previous dimensions and the ones sent as parameters */
+ void toggleDockable(int width=0, int height=0);
+
+protected:
+
+ std::list<const DockItem *> _dock_items; //< added dock items
+
+ /** Interface widgets, will be packed like
+ * _scrolled_window -> (_dock_box -> (_paned -> (_dock -> _filler) | _dock_bar))
+ */
+ Gtk::Box *_dock_box;
+ Gtk::Paned* _paned;
+ GdlDock *_gdl_dock;
+ GdlDockBar *_gdl_dock_bar;
+ Gtk::VBox _filler;
+ Gtk::ScrolledWindow *_scrolled_window;
+
+ /** Internal signal handlers */
+ void _onLayoutChanged();
+
+ void _onFoo();
+
+ /** GdlDock signal proxy structures */
+ static const Glib::SignalProxyInfo _signal_layout_changed_proxy;
+
+ /** Standard widths */
+ static const int _default_empty_width;
+ static const int _default_dock_bar_width;
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif //INKSCAPE_UI_DIALOG_BEHAVIOUR_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99
+