feat(theme): add Blueprint theme and corresponding pattern renderer

This commit is contained in:
extio-de
2025-12-28 11:53:59 +01:00
parent 120dd91161
commit 23a95cd137
3 changed files with 181 additions and 0 deletions

View File

@@ -14,6 +14,7 @@ import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
import de.extio.game_engine.renderer.g2d.theme.PatternRenderer; import de.extio.game_engine.renderer.g2d.theme.PatternRenderer;
import de.extio.game_engine.renderer.g2d.theme.BevelDarkThemeFactoryBean; import de.extio.game_engine.renderer.g2d.theme.BevelDarkThemeFactoryBean;
import de.extio.game_engine.renderer.g2d.theme.BevelLightThemeFactoryBean; import de.extio.game_engine.renderer.g2d.theme.BevelLightThemeFactoryBean;
import de.extio.game_engine.renderer.g2d.theme.BlueprintThemeFactoryBean;
import de.extio.game_engine.renderer.g2d.theme.ContemporaryThemeFactoryBean; import de.extio.game_engine.renderer.g2d.theme.ContemporaryThemeFactoryBean;
import de.extio.game_engine.renderer.g2d.theme.DreamThemeFactoryBean; import de.extio.game_engine.renderer.g2d.theme.DreamThemeFactoryBean;
import de.extio.game_engine.renderer.g2d.theme.FantasyThemeFactoryBean; import de.extio.game_engine.renderer.g2d.theme.FantasyThemeFactoryBean;
@@ -104,6 +105,11 @@ public class G2DAutoConfiguration {
return new BevelDarkThemeFactoryBean(); return new BevelDarkThemeFactoryBean();
} }
@Bean
FactoryBean<Theme> blueprintTheme() {
return new BlueprintThemeFactoryBean();
}
@Bean @Bean
G2DThemeManager g2dThemeManager( G2DThemeManager g2dThemeManager(
final StaticResourceService staticResourceService, final StaticResourceService staticResourceService,

View File

@@ -0,0 +1,129 @@
package de.extio.game_engine.renderer.g2d.theme;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import de.extio.game_engine.renderer.g2d.G2DRendererCondition;
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
/**
* Implementation of PatternRenderer that draws a technical "Blueprint" style with grids and measurement markers.
*/
@Conditional(G2DRendererCondition.class)
@Component
public class BlueprintPatternRenderer implements PatternRenderer {
@Override
public void drawDecorativeBorder(final Graphics2D g2d, final int x, final int y, final int width, final int height, final int strength, final Color color) {
g2d.setColor(color);
// Main thin border line
final Stroke oldStroke = g2d.getStroke();
g2d.setStroke(new BasicStroke(1.0f));
g2d.drawRect(x, y, width - 1, height - 1);
// Corner accents (thicker)
final int cornerLen = Math.min(Math.min(width, height) / 3, 20);
final int thick = Math.max(2, strength);
g2d.fillRect(x, y, cornerLen, thick); // Top-Left Horz
g2d.fillRect(x, y, thick, cornerLen); // Top-Left Vert
g2d.fillRect(x + width - cornerLen, y, cornerLen, thick); // Top-Right Horz
g2d.fillRect(x + width - thick, y, thick, cornerLen); // Top-Right Vert
g2d.fillRect(x, y + height - thick, cornerLen, thick); // Bottom-Left Horz
g2d.fillRect(x, y + height - cornerLen, thick, cornerLen); // Bottom-Left Vert
g2d.fillRect(x + width - cornerLen, y + height - thick, cornerLen, thick); // Bottom-Right Horz
g2d.fillRect(x + width - thick, y + height - cornerLen, thick, cornerLen); // Bottom-Right Vert
// Mid-point markers
final int midX = x + width / 2;
final int midY = y + height / 2;
final int markerLen = 6;
g2d.fillRect(midX - markerLen/2, y, markerLen, thick); // Top Mid
g2d.fillRect(midX - markerLen/2, y + height - thick, markerLen, thick); // Bottom Mid
g2d.fillRect(x, midY - markerLen/2, thick, markerLen); // Left Mid
g2d.fillRect(x + width - thick, midY - markerLen/2, thick, markerLen); // Right Mid
g2d.setStroke(oldStroke);
}
@Override
public void drawDecorativeBorderFilled(final Graphics2D g2d, final int x, final int y, final int width, final int height, final int strength, final Color borderColor, final Color backgroundColor) {
// Fill background
g2d.setColor(backgroundColor);
g2d.fillRect(x, y, width, height);
// Draw border
this.drawDecorativeBorder(g2d, x, y, width, height, strength, borderColor);
}
@Override
public void drawWindowPanel(final Graphics2D g2d, final int x, final int y, final int width, final int height, final boolean thickBorder, final Color innerBorderColor, final Color outerBorderColor, final Color backgroundColor, final double scaleFactor) {
// Background
g2d.setColor(backgroundColor);
g2d.fillRect(x, y, width, height);
// Grid
final Color gridColor = new Color(255, 255, 255, 20); // Faint white grid
g2d.setColor(gridColor);
final int gridSize = (int)(20 * scaleFactor);
if (gridSize > 2) {
for (int gx = x; gx < x + width; gx += gridSize) {
g2d.drawLine(gx, y, gx, y + height);
}
for (int gy = y; gy < y + height; gy += gridSize) {
g2d.drawLine(x, gy, x + width, gy);
}
}
// Border
final int strength = Math.max((thickBorder ? 3 : 2), (int) ((thickBorder ? 4 : 2) * scaleFactor));
drawDecorativeBorder(g2d, x, y, width, height, strength, outerBorderColor);
}
@Override
public void drawCloseButton(final Graphics2D g2d, final int width, final int height, final boolean enabled, final int state, final Color backgroundColor, final double scaleFactor, final Theme theme) {
final var STATE_PRESSED = 2;
final var pressed = (state & STATE_PRESSED) != 0;
// Button background (transparent or slightly lighter blue)
Color btnBg = backgroundColor;
if (btnBg == null) {
btnBg = pressed ? theme.getSelectionPrimary().toColor() : theme.getBackgroundNormal().toColor().brighter();
}
g2d.setColor(btnBg);
g2d.fillRect(0, 0, width, height);
// Border
g2d.setColor(theme.getBorderOuter().toColor());
g2d.drawRect(0, 0, width - 1, height - 1);
// X icon
if (enabled) {
g2d.setColor(theme.getTextNormal().toColor());
// Draw a technical X (crosshair style?)
// Or just a clean X
final int padding = (int)(4 * scaleFactor);
final int x1 = padding;
final int y1 = padding;
final int x2 = width - padding;
final int y2 = height - padding;
final Graphics2D g2 = (Graphics2D) g2d.create();
g2.setStroke(new BasicStroke((float)(2 * scaleFactor)));
g2.drawLine(x1, y1, x2, y2);
g2.drawLine(x1, y2, x2, y1);
g2.dispose();
}
}
}

View File

@@ -0,0 +1,46 @@
package de.extio.game_engine.renderer.g2d.theme;
import org.springframework.beans.factory.FactoryBean;
public class BlueprintThemeFactoryBean implements FactoryBean<Theme> {
@Override
public Theme getObject() {
return Theme.builder()
.name("Blueprint")
.patternRendererName("blueprintPatternRenderer")
// Highlight/Border (White/Cyan)
.borderOuter(new HSBColor(0.5f, 0.0f, 1.0f))
// Inner Border (Faint Blue)
.borderInner(new HSBColor(0.6f, 0.5f, 0.8f))
// Disabled
.borderInnerDisabled(new HSBColor(0.6f, 0.2f, 0.4f))
// Background (Deep Blueprint Blue)
.backgroundNormal(new HSBColor(0.62f, 0.90f, 0.40f))
// Selected Background (Lighter Blue)
.backgroundSelected(new HSBColor(0.62f, 0.70f, 0.60f))
// Text (White)
.textNormal(new HSBColor(0.0f, 0.0f, 1.0f))
// Text Disabled (Light Blue)
.textDisabled(new HSBColor(0.6f, 0.3f, 0.7f))
// Selection Primary (Cyan)
.selectionPrimary(new HSBColor(0.5f, 0.8f, 0.9f))
// Selection Secondary (White)
.selectionSecondary(new HSBColor(0.0f, 0.0f, 1.0f))
// Window Background (Deep Blueprint Blue)
.windowBackground(new HSBColor(0.62f, 0.90f, 0.40f))
.hoverBrightnessAdjustment(0.15f)
.pressedBrightnessAdjustment(0.30f)
.build();
}
@Override
public Class<?> getObjectType() {
return Theme.class;
}
@Override
public boolean isSingleton() {
return true;
}
}