Refactor DiceOS architecture: introduce DiceOSAdapter, enhance event handling in Component, and improve window management
Build and Test / build (push) Has been cancelled
Build and Test / build (push) Has been cancelled
This commit is contained in:
@@ -15,7 +15,7 @@ The project uses Gradle.
|
||||
* **Language:** Java
|
||||
* **Dependency Injection:** Uses `avaje-inject`. Components are marked with `@Component` and injected via constructor.
|
||||
* **Boilerplate:** Uses `lombok` for boilerplate reduction.
|
||||
* **Rendering:** Built on LibGDX. Main entry point is `DiceOS.java` which extends `ApplicationAdapter`.
|
||||
* **Rendering:** Built on LibGDX. Main entry point is `DiceOSAdapter.java` which extends `ApplicationAdapter`.
|
||||
* **Asset Loading:** All assets, including textures, fonts, and NinePatches, must be loaded via the `ResourceLoader` service to ensure proper lifecycle management and caching.
|
||||
* **Project Structure:**
|
||||
* `src/main/java/be/seeseemelk/diceos/system`: Core OS services (Display, Window, Input, etc.).
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package be.seeseemelk.diceos;
|
||||
|
||||
import be.seeseemelk.diceos.system.DiceOS;
|
||||
import be.seeseemelk.diceos.system.DiceOSAdapter;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.glutils.HdpiMode;
|
||||
@@ -13,7 +14,8 @@ public class Bootloader {
|
||||
config.setTitle("DiceOS");
|
||||
config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode());
|
||||
config.setHdpiMode(HdpiMode.Pixels);
|
||||
new Lwjgl3Application(beanScope.get(DiceOS.class), config);
|
||||
beanScope.get(DiceOS.class);
|
||||
new Lwjgl3Application(beanScope.get(DiceOSAdapter.class), config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,121 +1,36 @@
|
||||
package be.seeseemelk.diceos.system;
|
||||
|
||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||
import io.avaje.inject.Component;
|
||||
import io.avaje.inject.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DiceOS extends ApplicationAdapter {
|
||||
@Component
|
||||
public class DiceOS {
|
||||
private static DiceOS INSTANCE;
|
||||
private final ResourceLoader resourceLoader;
|
||||
private final DisplayService display;
|
||||
private final CursorService cursorService;
|
||||
private final WindowService windowService;
|
||||
private final List<OnStartup> startupTasks;
|
||||
private Texture clouds;
|
||||
private Texture border;
|
||||
private Viewport vmViewport;
|
||||
private Viewport screenViewport;
|
||||
private int scaling = 1;
|
||||
private int offsetX = 0;
|
||||
private int offsetY = 0;
|
||||
private GraphicsContext gc;
|
||||
|
||||
private BitmapFont font;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
log.info("DiceOS starting...");
|
||||
clouds = resourceLoader.loadTexture("backgrounds/clouds.png");
|
||||
border = resourceLoader.loadTexture("system/border.png");
|
||||
|
||||
screenViewport = new ScreenViewport();
|
||||
vmViewport = new ScreenViewport();
|
||||
vmViewport.update(display.getWidth(), display.getHeight(), true);
|
||||
|
||||
for (var task : startupTasks) {
|
||||
task.onStartup();
|
||||
@PostConstruct
|
||||
void register() {
|
||||
if (INSTANCE != null) {
|
||||
throw new IllegalStateException("DiceOS already created");
|
||||
}
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
font = resourceLoader.loadFont("system/font");
|
||||
|
||||
log.info("DiceOS started!");
|
||||
public static DiceOS get() {
|
||||
if (INSTANCE == null) {
|
||||
throw new IllegalStateException("ResourceLoader not initialized yet");
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
screenViewport.update(width, height, true);
|
||||
|
||||
int displayWidth = display.getWidth();
|
||||
int displayHeight = display.getHeight();
|
||||
scaling = Math.min(width / displayWidth, height / displayHeight);
|
||||
offsetX = (width - (displayWidth * scaling)) / 2;
|
||||
offsetY = (height - (displayHeight * scaling)) / 2;
|
||||
|
||||
cursorService.setScale(scaling);
|
||||
|
||||
gc = new GraphicsContext(screenViewport.getCamera(), display.getBatch(), displayHeight, displayWidth);
|
||||
public static ResourceLoader getResourceLoader() {
|
||||
return INSTANCE.resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
int mouseX = Gdx.input.getX();
|
||||
int mouseY = display.getHeight() - Gdx.input.getY();
|
||||
windowService.update(mouseX, mouseY, Gdx.input.isTouched());
|
||||
|
||||
cursorService.updateCursor();
|
||||
|
||||
ScreenUtils.clear(Color.BLACK);
|
||||
vmViewport.apply();
|
||||
display.getScreenBuffer().begin();
|
||||
display.getBatch().setProjectionMatrix(vmViewport.getCamera().combined);
|
||||
display.getBatch().begin();
|
||||
|
||||
ScreenUtils.clear(Color.GREEN);
|
||||
|
||||
// Render background
|
||||
gc.draw(clouds, 0, 0);
|
||||
|
||||
// Render windows
|
||||
windowService.paint(gc);
|
||||
|
||||
// Render borders
|
||||
var param = new GraphicsContext.Parameters();
|
||||
gc.draw(border, 0, 0, param);
|
||||
param.flipX = true;
|
||||
gc.draw(border, display.getWidth() - 8, 0, param);
|
||||
param.flipY = true;
|
||||
gc.draw(border, display.getWidth() - 8, display.getHeight() - 8, param);
|
||||
param.flipX = false;
|
||||
gc.draw(border, 0, display.getHeight() - 8, param);
|
||||
|
||||
font.draw(display.getBatch(), "The quick brown fox jumps over the lazy dog", 6, display.getHeight() - 12);
|
||||
|
||||
// Finish rendering to screen buffer
|
||||
display.getBatch().end();
|
||||
display.getScreenBuffer().end();
|
||||
|
||||
// Render screen buffer to actual screen
|
||||
screenViewport.apply();
|
||||
display.getBatch().setProjectionMatrix(screenViewport.getCamera().combined);
|
||||
display.getBatch().begin();
|
||||
var texture = display.getScreenBuffer().getColorBufferTexture();
|
||||
var textureRegion = new TextureRegion(texture);
|
||||
textureRegion.flip(false, true);
|
||||
display.getBatch().draw(textureRegion, offsetX, offsetY, display.getWidth() * scaling, display.getHeight() * scaling);
|
||||
display.getBatch().end();
|
||||
public static WindowService getWindowService() {
|
||||
return INSTANCE.windowService;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package be.seeseemelk.diceos.system;
|
||||
|
||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||
import io.avaje.inject.Component;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DiceOSAdapter extends ApplicationAdapter {
|
||||
private final ResourceLoader resourceLoader;
|
||||
private final DisplayService display;
|
||||
private final CursorService cursorService;
|
||||
private final WindowService windowService;
|
||||
private final List<OnStartup> startupTasks;
|
||||
private Texture clouds;
|
||||
private Texture border;
|
||||
private Viewport vmViewport;
|
||||
private Viewport screenViewport;
|
||||
private int scaling = 1;
|
||||
private int offsetX = 0;
|
||||
private int offsetY = 0;
|
||||
private GraphicsContext gc;
|
||||
|
||||
private BitmapFont font;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
log.info("DiceOS starting...");
|
||||
clouds = resourceLoader.loadTexture("backgrounds/clouds.png");
|
||||
border = resourceLoader.loadTexture("system/border.png");
|
||||
|
||||
screenViewport = new ScreenViewport();
|
||||
vmViewport = new ScreenViewport();
|
||||
vmViewport.update(display.getWidth(), display.getHeight(), true);
|
||||
|
||||
for (var task : startupTasks) {
|
||||
task.onStartup();
|
||||
}
|
||||
|
||||
font = resourceLoader.loadFont("system/font");
|
||||
|
||||
log.info("DiceOS started!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
screenViewport.update(width, height, true);
|
||||
|
||||
int displayWidth = display.getWidth();
|
||||
int displayHeight = display.getHeight();
|
||||
scaling = Math.min(width / displayWidth, height / displayHeight);
|
||||
offsetX = (width - (displayWidth * scaling)) / 2;
|
||||
offsetY = (height - (displayHeight * scaling)) / 2;
|
||||
|
||||
cursorService.setScale(scaling);
|
||||
|
||||
gc = new GraphicsContext(screenViewport.getCamera(), display.getBatch(), displayHeight, displayWidth, font);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
int mouseX = Gdx.input.getX();
|
||||
int mouseY = display.getHeight() - Gdx.input.getY();
|
||||
windowService.update(mouseX, mouseY, Gdx.input.isTouched());
|
||||
|
||||
cursorService.updateCursor();
|
||||
|
||||
ScreenUtils.clear(Color.BLACK);
|
||||
vmViewport.apply();
|
||||
display.getScreenBuffer().begin();
|
||||
display.getBatch().setProjectionMatrix(vmViewport.getCamera().combined);
|
||||
display.getBatch().begin();
|
||||
|
||||
ScreenUtils.clear(Color.GREEN);
|
||||
|
||||
// Render background
|
||||
gc.draw(clouds, 0, 0);
|
||||
|
||||
// Render windows
|
||||
windowService.paint(gc);
|
||||
|
||||
// Render borders
|
||||
var param = new GraphicsContext.Parameters();
|
||||
gc.draw(border, 0, 0, param);
|
||||
param.flipX = true;
|
||||
gc.draw(border, display.getWidth() - 8, 0, param);
|
||||
param.flipY = true;
|
||||
gc.draw(border, display.getWidth() - 8, display.getHeight() - 8, param);
|
||||
param.flipX = false;
|
||||
gc.draw(border, 0, display.getHeight() - 8, param);
|
||||
|
||||
// Finish rendering to screen buffer
|
||||
display.getBatch().end();
|
||||
display.getScreenBuffer().end();
|
||||
|
||||
// Render screen buffer to actual screen
|
||||
screenViewport.apply();
|
||||
display.getBatch().setProjectionMatrix(screenViewport.getCamera().combined);
|
||||
display.getBatch().begin();
|
||||
var texture = display.getScreenBuffer().getColorBufferTexture();
|
||||
var textureRegion = new TextureRegion(texture);
|
||||
textureRegion.flip(false, true);
|
||||
display.getBatch().draw(textureRegion, offsetX, offsetY, display.getWidth() * scaling, display.getHeight() * scaling);
|
||||
display.getBatch().end();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -16,13 +16,11 @@ public class WindowService implements OnStartup {
|
||||
private final ResourceLoader resourceLoader;
|
||||
private final List<Window> windows = new ArrayList<>();
|
||||
private NinePatch menubar;
|
||||
private NinePatch windowDecoration;
|
||||
private Menu menu;
|
||||
|
||||
@Override
|
||||
public void onStartup() {
|
||||
menubar = resourceLoader.loadNinePatch("system/menubar.png");
|
||||
windowDecoration = resourceLoader.loadNinePatch("system/window.png");
|
||||
|
||||
menu = new Menu("Root");
|
||||
menu.add(new Menu("Dice"));
|
||||
@@ -30,7 +28,25 @@ public class WindowService implements OnStartup {
|
||||
}
|
||||
|
||||
public void spawnWindow(int x, int y, int width, int height) {
|
||||
windows.add(new Window(x, y, width, height));
|
||||
windows.add(new Window(x, y, width, height, Window.Style.NORMAL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a window to be managed by this service.
|
||||
* @param window The window to manage.
|
||||
*/
|
||||
public void map(Window window) {
|
||||
if (!windows.contains(window)) {
|
||||
windows.add(window);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmaps a window, removing it from management.
|
||||
* @param window The window to remove.
|
||||
*/
|
||||
public void unmap(Window window) {
|
||||
windows.remove(window);
|
||||
}
|
||||
|
||||
public void update(int mouseX, int mouseY, boolean isTouched) {
|
||||
@@ -48,8 +64,12 @@ public class WindowService implements OnStartup {
|
||||
gc.draw(menubar, 0, 0, gc.getWidth(), 14);
|
||||
|
||||
// Render menubar items
|
||||
if (menu != null) {
|
||||
menu.paint(gc);
|
||||
}
|
||||
gc.save();
|
||||
gc.translate(5, 0);
|
||||
for (var submenu : menu.getItems()) {
|
||||
submenu.paint(gc);
|
||||
gc.translate(submenu.getWidth(), 0);
|
||||
}
|
||||
gc.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public class FontLoader {
|
||||
var region = new TextureRegion(texture);
|
||||
|
||||
var data = new BitmapFont.BitmapFontData();
|
||||
data.lineHeight = metadata.getGeneral().getLineHeight();
|
||||
|
||||
var glyphMap = new Map2D<Integer, Integer, BitmapFont.Glyph>();
|
||||
var glyphLines = metadata.getGeneral().getOrder().split("\n");
|
||||
@@ -65,6 +66,8 @@ public class FontLoader {
|
||||
glyph.u2 = (float)widthTiming.glyphEnd / pixmap.getWidth();
|
||||
glyph.v = (float)heightTiming.glyphStart / pixmap.getHeight();
|
||||
glyph.v2 = (float)heightTiming.glyphEnd / pixmap.getHeight();
|
||||
|
||||
data.capHeight = Math.max(data.capHeight, heightTiming.getGlyphHeight());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,4 +15,7 @@ public class GeneralSection {
|
||||
* The order of the glyphs in the image file.
|
||||
*/
|
||||
private String order;
|
||||
|
||||
// @gemini implement
|
||||
private int lineHeight;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package be.seeseemelk.diceos.system.gfx;
|
||||
|
||||
import be.seeseemelk.diceos.system.DiceOS;
|
||||
import com.badlogic.gdx.graphics.Camera;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Graphics context and rendering utilities.
|
||||
*/
|
||||
@@ -21,9 +21,19 @@ public class GraphicsContext {
|
||||
private final Batch batch;
|
||||
private final int height;
|
||||
private final int width;
|
||||
private final BitmapFont font;
|
||||
|
||||
private final com.badlogic.gdx.math.Matrix4 originalTransform = new com.badlogic.gdx.math.Matrix4();
|
||||
private final java.util.Stack<com.badlogic.gdx.math.Matrix4> transformStack = new java.util.Stack<>();
|
||||
private final java.util.Stack<GraphicsState> stateStack = new java.util.Stack<>();
|
||||
|
||||
private static class GraphicsState {
|
||||
private final com.badlogic.gdx.math.Matrix4 transform;
|
||||
private final boolean scissorEnabled;
|
||||
|
||||
public GraphicsState(com.badlogic.gdx.math.Matrix4 transform, boolean scissorEnabled) {
|
||||
this.transform = transform.cpy();
|
||||
this.scissorEnabled = scissorEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a NinePatch image at the specified coordinates and dimensions.
|
||||
@@ -61,6 +71,16 @@ public class GraphicsContext {
|
||||
params.flipX, params.flipY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws some text with the current font.
|
||||
* @param text The text to draw.
|
||||
* @param x The x coordinate to draw at.
|
||||
* @param y The y coordinate to draw at.
|
||||
*/
|
||||
public void draw(String text, int x, int y) {
|
||||
font.draw(batch, text, x, getHeight() - (y + font.getLineHeight()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills a rectangular area with the currently set color.
|
||||
* @param x The x-coordinate.
|
||||
@@ -69,7 +89,8 @@ public class GraphicsContext {
|
||||
* @param height The height.
|
||||
*/
|
||||
public void fillRect(int x, int y, int width, int height) {
|
||||
batch.draw(com.badlogic.gdx.graphics.Texture.class.cast(null), x, getHeight() - height - y, width, height); // This is not ideal.
|
||||
var texture = DiceOS.getResourceLoader().loadTexture("system/white.png");
|
||||
batch.draw(texture, x, getHeight() - height - y, width, height); // This is not ideal.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,13 +105,13 @@ public class GraphicsContext {
|
||||
|
||||
/**
|
||||
* Shifts the context to the right and down by some amount.
|
||||
* Negative values move to the opposite direction.
|
||||
* Negative values move towards the opposite direction.
|
||||
*
|
||||
* @param x The number of pixels to move to the right by.
|
||||
* @param y The number of pixels to move down by.
|
||||
*/
|
||||
public void translate(int x, int y) {
|
||||
batch.getTransformMatrix().trn(x, -y, 0);
|
||||
batch.setTransformMatrix(batch.getTransformMatrix().trn(x, -y, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +132,7 @@ public class GraphicsContext {
|
||||
* The state can later be restored using {@link #restore()}.
|
||||
*/
|
||||
public void save() {
|
||||
transformStack.push(batch.getTransformMatrix().cpy());
|
||||
stateStack.push(new GraphicsState(batch.getTransformMatrix(), false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,12 +140,12 @@ public class GraphicsContext {
|
||||
* @throws IllegalStateException if no state was pushed.
|
||||
*/
|
||||
public void restore() {
|
||||
if (transformStack.isEmpty()) {
|
||||
if (stateStack.isEmpty()) {
|
||||
throw new IllegalStateException("No state to restore");
|
||||
}
|
||||
batch.flush();
|
||||
ScissorStack.popScissors();
|
||||
batch.setTransformMatrix(transformStack.pop());
|
||||
GraphicsState state = stateStack.pop();
|
||||
batch.setTransformMatrix(state.transform);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
package be.seeseemelk.diceos.system.toolkit;
|
||||
|
||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||
import be.seeseemelk.diceos.system.toolkit.events.Event;
|
||||
import be.seeseemelk.diceos.system.toolkit.events.InputEvent;
|
||||
import be.seeseemelk.diceos.system.toolkit.events.MouseEvent;
|
||||
|
||||
public abstract class Component {
|
||||
public abstract int getX();
|
||||
public abstract int getY();
|
||||
public abstract int getWidth();
|
||||
public abstract int getHeight();
|
||||
|
||||
public abstract void paint(GraphicsContext gc);
|
||||
|
||||
public void onEvent(Event event) {
|
||||
switch (event) {
|
||||
case InputEvent inputEvent -> onInputEvent(inputEvent);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
public void onInputEvent(InputEvent event) {
|
||||
switch (event) {
|
||||
case MouseEvent mouseEvent -> onMouseEvent(mouseEvent);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseEvent(MouseEvent event) {
|
||||
switch (event) {
|
||||
case be.seeseemelk.diceos.system.toolkit.events.MouseClickEvent mouseClickEvent -> onMouseClick(mouseClickEvent);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseClick(be.seeseemelk.diceos.system.toolkit.events.MouseClickEvent event) {
|
||||
// Default empty implementation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package be.seeseemelk.diceos.system.toolkit;
|
||||
|
||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||
import be.seeseemelk.diceos.system.toolkit.events.MouseEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -22,4 +23,14 @@ public abstract class Container extends Component {
|
||||
component.paint(gc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseEvent(MouseEvent event) {
|
||||
super.onMouseEvent(event);
|
||||
for (var component : components) {
|
||||
if (component instanceof Window window && window.isHovered(event.getX(), event.getY())) {
|
||||
component.onMouseEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package be.seeseemelk.diceos.system.toolkit;
|
||||
|
||||
import be.seeseemelk.diceos.system.DiceOS;
|
||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
||||
import lombok.Getter;
|
||||
@@ -14,7 +15,7 @@ public class Window extends Container {
|
||||
private String title;
|
||||
private int x, y, width, height;
|
||||
private boolean active;
|
||||
private Style style;
|
||||
private NinePatch borders;
|
||||
|
||||
/**
|
||||
* The style of window decorations to use.
|
||||
@@ -32,12 +33,33 @@ public class Window extends Container {
|
||||
NONE,
|
||||
}
|
||||
|
||||
public Window(int x, int y, int width, int height) {
|
||||
public Window(int x, int y, int width, int height, Style style) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.style = Style.NORMAL;
|
||||
setStyle(style);
|
||||
}
|
||||
|
||||
public void setStyle(Style style) {
|
||||
switch (style) {
|
||||
case NORMAL -> borders = DiceOS.getResourceLoader().loadNinePatch("system/window.png");
|
||||
case NONE -> borders = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows this window in the system.
|
||||
*/
|
||||
public void show() {
|
||||
DiceOS.getWindowService().map(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides this window from the system.
|
||||
*/
|
||||
public void hide() {
|
||||
DiceOS.getWindowService().unmap(this);
|
||||
}
|
||||
|
||||
public boolean isHovered(int mouseX, int mouseY) {
|
||||
@@ -66,6 +88,9 @@ public class Window extends Container {
|
||||
|
||||
@Override
|
||||
public void paint(GraphicsContext gc) {
|
||||
if (borders != null) {
|
||||
borders.draw(gc.getBatch(), x, gc.getHeight() - height - y, width, height);
|
||||
}
|
||||
super.paint(gc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
package be.seeseemelk.diceos.system.toolkit.events;
|
||||
|
||||
public abstract class Event {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package be.seeseemelk.diceos.system.toolkit.events;
|
||||
|
||||
public abstract class InputEvent extends Event {
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package be.seeseemelk.diceos.system.toolkit.events;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Event representing a mouse button click.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class MouseClickEvent extends MouseEvent {
|
||||
private final int x;
|
||||
private final int y;
|
||||
|
||||
/**
|
||||
* The mouse button that was clicked.
|
||||
*/
|
||||
private final Button button;
|
||||
|
||||
public enum Button {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package be.seeseemelk.diceos.system.toolkit.events;
|
||||
|
||||
/**
|
||||
* Base class for all mouse-related input events.
|
||||
*/
|
||||
public abstract class MouseEvent extends InputEvent {
|
||||
/**
|
||||
* @return The x-coordinate of the mouse event.
|
||||
*/
|
||||
public abstract int getX();
|
||||
|
||||
/**
|
||||
* @return The y-coordinate of the mouse event.
|
||||
*/
|
||||
public abstract int getY();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package be.seeseemelk.diceos.system.toolkit.menu;
|
||||
|
||||
import be.seeseemelk.diceos.system.DiceOS;
|
||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -33,17 +34,20 @@ public class Menu implements MenuItem {
|
||||
return items.stream().mapToInt(MenuItem::getHeight).sum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the popup at a specific coordinate.
|
||||
*
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
* @return The created MenuPopup.
|
||||
*/
|
||||
public MenuPopup show(int x, int y) {
|
||||
return new MenuPopup(this, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(GraphicsContext gc) {
|
||||
// @gemini re-implement
|
||||
// Need to render background and offset items
|
||||
// Since GC doesn't have direct rect methods, I'll use a simple approach with the batch
|
||||
// For now, focusing on correct rendering of items
|
||||
|
||||
int currentY = 0;
|
||||
for (MenuItem item : items) {
|
||||
item.paint(gc);
|
||||
currentY += item.getHeight();
|
||||
}
|
||||
// Renders the menu as a simple menu button
|
||||
gc.draw(title, 0, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package be.seeseemelk.diceos.system.toolkit.menu;
|
||||
|
||||
import be.seeseemelk.diceos.system.toolkit.Window;
|
||||
|
||||
/**
|
||||
* A visisble menu popup.
|
||||
*/
|
||||
public class MenuPopup {
|
||||
private final Menu menu;
|
||||
private final Window window;
|
||||
|
||||
public MenuPopup(Menu menu, int x, int y) {
|
||||
this.menu = menu;
|
||||
this.window = new Window(x, y, menu.getWidth(), menu.getHeight(), Window.Style.NONE);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ order = """
|
||||
aAbBcCdDeEfFgGhHiIjJkKlLmMnN
|
||||
oOpPqQrRsStTuUvVwWxXyYzZ
|
||||
"""
|
||||
lineHeight = 7
|
||||
|
||||
[padding]
|
||||
horizontal = 1
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 82 B |
Reference in New Issue
Block a user