From 9fb081a7e6ba9b209d0a7ef49854b1a4d2d57ff4 Mon Sep 17 00:00:00 2001 From: Manish Singh Date: Thu, 2 Sep 1999 01:41:18 +0000 Subject: [PATCH] add gimpmath.h * libgimp/Makefile.am: add gimpmath.h * app/gtkwrapbox.[ch] * app/gtkhwrapbox.[ch]: wrapbox widget from gle * app/Makefile.am: added those files * app/interface.c: use an hwrapbox for the toolbar. Still not perfect yet, working on it. * app/gimpdrawable.c * app/about_dialog.c * app/airbrush.c * app/blend.c: some minor code cleanup -Yosh --- ChangeLog | 17 + app/Makefile.am | 4 + app/about_dialog.c | 4 +- app/airbrush.c | 2 +- app/blend.c | 2 + app/core/gimpdrawable-blend.c | 2 + app/core/gimpdrawable.c | 2 +- app/dialogs/about-dialog.c | 4 +- app/display/gimpdisplayshell-draw.c | 23 +- app/display/gimpdisplayshell.c | 23 +- app/gimpdrawable.c | 2 +- app/gtkhwrapbox.c | 628 ++++++++++++++++++++++++ app/gtkhwrapbox.h | 76 +++ app/gtkwrapbox.c | 724 ++++++++++++++++++++++++++++ app/gtkwrapbox.h | 129 +++++ app/gui/about-dialog.c | 4 +- app/interface.c | 23 +- app/paint/gimpairbrush.c | 2 +- app/tools/airbrush.c | 2 +- app/tools/blend.c | 2 + app/tools/gimpairbrushtool.c | 2 +- app/tools/gimpblendtool.c | 2 + app/widgets/gtkhwrapbox.c | 628 ++++++++++++++++++++++++ app/widgets/gtkhwrapbox.h | 76 +++ app/widgets/gtkwrapbox.c | 724 ++++++++++++++++++++++++++++ app/widgets/gtkwrapbox.h | 129 +++++ libgimp/Makefile.am | 1 + 27 files changed, 3189 insertions(+), 48 deletions(-) create mode 100644 app/gtkhwrapbox.c create mode 100644 app/gtkhwrapbox.h create mode 100644 app/gtkwrapbox.c create mode 100644 app/gtkwrapbox.h create mode 100644 app/widgets/gtkhwrapbox.c create mode 100644 app/widgets/gtkhwrapbox.h create mode 100644 app/widgets/gtkwrapbox.c create mode 100644 app/widgets/gtkwrapbox.h diff --git a/ChangeLog b/ChangeLog index 7c5bfdaaea..914bbb07b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Wed Sep 1 14:50:29 PDT 1999 Manish Singh + + * libgimp/Makefile.am: add gimpmath.h + + * app/gtkwrapbox.[ch] + * app/gtkhwrapbox.[ch]: wrapbox widget from gle + + * app/Makefile.am: added those files + + * app/interface.c: use an hwrapbox for the toolbar + + * app/gimpdrawable.c + * app/about_dialog.c + * app/airbrush.c + * app/blend.c: some minor code cleanup + 1999-09-02 Tor Lillqvist * app/paintbrush.c (paintbrush_non_gui_default, @@ -44,6 +60,7 @@ Wed Sep 1 23:18:21 BST 1999 Andy Thomas the area shown is smaller than the overall image size. Thanks to tml for the idea. +>>>>>>> 1.1481 Wed Sep 1 22:28:09 BST 1999 Adam D. Moss * app/gradient.c diff --git a/app/Makefile.am b/app/Makefile.am index 29f4627a86..5463d8a5fa 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -227,6 +227,10 @@ gimp_SOURCES = \ gradient_select_cmds.c \ gradient.h \ gradient_cmds.c \ + gtkwrapbox.c \ + gtkwrapbox.h \ + gtkhwrapbox.c \ + gtkhwrapbox.h \ guides_cmds.c \ gximage.c \ gximage.h \ diff --git a/app/about_dialog.c b/app/about_dialog.c index 4580c60634..333ae762e8 100644 --- a/app/about_dialog.c +++ b/app/about_dialog.c @@ -368,14 +368,14 @@ about_dialog_load_logo (GtkWidget *window) } static void -about_dialog_destroy () +about_dialog_destroy (void) { about_dialog = NULL; about_dialog_unmap (); } static void -about_dialog_unmap () +about_dialog_unmap (void) { if (timer) { diff --git a/app/airbrush.c b/app/airbrush.c index 07c5776e17..58268c5e32 100644 --- a/app/airbrush.c +++ b/app/airbrush.c @@ -167,7 +167,7 @@ airbrush_options_new (void) } Tool * -tools_new_airbrush () +tools_new_airbrush (void) { Tool * tool; PaintCore * private; diff --git a/app/blend.c b/app/blend.c index 183d4a41da..cea60c01dc 100644 --- a/app/blend.c +++ b/app/blend.c @@ -17,6 +17,8 @@ */ #include "config.h" +#include + #include "appenv.h" #include "asupsample.h" #include "blend.h" diff --git a/app/core/gimpdrawable-blend.c b/app/core/gimpdrawable-blend.c index 183d4a41da..cea60c01dc 100644 --- a/app/core/gimpdrawable-blend.c +++ b/app/core/gimpdrawable-blend.c @@ -17,6 +17,8 @@ */ #include "config.h" +#include + #include "appenv.h" #include "asupsample.h" #include "blend.h" diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 4f4d61b5f2..cb062a989c 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -44,7 +44,7 @@ static GimpDrawableClass *parent_class = NULL; GtkType -gimp_drawable_get_type () +gimp_drawable_get_type (void) { static GtkType type; GIMP_TYPE_INIT(type, diff --git a/app/dialogs/about-dialog.c b/app/dialogs/about-dialog.c index 4580c60634..333ae762e8 100644 --- a/app/dialogs/about-dialog.c +++ b/app/dialogs/about-dialog.c @@ -368,14 +368,14 @@ about_dialog_load_logo (GtkWidget *window) } static void -about_dialog_destroy () +about_dialog_destroy (void) { about_dialog = NULL; about_dialog_unmap (); } static void -about_dialog_unmap () +about_dialog_unmap (void) { if (timer) { diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c index 82f4f2ee83..550126d61b 100644 --- a/app/display/gimpdisplayshell-draw.c +++ b/app/display/gimpdisplayshell-draw.c @@ -35,6 +35,7 @@ #include "gimage.h" #include "gimpdnd.h" #include "gimprc.h" +#include "gtkhwrapbox.h" #include "indicator_area.h" #include "interface.h" #include "menus.h" @@ -340,7 +341,7 @@ create_tool_pixmap (GtkWidget *parent, static void create_tools (GtkWidget *parent) { - GtkWidget *table; + GtkWidget *wbox; GtkWidget *button; GtkWidget *alignment; GtkWidget *pixmap; @@ -348,9 +349,11 @@ create_tools (GtkWidget *parent) gint i, j; /*create_logo (parent);*/ - table = gtk_table_new (ROWS, COLUMNS, TRUE); - gtk_box_pack_start (GTK_BOX (parent), table, TRUE, TRUE, 0); - gtk_widget_realize (table); + wbox = GTK_WIDGET (gtk_type_new (gtk_hwrap_box_get_type ())); + gtk_wrap_box_set_aspect_ratio (GTK_WRAP_BOX (wbox), .36); + gtk_box_pack_start (GTK_BOX (parent), wbox, TRUE, TRUE, 0); + + gtk_widget_realize (gtk_widget_get_toplevel (wbox)); group = NULL; @@ -365,18 +368,14 @@ create_tools (GtkWidget *parent) gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE); - gtk_table_attach (GTK_TABLE (table), button, - (i % 3), (i % 3) + 1, - (i / 3), (i / 3) + 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - 0, 0); + gtk_wrap_box_pack (GTK_WRAP_BOX (wbox), button, + FALSE, TRUE, FALSE, TRUE); alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_container_set_border_width (GTK_CONTAINER (alignment), 0); gtk_container_add (GTK_CONTAINER (button), alignment); - pixmap = create_pixmap_widget (table->window, tool_info[j].icon_data, 22, 22); + pixmap = create_pixmap_widget (wbox->window, tool_info[j].icon_data, 22, 22); gtk_container_add (GTK_CONTAINER (alignment), pixmap); gtk_signal_connect (GTK_OBJECT (button), "toggled", @@ -406,7 +405,7 @@ create_tools (GtkWidget *parent) (gpointer) tool_info[j].tool_id); } } - gtk_widget_show (table); + gtk_widget_show (wbox); } static GdkPixmap * diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c index 82f4f2ee83..550126d61b 100644 --- a/app/display/gimpdisplayshell.c +++ b/app/display/gimpdisplayshell.c @@ -35,6 +35,7 @@ #include "gimage.h" #include "gimpdnd.h" #include "gimprc.h" +#include "gtkhwrapbox.h" #include "indicator_area.h" #include "interface.h" #include "menus.h" @@ -340,7 +341,7 @@ create_tool_pixmap (GtkWidget *parent, static void create_tools (GtkWidget *parent) { - GtkWidget *table; + GtkWidget *wbox; GtkWidget *button; GtkWidget *alignment; GtkWidget *pixmap; @@ -348,9 +349,11 @@ create_tools (GtkWidget *parent) gint i, j; /*create_logo (parent);*/ - table = gtk_table_new (ROWS, COLUMNS, TRUE); - gtk_box_pack_start (GTK_BOX (parent), table, TRUE, TRUE, 0); - gtk_widget_realize (table); + wbox = GTK_WIDGET (gtk_type_new (gtk_hwrap_box_get_type ())); + gtk_wrap_box_set_aspect_ratio (GTK_WRAP_BOX (wbox), .36); + gtk_box_pack_start (GTK_BOX (parent), wbox, TRUE, TRUE, 0); + + gtk_widget_realize (gtk_widget_get_toplevel (wbox)); group = NULL; @@ -365,18 +368,14 @@ create_tools (GtkWidget *parent) gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE); - gtk_table_attach (GTK_TABLE (table), button, - (i % 3), (i % 3) + 1, - (i / 3), (i / 3) + 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - 0, 0); + gtk_wrap_box_pack (GTK_WRAP_BOX (wbox), button, + FALSE, TRUE, FALSE, TRUE); alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_container_set_border_width (GTK_CONTAINER (alignment), 0); gtk_container_add (GTK_CONTAINER (button), alignment); - pixmap = create_pixmap_widget (table->window, tool_info[j].icon_data, 22, 22); + pixmap = create_pixmap_widget (wbox->window, tool_info[j].icon_data, 22, 22); gtk_container_add (GTK_CONTAINER (alignment), pixmap); gtk_signal_connect (GTK_OBJECT (button), "toggled", @@ -406,7 +405,7 @@ create_tools (GtkWidget *parent) (gpointer) tool_info[j].tool_id); } } - gtk_widget_show (table); + gtk_widget_show (wbox); } static GdkPixmap * diff --git a/app/gimpdrawable.c b/app/gimpdrawable.c index 4f4d61b5f2..cb062a989c 100644 --- a/app/gimpdrawable.c +++ b/app/gimpdrawable.c @@ -44,7 +44,7 @@ static GimpDrawableClass *parent_class = NULL; GtkType -gimp_drawable_get_type () +gimp_drawable_get_type (void) { static GtkType type; GIMP_TYPE_INIT(type, diff --git a/app/gtkhwrapbox.c b/app/gtkhwrapbox.c new file mode 100644 index 0000000000..21820aa1b7 --- /dev/null +++ b/app/gtkhwrapbox.c @@ -0,0 +1,628 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkHWrapBox: Horizontal wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtkhwrapbox.h" +#include + + +/* --- prototypes --- */ +static void gtk_hwrap_box_class_init (GtkHWrapBoxClass *klass); +static void gtk_hwrap_box_init (GtkHWrapBox *hwbox); +static void gtk_hwrap_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hwrap_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +/* --- variables --- */ +static gpointer parent_class = NULL; + + +/* --- functions --- */ +GtkType +gtk_hwrap_box_get_type (void) +{ + static GtkType hwrap_box_type = 0; + + if (!hwrap_box_type) + { + static const GtkTypeInfo hwrap_box_info = + { + "GtkHWrapBox", + sizeof (GtkHWrapBox), + sizeof (GtkHWrapBoxClass), + (GtkClassInitFunc) gtk_hwrap_box_class_init, + (GtkObjectInitFunc) gtk_hwrap_box_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + hwrap_box_type = gtk_type_unique (GTK_TYPE_WRAP_BOX, &hwrap_box_info); + } + + return hwrap_box_type; +} + +static void +gtk_hwrap_box_class_init (GtkHWrapBoxClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkWrapBoxClass *wrap_box_class; + + object_class = GTK_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); + container_class = GTK_CONTAINER_CLASS (class); + wrap_box_class = GTK_WRAP_BOX_CLASS (class); + + parent_class = gtk_type_class (GTK_TYPE_WRAP_BOX); + + widget_class->size_request = gtk_hwrap_box_size_request; + widget_class->size_allocate = gtk_hwrap_box_size_allocate; +} + +static void +gtk_hwrap_box_init (GtkHWrapBox *hwbox) +{ + hwbox->max_child_width = 0; + hwbox->max_child_height = 0; +} + +static inline void +get_child_requisition (GtkWrapBox *wbox, + GtkWidget *child, + GtkRequisition *child_requisition) +{ + if (wbox->homogeneous) + { + GtkHWrapBox *hwbox = GTK_HWRAP_BOX (wbox); + + child_requisition->width = hwbox->max_child_width; + child_requisition->height = hwbox->max_child_height; + } + else + gtk_widget_get_child_requisition (child, child_requisition); +} + +static void +_gtk_hwrap_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkHWrapBox *this = GTK_HWRAP_BOX (widget); + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + guint area = 0; + + g_return_if_fail (requisition != NULL); + + /**/ + requisition->width = 0; + requisition->height = 0; + this->max_child_width = 0; + this->max_child_height = 0; + + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (child->widget, &child_requisition); + + area += child_requisition.width * child_requisition.height; + this->max_child_width = MAX (this->max_child_width, child_requisition.width); + this->max_child_height = MAX (this->max_child_height, child_requisition.height); + } + if (wbox->homogeneous) + area = this->max_child_width * this->max_child_height * wbox->n_children; + + if (area) + { + requisition->width = sqrt (area * wbox->aspect_ratio); + requisition->height = area / requisition->width; + } + else + { + requisition->width = 0; + requisition->height = 0; + } + + requisition->width += GTK_CONTAINER (wbox)->border_width * 2; + requisition->height += GTK_CONTAINER (wbox)->border_width * 2; + /**/ +} + +static gfloat +get_layout_size (GtkHWrapBox *this, + guint max_width, + guint *width_inc) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (this); + GtkWrapBoxChild *child; + guint n_rows, left_over = 0, total_height = 0; + gboolean last_row_filled = TRUE; + + *width_inc = this->max_child_width + 1; + + n_rows = 0; + for (child = wbox->children; child; child = child->next) + { + GtkWrapBoxChild *row_child; + GtkRequisition child_requisition; + guint row_width, row_height, n = 1; + + if (!GTK_WIDGET_VISIBLE (child->widget)) + continue; + + get_child_requisition (wbox, child->widget, &child_requisition); + if (!last_row_filled) + *width_inc = MIN (*width_inc, child_requisition.width - left_over); + row_width = child_requisition.width; + row_height = child_requisition.height; + for (row_child = child->next; row_child && n < wbox->child_limit; row_child = row_child->next) + { + if (GTK_WIDGET_VISIBLE (row_child->widget)) + { + get_child_requisition (wbox, row_child->widget, &child_requisition); + if (row_width + wbox->hspacing + child_requisition.width > max_width) + break; + row_width += wbox->hspacing + child_requisition.width; + row_height = MAX (row_height, child_requisition.height); + n++; + } + child = row_child; + } + last_row_filled = n >= wbox->child_limit; + left_over = last_row_filled ? 0 : max_width - (row_width + wbox->hspacing); + total_height += (n_rows ? wbox->vspacing : 0) + row_height; + n_rows++; + } + + if (*width_inc > this->max_child_width) + *width_inc = 0; + + return MAX (total_height, 1); +} + +static void +gtk_hwrap_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkHWrapBox *this = GTK_HWRAP_BOX (widget); + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + gfloat ratio_dist, layout_width = 0; + guint row_inc = 0; + + g_return_if_fail (requisition != NULL); + + requisition->width = 0; + requisition->height = 0; + this->max_child_width = 0; + this->max_child_height = 0; + + /* size_request all children */ + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (child->widget, &child_requisition); + + this->max_child_width = MAX (this->max_child_width, child_requisition.width); + this->max_child_height = MAX (this->max_child_height, child_requisition.height); + } + + /* figure all possible layouts */ + ratio_dist = 32768; + layout_width = this->max_child_width; + do + { + gfloat layout_height; + gfloat ratio, dist; + + layout_width += row_inc; + layout_height = get_layout_size (this, layout_width, &row_inc); + ratio = layout_width / layout_height; /**/ + dist = MAX (ratio, wbox->aspect_ratio) - MIN (ratio, wbox->aspect_ratio); + if (dist < ratio_dist) + { + ratio_dist = dist; + requisition->width = layout_width; + requisition->height = layout_height; + } + + /**/ + g_print ("ratio for width %d height %d = %f\n", + (gint) layout_width, + (gint) layout_height, + ratio); + /**/ + } + while (row_inc); + + /**/ + requisition->width += GTK_CONTAINER (wbox)->border_width * 2; + requisition->height += GTK_CONTAINER (wbox)->border_width * 2; + g_print ("choosen: width %d, height %d\n", + requisition->width, + requisition->height); + /**/ +} + +static GSList* +list_row_children (GtkWrapBox *wbox, + GtkWrapBoxChild **child_p, + guint row_width, + guint *max_height, + gboolean *can_vexpand) +{ + GSList *slist = NULL; + guint width = 0; + GtkWrapBoxChild *child = *child_p; + + *max_height = 0; + *can_vexpand = FALSE; + + while (child && !GTK_WIDGET_VISIBLE (child->widget)) + { + *child_p = child->next; + child = *child_p; + } + + if (child) + { + GtkRequisition child_requisition; + guint n = 1; + + get_child_requisition (wbox, child->widget, &child_requisition); + width += child_requisition.width; + *max_height = MAX (*max_height, child_requisition.height); + *can_vexpand |= child->vexpand; + slist = g_slist_prepend (slist, child); + *child_p = child->next; + child = *child_p; + + while (child && n < wbox->child_limit) + { + if (GTK_WIDGET_VISIBLE (child->widget)) + { + get_child_requisition (wbox, child->widget, &child_requisition); + if (width + wbox->hspacing + child_requisition.width > row_width) + break; + width += wbox->hspacing + child_requisition.width; + *max_height = MAX (*max_height, child_requisition.height); + *can_vexpand |= child->vexpand; + slist = g_slist_prepend (slist, child); + n++; + } + *child_p = child->next; + child = *child_p; + } + } + + return g_slist_reverse (slist); +} + +static void +layout_row (GtkWrapBox *wbox, + GtkAllocation *area, + GSList *children, + guint children_per_line, + gboolean vexpand) +{ + GSList *slist; + guint n_children = 0, n_expand_children = 0, have_expand_children = 0, total_width = 0; + gfloat x, width, extra; + GtkAllocation child_allocation; + + for (slist = children; slist; slist = slist->next) + { + GtkWrapBoxChild *child = slist->data; + GtkRequisition child_requisition; + + n_children++; + if (child->hexpand) + n_expand_children++; + + get_child_requisition (wbox, child->widget, &child_requisition); + total_width += child_requisition.width; + } + + width = MAX (1, area->width - (n_children - 1) * wbox->hspacing); + if (width > total_width) + extra = width - total_width; + else + extra = 0; + have_expand_children = n_expand_children && extra; + + x = area->x; + if (wbox->homogeneous) + { + width = MAX (1, area->width - (children_per_line - 1) * wbox->hspacing); + width /= ((gdouble) children_per_line); + extra = 0; + } + else if (have_expand_children) + { + width = extra; + extra /= ((gdouble) n_expand_children); + } + else + { + if (wbox->justify == GTK_JUSTIFY_FILL) + { + width = extra; + have_expand_children = TRUE; + n_expand_children = n_children; + extra /= ((gdouble) n_expand_children); + } + else if (wbox->justify == GTK_JUSTIFY_CENTER) + { + x += extra / 2; + width = 0; + extra = 0; + } + else if (wbox->justify == GTK_JUSTIFY_LEFT) + { + width = 0; + extra = 0; + } + else if (wbox->justify == GTK_JUSTIFY_RIGHT) + { + x += extra; + width = 0; + extra = 0; + } + } + + n_children = 0; + for (slist = children; slist; slist = slist->next) + { + GtkWrapBoxChild *child = slist->data; + + child_allocation.x = x; + child_allocation.y = area->y; + if (wbox->homogeneous) + { + child_allocation.height = area->height; + child_allocation.width = width; + x += child_allocation.width + wbox->hspacing; + } + else + { + GtkRequisition child_requisition; + + get_child_requisition (wbox, child->widget, &child_requisition); + + if (child_requisition.height >= area->height) + child_allocation.height = area->height; + else + { + child_allocation.height = child_requisition.height; + if (wbox->line_justify == GTK_JUSTIFY_FILL || child->vfill) + child_allocation.height = area->height; + else if (child->vexpand || wbox->line_justify == GTK_JUSTIFY_CENTER) + child_allocation.y += (area->height - child_requisition.height) / 2; + else if (wbox->line_justify == GTK_JUSTIFY_BOTTOM) + child_allocation.y += area->height - child_requisition.height; + } + + if (have_expand_children) + { + child_allocation.width = child_requisition.width; + if (child->hexpand || wbox->justify == GTK_JUSTIFY_FILL) + { + guint space; + + n_expand_children--; + space = extra * n_expand_children; + space = width - space; + width -= space; + if (child->hfill) + child_allocation.width += space; + else + { + child_allocation.x += space / 2; + x += space; + } + } + } + else + { + g_print ("child_allocation.x %d += %d * %f ", + child_allocation.x, n_children, extra); + child_allocation.x += n_children * extra; + g_print ("= %d\n", + child_allocation.x); + child_allocation.width = MIN (child_requisition.width, + area->width - child_allocation.x + area->x); + } + } + + x += child_allocation.width + wbox->hspacing; + gtk_widget_size_allocate (child->widget, &child_allocation); + n_children++; + } +} + +typedef struct _Line Line; +struct _Line +{ + GSList *children; + guint16 min_size; + guint expand : 1; + Line *next; +}; + +static void +layout_rows (GtkWrapBox *wbox, + GtkAllocation *area) +{ + GtkWrapBoxChild *next_child; + guint min_height; + gboolean vexpand; + GSList *slist; + Line *line_list = NULL; + guint total_height = 0, n_expand_lines = 0, n_lines = 0; + gfloat shrink_height; + guint children_per_line; + + next_child = wbox->children; + slist = list_row_children (wbox, &next_child, area->width, &min_height, &vexpand); + children_per_line = g_slist_length (slist); + while (slist) + { + Line *line = g_new (Line, 1); + + line->children = slist; + line->min_size = min_height; + total_height += min_height; + line->expand = vexpand; + if (vexpand) + n_expand_lines++; + line->next = line_list; + line_list = line; + n_lines++; + + slist = list_row_children (wbox, + &next_child, + area->width, + &min_height, + &vexpand); + } + + if (total_height > area->height) + shrink_height = total_height - area->height; + else + shrink_height = 0; + + if (1) /* reverse and shrink */ + { + Line *prev = NULL, *last = NULL; + gfloat n_shrink_lines = n_lines; + + while (line_list) + { + Line *tmp = line_list->next; + + if (shrink_height) + { + Line *line = line_list; + guint shrink_fract = shrink_height / n_shrink_lines + 0.5; + + if (line->min_size > shrink_fract) + { + shrink_height -= shrink_fract; + line->min_size -= shrink_fract; + } + else + { + shrink_height -= line->min_size - 1; + line->min_size = 1; + } + } + n_shrink_lines--; + + last = line_list; + line_list->next = prev; + prev = line_list; + line_list = tmp; + } + line_list = last; + } + + if (n_lines) + { + Line *line; + gfloat y, height, extra = 0; + + height = area->height; + height = MAX (n_lines, height - (n_lines - 1) * wbox->vspacing); + + if (wbox->homogeneous) + height /= ((gdouble) n_lines); + else if (n_expand_lines) + { + height = MAX (0, height - total_height); + extra = height / ((gdouble) n_expand_lines); + } + else + height = 0; + + y = area->y; + line = line_list; + while (line) + { + GtkAllocation row_allocation; + Line *next_line = line->next; + + row_allocation.x = area->x; + row_allocation.width = area->width; + if (wbox->homogeneous) + row_allocation.height = height; + else + { + row_allocation.height = line->min_size; + + if (line->expand) + row_allocation.height += extra; + } + + row_allocation.y = y; + + y += row_allocation.height + wbox->vspacing; + layout_row (wbox, + &row_allocation, + line->children, + children_per_line, + line->expand); + + g_slist_free (line->children); + g_free (line); + line = next_line; + } + } +} + +static void +gtk_hwrap_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkAllocation area; + guint border = GTK_CONTAINER (wbox)->border_width; /**/ + + widget->allocation = *allocation; + area.x = allocation->x + border; + area.y = allocation->y + border; + area.width = MAX (1, (gint) allocation->width - border * 2); + area.height = MAX (1, (gint) allocation->height - border * 2); + + /**/ + g_print ("got: width %d, height %d\n", + allocation->width, + allocation->height); + /**/ + + layout_rows (wbox, &area); +} diff --git a/app/gtkhwrapbox.h b/app/gtkhwrapbox.h new file mode 100644 index 0000000000..5e34757825 --- /dev/null +++ b/app/gtkhwrapbox.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkHWrapBox: Horizontal wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GTK_HWRAP_BOX_H__ +#define __GTK_HWRAP_BOX_H__ + + +#include "gtkwrapbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* --- type macros --- */ +#define GTK_TYPE_HWRAP_BOX (gtk_hwrap_box_get_type ()) +#define GTK_HWRAP_BOX(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_HWRAP_BOX, GtkHWrapBox)) +#define GTK_HWRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_HWRAP_BOX, GtkHWrapBoxClass)) +#define GTK_IS_HWRAP_BOX(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_HWRAP_BOX)) +#define GTK_IS_HWRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_HWRAP_BOX)) +#define GTK_HWRAP_BOX_GET_CLASS(obj) (GTK_HWRAP_BOX_CLASS (((GtkObject*) (obj))->klass)) + + +/* --- typedefs --- */ +typedef struct _GtkHWrapBox GtkHWrapBox; +typedef struct _GtkHWrapBoxClass GtkHWrapBoxClass; + + +/* --- GtkHWrapBox --- */ +struct _GtkHWrapBox +{ + GtkWrapBox parent_widget; + + guint16 max_child_width; + guint16 max_child_height; +}; +struct _GtkHWrapBoxClass +{ + GtkWrapBoxClass parent_class; +}; + + +/* --- prototypes --- */ +GtkType gtk_hwrap_box_get_type (void); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HWRAP_BOX_H__ */ + + + + diff --git a/app/gtkwrapbox.c b/app/gtkwrapbox.c new file mode 100644 index 0000000000..169aa8b7a1 --- /dev/null +++ b/app/gtkwrapbox.c @@ -0,0 +1,724 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkWrapBox: Wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtkwrapbox.h" +#include + + +/* --- arguments --- */ +enum { + ARG_0, + ARG_HOMOGENEOUS, + ARG_JUSTIFY, + ARG_HSPACING, + ARG_VSPACING, + ARG_LINE_JUSTIFY, + ARG_ASPECT_RATIO, + ARG_CURRENT_RATIO, + ARG_CHILD_LIMIT +}; +enum { + CHILD_ARG_0, + CHILD_ARG_POSITION, + CHILD_ARG_HEXPAND, + CHILD_ARG_HFILL, + CHILD_ARG_VEXPAND, + CHILD_ARG_VFILL +}; + + +/* --- prototypes --- */ +static void gtk_wrap_box_class_init (GtkWrapBoxClass *klass); +static void gtk_wrap_box_init (GtkWrapBox *wbox); +static void gtk_wrap_box_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_set_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_get_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_map (GtkWidget *widget); +static void gtk_wrap_box_unmap (GtkWidget *widget); +static void gtk_wrap_box_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_wrap_box_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_wrap_box_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_wrap_box_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_wrap_box_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GtkType gtk_wrap_box_child_type (GtkContainer *container); + + +/* --- variables --- */ +static gpointer parent_class = NULL; + + +/* --- functions --- */ +GtkType +gtk_wrap_box_get_type (void) +{ + static GtkType wrap_box_type = 0; + + if (!wrap_box_type) + { + static const GtkTypeInfo wrap_box_info = + { + "GtkWrapBox", + sizeof (GtkWrapBox), + sizeof (GtkWrapBoxClass), + (GtkClassInitFunc) gtk_wrap_box_class_init, + (GtkObjectInitFunc) gtk_wrap_box_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + wrap_box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &wrap_box_info); + } + + return wrap_box_type; +} + +static void +gtk_wrap_box_class_init (GtkWrapBoxClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = GTK_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); + container_class = GTK_CONTAINER_CLASS (class); + + parent_class = gtk_type_class (GTK_TYPE_CONTAINER); + + object_class->set_arg = gtk_wrap_box_set_arg; + object_class->get_arg = gtk_wrap_box_get_arg; + + widget_class->map = gtk_wrap_box_map; + widget_class->unmap = gtk_wrap_box_unmap; + widget_class->draw = gtk_wrap_box_draw; + widget_class->expose_event = gtk_wrap_box_expose; + + container_class->add = gtk_wrap_box_add; + container_class->remove = gtk_wrap_box_remove; + container_class->forall = gtk_wrap_box_forall; + container_class->child_type = gtk_wrap_box_child_type; + container_class->set_child_arg = gtk_wrap_box_set_child_arg; + container_class->get_child_arg = gtk_wrap_box_get_child_arg; + + gtk_object_add_arg_type ("GtkWrapBox::homogeneous", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS); + gtk_object_add_arg_type ("GtkWrapBox::justify", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY); + gtk_object_add_arg_type ("GtkWrapBox::hspacing", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_HSPACING); + gtk_object_add_arg_type ("GtkWrapBox::vspacing", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_VSPACING); + gtk_object_add_arg_type ("GtkWrapBox::line_justify", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_LINE_JUSTIFY); + gtk_object_add_arg_type ("GtkWrapBox::aspect_ratio", + GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_ASPECT_RATIO); + gtk_object_add_arg_type ("GtkWrapBox::current_ratio", + GTK_TYPE_FLOAT, GTK_ARG_READABLE, ARG_CURRENT_RATIO); + gtk_object_add_arg_type ("GtkWrapBox::max_children_per_line", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_CHILD_LIMIT); + gtk_container_add_child_arg_type ("GtkWrapBox::position", + GTK_TYPE_INT, GTK_ARG_READWRITE, CHILD_ARG_POSITION); + gtk_container_add_child_arg_type ("GtkWrapBox::hexpand", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_HEXPAND); + gtk_container_add_child_arg_type ("GtkWrapBox::hfill", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_HFILL); + gtk_container_add_child_arg_type ("GtkWrapBox::vexpand", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_VEXPAND); + gtk_container_add_child_arg_type ("GtkWrapBox::vfill", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_VFILL); +} + +static void +gtk_wrap_box_init (GtkWrapBox *wbox) +{ + GTK_WIDGET_SET_FLAGS (wbox, GTK_NO_WINDOW); + + wbox->homogeneous = FALSE; + wbox->hspacing = 0; + wbox->vspacing = 0; + wbox->justify = GTK_JUSTIFY_LEFT; + wbox->line_justify = GTK_JUSTIFY_BOTTOM; + wbox->n_children = 0; + wbox->children = NULL; + wbox->aspect_ratio = 1; + wbox->child_limit = 32767; +} + +static void +gtk_wrap_box_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (object); + + switch (arg_id) + { + case ARG_HOMOGENEOUS: + gtk_wrap_box_set_homogeneous (wbox, GTK_VALUE_BOOL (*arg)); + break; + case ARG_JUSTIFY: + gtk_wrap_box_set_justify (wbox, GTK_VALUE_ENUM (*arg)); + break; + case ARG_LINE_JUSTIFY: + gtk_wrap_box_set_line_justify (wbox, GTK_VALUE_ENUM (*arg)); + break; + case ARG_HSPACING: + gtk_wrap_box_set_hspacing (wbox, GTK_VALUE_UINT (*arg)); + break; + case ARG_VSPACING: + gtk_wrap_box_set_vspacing (wbox, GTK_VALUE_UINT (*arg)); + break; + case ARG_ASPECT_RATIO: + gtk_wrap_box_set_aspect_ratio (wbox, GTK_VALUE_FLOAT (*arg)); + break; + case ARG_CHILD_LIMIT: + if (wbox->child_limit != GTK_VALUE_UINT (*arg)) + { + wbox->child_limit = CLAMP (GTK_VALUE_UINT (*arg), 1, 32767); + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } + break; + } +} + +static void +gtk_wrap_box_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (object); + GtkWidget *widget = GTK_WIDGET (object); + + switch (arg_id) + { + case ARG_HOMOGENEOUS: + GTK_VALUE_BOOL (*arg) = wbox->homogeneous; + break; + case ARG_JUSTIFY: + GTK_VALUE_ENUM (*arg) = wbox->justify; + break; + case ARG_LINE_JUSTIFY: + GTK_VALUE_ENUM (*arg) = wbox->line_justify; + break; + case ARG_HSPACING: + GTK_VALUE_UINT (*arg) = wbox->hspacing; + break; + case ARG_VSPACING: + GTK_VALUE_UINT (*arg) = wbox->vspacing; + break; + case ARG_ASPECT_RATIO: + GTK_VALUE_FLOAT (*arg) = wbox->aspect_ratio; + break; + case ARG_CURRENT_RATIO: + GTK_VALUE_FLOAT (*arg) = (((gfloat) widget->allocation.width) / + ((gfloat) widget->allocation.height)); + break; + case ARG_CHILD_LIMIT: + GTK_VALUE_UINT (*arg) = wbox->child_limit; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +gtk_wrap_box_set_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + gboolean hexpand = FALSE, hfill = FALSE, vexpand = FALSE, vfill = FALSE; + + if (arg_id != CHILD_ARG_POSITION) + gtk_wrap_box_query_child_packing (wbox, child, &hexpand, &hfill, &vexpand, &vfill); + + switch (arg_id) + { + case CHILD_ARG_POSITION: + gtk_wrap_box_reorder_child (wbox, child, GTK_VALUE_INT (*arg)); + break; + case CHILD_ARG_HEXPAND: + gtk_wrap_box_set_child_packing (wbox, child, + GTK_VALUE_BOOL (*arg), hfill, + vexpand, vfill); + break; + case CHILD_ARG_HFILL: + gtk_wrap_box_set_child_packing (wbox, child, + hexpand, GTK_VALUE_BOOL (*arg), + vexpand, vfill); + break; + case CHILD_ARG_VEXPAND: + gtk_wrap_box_set_child_packing (wbox, child, + hexpand, hfill, + GTK_VALUE_BOOL (*arg), vfill); + break; + case CHILD_ARG_VFILL: + gtk_wrap_box_set_child_packing (wbox, child, + hexpand, hfill, + vexpand, GTK_VALUE_BOOL (*arg)); + break; + default: + break; + } +} + +static void +gtk_wrap_box_get_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + gboolean hexpand = FALSE, hfill = FALSE, vexpand = FALSE, vfill = FALSE; + + if (arg_id != CHILD_ARG_POSITION) + gtk_wrap_box_query_child_packing (wbox, child, &hexpand, &hfill, &vexpand, &vfill); + + switch (arg_id) + { + GtkWrapBoxChild *child_info; + case CHILD_ARG_POSITION: + GTK_VALUE_INT (*arg) = 0; + for (child_info = wbox->children; child_info; child_info = child_info->next) + { + if (child_info->widget == child) + break; + GTK_VALUE_INT (*arg)++; + } + if (!child_info) + GTK_VALUE_INT (*arg) = -1; + break; + case CHILD_ARG_HEXPAND: + GTK_VALUE_BOOL (*arg) = hexpand; + break; + case CHILD_ARG_HFILL: + GTK_VALUE_BOOL (*arg) = hfill; + break; + case CHILD_ARG_VEXPAND: + GTK_VALUE_BOOL (*arg) = vexpand; + break; + case CHILD_ARG_VFILL: + GTK_VALUE_BOOL (*arg) = vfill; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static GtkType +gtk_wrap_box_child_type (GtkContainer *container) +{ + return GTK_TYPE_WIDGET; +} + +void +gtk_wrap_box_set_homogeneous (GtkWrapBox *wbox, + gboolean homogeneous) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + homogeneous = homogeneous != FALSE; + if (wbox->homogeneous != homogeneous) + { + wbox->homogeneous = homogeneous; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_hspacing (GtkWrapBox *wbox, + guint hspacing) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + if (wbox->hspacing != hspacing) + { + wbox->hspacing = hspacing; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_vspacing (GtkWrapBox *wbox, + guint vspacing) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + if (wbox->vspacing != vspacing) + { + wbox->vspacing = vspacing; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_justify (GtkWrapBox *wbox, + GtkJustification justify) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (justify <= GTK_JUSTIFY_FILL); + + if (wbox->justify != justify) + { + wbox->justify = justify; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_line_justify (GtkWrapBox *wbox, + GtkJustification line_justify) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (line_justify <= GTK_JUSTIFY_FILL); + + if (wbox->line_justify != line_justify) + { + wbox->line_justify = line_justify; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_aspect_ratio (GtkWrapBox *wbox, + gfloat aspect_ratio) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + aspect_ratio = CLAMP (aspect_ratio, 1.0 / 256.0, 256.0); + + if (wbox->aspect_ratio != aspect_ratio) + { + wbox->aspect_ratio = aspect_ratio; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_pack (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill) +{ + GtkWrapBoxChild *child_info; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (child->parent == NULL); + + child_info = g_new (GtkWrapBoxChild, 1); + child_info->widget = child; + child_info->hexpand = hexpand ? TRUE : FALSE; + child_info->hfill = hfill ? TRUE : FALSE; + child_info->vexpand = vexpand ? TRUE : FALSE; + child_info->vfill = vfill ? TRUE : FALSE; + child_info->next = NULL; + if (wbox->children) + { + GtkWrapBoxChild *last = wbox->children; + + while (last->next) + last = last->next; + last->next = child_info; + } + else + wbox->children = child_info; + wbox->n_children++; + + gtk_widget_set_parent (child, GTK_WIDGET (wbox)); + + if (GTK_WIDGET_REALIZED (wbox)) + gtk_widget_realize (child); + + if (GTK_WIDGET_VISIBLE (wbox) && GTK_WIDGET_VISIBLE (child)) + { + if (GTK_WIDGET_MAPPED (wbox)) + gtk_widget_map (child); + + gtk_widget_queue_resize (child); + } +} + +void +gtk_wrap_box_reorder_child (GtkWrapBox *wbox, + GtkWidget *child, + gint position) +{ + GtkWrapBoxChild *child_info, *last = NULL; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + for (child_info = wbox->children; child_info; last = child_info, child_info = last->next) + if (child_info->widget == child) + break; + + if (child_info && wbox->children->next) + { + GtkWrapBoxChild *tmp; + + if (last) + last->next = child_info->next; + else + wbox->children = child_info->next; + + last = NULL; + tmp = wbox->children; + while (position && tmp->next) + { + position--; + last = tmp; + tmp = last->next; + } + + if (position) + { + tmp->next = child_info; + child_info->next = NULL; + } + else + { + child_info->next = tmp; + if (last) + last->next = child_info; + else + wbox->children = child_info; + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (wbox)) + gtk_widget_queue_resize (child); + } +} + +void +gtk_wrap_box_query_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean *hexpand, + gboolean *hfill, + gboolean *vexpand, + gboolean *vfill) +{ + GtkWrapBoxChild *child_info; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + for (child_info = wbox->children; child_info; child_info = child_info->next) + if (child_info->widget == child) + break; + + if (child_info) + { + if (hexpand) + *hexpand = child_info->hexpand; + if (hfill) + *hfill = child_info->hfill; + if (vexpand) + *vexpand = child_info->vexpand; + if (vfill) + *vfill = child_info->vfill; + } +} + +void +gtk_wrap_box_set_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill) +{ + GtkWrapBoxChild *child_info; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + hexpand = hexpand != FALSE; + hfill = hfill != FALSE; + vexpand = vexpand != FALSE; + vfill = vfill != FALSE; + + for (child_info = wbox->children; child_info; child_info = child_info->next) + if (child_info->widget == child) + break; + + if (child_info && + (child_info->hexpand != hexpand || child_info->vexpand != vexpand || + child_info->hfill != hfill || child_info->vfill != vfill)) + { + child_info->hexpand = hexpand; + child_info->hfill = hfill; + child_info->vexpand = vexpand; + child_info->vfill = vfill; + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (wbox)) + gtk_widget_queue_resize (child); + } +} + +static void +gtk_wrap_box_map (GtkWidget *widget) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + + GTK_WIDGET_SET_FLAGS (wbox, GTK_MAPPED); + + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); +} + +static void +gtk_wrap_box_unmap (GtkWidget *widget) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + + GTK_WIDGET_UNSET_FLAGS (wbox, GTK_MAPPED); + + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget) && + GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); +} + +static void +gtk_wrap_box_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + GdkRectangle child_area; + + if (GTK_WIDGET_DRAWABLE (widget)) + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_DRAWABLE (child->widget) && + gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); +} + +static gint +gtk_wrap_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + GdkEventExpose child_event = *event; + + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_DRAWABLE (child->widget) && + GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + + return FALSE; +} + +static void +gtk_wrap_box_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_wrap_box_pack (GTK_WRAP_BOX (container), widget, FALSE, TRUE, FALSE, TRUE); +} + +static void +gtk_wrap_box_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + GtkWrapBoxChild *child, *last = NULL; + + child = wbox->children; + while (child) + { + if (child->widget == widget) + { + gboolean was_visible; + + was_visible = GTK_WIDGET_VISIBLE (widget); + gtk_widget_unparent (widget); + + if (last) + last->next = child->next; + else + wbox->children = child->next; + g_free (child); + wbox->n_children--; + + if (was_visible) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + last = child; + child = last->next; + } +} + +static void +gtk_wrap_box_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + GtkWrapBoxChild *child; + + child = wbox->children; + while (child) + { + GtkWidget *widget = child->widget; + + child = child->next; + + callback (widget, callback_data); + } +} diff --git a/app/gtkwrapbox.h b/app/gtkwrapbox.h new file mode 100644 index 0000000000..58319a15e3 --- /dev/null +++ b/app/gtkwrapbox.h @@ -0,0 +1,129 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkWrapBox: Wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GTK_WRAP_BOX_H__ +#define __GTK_WRAP_BOX_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* --- type macros --- */ +#define GTK_TYPE_WRAP_BOX (gtk_wrap_box_get_type ()) +#define GTK_WRAP_BOX(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_WRAP_BOX, GtkWrapBox)) +#define GTK_WRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_WRAP_BOX, GtkWrapBoxClass)) +#define GTK_IS_WRAP_BOX(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_WRAP_BOX)) +#define GTK_IS_WRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WRAP_BOX)) +#define GTK_WRAP_BOX_GET_CLASS(obj) (GTK_WRAP_BOX_CLASS (((GtkObject*) (obj))->klass)) + + +/* --- typedefs --- */ +typedef struct _GtkWrapBox GtkWrapBox; +typedef struct _GtkWrapBoxClass GtkWrapBoxClass; +typedef struct _GtkWrapBoxChild GtkWrapBoxChild; + +/* --- GtkWrapBox --- */ +struct _GtkWrapBox +{ + GtkContainer container; + + guint homogeneous : 1; + guint justify : 4; + guint line_justify : 4; + guint8 hspacing; + guint8 vspacing; + guint16 n_children; + GtkWrapBoxChild *children; + gfloat aspect_ratio; /* 1/256..256 */ + guint child_limit; +}; +struct _GtkWrapBoxClass +{ + GtkContainerClass parent_class; +}; +struct _GtkWrapBoxChild +{ + GtkWidget *widget; + guint hexpand : 1; + guint hfill : 1; + guint vexpand : 1; + guint vfill : 1; + + GtkWrapBoxChild *next; +}; +#define GTK_JUSTIFY_TOP GTK_JUSTIFY_LEFT +#define GTK_JUSTIFY_BOTTOM GTK_JUSTIFY_RIGHT + + +/* --- prototypes --- */ +GtkType gtk_wrap_box_get_type (void); +void gtk_wrap_box_set_homogeneous (GtkWrapBox *wbox, + gboolean homogeneous); +void gtk_wrap_box_set_hspacing (GtkWrapBox *wbox, + guint hspacing); +void gtk_wrap_box_set_vspacing (GtkWrapBox *wbox, + guint vspacing); +void gtk_wrap_box_set_justify (GtkWrapBox *wbox, + GtkJustification justify); +void gtk_wrap_box_set_line_justify (GtkWrapBox *wbox, + GtkJustification line_justify); +void gtk_wrap_box_set_aspect_ratio (GtkWrapBox *wbox, + gfloat aspect_ratio); +void gtk_wrap_box_pack (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill); +void gtk_wrap_box_reorder_child (GtkWrapBox *wbox, + GtkWidget *child, + gint position); +void gtk_wrap_box_query_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean *hexpand, + gboolean *hfill, + gboolean *vexpand, + gboolean *vfill); +void gtk_wrap_box_set_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_WRAP_BOX_H__ */ + + + + diff --git a/app/gui/about-dialog.c b/app/gui/about-dialog.c index 4580c60634..333ae762e8 100644 --- a/app/gui/about-dialog.c +++ b/app/gui/about-dialog.c @@ -368,14 +368,14 @@ about_dialog_load_logo (GtkWidget *window) } static void -about_dialog_destroy () +about_dialog_destroy (void) { about_dialog = NULL; about_dialog_unmap (); } static void -about_dialog_unmap () +about_dialog_unmap (void) { if (timer) { diff --git a/app/interface.c b/app/interface.c index 82f4f2ee83..550126d61b 100644 --- a/app/interface.c +++ b/app/interface.c @@ -35,6 +35,7 @@ #include "gimage.h" #include "gimpdnd.h" #include "gimprc.h" +#include "gtkhwrapbox.h" #include "indicator_area.h" #include "interface.h" #include "menus.h" @@ -340,7 +341,7 @@ create_tool_pixmap (GtkWidget *parent, static void create_tools (GtkWidget *parent) { - GtkWidget *table; + GtkWidget *wbox; GtkWidget *button; GtkWidget *alignment; GtkWidget *pixmap; @@ -348,9 +349,11 @@ create_tools (GtkWidget *parent) gint i, j; /*create_logo (parent);*/ - table = gtk_table_new (ROWS, COLUMNS, TRUE); - gtk_box_pack_start (GTK_BOX (parent), table, TRUE, TRUE, 0); - gtk_widget_realize (table); + wbox = GTK_WIDGET (gtk_type_new (gtk_hwrap_box_get_type ())); + gtk_wrap_box_set_aspect_ratio (GTK_WRAP_BOX (wbox), .36); + gtk_box_pack_start (GTK_BOX (parent), wbox, TRUE, TRUE, 0); + + gtk_widget_realize (gtk_widget_get_toplevel (wbox)); group = NULL; @@ -365,18 +368,14 @@ create_tools (GtkWidget *parent) gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE); - gtk_table_attach (GTK_TABLE (table), button, - (i % 3), (i % 3) + 1, - (i / 3), (i / 3) + 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - 0, 0); + gtk_wrap_box_pack (GTK_WRAP_BOX (wbox), button, + FALSE, TRUE, FALSE, TRUE); alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_container_set_border_width (GTK_CONTAINER (alignment), 0); gtk_container_add (GTK_CONTAINER (button), alignment); - pixmap = create_pixmap_widget (table->window, tool_info[j].icon_data, 22, 22); + pixmap = create_pixmap_widget (wbox->window, tool_info[j].icon_data, 22, 22); gtk_container_add (GTK_CONTAINER (alignment), pixmap); gtk_signal_connect (GTK_OBJECT (button), "toggled", @@ -406,7 +405,7 @@ create_tools (GtkWidget *parent) (gpointer) tool_info[j].tool_id); } } - gtk_widget_show (table); + gtk_widget_show (wbox); } static GdkPixmap * diff --git a/app/paint/gimpairbrush.c b/app/paint/gimpairbrush.c index 07c5776e17..58268c5e32 100644 --- a/app/paint/gimpairbrush.c +++ b/app/paint/gimpairbrush.c @@ -167,7 +167,7 @@ airbrush_options_new (void) } Tool * -tools_new_airbrush () +tools_new_airbrush (void) { Tool * tool; PaintCore * private; diff --git a/app/tools/airbrush.c b/app/tools/airbrush.c index 07c5776e17..58268c5e32 100644 --- a/app/tools/airbrush.c +++ b/app/tools/airbrush.c @@ -167,7 +167,7 @@ airbrush_options_new (void) } Tool * -tools_new_airbrush () +tools_new_airbrush (void) { Tool * tool; PaintCore * private; diff --git a/app/tools/blend.c b/app/tools/blend.c index 183d4a41da..cea60c01dc 100644 --- a/app/tools/blend.c +++ b/app/tools/blend.c @@ -17,6 +17,8 @@ */ #include "config.h" +#include + #include "appenv.h" #include "asupsample.h" #include "blend.h" diff --git a/app/tools/gimpairbrushtool.c b/app/tools/gimpairbrushtool.c index 07c5776e17..58268c5e32 100644 --- a/app/tools/gimpairbrushtool.c +++ b/app/tools/gimpairbrushtool.c @@ -167,7 +167,7 @@ airbrush_options_new (void) } Tool * -tools_new_airbrush () +tools_new_airbrush (void) { Tool * tool; PaintCore * private; diff --git a/app/tools/gimpblendtool.c b/app/tools/gimpblendtool.c index 183d4a41da..cea60c01dc 100644 --- a/app/tools/gimpblendtool.c +++ b/app/tools/gimpblendtool.c @@ -17,6 +17,8 @@ */ #include "config.h" +#include + #include "appenv.h" #include "asupsample.h" #include "blend.h" diff --git a/app/widgets/gtkhwrapbox.c b/app/widgets/gtkhwrapbox.c new file mode 100644 index 0000000000..21820aa1b7 --- /dev/null +++ b/app/widgets/gtkhwrapbox.c @@ -0,0 +1,628 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkHWrapBox: Horizontal wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtkhwrapbox.h" +#include + + +/* --- prototypes --- */ +static void gtk_hwrap_box_class_init (GtkHWrapBoxClass *klass); +static void gtk_hwrap_box_init (GtkHWrapBox *hwbox); +static void gtk_hwrap_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hwrap_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +/* --- variables --- */ +static gpointer parent_class = NULL; + + +/* --- functions --- */ +GtkType +gtk_hwrap_box_get_type (void) +{ + static GtkType hwrap_box_type = 0; + + if (!hwrap_box_type) + { + static const GtkTypeInfo hwrap_box_info = + { + "GtkHWrapBox", + sizeof (GtkHWrapBox), + sizeof (GtkHWrapBoxClass), + (GtkClassInitFunc) gtk_hwrap_box_class_init, + (GtkObjectInitFunc) gtk_hwrap_box_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + hwrap_box_type = gtk_type_unique (GTK_TYPE_WRAP_BOX, &hwrap_box_info); + } + + return hwrap_box_type; +} + +static void +gtk_hwrap_box_class_init (GtkHWrapBoxClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkWrapBoxClass *wrap_box_class; + + object_class = GTK_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); + container_class = GTK_CONTAINER_CLASS (class); + wrap_box_class = GTK_WRAP_BOX_CLASS (class); + + parent_class = gtk_type_class (GTK_TYPE_WRAP_BOX); + + widget_class->size_request = gtk_hwrap_box_size_request; + widget_class->size_allocate = gtk_hwrap_box_size_allocate; +} + +static void +gtk_hwrap_box_init (GtkHWrapBox *hwbox) +{ + hwbox->max_child_width = 0; + hwbox->max_child_height = 0; +} + +static inline void +get_child_requisition (GtkWrapBox *wbox, + GtkWidget *child, + GtkRequisition *child_requisition) +{ + if (wbox->homogeneous) + { + GtkHWrapBox *hwbox = GTK_HWRAP_BOX (wbox); + + child_requisition->width = hwbox->max_child_width; + child_requisition->height = hwbox->max_child_height; + } + else + gtk_widget_get_child_requisition (child, child_requisition); +} + +static void +_gtk_hwrap_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkHWrapBox *this = GTK_HWRAP_BOX (widget); + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + guint area = 0; + + g_return_if_fail (requisition != NULL); + + /**/ + requisition->width = 0; + requisition->height = 0; + this->max_child_width = 0; + this->max_child_height = 0; + + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (child->widget, &child_requisition); + + area += child_requisition.width * child_requisition.height; + this->max_child_width = MAX (this->max_child_width, child_requisition.width); + this->max_child_height = MAX (this->max_child_height, child_requisition.height); + } + if (wbox->homogeneous) + area = this->max_child_width * this->max_child_height * wbox->n_children; + + if (area) + { + requisition->width = sqrt (area * wbox->aspect_ratio); + requisition->height = area / requisition->width; + } + else + { + requisition->width = 0; + requisition->height = 0; + } + + requisition->width += GTK_CONTAINER (wbox)->border_width * 2; + requisition->height += GTK_CONTAINER (wbox)->border_width * 2; + /**/ +} + +static gfloat +get_layout_size (GtkHWrapBox *this, + guint max_width, + guint *width_inc) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (this); + GtkWrapBoxChild *child; + guint n_rows, left_over = 0, total_height = 0; + gboolean last_row_filled = TRUE; + + *width_inc = this->max_child_width + 1; + + n_rows = 0; + for (child = wbox->children; child; child = child->next) + { + GtkWrapBoxChild *row_child; + GtkRequisition child_requisition; + guint row_width, row_height, n = 1; + + if (!GTK_WIDGET_VISIBLE (child->widget)) + continue; + + get_child_requisition (wbox, child->widget, &child_requisition); + if (!last_row_filled) + *width_inc = MIN (*width_inc, child_requisition.width - left_over); + row_width = child_requisition.width; + row_height = child_requisition.height; + for (row_child = child->next; row_child && n < wbox->child_limit; row_child = row_child->next) + { + if (GTK_WIDGET_VISIBLE (row_child->widget)) + { + get_child_requisition (wbox, row_child->widget, &child_requisition); + if (row_width + wbox->hspacing + child_requisition.width > max_width) + break; + row_width += wbox->hspacing + child_requisition.width; + row_height = MAX (row_height, child_requisition.height); + n++; + } + child = row_child; + } + last_row_filled = n >= wbox->child_limit; + left_over = last_row_filled ? 0 : max_width - (row_width + wbox->hspacing); + total_height += (n_rows ? wbox->vspacing : 0) + row_height; + n_rows++; + } + + if (*width_inc > this->max_child_width) + *width_inc = 0; + + return MAX (total_height, 1); +} + +static void +gtk_hwrap_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkHWrapBox *this = GTK_HWRAP_BOX (widget); + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + gfloat ratio_dist, layout_width = 0; + guint row_inc = 0; + + g_return_if_fail (requisition != NULL); + + requisition->width = 0; + requisition->height = 0; + this->max_child_width = 0; + this->max_child_height = 0; + + /* size_request all children */ + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (child->widget, &child_requisition); + + this->max_child_width = MAX (this->max_child_width, child_requisition.width); + this->max_child_height = MAX (this->max_child_height, child_requisition.height); + } + + /* figure all possible layouts */ + ratio_dist = 32768; + layout_width = this->max_child_width; + do + { + gfloat layout_height; + gfloat ratio, dist; + + layout_width += row_inc; + layout_height = get_layout_size (this, layout_width, &row_inc); + ratio = layout_width / layout_height; /**/ + dist = MAX (ratio, wbox->aspect_ratio) - MIN (ratio, wbox->aspect_ratio); + if (dist < ratio_dist) + { + ratio_dist = dist; + requisition->width = layout_width; + requisition->height = layout_height; + } + + /**/ + g_print ("ratio for width %d height %d = %f\n", + (gint) layout_width, + (gint) layout_height, + ratio); + /**/ + } + while (row_inc); + + /**/ + requisition->width += GTK_CONTAINER (wbox)->border_width * 2; + requisition->height += GTK_CONTAINER (wbox)->border_width * 2; + g_print ("choosen: width %d, height %d\n", + requisition->width, + requisition->height); + /**/ +} + +static GSList* +list_row_children (GtkWrapBox *wbox, + GtkWrapBoxChild **child_p, + guint row_width, + guint *max_height, + gboolean *can_vexpand) +{ + GSList *slist = NULL; + guint width = 0; + GtkWrapBoxChild *child = *child_p; + + *max_height = 0; + *can_vexpand = FALSE; + + while (child && !GTK_WIDGET_VISIBLE (child->widget)) + { + *child_p = child->next; + child = *child_p; + } + + if (child) + { + GtkRequisition child_requisition; + guint n = 1; + + get_child_requisition (wbox, child->widget, &child_requisition); + width += child_requisition.width; + *max_height = MAX (*max_height, child_requisition.height); + *can_vexpand |= child->vexpand; + slist = g_slist_prepend (slist, child); + *child_p = child->next; + child = *child_p; + + while (child && n < wbox->child_limit) + { + if (GTK_WIDGET_VISIBLE (child->widget)) + { + get_child_requisition (wbox, child->widget, &child_requisition); + if (width + wbox->hspacing + child_requisition.width > row_width) + break; + width += wbox->hspacing + child_requisition.width; + *max_height = MAX (*max_height, child_requisition.height); + *can_vexpand |= child->vexpand; + slist = g_slist_prepend (slist, child); + n++; + } + *child_p = child->next; + child = *child_p; + } + } + + return g_slist_reverse (slist); +} + +static void +layout_row (GtkWrapBox *wbox, + GtkAllocation *area, + GSList *children, + guint children_per_line, + gboolean vexpand) +{ + GSList *slist; + guint n_children = 0, n_expand_children = 0, have_expand_children = 0, total_width = 0; + gfloat x, width, extra; + GtkAllocation child_allocation; + + for (slist = children; slist; slist = slist->next) + { + GtkWrapBoxChild *child = slist->data; + GtkRequisition child_requisition; + + n_children++; + if (child->hexpand) + n_expand_children++; + + get_child_requisition (wbox, child->widget, &child_requisition); + total_width += child_requisition.width; + } + + width = MAX (1, area->width - (n_children - 1) * wbox->hspacing); + if (width > total_width) + extra = width - total_width; + else + extra = 0; + have_expand_children = n_expand_children && extra; + + x = area->x; + if (wbox->homogeneous) + { + width = MAX (1, area->width - (children_per_line - 1) * wbox->hspacing); + width /= ((gdouble) children_per_line); + extra = 0; + } + else if (have_expand_children) + { + width = extra; + extra /= ((gdouble) n_expand_children); + } + else + { + if (wbox->justify == GTK_JUSTIFY_FILL) + { + width = extra; + have_expand_children = TRUE; + n_expand_children = n_children; + extra /= ((gdouble) n_expand_children); + } + else if (wbox->justify == GTK_JUSTIFY_CENTER) + { + x += extra / 2; + width = 0; + extra = 0; + } + else if (wbox->justify == GTK_JUSTIFY_LEFT) + { + width = 0; + extra = 0; + } + else if (wbox->justify == GTK_JUSTIFY_RIGHT) + { + x += extra; + width = 0; + extra = 0; + } + } + + n_children = 0; + for (slist = children; slist; slist = slist->next) + { + GtkWrapBoxChild *child = slist->data; + + child_allocation.x = x; + child_allocation.y = area->y; + if (wbox->homogeneous) + { + child_allocation.height = area->height; + child_allocation.width = width; + x += child_allocation.width + wbox->hspacing; + } + else + { + GtkRequisition child_requisition; + + get_child_requisition (wbox, child->widget, &child_requisition); + + if (child_requisition.height >= area->height) + child_allocation.height = area->height; + else + { + child_allocation.height = child_requisition.height; + if (wbox->line_justify == GTK_JUSTIFY_FILL || child->vfill) + child_allocation.height = area->height; + else if (child->vexpand || wbox->line_justify == GTK_JUSTIFY_CENTER) + child_allocation.y += (area->height - child_requisition.height) / 2; + else if (wbox->line_justify == GTK_JUSTIFY_BOTTOM) + child_allocation.y += area->height - child_requisition.height; + } + + if (have_expand_children) + { + child_allocation.width = child_requisition.width; + if (child->hexpand || wbox->justify == GTK_JUSTIFY_FILL) + { + guint space; + + n_expand_children--; + space = extra * n_expand_children; + space = width - space; + width -= space; + if (child->hfill) + child_allocation.width += space; + else + { + child_allocation.x += space / 2; + x += space; + } + } + } + else + { + g_print ("child_allocation.x %d += %d * %f ", + child_allocation.x, n_children, extra); + child_allocation.x += n_children * extra; + g_print ("= %d\n", + child_allocation.x); + child_allocation.width = MIN (child_requisition.width, + area->width - child_allocation.x + area->x); + } + } + + x += child_allocation.width + wbox->hspacing; + gtk_widget_size_allocate (child->widget, &child_allocation); + n_children++; + } +} + +typedef struct _Line Line; +struct _Line +{ + GSList *children; + guint16 min_size; + guint expand : 1; + Line *next; +}; + +static void +layout_rows (GtkWrapBox *wbox, + GtkAllocation *area) +{ + GtkWrapBoxChild *next_child; + guint min_height; + gboolean vexpand; + GSList *slist; + Line *line_list = NULL; + guint total_height = 0, n_expand_lines = 0, n_lines = 0; + gfloat shrink_height; + guint children_per_line; + + next_child = wbox->children; + slist = list_row_children (wbox, &next_child, area->width, &min_height, &vexpand); + children_per_line = g_slist_length (slist); + while (slist) + { + Line *line = g_new (Line, 1); + + line->children = slist; + line->min_size = min_height; + total_height += min_height; + line->expand = vexpand; + if (vexpand) + n_expand_lines++; + line->next = line_list; + line_list = line; + n_lines++; + + slist = list_row_children (wbox, + &next_child, + area->width, + &min_height, + &vexpand); + } + + if (total_height > area->height) + shrink_height = total_height - area->height; + else + shrink_height = 0; + + if (1) /* reverse and shrink */ + { + Line *prev = NULL, *last = NULL; + gfloat n_shrink_lines = n_lines; + + while (line_list) + { + Line *tmp = line_list->next; + + if (shrink_height) + { + Line *line = line_list; + guint shrink_fract = shrink_height / n_shrink_lines + 0.5; + + if (line->min_size > shrink_fract) + { + shrink_height -= shrink_fract; + line->min_size -= shrink_fract; + } + else + { + shrink_height -= line->min_size - 1; + line->min_size = 1; + } + } + n_shrink_lines--; + + last = line_list; + line_list->next = prev; + prev = line_list; + line_list = tmp; + } + line_list = last; + } + + if (n_lines) + { + Line *line; + gfloat y, height, extra = 0; + + height = area->height; + height = MAX (n_lines, height - (n_lines - 1) * wbox->vspacing); + + if (wbox->homogeneous) + height /= ((gdouble) n_lines); + else if (n_expand_lines) + { + height = MAX (0, height - total_height); + extra = height / ((gdouble) n_expand_lines); + } + else + height = 0; + + y = area->y; + line = line_list; + while (line) + { + GtkAllocation row_allocation; + Line *next_line = line->next; + + row_allocation.x = area->x; + row_allocation.width = area->width; + if (wbox->homogeneous) + row_allocation.height = height; + else + { + row_allocation.height = line->min_size; + + if (line->expand) + row_allocation.height += extra; + } + + row_allocation.y = y; + + y += row_allocation.height + wbox->vspacing; + layout_row (wbox, + &row_allocation, + line->children, + children_per_line, + line->expand); + + g_slist_free (line->children); + g_free (line); + line = next_line; + } + } +} + +static void +gtk_hwrap_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkAllocation area; + guint border = GTK_CONTAINER (wbox)->border_width; /**/ + + widget->allocation = *allocation; + area.x = allocation->x + border; + area.y = allocation->y + border; + area.width = MAX (1, (gint) allocation->width - border * 2); + area.height = MAX (1, (gint) allocation->height - border * 2); + + /**/ + g_print ("got: width %d, height %d\n", + allocation->width, + allocation->height); + /**/ + + layout_rows (wbox, &area); +} diff --git a/app/widgets/gtkhwrapbox.h b/app/widgets/gtkhwrapbox.h new file mode 100644 index 0000000000..5e34757825 --- /dev/null +++ b/app/widgets/gtkhwrapbox.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkHWrapBox: Horizontal wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GTK_HWRAP_BOX_H__ +#define __GTK_HWRAP_BOX_H__ + + +#include "gtkwrapbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* --- type macros --- */ +#define GTK_TYPE_HWRAP_BOX (gtk_hwrap_box_get_type ()) +#define GTK_HWRAP_BOX(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_HWRAP_BOX, GtkHWrapBox)) +#define GTK_HWRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_HWRAP_BOX, GtkHWrapBoxClass)) +#define GTK_IS_HWRAP_BOX(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_HWRAP_BOX)) +#define GTK_IS_HWRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_HWRAP_BOX)) +#define GTK_HWRAP_BOX_GET_CLASS(obj) (GTK_HWRAP_BOX_CLASS (((GtkObject*) (obj))->klass)) + + +/* --- typedefs --- */ +typedef struct _GtkHWrapBox GtkHWrapBox; +typedef struct _GtkHWrapBoxClass GtkHWrapBoxClass; + + +/* --- GtkHWrapBox --- */ +struct _GtkHWrapBox +{ + GtkWrapBox parent_widget; + + guint16 max_child_width; + guint16 max_child_height; +}; +struct _GtkHWrapBoxClass +{ + GtkWrapBoxClass parent_class; +}; + + +/* --- prototypes --- */ +GtkType gtk_hwrap_box_get_type (void); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HWRAP_BOX_H__ */ + + + + diff --git a/app/widgets/gtkwrapbox.c b/app/widgets/gtkwrapbox.c new file mode 100644 index 0000000000..169aa8b7a1 --- /dev/null +++ b/app/widgets/gtkwrapbox.c @@ -0,0 +1,724 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkWrapBox: Wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtkwrapbox.h" +#include + + +/* --- arguments --- */ +enum { + ARG_0, + ARG_HOMOGENEOUS, + ARG_JUSTIFY, + ARG_HSPACING, + ARG_VSPACING, + ARG_LINE_JUSTIFY, + ARG_ASPECT_RATIO, + ARG_CURRENT_RATIO, + ARG_CHILD_LIMIT +}; +enum { + CHILD_ARG_0, + CHILD_ARG_POSITION, + CHILD_ARG_HEXPAND, + CHILD_ARG_HFILL, + CHILD_ARG_VEXPAND, + CHILD_ARG_VFILL +}; + + +/* --- prototypes --- */ +static void gtk_wrap_box_class_init (GtkWrapBoxClass *klass); +static void gtk_wrap_box_init (GtkWrapBox *wbox); +static void gtk_wrap_box_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_set_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_get_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id); +static void gtk_wrap_box_map (GtkWidget *widget); +static void gtk_wrap_box_unmap (GtkWidget *widget); +static void gtk_wrap_box_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_wrap_box_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_wrap_box_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_wrap_box_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_wrap_box_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GtkType gtk_wrap_box_child_type (GtkContainer *container); + + +/* --- variables --- */ +static gpointer parent_class = NULL; + + +/* --- functions --- */ +GtkType +gtk_wrap_box_get_type (void) +{ + static GtkType wrap_box_type = 0; + + if (!wrap_box_type) + { + static const GtkTypeInfo wrap_box_info = + { + "GtkWrapBox", + sizeof (GtkWrapBox), + sizeof (GtkWrapBoxClass), + (GtkClassInitFunc) gtk_wrap_box_class_init, + (GtkObjectInitFunc) gtk_wrap_box_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + wrap_box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &wrap_box_info); + } + + return wrap_box_type; +} + +static void +gtk_wrap_box_class_init (GtkWrapBoxClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = GTK_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); + container_class = GTK_CONTAINER_CLASS (class); + + parent_class = gtk_type_class (GTK_TYPE_CONTAINER); + + object_class->set_arg = gtk_wrap_box_set_arg; + object_class->get_arg = gtk_wrap_box_get_arg; + + widget_class->map = gtk_wrap_box_map; + widget_class->unmap = gtk_wrap_box_unmap; + widget_class->draw = gtk_wrap_box_draw; + widget_class->expose_event = gtk_wrap_box_expose; + + container_class->add = gtk_wrap_box_add; + container_class->remove = gtk_wrap_box_remove; + container_class->forall = gtk_wrap_box_forall; + container_class->child_type = gtk_wrap_box_child_type; + container_class->set_child_arg = gtk_wrap_box_set_child_arg; + container_class->get_child_arg = gtk_wrap_box_get_child_arg; + + gtk_object_add_arg_type ("GtkWrapBox::homogeneous", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS); + gtk_object_add_arg_type ("GtkWrapBox::justify", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY); + gtk_object_add_arg_type ("GtkWrapBox::hspacing", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_HSPACING); + gtk_object_add_arg_type ("GtkWrapBox::vspacing", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_VSPACING); + gtk_object_add_arg_type ("GtkWrapBox::line_justify", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_LINE_JUSTIFY); + gtk_object_add_arg_type ("GtkWrapBox::aspect_ratio", + GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_ASPECT_RATIO); + gtk_object_add_arg_type ("GtkWrapBox::current_ratio", + GTK_TYPE_FLOAT, GTK_ARG_READABLE, ARG_CURRENT_RATIO); + gtk_object_add_arg_type ("GtkWrapBox::max_children_per_line", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_CHILD_LIMIT); + gtk_container_add_child_arg_type ("GtkWrapBox::position", + GTK_TYPE_INT, GTK_ARG_READWRITE, CHILD_ARG_POSITION); + gtk_container_add_child_arg_type ("GtkWrapBox::hexpand", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_HEXPAND); + gtk_container_add_child_arg_type ("GtkWrapBox::hfill", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_HFILL); + gtk_container_add_child_arg_type ("GtkWrapBox::vexpand", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_VEXPAND); + gtk_container_add_child_arg_type ("GtkWrapBox::vfill", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_VFILL); +} + +static void +gtk_wrap_box_init (GtkWrapBox *wbox) +{ + GTK_WIDGET_SET_FLAGS (wbox, GTK_NO_WINDOW); + + wbox->homogeneous = FALSE; + wbox->hspacing = 0; + wbox->vspacing = 0; + wbox->justify = GTK_JUSTIFY_LEFT; + wbox->line_justify = GTK_JUSTIFY_BOTTOM; + wbox->n_children = 0; + wbox->children = NULL; + wbox->aspect_ratio = 1; + wbox->child_limit = 32767; +} + +static void +gtk_wrap_box_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (object); + + switch (arg_id) + { + case ARG_HOMOGENEOUS: + gtk_wrap_box_set_homogeneous (wbox, GTK_VALUE_BOOL (*arg)); + break; + case ARG_JUSTIFY: + gtk_wrap_box_set_justify (wbox, GTK_VALUE_ENUM (*arg)); + break; + case ARG_LINE_JUSTIFY: + gtk_wrap_box_set_line_justify (wbox, GTK_VALUE_ENUM (*arg)); + break; + case ARG_HSPACING: + gtk_wrap_box_set_hspacing (wbox, GTK_VALUE_UINT (*arg)); + break; + case ARG_VSPACING: + gtk_wrap_box_set_vspacing (wbox, GTK_VALUE_UINT (*arg)); + break; + case ARG_ASPECT_RATIO: + gtk_wrap_box_set_aspect_ratio (wbox, GTK_VALUE_FLOAT (*arg)); + break; + case ARG_CHILD_LIMIT: + if (wbox->child_limit != GTK_VALUE_UINT (*arg)) + { + wbox->child_limit = CLAMP (GTK_VALUE_UINT (*arg), 1, 32767); + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } + break; + } +} + +static void +gtk_wrap_box_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (object); + GtkWidget *widget = GTK_WIDGET (object); + + switch (arg_id) + { + case ARG_HOMOGENEOUS: + GTK_VALUE_BOOL (*arg) = wbox->homogeneous; + break; + case ARG_JUSTIFY: + GTK_VALUE_ENUM (*arg) = wbox->justify; + break; + case ARG_LINE_JUSTIFY: + GTK_VALUE_ENUM (*arg) = wbox->line_justify; + break; + case ARG_HSPACING: + GTK_VALUE_UINT (*arg) = wbox->hspacing; + break; + case ARG_VSPACING: + GTK_VALUE_UINT (*arg) = wbox->vspacing; + break; + case ARG_ASPECT_RATIO: + GTK_VALUE_FLOAT (*arg) = wbox->aspect_ratio; + break; + case ARG_CURRENT_RATIO: + GTK_VALUE_FLOAT (*arg) = (((gfloat) widget->allocation.width) / + ((gfloat) widget->allocation.height)); + break; + case ARG_CHILD_LIMIT: + GTK_VALUE_UINT (*arg) = wbox->child_limit; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +gtk_wrap_box_set_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + gboolean hexpand = FALSE, hfill = FALSE, vexpand = FALSE, vfill = FALSE; + + if (arg_id != CHILD_ARG_POSITION) + gtk_wrap_box_query_child_packing (wbox, child, &hexpand, &hfill, &vexpand, &vfill); + + switch (arg_id) + { + case CHILD_ARG_POSITION: + gtk_wrap_box_reorder_child (wbox, child, GTK_VALUE_INT (*arg)); + break; + case CHILD_ARG_HEXPAND: + gtk_wrap_box_set_child_packing (wbox, child, + GTK_VALUE_BOOL (*arg), hfill, + vexpand, vfill); + break; + case CHILD_ARG_HFILL: + gtk_wrap_box_set_child_packing (wbox, child, + hexpand, GTK_VALUE_BOOL (*arg), + vexpand, vfill); + break; + case CHILD_ARG_VEXPAND: + gtk_wrap_box_set_child_packing (wbox, child, + hexpand, hfill, + GTK_VALUE_BOOL (*arg), vfill); + break; + case CHILD_ARG_VFILL: + gtk_wrap_box_set_child_packing (wbox, child, + hexpand, hfill, + vexpand, GTK_VALUE_BOOL (*arg)); + break; + default: + break; + } +} + +static void +gtk_wrap_box_get_child_arg (GtkContainer *container, + GtkWidget *child, + GtkArg *arg, + guint arg_id) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + gboolean hexpand = FALSE, hfill = FALSE, vexpand = FALSE, vfill = FALSE; + + if (arg_id != CHILD_ARG_POSITION) + gtk_wrap_box_query_child_packing (wbox, child, &hexpand, &hfill, &vexpand, &vfill); + + switch (arg_id) + { + GtkWrapBoxChild *child_info; + case CHILD_ARG_POSITION: + GTK_VALUE_INT (*arg) = 0; + for (child_info = wbox->children; child_info; child_info = child_info->next) + { + if (child_info->widget == child) + break; + GTK_VALUE_INT (*arg)++; + } + if (!child_info) + GTK_VALUE_INT (*arg) = -1; + break; + case CHILD_ARG_HEXPAND: + GTK_VALUE_BOOL (*arg) = hexpand; + break; + case CHILD_ARG_HFILL: + GTK_VALUE_BOOL (*arg) = hfill; + break; + case CHILD_ARG_VEXPAND: + GTK_VALUE_BOOL (*arg) = vexpand; + break; + case CHILD_ARG_VFILL: + GTK_VALUE_BOOL (*arg) = vfill; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static GtkType +gtk_wrap_box_child_type (GtkContainer *container) +{ + return GTK_TYPE_WIDGET; +} + +void +gtk_wrap_box_set_homogeneous (GtkWrapBox *wbox, + gboolean homogeneous) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + homogeneous = homogeneous != FALSE; + if (wbox->homogeneous != homogeneous) + { + wbox->homogeneous = homogeneous; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_hspacing (GtkWrapBox *wbox, + guint hspacing) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + if (wbox->hspacing != hspacing) + { + wbox->hspacing = hspacing; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_vspacing (GtkWrapBox *wbox, + guint vspacing) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + if (wbox->vspacing != vspacing) + { + wbox->vspacing = vspacing; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_justify (GtkWrapBox *wbox, + GtkJustification justify) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (justify <= GTK_JUSTIFY_FILL); + + if (wbox->justify != justify) + { + wbox->justify = justify; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_line_justify (GtkWrapBox *wbox, + GtkJustification line_justify) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (line_justify <= GTK_JUSTIFY_FILL); + + if (wbox->line_justify != line_justify) + { + wbox->line_justify = line_justify; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_set_aspect_ratio (GtkWrapBox *wbox, + gfloat aspect_ratio) +{ + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + + aspect_ratio = CLAMP (aspect_ratio, 1.0 / 256.0, 256.0); + + if (wbox->aspect_ratio != aspect_ratio) + { + wbox->aspect_ratio = aspect_ratio; + gtk_widget_queue_resize (GTK_WIDGET (wbox)); + } +} + +void +gtk_wrap_box_pack (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill) +{ + GtkWrapBoxChild *child_info; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (child->parent == NULL); + + child_info = g_new (GtkWrapBoxChild, 1); + child_info->widget = child; + child_info->hexpand = hexpand ? TRUE : FALSE; + child_info->hfill = hfill ? TRUE : FALSE; + child_info->vexpand = vexpand ? TRUE : FALSE; + child_info->vfill = vfill ? TRUE : FALSE; + child_info->next = NULL; + if (wbox->children) + { + GtkWrapBoxChild *last = wbox->children; + + while (last->next) + last = last->next; + last->next = child_info; + } + else + wbox->children = child_info; + wbox->n_children++; + + gtk_widget_set_parent (child, GTK_WIDGET (wbox)); + + if (GTK_WIDGET_REALIZED (wbox)) + gtk_widget_realize (child); + + if (GTK_WIDGET_VISIBLE (wbox) && GTK_WIDGET_VISIBLE (child)) + { + if (GTK_WIDGET_MAPPED (wbox)) + gtk_widget_map (child); + + gtk_widget_queue_resize (child); + } +} + +void +gtk_wrap_box_reorder_child (GtkWrapBox *wbox, + GtkWidget *child, + gint position) +{ + GtkWrapBoxChild *child_info, *last = NULL; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + for (child_info = wbox->children; child_info; last = child_info, child_info = last->next) + if (child_info->widget == child) + break; + + if (child_info && wbox->children->next) + { + GtkWrapBoxChild *tmp; + + if (last) + last->next = child_info->next; + else + wbox->children = child_info->next; + + last = NULL; + tmp = wbox->children; + while (position && tmp->next) + { + position--; + last = tmp; + tmp = last->next; + } + + if (position) + { + tmp->next = child_info; + child_info->next = NULL; + } + else + { + child_info->next = tmp; + if (last) + last->next = child_info; + else + wbox->children = child_info; + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (wbox)) + gtk_widget_queue_resize (child); + } +} + +void +gtk_wrap_box_query_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean *hexpand, + gboolean *hfill, + gboolean *vexpand, + gboolean *vfill) +{ + GtkWrapBoxChild *child_info; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + for (child_info = wbox->children; child_info; child_info = child_info->next) + if (child_info->widget == child) + break; + + if (child_info) + { + if (hexpand) + *hexpand = child_info->hexpand; + if (hfill) + *hfill = child_info->hfill; + if (vexpand) + *vexpand = child_info->vexpand; + if (vfill) + *vfill = child_info->vfill; + } +} + +void +gtk_wrap_box_set_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill) +{ + GtkWrapBoxChild *child_info; + + g_return_if_fail (GTK_IS_WRAP_BOX (wbox)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + hexpand = hexpand != FALSE; + hfill = hfill != FALSE; + vexpand = vexpand != FALSE; + vfill = vfill != FALSE; + + for (child_info = wbox->children; child_info; child_info = child_info->next) + if (child_info->widget == child) + break; + + if (child_info && + (child_info->hexpand != hexpand || child_info->vexpand != vexpand || + child_info->hfill != hfill || child_info->vfill != vfill)) + { + child_info->hexpand = hexpand; + child_info->hfill = hfill; + child_info->vexpand = vexpand; + child_info->vfill = vfill; + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (wbox)) + gtk_widget_queue_resize (child); + } +} + +static void +gtk_wrap_box_map (GtkWidget *widget) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + + GTK_WIDGET_SET_FLAGS (wbox, GTK_MAPPED); + + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); +} + +static void +gtk_wrap_box_unmap (GtkWidget *widget) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + + GTK_WIDGET_UNSET_FLAGS (wbox, GTK_MAPPED); + + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_VISIBLE (child->widget) && + GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); +} + +static void +gtk_wrap_box_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + GdkRectangle child_area; + + if (GTK_WIDGET_DRAWABLE (widget)) + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_DRAWABLE (child->widget) && + gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); +} + +static gint +gtk_wrap_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (widget); + GtkWrapBoxChild *child; + GdkEventExpose child_event = *event; + + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + for (child = wbox->children; child; child = child->next) + if (GTK_WIDGET_DRAWABLE (child->widget) && + GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + + return FALSE; +} + +static void +gtk_wrap_box_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_wrap_box_pack (GTK_WRAP_BOX (container), widget, FALSE, TRUE, FALSE, TRUE); +} + +static void +gtk_wrap_box_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + GtkWrapBoxChild *child, *last = NULL; + + child = wbox->children; + while (child) + { + if (child->widget == widget) + { + gboolean was_visible; + + was_visible = GTK_WIDGET_VISIBLE (widget); + gtk_widget_unparent (widget); + + if (last) + last->next = child->next; + else + wbox->children = child->next; + g_free (child); + wbox->n_children--; + + if (was_visible) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + last = child; + child = last->next; + } +} + +static void +gtk_wrap_box_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkWrapBox *wbox = GTK_WRAP_BOX (container); + GtkWrapBoxChild *child; + + child = wbox->children; + while (child) + { + GtkWidget *widget = child->widget; + + child = child->next; + + callback (widget, callback_data); + } +} diff --git a/app/widgets/gtkwrapbox.h b/app/widgets/gtkwrapbox.h new file mode 100644 index 0000000000..58319a15e3 --- /dev/null +++ b/app/widgets/gtkwrapbox.h @@ -0,0 +1,129 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkWrapBox: Wrapping box widget + * Copyright (C) 1999 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __GTK_WRAP_BOX_H__ +#define __GTK_WRAP_BOX_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* --- type macros --- */ +#define GTK_TYPE_WRAP_BOX (gtk_wrap_box_get_type ()) +#define GTK_WRAP_BOX(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_WRAP_BOX, GtkWrapBox)) +#define GTK_WRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_WRAP_BOX, GtkWrapBoxClass)) +#define GTK_IS_WRAP_BOX(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_WRAP_BOX)) +#define GTK_IS_WRAP_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WRAP_BOX)) +#define GTK_WRAP_BOX_GET_CLASS(obj) (GTK_WRAP_BOX_CLASS (((GtkObject*) (obj))->klass)) + + +/* --- typedefs --- */ +typedef struct _GtkWrapBox GtkWrapBox; +typedef struct _GtkWrapBoxClass GtkWrapBoxClass; +typedef struct _GtkWrapBoxChild GtkWrapBoxChild; + +/* --- GtkWrapBox --- */ +struct _GtkWrapBox +{ + GtkContainer container; + + guint homogeneous : 1; + guint justify : 4; + guint line_justify : 4; + guint8 hspacing; + guint8 vspacing; + guint16 n_children; + GtkWrapBoxChild *children; + gfloat aspect_ratio; /* 1/256..256 */ + guint child_limit; +}; +struct _GtkWrapBoxClass +{ + GtkContainerClass parent_class; +}; +struct _GtkWrapBoxChild +{ + GtkWidget *widget; + guint hexpand : 1; + guint hfill : 1; + guint vexpand : 1; + guint vfill : 1; + + GtkWrapBoxChild *next; +}; +#define GTK_JUSTIFY_TOP GTK_JUSTIFY_LEFT +#define GTK_JUSTIFY_BOTTOM GTK_JUSTIFY_RIGHT + + +/* --- prototypes --- */ +GtkType gtk_wrap_box_get_type (void); +void gtk_wrap_box_set_homogeneous (GtkWrapBox *wbox, + gboolean homogeneous); +void gtk_wrap_box_set_hspacing (GtkWrapBox *wbox, + guint hspacing); +void gtk_wrap_box_set_vspacing (GtkWrapBox *wbox, + guint vspacing); +void gtk_wrap_box_set_justify (GtkWrapBox *wbox, + GtkJustification justify); +void gtk_wrap_box_set_line_justify (GtkWrapBox *wbox, + GtkJustification line_justify); +void gtk_wrap_box_set_aspect_ratio (GtkWrapBox *wbox, + gfloat aspect_ratio); +void gtk_wrap_box_pack (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill); +void gtk_wrap_box_reorder_child (GtkWrapBox *wbox, + GtkWidget *child, + gint position); +void gtk_wrap_box_query_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean *hexpand, + gboolean *hfill, + gboolean *vexpand, + gboolean *vfill); +void gtk_wrap_box_set_child_packing (GtkWrapBox *wbox, + GtkWidget *child, + gboolean hexpand, + gboolean hfill, + gboolean vexpand, + gboolean vfill); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_WRAP_BOX_H__ */ + + + + diff --git a/libgimp/Makefile.am b/libgimp/Makefile.am index 7ef1f8e81a..71f643c514 100644 --- a/libgimp/Makefile.am +++ b/libgimp/Makefile.am @@ -113,6 +113,7 @@ gimpinclude_HEADERS = \ gimpfeatures.h \ gimpfileselection.h \ gimplimits.h \ + gimpmath.h \ gimpmatrix.h \ gimpmenu.h \ gimpmodule.h \