<commit_before>package tripleplay.ui.layout;

import java.util.ArrayList;
import java.util.List;

import pythagoras.f.Dimension;
import pythagoras.f.IDimension;
import tripleplay.ui.Element;
import tripleplay.ui.Elements;
import tripleplay.ui.Layout;
import tripleplay.ui.Style;

/**
 * Lays out elements in horizontal rows, starting a new row when a width limit is reached. By
 * default, the hint width is used as the limit; this can be overridden with a fixed value.
 * <p>TODO: vertical</p>
 */
public class FlowLayout extends Layout
{
    /** The default gap between rows and elements in a row. */
    public static final float DEFAULT_GAP = 5;

    /**
     * Sets the maximum width of a row of elements. This should normally be used whenever a flow
     * layout governs {@code Elements} that have horizontal siblings. By default, the hint width
     * is used.
     */
    public FlowLayout wrapAt (float width) {
        _wrapWidth = width;
        return this;
    }

    /**
     * Sets the gap, in pixels, to use between rows and between elements within a row.
     */
    public FlowLayout gaps (float gap) {
        _hgap = _vgap = gap;
        return this;
    }

    /**
     * Sets the gap, in pixels, to use between rows and between elements within a row.
     * @param hgap the gap to use between elements in a row
     * @param vgap the gap to use between rows
     */
    public FlowLayout gaps (float hgap, float vgap) {
        _hgap = hgap;
        _vgap = vgap;
        return this;
    }

    /**
     * Sets the alignment used for positioning elements within their row. By default, elements
     * are centered vertically: {@link Style.VAlign#CENTER}.
     */
    public FlowLayout align (Style.VAlign align) {
        _valign = align;
        return this;
    }

    @Override public Dimension computeSize (Elements<?> elems, float hintX, float hintY) {
        Metrics m = computeMetrics(elems, hintX, hintY);
        return m.size;
    }

    @Override public void layout (Elements<?> elems,
                                  float left, float top, float width, float height) {
        Style.HAlign halign = resolveStyle(elems, Style.HALIGN);
        Metrics m = computeMetrics(elems, width, height);
        float y = top + resolveStyle(elems, Style.VALIGN).offset(m.size.height, height);
        for (int elemIdx = 0, row = 0, size = m.rowBreaks.size(); row < size; ++row) {
            Dimension rowSize = m.rows.get(row);
            float x = left + halign.offset(rowSize.width, width);
            for (; elemIdx < m.rowBreaks.get(row).intValue(); ++elemIdx) {
                Element<?> elem = elems.childAt(elemIdx);
                if (!elem.isVisible()) continue;
                IDimension esize = preferredSize(elem, width, height);
                setBounds(elem, x, y + _valign.offset(esize.height(), rowSize.height()),
                    esize.width(), esize.height());
                x += esize.width() + _hgap;
            }
            y += _vgap + rowSize.height;
        }
    }

    protected Metrics computeMetrics (Elements<?> elems, float width, float height) {
        Metrics m = new Metrics();<commit_msg>Allow flowed items to stretch vertically<commit_after>package tripleplay.ui.layout;

import java.util.ArrayList;
import java.util.List;

import pythagoras.f.Dimension;
import pythagoras.f.IDimension;
import tripleplay.ui.Element;
import tripleplay.ui.Elements;
import tripleplay.ui.Layout;
import tripleplay.ui.Style;

/**
 * Lays out elements in horizontal rows, starting a new row when a width limit is reached. By
 * default, the hint width is used as the limit; this can be overridden with a fixed value.
 * <p>TODO: vertical</p>
 */
public class FlowLayout extends Layout
{
    /** The default gap between rows and elements in a row. */
    public static final float DEFAULT_GAP = 5;

    /**
     * Sets the maximum width of a row of elements. This should normally be used whenever a flow
     * layout governs {@code Elements} that have horizontal siblings. By default, the hint width
     * is used.
     */
    public FlowLayout wrapAt (float width) {
        _wrapWidth = width;
        return this;
    }

    /**
     * Sets the gap, in pixels, to use between rows and between elements within a row.
     */
    public FlowLayout gaps (float gap) {
        _hgap = _vgap = gap;
        return this;
    }

    /**
     * Sets the gap, in pixels, to use between rows and between elements within a row.
     * @param hgap the gap to use between elements in a row
     * @param vgap the gap to use between rows
     */
    public FlowLayout gaps (float hgap, float vgap) {
        _hgap = hgap;
        _vgap = vgap;
        return this;
    }

    /**
     * Sets the alignment used for positioning elements within their row. By default, elements
     * are not stretched and centered vertically: {@link Style.VAlign#CENTER}.
     */
    public FlowLayout align (Style.VAlign align) {
        _valign = align;
        return this;
    }

    /**
     * Stretch elements vertically to the maximum height of other elements in the same row. This
     * clears any previously set vertical alignment.
     */
    public FlowLayout stretch () {
        _valign = null;
        return this;
    }

    @Override public Dimension computeSize (Elements<?> elems, float hintX, float hintY) {
        Metrics m = computeMetrics(elems, hintX, hintY);
        return m.size;
    }

    @Override public void layout (Elements<?> elems,
                                  float left, float top, float width, float height) {
        Style.HAlign halign = resolveStyle(elems, Style.HALIGN);
        Metrics m = computeMetrics(elems, width, height);
        float y = top + resolveStyle(elems, Style.VALIGN).offset(m.size.height, height);
        for (int elemIdx = 0, row = 0, size = m.rowBreaks.size(); row < size; ++row) {
            Dimension rowSize = m.rows.get(row);
            float x = left + halign.offset(rowSize.width, width);
            for (; elemIdx < m.rowBreaks.get(row).intValue(); ++elemIdx) {
                Element<?> elem = elems.childAt(elemIdx);
                if (!elem.isVisible()) continue;
                IDimension esize = preferredSize(elem, width, height);
                if (_valign == null) {
                    setBounds(elem, x, y, esize.width(), rowSize.height());
                } else {
                    setBounds(elem, x, y + _valign.offset(esize.height(), rowSize.height()),
                        esize.width(), esize.height());
                }
                x += esize.width() + _hgap;
            }
            y += _vgap + rowSize.height;
        }
    }

    protected Metrics computeMetrics (Elements<?> elems, float width, float height) {
        Metrics m = new Metrics();
{'fraction_non_alphanumeric': 0.0987926972909305, 'fraction_numerical': 0.0008833922261484099, 'mean_word_length': 2.2768933912204536, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6956909', 'n_tokens_mistral': 1962, 'n_tokens_neox': 1882, 'n_words': 686}