Interface CssEmittingLayoutManager

All Superinterfaces:
LayoutManager
All Known Implementing Classes:
BorderLayout, BoxLayout, FlowLayout, GridBagLayout, GridLayout, GroupLayout

public interface CssEmittingLayoutManager extends LayoutManager
A LayoutManager that positions children by emitting CSS onto the container's peer <div> (and optionally onto each child) instead of the pixel setBounds arithmetic a desktop LayoutManager does — there is no synchronous child-size measurement in the browser to drive that arithmetic. This is the seam a migrator implements to teach the emulator a custom Swing layout; every built-in (FlowLayout, BorderLayout, BoxLayout, GridLayout, GridBagLayout, GroupLayout) is one of these.

Implement containerCss(Container); add childCss(Container, Component) only when children need per-item CSS. The framework drives layoutContainer(Container) for you — you never touch EHelper or a Vaadin Element:

// A two-column form: labels hug their content, fields absorb the rest.
public class TwoColumnLayout implements CssEmittingLayoutManager {
    public Map<String,String> containerCss(Container parent) {
        return Map.of("display", "grid",
                      "grid-template-columns", "auto 1fr",
                      "gap", "4px 8px");
    }
    // Each child fills its cell's width, so a JTextField(20)'s preferred width yields.
    public Map<String,String> childCss(Container parent, Component child) {
        return CssEmittingLayoutManager.sizingCss(true, false);
    }
}
// parent.setLayout(new TwoColumnLayout());   // children flow into the grid

A container whose installed layout is not a CssEmittingLayoutManager — a hand-rolled pixel LayoutManager — can't be translated: Container.doLayout() WARNs once and falls back to a readable vertical stack (M1D_custom_layoutmanager).

Implementation details

Call order (contract). Within one layoutContainer(Container) pass containerCss(Container) runs exactly once, before any childCss(Container, Component) call. A layout whose per-child CSS is a byproduct of a whole-container analysis (GridBag track weights, GroupLayout bands) may compute in containerCss, stash the result, and read it back in childCss — GridBagLayout and GroupLayout do exactly this. A layout whose per-child CSS is already known at add time can instead write it eagerly from addLayoutComponent and skip childCss entirely — BorderLayout does that with grid-area.

Child sizing (D_layout_owns_child_sizing). A child's Component.setPreferredSize(Dimension) does not write width / height outright — it writes width: var(--emul-layout-w, Npx), and the parent layout rules on each axis by writing that variable from childCss(Container, Component), with sizingCss(boolean, boolean) building the pair. This is the rule a CSS stretch alone cannot express: a cell's justify-self: stretch grows only an auto-sized child, so a child carrying its preferred width keeps it until the layout says otherwise. A layout that returns neither variable leaves whatever the last layout wrote in place, so emit both for every child — sizingCss always does.

Map semantics. A returned map applies key-by-key: a value sets the property, null removes it, an absent key is left untouched — so a layout can clear a sibling layout's leftover keys without clobbering co-owned ones (a field surrogate's inline width). containerCss(Container) writes gate on the peer being a <div> (a non-Div peer gets an ERROR and no write); childCss(Container, Component) writes do not gate — a child is any element.

  • Method Details

    • containerCss

      Map<String,String> containerCss(Container parent)
      Container-wide CSS for parent's peer content element (its <div>).
      Returns:
      property→value map; a null value removes the property, an absent key is left untouched.
    • childCss

      default Map<String,String> childCss(Container parent, Component child)
      Per-child CSS for one child of parent; null (the default) means the child needs none. Called once per child per pass, after containerCss(Container) (see the call-order contract).
    • sizingCss

      static Map<String,String> sizingCss(boolean layoutSizesWidth, boolean layoutSizesHeight)
      The per-child sizing pair for childCss(Container, Component): which axes of the child this layout sizes itself, and which it leaves to the child's preferred size. Say true for an axis the layout sizes (the pref is ignored, as BorderLayout NORTH ignores the pref width, or a GridBagLayout cell whose fill covers the axis), false to let the pref stand.
      Returns:
      a new map holding both variables; merge it into the child's CSS
    • cssLayoutName

      default String cssLayoutName()
      Name used in the non-Div ERROR log for containerCss(Container) writes.
    • layoutContainer

      default void layoutContainer(Container parent)
      Specified by:
      layoutContainer in interface LayoutManager