diff options
| author | gustav_b <gustav_b@users.sourceforge.net> | 2007-08-29 21:27:07 +0000 |
|---|---|---|
| committer | gustav_b <gustav_b@users.sourceforge.net> | 2007-08-29 21:27:07 +0000 |
| commit | 731f2b5adbb6f9e9fc853a6506c695fd2fcec320 (patch) | |
| tree | 6e7775c500ffc41d1376d7496c9334840b0f065f /src/ui/widget | |
| parent | Don't snap node handles to the parent path, plus a small string change (diff) | |
| download | inkscape-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_insert | 4 | ||||
| -rw-r--r-- | src/ui/widget/dock-item.cpp | 539 | ||||
| -rw-r--r-- | src/ui/widget/dock-item.h | 165 | ||||
| -rw-r--r-- | src/ui/widget/dock.cpp | 235 | ||||
| -rw-r--r-- | src/ui/widget/dock.h | 97 |
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 + |
