feat(FileSelectionDialogModule, G2DButtonControlImpl): add optional lazy per-file tooltip data on hover

This commit is contained in:
extio-de
2026-10-16 13:26:51 +02:00
parent f53ced0cb3
commit a006b76841
4 changed files with 114 additions and 1 deletions

View File

@@ -9,8 +9,11 @@ import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.ButtonControl;
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.ButtonData;
import de.extio.game_engine.renderer.model.color.RgbaColor;
import de.extio.game_engine.renderer.model.event.MouseEnterEvent;
import de.extio.game_engine.renderer.model.event.MouseExitEvent;
import de.extio.game_engine.renderer.model.event.UiControlEvent;
import de.extio.game_engine.resource.StaticResource;
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
public class G2DButtonControlImpl extends G2DBaseControlImpl implements ButtonControl {
@@ -24,6 +27,8 @@ public class G2DButtonControlImpl extends G2DBaseControlImpl implements ButtonCo
protected long lastControlDataUpdateTimeInternal;
protected boolean hovered;
@Override
public void setCustomData(final ButtonData data) {
if (data != null) {
@@ -68,7 +73,21 @@ public class G2DButtonControlImpl extends G2DBaseControlImpl implements ButtonCo
this.control.setLocation(this.x, this.y);
this.positionModified = false;
}
this.tooltipMousePosition = this.control.getLastMousePosition();
final var mousePosition = this.control.getLastMousePosition();
final var hoveredNow = mousePosition != null && this.visible && this.enabled;
if (hoveredNow != this.hovered) {
this.hovered = hoveredNow;
final var coord = mousePosition != null
? ImmutableCoordI2.create(this.x + mousePosition.getX(), this.y + mousePosition.getY())
: ImmutableCoordI2.create(this.x + this.width / 2, this.y + this.height / 2);
if (hoveredNow) {
this.rendererData.getEventService().fire(new MouseEnterEvent(this.id, 0, coord, coord));
}
else {
this.rendererData.getEventService().fire(new MouseExitEvent(this.id, 0, coord, coord));
}
}
this.tooltipMousePosition = mousePosition;
super.render();
}
@@ -82,6 +101,7 @@ public class G2DButtonControlImpl extends G2DBaseControlImpl implements ButtonCo
this.control.invalidate();
this.control.close();
((G2DRenderer) this.rendererData.getRenderer()).getMainFrame().remove(this.control);
this.hovered = false;
super.close();
}

View File

@@ -7,8 +7,22 @@ import de.extio.game_engine.spatial2.model.CoordI2;
*/
public final class MouseEnterEvent extends MouseEvent {
private final String controlId;
public MouseEnterEvent(final int modifiers, final CoordI2 rawCoord, final CoordI2 scaledCoord) {
this(null, modifiers, rawCoord, scaledCoord);
}
public MouseEnterEvent(final String controlId, final int modifiers, final CoordI2 rawCoord, final CoordI2 scaledCoord) {
super(rawCoord, scaledCoord, modifiers);
this.controlId = controlId;
}
/**
* Control ID the mouse entered, null if the mouse entered the viewport
*/
public String getControlId() {
return this.controlId;
}
}

View File

@@ -7,8 +7,22 @@ import de.extio.game_engine.spatial2.model.CoordI2;
*/
public final class MouseExitEvent extends MouseEvent {
private final String controlId;
public MouseExitEvent(final int modifiers, final CoordI2 rawCoord, final CoordI2 scaledCoord) {
this(null, modifiers, rawCoord, scaledCoord);
}
public MouseExitEvent(final String controlId, final int modifiers, final CoordI2 rawCoord, final CoordI2 scaledCoord) {
super(rawCoord, scaledCoord, modifiers);
this.controlId = controlId;
}
/**
* Control ID the mouse exited, null if the mouse exited the viewport
*/
public String getControlId() {
return this.controlId;
}
}

View File

@@ -9,6 +9,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import org.springframework.context.ApplicationContext;
@@ -30,6 +31,8 @@ import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.ToggleButtonCon
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.ToggleButtonData;
import de.extio.game_engine.renderer.model.bo.DrawFontRenderingBo;
import de.extio.game_engine.renderer.model.bo.HorizontalAlignment;
import de.extio.game_engine.renderer.model.event.MouseEnterEvent;
import de.extio.game_engine.renderer.model.event.MouseExitEvent;
import de.extio.game_engine.renderer.model.event.UiControlEvent;
import de.extio.game_engine.renderer.work.RenderingBoPool;
import de.extio.game_engine.spatial2.model.Area2;
@@ -145,8 +148,12 @@ public class FileSelectionDialogModule extends AbstractClientModule {
private String nameFieldValue;
private Function<StorageItemDescriptor, String> tooltipDataProvider;
private final Map<String, List<String>> folderPathByControlId = new HashMap<>();
private final Map<UUID, String> tooltipCache = new HashMap<>();
private final Map<String, StorageItemDescriptor> itemByControlId = new HashMap<>();
private final Set<List<String>> virtualFolders = new HashSet<>();
@@ -188,6 +195,8 @@ public class FileSelectionDialogModule extends AbstractClientModule {
@Override
public void onShow() {
this.eventService.register(UiControlEvent.class, this.getId(), this::onUiControlEvent);
this.eventService.register(MouseEnterEvent.class, this.getId(), this::onItemMouseEnter);
this.eventService.register(MouseExitEvent.class, this.getId(), this::onItemMouseExit);
this.eventService.register(FileSelectionMoveDialogResponse.class, this.getId(), this::onMoveResponse);
this.eventService.register(FileSelectionNewFolderDialogResponse.class, this.getId(), this::onNewFolderResponse);
this.getModuleService().changeDisplayState(this.dialogWindow.getId(), true);
@@ -199,6 +208,8 @@ public class FileSelectionDialogModule extends AbstractClientModule {
@Override
public void onHide() {
this.eventService.unregister(UiControlEvent.class, this.getId());
this.eventService.unregister(MouseEnterEvent.class, this.getId());
this.eventService.unregister(MouseExitEvent.class, this.getId());
this.eventService.unregister(FileSelectionMoveDialogResponse.class, this.getId());
this.eventService.unregister(FileSelectionNewFolderDialogResponse.class, this.getId());
this.getModuleService().changeDisplayState(this.dialogWindow.getId(), false);
@@ -209,6 +220,10 @@ public class FileSelectionDialogModule extends AbstractClientModule {
}
public void open(final String requestId, final FileSelectionMode mode, final List<String> basePath, final String filterPattern, final boolean recursive, final boolean modal, final String initialName, final Window parentWindow) {
this.open(requestId, mode, basePath, filterPattern, recursive, modal, initialName, parentWindow, null);
}
public void open(final String requestId, final FileSelectionMode mode, final List<String> basePath, final String filterPattern, final boolean recursive, final boolean modal, final String initialName, final Window parentWindow, final Function<StorageItemDescriptor, String> tooltipDataProvider) {
this.requestId = requestId;
this.mode = mode != null ? mode : FileSelectionMode.LOAD;
this.basePath = basePath != null ? List.copyOf(basePath) : List.of();
@@ -216,6 +231,8 @@ public class FileSelectionDialogModule extends AbstractClientModule {
this.filterPattern = filterPattern;
this.recursive = recursive;
this.modal = modal;
this.tooltipDataProvider = tooltipDataProvider;
this.tooltipCache.clear();
this.selectedDescriptor = null;
this.selectionIsNew = this.mode == FileSelectionMode.SAVE;
this.nameFieldValue = initialName != null && !initialName.isBlank() ? initialName.trim() : "";
@@ -269,6 +286,52 @@ public class FileSelectionDialogModule extends AbstractClientModule {
}
}
private void onItemMouseEnter(final MouseEnterEvent event) {
if (this.tooltipDataProvider == null || event == null || event.getControlId() == null || !event.getControlId().startsWith(ITEM_PREFIX)) {
return;
}
final var descriptor = this.itemByControlId.get(event.getControlId());
if (descriptor == null) {
return;
}
final var data = this.resolveTooltipData(descriptor);
if (data == null || data.isBlank()) {
return;
}
this.updateItemTooltip(event.getControlId(), data);
}
private void onItemMouseExit(final MouseExitEvent event) {
}
private String resolveTooltipData(final StorageItemDescriptor descriptor) {
final var cached = this.tooltipCache.get(descriptor.id());
if (cached != null) {
return cached;
}
String data;
try {
data = this.tooltipDataProvider.apply(descriptor);
}
catch (final Exception ex) {
data = null;
}
if (data == null) {
data = "";
}
this.tooltipCache.put(descriptor.id(), data);
return data;
}
private void updateItemTooltip(final String controlId, final String data) {
final var bo = this.itemsScrollArea.getRenderingBo(controlId, ControlRenderingBo.class);
if (bo != null) {
bo.setTooltip(data);
this.itemsScrollArea.putRenderingBo(bo);
this.dialogWindow.draw();
}
}
private void buildDialog() {
this.dialogWindow.clearRenderingBos();
this.clearScrollArea();
@@ -685,6 +748,8 @@ public class FileSelectionDialogModule extends AbstractClientModule {
this.selectedDescriptor = null;
this.selectionIsNew = false;
this.nameFieldValue = "";
this.tooltipDataProvider = null;
this.tooltipCache.clear();
this.virtualFolders.clear();
this.folderPathByControlId.clear();
this.itemByControlId.clear();