Class Expanded

java.lang.Object
limn.scene.Widget<Expanded>
limn.scene.layout.Expanded

public final class Expanded extends Widget<Expanded>
Flex wrapper: inside a Column/Row it receives a share of the leftover main-axis space proportional to flex. Without a child it is a spacer(int): pure flexible whitespace.

The share is a tight constraint, so it overrides what the child asked for. A flex child is measured with its main axis pinned to the share (minimum and maximum both equal to it), and the size the child returns from its own onMeasure is discarded on that axis. A control that measured itself at 116 pt because that is what its chrome and its widest value need will be handed 35 pt in a crowded row and will paint at 35, one part on top of another. That is the container doing as it was told: nothing in the layout protocol lets a widget refuse.

atLeast(float) is how a call site refuses on the child's behalf. It is opt-in per call site rather than a default, because the right floor is not a property of the widget class: a caption that ellipsises wants to be squeezed (that is what the ellipsis is for) and a stepper with a fixed chrome width does not, and the same widget can be either one depending on the row it is in.

  • Method Details

    • of

      public static Expanded of(Widget<?> child, int flex)
      Gives child a share of the leftover space proportional to flex.
    • of

      public static Expanded of(Widget<?> child)
      An equal share of the leftover space: flex of 1.
    • spacer

      public static Expanded spacer(int flex)
      Flexible empty space.
    • flex

      public int flex()
      This child's share weight.
    • atLeast

      public Expanded atLeast(float points)
      Declares a main-axis floor, in logical points: this child is never given less than points, however little the weighted split would leave it. Chains after of(limn.scene.Widget<?>, int). The default is 0: no floor, and the distribution is the plain weighted one.

      The container satisfies floors before weight. A child whose share would fall under its floor is frozen at the floor and drops out of the split; whatever is left is re-divided among the others, which can push another one under its own floor, so this repeats until nothing is under. Siblings without floors absorb the whole loss, which is the point: a floored stepper beside an ellipsising label keeps its chrome and the label gives up the points.

      Floors that do not fit overflow the container. When they add up to more than there is room for, every child still gets its floor and the row is over-subscribed; children paint past the container's edge. This is the same outcome a row of too-wide fixed children has today: a Flex does not clip and does not wrap, so an over-subscribed row is visibly over-subscribed rather than silently truncated. Declare floors that fit, or give the container more room.

      Negative values clamp to 0. UI thread only.

      Throws:
      IllegalArgumentException - when NaN or infinite, or above a ceiling atMost(float) set
    • minMain

      public float minMain()
      Returns:
      the declared main-axis floor in points, 0 when none was set
    • atMost

      public Expanded atMost(float points)
      Declares a main-axis ceiling, in logical points: this child is never given more than points, however much the weighted split would hand it. Chains after of(limn.scene.Widget<?>, int), beside atLeast(float); the default is no ceiling.

      The container holds ceilings the way it holds floors. A child whose share would pass its ceiling is frozen at the ceiling and drops out of the split, and what it gives up is re-divided among the others, floors first. When every flexible child is held at its ceiling, the space left over is placed by the container's main alignment, as it is in a row with no flexible child.

      Constraints.UNBOUNDED_LIMIT clears it. UI thread only.

      Parameters:
      points - the most this child is given along the main axis, in logical points
      Returns:
      this
      Throws:
      IllegalArgumentException - when negative or NaN, or below the floor atLeast(float) set
    • maxMain

      public float maxMain()
      Returns:
      the declared main-axis ceiling in points, Constraints.UNBOUNDED_LIMIT when none was set
    • paintOverflow

      public Expanded paintOverflow(float points)
      Declares how far the child may paint past this wrapper's box, in logical points, in place of the reach of the theme's focus ring, which is the default. It is what Container.paintOverflow(float) is to a container, for the one child here: the public setter of paintOutset(), and a new declaration repaints this wrapper and its band while one already in force repaints nothing. UI thread only.
      Parameters:
      points - how far the child may paint past each side of this box, in logical points
      Returns:
      this wrapper
      Throws:
      IllegalArgumentException - when negative, NaN or infinite
    • paintOverflowFromTheme

      public Expanded paintOverflowFromTheme()
      Goes back to declaring the reach of the theme's focus ring for the child, which is the default; see paintOverflow(float). UI thread only.
      Returns:
      this wrapper
    • paintOutset

      protected float paintOutset()
      What paintOverflow(float) declared; else nothing for a spacer, which has no child to paint past it; else the reach of the focus ring in the theme in effect for this wrapper: the child is laid out over the whole box, so a ring at its edge is a ring at this box's edge. O(1) and allocation-free.
      Overrides:
      paintOutset in class Widget<Expanded>
    • onMeasure

      protected Size onMeasure(Constraints constraints)
      Description copied from class: Widget
      Reports the size this widget wants within constraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.

      Resolve the ControlSize and the LayoutDirection once each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, and I18n.locale() answers it wherever text is resolved.

      Specified by:
      onMeasure in class Widget<Expanded>
    • onLayout

      protected void onLayout()
      Description copied from class: Widget
      Containers position children here (measure + Widget.layoutBox(float, float, float, float) per child).
      Overrides:
      onLayout in class Widget<Expanded>