diff options
Diffstat (limited to 'gtk/gtktoolitemgroup.c')
-rw-r--r-- | gtk/gtktoolitemgroup.c | 2333 |
1 files changed, 0 insertions, 2333 deletions
diff --git a/gtk/gtktoolitemgroup.c b/gtk/gtktoolitemgroup.c deleted file mode 100644 index f2c9c51051..0000000000 --- a/gtk/gtktoolitemgroup.c +++ /dev/null @@ -1,2333 +0,0 @@ -/* GtkToolPalette -- A tool palette with categories and DnD support - * Copyright (C) 2008 Openismus GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - * Authors: - * Mathias Hasselmann - * Jan Arne Petersen - */ - -#include "config.h" - -#include <math.h> -#include <string.h> - -#include "gtktoolpaletteprivate.h" -#include "gtktypebuiltins.h" -#include "gtkprivate.h" -#include "gtkintl.h" -#include "gtkcssnodeprivate.h" -#include "gtkstylecontextprivate.h" -#include "gtkwidgetprivate.h" - - -#define ANIMATION_TIMEOUT 50 -#define ANIMATION_DURATION (ANIMATION_TIMEOUT * 4) -#define DEFAULT_ANIMATION_STATE TRUE -#define DEFAULT_EXPANDER_SIZE 16 -#define DEFAULT_HEADER_SPACING 2 - -#define DEFAULT_LABEL "" -#define DEFAULT_COLLAPSED FALSE -#define DEFAULT_ELLIPSIZE PANGO_ELLIPSIZE_NONE - -/** - * SECTION:gtktoolitemgroup - * @Short_description: A sub container used in a tool palette - * @Title: GtkToolItemGroup - * - * A #GtkToolItemGroup is used together with #GtkToolPalette to add - * #GtkToolItems to a palette like container with different - * categories and drag and drop support. - * - * # CSS nodes - * - * GtkToolItemGroup has a single CSS node named toolitemgroup. - * - * Since: 2.20 - */ - -enum -{ - PROP_NONE, - PROP_LABEL, - PROP_LABEL_WIDGET, - PROP_COLLAPSED, - PROP_ELLIPSIZE, - PROP_RELIEF -}; - -enum -{ - CHILD_PROP_NONE, - CHILD_PROP_HOMOGENEOUS, - CHILD_PROP_EXPAND, - CHILD_PROP_FILL, - CHILD_PROP_NEW_ROW, - CHILD_PROP_POSITION, -}; - -typedef struct _GtkToolItemGroupChild GtkToolItemGroupChild; - -struct _GtkToolItemGroupPrivate -{ - GtkWidget *header; - GtkWidget *label_widget; - - GtkCssNode *arrow_node; - - GList *children; - - gint64 animation_start; - GSource *animation_timeout; - - gulong focus_set_id; - GtkWidget *toplevel; - - GtkSettings *settings; - gulong settings_connection; - - PangoEllipsizeMode ellipsize; - - guint animation : 1; - guint collapsed : 1; -}; - -struct _GtkToolItemGroupChild -{ - GtkToolItem *item; - - guint homogeneous : 1; - guint expand : 1; - guint fill : 1; - guint new_row : 1; -}; - -static void gtk_tool_item_group_tool_shell_init (GtkToolShellIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GtkToolItemGroup, gtk_tool_item_group, GTK_TYPE_CONTAINER, - G_ADD_PRIVATE (GtkToolItemGroup) - G_IMPLEMENT_INTERFACE (GTK_TYPE_TOOL_SHELL, - gtk_tool_item_group_tool_shell_init)); - -static GtkWidget* -gtk_tool_item_group_get_frame (GtkToolItemGroup *group) -{ - return gtk_bin_get_child (GTK_BIN (group->priv->header)); -} - -static GtkOrientation -gtk_tool_item_group_get_orientation (GtkToolShell *shell) -{ - GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell)); - - if (GTK_IS_TOOL_PALETTE (parent)) - return gtk_orientable_get_orientation (GTK_ORIENTABLE (parent)); - - return GTK_ORIENTATION_VERTICAL; -} - -static GtkToolbarStyle -gtk_tool_item_group_get_style (GtkToolShell *shell) -{ - GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell)); - - if (GTK_IS_TOOL_PALETTE (parent)) - return gtk_tool_palette_get_style (GTK_TOOL_PALETTE (parent)); - - return GTK_TOOLBAR_ICONS; -} - -static PangoEllipsizeMode -gtk_tool_item_group_get_ellipsize_mode (GtkToolShell *shell) -{ - return GTK_TOOL_ITEM_GROUP (shell)->priv->ellipsize; -} - -static gfloat -gtk_tool_item_group_get_text_alignment (GtkToolShell *shell) -{ - if (GTK_TOOLBAR_TEXT == gtk_tool_item_group_get_style (shell) || - GTK_TOOLBAR_BOTH_HORIZ == gtk_tool_item_group_get_style (shell)) - return 0.0; - - return 0.5; -} - -static GtkOrientation -gtk_tool_item_group_get_text_orientation (GtkToolShell *shell) -{ - return GTK_ORIENTATION_HORIZONTAL; -} - -static GtkSizeGroup * -gtk_tool_item_group_get_text_size_group (GtkToolShell *shell) -{ - GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (shell)); - - if (GTK_IS_TOOL_PALETTE (parent)) - return _gtk_tool_palette_get_size_group (GTK_TOOL_PALETTE (parent)); - - return NULL; -} - -static void -animation_change_notify (GtkToolItemGroup *group) -{ - GtkSettings *settings = group->priv->settings; - gboolean animation; - - if (settings) - g_object_get (settings, - "gtk-enable-animations", &animation, - NULL); - else - animation = DEFAULT_ANIMATION_STATE; - - group->priv->animation = animation; -} - -static void -gtk_tool_item_group_settings_change_notify (GtkSettings *settings, - const GParamSpec *pspec, - GtkToolItemGroup *group) -{ - if (strcmp (pspec->name, "gtk-enable-animations") == 0) - animation_change_notify (group); -} - -static void -gtk_tool_item_group_display_changed (GtkWidget *widget, - GdkDisplay *previous_display) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (widget); - GtkToolItemGroupPrivate* priv = group->priv; - GtkSettings *old_settings = priv->settings; - GtkSettings *settings; - - settings = gtk_widget_get_settings (GTK_WIDGET (group)); - - if (settings == old_settings) - return; - - if (old_settings) - { - g_signal_handler_disconnect (old_settings, priv->settings_connection); - priv->settings_connection = 0; - g_object_unref (old_settings); - } - - if (settings) - { - priv->settings_connection = - g_signal_connect (settings, "notify", - G_CALLBACK (gtk_tool_item_group_settings_change_notify), - group); - priv->settings = g_object_ref (settings); - } - else - priv->settings = NULL; - - animation_change_notify (group); -} - -static void -gtk_tool_item_group_tool_shell_init (GtkToolShellIface *iface) -{ - iface->get_orientation = gtk_tool_item_group_get_orientation; - iface->get_style = gtk_tool_item_group_get_style; - iface->get_text_alignment = gtk_tool_item_group_get_text_alignment; - iface->get_text_orientation = gtk_tool_item_group_get_text_orientation; - iface->get_text_size_group = gtk_tool_item_group_get_text_size_group; - iface->get_ellipsize_mode = gtk_tool_item_group_get_ellipsize_mode; -} - -static gboolean -gtk_tool_item_group_header_draw_cb (GtkWidget *widget, - cairo_t *cr, - gpointer data) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (data); - GtkToolItemGroupPrivate* priv = group->priv; - GtkOrientation orientation; - gint x, y, width, height; - GtkTextDirection direction; - GtkStyleContext *context; - - orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group)); - direction = gtk_widget_get_direction (widget); - width = gtk_widget_get_allocated_width (widget); - height = gtk_widget_get_allocated_height (widget); - context = gtk_widget_get_style_context (widget); - - gtk_style_context_save_to_node (context, priv->arrow_node); - - if (GTK_ORIENTATION_VERTICAL == orientation) - { - gtk_style_context_add_class (context, GTK_STYLE_CLASS_VERTICAL); - - if (GTK_TEXT_DIR_RTL == direction) - x = width; - else - x = 0; - - y = height / 2 - (DEFAULT_EXPANDER_SIZE / 2); - } - else - { - gtk_style_context_add_class (context, GTK_STYLE_CLASS_HORIZONTAL); - x = width / 2 - (DEFAULT_EXPANDER_SIZE / 2); - y = 0; - } - - gtk_render_expander (context, cr, x, y, - DEFAULT_EXPANDER_SIZE, - DEFAULT_EXPANDER_SIZE); - - gtk_style_context_restore (context); - - return FALSE; -} - -static void -gtk_tool_item_group_header_clicked_cb (GtkButton *button, - gpointer data) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (data); - GtkToolItemGroupPrivate* priv = group->priv; - GtkWidget *parent = gtk_widget_get_parent (data); - - if (priv->collapsed || - !GTK_IS_TOOL_PALETTE (parent) || - !gtk_tool_palette_get_exclusive (GTK_TOOL_PALETTE (parent), data)) - gtk_tool_item_group_set_collapsed (group, !priv->collapsed); -} - -static void -gtk_tool_item_group_header_adjust_style (GtkToolItemGroup *group) -{ - GtkWidget *frame = gtk_bin_get_child (GTK_BIN (group->priv->header)); - GtkWidget *label_widget = gtk_bin_get_child (GTK_BIN (frame)); - GtkToolItemGroupPrivate* priv = group->priv; - gint dx = 0, dy = 0; - - switch (gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group))) - { - case GTK_ORIENTATION_HORIZONTAL: - dy = DEFAULT_HEADER_SPACING + DEFAULT_EXPANDER_SIZE; - - if (GTK_IS_LABEL (label_widget)) - { - gtk_label_set_ellipsize (GTK_LABEL (label_widget), PANGO_ELLIPSIZE_NONE); - } - break; - - case GTK_ORIENTATION_VERTICAL: - dx = DEFAULT_HEADER_SPACING + DEFAULT_EXPANDER_SIZE; - - if (GTK_IS_LABEL (label_widget)) - { - gtk_label_set_ellipsize (GTK_LABEL (label_widget), priv->ellipsize); - } - break; - - default: - g_assert_not_reached (); - break; - } - - gtk_widget_set_margin_start (frame, dx); - gtk_widget_set_margin_top (frame, dy); -} - -static void -update_arrow_state (GtkToolItemGroup *group) -{ - GtkToolItemGroupPrivate *priv = group->priv; - GtkStateFlags state; - - state = gtk_widget_get_state_flags (GTK_WIDGET (group)); - - if (priv->collapsed) - state &= ~GTK_STATE_FLAG_CHECKED; - else - state |= GTK_STATE_FLAG_CHECKED; - gtk_css_node_set_state (priv->arrow_node, state); -} - -static void -gtk_tool_item_group_init (GtkToolItemGroup *group) -{ - GtkWidget *frame; - GtkToolItemGroupPrivate* priv; - GtkCssNode *widget_node; - - gtk_widget_set_has_window (GTK_WIDGET (group), FALSE); - - group->priv = priv = gtk_tool_item_group_get_instance_private (group); - - priv->children = NULL; - priv->collapsed = DEFAULT_COLLAPSED; - - priv->label_widget = gtk_label_new (NULL); - gtk_widget_set_halign (priv->label_widget, GTK_ALIGN_START); - gtk_widget_set_valign (priv->label_widget, GTK_ALIGN_CENTER); - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); - gtk_container_add (GTK_CONTAINER (frame), priv->label_widget); - - priv->header = gtk_button_new (); - g_object_ref_sink (priv->header); - gtk_widget_set_focus_on_click (priv->header, FALSE); - gtk_container_add (GTK_CONTAINER (priv->header), frame); - gtk_widget_set_parent (priv->header, GTK_WIDGET (group)); - - gtk_tool_item_group_header_adjust_style (group); - - g_signal_connect_after (frame, "draw", - G_CALLBACK (gtk_tool_item_group_header_draw_cb), - group); - - g_signal_connect (priv->header, "clicked", - G_CALLBACK (gtk_tool_item_group_header_clicked_cb), - group); - - widget_node = gtk_widget_get_css_node (GTK_WIDGET (group)); - priv->arrow_node = gtk_css_node_new (); - gtk_css_node_set_name (priv->arrow_node, I_("arrow")); - gtk_css_node_set_parent (priv->arrow_node, widget_node); - gtk_css_node_set_state (priv->arrow_node, gtk_css_node_get_state (widget_node)); - g_object_unref (priv->arrow_node); - - update_arrow_state (group); -} - -static void -gtk_tool_item_group_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (object); - - switch (prop_id) - { - case PROP_LABEL: - gtk_tool_item_group_set_label (group, g_value_get_string (value)); - break; - - case PROP_LABEL_WIDGET: - gtk_tool_item_group_set_label_widget (group, g_value_get_object (value)); - break; - - case PROP_COLLAPSED: - gtk_tool_item_group_set_collapsed (group, g_value_get_boolean (value)); - break; - - case PROP_ELLIPSIZE: - gtk_tool_item_group_set_ellipsize (group, g_value_get_enum (value)); - break; - - case PROP_RELIEF: - gtk_tool_item_group_set_header_relief (group, g_value_get_enum(value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_tool_item_group_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (object); - - switch (prop_id) - { - case PROP_LABEL: - g_value_set_string (value, gtk_tool_item_group_get_label (group)); - break; - - case PROP_LABEL_WIDGET: - g_value_set_object (value, - gtk_tool_item_group_get_label_widget (group)); - break; - - case PROP_COLLAPSED: - g_value_set_boolean (value, gtk_tool_item_group_get_collapsed (group)); - break; - - case PROP_ELLIPSIZE: - g_value_set_enum (value, gtk_tool_item_group_get_ellipsize (group)); - break; - - case PROP_RELIEF: - g_value_set_enum (value, gtk_tool_item_group_get_header_relief (group)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_tool_item_group_finalize (GObject *object) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (object); - - g_list_free (group->priv->children); - - G_OBJECT_CLASS (gtk_tool_item_group_parent_class)->finalize (object); -} - -static void -gtk_tool_item_group_dispose (GObject *object) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (object); - GtkToolItemGroupPrivate* priv = group->priv; - - if (priv->toplevel) - { - /* disconnect focus tracking handler */ - g_signal_handler_disconnect (priv->toplevel, - priv->focus_set_id); - - priv->focus_set_id = 0; - priv->toplevel = NULL; - } - - if (priv->settings_connection > 0) - { - g_signal_handler_disconnect (priv->settings, priv->settings_connection); - priv->settings_connection = 0; - } - - g_clear_object (&priv->settings); - if (priv->header) - gtk_widget_unparent (priv->header); - g_clear_object (&priv->header); - - G_OBJECT_CLASS (gtk_tool_item_group_parent_class)->dispose (object); -} - -static void -gtk_tool_item_group_get_item_size (GtkToolItemGroup *group, - GtkRequisition *item_size, - gboolean homogeneous_only, - gint *requested_rows) -{ - GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (group)); - - if (GTK_IS_TOOL_PALETTE (parent)) - _gtk_tool_palette_get_item_size (GTK_TOOL_PALETTE (parent), item_size, homogeneous_only, requested_rows); - else - _gtk_tool_item_group_item_size_request (group, item_size, homogeneous_only, requested_rows); -} - -static void -gtk_tool_item_group_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (widget); - GtkToolItemGroupPrivate* priv = group->priv; - GtkOrientation orientation; - GtkRequisition item_size; - gint requested_rows; - - if (priv->children && gtk_tool_item_group_get_label_widget (group)) - { - gtk_widget_get_preferred_size (priv->header, - requisition, NULL); - gtk_widget_show (priv->header); - } - else - { - requisition->width = requisition->height = 0; - gtk_widget_hide (priv->header); - } - - gtk_tool_item_group_get_item_size (group, &item_size, FALSE, &requested_rows); - - orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group)); - - if (GTK_ORIENTATION_VERTICAL == orientation) - requisition->width = MAX (requisition->width, item_size.width); - else - requisition->height = MAX (requisition->height, item_size.height * requested_rows); -} - -static void -gtk_tool_item_group_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - GtkRequisition requisition; - - gtk_tool_item_group_size_request (widget, &requisition); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - *minimum = *natural = requisition.width; - else - *minimum = *natural = requisition.height; -} - -static gboolean -gtk_tool_item_group_is_item_visible (GtkToolItemGroup *group, - GtkToolItemGroupChild *child) -{ - GtkToolbarStyle style; - GtkOrientation orientation; - - orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group)); - style = gtk_tool_shell_get_style (GTK_TOOL_SHELL (group)); - - /* horizontal tool palettes with text style support only homogeneous items */ - if (!child->homogeneous && - GTK_ORIENTATION_HORIZONTAL == orientation && - GTK_TOOLBAR_TEXT == style) - return FALSE; - - return - (gtk_widget_get_visible (GTK_WIDGET (child->item))) && - (GTK_ORIENTATION_VERTICAL == orientation ? - gtk_tool_item_get_visible_vertical (child->item) : - gtk_tool_item_get_visible_horizontal (child->item)); -} - -static inline unsigned -udiv (unsigned x, - unsigned y) -{ - return (x + y - 1) / y; -} - -static void -gtk_tool_item_group_real_size_query (GtkWidget *widget, - GtkAllocation *allocation, - GtkRequisition *inquery) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (widget); - GtkToolItemGroupPrivate* priv = group->priv; - - GtkRequisition item_size; - GtkAllocation item_area; - - GtkOrientation orientation; - - gint min_rows; - - orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group)); - - /* figure out the size of homogeneous items */ - gtk_tool_item_group_get_item_size (group, &item_size, TRUE, &min_rows); - - if (GTK_ORIENTATION_VERTICAL == orientation) - item_size.width = MIN (item_size.width, allocation->width); - else - item_size.height = MIN (item_size.height, allocation->height); - - item_size.width = MAX (item_size.width, 1); - item_size.height = MAX (item_size.height, 1); - - item_area.width = 0; - item_area.height = 0; - - /* figure out the required columns (n_columns) and rows (n_rows) - * to place all items - */ - if (!priv->collapsed || !priv->animation || priv->animation_timeout) - { - guint n_columns; - gint n_rows; - GList *it; - - if (GTK_ORIENTATION_VERTICAL == orientation) - { - gboolean new_row = FALSE; - gint row = -1; - guint col = 0; - - item_area.width = allocation->width; - n_columns = MAX (item_area.width / item_size.width, 1); - - /* calculate required rows for n_columns columns */ - for (it = priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - - if (!gtk_tool_item_group_is_item_visible (group, child)) - continue; - - if (new_row || child->new_row) - { - new_row = FALSE; - row++; - col = 0; - } - - if (child->expand) - new_row = TRUE; - - if (child->homogeneous) - { - col++; - if (col >= n_columns) - new_row = TRUE; - } - else - { - GtkRequisition req = {0, 0}; - guint width; - - gtk_widget_get_preferred_size (GTK_WIDGET (child->item), - &req, NULL); - - width = udiv (req.width, item_size.width); - col += width; - - if (col > n_columns) - row++; - - col = width; - - if (col >= n_columns) - new_row = TRUE; - } - } - n_rows = row + 2; - } - else - { - guint *row_min_width; - gint row = -1; - gboolean new_row = TRUE; - guint col = 0, min_col, max_col = 0, all_items = 0; - gint i; - - item_area.height = allocation->height; - n_rows = MAX (item_area.height / item_size.height, min_rows); - - row_min_width = g_new0 (guint, n_rows); - - /* calculate minimal and maximal required cols and minimal - * required rows - */ - for (it = priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - - if (!gtk_tool_item_group_is_item_visible (group, child)) - continue; - - if (new_row || child->new_row) - { - new_row = FALSE; - row++; - col = 0; - row_min_width[row] = 1; - } - - if (child->expand) - new_row = TRUE; - - if (child->homogeneous) - { - col++; - all_items++; - } - else - { - GtkRequisition req = {0, 0}; - guint width; - - gtk_widget_get_preferred_size (GTK_WIDGET (child->item), - &req, NULL); - - width = udiv (req.width, item_size.width); - - col += width; - all_items += width; - - row_min_width[row] = MAX (row_min_width[row], width); - } - - max_col = MAX (max_col, col); - } - - /* calculate minimal required cols */ - min_col = udiv (all_items, n_rows); - - for (i = 0; i <= row; i++) - { - min_col = MAX (min_col, row_min_width[i]); - } - - /* simple linear search for minimal required columns - * for the given maximal number of rows (n_rows) - */ - for (n_columns = min_col; n_columns < max_col; n_columns ++) - { - new_row = TRUE; - row = -1; - /* calculate required rows for n_columns columns */ - for (it = priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - - if (!gtk_tool_item_group_is_item_visible (group, child)) - continue; - - if (new_row || child->new_row) - { - new_row = FALSE; - row++; - col = 0; - } - - if (child->expand) - new_row = TRUE; - - if (child->homogeneous) - { - col++; - if (col >= n_columns) - new_row = TRUE; - } - else - { - GtkRequisition req = {0, 0}; - guint width; - - gtk_widget_get_preferred_size (GTK_WIDGET (child->item), - &req, NULL); - - width = udiv (req.width, item_size.width); - col += width; - - if (col > n_columns) - row++; - - col = width; - - if (col >= n_columns) - new_row = TRUE; - } - } - - if (row < n_rows) - break; - } - } - - item_area.width = item_size.width * n_columns; - item_area.height = item_size.height * n_rows; - } - - inquery->width = 0; - inquery->height = 0; - - /* figure out header widget size */ - if (gtk_widget_get_visible (priv->header)) - { - GtkRequisition child_requisition; - - gtk_widget_get_preferred_size (priv->header, - &child_requisition, NULL); - - if (GTK_ORIENTATION_VERTICAL == orientation) - inquery->height += child_requisition.height; - else - inquery->width += child_requisition.width; - } - - /* report effective widget size */ - inquery->width += item_area.width; - inquery->height += item_area.height; -} - -static void -gtk_tool_item_group_real_size_allocate (GtkWidget *widget, - const GtkAllocation *allocation, - int baseline, - GtkAllocation *out_clip) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (widget); - GtkToolItemGroupPrivate* priv = group->priv; - GtkRequisition child_requisition; - GtkAllocation child_allocation; - - GtkRequisition item_size; - GtkAllocation item_area; - - GtkOrientation orientation; - - GList *it; - - gint n_columns, n_rows = 1; - gint min_rows; - GtkTextDirection direction; - - direction = gtk_widget_get_direction (widget); - - orientation = gtk_tool_shell_get_orientation (GTK_TOOL_SHELL (group)); - - /* chain up */ - GTK_WIDGET_CLASS (gtk_tool_item_group_parent_class)->size_allocate (widget, allocation, - baseline, out_clip); - - child_allocation.x = 0; - child_allocation.y = 0; - - /* place the header widget */ - if (gtk_widget_get_visible (priv->header)) - { - gtk_widget_get_preferred_size (priv->header, - &child_requisition, NULL); - - if (GTK_ORIENTATION_VERTICAL == orientation) - { - child_allocation.width = allocation->width; - child_allocation.height = child_requisition.height; - } - else - { - child_allocation.width = child_requisition.width; - child_allocation.height = allocation->height; - - if (GTK_TEXT_DIR_RTL == direction) - child_allocation.x = allocation->width - child_allocation.width; - } - - gtk_widget_size_allocate (priv->header, &child_allocation, -1, out_clip); - - if (GTK_ORIENTATION_VERTICAL == orientation) - child_allocation.y += child_allocation.height; - else if (GTK_TEXT_DIR_RTL != direction) - child_allocation.x += child_allocation.width; - else - child_allocation.x = 0; - } - else - child_requisition.width = child_requisition.height = 0; - - /* figure out the size of homogeneous items */ - gtk_tool_item_group_get_item_size (group, &item_size, TRUE, &min_rows); - - item_size.width = MAX (item_size.width, 1); - item_size.height = MAX (item_size.height, 1); - - /* figure out the available columns and size of item_area */ - if (GTK_ORIENTATION_VERTICAL == orientation) - { - item_size.width = MIN (item_size.width, allocation->width); - - item_area.width = allocation->width; - item_area.height = allocation->height - child_requisition.height; - - n_columns = MAX (item_area.width / item_size.width, 1); - - item_size.width = item_area.width / n_columns; - } - else - { - item_size.height = MIN (item_size.height, allocation->height); - - item_area.width = allocation->width - child_requisition.width; - item_area.height = allocation->height; - - n_columns = MAX (item_area.width / item_size.width, 1); - n_rows = MAX (item_area.height / item_size.height, min_rows); - - item_size.height = item_area.height / n_rows; - } - - item_area.x = child_allocation.x; - item_area.y = child_allocation.y; - - /* when expanded or in transition, place the tool items in a grid like layout */ - if (!priv->collapsed || !priv->animation || priv->animation_timeout) - { - gint col = 0, row = 0; - - for (it = priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - gint col_child; - - if (!gtk_tool_item_group_is_item_visible (group, child)) - { - gtk_widget_set_child_visible (GTK_WIDGET (child->item), FALSE); - - continue; - } - - /* for non homogeneous widgets request the required size */ - child_requisition.width = 0; - - if (!child->homogeneous) - { - gtk_widget_get_preferred_size (GTK_WIDGET (child->item), - &child_requisition, NULL); - child_requisition.width = MIN (child_requisition.width, item_area.width); - } - - /* select next row if at end of row */ - if (col > 0 && (child->new_row || (col * item_size.width) + MAX (child_requisition.width, item_size.width) > item_area.width)) - { - row++; - col = 0; - child_allocation.y += child_allocation.height; - } - - col_child = col; - - /* calculate the position and size of the item */ - if (!child->homogeneous) - { - gint col_width; - gint width; - - if (!child->expand) - col_width = udiv (child_requisition.width, item_size.width); - else - col_width = n_columns - col; - - width = col_width * item_size.width; - - if (GTK_TEXT_DIR_RTL == direction) - col_child = (n_columns - col - col_width); - - if (child->fill) - { - child_allocation.x = item_area.x + col_child * item_size.width; - child_allocation.width = width; - } - else - { - child_allocation.x = - (item_area.x + col_child * item_size.width + - (width - child_requisition.width) / 2); - child_allocation.width = child_requisition.width; - } - - col += col_width; - } - else - { - if (GTK_TEXT_DIR_RTL == direction) - col_child = (n_columns - col - 1); - - child_allocation.x = item_area.x + col_child * item_size.width; - child_allocation.width = item_size.width; - - col++; - } - - child_allocation.height = item_size.height; - - gtk_widget_size_allocate (GTK_WIDGET (child->item), &child_allocation, -1, out_clip); - gtk_widget_set_child_visible (GTK_WIDGET (child->item), TRUE); - } - - child_allocation.y += item_size.height; - } - - /* or just hide all items, when collapsed */ - - else - { - for (it = priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - - gtk_widget_set_child_visible (GTK_WIDGET (child->item), FALSE); - } - } -} - -static void -gtk_tool_item_group_size_allocate (GtkWidget *widget, - const GtkAllocation *allocation, - int baseline, - GtkAllocation *out_clip) -{ - gtk_tool_item_group_real_size_allocate (widget, allocation, baseline, out_clip); -} - -static void -gtk_tool_item_group_set_focus_cb (GtkWidget *window, - GtkWidget *widget, - gpointer user_data) -{ - GtkAdjustment *adjustment; - GtkAllocation allocation, p_allocation; - GtkWidget *p; - - /* Find this group's parent widget in the focused widget's anchestry. */ - for (p = widget; p; p = gtk_widget_get_parent (p)) - if (p == user_data) - { - p = gtk_widget_get_parent (p); - break; - } - - if (GTK_IS_TOOL_PALETTE (p)) - { - /* Check that the focused widgets is fully visible within - * the group's parent widget and make it visible otherwise. */ - - adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (p)); - - if (adjustment) - { - int y; - - gtk_widget_get_allocation (widget, &allocation); - gtk_widget_get_allocation (p, &p_allocation); - - /* Handle vertical adjustment. */ - if (gtk_widget_translate_coordinates - (widget, p, 0, 0, NULL, &y) && y < 0) - { - y += gtk_adjustment_get_value (adjustment); - gtk_adjustment_clamp_page (adjustment, y, y + allocation.height); - } - else if (gtk_widget_translate_coordinates (widget, p, 0, allocation.height, NULL, &y) && - y > p_allocation.height) - { - y += gtk_adjustment_get_value (adjustment); - gtk_adjustment_clamp_page (adjustment, y - allocation.height, y); - } - } - - adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (p)); - - if (adjustment) - { - int x; - - gtk_widget_get_allocation (widget, &allocation); - gtk_widget_get_allocation (p, &p_allocation); - - /* Handle horizontal adjustment. */ - if (gtk_widget_translate_coordinates - (widget, p, 0, 0, &x, NULL) && x < 0) - { - x += gtk_adjustment_get_value (adjustment); - gtk_adjustment_clamp_page (adjustment, x, x + allocation.width); - } - else if (gtk_widget_translate_coordinates (widget, p, allocation.width, 0, &x, NULL) && - x > p_allocation.width) - { - x += gtk_adjustment_get_value (adjustment); - gtk_adjustment_clamp_page (adjustment, x - allocation.width, x); - } - - return; - } - } -} - -static void -gtk_tool_item_group_set_toplevel_window (GtkToolItemGroup *group, - GtkWidget *toplevel) -{ - GtkToolItemGroupPrivate* priv = group->priv; - - if (toplevel != priv->toplevel) - { - if (priv->toplevel) - { - /* Disconnect focus tracking handler. */ - g_signal_handler_disconnect (priv->toplevel, - priv->focus_set_id); - - priv->focus_set_id = 0; - priv->toplevel = NULL; - } - - if (toplevel) - { - /* Install focus tracking handler. We connect to the window's - * set-focus signal instead of connecting to the focus signal of - * each child to: - * - * 1) Reduce the number of signal handlers used. - * 2) Avoid special handling for group headers. - * 3) Catch focus grabs not only for direct children, - * but also for nested widgets. - */ - priv->focus_set_id = - g_signal_connect (toplevel, "set-focus", - G_CALLBACK (gtk_tool_item_group_set_focus_cb), - group); - - priv->toplevel = toplevel; - } - } -} - -static void -gtk_tool_item_group_realize (GtkWidget *widget) -{ - GtkWidget *toplevel_window; - - GTK_WIDGET_CLASS (gtk_tool_item_group_parent_class)->realize (widget); - - toplevel_window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); - gtk_tool_item_group_set_toplevel_window (GTK_TOOL_ITEM_GROUP (widget), - toplevel_window); -} - -static void -gtk_tool_item_group_unrealize (GtkWidget *widget) -{ - gtk_tool_item_group_set_toplevel_window (GTK_TOOL_ITEM_GROUP (widget), NULL); - GTK_WIDGET_CLASS (gtk_tool_item_group_parent_class)->unrealize (widget); -} - -static void -gtk_tool_item_group_style_updated (GtkWidget *widget) -{ - gtk_tool_item_group_header_adjust_style (GTK_TOOL_ITEM_GROUP (widget)); - GTK_WIDGET_CLASS (gtk_tool_item_group_parent_class)->style_updated (widget); -} - -static void -gtk_tool_item_group_state_flags_changed (GtkWidget *widget, - GtkStateFlags previous_flags) -{ - update_arrow_state (GTK_TOOL_ITEM_GROUP (widget)); -} - -static void -gtk_tool_item_group_add (GtkContainer *container, - GtkWidget *widget) -{ - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (container)); - g_return_if_fail (GTK_IS_TOOL_ITEM (widget)); - - gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (container), - GTK_TOOL_ITEM (widget), -1); -} - -static void -gtk_tool_item_group_remove (GtkContainer *container, - GtkWidget *child) -{ - GtkToolItemGroup *group; - GtkToolItemGroupPrivate* priv; - GList *it; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (container)); - group = GTK_TOOL_ITEM_GROUP (container); - priv = group->priv; - - for (it = priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child_info = it->data; - - if ((GtkWidget *)child_info->item == child) - { - g_object_unref (child); - gtk_widget_unparent (child); - - g_free (child_info); - priv->children = g_list_delete_link (priv->children, it); - - gtk_widget_queue_resize (GTK_WIDGET (container)); - break; - } - } -} - -static void -gtk_tool_item_group_forall (GtkContainer *container, - GtkCallback callback, - gpointer callback_data) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (container); - GtkToolItemGroupPrivate* priv = group->priv; - GList *children; - - children = priv->children; - while (children) - { - GtkToolItemGroupChild *child = children->data; - children = children->next; /* store pointer before call to callback - because the child pointer is invalid if the - child->item is removed from the item group - in callback */ - - callback (GTK_WIDGET (child->item), callback_data); - } -} - -static GType -gtk_tool_item_group_child_type (GtkContainer *container) -{ - return GTK_TYPE_TOOL_ITEM; -} - -static GtkToolItemGroupChild * -gtk_tool_item_group_get_child (GtkToolItemGroup *group, - GtkToolItem *item, - gint *position, - GList **link) -{ - guint i; - GList *it; - - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), NULL); - g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), NULL); - - for (it = group->priv->children, i = 0; it != NULL; it = it->next, ++i) - { - GtkToolItemGroupChild *child = it->data; - - if (child->item == item) - { - if (position) - *position = i; - - if (link) - *link = it; - - return child; - } - } - - return NULL; -} - -static void -gtk_tool_item_group_get_item_packing (GtkToolItemGroup *group, - GtkToolItem *item, - gboolean *homogeneous, - gboolean *expand, - gboolean *fill, - gboolean *new_row) -{ - GtkToolItemGroupChild *child; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - g_return_if_fail (GTK_IS_TOOL_ITEM (item)); - - child = gtk_tool_item_group_get_child (group, item, NULL, NULL); - if (!child) - return; - - if (expand) - *expand = child->expand; - - if (homogeneous) - *homogeneous = child->homogeneous; - - if (fill) - *fill = child->fill; - - if (new_row) - *new_row = child->new_row; -} - -static void -gtk_tool_item_group_set_item_packing (GtkToolItemGroup *group, - GtkToolItem *item, - gboolean homogeneous, - gboolean expand, - gboolean fill, - gboolean new_row) -{ - GtkToolItemGroupChild *child; - gboolean changed = FALSE; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - g_return_if_fail (GTK_IS_TOOL_ITEM (item)); - - child = gtk_tool_item_group_get_child (group, item, NULL, NULL); - if (!child) - return; - - gtk_widget_freeze_child_notify (GTK_WIDGET (item)); - - if (child->homogeneous != homogeneous) - { - child->homogeneous = homogeneous; - changed = TRUE; - gtk_widget_child_notify (GTK_WIDGET (item), "homogeneous"); - } - if (child->expand != expand) - { - child->expand = expand; - changed = TRUE; - gtk_widget_child_notify (GTK_WIDGET (item), "expand"); - } - if (child->fill != fill) - { - child->fill = fill; - changed = TRUE; - gtk_widget_child_notify (GTK_WIDGET (item), "fill"); - } - if (child->new_row != new_row) - { - child->new_row = new_row; - changed = TRUE; - gtk_widget_child_notify (GTK_WIDGET (item), "new-row"); - } - - gtk_widget_thaw_child_notify (GTK_WIDGET (item)); - - if (changed - && gtk_widget_get_visible (GTK_WIDGET (group)) - && gtk_widget_get_visible (GTK_WIDGET (item))) - gtk_widget_queue_resize (GTK_WIDGET (group)); -} - -static void -gtk_tool_item_group_set_child_property (GtkContainer *container, - GtkWidget *child, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (container); - GtkToolItem *item = GTK_TOOL_ITEM (child); - gboolean homogeneous, expand, fill, new_row; - - if (prop_id != CHILD_PROP_POSITION) - gtk_tool_item_group_get_item_packing (group, item, - &homogeneous, - &expand, - &fill, - &new_row); - - switch (prop_id) - { - case CHILD_PROP_HOMOGENEOUS: - gtk_tool_item_group_set_item_packing (group, item, - g_value_get_boolean (value), - expand, - fill, - new_row); - break; - - case CHILD_PROP_EXPAND: - gtk_tool_item_group_set_item_packing (group, item, - homogeneous, - g_value_get_boolean (value), - fill, - new_row); - break; - - case CHILD_PROP_FILL: - gtk_tool_item_group_set_item_packing (group, item, - homogeneous, - expand, - g_value_get_boolean (value), - new_row); - break; - - case CHILD_PROP_NEW_ROW: - gtk_tool_item_group_set_item_packing (group, item, - homogeneous, - expand, - fill, - g_value_get_boolean (value)); - break; - - case CHILD_PROP_POSITION: - gtk_tool_item_group_set_item_position (group, item, g_value_get_int (value)); - break; - - default: - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec); - break; - } -} - -static void -gtk_tool_item_group_get_child_property (GtkContainer *container, - GtkWidget *child, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (container); - GtkToolItem *item = GTK_TOOL_ITEM (child); - gboolean homogeneous, expand, fill, new_row; - - if (prop_id != CHILD_PROP_POSITION) - gtk_tool_item_group_get_item_packing (group, item, - &homogeneous, - &expand, - &fill, - &new_row); - - switch (prop_id) - { - case CHILD_PROP_HOMOGENEOUS: - g_value_set_boolean (value, homogeneous); - break; - - case CHILD_PROP_EXPAND: - g_value_set_boolean (value, expand); - break; - - case CHILD_PROP_FILL: - g_value_set_boolean (value, fill); - break; - - case CHILD_PROP_NEW_ROW: - g_value_set_boolean (value, new_row); - break; - - case CHILD_PROP_POSITION: - g_value_set_int (value, gtk_tool_item_group_get_item_position (group, item)); - break; - - default: - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec); - break; - } -} - -static void -gtk_tool_item_group_class_init (GtkToolItemGroupClass *cls) -{ - GObjectClass *oclass = G_OBJECT_CLASS (cls); - GtkWidgetClass *wclass = GTK_WIDGET_CLASS (cls); - GtkContainerClass *cclass = GTK_CONTAINER_CLASS (cls); - - oclass->set_property = gtk_tool_item_group_set_property; - oclass->get_property = gtk_tool_item_group_get_property; - oclass->finalize = gtk_tool_item_group_finalize; - oclass->dispose = gtk_tool_item_group_dispose; - - wclass->measure = gtk_tool_item_group_measure; - wclass->size_allocate = gtk_tool_item_group_size_allocate; - wclass->realize = gtk_tool_item_group_realize; - wclass->unrealize = gtk_tool_item_group_unrealize; - wclass->style_updated = gtk_tool_item_group_style_updated; - wclass->display_changed = gtk_tool_item_group_display_changed; - wclass->state_flags_changed = gtk_tool_item_group_state_flags_changed; - - cclass->add = gtk_tool_item_group_add; - cclass->remove = gtk_tool_item_group_remove; - cclass->forall = gtk_tool_item_group_forall; - cclass->child_type = gtk_tool_item_group_child_type; - cclass->set_child_property = gtk_tool_item_group_set_child_property; - cclass->get_child_property = gtk_tool_item_group_get_child_property; - - g_object_class_install_property (oclass, PROP_LABEL, - g_param_spec_string ("label", - P_("Label"), - P_("The human-readable title of this item group"), - DEFAULT_LABEL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (oclass, PROP_LABEL_WIDGET, - g_param_spec_object ("label-widget", - P_("Label widget"), - P_("A widget to display in place of the usual label"), - GTK_TYPE_WIDGET, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (oclass, PROP_COLLAPSED, - g_param_spec_boolean ("collapsed", - P_("Collapsed"), - P_("Whether the group has been collapsed and items are hidden"), - DEFAULT_COLLAPSED, - GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); - - g_object_class_install_property (oclass, PROP_ELLIPSIZE, - g_param_spec_enum ("ellipsize", - P_("ellipsize"), - P_("Ellipsize for item group headers"), - PANGO_TYPE_ELLIPSIZE_MODE, DEFAULT_ELLIPSIZE, - GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); - - g_object_class_install_property (oclass, PROP_RELIEF, - g_param_spec_enum ("header-relief", - P_("Header Relief"), - P_("Relief of the group header button"), - GTK_TYPE_RELIEF_STYLE, GTK_RELIEF_NORMAL, - GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); - - gtk_container_class_install_child_property (cclass, CHILD_PROP_HOMOGENEOUS, - g_param_spec_boolean ("homogeneous", - P_("Homogeneous"), - P_("Whether the item should be the same size as other homogeneous items"), - TRUE, - GTK_PARAM_READWRITE)); - - gtk_container_class_install_child_property (cclass, CHILD_PROP_EXPAND, - g_param_spec_boolean ("expand", - P_("Expand"), - P_("Whether the item should receive extra space when the group grows"), - FALSE, - GTK_PARAM_READWRITE)); - - gtk_container_class_install_child_property (cclass, CHILD_PROP_FILL, - g_param_spec_boolean ("fill", - P_("Fill"), - P_("Whether the item should fill the available space"), - TRUE, - GTK_PARAM_READWRITE)); - - gtk_container_class_install_child_property (cclass, CHILD_PROP_NEW_ROW, - g_param_spec_boolean ("new-row", - P_("New Row"), - P_("Whether the item should start a new row"), - FALSE, - GTK_PARAM_READWRITE)); - - gtk_container_class_install_child_property (cclass, CHILD_PROP_POSITION, - g_param_spec_int ("position", - P_("Position"), - P_("Position of the item within this group"), - 0, - G_MAXINT, - 0, - GTK_PARAM_READWRITE)); - - gtk_widget_class_set_css_name (wclass, I_("toolitemgroup")); -} - -/** - * gtk_tool_item_group_new: - * @label: the label of the new group - * - * Creates a new tool item group with label @label. - * - * Returns: a new #GtkToolItemGroup. - * - * Since: 2.20 - */ -GtkWidget* -gtk_tool_item_group_new (const gchar *label) -{ - return g_object_new (GTK_TYPE_TOOL_ITEM_GROUP, "label", label, NULL); -} - -/** - * gtk_tool_item_group_set_label: - * @group: a #GtkToolItemGroup - * @label: the new human-readable label of of the group - * - * Sets the label of the tool item group. The label is displayed in the header - * of the group. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_set_label (GtkToolItemGroup *group, - const gchar *label) -{ - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - - if (!label) - gtk_tool_item_group_set_label_widget (group, NULL); - else - { - GtkWidget *child = gtk_label_new (label); - gtk_widget_show (child); - - gtk_tool_item_group_set_label_widget (group, child); - } - - g_object_notify (G_OBJECT (group), "label"); -} - -/** - * gtk_tool_item_group_set_label_widget: - * @group: a #GtkToolItemGroup - * @label_widget: the widget to be displayed in place of the usual label - * - * Sets the label of the tool item group. - * The label widget is displayed in the header of the group, in place - * of the usual label. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_set_label_widget (GtkToolItemGroup *group, - GtkWidget *label_widget) -{ - GtkToolItemGroupPrivate* priv; - GtkWidget *frame; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget)); - g_return_if_fail (label_widget == NULL || gtk_widget_get_parent (label_widget) == NULL); - - priv = group->priv; - - if (priv->label_widget == label_widget) - return; - - frame = gtk_tool_item_group_get_frame (group); - - if (priv->label_widget) - { - gtk_widget_set_state_flags (priv->label_widget, 0, TRUE); - gtk_container_remove (GTK_CONTAINER (frame), priv->label_widget); - } - - - if (label_widget) - gtk_container_add (GTK_CONTAINER (frame), label_widget); - - priv->label_widget = label_widget; - - if (gtk_widget_get_visible (GTK_WIDGET (group))) - gtk_widget_queue_resize (GTK_WIDGET (group)); - - /* Only show the header widget if the group has children: */ - if (label_widget && priv->children) - gtk_widget_show (priv->header); - else - gtk_widget_hide (priv->header); - - g_object_freeze_notify (G_OBJECT (group)); - g_object_notify (G_OBJECT (group), "label-widget"); - g_object_notify (G_OBJECT (group), "label"); - g_object_thaw_notify (G_OBJECT (group)); -} - -/** - * gtk_tool_item_group_set_header_relief: - * @group: a #GtkToolItemGroup - * @style: the #GtkReliefStyle - * - * Set the button relief of the group header. - * See gtk_button_set_relief() for details. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_set_header_relief (GtkToolItemGroup *group, - GtkReliefStyle style) -{ - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - - if (gtk_button_get_relief (GTK_BUTTON (group->priv->header)) != style) - { - gtk_button_set_relief (GTK_BUTTON (group->priv->header), style); - g_object_notify (G_OBJECT (group), "header-relief"); - } -} - -static gint64 -gtk_tool_item_group_get_animation_timestamp (GtkToolItemGroup *group) -{ - return (g_source_get_time (group->priv->animation_timeout) - - group->priv->animation_start) / 1000; -} - -static void -gtk_tool_item_group_force_expose (GtkToolItemGroup *group) -{ - GtkToolItemGroupPrivate* priv = group->priv; - GtkWidget *widget = GTK_WIDGET (group); - - if (gtk_widget_get_realized (priv->header)) - { - GtkAllocation frame_allocation; - GtkWidget *frame = gtk_tool_item_group_get_frame (group); - - /* Find the header button's arrow area and - * invalidate it to get it animated. */ - gtk_widget_get_allocation (frame, &frame_allocation); - gtk_widget_queue_draw_area (priv->header, - frame_allocation.x, - frame_allocation.y + (frame_allocation.height - DEFAULT_EXPANDER_SIZE) / 2, - DEFAULT_EXPANDER_SIZE, - DEFAULT_EXPANDER_SIZE); - } - - if (gtk_widget_get_realized (widget)) - { - GtkAllocation allocation; - GtkWidget *parent = gtk_widget_get_parent (widget); - int x, y, width, height; - - /* Find the tool item area button's arrow area... */ - gtk_widget_get_allocation (widget, &allocation); - width = allocation.width; - height = allocation.height; - - gtk_widget_translate_coordinates (widget, parent, 0, 0, &x, &y); - - if (gtk_widget_get_visible (priv->header)) - { - GtkAllocation header_allocation; - - gtk_widget_get_allocation (priv->header, &header_allocation); - height -= header_allocation.height; - y += header_allocation.height; - } - - /* ... and invalidated it to get it animated. */ - gtk_widget_queue_draw_area (parent, x, y, width, height); - } -} - -static gboolean -gtk_tool_item_group_animation_cb (gpointer data) -{ - GtkToolItemGroup *group = GTK_TOOL_ITEM_GROUP (data); - GtkToolItemGroupPrivate* priv = group->priv; - gint64 timestamp = gtk_tool_item_group_get_animation_timestamp (group); - gboolean retval; - - gdk_threads_enter (); - - /* Enque this early to reduce number of expose events. */ - gtk_widget_queue_resize_no_redraw (GTK_WIDGET (group)); - - gtk_tool_item_group_force_expose (group); - - /* Finish animation when done. */ - if (timestamp >= ANIMATION_DURATION) - priv->animation_timeout = NULL; - - retval = (priv->animation_timeout != NULL); - - gdk_threads_leave (); - - return retval; -} - -/** - * gtk_tool_item_group_set_collapsed: - * @group: a #GtkToolItemGroup - * @collapsed: whether the @group should be collapsed or expanded - * - * Sets whether the @group should be collapsed or expanded. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_set_collapsed (GtkToolItemGroup *group, - gboolean collapsed) -{ - GtkWidget *parent; - GtkToolItemGroupPrivate* priv; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - - priv = group->priv; - - parent = gtk_widget_get_parent (GTK_WIDGET (group)); - if (GTK_IS_TOOL_PALETTE (parent) && !collapsed) - _gtk_tool_palette_set_expanding_child (GTK_TOOL_PALETTE (parent), - GTK_WIDGET (group)); - if (collapsed != priv->collapsed) - { - if (priv->animation) - { - if (priv->animation_timeout) - g_source_destroy (priv->animation_timeout); - - priv->animation_start = g_get_monotonic_time (); - priv->animation_timeout = g_timeout_source_new (ANIMATION_TIMEOUT); - - g_source_set_callback (priv->animation_timeout, - gtk_tool_item_group_animation_cb, - group, NULL); - g_source_attach (priv->animation_timeout, NULL); - } - else - gtk_tool_item_group_force_expose (group); - - priv->collapsed = collapsed; - update_arrow_state (group); - g_object_notify (G_OBJECT (group), "collapsed"); - } -} - -/** - * gtk_tool_item_group_set_ellipsize: - * @group: a #GtkToolItemGroup - * @ellipsize: the #PangoEllipsizeMode labels in @group should use - * - * Sets the ellipsization mode which should be used by labels in @group. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_set_ellipsize (GtkToolItemGroup *group, - PangoEllipsizeMode ellipsize) -{ - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - - if (ellipsize != group->priv->ellipsize) - { - group->priv->ellipsize = ellipsize; - gtk_tool_item_group_header_adjust_style (group); - g_object_notify (G_OBJECT (group), "ellipsize"); - _gtk_tool_item_group_palette_reconfigured (group); - } -} - -/** - * gtk_tool_item_group_get_label: - * @group: a #GtkToolItemGroup - * - * Gets the label of @group. - * - * Returns: the label of @group. The label is an internal string of @group - * and must not be modified. Note that %NULL is returned if a custom - * label has been set with gtk_tool_item_group_set_label_widget() - * - * Since: 2.20 - */ -const gchar* -gtk_tool_item_group_get_label (GtkToolItemGroup *group) -{ - GtkToolItemGroupPrivate *priv; - - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), NULL); - - priv = group->priv; - - if (GTK_IS_LABEL (priv->label_widget)) - return gtk_label_get_label (GTK_LABEL (priv->label_widget)); - else - return NULL; -} - -/** - * gtk_tool_item_group_get_label_widget: - * @group: a #GtkToolItemGroup - * - * Gets the label widget of @group. - * See gtk_tool_item_group_set_label_widget(). - * - * Returns: (transfer none): the label widget of @group - * - * Since: 2.20 - */ -GtkWidget* -gtk_tool_item_group_get_label_widget (GtkToolItemGroup *group) -{ - GtkWidget *frame = gtk_tool_item_group_get_frame (group); - - return gtk_bin_get_child (GTK_BIN (frame)); -} - -/** - * gtk_tool_item_group_get_collapsed: - * @group: a GtkToolItemGroup - * - * Gets whether @group is collapsed or expanded. - * - * Returns: %TRUE if @group is collapsed, %FALSE if it is expanded - * - * Since: 2.20 - */ -gboolean -gtk_tool_item_group_get_collapsed (GtkToolItemGroup *group) -{ - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), DEFAULT_COLLAPSED); - - return group->priv->collapsed; -} - -/** - * gtk_tool_item_group_get_ellipsize: - * @group: a #GtkToolItemGroup - * - * Gets the ellipsization mode of @group. - * - * Returns: the #PangoEllipsizeMode of @group - * - * Since: 2.20 - */ -PangoEllipsizeMode -gtk_tool_item_group_get_ellipsize (GtkToolItemGroup *group) -{ - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), DEFAULT_ELLIPSIZE); - - return group->priv->ellipsize; -} - -/** - * gtk_tool_item_group_get_header_relief: - * @group: a #GtkToolItemGroup - * - * Gets the relief mode of the header button of @group. - * - * Returns: the #GtkReliefStyle - * - * Since: 2.20 - */ -GtkReliefStyle -gtk_tool_item_group_get_header_relief (GtkToolItemGroup *group) -{ - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), GTK_RELIEF_NORMAL); - - return gtk_button_get_relief (GTK_BUTTON (group->priv->header)); -} - -/** - * gtk_tool_item_group_insert: - * @group: a #GtkToolItemGroup - * @item: the #GtkToolItem to insert into @group - * @position: the position of @item in @group, starting with 0. - * The position -1 means end of list. - * - * Inserts @item at @position in the list of children of @group. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_insert (GtkToolItemGroup *group, - GtkToolItem *item, - gint position) -{ - GtkWidget *parent, *child_widget; - GtkToolItemGroupChild *child; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - g_return_if_fail (GTK_IS_TOOL_ITEM (item)); - g_return_if_fail (position >= -1); - - parent = gtk_widget_get_parent (GTK_WIDGET (group)); - - child = g_new (GtkToolItemGroupChild, 1); - child->item = g_object_ref_sink (item); - child->homogeneous = TRUE; - child->expand = FALSE; - child->fill = TRUE; - child->new_row = FALSE; - - group->priv->children = g_list_insert (group->priv->children, child, position); - - if (GTK_IS_TOOL_PALETTE (parent)) - _gtk_tool_palette_child_set_drag_source (GTK_WIDGET (item), parent); - - child_widget = gtk_bin_get_child (GTK_BIN (item)); - - gtk_widget_set_focus_on_click (child_widget, TRUE); - - gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (group)); -} - -/** - * gtk_tool_item_group_set_item_position: - * @group: a #GtkToolItemGroup - * @item: the #GtkToolItem to move to a new position, should - * be a child of @group. - * @position: the new position of @item in @group, starting with 0. - * The position -1 means end of list. - * - * Sets the position of @item in the list of children of @group. - * - * Since: 2.20 - */ -void -gtk_tool_item_group_set_item_position (GtkToolItemGroup *group, - GtkToolItem *item, - gint position) -{ - gint old_position; - GList *link; - GtkToolItemGroupChild *child; - GtkToolItemGroupPrivate* priv; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - g_return_if_fail (GTK_IS_TOOL_ITEM (item)); - g_return_if_fail (position >= -1); - - child = gtk_tool_item_group_get_child (group, item, &old_position, &link); - priv = group->priv; - - g_return_if_fail (child != NULL); - - if (position == old_position) - return; - - priv->children = g_list_delete_link (priv->children, link); - priv->children = g_list_insert (priv->children, child, position); - - gtk_widget_child_notify (GTK_WIDGET (item), "position"); - if (gtk_widget_get_visible (GTK_WIDGET (group)) && - gtk_widget_get_visible (GTK_WIDGET (item))) - gtk_widget_queue_resize (GTK_WIDGET (group)); -} - -/** - * gtk_tool_item_group_get_item_position: - * @group: a #GtkToolItemGroup - * @item: a #GtkToolItem - * - * Gets the position of @item in @group as index. - * - * Returns: the index of @item in @group or -1 if @item is no child of @group - * - * Since: 2.20 - */ -gint -gtk_tool_item_group_get_item_position (GtkToolItemGroup *group, - GtkToolItem *item) -{ - gint position; - - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), -1); - g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1); - - if (gtk_tool_item_group_get_child (group, item, &position, NULL)) - return position; - - return -1; -} - -/** - * gtk_tool_item_group_get_n_items: - * @group: a #GtkToolItemGroup - * - * Gets the number of tool items in @group. - * - * Returns: the number of tool items in @group - * - * Since: 2.20 - */ -guint -gtk_tool_item_group_get_n_items (GtkToolItemGroup *group) -{ - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), 0); - - return g_list_length (group->priv->children); -} - -/** - * gtk_tool_item_group_get_nth_item: - * @group: a #GtkToolItemGroup - * @index: the index - * - * Gets the tool item at @index in group. - * - * Returns: (transfer none): the #GtkToolItem at index - * - * Since: 2.20 - */ -GtkToolItem* -gtk_tool_item_group_get_nth_item (GtkToolItemGroup *group, - guint index) -{ - GtkToolItemGroupChild *child; - - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), NULL); - - child = g_list_nth_data (group->priv->children, index); - - return child != NULL ? child->item : NULL; -} - -/** - * gtk_tool_item_group_get_drop_item: - * @group: a #GtkToolItemGroup - * @x: the x position - * @y: the y position - * - * Gets the tool item at position (x, y). - * - * Returns: (transfer none): the #GtkToolItem at position (x, y) - * - * Since: 2.20 - */ -GtkToolItem* -gtk_tool_item_group_get_drop_item (GtkToolItemGroup *group, - gint x, - gint y) -{ - GtkAllocation allocation; - GList *it; - - g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), NULL); - - gtk_widget_get_allocation (GTK_WIDGET (group), &allocation); - - g_return_val_if_fail (x >= 0 && x < allocation.width, NULL); - g_return_val_if_fail (y >= 0 && y < allocation.height, NULL); - - for (it = group->priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - GtkToolItem *item = child->item; - gint x0, y0; - - if (!item || !gtk_tool_item_group_is_item_visible (group, child)) - continue; - - gtk_widget_get_allocation (GTK_WIDGET (item), &allocation); - - x0 = x - allocation.x; - y0 = y - allocation.y; - - if (x0 >= 0 && x0 < allocation.width && - y0 >= 0 && y0 < allocation.height) - return item; - } - - return NULL; -} - -void -_gtk_tool_item_group_item_size_request (GtkToolItemGroup *group, - GtkRequisition *item_size, - gboolean homogeneous_only, - gint *requested_rows) -{ - GtkRequisition child_requisition; - GList *it; - gint rows = 0; - gboolean new_row = TRUE; - - g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group)); - g_return_if_fail (NULL != item_size); - - item_size->width = item_size->height = 0; - - for (it = group->priv->children; it != NULL; it = it->next) - { - GtkToolItemGroupChild *child = it->data; - - if (!gtk_tool_item_group_is_item_visible (group, child)) - continue; - - if (child->new_row || new_row) - { - rows++; - new_row = FALSE; - } - - if (!child->homogeneous && child->expand) - new_row = TRUE; - - gtk_widget_get_preferred_size (GTK_WIDGET (child->item), - &child_requisition, NULL); - - if (!homogeneous_only || child->homogeneous) - item_size->width = MAX (item_size->width, child_requisition.width); - item_size->height = MAX (item_size->height, child_requisition.height); - } - - if (requested_rows) - *requested_rows = rows; -} - -gint -_gtk_tool_item_group_get_size_for_limit (GtkToolItemGroup *group, - gint limit, - gboolean vertical, - gboolean animation) -{ - GtkRequisition requisition; - GtkToolItemGroupPrivate* priv = group->priv; - - gtk_widget_get_preferred_size (GTK_WIDGET (group), - &requisition, NULL); - - if (!priv->collapsed || priv->animation_timeout) - { - GtkAllocation allocation = { 0, 0, requisition.width, requisition.height }; - GtkRequisition inquery; - - if (vertical) - allocation.width = limit; - else - allocation.height = limit; - - gtk_tool_item_group_real_size_query (GTK_WIDGET (group), - &allocation, &inquery); - - if (vertical) - inquery.height -= requisition.height; - else - inquery.width -= requisition.width; - - if (priv->animation_timeout && animation) - { - gint64 timestamp = gtk_tool_item_group_get_animation_timestamp (group); - - timestamp = MIN (timestamp, ANIMATION_DURATION); - - if (priv->collapsed) - timestamp = ANIMATION_DURATION - timestamp; - - if (vertical) - { - inquery.height *= timestamp; - inquery.height /= ANIMATION_DURATION; - } - else - { - inquery.width *= timestamp; - inquery.width /= ANIMATION_DURATION; - } - } - - if (vertical) - requisition.height += inquery.height; - else - requisition.width += inquery.width; - } - - return (vertical ? requisition.height : requisition.width); -} - -gint -_gtk_tool_item_group_get_height_for_width (GtkToolItemGroup *group, - gint width) -{ - return _gtk_tool_item_group_get_size_for_limit (group, width, TRUE, group->priv->animation); -} - -gint -_gtk_tool_item_group_get_width_for_height (GtkToolItemGroup *group, - gint height) -{ - return _gtk_tool_item_group_get_size_for_limit (group, height, FALSE, TRUE); -} - -static void -gtk_tool_palette_reconfigured_foreach_item (GtkWidget *child, - gpointer data) -{ - if (GTK_IS_TOOL_ITEM (child)) - gtk_tool_item_toolbar_reconfigured (GTK_TOOL_ITEM (child)); -} - - -void -_gtk_tool_item_group_palette_reconfigured (GtkToolItemGroup *group) -{ - gtk_container_foreach (GTK_CONTAINER (group), - gtk_tool_palette_reconfigured_foreach_item, - NULL); - - gtk_tool_item_group_header_adjust_style (group); -} |