Implement retained target sessions, runtime sizing and Component navigation

This commit is contained in:
2026-11-12 14:20:26 +01:00
parent e41b276b13
commit 6e25cf3ac6
71 changed files with 2538 additions and 120 deletions
@@ -13,8 +13,26 @@ public record DesignerConfiguration(String schemaVersion, Map<String, Context> c
String module,
String provider,
String defaultExample,
List<String> examples) {
List<String> examples,
int requestTimeoutSeconds,
int readinessTimeoutSeconds) {
public Preview(
String sourceSet,
String module,
String provider,
String defaultExample,
List<String> examples) {
this(sourceSet, module, provider, defaultExample, examples, 30, 20);
}
public Preview {
if (requestTimeoutSeconds == 0) requestTimeoutSeconds = 30;
if (readinessTimeoutSeconds == 0) readinessTimeoutSeconds = 20;
if (requestTimeoutSeconds < 1
|| requestTimeoutSeconds > 300
|| readinessTimeoutSeconds < 1
|| readinessTimeoutSeconds > requestTimeoutSeconds)
throw new IllegalArgumentException("Invalid preview deadlines");
examples = List.copyOf(examples);
}
}
@@ -0,0 +1,65 @@
package de.neitzel.fxdesigner.protocol;
import java.util.Map;
/** Logical target pixels; finite Double.MAX_VALUE represents an unbounded maximum. */
public record LayoutMetrics(
String occurrence,
double minWidth,
double prefWidth,
double maxWidth,
double minHeight,
double prefHeight,
double maxHeight,
double baseline,
String bias) {
public LayoutMetrics {
if (occurrence == null || occurrence.isBlank() || occurrence.length() > 4096)
throw new IllegalArgumentException("Invalid occurrence");
for (double value :
new double[] {minWidth, prefWidth, maxWidth, minHeight, prefHeight, maxHeight, baseline})
if (!Double.isFinite(value) || value < 0)
throw new IllegalArgumentException("Invalid target measurement");
if (!java.util.Set.of("NONE", "HORIZONTAL", "VERTICAL").contains(bias))
throw new IllegalArgumentException("Invalid content bias");
}
public Map<String, String> encode() {
return Map.of(
"occurrence",
occurrence,
"minWidth",
"" + minWidth,
"prefWidth",
"" + prefWidth,
"maxWidth",
"" + maxWidth,
"minHeight",
"" + minHeight,
"prefHeight",
"" + prefHeight,
"maxHeight",
"" + maxHeight,
"baseline",
"" + baseline,
"bias",
bias);
}
public static LayoutMetrics decode(Map<String, String> m) {
return new LayoutMetrics(
m.get("occurrence"),
number(m, "minWidth"),
number(m, "prefWidth"),
number(m, "maxWidth"),
number(m, "minHeight"),
number(m, "prefHeight"),
number(m, "maxHeight"),
number(m, "baseline"),
m.get("bias"));
}
private static double number(Map<String, String> m, String key) {
return Double.parseDouble(m.get(key));
}
}
@@ -72,11 +72,23 @@ public final class ProtocolSession implements AutoCloseable {
if (hello.preview().major() == 1
&& supported.contains("render-rgba-v1")
&& hello.capabilities().contains("render-rgba-v1")) usable.add(Operation.RENDER);
if (hello.preview().major() == 1
&& supported.contains("layout-v1")
&& hello.capabilities().contains("layout-v1")) {
usable.add(Operation.MEASURE);
usable.add(Operation.OCCURRENCES);
}
if (hello.preview().major() == 1
&& supported.contains("interactive-v1")
&& hello.capabilities().contains("interactive-v1")) usable.add(Operation.INTERACTIVE);
var requiredByEither = new HashSet<>(required);
requiredByEither.addAll(hello.required());
if ((requiredByEither.contains("discover-v1") && !usable.contains(Operation.DISCOVER))
|| (requiredByEither.contains("render-rgba-v1") && !usable.contains(Operation.RENDER)))
throw new IllegalArgumentException("Required capability version incompatible");
if ((requiredByEither.contains("layout-v1") && !usable.contains(Operation.MEASURE))
|| (requiredByEither.contains("interactive-v1") && !usable.contains(Operation.INTERACTIVE)))
throw new IllegalArgumentException("Required capability version incompatible");
operations = Set.copyOf(usable);
state = State.READY;
return operations;
@@ -73,7 +73,10 @@ public final class WireProtocol {
public enum Operation {
DISCOVER,
RENDER
RENDER,
MEASURE,
OCCURRENCES,
INTERACTIVE
}
public record Identity(
@@ -111,14 +114,14 @@ public final class WireProtocol {
Objects.requireNonNull(operation);
Objects.requireNonNull(identity);
Objects.requireNonNull(payload);
boolean render = operation == Operation.RENDER;
boolean render = operation != Operation.DISCOVER;
if (render
&& (identity.width() == 0 || identity.height() == 0 || identity.revisions().isEmpty()))
throw new IllegalArgumentException("Rendering needs dimensions and document revisions");
if (!render
&& (identity.width() != 0 || identity.height() != 0 || !identity.revisions().isEmpty()))
throw new IllegalArgumentException("Discovery does not carry render identity");
boolean image = render && kind == Kind.RESULT;
boolean image = operation == Operation.RENDER && kind == Kind.RESULT;
if (image
? payload.length != (long) identity.width() * identity.height() * 4
: payload.length > MAX_METADATA)