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.
This commit is contained in:
Martin Nordholts 2010-06-11 23:18:49 +02:00
parent 501f97b54b
commit 9b86acd16b
17 changed files with 557 additions and 39 deletions

View File

@ -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);

View File

@ -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',

View File

@ -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 */

View File

@ -67,7 +67,7 @@
(book
(current-page 0)
(dockable "gimp-channel-list"
(tab-style icon)
(tab-style automatic)
(preview-size 32)))
(book
(position 162)

View File

@ -71,7 +71,7 @@
(book
(current-page 0)
(dockable "gimp-channel-list"
(tab-style icon)
(tab-style automatic)
(preview-size 32)))
(book
(position 162)

View File

@ -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)

View File

@ -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 *

View File

@ -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,

View File

@ -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;
@ -254,6 +290,18 @@ gimp_dockbook_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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 */

View File

@ -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 }
};

View File

@ -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;

View File

@ -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)

View File

@ -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" />