fix(ScrollArea): renderingBoIds concurrency and add immutable view

This commit is contained in:
extio-de
2026-10-04 08:57:05 +02:00
parent fe85b72348
commit 3f56dc9c59
5 changed files with 36 additions and 17 deletions

View File

@@ -134,7 +134,7 @@ public class OptionsModule extends AbstractClientModule implements OptionsModule
@Override @Override
public void refreshContent() { public void refreshContent() {
for (final var boId : this.contentScrollArea.getRenderingBoIds().toArray(new String[0])) { for (final var boId : this.contentScrollArea.getRenderingBoIds()) {
this.contentScrollArea.removeRenderingBo(boId); this.contentScrollArea.removeRenderingBo(boId);
} }
for (final var tab : this.tabs) { for (final var tab : this.tabs) {

View File

@@ -222,7 +222,7 @@ public class ThemeEditorModule extends AbstractClientModule implements OptionsTh
private void setupEditor() { private void setupEditor() {
this.editorWindow.clearRenderingBos(); this.editorWindow.clearRenderingBos();
for (final var boId : this.scrollArea.getRenderingBoIds().toArray(new String[0])) { for (final var boId : this.scrollArea.getRenderingBoIds()) {
this.scrollArea.removeRenderingBo(boId); this.scrollArea.removeRenderingBo(boId);
} }
this.colorSlotByControlId.clear(); this.colorSlotByControlId.clear();

View File

@@ -2,6 +2,7 @@ package de.extio.game_engine.renderer.container;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -41,15 +42,19 @@ public class ScrollArea implements WindowComponent {
protected final Set<String> renderingBoIds = Collections.synchronizedSet(new HashSet<>()); protected final Set<String> renderingBoIds = Collections.synchronizedSet(new HashSet<>());
protected volatile Set<String> renderingBoIdsView = null;
protected volatile boolean renderingBoIdsViewDirty = true;
protected final Area2 relativeArea = new Area2(ImmutableCoordI2.zero(), ImmutableCoordI2.one()); protected final Area2 relativeArea = new Area2(ImmutableCoordI2.zero(), ImmutableCoordI2.one());
protected Window parent; protected volatile Window parent;
protected double scrollPositionVertical = 1.0; // 1.0 = top, 0.0 = bottom protected volatile double scrollPositionVertical = 1.0; // 1.0 = top, 0.0 = bottom
protected double scrollPositionHorizontal = 0.0; // 0.0 = left, 1.0 = right protected volatile double scrollPositionHorizontal = 0.0; // 0.0 = left, 1.0 = right
protected int verticalScrollInputRevision = 0; protected volatile int verticalScrollInputRevision = 0;
public ScrollArea(final RenderingBoPool renderingBoPool, final EventService eventService) { public ScrollArea(final RenderingBoPool renderingBoPool, final EventService eventService) {
this.renderingBoPool = renderingBoPool; this.renderingBoPool = renderingBoPool;
@@ -95,7 +100,7 @@ public class ScrollArea implements WindowComponent {
return; return;
} }
final double scrollIncrement = Math.max(0.00001, Math.min(1.0, (double)this.relativeArea.getDimension().getY() / this.contentDimension.getY() / 14.0)); final double scrollIncrement = Math.max(0.00001, Math.min(1.0, (double) this.relativeArea.getDimension().getY() / this.contentDimension.getY() / 14.0));
final double delta = event.getButton() == 4 ? scrollIncrement : -scrollIncrement; final double delta = event.getButton() == 4 ? scrollIncrement : -scrollIncrement;
this.updateVerticalScrollPosition(this.scrollPositionVertical + delta, true); this.updateVerticalScrollPosition(this.scrollPositionVertical + delta, true);
this.parent.draw(); this.parent.draw();
@@ -169,6 +174,7 @@ public class ScrollArea implements WindowComponent {
public void putRenderingBo(final RenderingBo renderingBo) { public void putRenderingBo(final RenderingBo renderingBo) {
this.renderingBoIds.add(renderingBo.getId()); this.renderingBoIds.add(renderingBo.getId());
this.renderingBoIdsViewDirty = true;
this.parent.putRenderingBo(renderingBo); this.parent.putRenderingBo(renderingBo);
} }
@@ -178,6 +184,7 @@ public class ScrollArea implements WindowComponent {
public void removeRenderingBo(final String renderingBoId) { public void removeRenderingBo(final String renderingBoId) {
this.renderingBoIds.remove(renderingBoId); this.renderingBoIds.remove(renderingBoId);
this.renderingBoIdsViewDirty = true;
this.parent.removeRenderingBo(renderingBoId); this.parent.removeRenderingBo(renderingBoId);
} }
@@ -263,9 +270,21 @@ public class ScrollArea implements WindowComponent {
this.relativeArea.setDimension(relativeArea.getDimension().toImmutableCoordI2()); this.relativeArea.setDimension(relativeArea.getDimension().toImmutableCoordI2());
} }
/**
* Returns an immutable copy of the rendering BO IDs currently in this scroll area.
*
* @return an immutable {@link List} containing all rendering BO IDs; safe to iterate
* while the scroll area is being modified
*/
@Override @Override
public Set<String> getRenderingBoIds() { public Set<String> getRenderingBoIds() {
return this.renderingBoIds; synchronized (this.renderingBoIds) {
if (this.renderingBoIdsViewDirty) {
this.renderingBoIdsView = Collections.unmodifiableSet(new HashSet<>(this.renderingBoIds));
this.renderingBoIdsViewDirty = false;
}
return this.renderingBoIdsView;
}
} }
@Override @Override

View File

@@ -692,7 +692,7 @@ public class FileSelectionDialogModule extends AbstractClientModule {
} }
private void clearScrollArea() { private void clearScrollArea() {
for (final var boId : this.itemsScrollArea.getRenderingBoIds().toArray(new String[0])) { for (final var boId : this.itemsScrollArea.getRenderingBoIds()) {
this.itemsScrollArea.removeRenderingBo(boId); this.itemsScrollArea.removeRenderingBo(boId);
} }
} }

View File

@@ -357,7 +357,7 @@ public class FileSelectionMoveDialogModule extends AbstractClientModule {
} }
private void clearScrollArea() { private void clearScrollArea() {
for (final var boId : this.folderScrollArea.getRenderingBoIds().toArray(new String[0])) { for (final var boId : this.folderScrollArea.getRenderingBoIds()) {
this.folderScrollArea.removeRenderingBo(boId); this.folderScrollArea.removeRenderingBo(boId);
} }
} }