Compare commits
1 Commits
master
..
936942c1bf
| Author | SHA1 | Date | |
|---|---|---|---|
| 936942c1bf |
@@ -1,23 +0,0 @@
|
|||||||
name: Build and Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
|
||||||
with:
|
|
||||||
java-version: '21'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- name: Build and Test
|
|
||||||
run: ./gradlew build
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Bootloader" type="Application" factoryName="Application" nameIsGenerated="true">
|
|
||||||
<option name="MAIN_CLASS_NAME" value="be.seeseemelk.diceos.Bootloader" />
|
|
||||||
<module name="diceos.main" />
|
|
||||||
<extension name="coverage">
|
|
||||||
<pattern>
|
|
||||||
<option name="PATTERN" value="be.seeseemelk.diceos.*" />
|
|
||||||
<option name="ENABLED" value="true" />
|
|
||||||
</pattern>
|
|
||||||
</extension>
|
|
||||||
<method v="2">
|
|
||||||
<option name="Make" enabled="true" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
@@ -15,8 +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 `DiceOSAdapter.java` which extends `ApplicationAdapter`.
|
* **Rendering:** Built on LibGDX. Main entry point is `DiceOS.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:**
|
* **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.).
|
||||||
* `src/main/resources`: Assets (backgrounds, system textures, fonts).
|
* `src/main/resources`: Assets (backgrounds, system textures, fonts).
|
||||||
|
|||||||
+5
-9
@@ -7,14 +7,10 @@ plugins {
|
|||||||
group = "be.seeseemelk"
|
group = "be.seeseemelk"
|
||||||
version = "1.0-SNAPSHOT"
|
version = "1.0-SNAPSHOT"
|
||||||
|
|
||||||
val gdxVersion = "1.14.2"
|
val gdxVersion = "1.14.0"
|
||||||
val slf4j = "2.0.18"
|
val slf4j = "2.0.18"
|
||||||
val lombokVersion = "1.18.46"
|
val lombokVersion = "1.18.46"
|
||||||
val avajeInjectVersion = "12.6-javax"
|
val avajeInjectVersion = "12.5"
|
||||||
|
|
||||||
application {
|
|
||||||
mainClass = "be.seeseemelk.diceos.Bootloader"
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -32,21 +28,21 @@ dependencies {
|
|||||||
testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}")
|
testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}")
|
||||||
|
|
||||||
// Dependency Injection
|
// Dependency Injection
|
||||||
implementation("io.avaje:avaje-config:5.1")
|
implementation("io.avaje:avaje-config:4.4")
|
||||||
implementation("io.avaje:avaje-inject:${avajeInjectVersion}")
|
implementation("io.avaje:avaje-inject:${avajeInjectVersion}")
|
||||||
annotationProcessor("io.avaje:avaje-inject-generator:${avajeInjectVersion}")
|
annotationProcessor("io.avaje:avaje-inject-generator:${avajeInjectVersion}")
|
||||||
testImplementation("io.avaje:avaje-inject-test:${avajeInjectVersion}")
|
testImplementation("io.avaje:avaje-inject-test:${avajeInjectVersion}")
|
||||||
testAnnotationProcessor("io.avaje:avaje-inject-generator:${avajeInjectVersion}")
|
testAnnotationProcessor("io.avaje:avaje-inject-generator:${avajeInjectVersion}")
|
||||||
|
|
||||||
// Parsing TOML files
|
// Parsing TOML files
|
||||||
implementation("tools.jackson.dataformat:jackson-dataformat-toml:3.2.0")
|
implementation("tools.jackson.dataformat:jackson-dataformat-toml:3.1.3")
|
||||||
|
|
||||||
// LibGDX
|
// LibGDX
|
||||||
api("com.badlogicgames.gdx:gdx:$gdxVersion")
|
api("com.badlogicgames.gdx:gdx:$gdxVersion")
|
||||||
api("com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion")
|
api("com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion")
|
||||||
api("com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop")
|
api("com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop")
|
||||||
|
|
||||||
testImplementation(platform("org.junit:junit-bom:6.1.0"))
|
testImplementation(platform("org.junit:junit-bom:6.0.3"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+1
-3
@@ -1,9 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.5-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
retries=0
|
|
||||||
retryBackOffMs=500
|
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015 the original authors.
|
# Copyright © 2015-2021 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -114,6 +114,7 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -171,6 +172,7 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -210,6 +212,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
|
|||||||
Vendored
+22
-10
@@ -23,8 +23,8 @@
|
|||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables, and ensure extensions are enabled
|
@rem Set local scope for the variables with windows NT shell
|
||||||
setlocal EnableExtensions
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@@ -51,7 +51,7 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
"%COMSPEC%" /c exit 1
|
goto fail
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
@@ -65,18 +65,30 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
"%COMSPEC%" /c exit 1
|
goto fail
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
@rem which allows us to clear the local environment before executing the java command
|
|
||||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
|
||||||
|
|
||||||
:exitWithErrorLevel
|
:end
|
||||||
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
@rem End local scope for the variables with windows NT shell
|
||||||
"%COMSPEC%" /c exit %ERRORLEVEL%
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
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;
|
||||||
@@ -14,8 +13,7 @@ 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);
|
||||||
beanScope.get(DiceOS.class);
|
new Lwjgl3Application(beanScope.get(DiceOS.class), config);
|
||||||
new Lwjgl3Application(beanScope.get(DiceOSAdapter.class), config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,115 @@
|
|||||||
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.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;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class DiceOS {
|
@RequiredArgsConstructor
|
||||||
private static DiceOS INSTANCE;
|
public class DiceOS extends ApplicationAdapter {
|
||||||
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 InputService inputService;
|
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;
|
||||||
|
|
||||||
@PostConstruct
|
private BitmapFont font;
|
||||||
void register() {
|
|
||||||
if (INSTANCE != null) {
|
@Override
|
||||||
throw new IllegalStateException("DiceOS already created");
|
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();
|
||||||
}
|
}
|
||||||
INSTANCE = this;
|
|
||||||
|
font = resourceLoader.loadFont("system/font");
|
||||||
|
|
||||||
|
log.info("DiceOS started!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DiceOS get() {
|
@Override
|
||||||
if (INSTANCE == null) {
|
public void resize(int width, int height) {
|
||||||
throw new IllegalStateException("ResourceLoader not initialized yet");
|
screenViewport.update(width, height, true);
|
||||||
}
|
|
||||||
return INSTANCE;
|
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() {
|
@Override
|
||||||
return INSTANCE.resourceLoader;
|
public void render() {
|
||||||
}
|
cursorService.updateCursor();
|
||||||
|
|
||||||
public static WindowService getWindowService() {
|
ScreenUtils.clear(Color.BLACK);
|
||||||
return INSTANCE.windowService;
|
vmViewport.apply();
|
||||||
}
|
display.getScreenBuffer().begin();
|
||||||
|
display.getBatch().setProjectionMatrix(vmViewport.getCamera().combined);
|
||||||
|
display.getBatch().begin();
|
||||||
|
|
||||||
public static InputService getInputService() {
|
ScreenUtils.clear(Color.GREEN);
|
||||||
return INSTANCE.inputService;
|
|
||||||
|
// Render background
|
||||||
|
gc.draw(clouds, 0, 0);
|
||||||
|
|
||||||
|
gc.scissor(0, 0, gc.getWidth(), gc.getHeight(), windowService::paint);
|
||||||
|
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
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.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 InputService inputService;
|
|
||||||
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;
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
inputService.setScale(scaling);
|
|
||||||
inputService.setOffset(offsetX, offsetY);
|
|
||||||
|
|
||||||
gc = new GraphicsContext(screenViewport.getCamera(), display.getBatch(), displayHeight, displayWidth,
|
|
||||||
DiceOS.getResourceLoader().getDefaultFont().getBitmapFont());
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package be.seeseemelk.diceos.system;
|
package be.seeseemelk.diceos.system;
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.toolkit.events.MouseClickEvent;
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.Input;
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.InputAdapter;
|
import com.badlogic.gdx.InputAdapter;
|
||||||
@@ -13,9 +12,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class InputService implements OnStartup {
|
public class InputService implements OnStartup {
|
||||||
private final DisplayService displayService;
|
private final DisplayService displayService;
|
||||||
private int scale = 1;
|
|
||||||
private int offsetX = 0;
|
|
||||||
private int offsetY = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartup() {
|
public void onStartup() {
|
||||||
@@ -28,19 +24,6 @@ public class InputService implements OnStartup {
|
|||||||
} else if (keycode == Input.Keys.ESCAPE) {
|
} else if (keycode == Input.Keys.ESCAPE) {
|
||||||
Gdx.app.exit();
|
Gdx.app.exit();
|
||||||
}
|
}
|
||||||
//DiceOS.getWindowService().onEvent(new KeyEvent(keycode));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
|
|
||||||
DiceOS.getWindowService().onEvent(new MouseClickEvent(screenX, screenY, MouseClickEvent.Button.LEFT, MouseClickEvent.Action.RELEASED));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
|
|
||||||
DiceOS.getWindowService().onEvent(new MouseClickEvent(screenX, screenY, MouseClickEvent.Button.LEFT, MouseClickEvent.Action.PRESSED));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -50,36 +33,4 @@ public class InputService implements OnStartup {
|
|||||||
return Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_LEFT) ||
|
return Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_LEFT) ||
|
||||||
Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_RIGHT);
|
Gdx.input.isKeyPressed(com.badlogic.gdx.Input.Keys.ALT_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMouseX() {
|
|
||||||
return (Gdx.input.getX() - offsetX) / scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMouseY() {
|
|
||||||
return (Gdx.input.getY() - offsetY) / scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setScale(int scale) {
|
|
||||||
this.scale = scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOffset(int x, int y) {
|
|
||||||
this.offsetX = x;
|
|
||||||
this.offsetY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the mouse is currently within the specified rectangle.
|
|
||||||
* @param x The x-coordinate of the rectangle.
|
|
||||||
* @param y The y-coordinate of the rectangle.
|
|
||||||
* @param width The width of the rectangle.
|
|
||||||
* @param height The height of the rectangle.
|
|
||||||
* @return True if the mouse is within the rectangle, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean mouseInBounds(int x, int y, int width, int height) {
|
|
||||||
int mx = getMouseX();
|
|
||||||
int my = getMouseY();
|
|
||||||
return mx >= x && mx < x + width &&
|
|
||||||
my >= y && my < y + height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package be.seeseemelk.diceos.system;
|
package be.seeseemelk.diceos.system;
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.font.Font;
|
|
||||||
import be.seeseemelk.diceos.system.font.FontLoader;
|
import be.seeseemelk.diceos.system.font.FontLoader;
|
||||||
import be.seeseemelk.diceos.system.font.FontMetadata;
|
import be.seeseemelk.diceos.system.font.FontMetadata;
|
||||||
import be.seeseemelk.diceos.system.gfx.NinePatchLoader;
|
import be.seeseemelk.diceos.system.gfx.NinePatchLoader;
|
||||||
@@ -19,14 +18,6 @@ import tools.jackson.dataformat.toml.TomlFactory;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility class responsible for loading and caching graphical and textual assets used in the application.
|
|
||||||
* It manages various types of resources including pixmaps, textures, nine-patches, and fonts, ensuring that
|
|
||||||
* assets are loaded only once and subsequently reused to optimize performance.
|
|
||||||
*
|
|
||||||
* The class supports loading assets from specified file paths and caches them in memory. It implements a
|
|
||||||
* lazy-loading mechanism to defer loading until a resource is requested.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
@@ -34,7 +25,7 @@ public class ResourceLoader {
|
|||||||
private final Map<String, Pixmap> pixmaps = new HashMap<>();
|
private final Map<String, Pixmap> pixmaps = new HashMap<>();
|
||||||
private final Map<String, Texture> textures = new HashMap<>();
|
private final Map<String, Texture> textures = new HashMap<>();
|
||||||
private final Map<String, NinePatch> ninePatches = new HashMap<>();
|
private final Map<String, NinePatch> ninePatches = new HashMap<>();
|
||||||
private final Map<String, Font> fonts = new HashMap<>();
|
private final Map<String, BitmapFont> fonts = new HashMap<>();
|
||||||
private final ObjectMapper mapper = new ObjectMapper(new TomlFactory());
|
private final ObjectMapper mapper = new ObjectMapper(new TomlFactory());
|
||||||
|
|
||||||
public Pixmap loadPixmap(String path) {
|
public Pixmap loadPixmap(String path) {
|
||||||
@@ -45,13 +36,6 @@ public class ResourceLoader {
|
|||||||
return textures.computeIfAbsent(path, p -> new Texture(Gdx.files.internal(p)));
|
return textures.computeIfAbsent(path, p -> new Texture(Gdx.files.internal(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads and retrieves a {@link NinePatch} object for the given image path. The method caches loaded
|
|
||||||
* {@link NinePatch} instances to avoid redundant processing of the same asset.
|
|
||||||
*
|
|
||||||
* @param path the file path of the image to load as a 9-patch
|
|
||||||
* @return the loaded {@link NinePatch} instance corresponding to the specified image path
|
|
||||||
*/
|
|
||||||
public NinePatch loadNinePatch(String path) {
|
public NinePatch loadNinePatch(String path) {
|
||||||
return ninePatches.computeIfAbsent(path, p -> {
|
return ninePatches.computeIfAbsent(path, p -> {
|
||||||
var pixmap = loadPixmap(p);
|
var pixmap = loadPixmap(p);
|
||||||
@@ -60,28 +44,16 @@ public class ResourceLoader {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public BitmapFont loadFont(String path) {
|
||||||
* Loads and retrieves a {@link Font} object for the given file path.
|
|
||||||
* The method caches loaded {@link Font} instances to avoid redundant
|
|
||||||
* processing of the same asset.
|
|
||||||
*
|
|
||||||
* @param path the file path of the font to load
|
|
||||||
* @return the loaded {@link Font} instance corresponding to the specified file path
|
|
||||||
*/
|
|
||||||
public Font loadFont(String path) {
|
|
||||||
return fonts.computeIfAbsent(path, this::loadBitmapfont);
|
return fonts.computeIfAbsent(path, this::loadBitmapfont);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font getDefaultFont() {
|
private BitmapFont loadBitmapfont(String path) {
|
||||||
return loadFont("system/font");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Font loadBitmapfont(String path) {
|
|
||||||
log.info("Loading bitmap font from {}", path);
|
log.info("Loading bitmap font from {}", path);
|
||||||
|
|
||||||
var metadataString = Gdx.files.internal(path + ".toml").readString();
|
var metadataString = Gdx.files.internal(path + ".toml").readString();
|
||||||
var metadata = mapper.readValue(metadataString, FontMetadata.class);
|
var metadata = mapper.readValue(metadataString, FontMetadata.class);
|
||||||
@Cleanup("dispose") var pixmap = loadPixmap(metadata.getGeneral().getSource());
|
@Cleanup("dispose") var pixmap = loadPixmap(metadata.getGeneral().getSource());
|
||||||
return new Font(FontLoader.loadBitmapfont(pixmap, metadata));
|
return FontLoader.loadBitmapfont(pixmap, metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,95 +1,29 @@
|
|||||||
package be.seeseemelk.diceos.system;
|
package be.seeseemelk.diceos.system;
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
||||||
import be.seeseemelk.diceos.system.toolkit.Window;
|
import be.seeseemelk.diceos.system.toolkit.Menubar;
|
||||||
import be.seeseemelk.diceos.system.toolkit.events.Event;
|
|
||||||
import be.seeseemelk.diceos.system.toolkit.events.MouseClickEvent;
|
|
||||||
import be.seeseemelk.diceos.system.toolkit.menu.Menu;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
import com.badlogic.gdx.graphics.g2d.NinePatch;
|
||||||
import io.avaje.inject.Component;
|
import io.avaje.inject.Component;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
public class WindowService implements OnStartup {
|
public class WindowService implements OnStartup {
|
||||||
private final ResourceLoader resourceLoader;
|
private final ResourceLoader resourceLoader;
|
||||||
private final List<Window> windows = new ArrayList<>();
|
|
||||||
private NinePatch menubar;
|
private NinePatch menubar;
|
||||||
private Menu menu;
|
private Menubar systemMenubar;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartup() {
|
public void onStartup() {
|
||||||
menubar = resourceLoader.loadNinePatch("system/menubar.png");
|
menubar = resourceLoader.loadNinePatch("system/menubar.png");
|
||||||
|
|
||||||
menu = new Menu("Root");
|
systemMenubar = new Menubar()
|
||||||
menu.add(new Menu("Dice"));
|
.addItem("Dice")
|
||||||
menu.add(new Menu("System"));
|
.addItem("System");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnWindow(int x, int y, int width, int height) {
|
void paint(GraphicsContext gc) {
|
||||||
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) {
|
|
||||||
for (Window window : windows) {
|
|
||||||
window.handleInput(mouseX, mouseY, isTouched);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void paint(GraphicsContext gc) {
|
|
||||||
for (Window window : windows) {
|
|
||||||
window.paint(gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render menubar
|
// Render menubar
|
||||||
gc.draw(menubar, 0, 0, gc.getWidth(), 14);
|
gc.draw(menubar, 0, 0, gc.getWidth(), 14);
|
||||||
|
|
||||||
// Render menubar items
|
|
||||||
gc.save();
|
|
||||||
gc.translate(8, 0);
|
|
||||||
for (var submenu : menu.getItems()) {
|
|
||||||
gc.save();
|
|
||||||
gc.clip(0, 0, submenu.getWidth(), submenu.getHeight());
|
|
||||||
submenu.paint(gc);
|
|
||||||
gc.restore();
|
|
||||||
gc.translate(submenu.getWidth(), 0);
|
|
||||||
}
|
|
||||||
gc.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onEvent(Event event) {
|
|
||||||
switch (event) {
|
|
||||||
case MouseClickEvent e -> onMouseClickEvent(e);
|
|
||||||
default -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onMouseClickEvent(MouseClickEvent event) {
|
|
||||||
if (event.getY() <= 14) {
|
|
||||||
log.info("Clicking on menubar");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system;
|
|
||||||
|
|
||||||
import io.avaje.inject.Component;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class WindowSpawnTask implements OnStartup {
|
|
||||||
private final WindowService windowService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartup() {
|
|
||||||
windowService.spawnWindow(50, 50, 200, 150);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.font;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a font used for rendering text, providing utilities
|
|
||||||
* for measuring text dimensions.
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class Font {
|
|
||||||
@Getter
|
|
||||||
private final BitmapFont bitmapFont;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the width of the given text when rendered with the current font.
|
|
||||||
* @param text The text to measure.
|
|
||||||
* @return The width of the text in pixels.
|
|
||||||
*/
|
|
||||||
public int getTextWidth(String text) {
|
|
||||||
var layout = new com.badlogic.gdx.graphics.g2d.GlyphLayout();
|
|
||||||
layout.setText(bitmapFont, text);
|
|
||||||
return (int) layout.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,6 @@ 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");
|
||||||
@@ -66,8 +65,6 @@ 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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +192,7 @@ public class FontLoader {
|
|||||||
if (!isBlack) {
|
if (!isBlack) {
|
||||||
currentTiming.glyphEnd = x;
|
currentTiming.glyphEnd = x;
|
||||||
state = State.WAITING_FOR_GLYPH_WIDTHS;
|
state = State.WAITING_FOR_GLYPH_WIDTHS;
|
||||||
//log.info("Found glyph width: {} (from {} to {})", currentTiming.getGlyphWidth(), currentTiming.glyphStart, currentTiming.glyphEnd);
|
log.info("Found glyph width: {} (from {} to {})", currentTiming.getGlyphWidth(), currentTiming.glyphStart, currentTiming.glyphEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,4 @@ 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;
|
||||||
|
|
||||||
private int lineHeight;
|
|
||||||
|
|
||||||
public int getLineHeight() {
|
|
||||||
return lineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLineHeight(int lineHeight) {
|
|
||||||
this.lineHeight = lineHeight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
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.Stack;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Graphics context and rendering utilities.
|
* Graphics context and rendering utilities.
|
||||||
@@ -23,196 +21,38 @@ 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 Stack<GraphicsState> stateStack = new java.util.Stack<>();
|
|
||||||
|
|
||||||
private int translateX = 0;
|
|
||||||
private int translateY = 0;
|
|
||||||
|
|
||||||
private static class GraphicsState {
|
|
||||||
private final int translateX;
|
|
||||||
private final int translateY;
|
|
||||||
private int scissorCount;
|
|
||||||
|
|
||||||
public GraphicsState(int translateX, int translateY, int scissorCount) {
|
|
||||||
this.translateX = translateX;
|
|
||||||
this.translateY = translateY;
|
|
||||||
this.scissorCount = scissorCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a NinePatch image at the specified coordinates and dimensions.
|
|
||||||
* @param image The NinePatch to draw.
|
|
||||||
* @param x The x-coordinate.
|
|
||||||
* @param y The y-coordinate.
|
|
||||||
* @param width The width.
|
|
||||||
* @param height The height.
|
|
||||||
*/
|
|
||||||
public void draw(NinePatch image, int x, int y, int width, int height) {
|
public void draw(NinePatch image, int x, int y, int width, int height) {
|
||||||
image.draw(batch, x + translateX, getHeight() - height - (y + translateY), width, height);
|
image.draw(batch, x, getHeight() - height - y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a texture at the specified coordinates.
|
|
||||||
* @param texture The texture to draw.
|
|
||||||
* @param x The x-coordinate.
|
|
||||||
* @param y The y-coordinate.
|
|
||||||
*/
|
|
||||||
public void draw(Texture texture, int x, int y) {
|
public void draw(Texture texture, int x, int y) {
|
||||||
draw(texture, x + translateX, y + translateY, Parameters.DEFAULT);
|
draw(texture, x, y, Parameters.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a texture with specific drawing parameters.
|
|
||||||
* @param texture The texture to draw.
|
|
||||||
* @param x The x-coordinate.
|
|
||||||
* @param y The y-coordinate.
|
|
||||||
* @param params Drawing parameters (flipX, flipY).
|
|
||||||
*/
|
|
||||||
public void draw(Texture texture, int x, int y, Parameters params) {
|
public void draw(Texture texture, int x, int y, Parameters params) {
|
||||||
batch.draw(texture,
|
batch.draw(texture,
|
||||||
x + translateX, getHeight() - (y + translateY) - texture.getHeight(), texture.getWidth(), texture.getHeight(),
|
x, getHeight() - y - texture.getHeight(), texture.getWidth(), texture.getHeight(),
|
||||||
0, 0, texture.getWidth(), texture.getHeight(),
|
0, 0, texture.getWidth(), texture.getHeight(),
|
||||||
params.flipX, params.flipY);
|
params.flipX, params.flipY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void scissor(int x, int y, int width, int height, Consumer<GraphicsContext> callback) {
|
||||||
* Draws some text with the current font.
|
var scissors = new Rectangle();
|
||||||
* @param text The text to draw.
|
var clipBounds = new Rectangle(x, getHeight() - y - height, width, height);
|
||||||
* @param x The x coordinate to draw at.
|
ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), clipBounds, scissors);
|
||||||
* @param y The y coordinate to draw at.
|
|
||||||
*/
|
|
||||||
public void draw(String text, int x, int y) {
|
|
||||||
font.draw(batch, text, x + translateX, getHeight() - (y + translateY + font.getLineHeight()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills a rectangular area with the currently set color.
|
|
||||||
* @param x The x-coordinate.
|
|
||||||
* @param y The y-coordinate.
|
|
||||||
* @param width The width.
|
|
||||||
* @param height The height.
|
|
||||||
*/
|
|
||||||
public void fillRect(int x, int y, int width, int height) {
|
|
||||||
var texture = DiceOS.getResourceLoader().loadTexture("system/white.png");
|
|
||||||
batch.draw(texture, x + translateX, getHeight() - height - (y + translateY), width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the color for subsequent drawing operations.
|
|
||||||
* @param r The red component (0-255).
|
|
||||||
* @param g The green component (0-255).
|
|
||||||
* @param b The blue component (0-255).
|
|
||||||
*/
|
|
||||||
public void setColour(int r, int g, int b) {
|
|
||||||
batch.setColor(r / 255f, g / 255f, b / 255f, 1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the color for subsequent drawing operations using an RGB integer.
|
|
||||||
* @param rgb The RGB color integer.
|
|
||||||
*/
|
|
||||||
public void setColour(int rgb) {
|
|
||||||
setColour((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shifts the context to the right and down by some amount.
|
|
||||||
* 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) {
|
|
||||||
translateX += x;
|
|
||||||
translateY += y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the total amount of X-translation applied by this graphics context.
|
|
||||||
* In other words, a draw command with `x=0` would actually write to this screen coordinate.
|
|
||||||
* @return The total amount of X-translation.
|
|
||||||
*/
|
|
||||||
public int getXTranslation() {
|
|
||||||
return translateX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getYTranslation() {
|
|
||||||
return translateY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a clipping rectangle for subsequent draw operations.
|
|
||||||
*
|
|
||||||
* @param width The width of the clipping area.
|
|
||||||
* @param height The height of the clipping area.
|
|
||||||
*/
|
|
||||||
public void clip(int width, int height) {
|
|
||||||
clip(0, 0, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a clipping rectangle for subsequent draw operations.
|
|
||||||
*
|
|
||||||
* @param x The x-coordinate of the clipping area.
|
|
||||||
* @param y The y-coordinate of the clipping area.
|
|
||||||
* @param width The width of the clipping area.
|
|
||||||
* @param height The height of the clipping area.
|
|
||||||
*/
|
|
||||||
public void clip(int x, int y, int width, int height) {
|
|
||||||
var scissors = new Rectangle(x + getXTranslation(), getHeight() - (y + getYTranslation()) - height, width, height);
|
|
||||||
ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), scissors, scissors);
|
|
||||||
batch.flush();
|
batch.flush();
|
||||||
if (ScissorStack.pushScissors(scissors)) {
|
if (ScissorStack.pushScissors(scissors)) {
|
||||||
getCurrentState().scissorCount++;
|
callback.accept(this);
|
||||||
}
|
batch.flush();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current graphics state from the top of the stack.
|
|
||||||
* @return The current state.
|
|
||||||
*/
|
|
||||||
private GraphicsState getCurrentState() {
|
|
||||||
return stateStack.peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes the current state onto an internal stack.
|
|
||||||
* The state can later be restored using {@link #restore()}.
|
|
||||||
*/
|
|
||||||
public void save() {
|
|
||||||
stateStack.push(new GraphicsState(translateX, translateY, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restores a state pushed by {@link #save()}
|
|
||||||
* @throws IllegalStateException if no state was pushed.
|
|
||||||
*/
|
|
||||||
public void restore() {
|
|
||||||
if (stateStack.isEmpty()) {
|
|
||||||
throw new IllegalStateException("No state to restore");
|
|
||||||
}
|
|
||||||
batch.flush();
|
|
||||||
GraphicsState state = stateStack.pop();
|
|
||||||
translateX = state.translateX;
|
|
||||||
translateY = state.translateY;
|
|
||||||
for (int i = 0; i < state.scissorCount; i++) {
|
|
||||||
ScissorStack.popScissors();
|
ScissorStack.popScissors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Graphics drawing parameters.
|
|
||||||
*/
|
|
||||||
public static class Parameters {
|
public static class Parameters {
|
||||||
public final static Parameters DEFAULT = new Parameters();
|
public final static Parameters DEFAULT = new Parameters();
|
||||||
|
|
||||||
/** Indicates if the x-axis should be flipped. */
|
|
||||||
public boolean flipX = false;
|
public boolean flipX = false;
|
||||||
|
|
||||||
/** Indicates if the y-axis should be flipped. */
|
|
||||||
public boolean flipY = false;
|
public boolean flipY = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +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.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,7 +1,6 @@
|
|||||||
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;
|
||||||
@@ -23,14 +22,4 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package be.seeseemelk.diceos.system.toolkit;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Menubar {
|
||||||
|
@Getter
|
||||||
|
private final List<String> items = new ArrayList<>();
|
||||||
|
|
||||||
|
public Menubar addItem(String item) {
|
||||||
|
items.add(item);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,96 +1,16 @@
|
|||||||
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 lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a window within the system.
|
|
||||||
*/
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
public class Window extends Container {
|
public class Window extends Container {
|
||||||
private String title;
|
private String title;
|
||||||
private int x, y, width, height;
|
|
||||||
private boolean active;
|
|
||||||
private NinePatch borders;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The style of window decorations to use.
|
|
||||||
*/
|
|
||||||
public enum Style {
|
|
||||||
/**
|
|
||||||
* The standard style with a full window border.
|
|
||||||
* This is the default.
|
|
||||||
*/
|
|
||||||
NORMAL,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No borders
|
|
||||||
*/
|
|
||||||
NONE,
|
|
||||||
}
|
|
||||||
|
|
||||||
public Window(int x, int y, int width, int height, Style style) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
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) {
|
|
||||||
return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int dragOffsetX, dragOffsetY;
|
|
||||||
private boolean isDragging;
|
|
||||||
|
|
||||||
public void handleInput(int mouseX, int mouseY, boolean isTouched) {
|
|
||||||
if (isTouched) {
|
|
||||||
if (!isDragging && isHovered(mouseX, mouseY)) {
|
|
||||||
isDragging = true;
|
|
||||||
dragOffsetX = mouseX - x;
|
|
||||||
dragOffsetY = mouseY - y;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isDragging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDragging) {
|
|
||||||
x = mouseX - dragOffsetX;
|
|
||||||
y = mouseY - dragOffsetY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit.events;
|
|
||||||
|
|
||||||
public abstract class Event {
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit.events;
|
|
||||||
|
|
||||||
public abstract class InputEvent extends Event {
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The action performed in the mouse click event, indicating whether the mouse button
|
|
||||||
* was pressed or released.
|
|
||||||
*/
|
|
||||||
private final Action action;
|
|
||||||
|
|
||||||
public enum Button {
|
|
||||||
LEFT, RIGHT,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Action {
|
|
||||||
PRESSED, RELEASED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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,68 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit.menu;
|
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.DiceOS;
|
|
||||||
import be.seeseemelk.diceos.system.font.Font;
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
|
||||||
import be.seeseemelk.diceos.system.toolkit.Window;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Getter
|
|
||||||
@Slf4j
|
|
||||||
public class Menu implements MenuItem {
|
|
||||||
private final static int HORIZONTAL_PADDING = 2;
|
|
||||||
|
|
||||||
private final String title;
|
|
||||||
private final List<MenuItem> items = new ArrayList<>();
|
|
||||||
private final Font font = DiceOS.getResourceLoader().getDefaultFont();
|
|
||||||
|
|
||||||
public Menu add(MenuItem item) {
|
|
||||||
items.add(item);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Menu remove(MenuItem item) {
|
|
||||||
items.remove(item);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
return font.getTextWidth(title) + HORIZONTAL_PADDING * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return 13;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the popup at a specific coordinate.
|
|
||||||
*
|
|
||||||
* @param x The x-coordinate.
|
|
||||||
* @param y The y-coordinate.
|
|
||||||
* @return The created Window for the menu.
|
|
||||||
*/
|
|
||||||
public Window show(int x, int y) {
|
|
||||||
return new Window(x, y, getWidth(), getHeight(), Window.Style.NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void paint(GraphicsContext gc) {
|
|
||||||
if (DiceOS.getInputService().mouseInBounds(gc.getXTranslation(), gc.getYTranslation(), getWidth(), getHeight())) {
|
|
||||||
log.info("Mouse in bounds");
|
|
||||||
gc.setColour(0x9f7445);
|
|
||||||
gc.fillRect(-100, -100, 500, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
gc.setColour(255, 255, 255);
|
|
||||||
|
|
||||||
// Renders the menu as a simple menu button
|
|
||||||
gc.draw(title, HORIZONTAL_PADDING, 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit.menu;
|
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class MenuButton implements MenuItem {
|
|
||||||
private String text;
|
|
||||||
private Runnable callback;
|
|
||||||
|
|
||||||
public MenuButton(String text) {
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClick(Runnable callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void click() {
|
|
||||||
if (callback != null) {
|
|
||||||
callback.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
return text.length() * 8 + 10; // Simple approximation for now
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void paint(GraphicsContext gc) {
|
|
||||||
// Implement painting logic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit.menu;
|
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
|
||||||
|
|
||||||
public class MenuDivider implements MenuItem {
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void paint(GraphicsContext gc) {
|
|
||||||
// Implement divider drawing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.toolkit.menu;
|
|
||||||
|
|
||||||
import be.seeseemelk.diceos.system.gfx.GraphicsContext;
|
|
||||||
|
|
||||||
public interface MenuItem {
|
|
||||||
int getWidth();
|
|
||||||
int getHeight();
|
|
||||||
void paint(GraphicsContext gc);
|
|
||||||
}
|
|
||||||
@@ -12,18 +12,4 @@ public class Utils {
|
|||||||
public static boolean isPowerOfTwo(int value) {
|
public static boolean isPowerOfTwo(int value) {
|
||||||
return (value & (value - 1)) == 0 && value != 0;
|
return (value & (value - 1)) == 0 && value != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the point at (x, y) is inside the bounds of (x1, y1, width, height).
|
|
||||||
* @param x The x-coordinate of the point.
|
|
||||||
* @param y The y-coordinate of the point.
|
|
||||||
* @param x1 The x-coordinate of the bounds.
|
|
||||||
* @param y1 The y-coordinate of the bounds.
|
|
||||||
* @param width The width of the bounds.
|
|
||||||
* @param height The height of the bounds.
|
|
||||||
* @return True if the point is inside the bounds, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isInBounds(int x, int y, int x1, int y1, int width, int height) {
|
|
||||||
return x >= x1 && x < x1 + width && y >= y1 && y < y1 + height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ order = """
|
|||||||
aAbBcCdDeEfFgGhHiIjJkKlLmMnN
|
aAbBcCdDeEfFgGhHiIjJkKlLmMnN
|
||||||
oOpPqQrRsStTuUvVwWxXyYzZ
|
oOpPqQrRsStTuUvVwWxXyYzZ
|
||||||
"""
|
"""
|
||||||
lineHeight = 7
|
|
||||||
|
|
||||||
[padding]
|
[padding]
|
||||||
horizontal = 1
|
horizontal = 1
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 82 B |
Binary file not shown.
|
Before Width: | Height: | Size: 205 B |
@@ -1,39 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
|
||||||
import com.badlogic.gdx.Input;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
class InputServiceTest {
|
|
||||||
private DisplayService displayService;
|
|
||||||
private InputService inputService;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
displayService = Mockito.mock(DisplayService.class);
|
|
||||||
inputService = new InputService(displayService);
|
|
||||||
Gdx.input = Mockito.mock(Input.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testMouseMethods() {
|
|
||||||
Mockito.when(Gdx.input.getX()).thenReturn(100);
|
|
||||||
Mockito.when(Gdx.input.getY()).thenReturn(200);
|
|
||||||
|
|
||||||
assertEquals(100, inputService.getMouseX());
|
|
||||||
assertEquals(200, inputService.getMouseY());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testMouseInBounds() {
|
|
||||||
Mockito.when(Gdx.input.getX()).thenReturn(100);
|
|
||||||
Mockito.when(Gdx.input.getY()).thenReturn(200);
|
|
||||||
|
|
||||||
assertTrue(inputService.mouseInBounds(90, 190, 20, 20));
|
|
||||||
assertFalse(inputService.mouseInBounds(0, 0, 50, 50));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package be.seeseemelk.diceos.system.gfx;
|
|
||||||
|
|
||||||
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.Matrix4;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
class GraphicsContextTest {
|
|
||||||
private Camera camera;
|
|
||||||
private Batch batch;
|
|
||||||
private BitmapFont font;
|
|
||||||
private GraphicsContext gc;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
camera = mock(Camera.class);
|
|
||||||
batch = mock(Batch.class);
|
|
||||||
font = mock(BitmapFont.class);
|
|
||||||
gc = new GraphicsContext(camera, batch, 600, 800, font);
|
|
||||||
when(batch.getTransformMatrix()).thenReturn(new Matrix4());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testDrawNinePatch() {
|
|
||||||
NinePatch np = mock(NinePatch.class);
|
|
||||||
gc.draw(np, 10, 20, 100, 200);
|
|
||||||
verify(np).draw(eq(batch), eq(10f), eq(380f), eq(100f), eq(200f));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testDrawTexture() {
|
|
||||||
Texture tex = mock(Texture.class);
|
|
||||||
when(tex.getHeight()).thenReturn(50);
|
|
||||||
when(tex.getWidth()).thenReturn(50);
|
|
||||||
gc.draw(tex, 10, 20);
|
|
||||||
verify(batch).draw(eq(tex), eq(10f), anyFloat(), anyFloat(), anyFloat(), anyInt(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testDrawText() {
|
|
||||||
gc.draw("test", 10, 20);
|
|
||||||
verify(font).draw(batch, "test", 10f, 600f - (20f + font.getLineHeight()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetColour() {
|
|
||||||
gc.setColour(255, 0, 0);
|
|
||||||
verify(batch).setColor(1f, 0f, 0f, 1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetColourRGB() {
|
|
||||||
gc.setColour(0xFF00FF);
|
|
||||||
verify(batch).setColor(1f, 0f, 1f, 1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testTranslate() {
|
|
||||||
gc.translate(10, 20);
|
|
||||||
assertEquals(10, gc.getXTranslation());
|
|
||||||
assertEquals(20, gc.getYTranslation());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSaveRestore() {
|
|
||||||
gc.save();
|
|
||||||
assertDoesNotThrow(() -> gc.restore());
|
|
||||||
assertThrows(IllegalStateException.class, () -> gc.restore());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user