java.lang.Object
com.ultikits.ultitools.abstracts.gui.declarative.core.Element
Direct Known Subclasses:
ComponentElement, ContainerElement, GridViewElement, RenderObjectElement

public abstract class Element extends Object
Element is the instantiated representation of a Widget, responsible for managing the Widget's lifecycle and updates.

An Element is a persistent object: when a Widget rebuilds, its Element is reused if the type still matches. That reuse is the key to the framework's efficient updates.

Element's responsibilities:

  • Holds a reference to the Widget (updated across rebuilds)
  • Manages the child Element tree
  • Coordinates Widget creation, update, and disposal
  • Supplies a RenderNode for RenderObjectElement

Element types:

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

    • _widget

      @Nullable private @Nullable Widget _widget
    • _parent

      @Nullable private @Nullable Element _parent
    • _children

      @Nullable private @Nullable List<Element> _children
    • _dirty

      private boolean _dirty
    • _mounted

      private boolean _mounted
    • _context

      @Nullable private @Nullable BuildContext _context
    • _rootBuildScheduler

      @Nullable private @Nullable Runnable _rootBuildScheduler
  • Constructor Details

    • Element

      protected Element(@NotNull @NotNull Widget widget)
  • Method Details

    • assignContext

      public void assignContext(@NotNull @NotNull BuildContext context)
      Assigns a Context to this Element (only used for the root Element or in tests).
      Parameters:
      context - the BuildContext
    • mount

      public void mount(@Nullable @Nullable Element parent)
      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() calling childElement.mount(this) for each child, 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.

      Parameters:
      parent - the parent Element, or null if this is the root Element
    • update

      public void update(@NotNull @NotNull Widget newWidget)
      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.

      Parameters:
      newWidget - the new Widget instance
    • canUpdate

      public boolean canUpdate(@NotNull @NotNull Widget newWidget)
      Checks whether this Element can update to the given Widget.
      Parameters:
      newWidget - the new Widget
      Returns:
      true if it can be updated
    • unmount

      public void unmount()
      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.

    • markNeedsBuild

      public void markNeedsBuild()
      Marks this Element as needing a rebuild.

      This schedules the framework to rebuild this Element on the next frame.

    • markChildNeedsBuild

      public void markChildNeedsBuild(@NotNull @NotNull Element child)
      Marks a child Element as needing a rebuild.
      Parameters:
      child - the child Element
    • setRootBuildScheduler

      public void setRootBuildScheduler(@Nullable @Nullable Runnable scheduler)
      Registers, on the mounted root Element, the callback that a "needs rebuild" bubble hands off to on GuiRenderer.

      Framework-internal method -- only GuiRenderer calls this, when it mounts or remounts the root Element; module authors do not need to (and should not) call it themselves. On a non-root Element this field is always null, because bubbling forwards to the first ancestor with _parent != null and never reaches this branch.

      Parameters:
      scheduler - the callback invoked when the root needs a rebuild, typically GuiRenderer::scheduleBuild; pass null to unregister (when the renderer is destroyed)
    • performRebuild

      public abstract void performRebuild()
      Performs a rebuild.

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

    • getWidget

      @NotNull public @NotNull Widget getWidget()
      Gets the Widget associated with this Element.
      Returns:
      the Widget instance
      Throws:
      IllegalStateException - if the Widget is null
    • getParent

      @Nullable public @Nullable Element getParent()
      Gets the parent Element.
      Returns:
      the parent Element, or null at the root
    • getChildren

      @NotNull public @NotNull List<Element> getChildren()
      Gets the list of child Elements.
      Returns:
      the child Element list, or an empty list if there are none
    • getContext

      @NotNull public @NotNull BuildContext getContext()
      Gets the build context.
      Returns:
      the BuildContext
    • isMounted

      public boolean isMounted()
      Checks whether this Element is mounted.
      Returns:
      true if mounted
    • isDirty

      public boolean isDirty()
      Checks whether this Element needs a rebuild.
      Returns:
      true if it needs a rebuild
    • clearDirty

      public void clearDirty()
      Clears the dirty flag.
    • addChild

      protected void addChild(@NotNull @NotNull Element child)
      Adds a child Element.
      Parameters:
      child - the child Element
    • updateChild

      @Nullable protected @Nullable Element updateChild(@Nullable @Nullable Widget newWidget, @Nullable @Nullable Element oldChild)
      Updates a single child Element.

      This is the core method of reconciliation. It decides whether to reuse the existing Element or create a new one.

      Parameters:
      newWidget - the new Widget
      oldChild - the previous child Element, may be null
      Returns:
      the updated Element
    • updateChildren

      @NotNull protected @NotNull List<Element> updateChildren(@NotNull @NotNull List<Element> oldChildren, @NotNull @NotNull List<Widget> newWidgets)
      Reconciles a list of old child Elements against a list of new Widgets, pairing by SlotKey where a Widget declares one and falling back to positional (index) pairing where it does not -- so a caller that never supplies a key sees exactly the same index-based behaviour this method replaces.

      This is the shared implementation D-09 item 5 asks for: ContainerElement and GridViewElement were literal twins, each hand-rolling the same Math.min(size) index pairing and never reading Widget.getKey(). Both now call this method instead of maintaining their own copy, so the two classes cannot drift apart the way they did before this plan.

      Algorithm: the old child Elements are first split into a keyed group and an unkeyed group. Iterating the new Widget list, a keyed Widget looks up its match in the keyed group, and an unkeyed Widget takes the next available Element from the unkeyed group, in order. A match is reused via updateChild(Widget, Element) (or replaced there if its type no longer matches); no match means a new Element is created. After the pass, whatever remains in either group -- unclaimed by any new Widget -- is unmounted.

      Parameters:
      oldChildren - the previously-mounted child Elements, in their current order
      newWidgets - the new child Widgets, in their desired order
      Returns:
      the reconciled child Elements, in newWidgets' order
    • toString

      public String toString()
      Overrides:
      toString in class Object