diff options
Diffstat (limited to 'unix/gtkcols.c')
-rw-r--r-- | unix/gtkcols.c | 1201 |
1 files changed, 0 insertions, 1201 deletions
diff --git a/unix/gtkcols.c b/unix/gtkcols.c deleted file mode 100644 index 35c02875..00000000 --- a/unix/gtkcols.c +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * gtkcols.c - implementation of the `Columns' GTK layout container. - */ - -#include <assert.h> -#include <gtk/gtk.h> -#include "defs.h" -#include "gtkcompat.h" -#include "gtkcols.h" - -#if GTK_CHECK_VERSION(2,0,0) -/* The "focus" method lives in GtkWidget from GTK 2 onwards, but it - * was in GtkContainer in GTK 1 */ -#define FOCUS_METHOD_SUPERCLASS GtkWidget -#define FOCUS_METHOD_LOCATION widget_class /* used in columns_init */ -#define CHILD_FOCUS(cont, dir) gtk_widget_child_focus(GTK_WIDGET(cont), dir) -#else -#define FOCUS_METHOD_SUPERCLASS GtkContainer -#define FOCUS_METHOD_LOCATION container_class -#define CHILD_FOCUS(cont, dir) gtk_container_focus(GTK_CONTAINER(cont), dir) -#endif - -static void columns_init(Columns *cols); -static void columns_class_init(ColumnsClass *klass); -#if !GTK_CHECK_VERSION(2,0,0) -static void columns_finalize(GtkObject *object); -#else -static void columns_finalize(GObject *object); -#endif -static void columns_map(GtkWidget *widget); -static void columns_unmap(GtkWidget *widget); -#if !GTK_CHECK_VERSION(2,0,0) -static void columns_draw(GtkWidget *widget, GdkRectangle *area); -static gint columns_expose(GtkWidget *widget, GdkEventExpose *event); -#endif -static void columns_base_add(GtkContainer *container, GtkWidget *widget); -static void columns_remove(GtkContainer *container, GtkWidget *widget); -static void columns_forall(GtkContainer *container, gboolean include_internals, - GtkCallback callback, gpointer callback_data); -static gint columns_focus(FOCUS_METHOD_SUPERCLASS *container, - GtkDirectionType dir); -static GType columns_child_type(GtkContainer *container); -#if GTK_CHECK_VERSION(3,0,0) -static void columns_get_preferred_width(GtkWidget *widget, - gint *min, gint *nat); -static void columns_get_preferred_height(GtkWidget *widget, - gint *min, gint *nat); -static void columns_get_preferred_width_for_height(GtkWidget *widget, - gint height, - gint *min, gint *nat); -static void columns_get_preferred_height_for_width(GtkWidget *widget, - gint width, - gint *min, gint *nat); -#else -static void columns_size_request(GtkWidget *widget, GtkRequisition *req); -#endif -static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc); - -static GtkContainerClass *parent_class = NULL; - -#if !GTK_CHECK_VERSION(2,0,0) -GType columns_get_type(void) -{ - static GType columns_type = 0; - - if (!columns_type) { - static const GtkTypeInfo columns_info = { - "Columns", - sizeof(Columns), - sizeof(ColumnsClass), - (GtkClassInitFunc) columns_class_init, - (GtkObjectInitFunc) columns_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; - - columns_type = gtk_type_unique(GTK_TYPE_CONTAINER, &columns_info); - } - - return columns_type; -} -#else -GType columns_get_type(void) -{ - static GType columns_type = 0; - - if (!columns_type) { - static const GTypeInfo columns_info = { - sizeof(ColumnsClass), - NULL, - NULL, - (GClassInitFunc) columns_class_init, - NULL, - NULL, - sizeof(Columns), - 0, - (GInstanceInitFunc)columns_init, - }; - - columns_type = g_type_register_static(GTK_TYPE_CONTAINER, "Columns", - &columns_info, 0); - } - - return columns_type; -} -#endif - -static gint (*columns_inherited_focus)(FOCUS_METHOD_SUPERCLASS *container, - GtkDirectionType direction); - -static void columns_class_init(ColumnsClass *klass) -{ -#if !GTK_CHECK_VERSION(2,0,0) - GtkObjectClass *object_class = (GtkObjectClass *)klass; - GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; - GtkContainerClass *container_class = (GtkContainerClass *)klass; -#else - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass); -#endif - -#if !GTK_CHECK_VERSION(2,0,0) - parent_class = gtk_type_class(GTK_TYPE_CONTAINER); -#else - parent_class = g_type_class_peek_parent(klass); -#endif - - object_class->finalize = columns_finalize; - widget_class->map = columns_map; - widget_class->unmap = columns_unmap; -#if !GTK_CHECK_VERSION(2,0,0) - widget_class->draw = columns_draw; - widget_class->expose_event = columns_expose; -#endif -#if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = columns_get_preferred_width; - widget_class->get_preferred_height = columns_get_preferred_height; - widget_class->get_preferred_width_for_height = - columns_get_preferred_width_for_height; - widget_class->get_preferred_height_for_width = - columns_get_preferred_height_for_width; -#else - widget_class->size_request = columns_size_request; -#endif - widget_class->size_allocate = columns_size_allocate; - - container_class->add = columns_base_add; - container_class->remove = columns_remove; - container_class->forall = columns_forall; - container_class->child_type = columns_child_type; - - /* Save the previous value of this method. */ - if (!columns_inherited_focus) - columns_inherited_focus = FOCUS_METHOD_LOCATION->focus; - FOCUS_METHOD_LOCATION->focus = columns_focus; -} - -static void columns_init(Columns *cols) -{ - gtk_widget_set_has_window(GTK_WIDGET(cols), false); - - cols->children = NULL; - cols->spacing = 0; -} - -static void columns_child_free(gpointer vchild) -{ - ColumnsChild *child = (ColumnsChild *)vchild; - if (child->percentages) - g_free(child->percentages); - g_free(child); -} - -static void columns_finalize( -#if !GTK_CHECK_VERSION(2,0,0) - GtkObject *object -#else - GObject *object -#endif - ) -{ - Columns *cols; - - g_return_if_fail(object != NULL); - g_return_if_fail(IS_COLUMNS(object)); - - cols = COLUMNS(object); - -#if !GTK_CHECK_VERSION(2,0,0) - { - GList *node; - for (node = cols->children; node; node = node->next) - if (node->data) - columns_child_free(node->data); - } - g_list_free(cols->children); -#else - g_list_free_full(cols->children, columns_child_free); -#endif - - cols->children = NULL; - -#if !GTK_CHECK_VERSION(2,0,0) - GTK_OBJECT_CLASS(parent_class)->finalize(object); -#else - G_OBJECT_CLASS(parent_class)->finalize(object); -#endif -} - -/* - * These appear to be thoroughly tedious functions; the only reason - * we have to reimplement them at all is because we defined our own - * format for our GList of children... - */ -static void columns_map(GtkWidget *widget) -{ - Columns *cols; - ColumnsChild *child; - GList *children; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - cols = COLUMNS(widget); - gtk_widget_set_mapped(GTK_WIDGET(cols), true); - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget && - gtk_widget_get_visible(child->widget) && - !gtk_widget_get_mapped(child->widget)) - gtk_widget_map(child->widget); - } -} -static void columns_unmap(GtkWidget *widget) -{ - Columns *cols; - ColumnsChild *child; - GList *children; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - cols = COLUMNS(widget); - gtk_widget_set_mapped(GTK_WIDGET(cols), false); - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget && - gtk_widget_get_visible(child->widget) && - gtk_widget_get_mapped(child->widget)) - gtk_widget_unmap(child->widget); - } -} -#if !GTK_CHECK_VERSION(2,0,0) -static void columns_draw(GtkWidget *widget, GdkRectangle *area) -{ - Columns *cols; - ColumnsChild *child; - GList *children; - GdkRectangle child_area; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - if (GTK_WIDGET_DRAWABLE(widget)) { - cols = COLUMNS(widget); - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget && - GTK_WIDGET_DRAWABLE(child->widget) && - gtk_widget_intersect(child->widget, area, &child_area)) - gtk_widget_draw(child->widget, &child_area); - } - } -} -static gint columns_expose(GtkWidget *widget, GdkEventExpose *event) -{ - Columns *cols; - ColumnsChild *child; - GList *children; - GdkEventExpose child_event; - - g_return_val_if_fail(widget != NULL, false); - g_return_val_if_fail(IS_COLUMNS(widget), false); - g_return_val_if_fail(event != NULL, false); - - if (GTK_WIDGET_DRAWABLE(widget)) { - cols = COLUMNS(widget); - child_event = *event; - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget && - 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; -} -#endif - -static void columns_base_add(GtkContainer *container, GtkWidget *widget) -{ - Columns *cols; - - g_return_if_fail(container != NULL); - g_return_if_fail(IS_COLUMNS(container)); - g_return_if_fail(widget != NULL); - - cols = COLUMNS(container); - - /* - * Default is to add a new widget spanning all columns. - */ - columns_add(cols, widget, 0, 0); /* 0 means ncols */ -} - -static void columns_remove(GtkContainer *container, GtkWidget *widget) -{ - Columns *cols; - ColumnsChild *child; - GtkWidget *childw; - GList *children; - bool was_visible; - - g_return_if_fail(container != NULL); - g_return_if_fail(IS_COLUMNS(container)); - g_return_if_fail(widget != NULL); - - cols = COLUMNS(container); - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget != widget) - continue; - - was_visible = gtk_widget_get_visible(widget); - gtk_widget_unparent(widget); - cols->children = g_list_remove_link(cols->children, children); - g_list_free(children); - - if (child->same_height_as) { - g_return_if_fail(child->same_height_as->same_height_as == child); - child->same_height_as->same_height_as = NULL; - if (gtk_widget_get_visible(child->same_height_as->widget)) - gtk_widget_queue_resize(GTK_WIDGET(container)); - } - - g_free(child); - if (was_visible) - gtk_widget_queue_resize(GTK_WIDGET(container)); - break; - } - - for (children = cols->taborder; - children && (childw = children->data); - children = children->next) { - if (childw != widget) - continue; - - cols->taborder = g_list_remove_link(cols->taborder, children); - g_list_free(children); - break; - } -} - -static void columns_forall(GtkContainer *container, gboolean include_internals, - GtkCallback callback, gpointer callback_data) -{ - Columns *cols; - ColumnsChild *child; - GList *children, *next; - - g_return_if_fail(container != NULL); - g_return_if_fail(IS_COLUMNS(container)); - g_return_if_fail(callback != NULL); - - cols = COLUMNS(container); - - for (children = cols->children; - children && (child = children->data); - children = next) { - /* - * We can't wait until after the callback to assign - * `children = children->next', because the callback might - * be gtk_widget_destroy, which would remove the link - * `children' from the list! So instead we must get our - * hands on the value of the `next' pointer _before_ the - * callback. - */ - next = children->next; - if (child->widget) - callback(child->widget, callback_data); - } -} - -static GType columns_child_type(GtkContainer *container) -{ - return GTK_TYPE_WIDGET; -} - -GtkWidget *columns_new(gint spacing) -{ - Columns *cols; - -#if !GTK_CHECK_VERSION(2,0,0) - cols = gtk_type_new(columns_get_type()); -#else - cols = g_object_new(TYPE_COLUMNS, NULL); -#endif - - cols->spacing = spacing; - - return GTK_WIDGET(cols); -} - -void columns_set_cols(Columns *cols, gint ncols, const gint *percentages) -{ - ColumnsChild *childdata; - gint i; - - g_return_if_fail(cols != NULL); - g_return_if_fail(IS_COLUMNS(cols)); - g_return_if_fail(ncols > 0); - g_return_if_fail(percentages != NULL); - - childdata = g_new(ColumnsChild, 1); - childdata->widget = NULL; - childdata->ncols = ncols; - childdata->percentages = g_new(gint, ncols); - childdata->force_left = false; - for (i = 0; i < ncols; i++) - childdata->percentages[i] = percentages[i]; - - cols->children = g_list_append(cols->children, childdata); -} - -void columns_add(Columns *cols, GtkWidget *child, - gint colstart, gint colspan) -{ - ColumnsChild *childdata; - - g_return_if_fail(cols != NULL); - g_return_if_fail(IS_COLUMNS(cols)); - g_return_if_fail(child != NULL); - g_return_if_fail(gtk_widget_get_parent(child) == NULL); - - childdata = g_new(ColumnsChild, 1); - childdata->widget = child; - childdata->colstart = colstart; - childdata->colspan = colspan; - childdata->force_left = false; - childdata->same_height_as = NULL; - childdata->percentages = NULL; - - cols->children = g_list_append(cols->children, childdata); - cols->taborder = g_list_append(cols->taborder, child); - - gtk_widget_set_parent(child, GTK_WIDGET(cols)); - - if (gtk_widget_get_realized(GTK_WIDGET(cols))) - gtk_widget_realize(child); - - if (gtk_widget_get_visible(GTK_WIDGET(cols)) && - gtk_widget_get_visible(child)) { - if (gtk_widget_get_mapped(GTK_WIDGET(cols))) - gtk_widget_map(child); - gtk_widget_queue_resize(child); - } -} - -static ColumnsChild *columns_find_child(Columns *cols, GtkWidget *widget) -{ - GList *children; - ColumnsChild *child; - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - - if (child->widget == widget) - return child; - } - - return NULL; -} - -void columns_force_left_align(Columns *cols, GtkWidget *widget) -{ - ColumnsChild *child; - - g_return_if_fail(cols != NULL); - g_return_if_fail(IS_COLUMNS(cols)); - g_return_if_fail(widget != NULL); - - child = columns_find_child(cols, widget); - g_return_if_fail(child != NULL); - - child->force_left = true; - if (gtk_widget_get_visible(widget)) - gtk_widget_queue_resize(GTK_WIDGET(cols)); -} - -void columns_force_same_height(Columns *cols, GtkWidget *cw1, GtkWidget *cw2) -{ - ColumnsChild *child1, *child2; - - g_return_if_fail(cols != NULL); - g_return_if_fail(IS_COLUMNS(cols)); - g_return_if_fail(cw1 != NULL); - g_return_if_fail(cw2 != NULL); - - child1 = columns_find_child(cols, cw1); - g_return_if_fail(child1 != NULL); - child2 = columns_find_child(cols, cw2); - g_return_if_fail(child2 != NULL); - - child1->same_height_as = child2; - child2->same_height_as = child1; - if (gtk_widget_get_visible(cw1) || gtk_widget_get_visible(cw2)) - gtk_widget_queue_resize(GTK_WIDGET(cols)); -} - -void columns_taborder_last(Columns *cols, GtkWidget *widget) -{ - GtkWidget *childw; - GList *children; - - g_return_if_fail(cols != NULL); - g_return_if_fail(IS_COLUMNS(cols)); - g_return_if_fail(widget != NULL); - - for (children = cols->taborder; - children && (childw = children->data); - children = children->next) { - if (childw != widget) - continue; - - cols->taborder = g_list_remove_link(cols->taborder, children); - g_list_free(children); - cols->taborder = g_list_append(cols->taborder, widget); - break; - } -} - -/* - * Override GtkContainer's focus movement so the user can - * explicitly specify the tab order. - */ -static gint columns_focus(FOCUS_METHOD_SUPERCLASS *super, GtkDirectionType dir) -{ - Columns *cols; - GList *pos; - GtkWidget *focuschild; - - g_return_val_if_fail(super != NULL, false); - g_return_val_if_fail(IS_COLUMNS(super), false); - - cols = COLUMNS(super); - - if (!gtk_widget_is_drawable(GTK_WIDGET(cols)) || - !gtk_widget_is_sensitive(GTK_WIDGET(cols))) - return false; - - if (!gtk_widget_get_can_focus(GTK_WIDGET(cols)) && - (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) { - - focuschild = gtk_container_get_focus_child(GTK_CONTAINER(cols)); - gtk_container_set_focus_child(GTK_CONTAINER(cols), NULL); - - if (dir == GTK_DIR_TAB_FORWARD) - pos = cols->taborder; - else - pos = g_list_last(cols->taborder); - - while (pos) { - GtkWidget *child = pos->data; - - if (focuschild) { - if (focuschild == child) { - focuschild = NULL; /* now we can start looking in here */ - if (gtk_widget_is_drawable(child) && - GTK_IS_CONTAINER(child) && - !gtk_widget_has_focus(child)) { - if (CHILD_FOCUS(child, dir)) - return true; - } - } - } else if (gtk_widget_is_drawable(child)) { - if (GTK_IS_CONTAINER(child)) { - if (CHILD_FOCUS(child, dir)) - return true; - } else if (gtk_widget_get_can_focus(child)) { - gtk_widget_grab_focus(child); - return true; - } - } - - if (dir == GTK_DIR_TAB_FORWARD) - pos = pos->next; - else - pos = pos->prev; - } - - return false; - } else - return columns_inherited_focus(super, dir); -} - -/* - * Underlying parts of the layout algorithm, to compute the Columns - * container's width or height given the widths or heights of its - * children. These will be called in various ways with different - * notions of width and height in use, so we abstract them out and - * pass them a 'get width' or 'get height' function pointer. - */ - -typedef gint (*widget_dim_fn_t)(ColumnsChild *child); - -static gint columns_compute_width(Columns *cols, widget_dim_fn_t get_width) -{ - ColumnsChild *child; - GList *children; - gint i, ncols, colspan, retwidth, childwidth; - const gint *percentages; - static const gint onecol[] = { 100 }; - -#ifdef COLUMNS_WIDTH_DIAGNOSTICS - printf("compute_width(%p): start\n", cols); -#endif - - retwidth = 0; - - ncols = 1; - percentages = onecol; - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - - if (!child->widget) { - /* Column reconfiguration. */ - ncols = child->ncols; - percentages = child->percentages; - continue; - } - - /* Only take visible widgets into account. */ - if (!gtk_widget_get_visible(child->widget)) - continue; - - childwidth = get_width(child); - colspan = child->colspan ? child->colspan : ncols-child->colstart; - assert(colspan > 0); - -#ifdef COLUMNS_WIDTH_DIAGNOSTICS - printf("compute_width(%p): ", cols); - if (GTK_IS_LABEL(child->widget)) - printf("label %p '%s' wrap=%s: ", child->widget, - gtk_label_get_text(GTK_LABEL(child->widget)), - (gtk_label_get_line_wrap(GTK_LABEL(child->widget)) - ? "true" : "false")); - else - printf("widget %p: ", child->widget); - { - gint min, nat; - gtk_widget_get_preferred_width(child->widget, &min, &nat); - printf("minwidth=%d natwidth=%d ", min, nat); - } - printf("thiswidth=%d span=%d\n", childwidth, colspan); -#endif - - /* - * To compute width: we know that childwidth + cols->spacing - * needs to equal a certain percentage of the full width of - * the container. So we work this value out, figure out how - * wide the container will need to be to make that percentage - * of it equal to that width, and ensure our returned width is - * at least that much. Very simple really. - */ - { - int percent, thiswid, fullwid; - - percent = 0; - for (i = 0; i < colspan; i++) - percent += percentages[child->colstart+i]; - - thiswid = childwidth + cols->spacing; - /* - * Since childwidth is (at least sometimes) the _minimum_ - * size the child needs, we must ensure that it gets _at - * least_ that size. Hence, when scaling thiswid up to - * fullwid, we must round up, which means adding percent-1 - * before dividing by percent. - */ - fullwid = (thiswid * 100 + percent - 1) / percent; -#ifdef COLUMNS_WIDTH_DIAGNOSTICS - printf("compute_width(%p): after %p, thiswid=%d fullwid=%d\n", - cols, child->widget, thiswid, fullwid); -#endif - - /* - * The above calculation assumes every widget gets - * cols->spacing on the right. So we subtract - * cols->spacing here to account for the extra load of - * spacing on the right. - */ - if (retwidth < fullwid - cols->spacing) - retwidth = fullwid - cols->spacing; - } - } - - retwidth += 2*gtk_container_get_border_width(GTK_CONTAINER(cols)); - -#ifdef COLUMNS_WIDTH_DIAGNOSTICS - printf("compute_width(%p): done, returning %d\n", cols, retwidth); -#endif - - return retwidth; -} - -static void columns_alloc_horiz(Columns *cols, gint ourwidth, - widget_dim_fn_t get_width) -{ - ColumnsChild *child; - GList *children; - gint i, ncols, colspan, border, *colxpos, childwidth; - - border = gtk_container_get_border_width(GTK_CONTAINER(cols)); - - ncols = 1; - /* colxpos gives the starting x position of each column. - * We supply n+1 of them, so that we can find the RH edge easily. - * All ending x positions are expected to be adjusted afterwards by - * subtracting the spacing. */ - colxpos = g_new(gint, 2); - colxpos[0] = 0; - colxpos[1] = ourwidth - 2*border + cols->spacing; - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - - if (!child->widget) { - gint percent; - - /* Column reconfiguration. */ - ncols = child->ncols; - colxpos = g_renew(gint, colxpos, ncols + 1); - colxpos[0] = 0; - percent = 0; - for (i = 0; i < ncols; i++) { - percent += child->percentages[i]; - colxpos[i+1] = (((ourwidth - 2*border) + cols->spacing) - * percent / 100); - } - continue; - } - - /* Only take visible widgets into account. */ - if (!gtk_widget_get_visible(child->widget)) - continue; - - childwidth = get_width(child); - colspan = child->colspan ? child->colspan : ncols-child->colstart; - - /* - * Starting x position is cols[colstart]. - * Ending x position is cols[colstart+colspan] - spacing. - * - * Unless we're forcing left, in which case the width is - * exactly the requisition width. - */ - child->x = colxpos[child->colstart]; - if (child->force_left) - child->w = childwidth; - else - child->w = (colxpos[child->colstart+colspan] - - colxpos[child->colstart] - cols->spacing); - } - - g_free(colxpos); -} - -static gint columns_compute_height(Columns *cols, widget_dim_fn_t get_height) -{ - ColumnsChild *child; - GList *children; - gint i, ncols, colspan, *colypos, retheight, childheight; - - retheight = cols->spacing; - - ncols = 1; - colypos = g_new(gint, 1); - colypos[0] = 0; - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - - if (!child->widget) { - /* Column reconfiguration. */ - for (i = 1; i < ncols; i++) { - if (colypos[0] < colypos[i]) - colypos[0] = colypos[i]; - } - ncols = child->ncols; - colypos = g_renew(gint, colypos, ncols); - for (i = 1; i < ncols; i++) - colypos[i] = colypos[0]; - continue; - } - - /* Only take visible widgets into account. */ - if (!gtk_widget_get_visible(child->widget)) - continue; - - childheight = get_height(child); - if (child->same_height_as) { - gint childheight2 = get_height(child->same_height_as); - if (childheight < childheight2) - childheight = childheight2; - } - colspan = child->colspan ? child->colspan : ncols-child->colstart; - - /* - * To compute height: the widget's top will be positioned at - * the largest y value so far reached in any of the columns it - * crosses. Then it will go down by childheight plus padding; - * and the point it reaches at the bottom is the new y value - * in all those columns, and minus the padding it is also a - * lower bound on our own height. - */ - { - int topy, boty; - - topy = 0; - for (i = 0; i < colspan; i++) { - if (topy < colypos[child->colstart+i]) - topy = colypos[child->colstart+i]; - } - boty = topy + childheight + cols->spacing; - for (i = 0; i < colspan; i++) { - colypos[child->colstart+i] = boty; - } - - if (retheight < boty - cols->spacing) - retheight = boty - cols->spacing; - } - } - - retheight += 2*gtk_container_get_border_width(GTK_CONTAINER(cols)); - - g_free(colypos); - - return retheight; -} - -static void columns_alloc_vert(Columns *cols, gint ourheight, - widget_dim_fn_t get_height) -{ - ColumnsChild *child; - GList *children; - gint i, ncols, colspan, *colypos, realheight, fakeheight; - - ncols = 1; - /* As in size_request, colypos is the lowest y reached in each column. */ - colypos = g_new(gint, 1); - colypos[0] = 0; - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (!child->widget) { - /* Column reconfiguration. */ - for (i = 1; i < ncols; i++) { - if (colypos[0] < colypos[i]) - colypos[0] = colypos[i]; - } - ncols = child->ncols; - colypos = g_renew(gint, colypos, ncols); - for (i = 1; i < ncols; i++) - colypos[i] = colypos[0]; - continue; - } - - /* Only take visible widgets into account. */ - if (!gtk_widget_get_visible(child->widget)) - continue; - - realheight = fakeheight = get_height(child); - if (child->same_height_as) { - gint childheight2 = get_height(child->same_height_as); - if (fakeheight < childheight2) - fakeheight = childheight2; - } - colspan = child->colspan ? child->colspan : ncols-child->colstart; - - /* - * To compute height: the widget's top will be positioned - * at the largest y value so far reached in any of the - * columns it crosses. Then it will go down by creq.height - * plus padding; and the point it reaches at the bottom is - * the new y value in all those columns. - */ - { - int topy, boty; - - topy = 0; - for (i = 0; i < colspan; i++) { - if (topy < colypos[child->colstart+i]) - topy = colypos[child->colstart+i]; - } - child->y = topy + fakeheight/2 - realheight/2; - child->h = realheight; - boty = topy + fakeheight + cols->spacing; - for (i = 0; i < colspan; i++) { - colypos[child->colstart+i] = boty; - } - } - } - - g_free(colypos); -} - -/* - * Now here comes the interesting bit. The actual layout part is - * done in the following two functions: - * - * columns_size_request() examines the list of widgets held in the - * Columns, and returns a requisition stating the absolute minimum - * size it can bear to be. - * - * columns_size_allocate() is given an allocation telling it what - * size the whole container is going to be, and it calls - * gtk_widget_size_allocate() on all of its (visible) children to - * set their size and position relative to the top left of the - * container. - */ - -#if !GTK_CHECK_VERSION(3,0,0) - -static gint columns_gtk2_get_width(ColumnsChild *child) -{ - GtkRequisition creq; - gtk_widget_size_request(child->widget, &creq); - return creq.width; -} - -static gint columns_gtk2_get_height(ColumnsChild *child) -{ - GtkRequisition creq; - gtk_widget_size_request(child->widget, &creq); - return creq.height; -} - -static void columns_size_request(GtkWidget *widget, GtkRequisition *req) -{ - Columns *cols; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - g_return_if_fail(req != NULL); - - cols = COLUMNS(widget); - - req->width = columns_compute_width(cols, columns_gtk2_get_width); - req->height = columns_compute_height(cols, columns_gtk2_get_height); -} - -static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc) -{ - Columns *cols; - ColumnsChild *child; - GList *children; - gint border; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - g_return_if_fail(alloc != NULL); - - cols = COLUMNS(widget); - gtk_widget_set_allocation(widget, alloc); - - border = gtk_container_get_border_width(GTK_CONTAINER(cols)); - - columns_alloc_horiz(cols, alloc->width, columns_gtk2_get_width); - columns_alloc_vert(cols, alloc->height, columns_gtk2_get_height); - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget && gtk_widget_get_visible(child->widget)) { - GtkAllocation call; - call.x = alloc->x + border + child->x; - call.y = alloc->y + border + child->y; - call.width = child->w; - call.height = child->h; - gtk_widget_size_allocate(child->widget, &call); - } - } -} - -#else /* GTK_CHECK_VERSION(3,0,0) */ - -static gint columns_gtk3_get_min_width(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_width(child->widget, &ret, NULL); - return ret; -} - -static gint columns_gtk3_get_nat_width(ColumnsChild *child) -{ - gint ret; - - if ((GTK_IS_LABEL(child->widget) && - gtk_label_get_line_wrap(GTK_LABEL(child->widget))) || - GTK_IS_ENTRY(child->widget)) { - /* - * We treat wrapping GtkLabels as a special case in this - * layout class, because the whole point of those is that I - * _don't_ want them to take up extra horizontal space for - * long text, but instead to wrap it to whatever size is used - * by the rest of the layout. - * - * GtkEntry gets similar treatment, because in OS X GTK I've - * found that it requests a natural width regardless of the - * output of gtk_entry_set_width_chars. - */ - gtk_widget_get_preferred_width(child->widget, &ret, NULL); - } else { - gtk_widget_get_preferred_width(child->widget, NULL, &ret); - } - return ret; -} - -static gint columns_gtk3_get_minfh_width(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_width_for_height(child->widget, child->h, - &ret, NULL); - return ret; -} - -static gint columns_gtk3_get_natfh_width(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_width_for_height(child->widget, child->h, - NULL, &ret); - return ret; -} - -static gint columns_gtk3_get_min_height(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_height(child->widget, &ret, NULL); - return ret; -} - -static gint columns_gtk3_get_nat_height(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_height(child->widget, NULL, &ret); - return ret; -} - -static gint columns_gtk3_get_minfw_height(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_height_for_width(child->widget, child->w, - &ret, NULL); - return ret; -} - -static gint columns_gtk3_get_natfw_height(ColumnsChild *child) -{ - gint ret; - gtk_widget_get_preferred_height_for_width(child->widget, child->w, - NULL, &ret); - return ret; -} - -static void columns_get_preferred_width(GtkWidget *widget, - gint *min, gint *nat) -{ - Columns *cols; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - cols = COLUMNS(widget); - - if (min) - *min = columns_compute_width(cols, columns_gtk3_get_min_width); - if (nat) - *nat = columns_compute_width(cols, columns_gtk3_get_nat_width); -} - -static void columns_get_preferred_height(GtkWidget *widget, - gint *min, gint *nat) -{ - Columns *cols; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - cols = COLUMNS(widget); - - if (min) - *min = columns_compute_height(cols, columns_gtk3_get_min_height); - if (nat) - *nat = columns_compute_height(cols, columns_gtk3_get_nat_height); -} - -static void columns_get_preferred_width_for_height(GtkWidget *widget, - gint height, - gint *min, gint *nat) -{ - Columns *cols; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - cols = COLUMNS(widget); - - /* FIXME: which one should the get-height function here be? */ - columns_alloc_vert(cols, height, columns_gtk3_get_nat_height); - - if (min) - *min = columns_compute_width(cols, columns_gtk3_get_minfh_width); - if (nat) - *nat = columns_compute_width(cols, columns_gtk3_get_natfh_width); -} - -static void columns_get_preferred_height_for_width(GtkWidget *widget, - gint width, - gint *min, gint *nat) -{ - Columns *cols; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - - cols = COLUMNS(widget); - - /* FIXME: which one should the get-height function here be? */ - columns_alloc_horiz(cols, width, columns_gtk3_get_nat_width); - - if (min) - *min = columns_compute_height(cols, columns_gtk3_get_minfw_height); - if (nat) - *nat = columns_compute_height(cols, columns_gtk3_get_natfw_height); -} - -static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc) -{ - Columns *cols; - ColumnsChild *child; - GList *children; - gint border; - - g_return_if_fail(widget != NULL); - g_return_if_fail(IS_COLUMNS(widget)); - g_return_if_fail(alloc != NULL); - - cols = COLUMNS(widget); - gtk_widget_set_allocation(widget, alloc); - - border = gtk_container_get_border_width(GTK_CONTAINER(cols)); - - columns_alloc_horiz(cols, alloc->width, columns_gtk3_get_min_width); - columns_alloc_vert(cols, alloc->height, columns_gtk3_get_minfw_height); - - for (children = cols->children; - children && (child = children->data); - children = children->next) { - if (child->widget && gtk_widget_get_visible(child->widget)) { - GtkAllocation call; - call.x = alloc->x + border + child->x; - call.y = alloc->y + border + child->y; - call.width = child->w; - call.height = child->h; - gtk_widget_size_allocate(child->widget, &call); - } - } -} - -#endif |