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
|
* **Language:** Java
|
||||||
* **Dependency Injection:** Uses `avaje-inject`. Components are marked with `@Component` and injected via constructor.
|
* **Dependency Injection:** Uses `avaje-inject`. Components are marked with `@Component` and injected via constructor.
|
||||||
* **Boilerplate:** Uses `lombok` for boilerplate reduction.
|
* **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.
|
* **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:**
|
* **Project Structure:**
|
||||||
* `src/main/java/be/seeseemelk/diceos/system`: Core OS services (Display, Window, Input, etc.).
|
* `src/main/java/be/seeseemelk/diceos/system`: Core OS services (Display, Window, Input, etc.).
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package be.seeseemelk.diceos;
|
package be.seeseemelk.diceos;
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.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.Lwjgl3Application;
|
||||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||||
import com.badlogic.gdx.graphics.glutils.HdpiMode;
|
import com.badlogic.gdx.graphics.glutils.HdpiMode;
|
||||||
@@ -13,7 +14,8 @@ public class Bootloader {
|
|||||||
config.setTitle("DiceOS");
|
config.setTitle("DiceOS");
|
||||||
config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode());
|
config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode());
|
||||||
config.setHdpiMode(HdpiMode.Pixels);
|
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;
|
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.Component;
|
||||||
|
import io.avaje.inject.PostConstruct;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class DiceOS extends ApplicationAdapter {
|
@Component
|
||||||
|
public class DiceOS {
|
||||||
|
private static DiceOS INSTANCE;
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
private final DisplayService display;
|
|
||||||
private final CursorService cursorService;
|
|
||||||
private final WindowService windowService;
|
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;
|
@PostConstruct
|
||||||
|
void register() {
|
||||||
@Override
|
if (INSTANCE != null) {
|
||||||
public void create() {
|
throw new IllegalStateException("DiceOS already created");
|
||||||
log.info("DiceOS starting...");
|
}
|
||||||
clouds = resourceLoader.loadTexture("backgrounds/clouds.png");
|
INSTANCE = this;
|
||||||
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");
|
public static DiceOS get() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
log.info("DiceOS started!");
|
throw new IllegalStateException("ResourceLoader not initialized yet");
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static ResourceLoader getResourceLoader() {
|
||||||
public void resize(int width, int height) {
|
return INSTANCE.resourceLoader;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static WindowService getWindowService() {
|
||||||
public void render() {
|
return INSTANCE.windowService;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ResourceLoader resourceLoader;
|
||||||
private final List<Window> windows = new ArrayList<>();
|
private final List<Window> windows = new ArrayList<>();
|
||||||
private NinePatch menubar;
|
private NinePatch menubar;
|
||||||
private NinePatch windowDecoration;
|
|
||||||
private Menu menu;
|
private Menu menu;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartup() {
|
public void onStartup() {
|
||||||
menubar = resourceLoader.loadNinePatch("system/menubar.png");
|
menubar = resourceLoader.loadNinePatch("system/menubar.png");
|
||||||
windowDecoration = resourceLoader.loadNinePatch("system/window.png");
|
|
||||||
|
|
||||||
menu = new Menu("Root");
|
menu = new Menu("Root");
|
||||||
menu.add(new Menu("Dice"));
|
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) {
|
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) {
|
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);
|
gc.draw(menubar, 0, 0, gc.getWidth(), 14);
|
||||||
|
|
||||||
// Render menubar items
|
// Render menubar items
|
||||||
if (menu != null) {
|
gc.save();
|
||||||
menu.paint(gc);
|
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 region = new TextureRegion(texture);
|
||||||
|
|
||||||
var data = new BitmapFont.BitmapFontData();
|
var data = new BitmapFont.BitmapFontData();
|
||||||
|
data.lineHeight = metadata.getGeneral().getLineHeight();
|
||||||
|
|
||||||
var glyphMap = new Map2D<Integer, Integer, BitmapFont.Glyph>();
|
var glyphMap = new Map2D<Integer, Integer, BitmapFont.Glyph>();
|
||||||
var glyphLines = metadata.getGeneral().getOrder().split("\n");
|
var glyphLines = metadata.getGeneral().getOrder().split("\n");
|
||||||
@@ -65,6 +66,8 @@ public class FontLoader {
|
|||||||
glyph.u2 = (float)widthTiming.glyphEnd / pixmap.getWidth();
|
glyph.u2 = (float)widthTiming.glyphEnd / pixmap.getWidth();
|
||||||
glyph.v = (float)heightTiming.glyphStart / pixmap.getHeight();
|
glyph.v = (float)heightTiming.glyphStart / pixmap.getHeight();
|
||||||
glyph.v2 = (float)heightTiming.glyphEnd / 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.
|
* The order of the glyphs in the image file.
|
||||||
*/
|
*/
|
||||||
private String order;
|
private String order;
|
||||||
|
|
||||||
|
// @gemini implement
|
||||||
|
private int lineHeight;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package be.seeseemelk.diceos.system.gfx;
|
package be.seeseemelk.diceos.system.gfx;
|
||||||
|
|
||||||
|
import be.seeseemelk.diceos.system.DiceOS;
|
||||||
import com.badlogic.gdx.graphics.Camera;
|
import com.badlogic.gdx.graphics.Camera;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
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.graphics.g2d.NinePatch;
|
||||||
import com.badlogic.gdx.math.Rectangle;
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
|
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Graphics context and rendering utilities.
|
* Graphics context and rendering utilities.
|
||||||
*/
|
*/
|
||||||
@@ -21,9 +21,19 @@ public class GraphicsContext {
|
|||||||
private final Batch batch;
|
private final Batch batch;
|
||||||
private final int height;
|
private final int height;
|
||||||
private final int width;
|
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<GraphicsState> stateStack = new java.util.Stack<>();
|
||||||
private final java.util.Stack<com.badlogic.gdx.math.Matrix4> transformStack = 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.
|
* Draws a NinePatch image at the specified coordinates and dimensions.
|
||||||
@@ -61,6 +71,16 @@ public class GraphicsContext {
|
|||||||
params.flipX, params.flipY);
|
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.
|
* Fills a rectangular area with the currently set color.
|
||||||
* @param x The x-coordinate.
|
* @param x The x-coordinate.
|
||||||
@@ -69,7 +89,8 @@ public class GraphicsContext {
|
|||||||
* @param height The height.
|
* @param height The height.
|
||||||
*/
|
*/
|
||||||
public void fillRect(int x, int y, int width, int 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.
|
* 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 x The number of pixels to move to the right by.
|
||||||
* @param y The number of pixels to move down by.
|
* @param y The number of pixels to move down by.
|
||||||
*/
|
*/
|
||||||
public void translate(int x, int y) {
|
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()}.
|
* The state can later be restored using {@link #restore()}.
|
||||||
*/
|
*/
|
||||||
public void save() {
|
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.
|
* @throws IllegalStateException if no state was pushed.
|
||||||
*/
|
*/
|
||||||
public void restore() {
|
public void restore() {
|
||||||
if (transformStack.isEmpty()) {
|
if (stateStack.isEmpty()) {
|
||||||
throw new IllegalStateException("No state to restore");
|
throw new IllegalStateException("No state to restore");
|
||||||
}
|
}
|
||||||
batch.flush();
|
batch.flush();
|
||||||
ScissorStack.popScissors();
|
GraphicsState state = stateStack.pop();
|
||||||
batch.setTransformMatrix(transformStack.pop());
|
batch.setTransformMatrix(state.transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,40 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit;
|
package be.seeseemelk.diceos.system.toolkit;
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
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 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 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;
|
package be.seeseemelk.diceos.system.toolkit;
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||||
|
import be.seeseemelk.diceos.system.toolkit.events.MouseEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -22,4 +23,14 @@ public abstract class Container extends Component {
|
|||||||
component.paint(gc);
|
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;
|
package be.seeseemelk.diceos.system.toolkit;
|
||||||
|
|
||||||
|
import be.seeseemelk.diceos.system.DiceOS;
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||||
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -14,7 +15,7 @@ public class Window extends Container {
|
|||||||
private String title;
|
private String title;
|
||||||
private int x, y, width, height;
|
private int x, y, width, height;
|
||||||
private boolean active;
|
private boolean active;
|
||||||
private Style style;
|
private NinePatch borders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style of window decorations to use.
|
* The style of window decorations to use.
|
||||||
@@ -32,12 +33,33 @@ public class Window extends Container {
|
|||||||
NONE,
|
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.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
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) {
|
public boolean isHovered(int mouseX, int mouseY) {
|
||||||
@@ -66,6 +88,9 @@ public class Window extends Container {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(GraphicsContext gc) {
|
public void paint(GraphicsContext gc) {
|
||||||
|
if (borders != null) {
|
||||||
|
borders.draw(gc.getBatch(), x, gc.getHeight() - height - y, width, height);
|
||||||
|
}
|
||||||
super.paint(gc);
|
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;
|
package be.seeseemelk.diceos.system.toolkit.menu;
|
||||||
|
|
||||||
|
import be.seeseemelk.diceos.system.DiceOS;
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -33,17 +34,20 @@ public class Menu implements MenuItem {
|
|||||||
return items.stream().mapToInt(MenuItem::getHeight).sum();
|
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
|
@Override
|
||||||
public void paint(GraphicsContext gc) {
|
public void paint(GraphicsContext gc) {
|
||||||
// @gemini re-implement
|
// Renders the menu as a simple menu button
|
||||||
// Need to render background and offset items
|
gc.draw(title, 0, 5);
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
aAbBcCdDeEfFgGhHiIjJkKlLmMnN
|
||||||
oOpPqQrRsStTuUvVwWxXyYzZ
|
oOpPqQrRsStTuUvVwWxXyYzZ
|
||||||
"""
|
"""
|
||||||
|
lineHeight = 7
|
||||||
|
|
||||||
[padding]
|
[padding]
|
||||||
horizontal = 1
|
horizontal = 1
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 82 B |
Reference in New Issue
Block a user