Skip to content

Commit 792c774

Browse files
committed
Fix ReactiveComponent
I swear it worked before!
1 parent ea57a09 commit 792c774

13 files changed

Lines changed: 208 additions & 41 deletions

settings.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ pluginManagement {
99
name = 'QuiltMC Releases'
1010
url 'https://maven.quiltmc.org/repository/release/'
1111
}
12-
mavenLocal()
1312
}
1413
}
1514

src/main/java/de/geolykt/starloader/api/gui/Drawing.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,27 @@ public static float drawText(@NotNull String message, float x, float y, @NotNull
153153
return implementation.drawText(message, x, y, color);
154154
}
155155

156+
/**
157+
* Fills a rectangle on the main drawing batch (as provided by {@link #getDrawingBatch()})
158+
* with a certain color.
159+
*
160+
* @param x The X-position to draw on; it is the left corner of the rectangle.
161+
* @param y The Y-position to draw on; it is not known which corner it corresponds to. Caution is advised
162+
* @param width The width of the rectangle.
163+
* @param height The height of the rectangle.
164+
* @param camera The camera to use. It transforms x/y-positions as well as width and height of the drawn rectangle.
165+
* @param fillColor The GDX color to fill it with.
166+
* @since 1.5.0
167+
*/
168+
public static void fillRect(float x, float y, float width, float height, @NotNull Color fillColor, @NotNull Camera camera) {
169+
implementation.fillRect(x, y, width, height, fillColor, camera);
170+
}
171+
156172
/**
157173
* <b>As specified by the APINote, this method has unintended consequences. It does not only operate
158174
* like a fillRect() method, but also draws a frame around the rectangle. More specifically
159175
* this frame is assumed to be linked with {@link TextureProvider#getAlternateWindowNinepatch()}.</b>
176+
* To fill the contents of a window/screen, use {@link #fillRect(float, float, float, float, Color, Camera)} instead.
160177
*
161178
* <p>Fills a rectangle with a given width and height with a specified color. As a
162179
* friendly reminder, the position 0,0 is the lower left corner and as the
@@ -172,8 +189,7 @@ public static float drawText(@NotNull String message, float x, float y, @NotNull
172189
* anything but the Widget. Act carefully for you may not want to call
173190
* this method.
174191
*/
175-
public static void fillWindow(float x, float y, float width, float height, @NotNull Color color,
176-
@NotNull Camera camera) {
192+
public static void fillWindow(float x, float y, float width, float height, @NotNull Color color, @NotNull Camera camera) {
177193
implementation.fillWindow(x, y, width, height, color, camera);
178194
}
179195

src/main/java/de/geolykt/starloader/api/gui/DrawingImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,20 @@ public default float drawText(@NotNull String message, float x, float y, @NotNul
115115
return this.drawText(message, x, y, color.toGalimulatorColor());
116116
}
117117

118+
/**
119+
* Fills a rectangle on the main drawing batch (as provided by {@link #getMainDrawingBatch()})
120+
* with a certain color.
121+
*
122+
* @param x The X-position to draw on; it is the left corner of the rectangle.
123+
* @param y The Y-position to draw on; it is not known which corner it corresponds to. Caution is advised
124+
* @param width The width of the rectangle.
125+
* @param height The height of the rectangle.
126+
* @param camera The camera to use. It transforms x/y-positions as well as width and height of the drawn rectangle.
127+
* @param fillColor The GDX color to fill it with.
128+
* @since 1.5.0
129+
*/
130+
public void fillRect(float x, float y, float width, float height, @NotNull Color fillColor, @NotNull Camera camera);
131+
118132
/**
119133
* <b>As specified by the APINote, this method has unintended consequences. It does not only operate
120134
* like a fillRect() method, but also draws a frame around the rectangle. More specifically

src/main/java/de/geolykt/starloader/api/gui/TextureProvider.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,22 @@
33
import org.jetbrains.annotations.NotNull;
44

55
import com.badlogic.gdx.graphics.g2d.NinePatch;
6+
import com.badlogic.gdx.graphics.g2d.TextureRegion;
67

78
public interface TextureProvider {
89

10+
/**
11+
* Obtains the texture region that is resolved by the given name.
12+
* Should there be no texture region by the given name (yet), then the texture
13+
* region for flower.png is returned. It will also return that texture region for an
14+
* empty name.
15+
*
16+
* @param name The name of the texture region. Usually the name of a file within the sprites folder.
17+
* @return The texture region registered under the name, or the texture region of flower.png
18+
*/
19+
@NotNull
20+
public TextureRegion findTextureRegion(@NotNull String name);
21+
922
/**
1023
* Obtains the ninepatch responsible for alternative window frames.
1124
* This ninepatch corresponds to the "window3.png" sprite.
@@ -14,7 +27,8 @@ public interface TextureProvider {
1427
*
1528
* @return The alternate window ninepatch
1629
*/
17-
public @NotNull NinePatch getAlternateWindowNinepatch();
30+
@NotNull
31+
public NinePatch getAlternateWindowNinepatch();
1832

1933
/**
2034
* Obtains the ninepatch responsible for button background of more non-rounded rectangular buttons.
@@ -24,15 +38,17 @@ public interface TextureProvider {
2438
*
2539
* @return The box button ninepatch
2640
*/
27-
public @NotNull NinePatch getBoxButtonNinePatch();
41+
@NotNull
42+
public NinePatch getBoxButtonNinePatch();
2843

2944
/**
3045
* Obtains the ninepatch responsible for button background of most buttons.
3146
* This ninepatch corresponds to the "button3.png" sprite.
3247
*
3348
* @return The button ninepatch
3449
*/
35-
public @NotNull NinePatch getRoundedButtonNinePatch();
50+
@NotNull
51+
public NinePatch getRoundedButtonNinePatch();
3652

3753
/**
3854
* Obtains the ninepatch responsible for window frames.
@@ -42,5 +58,6 @@ public interface TextureProvider {
4258
*
4359
* @return The window ninepatch
4460
*/
45-
public @NotNull NinePatch getWindowNinepatch();
61+
@NotNull
62+
public NinePatch getWindowNinepatch();
4663
}

src/main/java/de/geolykt/starloader/api/gui/screen/ReactiveComponent.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77

88
/**
99
* Interface that provides reactive behaviour for mouse movements.
10-
* Should always be implemented alongside {@link ScreenComponent}.
1110
*/
12-
public interface ReactiveComponent {
11+
public interface ReactiveComponent extends ScreenComponent {
1312

1413
/**
1514
* Called when the mouse moves over the component.
@@ -19,11 +18,17 @@ public interface ReactiveComponent {
1918
* @param componentX The X-position of the component relative to the screen. Use for drawing operations only.
2019
* @param componentY The Y-position of the component relative to the screen. Use for drawing operations only.
2120
* @param camera The camera supplied for drawing operations.
21+
* @deprecated Not yet implemented
2222
*/
23+
@Deprecated(forRemoval = false, since = "1.5.0")
2324
public void onHover(int screenX, int screenY, int componentX, int componentY, @NotNull Camera camera);
2425

2526
/**
2627
* Called when the user clicks on the component.
28+
* The documentation of screenX, screenY, componentX and componentY is done as intended. The future me should not come to the idea
29+
* that the documentation was wrong. However the variable names might be misleading ...
30+
*
31+
* <p>screenY will be inverted compared to the rendering y's. You might want to do component.getHeight() - screenY to obtain a more usable height.
2732
*
2833
* @param screenX The Y-position of the mouse relative to this component. Bound between {@link ScreenComponent#getWidth()} and {@code 0}
2934
* @param screenY The Y-position of the mouse relative to this component. Bound between {@link ScreenComponent#getHeight()} and {@code 0}

src/main/java/de/geolykt/starloader/api/gui/screen/Screen.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public interface Screen extends Iterable<Map.Entry<Vector2, ScreenComponent>> {
1616

1717
/**
1818
* Adds a child component to this screen.
19-
* Note: while this method might look attractive, only the fewest implementations support it.
19+
* Note: while this method might look attractive, some implementations may not support it.
2020
* {@link ScreenBuilder} exposes {@link ScreenBuilder#addComponentProvider(ComponentProvider)},
2121
* which you may want to use instead.
2222
*
@@ -26,10 +26,10 @@ public interface Screen extends Iterable<Map.Entry<Vector2, ScreenComponent>> {
2626

2727
/**
2828
* Checks whether {@link #addChild(ScreenComponent)} is a valid operation in this implementation.
29-
* This method is needed as many implementation will create their children by their needs,
29+
* This method is needed as some implementation will create their children by their needs,
3030
* at which point it is hard to implement potential foreign children getting added by external means.
3131
*
32-
* @return Where {@link #addChild(ScreenComponent)} is a valid operation.
32+
* @return True when {@link #addChild(ScreenComponent)} is a valid operation, false otherwise
3333
*/
3434
public boolean canAddChildren();
3535

src/main/java/de/geolykt/starloader/api/gui/screen/ScreenBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public void addComponentProvider(@NotNull ComponentProvider provider) {
139139
* Sets the title of the screen as shown in the screen header.
140140
* The default color of this title is white.
141141
* This method is a required operation and otherwise {@link #build()} will fail,
142-
* except if {@link #setHeaderEnabled(boolean)} was called if false as a parameter.
142+
* except if {@link #setHeaderEnabled(boolean)} was called with false as a parameter.
143143
*
144144
* @param title The title of the screen.
145145
*/

src/main/java/de/geolykt/starloader/impl/DrawingManager.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.badlogic.gdx.graphics.g2d.BitmapFont;
1515
import com.badlogic.gdx.graphics.g2d.NinePatch;
1616
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
17+
import com.badlogic.gdx.graphics.g2d.TextureRegion;
1718
import com.badlogic.gdx.math.Vector3;
1819

1920
import de.geolykt.starloader.api.NullUtils;
@@ -90,11 +91,34 @@ public float drawText(@NotNull String message, float x, float y, @NotNull GalCol
9091
}
9192
}
9293

94+
@Override
95+
public void fillRect(float x, float y, float width, float height, @NotNull Color fillColor, @NotNull Camera camera) {
96+
SpriteBatch drawBatch = getMainDrawingBatch();
97+
boolean beganDrawing = false;
98+
if (!drawBatch.isDrawing()) {
99+
drawBatch.begin();
100+
beganDrawing = true;
101+
}
102+
TextureRegion region = findTextureRegion("whitesquare.png");
103+
drawBatch.setColor(fillColor);
104+
drawBatch.setProjectionMatrix(camera.combined);
105+
drawBatch.draw(region, x, y, width, height);
106+
if (beganDrawing) {
107+
drawBatch.end();
108+
}
109+
}
110+
93111
@Override
94112
public void fillWindow(float x, float y, float width, float height, @NotNull Color color, @NotNull Camera camera) {
95113
GalFX.a(x, y, width, height, new GalColor(color), camera);
96114
}
97115

116+
@Override
117+
@NotNull
118+
public TextureRegion findTextureRegion(@NotNull String name) {
119+
return NullUtils.requireNotNull(GalFX.b(name));
120+
}
121+
98122
@SuppressWarnings("null")
99123
@Override
100124
public @NotNull NinePatch getAlternateWindowNinepatch() {

src/main/java/de/geolykt/starloader/impl/gui/SLScreenWidget.java

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import de.geolykt.starloader.api.gui.screen.ReactiveComponent;
2121
import de.geolykt.starloader.api.gui.screen.Screen;
2222
import de.geolykt.starloader.api.gui.screen.ScreenComponent;
23+
import de.geolykt.starloader.impl.gui.ScreenComponentPositioningMeta.UnmodifableScreenComponentPositoningMetaIterator;
2324

2425
import snoddasmannen.galimulator.GalColor;
2526

@@ -32,12 +33,14 @@ public class SLScreenWidget extends SLAbstractWidget implements Screen {
3233
/**
3334
* The list of components displayed by the screen instance.
3435
*/
35-
protected final @NotNull List<@NotNull ScreenComponent> components;
36+
@NotNull
37+
protected final List<@NotNull ScreenComponent> components;
3638

3739
/**
3840
* The colour of the header bar. Usually it is orange, however can be set to a different colour in the constructor.
3941
*/
40-
protected final @NotNull GalColor headerColor;
42+
@NotNull
43+
protected final GalColor headerColor;
4144

4245
/**
4346
* The value returned by {@link #isHeadless()}.
@@ -47,7 +50,8 @@ public class SLScreenWidget extends SLAbstractWidget implements Screen {
4750
/**
4851
* The title of the screen. Set in the constructor.
4952
*/
50-
protected final @NotNull String title;
53+
@NotNull
54+
protected final String title;
5155

5256
/**
5357
* The width of the screen, set by the constructor.
@@ -59,7 +63,13 @@ public class SLScreenWidget extends SLAbstractWidget implements Screen {
5963
* A dynamic provider for the width of the screen. This has to be null if {@link #width} is a non -1 value, but
6064
* cannot be null if {@link #width} has a -1 value.
6165
*/
62-
protected final @Nullable IntSupplier widthProvider;
66+
@Nullable
67+
protected final IntSupplier widthProvider;
68+
69+
@NotNull
70+
private final List<ScreenComponentPositioningMeta> componentPositioningMeta = new ArrayList<>();
71+
72+
private double lastRenderHeight = Double.NaN;
6373

6474
/**
6575
* The constructor of this screen instance.
@@ -217,11 +227,7 @@ public boolean isHeadless() {
217227

218228
@Override
219229
public Iterator<Entry<Vector2, ScreenComponent>> iterator() {
220-
@SuppressWarnings("null")
221-
@NotNull Iterator<ScreenComponent> components = this.components.iterator();
222-
Camera c = getCamera();
223-
int height = (c == null ? getHeight() : (int) c.viewportHeight);
224-
return new SLScreenWidgetIterator(height, isHeadless(), getInnerWidth(), components, true);
230+
return new UnmodifableScreenComponentPositoningMetaIterator(this.componentPositioningMeta);
225231
}
226232

227233
@Override
@@ -246,31 +252,39 @@ protected final void paintBackground() {
246252
}
247253

248254
protected void renderSLChildComponents() {
255+
@SuppressWarnings("null")
256+
@NotNull Iterator<ScreenComponent> hackvar = this.components.iterator();
249257
Camera c = NullUtils.requireNotNull(getCamera(), "The internal camera may not be null in order for draw operations to succeed.");
250-
for (Map.Entry<Vector2, ScreenComponent> component : this) {
251-
Vector2 pos = component.getKey();
252-
component.getValue().renderAt((int) pos.x, (int) pos.y, c); // TODO originally the render operation had offsets, but not anymore. Explore why this may have been dumb to remove
258+
int height = getHeight();
259+
Iterator<Map.Entry<Vector2, ScreenComponent>> populator = new SLScreenWidgetPopulator(height, isHeadless(), getInnerWidth(), hackvar, false);
260+
261+
componentPositioningMeta.clear();
262+
lastRenderHeight = height;
263+
while (populator.hasNext()) {
264+
Map.Entry<Vector2, ScreenComponent> componentEntry = populator.next();
265+
Vector2 pos = componentEntry.getKey();
266+
ScreenComponent component = componentEntry.getValue();
267+
int width = component.renderAt((int) pos.x, (int) pos.y, c); // TODO originally the render operation had offsets, but not anymore. Explore why this may have been dumb to remove. (#getInnerWidth does not make any sense anymore dummy.)
268+
componentPositioningMeta.add(new ScreenComponentPositioningMeta(pos, width, component.getHeight(), component));
253269
}
254270
}
255271

256272
@Override
257273
protected void tap(double x, double y, boolean isLongTap) {
258-
Camera c = NullUtils.requireNotNull(getCamera(), "Camera may not be null.");
259-
for (Map.Entry<Vector2, ScreenComponent> component : this) {
260-
// For galimulator, y = 0, x = 0 is the lower left edge, positive numbers go more towards the upper right.
261-
// We follow the same principle within our screen API.
262-
ScreenComponent comp = component.getValue();
263-
if (!(comp instanceof ReactiveComponent)) {
274+
Camera c = NullUtils.requireNotNull(getCamera());
275+
double actualY = lastRenderHeight - y - 25.0D; // GDX and galimulator are a bit strange, but it makes sense once you get the gist.
276+
for (ScreenComponentPositioningMeta posMeta : this.componentPositioningMeta) {
277+
if (!(posMeta.component instanceof ReactiveComponent)) {
264278
continue;
265279
}
266-
Vector2 pos = component.getKey();
267-
if ((x >= pos.x && x <= pos.x + comp.getWidth())
268-
&& (y <= pos.y && y >= pos.y - comp.getHeight())) {
269-
// FIXME galimulator provides values that I did not expect. Was my initial reverse-engineering wrong?
280+
ReactiveComponent component = (ReactiveComponent) posMeta.component;
281+
Vector2 pos = posMeta.pos;
282+
if ((x >= pos.x && x <= pos.x + posMeta.width)
283+
&& (pos.y <= actualY && (pos.y + posMeta.height) >= actualY)) {
270284
if (isLongTap) {
271-
((ReactiveComponent) comp).onLongClick((int) (x - pos.x), (int) (y - pos.y) + comp.getHeight(), (int) pos.x, (int) pos.y, c);
285+
component.onLongClick((int) (x - pos.x), (int) (posMeta.height - (actualY - pos.y)), (int) pos.x, (int) pos.y, c);
272286
} else {
273-
((ReactiveComponent) comp).onClick((int) (x - pos.x), (int) (y - pos.y) + comp.getHeight(), (int) pos.x, (int) pos.y, c);
287+
component.onClick((int) (x - pos.x), (int) (posMeta.height - (actualY - pos.y)), (int) pos.x, (int) pos.y, c);
274288
}
275289
}
276290
}

src/main/java/de/geolykt/starloader/impl/gui/SLScreenWidgetIterator.java renamed to src/main/java/de/geolykt/starloader/impl/gui/SLScreenWidgetPopulator.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
import de.geolykt.starloader.api.gui.screen.LineWrappingInfo;
1414
import de.geolykt.starloader.api.gui.screen.Screen;
1515
import de.geolykt.starloader.api.gui.screen.ScreenComponent;
16+
import de.geolykt.starloader.impl.gui.ScreenComponentPositioningMeta.UnmodifableScreenComponentPositoningMetaIterator;
1617

1718
/**
18-
* Internal class that implements the iterator required by the {@link Screen} interface.
19+
* Internal class that fits the components based on their meta.
1920
* For use with {@link SLScreenWidget}, it iterates based on insertion order.
21+
* The iterator required by the {@link Screen} interface is implemented by
22+
* the {@link UnmodifableScreenComponentPositoningMetaIterator}.
2023
*/
21-
final class SLScreenWidgetIterator implements Iterator<Map.Entry<Vector2, ScreenComponent>> {
24+
final class SLScreenWidgetPopulator implements Iterator<Map.Entry<Vector2, ScreenComponent>> {
2225

2326
private final @NotNull Iterator<ScreenComponent> components;
2427
private final int maxWidth;
@@ -28,7 +31,7 @@ final class SLScreenWidgetIterator implements Iterator<Map.Entry<Vector2, Screen
2831
private int x;
2932
private int y;
3033

31-
public SLScreenWidgetIterator(int viewportHeight, boolean headless, int innerWidth, @NotNull Iterator<ScreenComponent> components, boolean supportRemove) {
34+
public SLScreenWidgetPopulator(int viewportHeight, boolean headless, int innerWidth, @NotNull Iterator<ScreenComponent> components, boolean supportRemove) {
3235
this.components = components;
3336
this.y = viewportHeight;
3437
if (!headless) {

0 commit comments

Comments
 (0)