staticvoid
path_from_horizontal_line_rects (cairo_t *cr,
GdkRectangle *lines, int n_lines)
{ int start_line, end_line;
GdkRectangle *r; int i;
/* Join rows vertically by extending to the middle */ for (i = 0; i < n_lines - 1; i++)
{
GdkRectangle *r1 = &lines[i];
GdkRectangle *r2 = &lines[i+1]; int gap, old;
gap = r2->y - (r1->y + r1->height);
r1->height += gap / 2;
old = r2->y;
r2->y = r1->y + r1->height;
r2->height += old - r2->y;
}
cairo_new_path (cr);
start_line = 0;
do
{ for (i = start_line; i < n_lines; i++)
{
r = &lines[i]; if (i == start_line)
cairo_move_to (cr, r->x + r->width, r->y); else
cairo_line_to (cr, r->x + r->width, r->y);
cairo_line_to (cr, r->x + r->width, r->y + r->height);
if (i < n_lines - 1 &&
(r->x + r->width < lines[i+1].x ||
r->x > lines[i+1].x + lines[i+1].width))
{
i++; break;
}
}
end_line = i; for (i = end_line - 1; i >= start_line; i--)
{
r = &lines[i];
cairo_line_to (cr, r->x, r->y + r->height);
cairo_line_to (cr, r->x, r->y);
}
cairo_close_path (cr);
start_line = end_line;
} while (end_line < n_lines);
}
staticvoid
path_from_vertical_line_rects (cairo_t *cr,
GdkRectangle *lines, int n_lines)
{ int start_line, end_line;
GdkRectangle *r; int i;
/* Join rows horizontally by extending to the middle */ for (i = 0; i < n_lines - 1; i++)
{
GdkRectangle *r1 = &lines[i];
GdkRectangle *r2 = &lines[i+1]; int gap, old;
gap = r2->x - (r1->x + r1->width);
r1->width += gap / 2;
old = r2->x;
r2->x = r1->x + r1->width;
r2->width += old - r2->x;
}
cairo_new_path (cr);
start_line = 0;
do
{ for (i = start_line; i < n_lines; i++)
{
r = &lines[i]; if (i == start_line)
cairo_move_to (cr, r->x, r->y + r->height); else
cairo_line_to (cr, r->x, r->y + r->height);
cairo_line_to (cr, r->x + r->width, r->y + r->height);
if (i < n_lines - 1 &&
(r->y + r->height < lines[i+1].y ||
r->y > lines[i+1].y + lines[i+1].height))
{
i++; break;
}
}
end_line = i; for (i = end_line - 1; i >= start_line; i--)
{
r = &lines[i];
cairo_line_to (cr, r->x + r->width, r->y);
cairo_line_to (cr, r->x, r->y);
}
cairo_close_path (cr);
start_line = end_line;
} while (end_line < n_lines);
}
/* Without "focusable" flag try to pass the focus to the child immediately */ if (!gtk_widget_get_focusable (widget))
{ if (child)
{ if (gtk_widget_child_focus (child, direction))
{
GtkFlowBox *box;
box = gtk_flow_box_child_get_box (GTK_FLOW_BOX_CHILD (widget)); if (box)
gtk_flow_box_update_cursor (box, GTK_FLOW_BOX_CHILD (widget)); returnTRUE;
}
} returnFALSE;
}
g_object_get (widget, "has-focus", &had_focus, NULL); if (had_focus)
{ /* If on row, going right, enter into possible container */ if (child &&
(direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD))
{ if (gtk_widget_child_focus (GTK_WIDGET (child), direction)) returnTRUE;
}
returnFALSE;
} elseif (gtk_widget_get_focus_child (widget) != NULL)
{ /* Child has focus, always navigate inside it first */ if (gtk_widget_child_focus (child, direction)) returnTRUE;
/* If exiting child container to the left, select child */ if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
{
gtk_flow_box_child_set_focus (GTK_FLOW_BOX_CHILD (widget)); returnTRUE;
}
returnFALSE;
} else
{ /* If coming from the left, enter into possible container */ if (child &&
(direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD))
{ if (gtk_widget_child_focus (child, direction)) returnTRUE;
}
/* Children are visible if they are shown by the app (visible) *andnotfilteredout(child_visible)bythebox
*/ staticinline gboolean
child_is_visible (GtkWidget *child)
{ return gtk_widget_get_visible (child) &&
gtk_widget_get_child_visible (child);
}
staticint
get_visible_children (GtkFlowBox *box)
{
GSequenceIter *iter; int i = 0;
for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
{
GtkWidget *child;
child = g_sequence_get (iter); if (child_is_visible (child))
i++;
}
while (TRUE)
{
i = 0; while (i < BOX_PRIV (box)->cur_children_per_line)
{ if (g_sequence_iter_is_begin (iter)) return NULL;
iter = g_sequence_iter_prev (iter);
child = g_sequence_get (iter); if (child_is_visible (GTK_WIDGET (child)))
i++;
} if (child && gtk_widget_get_sensitive (GTK_WIDGET (child))) return iter;
}
while (TRUE)
{
i = 0; while (i < BOX_PRIV (box)->cur_children_per_line)
{
iter = g_sequence_iter_next (iter); if (g_sequence_iter_is_end (iter)) return NULL;
child = g_sequence_get (iter); if (child_is_visible (GTK_WIDGET (child)))
i++;
} if (child && gtk_widget_get_sensitive (GTK_WIDGET (child))) return iter;
}
return NULL;
}
/* GtkWidget implementation {{{2 */
/* Size allocation {{{3 */
/* Used in columned modes where all items share at least their *equalwidthsorheights
*/ staticvoid
get_max_item_size (GtkFlowBox *box,
GtkOrientation orientation, int *min_size, int *nat_size)
{
GSequenceIter *iter; int max_min_size = 0; int max_nat_size = 0;
for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
{
GtkWidget *child; int child_min, child_nat;
max_min_size = MAX (max_min_size, child_min);
max_nat_size = MAX (max_nat_size, child_nat);
}
if (min_size)
*min_size = max_min_size;
if (nat_size)
*nat_size = max_nat_size;
}
/* Gets the largest minimum/natural size for a given size (used to get *thelargestitemheightsforafixeditemwidthandtheopposite)
*/ staticvoid
get_largest_size_for_opposing_orientation (GtkFlowBox *box,
GtkOrientation orientation, int item_size, int *min_item_size, int *nat_item_size)
{
GSequenceIter *iter; int max_min_size = 0; int max_nat_size = 0;
for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
{
GtkWidget *child; int child_min, child_nat;
max_min_size = MAX (max_min_size, child_min);
max_nat_size = MAX (max_nat_size, child_nat);
}
if (min_item_size)
*min_item_size = max_min_size;
if (nat_item_size)
*nat_item_size = max_nat_size;
}
/* Gets the largest minimum/natural size on a single line for a given size *(usedtogetthelargestlineheightsforafixeditemwidthandtheopposite *whileiteratingoveralistofchildren,notethenewindexisreturned)
*/ static GSequenceIter *
get_largest_size_for_line_in_opposing_orientation (GtkFlowBox *box,
GtkOrientation orientation,
GSequenceIter *cursor, int line_length,
GtkRequestedSize *item_sizes, int extra_pixels, int *min_item_size, int *nat_item_size)
{
GSequenceIter *iter; int max_min_size = 0; int max_nat_size = 0; int i;
i = 0; for (iter = cursor;
!g_sequence_iter_is_end (iter) && i < line_length;
iter = g_sequence_iter_next (iter))
{
GtkWidget *child; int child_min, child_nat, this_item_size;
child = g_sequence_get (iter);
if (!child_is_visible (child)) continue;
/* Distribute the extra pixels to the first children in the line
* (could be fancier and spread them out more evenly) */
this_item_size = item_sizes[i].minimum_size; if (extra_pixels > 0 && ORIENTATION_ALIGN (box) == GTK_ALIGN_FILL)
{
this_item_size++;
extra_pixels--;
}
max_min_size = MAX (max_min_size, child_min);
max_nat_size = MAX (max_nat_size, child_nat);
i++;
}
if (min_item_size)
*min_item_size = max_min_size;
if (nat_item_size)
*nat_item_size = max_nat_size;
/* Return next item in the list */ return iter;
}
/* fit_aligned_item_requests() helper */ staticint
gather_aligned_item_requests (GtkFlowBox *box,
GtkOrientation orientation, int line_length, int item_spacing, int n_children,
GtkRequestedSize *item_sizes)
{
GSequenceIter *iter; int i; int extra_items, natural_line_size = 0;
extra_items = n_children % line_length;
i = 0; for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
{
GtkWidget *child;
GtkAlign item_align; int child_min, child_nat; int position;
/* Get the index and push it over for the last line when spreading to the end */
position = i % line_length;
item_align = ORIENTATION_ALIGN (box); if (item_align == GTK_ALIGN_END && i >= n_children - extra_items)
position += line_length - extra_items;
/* Round up the size of every column/row */
item_sizes[position].minimum_size = MAX (item_sizes[position].minimum_size, child_min);
item_sizes[position].natural_size = MAX (item_sizes[position].natural_size, child_nat);
i++;
}
for (i = 0; i < line_length; i++)
natural_line_size += item_sizes[i].natural_size;
static GtkRequestedSize *
fit_aligned_item_requests (GtkFlowBox *box,
GtkOrientation orientation, int avail_size, int item_spacing, int *line_length, /* in-out */ int items_per_line, int n_children)
{
GtkRequestedSize *sizes, *try_sizes; int try_line_size, try_length;
sizes = g_new0 (GtkRequestedSize, *line_length);
/* get the sizes for the initial guess */
try_line_size = gather_aligned_item_requests (box,
orientation,
*line_length,
item_spacing,
n_children,
sizes);
/* Try columnizing the whole thing and adding an item to the end of *theline;trytofitasmanycolumnsintotheavailablesizeas *possible
*/ for (try_length = *line_length + 1; try_line_size < avail_size; try_length++)
{
try_sizes = g_new0 (GtkRequestedSize, try_length);
try_line_size = gather_aligned_item_requests (box,
orientation,
try_length,
item_spacing,
n_children,
try_sizes);
g_free (sizes);
sizes = try_sizes;
} else
{ /* oops, this one failed; stick to the last size that fit and then return */
g_free (try_sizes); break;
}
}
return sizes;
}
typedefstruct {
GArray *requested; int extra_pixels;
} AllocatedLine;
staticint
get_offset_pixels (GtkAlign align, int pixels)
{ int offset;
switch (align) { case GTK_ALIGN_START: case GTK_ALIGN_FILL:
offset = 0; break; case GTK_ALIGN_CENTER:
offset = pixels / 2; break; case GTK_ALIGN_END:
offset = pixels; break; case GTK_ALIGN_BASELINE_FILL: case GTK_ALIGN_BASELINE_CENTER: default:
g_assert_not_reached (); break;
}
return offset;
}
staticvoid
gtk_flow_box_size_allocate (GtkWidget *widget, int width, int height, int baseline)
{
GtkFlowBox *box = GTK_FLOW_BOX (widget);
GtkFlowBoxPrivate *priv = BOX_PRIV (box);
GtkAllocation child_allocation; int avail_size, avail_other_size, min_items, item_spacing, line_spacing;
GtkAlign item_align;
GtkAlign line_align;
GtkRequestedSize *line_sizes = NULL;
GtkRequestedSize *item_sizes = NULL; int min_item_size, nat_item_size; int line_length; int item_size = 0; int line_size = 0, min_fixed_line_size = 0, nat_fixed_line_size = 0; int line_offset, item_offset, n_children, n_lines, line_count; int extra_pixels = 0, extra_per_item = 0, extra_extra = 0; int extra_line_pixels = 0, extra_per_line = 0, extra_line_extra = 0; int i, this_line_size;
GSequenceIter *iter;
/* By default flow at the natural item width */
line_length = avail_size / (nat_item_size + item_spacing);
/* After the above approximation, check if we can't fit one more on the line */ if (line_length * item_spacing + (line_length + 1) * nat_item_size <= avail_size)
line_length++;
/* Its possible we were allocated just less than the natural width of the *minimumitemflowlength
*/
line_length = MAX (min_items, line_length);
line_length = MIN (line_length, priv->max_children_per_line);
/* Here we just use the largest height-for-width and use that for the height *ofalllines
*/ if (priv->homogeneous)
{
n_lines = n_children / line_length; if ((n_children % line_length) > 0)
n_lines++;
n_lines = MAX (n_lines, 1);
/* Now we need the real item allocation size */
item_size = (avail_size - (line_length - 1) * item_spacing) / line_length;
/* Cut out the expand space if we're not distributing any */ if (item_align != GTK_ALIGN_FILL)
item_size = MIN (item_size, nat_item_size);
if (line_align != GTK_ALIGN_FILL)
line_size = MIN (line_size, nat_fixed_line_size);
/* Get the real extra pixels in case of GTK_ALIGN_START lines */
extra_pixels = avail_size - (line_length - 1) * item_spacing - item_size * line_length;
extra_line_pixels = avail_other_size - (n_lines - 1) * line_spacing - line_size * n_lines;
} else
{
gboolean first_line = TRUE;
/* Find the amount of columns that can fit aligned into the available space *andcollecttheirrequests.
*/
item_sizes = fit_aligned_item_requests (box,
priv->orientation,
avail_size,
item_spacing,
&line_length,
priv->max_children_per_line,
n_children);
/* Calculate the number of lines after determining the final line_length */
n_lines = n_children / line_length; if ((n_children % line_length) > 0)
n_lines++;
n_lines = MAX (n_lines, 1);
line_sizes = g_new0 (GtkRequestedSize, n_lines);
/* Get the available remaining size */
avail_size -= (line_length - 1) * item_spacing; for (i = 0; i < line_length; i++)
avail_size -= item_sizes[i].minimum_size;
/* Perform a natural allocation on the columnized items and get the remaining pixels */ if (avail_size > 0)
extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
/* Now that we have the size of each column of items find the size of each individual *linebasedonthealigneditemsizes.
*/
for (i = 0, iter = g_sequence_get_begin_iter (priv->children);
!g_sequence_iter_is_end (iter) && i < n_lines;
i++)
{
iter = get_largest_size_for_line_in_opposing_orientation (box,
priv->orientation,
iter,
line_length,
item_sizes,
extra_pixels,
&line_sizes[i].minimum_size,
&line_sizes[i].natural_size);
/* Its possible a line is made of completely invisible children */ if (line_sizes[i].natural_size > 0)
{ if (first_line)
first_line = FALSE; else
avail_other_size -= line_spacing;
avail_other_size -= line_sizes[i].minimum_size;
line_sizes[i].data = GINT_TO_POINTER (i);
}
}
/* Distribute space among lines naturally */ if (avail_other_size > 0)
extra_line_pixels = gtk_distribute_natural_allocation (avail_other_size, n_lines, line_sizes);
}
/* FIXME: This portion needs to consider which columns *androwsaskedforexpandspaceanddistributethose *accordinglyforthecaseofALIGNEDallocation. * *Ifatleastonechildinacolumn/rowaskedforexpand; *weshouldmakethatrow/columnexpandentirely.
*/
/* Calculate expand space per item */ if (item_align == GTK_ALIGN_FILL)
{
extra_per_item = extra_pixels / line_length;
extra_extra = extra_pixels % line_length;
}
/* Calculate expand space per line */ if (line_align == GTK_ALIGN_FILL)
{
extra_per_line = extra_line_pixels / n_lines;
extra_line_extra = extra_line_pixels % n_lines;
}
/* prepend extra space to item_offset/line_offset for SPREAD_END */
item_offset = get_offset_pixels (item_align, extra_pixels);
line_offset = get_offset_pixels (line_align, extra_line_pixels);
/* Get the allocation size for the first line */ if (priv->homogeneous)
this_line_size = line_size; else
{
this_line_size = line_sizes[0].minimum_size;
if (line_align == GTK_ALIGN_FILL)
{
this_line_size += extra_per_line;
if (extra_line_extra > 0)
this_line_size++;
}
}
i = 0;
line_count = 0; for (iter = g_sequence_get_begin_iter (priv->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
{
GtkWidget *child; int position; int this_item_size; int last_line_n_items = n_children % line_length;
if (last_line_n_items == 0)
last_line_n_items = line_length;
int last_line_extra_items = line_length - last_line_n_items;
child = g_sequence_get (iter);
if (!child_is_visible (child)) continue;
/* Get item position */
position = i % line_length;
/* adjust the line_offset/count at the beginning of each new line */ if (i > 0 && position == 0)
{ /* Push the line_offset */
line_offset += this_line_size + line_spacing;
line_count++;
/* Get the new line size */ if (priv->homogeneous)
this_line_size = line_size; else
{
this_line_size = line_sizes[line_count].minimum_size;
if (line_align == GTK_ALIGN_FILL)
{
this_line_size += extra_per_line;
if (line_count < extra_line_extra)
this_line_size++;
}
}
/* If we're on the last line, prepend the space for
* any leading items */ if (line_count == n_lines -1)
{ if (priv->homogeneous)
{
item_offset += item_size * last_line_extra_items;
item_offset += item_spacing * last_line_extra_items;
} else
{ int j;
/* Push the index along for the last line when spreading to the end */ if (item_align == GTK_ALIGN_END && line_count == n_lines -1)
position += last_line_extra_items;
if (priv->homogeneous)
this_item_size = item_size; else
this_item_size = item_sizes[position].minimum_size;
if (item_align == GTK_ALIGN_FILL)
{
this_item_size += extra_per_item;
if (visible_child) return gtk_widget_get_request_mode (visible_child);
return GTK_SIZE_REQUEST_CONSTANT_SIZE;
}
/* Gets the largest minimum and natural length of
* 'line_length' consecutive items when aligned into rows/columns */ staticvoid
get_largest_aligned_line_length (GtkFlowBox *box,
GtkOrientation orientation, int line_length, int *min_size, int *nat_size)
{
GSequenceIter *iter; int max_min_size = 0; int max_nat_size = 0; int spacing, i;
GtkRequestedSize *aligned_item_sizes;
/* Get the largest sizes of each index in the line.
*/
i = 0; for (iter = g_sequence_get_begin_iter (BOX_PRIV (box)->children);
!g_sequence_iter_is_end (iter);
iter = g_sequence_iter_next (iter))
{
GtkWidget *child; int child_min, child_nat;
child = g_sequence_get (iter); if (!child_is_visible (child)) continue;
aligned_item_sizes[i % line_length].minimum_size =
MAX (aligned_item_sizes[i % line_length].minimum_size, child_min);
aligned_item_sizes[i % line_length].natural_size =
MAX (aligned_item_sizes[i % line_length].natural_size, child_nat);
i++;
}
/* Add up the largest indexes */ for (i = 0; i < line_length; i++)
{
max_min_size += aligned_item_sizes[i].minimum_size;
max_nat_size += aligned_item_sizes[i].natural_size;
}
staticvoid
gtk_flow_box_measure (GtkWidget *widget,
GtkOrientation orientation, int for_size, int *minimum, int *natural, int *minimum_baseline, int *natural_baseline)
{
GtkFlowBox *box = GTK_FLOW_BOX (widget);
GtkFlowBoxPrivate *priv = BOX_PRIV (box);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{ if (for_size < 0)
{ int min_item_width, nat_item_width; int min_items, nat_items; int min_width, nat_width;
min_items = MAX (1, priv->min_children_per_line);
nat_items = MAX (min_items, priv->max_children_per_line);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
min_width = nat_width = 0;
if (!priv->homogeneous)
{ /* When not homogeneous; horizontally oriented boxes *needenoughwidthforthewidestrow
*/ int min_line_length, nat_line_length;
if (nat_items > min_items)
get_largest_aligned_line_length (box,
GTK_ORIENTATION_HORIZONTAL,
nat_items,
NULL,
&nat_line_length);
min_width += min_line_length;
nat_width += nat_line_length;
} else/* In homogeneous mode; horizontally oriented boxes
* give the same width to all children */
{
get_max_item_size (box, GTK_ORIENTATION_HORIZONTAL,
&min_item_width, &nat_item_width);
*minimum = min_width;
*natural = nat_width;
} else
{ int min_item_height, nat_item_height; int min_items; int min_width, nat_width; int avail_size, n_children;
min_items = MAX (1, priv->min_children_per_line);
min_width = 0;
nat_width = 0;
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{ /* Binary search :( */ int min, max; int min_height, nat_height;
gtk_flow_box_measure (widget,
GTK_ORIENTATION_HORIZONTAL,
-1,
&min_width, &nat_width,
NULL, NULL);
min = min_width;
max = G_MAXINT;
while (min < max)
{ int test;
if (max != G_MAXINT)
test = (min + max) / 2; elseif (min == min_width)
test = min; else
test = min * 2;
gtk_flow_box_measure (widget, GTK_ORIENTATION_VERTICAL,
test, &min_height, &nat_height,
NULL, NULL); if (min_height > for_size)
min = test + 1; else
max = test;
} /* TODO: calculate natural size properly */
min_width = min;
nat_width = MAX (min, nat_width);
} else/* GTK_ORIENTATION_VERTICAL */
{ int min_height; int line_length; int item_size, extra_pixels; int dummy;
n_children = get_visible_children (box); if (n_children <= 0) goto out_width;
/* Make sure its no smaller than the minimum */
gtk_flow_box_measure (widget,
GTK_ORIENTATION_VERTICAL,
-1,
&min_height, &dummy,
NULL, NULL);
avail_size = MAX (for_size, min_height); if (avail_size <= 0) goto out_width;
/* By default flow at the natural item width */
line_length = avail_size / (nat_item_height + priv->row_spacing);
/* After the above approximation, check if we can't fit one more on the line */ if (line_length * priv->row_spacing + (line_length + 1) * nat_item_height <= avail_size)
line_length++;
/* Its possible we were allocated just less than the natural width of the *minimumitemflowlength
*/
line_length = MAX (min_items, line_length);
line_length = MIN (line_length, priv->max_children_per_line);
/* Now we need the real item allocation size */
item_size = (avail_size - (line_length - 1) * priv->row_spacing) / line_length;
/* Cut out the expand space if we're not distributing any */ if (gtk_widget_get_valign (widget) != GTK_ALIGN_FILL)
{
item_size = MIN (item_size, nat_item_height);
extra_pixels = 0;
} else /* Collect the extra pixels for expand children */
extra_pixels = (avail_size - (line_length - 1) * priv->row_spacing) % line_length;
if (priv->homogeneous)
{ int min_item_width, nat_item_width; int lines;
/* Here we just use the largest height-for-width and *addupthesizeaccordingly
*/
get_largest_size_for_opposing_orientation (box,
GTK_ORIENTATION_VERTICAL,
item_size,
&min_item_width,
&nat_item_width);
/* Round up how many lines we need to allocate for */
n_children = get_visible_children (box);
lines = n_children / line_length; if ((n_children % line_length) > 0)
lines++;
/* First get the size each set of items take to span the line *whenaligningtheitemsaboveandbelowafterflowping.
*/
item_sizes = fit_aligned_item_requests (box,
priv->orientation,
avail_size,
priv->row_spacing,
&line_length,
priv->max_children_per_line,
n_children);
/* Get the available remaining size */
avail_size -= (line_length - 1) * priv->column_spacing; for (i = 0; i < line_length; i++)
avail_size -= item_sizes[i].minimum_size;
if (avail_size > 0)
extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
for (iter = g_sequence_get_begin_iter (priv->children);
!g_sequence_iter_is_end (iter);)
{
iter = get_largest_size_for_line_in_opposing_orientation (box,
GTK_ORIENTATION_VERTICAL,
iter,
line_length,
item_sizes,
extra_pixels,
&min_line_width,
&nat_line_width);
/* Its possible the last line only had invisible widgets */ if (nat_line_width > 0)
{ if (first_line)
first_line = FALSE; else
{
min_width += priv->column_spacing;
nat_width += priv->column_spacing;
}
*minimum = min_height;
*natural = nat_height;
} else
{ int min_item_width, nat_item_width; int min_items; int min_height, nat_height; int avail_size, n_children;
min_items = MAX (1, priv->min_children_per_line);
min_height = 0;
nat_height = 0;
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{ int min_width; int line_length; int item_size, extra_pixels; int dummy;
n_children = get_visible_children (box); if (n_children <= 0) goto out_height;
/* Make sure its no smaller than the minimum */
gtk_flow_box_measure (widget,
GTK_ORIENTATION_HORIZONTAL,
-1,
&min_width, &dummy,
NULL, NULL);
avail_size = MAX (for_size, min_width); if (avail_size <= 0) goto out_height;
/* By default flow at the natural item width */
line_length = avail_size / (nat_item_width + priv->column_spacing);
/* After the above approximation, check if we can't fit one more on the line */ if (line_length * priv->column_spacing + (line_length + 1) * nat_item_width <= avail_size)
line_length++;
/* Its possible we were allocated just less than the natural width of the *minimumitemflowlength
*/
line_length = MAX (min_items, line_length);
line_length = MIN (line_length, priv->max_children_per_line);
/* Now we need the real item allocation size */
item_size = (avail_size - (line_length - 1) * priv->column_spacing) / line_length;
/* Cut out the expand space if we're not distributing any */ if (gtk_widget_get_halign (widget) != GTK_ALIGN_FILL)
{
item_size = MIN (item_size, nat_item_width);
extra_pixels = 0;
} else /* Collect the extra pixels for expand children */
extra_pixels = (avail_size - (line_length - 1) * priv->column_spacing) % line_length;
if (priv->homogeneous)
{ int min_item_height, nat_item_height; int lines;
/* Here we just use the largest height-for-width and *addupthesizeaccordingly
*/
get_largest_size_for_opposing_orientation (box,
GTK_ORIENTATION_HORIZONTAL,
item_size,
&min_item_height,
&nat_item_height);
/* Round up how many lines we need to allocate for */
lines = n_children / line_length; if ((n_children % line_length) > 0)
lines++;
/* First get the size each set of items take to span the line *whenaligningtheitemsaboveandbelowafterflowping.
*/
item_sizes = fit_aligned_item_requests (box,
priv->orientation,
avail_size,
priv->column_spacing,
&line_length,
priv->max_children_per_line,
n_children);
/* Get the available remaining size */
avail_size -= (line_length - 1) * priv->column_spacing; for (i = 0; i < line_length; i++)
avail_size -= item_sizes[i].minimum_size;
if (avail_size > 0)
extra_pixels = gtk_distribute_natural_allocation (avail_size, line_length, item_sizes);
for (iter = g_sequence_get_begin_iter (priv->children);
!g_sequence_iter_is_end (iter);)
{
iter = get_largest_size_for_line_in_opposing_orientation (box,
GTK_ORIENTATION_HORIZONTAL,
iter,
line_length,
item_sizes,
extra_pixels,
&min_line_height,
&nat_line_height); /* Its possible the line only had invisible widgets */ if (nat_line_height > 0)
{ if (first_line)
first_line = FALSE; else
{
min_height += priv->row_spacing;
nat_height += priv->row_spacing;
}
switch (priv->autoscroll_mode)
{ case GTK_SCROLL_STEP_FORWARD:
factor = AUTOSCROLL_FACTOR; break; case GTK_SCROLL_STEP_BACKWARD:
factor = - AUTOSCROLL_FACTOR; break; case GTK_SCROLL_PAGE_FORWARD:
factor = AUTOSCROLL_FACTOR_FAST; break; case GTK_SCROLL_PAGE_BACKWARD:
factor = - AUTOSCROLL_FACTOR_FAST; break; case GTK_SCROLL_NONE: case GTK_SCROLL_JUMP: case GTK_SCROLL_STEP_UP: case GTK_SCROLL_STEP_DOWN: case GTK_SCROLL_STEP_LEFT: case GTK_SCROLL_STEP_RIGHT: case GTK_SCROLL_PAGE_UP: case GTK_SCROLL_PAGE_DOWN: case GTK_SCROLL_PAGE_LEFT: case GTK_SCROLL_PAGE_RIGHT: case GTK_SCROLL_START: case GTK_SCROLL_END: default:
g_assert_not_reached (); break;
}
if (focus_child != NULL)
{ if (gtk_widget_child_focus (focus_child, direction)) returnTRUE;
iter = CHILD_PRIV (focus_child)->iter;
if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
iter = gtk_flow_box_get_previous_focusable (box, iter); elseif (direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD)
iter = gtk_flow_box_get_next_focusable (box, iter); elseif (direction == GTK_DIR_UP)
iter = gtk_flow_box_get_above_focusable (box, iter); elseif (direction == GTK_DIR_DOWN)
iter = gtk_flow_box_get_below_focusable (box, iter);
if (iter != NULL)
next_focus_child = g_sequence_get (iter);
} else
{ if (BOX_PRIV (box)->selected_child)
next_focus_child = BOX_PRIV (box)->selected_child; else
{ if (direction == GTK_DIR_UP || direction == GTK_DIR_TAB_BACKWARD)
iter = gtk_flow_box_get_last_focusable (box); else
iter = gtk_flow_box_get_first_focusable (box);
if (iter != NULL)
next_focus_child = g_sequence_get (iter);
}
}
if (next_focus_child == NULL)
{ if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN ||
direction == GTK_DIR_LEFT || direction == GTK_DIR_RIGHT)
{ if (gtk_widget_keynav_failed (GTK_WIDGET (box), direction)) returnTRUE;
}
returnFALSE;
}
if (gtk_widget_child_focus (GTK_WIDGET (next_focus_child), direction)) returnTRUE;
case GTK_MOVEMENT_BUFFER_ENDS: if (count < 0)
iter = gtk_flow_box_get_first_focusable (box); else
iter = gtk_flow_box_get_last_focusable (box); if (iter != NULL)
child = g_sequence_get (iter); break;
case GTK_MOVEMENT_DISPLAY_LINES: if (priv->cursor_child != NULL)
{
iter = CHILD_PRIV (priv->cursor_child)->iter;
while (count < 0 && iter != NULL)
{
iter = gtk_flow_box_get_above_focusable (box, iter);
count = count + 1;
} while (count > 0 && iter != NULL)
{
iter = gtk_flow_box_get_below_focusable (box, iter);
count = count - 1;
}
if (iter != NULL)
child = g_sequence_get (iter);
} break;
case GTK_MOVEMENT_PAGES:
page_size = 100;
adjustment = vertical ? priv->hadjustment : priv->vadjustment; if (adjustment)
page_size = gtk_adjustment_get_page_increment (adjustment);
/* Up */ while (iter != NULL)
{
iter = gtk_flow_box_get_previous_focusable (box, iter); if (iter == NULL) break;
prev = g_sequence_get (iter);
/* go up an even number of rows */ if (i % priv->cur_children_per_line == 0)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_widget_get_allocation (GTK_WIDGET (prev), &allocation);
G_GNUC_END_IGNORE_DEPRECATIONS if ((vertical ? allocation.x : allocation.y) < start - page_size) break;
}
child = prev;
i++;
}
} else
{ int i = 0;
/* Down */ while (!g_sequence_iter_is_end (iter))
{
iter = gtk_flow_box_get_next_focusable (box, iter); if (iter == NULL || g_sequence_iter_is_end (iter)) break;
next = g_sequence_get (iter);
if (i % priv->cur_children_per_line == 0)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_widget_get_allocation (GTK_WIDGET (next), &allocation);
G_GNUC_END_IGNORE_DEPRECATIONS if ((vertical ? allocation.x : allocation.y) > start + page_size) break;
}
if (child == NULL || child == priv->cursor_child)
{
GtkDirectionType direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
if (!gtk_widget_keynav_failed (GTK_WIDGET (box), direction))
{ returnFALSE;
}
returnTRUE;
}
/* If the child has its "focusable" property set to FALSE then it will *notgrabthefocus.Wemustpassthefocustoitschilddirectly.
*/ if (!gtk_widget_get_focusable (GTK_WIDGET (child)))
{
GtkWidget *subchild;
/* We need to sink the floating reference here, so that we can accept *bothinstancescreatedwithafloatingreference(e.g.Cfunctions *thatjustreturntheresultofg_object_new())andwithout(e.g. *fromlanguagebindingswhichwillautomaticallysinkthefloating *reference). * *Seethesimilarcodeingtklistbox.c:gtk_list_box_bound_model_changed.
*/ if (g_object_is_floating (widget))
g_object_ref_sink (widget);
gtk_widget_set_visible (widget, TRUE);
gtk_flow_box_insert (box, widget, position + i);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.129Bemerkung:
(vorverarbeitet am 2026-07-02)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.