Layer

@Composable
fun Layer(modifier: SwingModifier = SwingModifier, onPaint: (g: Graphics2D, width: Int, height: Int, paintView: () -> Unit) -> Unit = UNDECLARED_PAINT, onMouseEvent: (MouseEvent) -> Unit = UNDECLARED, onMouseMotionEvent: (MouseEvent) -> Unit = UNDECLARED, onMouseWheelEvent: (MouseWheelEvent) -> Unit = UNDECLARED, content: @Composable LayerScope.() -> Unit)

A layer over one live component - a JLayer - that paints over what the component paints and watches the mouse events that reach it, while the component goes on being itself.

The component it wraps is the child that names no region, as new JLayer(view) holds it; an overlay over that component goes in the glass pane beside it. The view keeps answering for itself: a widget that tells a scroll pane how far to scroll it goes on telling it that through the layer, which a panel wrapping the widget would not.

Layer(
onPaint = { g, width, height, paintView ->
paintView()
g.paint = Color(255, 255, 255, 128)
g.fillRect(0, 0, width, height)
},
) {
Table(model = rows)
}

Each callback is read when it fires, so writing fresh lambdas on every recomposition costs one field write and installs nothing again.

Painting is snapshot-observed. Snapshot state onPaint reads directly inside itself is tracked, and a change to it repaints the layer and runs onPaint again - so a value the layer draws with can be read where it is drawn with, at paint time, rather than in the composition. A layer declaring no paint tracks nothing.

The mask is derived. A layer observes exactly the events whose callbacks this call declares: declaring onMouseEvent alone has it observe mouse events alone, and a call that declares only onPaint observes none. The events reach the callbacks while the layer is displayable, and a layer taken off screen takes up watching again when it goes back on.

A callback runs as the event is dispatched, several steps before the component the event is addressed to receives it. Returning from the callback does not consume the event or keep it from arriving, but the callback may consume the mutable event explicitly by calling consume(). Keeping input away from the view is a disabled view, or a glass pane over it with a mouse, motion or wheel listener of its own - not merely a callback here. A cursor set on the glass pane changes only the cursor shown over the view, and the view still receives the events.

Reach for the overload taking a LayerUI where a layer needs the rest of that type - the events these callbacks do not cover, a preferred size of its own, a layout of the view of its own.

Parameters

modifier

the SwingModifier applied to the underlying JLayer.

onPaint

paints the layer, in place of the view painting itself. It receives the layer's Graphics2D, the layer's width and height, and paintView, which paints the view and the glass pane over it: call it inside a composite to wash the view, before your own drawing to paint over it, after to paint under it, more than once, or not at all to replace it. paintView throws IllegalStateException once this call returns, so run it here rather than holding on to it. The graphics is a copy the layer disposes when this returns, so a composite, transform or clip left on it reaches no other painting. Left undeclared, the layer paints the view unchanged.

onMouseEvent

runs on a press, release, click, enter or exit anywhere in the layer, the view and everything under it included; declaring it has the layer observe MOUSE_EVENT_MASK.

onMouseMotionEvent

runs as the pointer moves or drags over the layer; declaring it has the layer observe MOUSE_MOTION_EVENT_MASK.

onMouseWheelEvent

runs as the wheel turns over the layer; declaring it has the layer observe MOUSE_WHEEL_EVENT_MASK.

content

the composable content of the layer; see LayerScope.

See also


@Composable
fun <V : Component> Layer(ui: LayerUI<in V>, modifier: SwingModifier = SwingModifier, eventMask: Long? = null, content: @Composable LayerScope.() -> Unit)

A layer over one live component - a JLayer - painted and driven by a LayerUI of your own, which is the whole of what the JDK type offers: the events the callback overload of Layer does not cover, a preferred size the delegate answers for, a layout of the view of its own.

The wrapped component is the child that names no region, and the overlay over it is declared in the glass pane of LayerScope, exactly as for the callback overload.

Layer(ui = remember { HoverHighlightLayerUI() }, eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK) {
Table(model = rows)
}

The type parameter is the view type ui is written against. It fixes which delegates this call accepts - a LayerUI<JComponent>, a LayerUI<Component> and a LayerUI<JTable> all bind without a type argument at the call site - and says nothing about the child that is the view: no type relates the two.

Parameters

ui

the delegate the layer installs: what paints it, lays its view out, and answers for its preferred size. It is required, because a layer without a delegate paints nothing and reports a preferred size of 0x0, so the view it holds never reaches its parent's layout. It is installed by identity, so a remembered instance stays put while a fresh one on every pass is uninstalled and installed again. Give each layer a delegate of its own: installing one puts the layer on the delegate's own listener list and only installing another delegate takes it off again, so a delegate shared between two layers holds both alive and hands each of them the other's property changes.

modifier

the SwingModifier applied to the underlying JLayer.

eventMask

the events the layer observes. null, the default, leaves the mask to ui, which is where a LayerUI usually sets it - from installUI, on the layer it was handed. A non-null value takes the mask over instead, written after the delegate is installed, so a delegate declared beside one must not set the mask itself. Withdrawing it - a non-null mask and then null - clears the mask and installs ui again, so the layer observes what ui sets for itself, and nothing if it sets none. The mask reaches the layer while it is displayable, and what it observes it cannot swallow: an event reaches ui as it is dispatched, several steps before the component it is addressed to receives it.

content

the composable content of the layer; see LayerScope.

See also