Commit deaa3516 authored by Tristan Van Berkom's avatar Tristan Van Berkom
Browse files

Added initial revision of GtkWrapBox container widget and test case.

parent 2a2f7c09
......@@ -335,7 +335,8 @@ gtk_public_h_sources = \
gtkvscrollbar.h \
gtkvseparator.h \
gtkwidget.h \
gtkwindow.h
gtkwindow.h \
gtkwrapbox.h
if OS_UNIX
gtk_unix_print_public_h_sources = \
......@@ -619,6 +620,7 @@ gtk_base_c_sources = \
gtkwidget.c \
gtkwindow-decorate.c \
gtkwindow.c \
gtkwrapbox.c \
$(gtk_clipboard_dnd_c_sources)
gtk_c_sources = $(gtk_base_c_sources)
......
......@@ -218,6 +218,7 @@
#include <gtk/gtkvseparator.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkwrapbox.h>
#undef __GTK_H_INSIDE__
......
......@@ -4629,6 +4629,29 @@ gtk_window_unstick
#endif
#endif
#if IN_HEADER(__GTK_WRAP_BOX_H__)
#if IN_FILE(__GTK_WRAP_BOX_C__)
gtk_wrap_box_get_allocation_mode
gtk_wrap_box_get_horizontal_spacing
gtk_wrap_box_get_minimum_line_children
gtk_wrap_box_get_natural_line_children
gtk_wrap_box_get_spreading
gtk_wrap_box_get_type G_GNUC_CONST
gtk_wrap_box_get_vertical_spacing
gtk_wrap_box_insert_child
gtk_wrap_box_new
gtk_wrap_box_reorder_child
gtk_wrap_box_set_allocation_mode
gtk_wrap_box_set_horizontal_spacing
gtk_wrap_box_set_minimum_line_children
gtk_wrap_box_set_natural_line_children
gtk_wrap_box_set_spreading
gtk_wrap_box_set_vertical_spacing
#endif
#endif
#if IN_HEADER(__GTK_WIN32_EMBED_WIDGET_H__)
#if IN_FILE(__GTK_WIN32_EMBED_WIDGET_C__)
#ifdef G_OS_WIN32
......
......@@ -560,6 +560,52 @@ typedef enum
} GtkSizeRequestMode;
/**
* GtkWrapAllocationMode:
* @GTK_WRAP_ALLOCATE_FREE: Items wrap freely in the box's orientation
* @GTK_WRAP_ALLOCATE_ALIGNED: Items are aligned into rows and columns
* @GTK_WRAP_ALLOCATE_HOMOGENEOUS: Items are all allocated the same size
*
* Describes how an #GtkWrapBox positions its children.
*/
typedef enum {
GTK_WRAP_ALLOCATE_FREE = 0,
GTK_WRAP_ALLOCATE_ALIGNED,
GTK_WRAP_ALLOCATE_HOMOGENEOUS
} GtkWrapAllocationMode;
/**
* GtkWrapBoxSpreading:
* @GTK_WRAP_BOX_SPREAD_BEGIN: Items are allocated no more than their natural size
* in the layout's orientation and any extra space is left trailing at
* the end of each line.
* @GTK_WRAP_BOX_SPREAD_END: Items are allocated no more than their natural size
* in the layout's orientation and any extra space skipped at the beginning
* of each line.
* @GTK_WRAP_BOX_SPREAD_EVEN: Items are allocated no more than their natural size
* in the layout's orientation and any extra space is evenly distributed
* between children.
* @GTK_WRAP_BOX_SPREAD_EXPAND: Items share the extra space evenly (or among children that 'expand' when
* in %GTK_WRAP_ALLOCATE_FREE mode.
*
* Describes how an #GtkWrapBox deals with extra space when allocating children.
*
* The box always tries to fit as many children at their natural size
* in the given orentation as possible with the exception of fitting "minimum-line-children"
* items into the available size. When the available size is larger than
* the size needed to fit a given number of children at their natural size
* then extra space is available to distribute among children. The
* #GtkWrapBoxSpreading option describes what to do with this space.
*
*/
typedef enum {
GTK_WRAP_BOX_SPREAD_BEGIN = 0,
GTK_WRAP_BOX_SPREAD_END,
GTK_WRAP_BOX_SPREAD_EVEN,
GTK_WRAP_BOX_SPREAD_EXPAND
} GtkWrapBoxSpreading;
G_END_DECLS
#endif /* __GTK_ENUMS_H__ */
This diff is collapsed.
/*
* Copyright (C) 2010 Openismus GmbH
*
* Authors:
* Tristan Van Berkom <tristanvb@openismus.com>
*
* 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 <gtk/gtkcontainer.h>
G_BEGIN_DECLS
#define GTK_TYPE_WRAP_BOX (gtk_wrap_box_get_type ())
#define GTK_WRAP_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WRAP_BOX, GtkWrapBox))
#define GTK_WRAP_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WRAP_BOX, GtkWrapBoxClass))
#define GTK_IS_WRAP_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WRAP_BOX))
#define GTK_IS_WRAP_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WRAP_BOX))
#define GTK_WRAP_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WRAP_BOX, GtkWrapBoxClass))
typedef struct _GtkWrapBox GtkWrapBox;
typedef struct _GtkWrapBoxPriv GtkWrapBoxPriv;
typedef struct _GtkWrapBoxClass GtkWrapBoxClass;
struct _GtkWrapBox
{
GtkContainer container;
/*< private >*/
GtkWrapBoxPriv *priv;
};
struct _GtkWrapBoxClass
{
GtkContainerClass parent_class;
};
GType gtk_wrap_box_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_wrap_box_new (GtkWrapAllocationMode mode,
GtkWrapBoxSpreading spreading,
guint horizontal_spacing,
guint vertical_spacing);
void gtk_wrap_box_set_allocation_mode (GtkWrapBox *layout,
GtkWrapAllocationMode mode);
GtkWrapAllocationMode gtk_wrap_box_get_allocation_mode (GtkWrapBox *layout);
void gtk_wrap_box_set_spreading (GtkWrapBox *layout,
GtkWrapBoxSpreading spreading);
GtkWrapBoxSpreading gtk_wrap_box_get_spreading (GtkWrapBox *layout);
void gtk_wrap_box_set_vertical_spacing (GtkWrapBox *layout,
guint spacing);
guint gtk_wrap_box_get_vertical_spacing (GtkWrapBox *layout);
void gtk_wrap_box_set_horizontal_spacing (GtkWrapBox *layout,
guint spacing);
guint gtk_wrap_box_get_horizontal_spacing (GtkWrapBox *layout);
void gtk_wrap_box_set_minimum_line_children (GtkWrapBox *layout,
guint n_children);
guint gtk_wrap_box_get_minimum_line_children (GtkWrapBox *layout);
void gtk_wrap_box_set_natural_line_children (GtkWrapBox *layout,
guint n_children);
guint gtk_wrap_box_get_natural_line_children (GtkWrapBox *layout);
void gtk_wrap_box_insert_child (GtkWrapBox *layout,
GtkWidget *widget,
gint index,
guint xpad,
guint ypad,
gboolean xexpand,
gboolean yexpand,
gboolean xfill,
gboolean yfill);
void gtk_wrap_box_reorder_child (GtkWrapBox *layout,
GtkWidget *widget,
guint index);
G_END_DECLS
#endif /* __GTK_WRAP_BOX_H__ */
......@@ -89,7 +89,8 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testgrouping \
testtooltips \
testexpander \
testvolumebutton
testvolumebutton \
testwrapbox
if USE_X11
noinst_PROGRAMS += testapplication
......@@ -170,6 +171,7 @@ testactions_DEPENDENCIES = $(TEST_DEPS)
testgrouping_DEPENDENCIES = $(TEST_DEPS)
testtooltips_DEPENDENCIES = $(TEST_DEPS)
testvolumebutton_DEPENDENCIES = $(TEST_DEPS)
testwrapbox_DEPENDENCIES = $(TEST_DEPS)
testwindows_DEPENDENCIES = $(TEST_DEPS)
testexpander_DEPENDENCIES = $(TEST_DEPS)
......@@ -238,6 +240,7 @@ testactions_LDADD = $(LDADDS)
testgrouping_LDADD = $(LDADDS)
testtooltips_LDADD = $(LDADDS)
testvolumebutton_LDADD = $(LDADDS)
testwrapbox_LDADD = $(LDADDS)
testwindows_LDADD = $(LDADDS)
testexpander_LDADD = $(LDADDS)
......@@ -337,6 +340,9 @@ testrecentchoosermenu_SOURCES = \
testvolumebutton_SOURCES = \
testvolumebutton.c
testwrapbox_SOURCES = \
testwrapbox.c
testoffscreen_SOURCES = \
gtkoffscreenbox.c \
gtkoffscreenbox.h \
......
/* testwrapbox.c
* Copyright (C) 2010 Openismus GmbH
*
* Author:
* Tristan Van Berkom <tristan.van.berkom@gmail.com>
*
* 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 <gtk/gtk.h>
enum {
SIMPLE_ITEMS = 0,
WRAPPY_ITEMS,
STOCK_ITEMS
};
#define INITIAL_ALLOCATION_MODE GTK_WRAP_ALLOCATE_HOMOGENEOUS
#define INITIAL_SPREADING GTK_WRAP_BOX_SPREAD_BEGIN
#define INITIAL_MINIMUM_LENGTH 3
#define INITIAL_HSPACING 2
#define INITIAL_VSPACING 2
static GtkWrapBox *the_wrapbox = NULL;
static gint items_type = SIMPLE_ITEMS;
static GtkOrientation text_orientation = GTK_ORIENTATION_HORIZONTAL;
static gboolean items_xexpand = TRUE;
static gboolean items_yexpand = TRUE;
static gboolean items_xfill = TRUE;
static gboolean items_yfill = TRUE;
static gint items_xpad = 0;
static gint items_ypad = 0;
static void
populate_wrapbox_simple (GtkWrapBox *wrapbox)
{
GtkWidget *widget, *frame;
gint i;
for (i = 0; i < 30; i++)
{
gchar *text = g_strdup_printf ("Item %02d", i);
widget = gtk_label_new (text);
frame = gtk_frame_new (NULL);
gtk_widget_show (widget);
gtk_widget_show (frame);
gtk_container_add (GTK_CONTAINER (frame), widget);
if (text_orientation == GTK_ORIENTATION_VERTICAL)
gtk_label_set_angle (GTK_LABEL (widget), 90);
gtk_wrap_box_insert_child (GTK_WRAP_BOX (wrapbox), frame, -1,
items_xpad, items_ypad,
items_xexpand, items_yexpand, items_xfill, items_yfill);
g_free (text);
}
}
static void
populate_wrapbox_wrappy (GtkWrapBox *wrapbox)
{
GtkWidget *widget, *frame;
gint i;
const gchar *strings[] = {
"These are", "some wrappy label", "texts", "of various", "lengths.",
"They should always be", "shown", "consecutively. Except it's",
"hard to say", "where exactly the", "label", "will wrap", "and where exactly",
"the actual", "container", "will wrap.", "This label is really really really long !",
"Let's add some more", "labels to the",
"mix. Just to", "make sure we", "got something to work", "with here."
};
for (i = 0; i < G_N_ELEMENTS (strings); i++)
{
widget = gtk_label_new (strings[i]);
frame = gtk_frame_new (NULL);
gtk_widget_show (widget);
gtk_widget_show (frame);
if (text_orientation == GTK_ORIENTATION_VERTICAL)
gtk_label_set_angle (GTK_LABEL (widget), 90);
gtk_container_add (GTK_CONTAINER (frame), widget);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
gtk_label_set_line_wrap_mode (GTK_LABEL (widget), PANGO_WRAP_WORD);
gtk_label_set_width_chars (GTK_LABEL (widget), 10);
gtk_wrap_box_insert_child (GTK_WRAP_BOX (wrapbox), frame, -1,
items_xpad, items_ypad,
items_xexpand, items_yexpand, items_xfill, items_yfill);
}
}
static void
populate_wrapbox_stock (GtkWrapBox *wrapbox)
{
GtkWidget *widget;
static GSList *stock_ids = NULL;
GSList *l;
gint i;
if (!stock_ids)
stock_ids = gtk_stock_list_ids ();
for (i = 0, l = stock_ids; i < 30 && l != NULL; i++, l = l->next)
{
gchar *stock_id = l->data;
widget = gtk_button_new_from_stock (stock_id);
gtk_widget_show (widget);
gtk_wrap_box_insert_child (GTK_WRAP_BOX (wrapbox), widget, -1,
items_xpad, items_ypad,
items_xexpand, items_yexpand, items_xfill, items_yfill);
}
}
static void
populate_items (GtkWrapBox *wrapbox)
{
GList *children, *l;
/* Remove all children first */
children = gtk_container_get_children (GTK_CONTAINER (wrapbox));
for (l = children; l; l = l->next)
{
GtkWidget *child = l->data;
gtk_container_remove (GTK_CONTAINER (wrapbox), child);
}
g_list_free (children);
if (items_type == SIMPLE_ITEMS)
populate_wrapbox_simple (wrapbox);
else if (items_type == WRAPPY_ITEMS)
populate_wrapbox_wrappy (wrapbox);
else if (items_type == STOCK_ITEMS)
populate_wrapbox_stock (wrapbox);
}
static void
mode_changed (GtkComboBox *box,
GtkWrapBox *wrapbox)
{
GtkWrapAllocationMode mode = gtk_combo_box_get_active (box);
gtk_wrap_box_set_allocation_mode (wrapbox, mode);
}
static void
spreading_changed (GtkComboBox *box,
GtkWrapBox *wrapbox)
{
GtkWrapBoxSpreading spreading = gtk_combo_box_get_active (box);
gtk_wrap_box_set_spreading (wrapbox, spreading);
}
static void
orientation_changed (GtkComboBox *box,
GtkWrapBox *wrapbox)
{
GtkOrientation orientation = gtk_combo_box_get_active (box);
gtk_orientable_set_orientation (GTK_ORIENTABLE (wrapbox), orientation);
}
static void
line_length_changed (GtkSpinButton *spin,
GtkWrapBox *wrapbox)
{
gint length = gtk_spin_button_get_value_as_int (spin);
gtk_wrap_box_set_minimum_line_children (wrapbox, length);
}
static void
spacing_changed (GtkSpinButton *button,
gpointer data)
{
GtkOrientation orientation = GPOINTER_TO_INT (data);
gint state = gtk_spin_button_get_value_as_int (button);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_wrap_box_set_horizontal_spacing (the_wrapbox, state);
else
gtk_wrap_box_set_vertical_spacing (the_wrapbox, state);
}
static void
items_changed (GtkComboBox *box,
GtkWrapBox *wrapbox)
{
items_type = gtk_combo_box_get_active (box);
populate_items (wrapbox);
}
static void
text_orientation_changed (GtkComboBox *box,
GtkWrapBox *wrapbox)
{
text_orientation = gtk_combo_box_get_active (box);
populate_items (wrapbox);
}
static void
child_option_toggled (GtkToggleButton *button,
gboolean *state)
{
*state = gtk_toggle_button_get_active (button);
populate_items (the_wrapbox);
}
static void
child_padding_changed (GtkSpinButton *button,
gint *state)
{
*state = gtk_spin_button_get_value_as_int (button);
populate_items (the_wrapbox);
}
static GtkWidget *
create_window (void)
{
GtkWidget *window, *hbox, *vbox, *frame, *wrapbox_cntl, *items_cntl;
GtkWidget *wrapbox, *widget, *expander, *swindow;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
hbox = gtk_hbox_new (FALSE, 2);
vbox = gtk_vbox_new (FALSE, 6);
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
gtk_widget_show (vbox);
gtk_widget_show (hbox);
gtk_container_add (GTK_CONTAINER (window), hbox);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
frame = gtk_frame_new ("Wrap Box");
gtk_widget_show (frame);
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (swindow);
gtk_container_add (GTK_CONTAINER (frame), swindow);
wrapbox = gtk_wrap_box_new (INITIAL_ALLOCATION_MODE, INITIAL_SPREADING,
INITIAL_HSPACING, INITIAL_VSPACING);
the_wrapbox = (GtkWrapBox *)wrapbox;
gtk_wrap_box_set_minimum_line_children (GTK_WRAP_BOX (wrapbox), INITIAL_MINIMUM_LENGTH);
gtk_widget_show (wrapbox);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), wrapbox);
/* Add Wrapbox test control frame */
expander = gtk_expander_new ("Wrap Box controls");
gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);
wrapbox_cntl = gtk_vbox_new (FALSE, 2);
gtk_widget_show (wrapbox_cntl);
gtk_widget_show (expander);
gtk_container_add (GTK_CONTAINER (expander), wrapbox_cntl);
gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
/* Add Allocation mode control */
widget = gtk_combo_box_new_text ();
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Wrap Freely");
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Align items");
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Homogeneous");
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), INITIAL_ALLOCATION_MODE);
gtk_widget_show (widget);
gtk_widget_set_tooltip_text (widget, "Set the wrapbox allocation mode");
gtk_box_pack_start (GTK_BOX (wrapbox_cntl), widget, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (mode_changed), wrapbox);
/* Add Spreading control */
widget = gtk_combo_box_new_text ();
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Spread Begin");
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Spread End");
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Spread Even");
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Spread Expand");
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), INITIAL_SPREADING);
gtk_widget_show (widget);
gtk_widget_set_tooltip_text (widget, "Set the wrapbox spread mode");
gtk_box_pack_start (GTK_BOX (wrapbox_cntl), widget, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (spreading_changed), wrapbox);
/* Add Orientation control */
widget = gtk_combo_box_new_text ();
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Horizontal");
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), "Vertical");
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
gtk_widget_show (widget);
gtk_widget_set_tooltip_text (widget, "Set the wrapbox orientation");
gtk_box_pack_start (GTK_BOX (wrapbox_cntl), widget, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (orientation_changed), wrapbox);
/* Add minimum line length in items control */
widget = gtk_spin_button_new_with_range (1, 10, 1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_MINIMUM_LENGTH);
gtk_widget_show (widget);
gtk_widget_set_tooltip_text (widget, "Set the minimum amount of items per line before wrapping");
gtk_box_pack_start (GTK_BOX (wrapbox_cntl), widget, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (line_length_changed), wrapbox);
g_signal_connect (G_OBJECT (widget), "value-changed",
G_CALLBACK (line_length_changed), wrapbox);
/* Add horizontal/vertical spacing controls */
hbox = gtk_hbox_new (FALSE, 2);
gtk_widget_show (hbox);
widget = gtk_label_new ("H Spacing");
gtk_widget_show (widget);
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
widget = gtk_spin_button_new_with_range (0, 30, 1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_HSPACING);
gtk_widget_show (widget);
gtk_widget_set_tooltip_text (widget, "Set the horizontal spacing between children");
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_HORIZONTAL));
g_signal_connect (G_OBJECT (widget), "value-changed",
G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_HORIZONTAL));
gtk_box_pack_start (GTK_BOX (wrapbox_cntl), hbox, FALSE, FALSE, 0);
hbox = gtk_hbox_new (FALSE, 2);
gtk_widget_show (hbox);
widget = gtk_label_new ("V Spacing");
gtk_widget_show (widget);
gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
widget = gtk_spin_button_new_with_range (0, 30, 1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), INITIAL_VSPACING);
gtk_widget_show (widget);
gtk_widget_set_tooltip_text (widget, "Set the vertical spacing between children");
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_VERTICAL));