[gimp/soc-2010-cage] Add 'Automatic' Tab Style support
- From: Michael Muré <mmure src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/soc-2010-cage] Add 'Automatic' Tab Style support
- Date: Wed, 30 Jun 2010 22:08:12 +0000 (UTC)
commit 277f202e7774a0d2a9848b042ddb78fc5add243f
Author: Martin Nordholts <martinn src gnome org>
Date: Fri Jun 11 23:18:49 2010 +0200
Add 'Automatic' Tab Style support
Add support for a new type of Tab Style called 'Automatic'. This tab
style makes the GimpDockbook use the biggest actual tab style it can
for its auto tab style dockables, based on its widget allocation.
The tab style candidates for auto tab style are "Status + Blurb",
"Status + Text" and "Status". A docked widget can also say that it
wants to use "Icon" instead of "Status" for its auto tab style. The
'Tool Options' dockable does this. This is to be as backwards
compatible with the old tab style setup, we make 'automatic' the
default everywhere.
We have quite a bit of dependency to internal layout code in
GtkNotebook, but the current code should be pixel perfect and rather
complete.
Also add a basic regression test.
app/actions/dockable-actions.c | 8 +-
app/gimp-log.c | 3 +-
app/gimp-log.h | 4 +-
app/tests/gimpdir/sessionrc | 2 +-
app/tests/gimpdir/sessionrc-expected | 2 +-
app/tests/test-ui.c | 88 ++++++++
app/widgets/gimpdockable.c | 62 ++++++-
app/widgets/gimpdockable.h | 3 +
app/widgets/gimpdockbook.c | 365 ++++++++++++++++++++++++++++++++--
app/widgets/gimpdockbook.h | 1 +
app/widgets/gimpdocked.c | 15 ++
app/widgets/gimpdocked.h | 2 +
app/widgets/gimptooloptionseditor.c | 15 ++-
app/widgets/widgets-enums.c | 4 +
app/widgets/widgets-enums.h | 4 +-
etc/sessionrc | 16 +-
menus/dockable-menu.xml.in | 2 +
17 files changed, 557 insertions(+), 39 deletions(-)
---
diff --git a/app/actions/dockable-actions.c b/app/actions/dockable-actions.c
index 73d0fa5..bf0933e 100644
--- a/app/actions/dockable-actions.c
+++ b/app/actions/dockable-actions.c
@@ -111,7 +111,9 @@ static const GimpRadioActionEntry dockable_tab_style_actions[] =
TAB_STYLE ("icon-name",
NC_("tab-style", "I_con & Text"), GIMP_TAB_STYLE_ICON_NAME),
TAB_STYLE ("preview-name",
- NC_("tab-style", "St_atus & Text"), GIMP_TAB_STYLE_PREVIEW_NAME)
+ NC_("tab-style", "St_atus & Text"), GIMP_TAB_STYLE_PREVIEW_NAME),
+ TAB_STYLE ("automatic",
+ NC_("tab-style", "Automatic"), GIMP_TAB_STYLE_AUTOMATIC)
};
#undef VIEW_SIZE
@@ -176,7 +178,7 @@ dockable_actions_setup (GimpActionGroup *group)
dockable_tab_style_actions,
G_N_ELEMENTS (dockable_tab_style_actions),
NULL,
- GIMP_TAB_STYLE_PREVIEW,
+ GIMP_TAB_STYLE_AUTOMATIC,
G_CALLBACK (dockable_tab_style_cmd_callback));
gimp_action_group_add_radio_actions (group, "dockable-action",
@@ -344,6 +346,8 @@ dockable_actions_update (GimpActionGroup *group,
SET_ACTIVE ("dockable-tab-style-icon-name", TRUE);
else if (tab_style == GIMP_TAB_STYLE_PREVIEW_NAME)
SET_ACTIVE ("dockable-tab-style-preview-name", TRUE);
+ else if (tab_style == GIMP_TAB_STYLE_AUTOMATIC)
+ SET_ACTIVE ("dockable-tab-style-automatic", TRUE);
SET_SENSITIVE ("dockable-tab-style-preview",
docked_iface->get_preview);
diff --git a/app/gimp-log.c b/app/gimp-log.c
index 96b5c69..3b0eb7a 100644
--- a/app/gimp-log.c
+++ b/app/gimp-log.c
@@ -51,7 +51,8 @@ gimp_log_init (void)
{ "floating-selection", GIMP_LOG_FLOATING_SELECTION },
{ "shm", GIMP_LOG_SHM },
{ "text-editing", GIMP_LOG_TEXT_EDITING },
- { "key-events", GIMP_LOG_KEY_EVENTS }
+ { "key-events", GIMP_LOG_KEY_EVENTS },
+ { "auto-tab-style", GIMP_LOG_AUTO_TAB_STYLE }
};
/* g_parse_debug_string() has special treatment of the string 'help',
diff --git a/app/gimp-log.h b/app/gimp-log.h
index 8113e32..8aa7444 100644
--- a/app/gimp-log.h
+++ b/app/gimp-log.h
@@ -35,7 +35,8 @@ typedef enum
GIMP_LOG_FLOATING_SELECTION = 1 << 11,
GIMP_LOG_SHM = 1 << 12,
GIMP_LOG_TEXT_EDITING = 1 << 13,
- GIMP_LOG_KEY_EVENTS = 1 << 14
+ GIMP_LOG_KEY_EVENTS = 1 << 14,
+ GIMP_LOG_AUTO_TAB_STYLE = 1 << 15
} GimpLogFlags;
@@ -91,6 +92,7 @@ void gimp_logv (const gchar *function,
#define SHM GIMP_LOG_SHM
#define TEXT_EDITING GIMP_LOG_TEXT_EDITING
#define KEY_EVENTS GIMP_LOG_KEY_EVENTS
+#define AUTO_TAB_STYLE GIMP_LOG_AUTO_TAB_STYLE
#if 0 /* last resort */
# define GIMP_LOG /* nothing => no varargs, no log */
diff --git a/app/tests/gimpdir/sessionrc b/app/tests/gimpdir/sessionrc
index c3942ea..0e02373 100644
--- a/app/tests/gimpdir/sessionrc
+++ b/app/tests/gimpdir/sessionrc
@@ -67,7 +67,7 @@
(book
(current-page 0)
(dockable "gimp-channel-list"
- (tab-style icon)
+ (tab-style automatic)
(preview-size 32)))
(book
(position 162)
diff --git a/app/tests/gimpdir/sessionrc-expected b/app/tests/gimpdir/sessionrc-expected
index 52b6f48..d2282b6 100644
--- a/app/tests/gimpdir/sessionrc-expected
+++ b/app/tests/gimpdir/sessionrc-expected
@@ -71,7 +71,7 @@
(book
(current-page 0)
(dockable "gimp-channel-list"
- (tab-style icon)
+ (tab-style automatic)
(preview-size 32)))
(book
(position 162)
diff --git a/app/tests/test-ui.c b/app/tests/test-ui.c
index fa222dd..594d8fc 100644
--- a/app/tests/test-ui.c
+++ b/app/tests/test-ui.c
@@ -16,6 +16,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
@@ -31,6 +32,8 @@
#include "display/gimpimagewindow.h"
#include "widgets/gimpdialogfactory.h"
+#include "widgets/gimpdockable.h"
+#include "widgets/gimpdockbook.h"
#include "widgets/gimpdocked.h"
#include "widgets/gimpdockwindow.h"
#include "widgets/gimphelp-ids.h"
@@ -66,6 +69,8 @@ typedef struct
static void gimp_ui_tool_options_editor_updates (GimpTestFixture *fixture,
gconstpointer data);
+static void gimp_ui_automatic_tab_style (GimpTestFixture *fixture,
+ gconstpointer data);
static void gimp_ui_create_new_image_via_dialog (GimpTestFixture *fixture,
gconstpointer data);
static void gimp_ui_restore_recently_closed_dock (GimpTestFixture *fixture,
@@ -112,6 +117,12 @@ int main(int argc, char **argv)
NULL,
gimp_ui_tool_options_editor_updates,
NULL);
+ g_test_add ("/gimp-ui/automatic-tab-style",
+ GimpTestFixture,
+ gimp,
+ NULL,
+ gimp_ui_automatic_tab_style,
+ NULL);
g_test_add ("/gimp-ui/create-new-image-via-dialog",
GimpTestFixture,
gimp,
@@ -155,6 +166,7 @@ int main(int argc, char **argv)
gimp_ui_switch_back_to_multi_window_mode,
NULL);
+
/* Run the tests and return status */
result = g_test_run ();
@@ -217,6 +229,82 @@ gimp_ui_tool_options_editor_updates (GimpTestFixture *fixture,
help_id);
}
+static GtkWidget *
+gimp_ui_get_dialog (const gchar *identifier)
+{
+ GtkWidget *result = NULL;
+ GList *iter;
+
+ for (iter = gimp_dialog_factory_get_open_dialogs (gimp_dialog_factory_get_singleton ());
+ iter;
+ iter = g_list_next (iter))
+ {
+ GtkWidget *dialog = GTK_WIDGET (iter->data);
+ GimpDialogFactoryEntry *entry = NULL;
+
+ gimp_dialog_factory_from_widget (dialog, &entry);
+
+ if (strcmp (entry->identifier, identifier) == 0)
+ {
+ result = dialog;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static void
+gimp_ui_automatic_tab_style (GimpTestFixture *fixture,
+ gconstpointer data)
+{
+ GtkWidget *channel_dockable = gimp_ui_get_dialog ("gimp-channel-list");
+ GimpDockable *dockable;
+ GimpUIManager *ui_manager;
+ g_assert (channel_dockable != NULL);
+
+ dockable = GIMP_DOCKABLE (channel_dockable);
+
+ /* The channel dockable is the only dockable, it has enough space
+ * for the icon-blurb
+ */
+ g_assert_cmpint (GIMP_TAB_STYLE_ICON_BLURB,
+ ==,
+ gimp_dockable_get_actual_tab_style (dockable));
+
+ /* Add some dockables to the channel dockable dockbook */
+ ui_manager =
+ gimp_dockbook_get_ui_manager (gimp_dockable_get_dockbook (dockable));
+ gimp_ui_manager_activate_action (ui_manager,
+ "dockable",
+ "dialogs-sample-points");
+ gimp_ui_manager_activate_action (ui_manager,
+ "dockable",
+ "dialogs-vectors");
+ gimp_test_run_mainloop_until_idle ();
+
+ /* Now there is not enough space to have icon-blurb for channel
+ * dockable, make sure it's just an icon now
+ */
+ g_assert_cmpint (GIMP_TAB_STYLE_ICON,
+ ==,
+ gimp_dockable_get_actual_tab_style (dockable));
+
+ /* Close the two dockables we added */
+ gimp_ui_manager_activate_action (ui_manager,
+ "dockable",
+ "dockable-close-tab");
+ gimp_ui_manager_activate_action (ui_manager,
+ "dockable",
+ "dockable-close-tab");
+ gimp_test_run_mainloop_until_idle ();
+
+ /* We should now be back on icon-blurb */
+ g_assert_cmpint (GIMP_TAB_STYLE_ICON_BLURB,
+ ==,
+ gimp_dockable_get_actual_tab_style (dockable));
+}
+
static void
gimp_ui_create_new_image_via_dialog (GimpTestFixture *fixture,
gconstpointer data)
diff --git a/app/widgets/gimpdockable.c b/app/widgets/gimpdockable.c
index 1f276c0..f2936b1 100644
--- a/app/widgets/gimpdockable.c
+++ b/app/widgets/gimpdockable.c
@@ -62,6 +62,7 @@ struct _GimpDockablePrivate
gchar *stock_id;
gchar *help_id;
GimpTabStyle tab_style;
+ GimpTabStyle actual_tab_style;
gboolean locked;
GimpDockbook *dockbook;
@@ -215,9 +216,10 @@ gimp_dockable_init (GimpDockable *dockable)
dockable->p = G_TYPE_INSTANCE_GET_PRIVATE (dockable,
GIMP_TYPE_DOCKABLE,
GimpDockablePrivate);
- dockable->p->tab_style = GIMP_TAB_STYLE_PREVIEW;
- dockable->p->drag_x = GIMP_DOCKABLE_DRAG_OFFSET;
- dockable->p->drag_y = GIMP_DOCKABLE_DRAG_OFFSET;
+ dockable->p->tab_style = GIMP_TAB_STYLE_AUTOMATIC;
+ dockable->p->actual_tab_style = GIMP_TAB_STYLE_UNDEFINED;
+ dockable->p->drag_x = GIMP_DOCKABLE_DRAG_OFFSET;
+ dockable->p->drag_y = GIMP_DOCKABLE_DRAG_OFFSET;
gtk_widget_push_composite_child ();
dockable->p->menu_button = gtk_button_new ();
@@ -884,6 +886,11 @@ gimp_dockable_new_tab_widget_internal (GimpDockable *dockable,
gtk_box_pack_start (GTK_BOX (tab_widget), label, FALSE, FALSE, 0);
gtk_widget_show (label);
break;
+
+ case GIMP_TAB_STYLE_UNDEFINED:
+ case GIMP_TAB_STYLE_AUTOMATIC:
+ g_warning ("Tab style error, unexpected code path taken, fix!");
+ break;
}
return tab_widget;
@@ -946,6 +953,22 @@ gimp_dockable_get_tab_style (GimpDockable *dockable)
return dockable->p->tab_style;
}
+/**
+ * gimp_dockable_get_actual_tab_style:
+ * @dockable:
+ *
+ * Get actual tab style, i.e. never "automatic". This state should
+ * actually be hold on a per-dockbook basis, but at this point that
+ * feels like over-engineering...
+ **/
+GimpTabStyle
+gimp_dockable_get_actual_tab_style (GimpDockable *dockable)
+{
+ g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), -1);
+
+ return dockable->p->actual_tab_style;
+}
+
const gchar *
gimp_dockable_get_name (GimpDockable *dockable)
{
@@ -1072,6 +1095,39 @@ gimp_dockable_set_tab_style (GimpDockable *dockable,
g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
dockable->p->tab_style = gimp_dockable_convert_tab_style (dockable, tab_style);
+
+ if (tab_style == GIMP_TAB_STYLE_AUTOMATIC)
+ gimp_dockable_set_actual_tab_style (dockable, GIMP_TAB_STYLE_UNDEFINED);
+ else
+ gimp_dockable_set_actual_tab_style (dockable, tab_style);
+
+ if (dockable->p->dockbook)
+ gimp_dockbook_update_auto_tab_style (dockable->p->dockbook);
+}
+
+/**
+ * gimp_dockable_set_actual_tab_style:
+ * @dockable:
+ * @tab_style:
+ *
+ * Sets actual tab style, meant for those that decides what
+ * "automatic" tab style means.
+ *
+ * Returns: %TRUE if changed, %FALSE otherwise.
+ **/
+gboolean
+gimp_dockable_set_actual_tab_style (GimpDockable *dockable,
+ GimpTabStyle tab_style)
+{
+ GimpTabStyle new_tab_style = gimp_dockable_convert_tab_style (dockable, tab_style);
+ GimpTabStyle old_tab_style = dockable->p->actual_tab_style;
+
+ g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), FALSE);
+ g_return_val_if_fail (tab_style != GIMP_TAB_STYLE_AUTOMATIC, FALSE);
+
+ dockable->p->actual_tab_style = new_tab_style;
+
+ return new_tab_style != old_tab_style;
}
GtkWidget *
diff --git a/app/widgets/gimpdockable.h b/app/widgets/gimpdockable.h
index a285b9e..52ea00e 100644
--- a/app/widgets/gimpdockable.h
+++ b/app/widgets/gimpdockable.h
@@ -88,6 +88,9 @@ gboolean gimp_dockable_is_locked (GimpDockable *dockable)
void gimp_dockable_set_tab_style (GimpDockable *dockable,
GimpTabStyle tab_style);
+gboolean gimp_dockable_set_actual_tab_style (GimpDockable *dockable,
+ GimpTabStyle tab_style);
+GimpTabStyle gimp_dockable_get_actual_tab_style (GimpDockable *dockable);
GtkWidget * gimp_dockable_create_tab_widget (GimpDockable *dockable,
GimpContext *context,
GimpTabStyle tab_style,
diff --git a/app/widgets/gimpdockbook.c b/app/widgets/gimpdockbook.c
index 943e1ff..0fce11e 100644
--- a/app/widgets/gimpdockbook.c
+++ b/app/widgets/gimpdockbook.c
@@ -47,12 +47,13 @@
#include "gimp-log.h"
-#define DEFAULT_TAB_BORDER 0
-#define DEFAULT_TAB_ICON_SIZE GTK_ICON_SIZE_BUTTON
-#define DND_WIDGET_ICON_SIZE GTK_ICON_SIZE_BUTTON
-#define MENU_WIDGET_ICON_SIZE GTK_ICON_SIZE_MENU
-#define MENU_WIDGET_SPACING 4
-#define TAB_HOVER_TIMEOUT 500
+#define DEFAULT_TAB_BORDER 0
+#define DEFAULT_TAB_ICON_SIZE GTK_ICON_SIZE_BUTTON
+#define DND_WIDGET_ICON_SIZE GTK_ICON_SIZE_BUTTON
+#define MENU_WIDGET_ICON_SIZE GTK_ICON_SIZE_MENU
+#define MENU_WIDGET_SPACING 4
+#define TAB_HOVER_TIMEOUT 500
+#define GIMP_N_TAB_STYLE_CANDIDATES 3 /* G_N_ELEMENTS (gimp_tab_style_candidates); */
enum
@@ -65,18 +66,34 @@ enum
struct _GimpDockbookPrivate
{
- GimpDock *dock;
- GimpUIManager *ui_manager;
+ GimpDock *dock;
+ GimpUIManager *ui_manager;
- guint tab_hover_timeout;
- GimpDockable *tab_hover_dockable;
+ guint tab_hover_timeout;
+ GimpDockable *tab_hover_dockable;
- GimpPanedBox *drag_handler;
+ GimpPanedBox *drag_handler;
+
+ /* Cache for "what actual tab style for automatic styles can we use
+ * for a given dockbook width
+ */
+ gint min_width_for_style[GIMP_N_TAB_STYLE_CANDIDATES];
+
+ /* We need a list separate from the GtkContainer children list,
+ * because we need to do calculations for all dockables before we
+ * can add a dockable as a child, namely automatic tab style
+ * calculations
+ */
+ GList *dockables;
+
+ GtkWidget *menu_button;
};
static void gimp_dockbook_dispose (GObject *object);
static void gimp_dockbook_finalize (GObject *object);
+static void gimp_dockbook_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
static void gimp_dockbook_style_set (GtkWidget *widget,
GtkStyle *prev_style);
static void gimp_dockbook_drag_leave (GtkWidget *widget,
@@ -98,7 +115,8 @@ static void gimp_dockbook_dockable_removed (GimpDockbook *d
GimpDockable *dockable);
static void gimp_dockbook_update_tabs (GimpDockbook *dockbook,
gboolean added);
-static void gimp_dockbook_recreate_tab_widgets (GimpDockbook *dockbook);
+static void gimp_dockbook_recreate_tab_widgets (GimpDockbook *dockbook,
+ gboolean only_auto);
static void gimp_dockbook_tab_drag_source_setup (GtkWidget *widget,
GimpDockable *dockable);
static void gimp_dockbook_tab_drag_begin (GtkWidget *widget,
@@ -122,6 +140,10 @@ static gboolean gimp_dockbook_tab_drag_drop (GtkWidget *w
gint x,
gint y,
guint time);
+static GimpTabStyle gimp_dockbook_tab_style_to_prefered (GimpTabStyle tab_style,
+ GimpDockable *dockable);
+static void gimp_dockbook_refresh_tab_layout_lut (GimpDockbook *dockbook);
+static void gimp_dockbook_update_automatic_tab_style (GimpDockbook *dockbook);
static GtkWidget * gimp_dockable_create_event_box_tab_widget (GimpDockable *dockable,
GimpContext *context,
GimpTabStyle tab_style,
@@ -136,6 +158,7 @@ static void gimp_dockbook_tab_locked_notify (GimpDockable *d
GimpDockbook *dockbook);
static void gimp_dockbook_help_func (const gchar *help_id,
gpointer help_data);
+static const gchar *gimp_dockbook_get_tab_style_name (GimpTabStyle tab_style);
G_DEFINE_TYPE (GimpDockbook, gimp_dockbook, GTK_TYPE_NOTEBOOK)
@@ -146,6 +169,15 @@ static guint dockbook_signals[LAST_SIGNAL] = { 0 };
static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_DIALOG };
+/* List of candidates for the automatic style, starting with the
+ * biggest first
+ */
+static GimpTabStyle gimp_tab_style_candidates[] = {
+ GIMP_TAB_STYLE_PREVIEW_BLURB,
+ GIMP_TAB_STYLE_PREVIEW_NAME,
+ GIMP_TAB_STYLE_PREVIEW,
+};
+
static void
gimp_dockbook_class_init (GimpDockbookClass *klass)
@@ -153,6 +185,9 @@ gimp_dockbook_class_init (GimpDockbookClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ if (G_N_ELEMENTS (gimp_tab_style_candidates) != GIMP_N_TAB_STYLE_CANDIDATES)
+ g_error ("Update GIMP_N_TAB_STYLE_CANDIDATES");
+
dockbook_signals[DOCKABLE_ADDED] =
g_signal_new ("dockable-added",
G_TYPE_FROM_CLASS (klass),
@@ -186,10 +221,11 @@ gimp_dockbook_class_init (GimpDockbookClass *klass)
object_class->dispose = gimp_dockbook_dispose;
object_class->finalize = gimp_dockbook_finalize;
- widget_class->style_set = gimp_dockbook_style_set;
- widget_class->drag_leave = gimp_dockbook_drag_leave;
- widget_class->drag_motion = gimp_dockbook_drag_motion;
- widget_class->drag_drop = gimp_dockbook_drag_drop;
+ widget_class->size_allocate = gimp_dockbook_size_allocate;
+ widget_class->style_set = gimp_dockbook_style_set;
+ widget_class->drag_leave = gimp_dockbook_drag_leave;
+ widget_class->drag_motion = gimp_dockbook_drag_motion;
+ widget_class->drag_drop = gimp_dockbook_drag_drop;
klass->dockable_added = gimp_dockbook_dockable_added;
klass->dockable_removed = gimp_dockbook_dockable_removed;
@@ -255,6 +291,18 @@ gimp_dockbook_finalize (GObject *object)
}
static void
+gimp_dockbook_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+
+ /* Update tab styles, also recreates if changed */
+ gimp_dockbook_update_automatic_tab_style (dockbook);
+}
+
+static void
gimp_dockbook_style_set (GtkWidget *widget,
GtkStyle *prev_style)
{
@@ -279,7 +327,8 @@ gimp_dockbook_style_set (GtkWidget *widget,
"tab-border", tab_border,
NULL);
- gimp_dockbook_recreate_tab_widgets (GIMP_DOCKBOOK (widget));
+ gimp_dockbook_recreate_tab_widgets (GIMP_DOCKBOOK (widget),
+ FALSE /*only_auto*/);
}
static void
@@ -382,6 +431,241 @@ gimp_dockbook_update_tabs (GimpDockbook *dockbook,
}
}
+/**
+ * gimp_dockbook_get_dockable_tab_width:
+ * @dockable:
+ * @tab_style:
+ *
+ * Returns: Width of tab when the dockable is using the specified tab
+ * style.
+ **/
+static gint
+gimp_dockbook_get_dockable_tab_width (GimpDockbook *dockbook,
+ GimpDockable *dockable,
+ GimpTabStyle tab_style)
+{
+ GtkRequisition dockable_request;
+ GtkWidget *tab_widget;
+
+ tab_widget =
+ gimp_dockable_create_event_box_tab_widget (dockable,
+ gimp_dock_get_context (dockbook->p->dock),
+ tab_style,
+ gimp_dockbook_get_tab_icon_size (dockbook));
+
+ /* So font-scale is applied. We can't apply styles without having a
+ * GdkScreen :(
+ */
+ gimp_dock_temp_add (dockbook->p->dock, tab_widget);
+
+ gtk_widget_size_request (tab_widget, &dockable_request);
+
+ /* Also destroys the widget */
+ gimp_dock_temp_remove (dockbook->p->dock, tab_widget);
+
+ return dockable_request.width;
+}
+
+/**
+ * gimp_dockbook_tab_style_to_prefered:
+ * @tab_style:
+ * @dockable:
+ *
+ * The list of tab styles to try in automatic mode only consists of
+ * preview styles. For some dockables, like the tool options dockable,
+ * we rather want to use the icon tab styles for the automatic
+ * mode. This function is used to convert tab styles for such
+ * dockables.
+ *
+ * Returns: An icon tab style if the dockable prefers icon tab styles
+ * in automatic mode.
+ **/
+static GimpTabStyle
+gimp_dockbook_tab_style_to_prefered (GimpTabStyle tab_style,
+ GimpDockable *dockable)
+{
+ GimpDocked *docked = GIMP_DOCKED (gtk_bin_get_child (GTK_BIN (dockable)));
+
+ if (gimp_docked_get_prefer_icon (docked))
+ tab_style = gimp_preview_tab_style_to_icon (tab_style);
+
+ return tab_style;
+}
+
+/**
+ * gimp_dockbook_refresh_tab_layout_lut:
+ * @dockbook:
+ *
+ * For each given set of tab widgets, there is a fixed mapping between
+ * the width of the dockbook and the actual tab style to use for auto
+ * tab widgets. This function refreshes that look-up table.
+ **/
+static void
+gimp_dockbook_refresh_tab_layout_lut (GimpDockbook *dockbook)
+{
+ GList *auto_dockables = NULL;
+ GList *iter = NULL;
+ gint fixed_tab_style_space = 0;
+ int i = 0;
+
+ /* Calculate space taken by dockables with fixed tab styles */
+ fixed_tab_style_space = 0;
+ for (iter = dockbook->p->dockables; iter; iter = g_list_next (iter))
+ {
+ GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
+ GimpTabStyle tab_style = gimp_dockable_get_tab_style (dockable);
+
+ if (tab_style == GIMP_TAB_STYLE_AUTOMATIC)
+ auto_dockables = g_list_prepend (auto_dockables, dockable);
+ else
+ fixed_tab_style_space +=
+ gimp_dockbook_get_dockable_tab_width (dockbook,
+ dockable,
+ tab_style);
+ }
+
+ /* Calculate space taken with auto tab style for all candidates */
+ for (i = 0; i < GIMP_N_TAB_STYLE_CANDIDATES; i++)
+ {
+ gint size_with_candidate = 0;
+ GimpTabStyle candidate = gimp_tab_style_candidates[i];
+
+ for (iter = auto_dockables; iter; iter = g_list_next (iter))
+ {
+ GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
+ GimpTabStyle style_to_use;
+
+ style_to_use = gimp_dockbook_tab_style_to_prefered (candidate,
+ dockable);
+ size_with_candidate +=
+ gimp_dockbook_get_dockable_tab_width (dockbook,
+ dockable,
+ style_to_use);
+ }
+
+ dockbook->p->min_width_for_style[i] =
+ fixed_tab_style_space + size_with_candidate;
+
+ GIMP_LOG (AUTO_TAB_STYLE, "Total tab space taken for auto tab style %s = %d",
+ gimp_dockbook_get_tab_style_name (candidate),
+ dockbook->p->min_width_for_style[i]);
+ }
+
+ g_list_free (auto_dockables);
+}
+
+/**
+ * gimp_dockbook_update_automatic_tab_style:
+ * @dockbook:
+ *
+ * Based on widget allocation, sets actual tab style for dockables
+ * with automatic tab styles. Takes care of recreating tab widgets if
+ * necessary.
+ **/
+static void
+gimp_dockbook_update_automatic_tab_style (GimpDockbook *dockbook)
+{
+ GtkWidget *widget = GTK_WIDGET (dockbook);
+ gboolean changed = FALSE;
+ GList *iter = NULL;
+ GtkAllocation dockbook_allocation = { 0, };
+ GtkAllocation button_allocation = { 0, };
+ GimpTabStyle tab_style = 0;
+ int i = 0;
+ gint available_space = 0;
+ guint tab_hborder = 0;
+ gint xthickness = 0;
+ gint tab_curvature = 0;
+ gint focus_width = 0;
+ gint tab_overlap = 0;
+ gint tab_padding = 0;
+ gint border_loss = 0;
+ gint action_widget_size = 0;
+
+ xthickness = gtk_widget_get_style (widget)->xthickness;
+ g_object_get (widget,
+ "tab-hborder", &tab_hborder,
+ NULL);
+ gtk_widget_style_get (widget,
+ "tab-curvature", &tab_curvature,
+ "focus-line-width", &focus_width,
+ "tab-overlap", &tab_overlap,
+ NULL);
+ gtk_widget_get_allocation (dockbook->p->menu_button,
+ &button_allocation);
+
+ /* Calculate available space. Based on code in GTK+ internal
+ * functions gtk_notebook_size_request() and
+ * gtk_notebook_pages_allocate()
+ */
+ gtk_widget_get_allocation (widget, &dockbook_allocation);
+
+ /* Border on both sides */
+ border_loss = gtk_container_get_border_width (GTK_CONTAINER (dockbook)) * 2;
+
+ /* Space taken by action widget */
+ action_widget_size = button_allocation.width + xthickness;
+
+ /* Space taken by the tabs but not the tab widgets themselves */
+ tab_padding = gtk_notebook_get_n_pages (GTK_NOTEBOOK (dockbook)) *
+ (2 * (xthickness + tab_curvature + focus_width + tab_hborder) -
+ tab_overlap);
+
+ available_space = dockbook_allocation.width
+ - border_loss
+ - action_widget_size
+ - tab_padding
+ - tab_overlap;
+
+ GIMP_LOG (AUTO_TAB_STYLE, "\n"
+ " available_space = %d where\n"
+ " dockbook_allocation.width = %d\n"
+ " border_loss = %d\n"
+ " action_widget_size = %d\n"
+ " tab_padding = %d\n"
+ " tab_overlap = %d\n",
+ available_space,
+ dockbook_allocation.width,
+ border_loss,
+ action_widget_size,
+ tab_padding,
+ tab_overlap);
+
+ /* Try all candidates, if we don't get any hit we still end up on
+ * the smallest style (which we always fall back to if we don't get
+ * a better match)
+ */
+ for (i = 0; i < GIMP_N_TAB_STYLE_CANDIDATES; i++)
+ {
+ tab_style = gimp_tab_style_candidates[i];
+ if (available_space > dockbook->p->min_width_for_style[i])
+ {
+ GIMP_LOG (AUTO_TAB_STYLE, "Choosing tab style %s",
+ gimp_dockbook_get_tab_style_name (tab_style));
+ break;
+ }
+ }
+
+ for (iter = dockbook->p->dockables; iter; iter = g_list_next (iter))
+ {
+ GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
+ GimpTabStyle actual_tab_style = tab_style;
+
+ if (gimp_dockable_get_tab_style (dockable) != GIMP_TAB_STYLE_AUTOMATIC)
+ continue;
+
+ actual_tab_style = gimp_dockbook_tab_style_to_prefered (tab_style,
+ dockable);
+
+ if (gimp_dockable_set_actual_tab_style (dockable, actual_tab_style))
+ changed = TRUE;
+ }
+
+ if (changed)
+ gimp_dockbook_recreate_tab_widgets (dockbook,
+ TRUE /*only_auto*/);
+}
+
GtkWidget *
gimp_dockbook_new (GimpMenuFactory *menu_factory)
{
@@ -443,6 +727,16 @@ gimp_dockbook_add (GimpDockbook *dockbook,
GIMP_LOG (DND, "Adding GimpDockable %p to GimpDockbook %p", dockable, dockbook);
+ /* Add to internal list before doing automatic tab style
+ * calculations
+ */
+ dockbook->p->dockables = g_list_insert (dockbook->p->dockables,
+ dockable,
+ position);
+
+ gimp_dockbook_update_auto_tab_style (dockbook);
+
+ /* Create the new tab widget, it will get the correct tab style now */
tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
g_return_if_fail (GTK_IS_WIDGET (tab_widget));
@@ -515,11 +809,15 @@ gimp_dockbook_remove (GimpDockbook *dockbook,
gimp_dockable_set_context (dockable, NULL);
gtk_container_remove (GTK_CONTAINER (dockbook), GTK_WIDGET (dockable));
+ dockbook->p->dockables = g_list_remove (dockbook->p->dockables,
+ dockable);
g_signal_emit (dockbook, dockbook_signals[DOCKABLE_REMOVED], 0, dockable);
g_object_unref (dockable);
+ gimp_dockbook_update_auto_tab_style (dockbook);
+
children = gtk_container_get_children (GTK_CONTAINER (dockbook));
if (! g_list_length (children))
@@ -565,7 +863,7 @@ gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
tab_widget =
gimp_dockable_create_event_box_tab_widget (dockable,
gimp_dock_get_context (dockbook->p->dock),
- gimp_dockable_get_tab_style (dockable),
+ gimp_dockable_get_actual_tab_style (dockable),
gimp_dockbook_get_tab_icon_size (dockbook));
/* EEK */
@@ -649,6 +947,23 @@ gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
return tab_widget;
}
+/**
+ * gimp_dockbook_update_auto_tab_style:
+ * @dockbook:
+ *
+ * Refresh the table that we use to map dockbook width to actual auto
+ * tab style, then update auto tabs (also recreate tab widgets if
+ * necessary).
+ **/
+void
+gimp_dockbook_update_auto_tab_style (GimpDockbook *dockbook)
+{
+ g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
+
+ gimp_dockbook_refresh_tab_layout_lut (dockbook);
+ gimp_dockbook_update_automatic_tab_style (dockbook);
+}
+
gboolean
gimp_dockbook_drop_dockable (GimpDockbook *dockbook,
GtkWidget *drag_source)
@@ -730,7 +1045,8 @@ gimp_dockbook_drag_source_to_dockable (GtkWidget *drag_source)
/* tab DND source side */
static void
-gimp_dockbook_recreate_tab_widgets (GimpDockbook *dockbook)
+gimp_dockbook_recreate_tab_widgets (GimpDockbook *dockbook,
+ gboolean only_auto)
{
GList *dockables = gtk_container_get_children (GTK_CONTAINER (dockbook));
GList *iter = NULL;
@@ -740,6 +1056,10 @@ gimp_dockbook_recreate_tab_widgets (GimpDockbook *dockbook)
GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
GtkWidget *tab_widget;
+ if (only_auto &&
+ ! gimp_dockable_get_tab_style (dockable) == GIMP_TAB_STYLE_AUTOMATIC)
+ continue;
+
tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (dockbook),
@@ -1109,3 +1429,10 @@ gimp_dockbook_help_func (const gchar *help_id,
else
gimp_standard_help_func (GIMP_HELP_DOCK, NULL);
}
+
+static const gchar *
+gimp_dockbook_get_tab_style_name (GimpTabStyle tab_style)
+{
+ return g_enum_get_value (g_type_class_peek (GIMP_TYPE_TAB_STYLE),
+ tab_style)->value_name;
+}
diff --git a/app/widgets/gimpdockbook.h b/app/widgets/gimpdockbook.h
index f43b680..e3249fe 100644
--- a/app/widgets/gimpdockbook.h
+++ b/app/widgets/gimpdockbook.h
@@ -74,6 +74,7 @@ void gimp_dockbook_update_with_context (GimpDockbook *dockbo
GimpContext *context);
GtkWidget * gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
GimpDockable *dockable);
+void gimp_dockbook_update_auto_tab_style (GimpDockbook *dockbook);
gboolean gimp_dockbook_drop_dockable (GimpDockbook *dockbook,
GtkWidget *drag_source);
void gimp_dockbook_set_drag_handler (GimpDockbook *dockbook,
diff --git a/app/widgets/gimpdocked.c b/app/widgets/gimpdocked.c
index 81e57b1..14d8246 100644
--- a/app/widgets/gimpdocked.c
+++ b/app/widgets/gimpdocked.c
@@ -191,6 +191,21 @@ gimp_docked_get_preview (GimpDocked *docked,
return NULL;
}
+gboolean
+gimp_docked_get_prefer_icon (GimpDocked *docked)
+{
+ GimpDockedInterface *docked_iface;
+
+ g_return_val_if_fail (GIMP_IS_DOCKED (docked), FALSE);
+
+ docked_iface = GIMP_DOCKED_GET_INTERFACE (docked);
+
+ if (docked_iface->get_prefer_icon)
+ return docked_iface->get_prefer_icon (docked);
+
+ return FALSE;
+}
+
GimpUIManager *
gimp_docked_get_menu (GimpDocked *docked,
const gchar **ui_path,
diff --git a/app/widgets/gimpdocked.h b/app/widgets/gimpdocked.h
index 04d73af..fe9e269 100644
--- a/app/widgets/gimpdocked.h
+++ b/app/widgets/gimpdocked.h
@@ -50,6 +50,7 @@ struct _GimpDockedInterface
GtkWidget * (* get_preview) (GimpDocked *docked,
GimpContext *context,
GtkIconSize size);
+ gboolean (* get_prefer_icon) (GimpDocked *docked);
GimpUIManager * (* get_menu) (GimpDocked *docked,
const gchar **ui_path,
gpointer *popup_data);
@@ -76,6 +77,7 @@ GList * gimp_docked_get_aux_info (GimpDocked *docked);
GtkWidget * gimp_docked_get_preview (GimpDocked *docked,
GimpContext *context,
GtkIconSize size);
+gboolean gimp_docked_get_prefer_icon (GimpDocked *docked);
GimpUIManager * gimp_docked_get_menu (GimpDocked *docked,
const gchar **ui_path,
gpointer *popup_data);
diff --git a/app/widgets/gimptooloptionseditor.c b/app/widgets/gimptooloptionseditor.c
index 3fd282d..63154bd 100644
--- a/app/widgets/gimptooloptionseditor.c
+++ b/app/widgets/gimptooloptionseditor.c
@@ -88,6 +88,7 @@ static GtkWidget * gimp_tool_options_editor_get_preview (GimpDocked
GimpContext *context,
GtkIconSize size);
static gchar * gimp_tool_options_editor_get_title (GimpDocked *docked);
+static gboolean gimp_tool_options_editor_get_prefer_icon (GimpDocked *docked);
static void gimp_tool_options_editor_save_clicked (GtkWidget *widget,
GimpToolOptionsEditor *editor);
static void gimp_tool_options_editor_restore_clicked (GtkWidget *widget,
@@ -184,8 +185,9 @@ gimp_tool_options_editor_init (GimpToolOptionsEditor *editor)
static void
gimp_tool_options_editor_docked_iface_init (GimpDockedInterface *docked_iface)
{
- docked_iface->get_preview = gimp_tool_options_editor_get_preview;
- docked_iface->get_title = gimp_tool_options_editor_get_title;
+ docked_iface->get_preview = gimp_tool_options_editor_get_preview;
+ docked_iface->get_title = gimp_tool_options_editor_get_title;
+ docked_iface->get_prefer_icon = gimp_tool_options_editor_get_prefer_icon;
}
static GObject *
@@ -349,6 +351,15 @@ gimp_tool_options_editor_get_title (GimpDocked *docked)
return tool_info ? g_strdup (tool_info->blurb) : NULL;
}
+static gboolean
+gimp_tool_options_editor_get_prefer_icon (GimpDocked *docked)
+{
+ /* We support get_preview() for tab tyles, but we prefer to show our
+ * icon
+ */
+ return TRUE;
+}
+
/* public functions */
diff --git a/app/widgets/widgets-enums.c b/app/widgets/widgets-enums.c
index 826edb1..9f6d07b 100644
--- a/app/widgets/widgets-enums.c
+++ b/app/widgets/widgets-enums.c
@@ -205,6 +205,8 @@ gimp_tab_style_get_type (void)
{ GIMP_TAB_STYLE_ICON_BLURB, "GIMP_TAB_STYLE_ICON_BLURB", "icon-blurb" },
{ GIMP_TAB_STYLE_PREVIEW_NAME, "GIMP_TAB_STYLE_PREVIEW_NAME", "preview-name" },
{ GIMP_TAB_STYLE_PREVIEW_BLURB, "GIMP_TAB_STYLE_PREVIEW_BLURB", "preview-blurb" },
+ { GIMP_TAB_STYLE_UNDEFINED, "GIMP_TAB_STYLE_UNDEFINED", "undefined" },
+ { GIMP_TAB_STYLE_AUTOMATIC, "GIMP_TAB_STYLE_AUTOMATIC", "automatic" },
{ 0, NULL, NULL }
};
@@ -218,6 +220,8 @@ gimp_tab_style_get_type (void)
{ GIMP_TAB_STYLE_ICON_BLURB, NC_("tab-style", "Icon & desc"), NULL },
{ GIMP_TAB_STYLE_PREVIEW_NAME, NC_("tab-style", "Status & text"), NULL },
{ GIMP_TAB_STYLE_PREVIEW_BLURB, NC_("tab-style", "Status & desc"), NULL },
+ { GIMP_TAB_STYLE_UNDEFINED, NC_("tab-style", "Undefined"), NULL },
+ { GIMP_TAB_STYLE_AUTOMATIC, NC_("tab-style", "Automatic"), NULL },
{ 0, NULL, NULL }
};
diff --git a/app/widgets/widgets-enums.h b/app/widgets/widgets-enums.h
index 56ffb4e..894214d 100644
--- a/app/widgets/widgets-enums.h
+++ b/app/widgets/widgets-enums.h
@@ -107,7 +107,9 @@ typedef enum
GIMP_TAB_STYLE_ICON_NAME, /*< desc="Icon & text" >*/
GIMP_TAB_STYLE_ICON_BLURB, /*< desc="Icon & desc" >*/
GIMP_TAB_STYLE_PREVIEW_NAME, /*< desc="Status & text" >*/
- GIMP_TAB_STYLE_PREVIEW_BLURB /*< desc="Status & desc" >*/
+ GIMP_TAB_STYLE_PREVIEW_BLURB, /*< desc="Status & desc" >*/
+ GIMP_TAB_STYLE_UNDEFINED, /*< desc="Undefined" >*/
+ GIMP_TAB_STYLE_AUTOMATIC /*< desc="Automatic" >*/
} GimpTabStyle;
diff --git a/etc/sessionrc b/etc/sessionrc
index f567316..f41c3bf 100644
--- a/etc/sessionrc
+++ b/etc/sessionrc
@@ -12,7 +12,7 @@
(gimp-toolbox
(book
(dockable "gimp-tool-options"
- (tab-style icon)))))
+ (tab-style automatic)))))
(session-info "dock" "gimp-dock-window"
(position -0 0)
(size 210 820)
@@ -20,21 +20,21 @@
(gimp-dock
(book
(dockable "gimp-layer-list"
- (tab-style icon))
+ (tab-style automatic))
(dockable "gimp-channel-list"
- (tab-style icon))
+ (tab-style automatic))
(dockable "gimp-vectors-list"
- (tab-style icon))
+ (tab-style automatic))
(dockable "gimp-undo-history"
- (tab-style icon)))
+ (tab-style automatic)))
(book
(position 420)
(dockable "gimp-brush-grid"
- (tab-style preview))
+ (tab-style automatic))
(dockable "gimp-pattern-grid"
- (tab-style preview))
+ (tab-style automatic))
(dockable "gimp-gradient-list"
- (tab-style preview)))))
+ (tab-style automatic)))))
(session-info "toplevel"
(factory-entry "gimp-empty-image-window")
(position 410 370)
diff --git a/menus/dockable-menu.xml.in b/menus/dockable-menu.xml.in
index 29301d1..55eff39 100644
--- a/menus/dockable-menu.xml.in
+++ b/menus/dockable-menu.xml.in
@@ -27,6 +27,8 @@
<menuitem action="dockable-tab-style-name" />
<menuitem action="dockable-tab-style-icon-name" />
<menuitem action="dockable-tab-style-preview-name" />
+ <separator />
+ <menuitem action="dockable-tab-style-automatic" />
</menu>
<menuitem action="dockable-view-type-list" />
<menuitem action="dockable-view-type-grid" />
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]