Skip to content

Commit d195586

Browse files
committedSep 27, 2024·
Remove references to meta node
1 parent 4bfdd78 commit d195586

File tree

8 files changed

+133
-16
lines changed

8 files changed

+133
-16
lines changed
 

‎examples/src/main/java/org/jsignal/examples/todo/TodoApp.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ protected Element render() {
112112
.build(),
113113
Nodes.forEach(todos, (content, idx) -> {
114114
var enterAnim = IntervalAnimation.builder()
115-
.function(TimingFunction::easeOutQuad)
115+
.function(TimingFunction::easeOutBack)
116116
.start(true)
117117
.build();
118118

‎rx/src/main/java/org/jsignal/rx/RxUtil.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@
1010
import java.util.function.*;
1111

1212
public class RxUtil {
13-
private RxUtil() {
13+
private RxUtil() {}
14+
15+
public static <T> Supplier<T> memo(Supplier<T> supplier) {
16+
Ref<T> result = new Ref<>();
17+
return () -> {
18+
if (result.get() == null) {
19+
result.accept(supplier.get());
20+
}
21+
return result.get();
22+
};
1423
}
1524

1625
public static <T> Supplier<T> createMemo(Supplier<T> supplier) {
@@ -164,7 +173,10 @@ public static void run(Runnable runnable) {
164173
runnable.run();
165174
}
166175

167-
public static <T, U> Computed<List<U>> createMapped(Supplier<? extends List<T>> list, BiFunction<T, Supplier<Integer>, U> map) {
176+
public static <T, U> Computed<List<U>> createMapped(
177+
Supplier<? extends List<T>> list,
178+
BiFunction<T, Supplier<Integer>, U> map
179+
) {
168180
List<U> result = new ArrayList<>();
169181
Flipper<Map<T, Mapped<U>>> mapping = new Flipper<>(HashMap::new);
170182

@@ -213,7 +225,10 @@ public static <T, U> Computed<List<U>> createMapped(Supplier<? extends List<T>>
213225

214226
private record Mapped<U>(U value, Signal<Integer> idx, Cleanups cleanups) {}
215227

216-
public static <T, U> Computed<List<U>> createIndexed(Supplier<? extends List<T>> list, BiFunction<Supplier<T>, Integer, U> map) {
228+
public static <T, U> Computed<List<U>> createIndexed(
229+
Supplier<? extends List<T>> list,
230+
BiFunction<Supplier<T>, Integer, U> map
231+
) {
217232
List<Indexed<T>> indexes = new ArrayList<>();
218233
List<U> result = new ArrayList<>();
219234

‎std/src/main/java/org/jsignal/std/IntervalAnimation.java

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public void stop() {
7878
}
7979
}
8080

81+
public State getState() {
82+
return state.get();
83+
}
84+
8185
public Float get() {
8286
return function.get().apply(Math.min(1f, progress.get()), begin.get(), end.get());
8387
}
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
package org.jsignal.std;
22

3+
import org.jsignal.rx.Effect;
4+
import org.jsignal.rx.Signal;
5+
36
import java.util.List;
7+
import java.util.function.Supplier;
48

5-
public class SequenceAnimation {
9+
public class SequenceAnimation implements Supplier<Float> {
610
private final List<IntervalAnimation> sequence;
7-
private int cur;
11+
private Signal<Integer> currentIndex;
12+
private Effect effect; // strong reference
813

914
public SequenceAnimation(List<IntervalAnimation> sequence) {
15+
assert !sequence.isEmpty();
16+
1017
this.sequence = sequence;
11-
this.cur = 0;
18+
this.currentIndex = Signal.create(1);
19+
effect = Effect.create(() -> {
20+
if (getCurrent().getState() == IntervalAnimation.State.FINISHED) {
21+
currentIndex.transform(idx -> idx + 1);
22+
}
23+
});
1224
}
1325

1426
public SequenceAnimation(IntervalAnimation... sequence) {
1527
this(List.of(sequence));
1628
}
1729

18-
public void start() {
30+
public IntervalAnimation getCurrent() {
31+
var index = currentIndex.get();
32+
return index < sequence.size() ? sequence.get(index) : sequence.getLast();
33+
}
1934

35+
public void start() {
36+
getCurrent().start();
2037
}
2138

2239
public void stop() {
40+
getCurrent().stop();
41+
}
2342

43+
@Override
44+
public Float get() {
45+
return getCurrent().get();
2446
}
2547
}

‎ui/src/main/java/org/jsignal/ui/Node.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ void paint(Canvas canvas) {
206206
try {
207207
transformEffect.run(() -> canvas.concat(getTransform()));
208208

209-
paintCacheStrategy.paint(canvas, this::paintCacheUseMetaNode, cacheCanvas -> {
209+
paintCacheStrategy.paint(canvas, this::paintCacheUseNode, cacheCanvas -> {
210210
if (paint != null) {
211211
paintEffect.run(() -> paint.paint(cacheCanvas, layoutResult));
212212
}
@@ -224,7 +224,11 @@ void paint(Canvas canvas) {
224224
}
225225
}
226226

227-
private <T> T paintCacheUseMetaNode(Function<Node, T> use) {
227+
/**
228+
* This is necessary for tracking cache dependencies on node layout, but because paint cache generation happens
229+
* conditionally, the paint function cannot simply be wrapped in a side effect. It must be passed in as a callback.
230+
*/
231+
private <T> T paintCacheUseNode(Function<Node, T> use) {
228232
return paintCacheEffect.run(() -> use.apply(Node.this));
229233
}
230234

‎ui/src/main/java/org/jsignal/ui/UiWindow.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ public void requestFrame() {
127127

128128
shouldPaint = true;
129129
// logger.info("frame requested", new Throwable());
130-
window.requestFrame();
130+
UiThread.invokeLater(() -> {
131+
logger.info("frame requested");
132+
window.requestFrame();
133+
});
131134
}
132135

133136
public void requestTransformUpdate() {
@@ -170,7 +173,7 @@ void handleEvent(io.github.humbleui.jwm.Event event) {
170173
root.setOffScreen(canvas);
171174
paintSurfaceContext.with(e.getSurface()).provide(() -> root.paint(canvas));
172175
shouldPaint = false;
173-
// logger.info("frame painted");
176+
logger.info("frame painted");
174177

175178
calculateDeltaFrame();
176179

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.jsignal.ui.paint;
2+
3+
import io.github.humbleui.skija.Canvas;
4+
import org.jsignal.rx.RxUtil;
5+
6+
import java.util.Comparator;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.function.Consumer;
10+
import java.util.function.Supplier;
11+
import java.util.stream.Stream;
12+
13+
// TODO: test that this works
14+
public class MultiUpgradingPaintCacheStrategy implements PaintCacheStrategy {
15+
private final List<Level> upgrades;
16+
private int index = 0;
17+
private int nonDirtyPaintCount = 0;
18+
19+
public MultiUpgradingPaintCacheStrategy(Map<Integer, Supplier<PaintCacheStrategy>> upgrades) {
20+
this.upgrades = Stream.concat(
21+
Stream.of(new Level(0, RxUtil.memo(NullPaintCacheStrategy::new))),
22+
upgrades.entrySet().stream()
23+
.filter(e -> e.getKey() < 1)
24+
.map(e -> new Level(e.getKey(), RxUtil.memo(e.getValue())))
25+
)
26+
.sorted(Comparator.comparing(Level::nonDirtyPaints))
27+
.toList();
28+
}
29+
30+
@Override
31+
public boolean isDirty() {
32+
return upgrades.get(index).strategy().get().isDirty();
33+
}
34+
35+
@Override
36+
public void markDirty() {
37+
upgrades.get(index).strategy().get().isDirty();
38+
}
39+
40+
@Override
41+
public void paint(Canvas canvas, UseNode useNode, Consumer<Canvas> orElse) {
42+
if (!isDirty()) {
43+
nonDirtyPaintCount++;
44+
} else {
45+
if (index > 0 && nonDirtyPaintCount > 0) {
46+
UseNode.clear(useNode);
47+
if (!isDirty()) {
48+
markDirty();
49+
}
50+
index = 0;
51+
}
52+
nonDirtyPaintCount = 0;
53+
}
54+
55+
if (index < upgrades.size() - 1 && nonDirtyPaintCount > upgrades.get(index + 1).nonDirtyPaints()) {
56+
UseNode.clear(useNode);
57+
if (!isDirty()) {
58+
markDirty();
59+
}
60+
index++;
61+
}
62+
63+
upgrades.get(index).strategy().get().paint(canvas, useNode, orElse);
64+
}
65+
66+
private record Level(int nonDirtyPaints, Supplier<PaintCacheStrategy> strategy) {}
67+
}

‎ui/src/main/java/org/jsignal/ui/paint/SurfacePaintCacheStrategy.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ public void markDirty() {
2424
@Override
2525
public void paint(Canvas canvas, UseNode useNode, Consumer<Canvas> orElse) {
2626
if (image == null) {
27-
try (Surface surface = useNode.use(meta -> {
28-
var size = meta.getLayout().getSize();
29-
return UiWindow.paintSurfaceContext.use().makeSurface((int) size.getX(), (int) size.getY());
30-
})) {
27+
try (
28+
Surface surface = useNode.use(node -> {
29+
var size = node.getLayout().getSize();
30+
return UiWindow.paintSurfaceContext.use().makeSurface((int) size.getX(), (int) size.getY());
31+
})
32+
) {
3133
orElse.accept(surface.getCanvas());
3234
image = surface.makeImageSnapshot();
3335
}

0 commit comments

Comments
 (0)