java.lang.Object
com.ultikits.ultitools.abstracts.gui.declarative.core.Element
com.ultikits.ultitools.abstracts.gui.declarative.widgets.GridViewElement

public class GridViewElement extends Element
The Element counterpart of GridView.

Task 2 (05-13, WIRE-03 / D-11): positions ANY widget type by writing parent data at render time -- applyGridPositions() computes each child's slot from the GridView's own layout parameters and writes it onto the RenderNode(s) that child's subtree produced, mirroring Flutter's ParentDataWidget: the child never knows its own position. This replaces the pre-plan approach of GridView.Builder.items() special-casing ItemDisplay and hand-copying six fields at build time -- every other widget type used to receive no slot at all and stacked on the default.

Since:
6.2.0
Version:
1.0.0
Author:
UltiTools Team
  • Field Details

    • LOGGER

      private static final Logger LOGGER
    • DEFAULT_UNSET_SLOT

      private static final int DEFAULT_UNSET_SLOT
      The slot value ItemDisplay and TextButton's builders default to when the caller never calls .slot(...). Neither widget carries a separate "unset" flag -- 0 doubles as both "not specified" and "genuinely slot 0" in this codebase today -- so this is the only signal available here for D-11's conflict rule without changing Widget/ItemDisplay/TextButton's public API (out of this plan's scope; Widget in particular is required to stay unchanged). A widget legitimately positioned at slot 0 therefore never triggers the conflict warning below -- see 05-13-SUMMARY.md for the full reasoning behind this choice.
      See Also:
    • childElements

      private final List<Element> childElements
  • Constructor Details

    • GridViewElement

      public GridViewElement(@NotNull @NotNull GridView<?> widget)
  • Method Details

    • mount

      public void mount(@Nullable @Nullable Element parent)
      Description copied from class: Element
      Mounts this Element into the tree.

      Called the first time the Element is inserted into the tree. Subclasses should perform initialization work here and mount their child Elements.

      CR-01 (T-05-62 / #371): every mount(Element) override in this codebase calls super.mount(parent) before doing its own work (mounting children, running the first performRebuild(), etc.) -- this base method is therefore the single choke point through which the ENTIRE mounting recursion passes, one call per Element, regardless of subtype: ContainerElement/GridViewElement.mountChildren() mounting each child through updateChildren() and updateChild(), and the mount()->performRebuild()->updateChild()->mount() cascade StatelessElement/StatefulElement drive when composing a child Widget for the first time. Checking the depth HERE, rather than separately in every subclass's own mounting method, guards the mount recursion exactly once per node without needing to duplicate the check at each override. update()/unmount()'s own recursions need no separate guard: they only ever walk a subtree whose depth was already validated here when it was first mounted, so they can never exceed RenderDepthGuard.MAX_DEPTH without first passing through an unguarded mount() call -- which this check closes.

      Overrides:
      mount in class Element
      Parameters:
      parent - the parent Element, or null if this is the root Element
    • update

      public void update(@NotNull @NotNull Widget newWidget)
      Description copied from class: Element
      Updates this Element with a new Widget.

      Called when the Widget rebuilds. Subclasses should update their reference to the Widget and perform any necessary updates.

      Overrides:
      update in class Element
      Parameters:
      newWidget - the new Widget instance
    • performRebuild

      public void performRebuild()
      Description copied from class: Element
      Performs a rebuild.

      Subclasses should implement this method to build or rebuild the Widget tree.

      Specified by:
      performRebuild in class Element
    • rebuildSubtree

      private static void rebuildSubtree(@NotNull @NotNull Element element)
      Rebuilds element's complete dirty subtree in GuiRenderer.rebuildElement's order: rebuild the node if it is dirty, then descend into its children as they are after that rebuild.

      Guarded by RenderDepthGuard at every visited node, under the same guard name as performRebuild(): a module-authored cell subtree deep enough raises RenderDepthExceededException here rather than overflowing the JVM stack mid-frame.

      Parameters:
      element - the root of the subtree to rebuild
    • unmount

      public void unmount()
      Description copied from class: Element
      Removes this Element from the tree.

      Called when the Element is no longer needed. Subclasses should perform cleanup work here and unmount their child Elements.

      Overrides:
      unmount in class Element
    • getChildren

      @NotNull public @NotNull List<Element> getChildren()
      Description copied from class: Element
      Gets the list of child Elements.
      Overrides:
      getChildren in class Element
      Returns:
      the child Element list, or an empty list if there are none
    • mountChildren

      private void mountChildren()
    • applyGridPositions

      private void applyGridPositions()
      Writes each child's GridView-computed slot onto the RenderNode(s) its subtree produced.

      This is parent data, D-11's mechanism: the child never knows its own position, the GridView writes it after the child's complete subtree has (re)built and before GuiRenderer's collection walk snapshots the tree -- 05-11's collectRenderNodesRecursive copies via RenderNode.copy(), so a write after that point would be invisible in the collected snapshot. On every frame after the first, performRebuild() rebuilds every dirty descendant of each child (not only the direct children) before calling this, so no later leaf rebuild in the same frame can reset a leaf's slot from its widget and overwrite the value written here. On the first frame, mount(com.ultikits.ultitools.abstracts.gui.declarative.core.Element) calls this after each child's own mount-time build.

      A child whose Element is not itself a leaf (a nested Container, for example) has no RenderNode of its own; collectRenderNodeLeaves(com.ultikits.ultitools.abstracts.gui.declarative.core.Element, java.util.List<com.ultikits.ultitools.abstracts.gui.declarative.core.RenderNode>) walks its descendants and every leaf found receives the same computed slot. When more than one leaf exists under a single cell this is a genuine, documented collision (see DEFAULT_UNSET_SLOT's sibling note in 05-13-SUMMARY.md) rather than an arbitrary "last writer wins" -- the traversal order is deterministic post-order, matching GuiRenderer.collectRenderNodesRecursive's own discipline, so the result is reproducible across rebuilds even though it is not yet a resolved layout.

    • collectRenderNodeLeaves

      private static void collectRenderNodeLeaves(@NotNull @NotNull Element element, @NotNull @NotNull List<RenderNode> out)