Add dropdowns and a popup color picker

Popup draws one element above the rest of the screen and gets mouse
events first; clicking or scrolling outside closes it. ElementContext now
carries each element's position on screen so an input inside a scroll can
open a popup beside itself.

Select is a dropdown: the current value opens an OptionList with the
current option ticked, scrolling for long lists and opening upward when
there's no room below. The color picker moved out of ColorInput into a
ColorPicker popup, so scroll areas no longer clip it and later rows no
longer draw over it, and all three of its parts can be dragged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-27 18:02:41 +02:00
co-authored by claude
parent 351507d60d
commit 6bfdfc40c9
16 changed files with 509 additions and 236 deletions
@@ -35,6 +35,7 @@ public abstract class SaturnScreen {
elements.clear();
width = provider.getWidth();
height = provider.getHeight();
Popup.reset(width, height);
ui(); // abstraction to render the saturn ui and also render extra stuff here
}
@@ -54,6 +55,7 @@ public abstract class SaturnScreen {
renderScope.getMatrixStack().scale(0.5f, 0.5f);
ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY);
Popup.render(renderScope, elapsed, mouseX, mouseY);
renderScope.getMatrixStack().pop();
}
@@ -66,7 +68,9 @@ public abstract class SaturnScreen {
mouseX *= 2;
mouseY *= 2;
ElementRenderer.mouseClicked(elements, mouseX, mouseY, button);
if (!Popup.mouseClicked(mouseX, mouseY, button)) {
ElementRenderer.mouseClicked(elements, mouseX, mouseY, button);
}
return false;
}
@@ -75,7 +79,9 @@ public abstract class SaturnScreen {
mouseX *= 2;
mouseY *= 2;
ElementRenderer.mouseDragged(elements, mouseX, mouseY, button, deltaX, deltaY);
if (!Popup.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) {
ElementRenderer.mouseDragged(elements, mouseX, mouseY, button, deltaX, deltaY);
}
return false;
}
@@ -84,6 +90,8 @@ public abstract class SaturnScreen {
mouseX *= 2;
mouseY *= 2;
// Everything hears the release, so no element is left thinking it's being dragged.
Popup.mouseReleased(mouseX, mouseY, button);
ElementRenderer.mouseReleased(elements, mouseX, mouseY, button);
return false;
@@ -97,7 +105,9 @@ public abstract class SaturnScreen {
mouseX *= 2;
mouseY *= 2;
ElementRenderer.mouseScrolled(elements, mouseX, mouseY, horizontalAmount, verticalAmount);
if (!Popup.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) {
ElementRenderer.mouseScrolled(elements, mouseX, mouseY, horizontalAmount, verticalAmount);
}
return false;
}