From 22e3afe1d78265a55ae81760b8fe568c1049c06b Mon Sep 17 00:00:00 2001 From: gustav_b Date: Thu, 25 Oct 2007 21:34:38 +0000 Subject: [PATCH] Dockable dialogs: Allow in-dock dialogs to be expanded even if there's no "slack". --- src/libgdl/gdl-dock-master.c | 21 ++++- src/libgdl/gdl-dock-object.h | 8 ++ src/libgdl/gdl-dock-paned.c | 134 ++++++++++++++++++++++++++++++-- src/libgdl/gdl-dock-paned.h | 2 + src/libgdl/libgdltypebuiltins.c | 22 ++++++ src/libgdl/libgdltypebuiltins.h | 2 + src/ui/widget/dock.cpp | 23 +++++- src/ui/widget/dock.h | 4 + 8 files changed, 209 insertions(+), 7 deletions(-) diff --git a/src/libgdl/gdl-dock-master.c b/src/libgdl/gdl-dock-master.c index 8a6aba315..205900702 100644 --- a/src/libgdl/gdl-dock-master.c +++ b/src/libgdl/gdl-dock-master.c @@ -79,7 +79,8 @@ enum { PROP_0, PROP_DEFAULT_TITLE, PROP_LOCKED, - PROP_SWITCHER_STYLE + PROP_SWITCHER_STYLE, + PROP_EXPANSION_DIRECTION }; enum { @@ -109,6 +110,8 @@ struct _GdlDockMasterPrivate { GHashTable *unlocked_items; GdlSwitcherStyle switcher_style; + + GdlDockExpansionDirection expansion_direction; }; #define COMPUTE_LOCKED(master) \ @@ -157,6 +160,15 @@ gdl_dock_master_class_init (GdlDockMasterClass *klass) GDL_SWITCHER_STYLE_BOTH, G_PARAM_READWRITE)); + g_object_class_install_property ( + g_object_class, PROP_EXPANSION_DIRECTION, + g_param_spec_enum ("expand-direction", _("Expand direction"), + _("Allow the master's dock items to expand their container " + "dock objects in the given direction"), + GDL_TYPE_EXPANSION_DIRECTION, + GDL_DOCK_EXPANSION_DIRECTION_NONE, + G_PARAM_READWRITE)); + master_signals [LAYOUT_CHANGED] = g_signal_new ("layout-changed", G_TYPE_FROM_CLASS (klass), @@ -183,6 +195,7 @@ gdl_dock_master_instance_init (GdlDockMaster *master) master->_priv = g_new0 (GdlDockMasterPrivate, 1); master->_priv->number = 1; master->_priv->switcher_style = GDL_SWITCHER_STYLE_BOTH; + master->_priv->expansion_direction = GDL_DOCK_EXPANSION_DIRECTION_NONE; master->_priv->locked_items = g_hash_table_new (g_direct_hash, g_direct_equal); master->_priv->unlocked_items = g_hash_table_new (g_direct_hash, g_direct_equal); } @@ -359,6 +372,9 @@ gdl_dock_master_set_property (GObject *object, case PROP_SWITCHER_STYLE: gdl_dock_master_set_switcher_style (master, g_value_get_enum (value)); break; + case PROP_EXPANSION_DIRECTION: + master->_priv->expansion_direction = g_value_get_enum (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -383,6 +399,9 @@ gdl_dock_master_get_property (GObject *object, case PROP_SWITCHER_STYLE: g_value_set_enum (value, master->_priv->switcher_style); break; + case PROP_EXPANSION_DIRECTION: + g_value_set_enum (value, master->_priv->expansion_direction); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/src/libgdl/gdl-dock-object.h b/src/libgdl/gdl-dock-object.h index f21418302..84e5eb9a7 100644 --- a/src/libgdl/gdl-dock-object.h +++ b/src/libgdl/gdl-dock-object.h @@ -66,6 +66,14 @@ typedef enum { GDL_DOCK_FLOATING } GdlDockPlacement; +typedef enum { + GDL_DOCK_EXPANSION_DIRECTION_NONE = 0, + GDL_DOCK_EXPANSION_DIRECTION_UP, + GDL_DOCK_EXPANSION_DIRECTION_DOWN, + GDL_DOCK_EXPANSION_DIRECTION_LEFT, + GDL_DOCK_EXPANSION_DIRECTION_RIGHT +} GdlDockExpansionDirection; + typedef struct _GdlDockObject GdlDockObject; typedef struct _GdlDockObjectClass GdlDockObjectClass; typedef struct _GdlDockRequest GdlDockRequest; diff --git a/src/libgdl/gdl-dock-paned.c b/src/libgdl/gdl-dock-paned.c index a176f1f7d..268a9f673 100644 --- a/src/libgdl/gdl-dock-paned.c +++ b/src/libgdl/gdl-dock-paned.c @@ -140,6 +140,64 @@ static void gdl_dock_paned_instance_init (GdlDockPaned *paned) { paned->position_changed = FALSE; + paned->in_drag = FALSE; + paned->last_drag_position = -1; +} + +static void +gdl_dock_paned_resize_paned_ancestors (GdlDockPaned *paned, + GdlDockExpansionDirection expansion_direction, + gint diff) +{ + GtkWidget *widget, *last_widget; + + g_return_if_fail (GDL_IS_DOCK_PANED (paned)); + + last_widget = GTK_WIDGET (paned); + + /* make sure resizing only can be done in the drag direction */ + if (expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_NONE || + ((expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_DOWN || + expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_UP) && + !GTK_IS_VPANED (GDL_DOCK_ITEM (paned)->child)) || + ((expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_LEFT || + expansion_direction == GDL_DOCK_EXPANSION_DIRECTION_RIGHT) && + !GTK_IS_HPANED (GDL_DOCK_ITEM (paned)->child))) + { + return; + } + + for (widget = GTK_WIDGET (paned)->parent; widget != NULL; + widget = widget->parent) { + + if (GTK_IS_PANED (widget)) { + + GtkPaned *paned = GTK_PANED (widget); + + if (last_widget == paned->child1) { + + if (!GDL_IS_DOCK_OBJECT(widget->parent)) { + GtkRequisition requisition; + GtkAllocation allocation = paned->child1->allocation; + + gtk_widget_size_request (paned->child1, &requisition); + + gint new_height = + (allocation.height > requisition.height && diff > 0 ? + allocation.height : requisition.height) + diff; + + gtk_widget_set_size_request (paned->child1, -1, new_height); + } + + gtk_paned_set_position (paned, gtk_paned_get_position (paned) + diff); + } + + } else if (!GDL_IS_DOCK_OBJECT (widget)) { + break; + } + + last_widget = widget; + } } static void @@ -148,7 +206,7 @@ gdl_dock_paned_notify_cb (GObject *g_object, gpointer user_data) { GdlDockPaned *paned; - + g_return_if_fail (user_data != NULL && GDL_IS_DOCK_PANED (user_data)); /* chain the notification to the GdlDockPaned */ @@ -156,8 +214,40 @@ gdl_dock_paned_notify_cb (GObject *g_object, paned = GDL_DOCK_PANED (user_data); - if (GDL_DOCK_ITEM_USER_ACTION (user_data) && !strcmp (pspec->name, "position")) + if (GDL_DOCK_ITEM_USER_ACTION (user_data) && !strcmp (pspec->name, "position")) { + + GdlDockExpansionDirection expansion_direction; + paned->position_changed = TRUE; + + g_object_get (GDL_DOCK_OBJECT(paned)->master, + "expand-direction", &expansion_direction, + NULL); + + switch (expansion_direction) { + case GDL_DOCK_EXPANSION_DIRECTION_DOWN: + if (paned->in_drag) { + gint max_position, position, diff; + g_object_get (GDL_DOCK_ITEM (paned)->child, + "max-position", &max_position, + "position", &position, + NULL); + + diff = position - paned->last_drag_position; + paned->last_drag_position = position; + + if (diff > 0 && position == max_position) { + gdl_dock_paned_resize_paned_ancestors (paned, expansion_direction, diff + 1); + } else { + gdl_dock_paned_resize_paned_ancestors (paned, expansion_direction, diff); + } + + } + break; + default: + ; + } + } } static gboolean @@ -171,8 +261,42 @@ gdl_dock_paned_button_cb (GtkWidget *widget, paned = GDL_DOCK_PANED (user_data); if (event->button == 1) { - if (event->type == GDK_BUTTON_PRESS) + if (event->type == GDK_BUTTON_PRESS) { + + GdlDockExpansionDirection expansion_direction; + GDL_DOCK_ITEM_SET_FLAGS (user_data, GDL_DOCK_USER_ACTION); + + paned->in_drag = TRUE; + + g_object_get (GDL_DOCK_OBJECT (paned)->master, + "expand-direction", &expansion_direction, + NULL); + + switch (expansion_direction) { + case GDL_DOCK_EXPANSION_DIRECTION_DOWN: + { + gint max_position, position; + g_object_get (GDL_DOCK_ITEM (paned)->child, + "max-position", &max_position, + "position", &position, + NULL); + + paned->last_drag_position = position; + /* expand the paned's ancestors a bit if the separator is in max position + * to allow dragging in all directions */ + if (position == max_position) + gdl_dock_paned_resize_paned_ancestors (paned, expansion_direction, 1); + break; + } + default: + ; + } + } + else if (event->type == GDK_BUTTON_RELEASE) { + paned->last_drag_position = -1; + paned->in_drag = FALSE; + } else { GDL_DOCK_ITEM_UNSET_FLAGS (user_data, GDL_DOCK_USER_ACTION); if (paned->position_changed) { @@ -570,7 +694,7 @@ gdl_dock_paned_dock (GdlDockObject *object, gtk_paned_pack1 (paned, GTK_WIDGET (requestor), hresize, FALSE); done = TRUE; } else if (!paned->child2 && position == GDL_DOCK_BOTTOM) { - gtk_paned_pack2 (paned, GTK_WIDGET (requestor), hresize, FALSE); + gtk_paned_pack2 (paned, GTK_WIDGET (requestor), TRUE, FALSE); done = TRUE; } break; @@ -581,7 +705,7 @@ gdl_dock_paned_dock (GdlDockObject *object, if (!done) { /* this will create another paned and reparent us there */ GDL_CALL_PARENT (GDL_DOCK_OBJECT_CLASS, dock, (object, requestor, position, - other_data)); + other_data)); } else { gdl_dock_item_show_grip (GDL_DOCK_ITEM (requestor)); diff --git a/src/libgdl/gdl-dock-paned.h b/src/libgdl/gdl-dock-paned.h index 41107a51f..208c9c422 100644 --- a/src/libgdl/gdl-dock-paned.h +++ b/src/libgdl/gdl-dock-paned.h @@ -44,6 +44,8 @@ struct _GdlDockPaned { GdlDockItem dock_item; gboolean position_changed; + gboolean in_drag; + gint last_drag_position; }; struct _GdlDockPanedClass { diff --git a/src/libgdl/libgdltypebuiltins.c b/src/libgdl/libgdltypebuiltins.c index 5ec9ec808..853dc5d53 100644 --- a/src/libgdl/libgdltypebuiltins.c +++ b/src/libgdl/libgdltypebuiltins.c @@ -65,6 +65,28 @@ gdl_dock_placement_get_type (void) } + +static const GEnumValue _gdl_dock_expansion_direction_values[] = { + { GDL_DOCK_EXPANSION_DIRECTION_NONE, "GDL_DOCK_EXPANSION_DIRECTION_NONE", "none" }, + { GDL_DOCK_EXPANSION_DIRECTION_UP, "GDL_DOCK_EXPANSION_DIRECTION_UP", "up" }, + { GDL_DOCK_EXPANSION_DIRECTION_DOWN, "GDL_DOCK_EXPANSION_DIRECTION_DOWN", "down" }, + { GDL_DOCK_EXPANSION_DIRECTION_LEFT, "GDL_DOCK_EXPANSION_DIRECTION_LEFT", "left" }, + { GDL_DOCK_EXPANSION_DIRECTION_RIGHT, "GDL_DOCK_EXPANSION_DIRECTION_RIGHT", "right" }, + { 0, NULL, NULL } +}; + +GType +gdl_dock_expansion_direction_get_type (void) +{ + static GType type = 0; + + if (!type) + type = g_enum_register_static ("GdlDockExpansionDirection", _gdl_dock_expansion_direction_values); + + return type; +} + + /* enumerations from "gdl-dock-item.h" */ static const GFlagsValue _gdl_dock_item_behavior_values[] = { { GDL_DOCK_ITEM_BEH_NORMAL, "GDL_DOCK_ITEM_BEH_NORMAL", "normal" }, diff --git a/src/libgdl/libgdltypebuiltins.h b/src/libgdl/libgdltypebuiltins.h index 22b28cf4b..8be5decb1 100644 --- a/src/libgdl/libgdltypebuiltins.h +++ b/src/libgdl/libgdltypebuiltins.h @@ -16,6 +16,8 @@ GType gdl_dock_param_flags_get_type (void); GType gdl_dock_object_flags_get_type (void); #define GDL_TYPE_DOCK_PLACEMENT gdl_dock_placement_get_type() GType gdl_dock_placement_get_type (void); +#define GDL_TYPE_EXPANSION_DIRECTION gdl_dock_expansion_direction_get_type() +GType gdl_dock_expansion_direction_get_type (void); /* --- gdl-dock-item.h --- */ #define GDL_TYPE_DOCK_ITEM_BEHAVIOR gdl_dock_item_behavior_get_type() diff --git a/src/ui/widget/dock.cpp b/src/ui/widget/dock.cpp index ae19ed8d6..1ca2580ba 100644 --- a/src/ui/widget/dock.cpp +++ b/src/ui/widget/dock.cpp @@ -80,6 +80,7 @@ Dock::Dock(Gtk::Orientation orientation) g_object_set (GDL_DOCK_OBJECT(_gdl_dock)->master, "switcher-style", gdl_switcher_style, + "expand-direction", GDL_DOCK_EXPANSION_DIRECTION_DOWN, NULL); GdlDockBarStyle gdl_dock_bar_style = @@ -91,6 +92,9 @@ Dock::Dock(Gtk::Orientation orientation) 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); + g_signal_connect(_paned->gobj(), "button-press-event", G_CALLBACK(_on_paned_button_event), (void *)this); + g_signal_connect(_paned->gobj(), "button-release-event", G_CALLBACK(_on_paned_button_event), (void *)this); + signal_layout_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::Dock::_onLayoutChanged)); } @@ -230,7 +234,6 @@ void Dock::_onLayoutChanged() { if (isEmpty()) { - if (hasIconifiedItems()) _scrolled_window->set_size_request(_default_dock_bar_width); else @@ -238,10 +241,28 @@ Dock::_onLayoutChanged() getParentPaned()->set_position(INT_MAX); } else { + // unset any forced size requests + _paned->get_child1()->set_size_request(-1, -1); _scrolled_window->set_size_request(-1); } } +void +Dock::_onPanedButtonEvent(GdkEventButton *event) +{ + if (event->button == 1 && event->type == GDK_BUTTON_PRESS) + /* unset size request when starting a drag */ + _paned->get_child1()->set_size_request(-1, -1); +} + +gboolean +Dock::_on_paned_button_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + if (Dock *dock = static_cast(user_data)) + dock->_onPanedButtonEvent(event); + + return FALSE; +} const Glib::SignalProxyInfo Dock::_signal_layout_changed_proxy = diff --git a/src/ui/widget/dock.h b/src/ui/widget/dock.h index b5ecc02ca..dd501f186 100644 --- a/src/ui/widget/dock.h +++ b/src/ui/widget/dock.h @@ -71,6 +71,10 @@ protected: /** Internal signal handlers */ void _onLayoutChanged(); + void _onPanedButtonEvent(GdkEventButton *event); + + static gboolean _on_paned_button_event(GtkWidget *widget, GdkEventButton *event, + gpointer user_data); /** GdlDock signal proxy structures */ static const Glib::SignalProxyInfo _signal_layout_changed_proxy; -- 2.30.2