Class Grid


public class Grid extends Container<Grid>
Places children in a fixed number of columns, row by row in the order they were added, so that they line up on both axes: the layout for a form of captions beside fields, a sheet of names beside values, or any set of rows whose cells should share their columns' edges.

The first columns children fill the first row, the next columns the second, and the last row may be short. A child's cell is decided by its index and by nothing else, so a hidden child leaves its cell empty rather than moving every later child one cell back into the wrong column; a row or a column whose every cell is hidden takes no room and no gap. An empty cell on purpose, such as the caption's cell beside a checkbox that carries its own text, is a SizedBox of no size.

Columns. Each column is as wide as the widest of its cells, and gap separates one column from the next. One column may take the width the others leave: the expandedColumn, which is given whatever the other columns and the gaps leave of the grid's width, more than its cells ask for when the grid has more and less when it has less, down to nothing, the way an Expanded child is given what a row leaves over. The other columns never shrink, so a grid narrower than them runs past its edge, as a row of children that are not flexible does. columnAlignment(int, limn.scene.layout.Flex.CrossAlignment) places a cell within its column's width, with the words a Column uses across: at the edge reading starts from by default, and STRETCH for a column of fields that should all be as wide as the column. A column of a fixed width is a SizedBox around one of its cells.

Rows. Each row is as tall as the tallest of its cells, and rowGap separates one row from the next. crossAlignment places a cell within its row's height with the words a Row uses, and its default is BASELINE, not a row's START, because a grid is where a caption stands beside the field it names and the two should share the line their text sits on.

In a right-to-left subtree (LayoutDirection) the first column is at the right edge and the columns follow leftwards, each cell placed within its column from the column's right edge; the rows still go down.

No child is flexible here. What a grid leaves over belongs to a column and not to a cell, so an Expanded is refused when it is added, rather than accepted and laid out as the widget it wraps: the column it would have stretched is named with expandedColumn.

A grid draws nothing, clips nothing and describes nothing to an assistive technology, so it publishes no node of its own and its children take its place. Their reading order, and the order Tab visits them in, is the order they were added in, which is the order the rows are read in, row by row and cell by cell in reading order, in both directions: a right-to-left subtree moves the boxes and not the order.

  • Constructor Details

    • Grid

      public Grid(int columns)
      An empty grid of columns columns, with no gap on either axis, no expanded column, every cell at the edge reading starts from within its column and on its row's baseline.
      Parameters:
      columns - how many cells make a row, fixed for the life of the grid: the children are added in rows of that many, and a different count would pair every one of them differently
      Throws:
      IllegalArgumentException - when columns is less than 1
  • Method Details

    • gap

      public Grid gap(float newGap)
      Space between one column and the next, in logical points: the gutter a Row's Flex.gap is between neighbours, never before the first column or after the last, and never beside a column whose every cell is hidden. Negative values clamp to 0. UI thread only.
      Parameters:
      newGap - the gutter between columns
      Returns:
      this grid
      Throws:
      IllegalArgumentException - when NaN or infinite
    • rowGap

      public Grid rowGap(float newGap)
      Space between one row and the next, in logical points, never above the first row or below the last, and never beside a row whose every cell is hidden. Negative values clamp to 0. UI thread only.
      Parameters:
      newGap - the gutter between rows
      Returns:
      this grid
      Throws:
      IllegalArgumentException - when NaN or infinite
    • crossAlignment

      public Grid crossAlignment(Flex.CrossAlignment alignment)
      Where a cell sits within the height of its row, which is the height of the row's tallest cell. BASELINE, the default, lines up the text of a row's cells, shifting each one down inside its row and never out of it, the clamp a Row applies inside its own height; a cell with no text lines up its bottom edge. START, CENTER and END place the box, and do not turn around in a right-to-left subtree because the axis is vertical. STRETCH makes every cell of a row as tall as the row, and costs a second measure in every pass of each cell shorter than its row, because the height it is stretched to is known only once the row is formed. UI thread only.
      Parameters:
      alignment - the placement of a cell within its row
      Returns:
      this grid
    • columnAlignment

      public Grid columnAlignment(int column, Flex.CrossAlignment alignment)
      Where the cells of one column sit within its width, which is the width of its widest cell or, for the expandedColumn, whatever the grid gives it. The words are the ones a Column places its children across with: START, the default, and END are the edges reading starts from and ends on, so they turn around in a right-to-left subtree; CENTER centres; STRETCH makes every cell as wide as the column, which is what a column of fields wants, and costs a second measure in every pass of each cell narrower than the column, because the column's width is known only once all of its cells have answered. BASELINE has no meaning across a column and places a cell as START does, as it does on a column. UI thread only.
      Parameters:
      column - the column, in [0, columns)
      alignment - the placement of that column's cells within its width
      Returns:
      this grid
      Throws:
      IndexOutOfBoundsException - when column is not a column of this grid
    • expandedColumn

      public Grid expandedColumn(int column)
      Makes one column take the width the others leave, the way an Expanded child takes the room a row leaves: given a width, the grid fills it, and this column is whatever the other columns and the gaps leave of it, wider than its cells need or narrower, down to nothing when the others alone fill the grid. With no bound on the width, which is what Scene.pack() and a horizontally scrolling parent give, it is as wide as its widest cell, like every other column. Its cells are placed within it by its columnAlignment(int, limn.scene.layout.Flex.CrossAlignment), so a column of fields that should grow with the window is this and STRETCH. There is at most one; the default is none, and the grid is then as wide as its columns. UI thread only.
      Parameters:
      column - the column that takes the leftover, in [0, columns), or -1 for none
      Returns:
      this grid
      Throws:
      IndexOutOfBoundsException - when column is neither a column of this grid nor -1
    • add

      public void add(Widget<?> child)
      Appends a child to the next cell, which starts a new row after every columns children (UI thread only).
      Overrides:
      add in class Container<Grid>
      Parameters:
      child - the child to append
      Throws:
      IllegalArgumentException - when child is an Expanded: what a grid leaves over belongs to a column, named with expandedColumn
    • add

      public void add(int index, Widget<?> child)
      Inserts a child at a position in Widget.children(), which moves every later child one cell on (UI thread only).
      Overrides:
      add in class Container<Grid>
      Parameters:
      index - where the child goes, in [0, children().size()]
      child - the child to insert; never null
      Throws:
      IllegalArgumentException - when child is an Expanded: what a grid leaves over belongs to a column, named with expandedColumn
    • 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<Grid>
    • 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<Grid>