gint *min, gint *nat);
static void columns_get_preferred_height(GtkWidget *widget,
gint *min, gint *nat);
-#endif
+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(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
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));
childdata->colstart = colstart;
childdata->colspan = colspan;
childdata->force_left = FALSE;
+ childdata->same_height_as = NULL;
cols->children = g_list_append(cols->children, childdata);
cols->taborder = g_list_append(cols->taborder, 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;
- GList *children;
g_return_if_fail(cols != NULL);
g_return_if_fail(IS_COLUMNS(cols));
g_return_if_fail(widget != NULL);
- for (children = cols->children;
- children && (child = children->data);
- children = children->next) {
- if (child->widget != widget)
- continue;
+ 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));
- break;
- }
+ 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)
const gint *percentages;
static const gint onecol[] = { 100 };
+#ifdef COLUMNS_WIDTH_DIAGNOSTICS
+ printf("compute_width(%p): start\n", cols);
+#endif
+
retwidth = 0;
ncols = 1;
childwidth = get_width(child);
colspan = child->colspan ? child->colspan : ncols-child->colstart;
+#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
* 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
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;
}
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;
/*
{
ColumnsChild *child;
GList *children;
- gint i, ncols, colspan, *colypos, childheight;
+ gint i, ncols, colspan, *colypos, realheight, fakeheight;
ncols = 1;
/* As in size_request, colypos is the lowest y reached in each column. */
if (!gtk_widget_get_visible(child->widget))
continue;
- childheight = get_height(child);
+ 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;
/*
if (topy < colypos[child->colstart+i])
topy = colypos[child->colstart+i];
}
- child->y = topy;
- child->h = childheight;
- boty = topy + childheight + cols->spacing;
+ 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;
}
* container.
*/
+#if !GTK_CHECK_VERSION(3,0,0)
+
static gint columns_gtk2_get_width(ColumnsChild *child)
{
GtkRequisition creq;
req->height = columns_compute_height(cols, columns_gtk2_get_height);
}
-#if GTK_CHECK_VERSION(3,0,0)
+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)
{
- GtkRequisition req;
- columns_size_request(widget, &req);
- *min = *nat = req.width;
+ 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)
+ gint *min, gint *nat)
{
- GtkRequisition req;
- columns_size_request(widget, &req);
- *min = *nat = req.height;
+ 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);
}
-#endif
static void columns_size_allocate(GtkWidget *widget, GtkAllocation *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);
+ 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);
}
}
}
+
+#endif