feat(theme): Introduce theming system with pattern renderers
- Added `ComponentState` enum to represent UI component states. - Implemented `G2DThemeManager` to manage themes and pattern renderers. - Created `HSBColor` class for HSB color representation and manipulation. - Defined `PatternRenderer` interface for rendering UI patterns. - Developed `SpacecraftPatternRenderer` and `VintagePatternRenderer` for default theming styles. - Introduced `Theme` class to encapsulate theme properties and builder pattern. - Added `SpacecraftThemeFactoryBean` and `VintageThemeFactoryBean` for theme instantiation. - Updated `G2DWindowPanelControlImpl` to utilize theme manager. - Removed obsolete `DrawWindowRenderingBo` interface. - Enhanced `DemoModule` to support theme selection and application.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package de.extio.game_engine.renderer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
|
||||
public interface ThemeManager {
|
||||
|
||||
List<String> getAvailableThemeNames();
|
||||
|
||||
Theme getCurrentTheme();
|
||||
|
||||
void setCurrentTheme(Theme theme);
|
||||
|
||||
void setCurrentTheme(String themeName);
|
||||
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package de.extio.game_engine.renderer.container.legacy;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererControl;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.spatial2.model.Area2;
|
||||
|
||||
/**
|
||||
* Helper to position, draw and manage virtual windows in the UI.
|
||||
* EnhancedWindow holds a state to switch between different representations and also can persist the window position.
|
||||
*/
|
||||
public class EnhancedWindow<T> extends Window {
|
||||
|
||||
public final static String PERSISTENT_STATE_PREFIX = "ENHANCEDWINDOW_POSITION_";
|
||||
|
||||
private final boolean persistentPosition;
|
||||
|
||||
private T state;
|
||||
|
||||
private final T initialState;
|
||||
|
||||
private final Function<T, Area2> areaFunction;
|
||||
|
||||
public static void resetWindows() {
|
||||
// boolean removed = false;
|
||||
// final Iterator<String> it = EngineFacade.instance().getPersistentClientState().state.keySet().iterator();
|
||||
// while (it.hasNext()) {
|
||||
// final String key = it.next();
|
||||
// if (key.startsWith(EnhancedWindow.PERSISTENT_STATE_PREFIX)) {
|
||||
// it.remove();
|
||||
// removed = true;
|
||||
// }
|
||||
// }
|
||||
// if (removed) {
|
||||
// EngineFacade.instance().storePersistentClientState();
|
||||
// }
|
||||
|
||||
synchronized (WINDOWS) {
|
||||
for (final Window window : WINDOWS) {
|
||||
if (window instanceof final EnhancedWindow<?> enhancedWindow) {
|
||||
enhancedWindow.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnhancedWindow(final String name, final boolean draggable, final boolean persistentPosition, final T initialState, final RenderingBoPool renderingBoPool, final RendererControl rendererControl, final Function<T, Area2> areaFunction) {
|
||||
super(name, draggable, renderingBoPool, rendererControl);
|
||||
|
||||
this.initialState = initialState;
|
||||
this.areaFunction = areaFunction;
|
||||
this.persistentPosition = persistentPosition;
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public T getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public void setState(final T state) {
|
||||
if (state == null) {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
this.state = state;
|
||||
}
|
||||
if (this.areaFunction != null) {
|
||||
this.updateArea();
|
||||
this.savePosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateArea() {
|
||||
if (this.areaFunction != null) {
|
||||
final var area = this.areaFunction.apply(this.state);
|
||||
this.setDimension(area.getDimension());
|
||||
// this.resizeCentered(area.getDimension());
|
||||
if (!this.persistentPosition) {
|
||||
this.setPosition(area.getPosition());
|
||||
}
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
super.updateArea();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
this.state = this.initialState;
|
||||
this.updateArea();
|
||||
this.loadPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseDragging() {
|
||||
if (this.isDragging()) {
|
||||
this.savePosition();
|
||||
}
|
||||
super.releaseDragging();
|
||||
}
|
||||
|
||||
private void loadPosition() {
|
||||
if (this.persistentPosition && this.name != null) {
|
||||
// final CoordD2 existingPosition = (CoordD2) EngineFacade.instance().getPersistentClientState().state.get(this.getPersistentStateKeyName());
|
||||
// if (existingPosition != null) {
|
||||
// LOGGER.debug(() -> "Position loaded: " + this.name + " " + existingPosition);
|
||||
// this.relativeScreenPosition = MutableCoordD2.create(existingPosition);
|
||||
// this.applyRelativeScreenPosition();
|
||||
// }
|
||||
/*else*/ if (this.areaFunction != null) {
|
||||
final var area = this.areaFunction.apply(this.state);
|
||||
this.setPosition(area.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void savePosition() {
|
||||
if (!this.persistentPosition) {
|
||||
}
|
||||
|
||||
// final CoordD2 existingPosition = (CoordD2) EngineFacade.instance().getPersistentClientState().state.get(this.getPersistentStateKeyName());
|
||||
// if (existingPosition == null || !this.relativeScreenPosition.equals(existingPosition)) {
|
||||
// EngineFacade.instance().getPersistentClientState().state.put(this.getPersistentStateKeyName(), MutableCoordD2.create(this.relativeScreenPosition));
|
||||
// EngineFacade.instance().storePersistentClientState();
|
||||
// LOGGER.debug(() -> "Position stored: " + this.name + " " + this.getPosition());
|
||||
// }
|
||||
}
|
||||
|
||||
// private String getPersistentStateKeyName() {
|
||||
// return PERSISTENT_STATE_PREFIX.concat(this.name);
|
||||
// }
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
package de.extio.game_engine.renderer.container.legacy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererControl;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.WindowCloseButtonControl;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.renderer.model.bo.DrawWindowRenderingBo;
|
||||
import de.extio.game_engine.spatial2.SpatialUtils2;
|
||||
import de.extio.game_engine.spatial2.model.Area2;
|
||||
import de.extio.game_engine.spatial2.model.CoordD2;
|
||||
import de.extio.game_engine.spatial2.model.CoordI2;
|
||||
import de.extio.game_engine.spatial2.model.HasPositionAndDimension2;
|
||||
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
|
||||
import de.extio.game_engine.spatial2.model.MutableCoordD2;
|
||||
import de.extio.game_engine.spatial2.model.MutableCoordI2;
|
||||
|
||||
/**
|
||||
* Helper to position, draw and manage virtual windows in the UI.
|
||||
*/
|
||||
public class Window implements HasPositionAndDimension2, AutoCloseable {
|
||||
|
||||
protected final static Logger LOGGER = LoggerFactory.getLogger(Window.class);
|
||||
|
||||
protected final static List<Window> WINDOWS = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
protected CoordD2 relativeScreenPosition = MutableCoordD2.create();
|
||||
|
||||
protected final String name;
|
||||
|
||||
private final RenderingBoPool renderingBoPool;
|
||||
|
||||
private final RendererControl rendererControl;
|
||||
|
||||
private Area2 area;
|
||||
|
||||
private CoordI2 dragCoordPrev;
|
||||
|
||||
private boolean dragging;
|
||||
|
||||
private boolean draggable;
|
||||
|
||||
private boolean drawCloseButton;
|
||||
|
||||
private short renderingBoLayer;
|
||||
|
||||
private CoordI2 lastEffectiveViewportDimension;
|
||||
|
||||
private RgbaColor color;
|
||||
|
||||
private long lastFrameDisplayed;
|
||||
|
||||
public Window(final String name, final boolean draggable, final RenderingBoPool renderingBoPool, final RendererControl rendererControl) {
|
||||
this.name = name;
|
||||
this.draggable = draggable;
|
||||
this.renderingBoPool = renderingBoPool;
|
||||
this.rendererControl = rendererControl;
|
||||
|
||||
WINDOWS.add(this);
|
||||
this.reset();
|
||||
}
|
||||
|
||||
public static boolean intersectsAny(final HasPositionAndDimension2 area) {
|
||||
// final long frame = EngineFacade.instance().getFrame();
|
||||
// synchronized (WINDOWS) {
|
||||
// for (final Window window : WINDOWS) {
|
||||
// if (window.lastFrameDisplayed >= frame - 1 && WorldUtils.intersects(window, area)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
synchronized (WINDOWS) {
|
||||
for (final Window window : WINDOWS) {
|
||||
if (SpatialUtils2.intersects(window, area)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.area = new Area2();
|
||||
this.area.setPosition(MutableCoordI2.create());
|
||||
this.area.setDimension(MutableCoordI2.create());
|
||||
this.releaseDragging();
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
public void releaseDragging() {
|
||||
this.dragCoordPrev = null;
|
||||
this.dragging = false;
|
||||
}
|
||||
|
||||
public boolean drag(final CoordI2 coord) {
|
||||
if (!this.draggable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.dragCoordPrev != null) {
|
||||
if (!this.dragging && this.intersects(coord)) {
|
||||
synchronized (WINDOWS) {
|
||||
for (final Window window : WINDOWS) {
|
||||
if (window.isDragging()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.dragging = true;
|
||||
}
|
||||
if (this.dragging) {
|
||||
this.move(MutableCoordI2.create(coord).substract(this.dragCoordPrev));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.dragCoordPrev = coord;
|
||||
}
|
||||
|
||||
return this.intersects(coord);
|
||||
}
|
||||
|
||||
public void move(final CoordI2 delta) {
|
||||
this.area.getPosition().add(delta);
|
||||
this.ensureBounds();
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
public void updateArea() {
|
||||
this.applyRelativeScreenPosition();
|
||||
this.ensureBounds();
|
||||
}
|
||||
|
||||
public void resizeCentered(final CoordI2 dimension) {
|
||||
if (ImmutableCoordI2.zero().equals(this.area.getDimension())) {
|
||||
this.area.getDimension().setXY(dimension);
|
||||
this.updateRelativeScreenPosition();
|
||||
return;
|
||||
}
|
||||
|
||||
final CoordI2 delta = MutableCoordI2.create(this.area.getDimension()).substract(dimension);
|
||||
if (ImmutableCoordI2.zero().equals(delta)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.area.getDimension().setXY(dimension);
|
||||
this.move(MutableCoordI2.create(delta.getX() / 2, delta.getY() / 2));
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
public boolean intersects(final CoordI2 coord) {
|
||||
return SpatialUtils2.intersects(this.area.getPosition(), this.area.getDimension(), coord, ImmutableCoordI2.one());
|
||||
}
|
||||
|
||||
public void render(final List<RenderingBo> renderingBo, final BiConsumer<List<RenderingBo>, RenderingBo> consumer) {
|
||||
final var currentEffectiveViewportDimension = this.rendererControl.getEffectiveViewportDimension();
|
||||
if (!currentEffectiveViewportDimension.equals(this.lastEffectiveViewportDimension)) {
|
||||
this.lastEffectiveViewportDimension = currentEffectiveViewportDimension;
|
||||
this.updateArea();
|
||||
}
|
||||
|
||||
var bo = this.renderingBoPool.acquire(this.name + "_Window", DrawWindowRenderingBo.class)
|
||||
.setThickBorder(this.draggable)
|
||||
.withDimensionAbsolute(this.area.getDimension())
|
||||
.withPositionAbsoluteAnchorTopLeft(this.area.getPosition())
|
||||
.setColor(this.color != null ? this.color : null);
|
||||
if (this.renderingBoLayer > 0) {
|
||||
bo.setLayer(this.renderingBoLayer);
|
||||
}
|
||||
consumer.accept(renderingBo, bo);
|
||||
|
||||
if (this.drawCloseButton) {
|
||||
bo = this.renderingBoPool.acquire(this.name + "_Close", ControlRenderingBo.class)
|
||||
.setType(WindowCloseButtonControl.class)
|
||||
.setCustomData(this.draggable)
|
||||
.setEnabled(true)
|
||||
.setVisible(true)
|
||||
.withDimensionAbsolute(this.area.getDimension())
|
||||
.withPositionAbsoluteAnchorTopLeft(this.area.getPosition())
|
||||
.setColor(this.color != null ? this.color : null);
|
||||
if (this.renderingBoLayer > 0) {
|
||||
bo.setLayer((short) Math.min(this.renderingBoLayer + 20, RenderingBoLayer.TOP));
|
||||
}
|
||||
else {
|
||||
bo.setLayer(RenderingBoLayer.UI1);
|
||||
}
|
||||
consumer.accept(renderingBo, bo);
|
||||
}
|
||||
|
||||
this.lastFrameDisplayed = this.rendererControl.getFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.releaseDragging();
|
||||
WINDOWS.remove(this);
|
||||
}
|
||||
|
||||
protected void ensureBounds() {
|
||||
final var effectiveDim = this.rendererControl.getEffectiveViewportDimension();
|
||||
var updated = false;
|
||||
|
||||
if (this.area.getPosition().getX() < 0) {
|
||||
this.area.getPosition().setX(0);
|
||||
updated = true;
|
||||
}
|
||||
if (this.area.getPosition().getY() < 0) {
|
||||
this.area.getPosition().setY(0);
|
||||
updated = true;
|
||||
}
|
||||
if (this.area.getDimension().getX() > effectiveDim.getX()) {
|
||||
this.area.getDimension().setX(effectiveDim.getX());
|
||||
updated = true;
|
||||
}
|
||||
if (this.area.getDimension().getY() > effectiveDim.getY()) {
|
||||
this.area.getDimension().setY(effectiveDim.getY());
|
||||
updated = true;
|
||||
}
|
||||
if (this.area.getPosition().getX() + this.area.getDimension().getX() > effectiveDim.getX()) {
|
||||
this.area.getPosition().setX(effectiveDim.getX() - this.area.getDimension().getX());
|
||||
updated = true;
|
||||
}
|
||||
if (this.area.getPosition().getY() + this.area.getDimension().getY() > effectiveDim.getY()) {
|
||||
this.area.getPosition().setY(effectiveDim.getY() - this.area.getDimension().getY());
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateRelativeScreenPosition() {
|
||||
final var currentEffectiveViewportDimension = this.rendererControl.getEffectiveViewportDimension();
|
||||
this.relativeScreenPosition.setX((double) this.area.getPosition().getX() / (double) currentEffectiveViewportDimension.getX());
|
||||
this.relativeScreenPosition.setY((double) this.area.getPosition().getY() / (double) currentEffectiveViewportDimension.getY());
|
||||
}
|
||||
|
||||
protected void applyRelativeScreenPosition() {
|
||||
final var currentEffectiveViewportDimension = this.rendererControl.getEffectiveViewportDimension();
|
||||
this.area.getPosition().setX((int) (this.relativeScreenPosition.getX() * (double) currentEffectiveViewportDimension.getX()));
|
||||
this.area.getPosition().setY((int) (this.relativeScreenPosition.getY() * (double) currentEffectiveViewportDimension.getY()));
|
||||
this.ensureBounds();
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return this.area.getPosition().getX();
|
||||
}
|
||||
|
||||
public void setX(final int x) {
|
||||
this.area.getPosition().setX(x);
|
||||
this.ensureBounds();
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return this.area.getPosition().getY();
|
||||
}
|
||||
|
||||
public void setY(final int y) {
|
||||
this.area.getPosition().setY(y);
|
||||
this.ensureBounds();
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return this.area.getDimension().getX();
|
||||
}
|
||||
|
||||
public void setWidth(final int width) {
|
||||
this.area.getDimension().setX(width);
|
||||
this.ensureBounds();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return this.area.getDimension().getY();
|
||||
}
|
||||
|
||||
public void setHeight(final int height) {
|
||||
this.area.getDimension().setY(height);
|
||||
this.ensureBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoordI2 getPosition() {
|
||||
return this.area.getPosition();
|
||||
}
|
||||
|
||||
public void setPosition(final CoordI2 position) {
|
||||
this.area.getPosition().setXY(position);
|
||||
this.ensureBounds();
|
||||
this.updateRelativeScreenPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CoordI2 getDimension() {
|
||||
return ImmutableCoordI2.create(this.area.getDimension());
|
||||
}
|
||||
|
||||
public void setDimension(final CoordI2 dimension) {
|
||||
this.area.getDimension().setXY(dimension);
|
||||
this.ensureBounds();
|
||||
}
|
||||
|
||||
public Area2 getArea() {
|
||||
return new Area2(ImmutableCoordI2.create(this.area.getPosition()), ImmutableCoordI2.create(this.area.getDimension()));
|
||||
}
|
||||
|
||||
public boolean isDragging() {
|
||||
return this.dragging;
|
||||
}
|
||||
|
||||
public boolean isDraggable() {
|
||||
return this.draggable;
|
||||
}
|
||||
|
||||
public void setDraggable(final boolean draggable) {
|
||||
this.draggable = draggable;
|
||||
}
|
||||
|
||||
public short getRenderingBoLayer() {
|
||||
return this.renderingBoLayer;
|
||||
}
|
||||
|
||||
public void setRenderingBoLayer(final short renderingBoLayer) {
|
||||
this.renderingBoLayer = renderingBoLayer;
|
||||
}
|
||||
|
||||
public RgbaColor getColor() {
|
||||
return this.color;
|
||||
}
|
||||
|
||||
public void setColor(final RgbaColor color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public boolean isDrawCloseButton() {
|
||||
return this.drawCloseButton;
|
||||
}
|
||||
|
||||
public void setDrawCloseButton(final boolean drawCloseButton) {
|
||||
this.drawCloseButton = drawCloseButton;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,62 @@
|
||||
package de.extio.game_engine.renderer.g2d;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
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.SpacecraftThemeFactoryBean;
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
import de.extio.game_engine.renderer.g2d.theme.VintageThemeFactoryBean;
|
||||
import de.extio.game_engine.resource.StaticResourceService;
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnProperty(name = "game-engine.renderer.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnProperty(name = "game-engine.renderer.strategy", havingValue = "g2d", matchIfMissing = true)
|
||||
public class G2DAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public G2DRenderer g2dRenderer(@Value("${game-engine.renderer.title:}") final String title) {
|
||||
G2DRenderer g2dRenderer(
|
||||
@Value("${game-engine.renderer.title:}") final String title,
|
||||
final G2DThemeManager themeManager,
|
||||
final StaticResourceService staticResourceService) {
|
||||
final var renderer = new G2DRenderer();
|
||||
renderer.setTitle(title);
|
||||
renderer.setThemeManager(themeManager);
|
||||
renderer.setStaticResourceService(staticResourceService);
|
||||
themeManager.setG2dRenderer(renderer);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public G2DRendererControl g2dRendererControl(final G2DRenderer renderer) {
|
||||
G2DRendererControl g2dRendererControl(final G2DRenderer renderer) {
|
||||
return new G2DRendererControl(renderer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
FactoryBean<Theme> spacecraftTheme() {
|
||||
return new SpacecraftThemeFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FactoryBean<Theme> vintageTheme() {
|
||||
return new VintageThemeFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
G2DThemeManager g2dThemeManager(
|
||||
final StaticResourceService staticResourceService,
|
||||
final List<PatternRenderer> patternRendererList,
|
||||
final Map<String, Theme> themes,
|
||||
@Qualifier("spacecraftTheme") final Theme defaultTheme) {
|
||||
return new G2DThemeManager(staticResourceService, patternRendererList, themes, defaultTheme);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,12 +30,14 @@ import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFpsHistory;
|
||||
import de.extio.game_engine.renderer.g2d.control.G2DDrawControl;
|
||||
import de.extio.game_engine.renderer.g2d.control.G2DDrawControlTooltip;
|
||||
import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.DrawFontRenderingBo;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.renderer.model.event.TakeScreenshotEvent;
|
||||
import de.extio.game_engine.resource.StaticResource;
|
||||
import de.extio.game_engine.resource.StaticResourceService;
|
||||
import de.extio.game_engine.util.RingBuffer;
|
||||
|
||||
public class G2DRenderer implements Renderer {
|
||||
@@ -78,6 +80,10 @@ public class G2DRenderer implements Renderer {
|
||||
|
||||
private StaticResource previousDefaultFont = null;
|
||||
|
||||
private G2DThemeManager themeManager;
|
||||
|
||||
private StaticResourceService staticResourceService;
|
||||
|
||||
public G2DRenderer() {
|
||||
LOGGER.info("ctor");
|
||||
|
||||
@@ -367,6 +373,22 @@ public class G2DRenderer implements Renderer {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
public G2DThemeManager getThemeManager() {
|
||||
return this.themeManager;
|
||||
}
|
||||
|
||||
public void setThemeManager(final G2DThemeManager themeManager) {
|
||||
this.themeManager = themeManager;
|
||||
}
|
||||
|
||||
public StaticResourceService getStaticResourceService() {
|
||||
return this.staticResourceService;
|
||||
}
|
||||
|
||||
public void setStaticResourceService(final StaticResourceService staticResourceService) {
|
||||
this.staticResourceService = staticResourceService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRendererData(final RendererData rendererData) {
|
||||
this.rendererData = rendererData;
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.G2DRendererCondition;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.ComponentRenderingSupport;
|
||||
import de.extio.game_engine.renderer.g2d.theme.PatternRenderer;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.DrawEffectRenderingBo;
|
||||
@@ -216,12 +216,20 @@ public class G2DDrawEffect extends G2DAbstractRenderingBo implements DrawEffectR
|
||||
}
|
||||
|
||||
final var strength = this.customInt0 <= 0 ? 2 : this.customInt0;
|
||||
final var effectColor = this.color == null ? Color.WHITE : this.color.toAwtColor();
|
||||
|
||||
if (this.effect == DrawEffectRenderingBoEffects.DECORATIVE_BORDER) {
|
||||
ComponentRenderingSupport.drawDecorativeBorder(graphics, area.getPosition().getX(), area.getPosition().getY(), area.getDimension().getX(), area.getDimension().getY(), strength, this.color == null ? Color.WHITE : this.color.toAwtColor());
|
||||
}
|
||||
else {
|
||||
ComponentRenderingSupport.drawDecorativeBorderFilled(graphics, area.getPosition().getX(), area.getPosition().getY(), area.getDimension().getX(), area.getDimension().getY(), strength, this.color == null ? Color.WHITE : this.color.toAwtColor());
|
||||
// Use PatternRenderer from ThemeManager
|
||||
final var renderer = this.rendererData.getRenderer();
|
||||
final G2DRenderer g2dRenderer = (G2DRenderer) renderer;
|
||||
final var themeManager = g2dRenderer.getThemeManager();
|
||||
final var theme = themeManager.getCurrentTheme();
|
||||
final PatternRenderer patternRenderer = themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
if (patternRenderer != null) {
|
||||
if (this.effect == DrawEffectRenderingBoEffects.DECORATIVE_BORDER) {
|
||||
patternRenderer.drawDecorativeBorder(graphics, area.getPosition().getX(), area.getPosition().getY(), area.getDimension().getX(), area.getDimension().getY(), strength, effectColor);
|
||||
} else {
|
||||
patternRenderer.drawDecorativeBorderFilled(graphics, area.getPosition().getX(), area.getPosition().getY(), area.getDimension().getX(), area.getDimension().getY(), strength, effectColor, effectColor);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package de.extio.game_engine.renderer.g2d.bo.rendering;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
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.control.components.ComponentRenderingSupport;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.DrawWindowRenderingBo;
|
||||
import de.extio.game_engine.renderer.model.color.ImmutableRgbaColor;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
|
||||
@Conditional(G2DRendererCondition.class)
|
||||
@Component
|
||||
public class G2DDrawWindow extends G2DAbstractRenderingBo implements DrawWindowRenderingBo {
|
||||
|
||||
private static final RgbaColor COLOR_WINDOW = new ImmutableRgbaColor(ComponentRenderingSupport.COLOR_COMPONENT_BORDER1.getRed(), ComponentRenderingSupport.COLOR_COMPONENT_BORDER1.getGreen(), ComponentRenderingSupport.COLOR_COMPONENT_BORDER1.getBlue());
|
||||
|
||||
private boolean thickBorder;
|
||||
|
||||
public G2DDrawWindow() {
|
||||
super(RenderingBoLayer.UI_BGR);
|
||||
|
||||
this.color = COLOR_WINDOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawWindowRenderingBo setThickBorder(final boolean thickBorder) {
|
||||
this.thickBorder = thickBorder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(final Graphics2D graphics, final double scaleFactor, final boolean force) {
|
||||
final var sx = (int) (this.x * scaleFactor);
|
||||
final var sy = (int) (this.y * scaleFactor);
|
||||
final var sw = (int) (this.width * scaleFactor);
|
||||
final var sh = (int) (this.height * scaleFactor);
|
||||
final var strength = Math.max(2, (int) (3 * scaleFactor));
|
||||
if (this.color == null) {
|
||||
this.color = COLOR_WINDOW;
|
||||
}
|
||||
|
||||
final var cMain = this.color.toAwtColor();
|
||||
final var rgbaDarker = this.color.toMutable();
|
||||
rgbaDarker.setR(rgbaDarker.getR() / 2);
|
||||
rgbaDarker.setG(rgbaDarker.getG() / 2);
|
||||
rgbaDarker.setB(rgbaDarker.getB() / 2);
|
||||
final var cDarker = rgbaDarker.toAwtColor();
|
||||
|
||||
if (this.thickBorder) {
|
||||
final var borderStrength = strength * 2;
|
||||
graphics.setColor(cMain);
|
||||
graphics.fillRect(sx + strength * 2, sy + strength * 2, sw - strength * 4, borderStrength);
|
||||
graphics.setColor(cDarker);
|
||||
graphics.fillRect(sx + strength * 2, sy + strength * 2 + borderStrength, sw - strength * 4, strength);
|
||||
}
|
||||
|
||||
ComponentRenderingSupport.drawDecorativeBorder(graphics, sx, sy, sw, sh, strength, cDarker);
|
||||
ComponentRenderingSupport.drawDecorativeBorderFilled(graphics, sx + strength, sy + strength, sw - strength * 2, sh - strength * 2, strength, cMain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(final RenderingBo other) {
|
||||
super.apply(other);
|
||||
|
||||
if (other instanceof final G2DDrawWindow o) {
|
||||
this.thickBorder = o.thickBorder;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
this.color = COLOR_WINDOW;
|
||||
this.thickBorder = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
package de.extio.game_engine.renderer.g2d.bo.rendering;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.G2DRendererCondition;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.DrawWindowRenderingBo;
|
||||
import de.extio.game_engine.renderer.model.color.ImmutableRgbaColor;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
|
||||
// TODO: Unused for now, merge window implementations when implementing theme management
|
||||
@Conditional(G2DRendererCondition.class)
|
||||
// @Component
|
||||
public class G2DDrawWindow2 extends G2DAbstractRenderingBo implements DrawWindowRenderingBo {
|
||||
|
||||
private static final Map<Long, G2DWindowCacheEntry> CACHE = new HashMap<>();
|
||||
|
||||
private static final RgbaColor COLOR_WINDOW_BGR = new ImmutableRgbaColor(119, 119, 189);
|
||||
|
||||
private static double LAST_SCALEFACTOR;
|
||||
|
||||
private static AlphaComposite alphaComposite;
|
||||
|
||||
private boolean thickBorder;
|
||||
|
||||
private Color awtColor;
|
||||
|
||||
public G2DDrawWindow2() {
|
||||
super(RenderingBoLayer.UI_BGR);
|
||||
|
||||
this.color = COLOR_WINDOW_BGR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DrawWindowRenderingBo setThickBorder(final boolean thickBorder) {
|
||||
this.thickBorder = thickBorder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(final Graphics2D graphics, final double scaleFactor, final boolean force) {
|
||||
this.awtColor = this.color == null ? COLOR_WINDOW_BGR.toAwtColor() : this.color.toAwtColor();
|
||||
|
||||
if (scaleFactor != LAST_SCALEFACTOR) {
|
||||
CACHE.clear();
|
||||
LAST_SCALEFACTOR = scaleFactor;
|
||||
}
|
||||
|
||||
final var key = Long.valueOf((long) this.width | ((long) this.height << 12) | ((this.thickBorder ? 1L : 0L) << 24) | ((long) this.awtColor.getRGB() << 32));
|
||||
var entry = CACHE.get(key);
|
||||
if (entry == null) {
|
||||
final var img = ((G2DRenderer) this.rendererData.getRenderer()).getMainFrame().getGraphicsConfiguration().createCompatibleImage((int) (this.width * scaleFactor), (int) (this.height * scaleFactor), Transparency.TRANSLUCENT);
|
||||
this.paintWindow(img, scaleFactor);
|
||||
|
||||
entry = new G2DWindowCacheEntry();
|
||||
entry.setImage(img);
|
||||
CACHE.put(key, entry);
|
||||
|
||||
}
|
||||
entry.setUsed(true);
|
||||
|
||||
final var currentAlphaComposite = graphics.getComposite();
|
||||
try {
|
||||
if (alphaComposite == null) {
|
||||
alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6F);
|
||||
}
|
||||
|
||||
graphics.setComposite(alphaComposite);
|
||||
graphics.drawImage(entry.getImage(), (int) (this.x * scaleFactor), (int) (this.y * scaleFactor), null);
|
||||
}
|
||||
finally {
|
||||
graphics.setComposite(currentAlphaComposite);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(final RenderingBo other) {
|
||||
super.apply(other);
|
||||
|
||||
if (other instanceof final G2DDrawWindow2 o) {
|
||||
this.color = o.color;
|
||||
this.thickBorder = o.thickBorder;
|
||||
this.awtColor = o.awtColor;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
this.color = COLOR_WINDOW_BGR;
|
||||
this.thickBorder = false;
|
||||
this.awtColor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void staticCleanupAfterFrame() {
|
||||
final var it = CACHE.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
final var entry = it.next();
|
||||
if (!entry.isUsed()) {
|
||||
entry.close();
|
||||
it.remove();
|
||||
}
|
||||
else {
|
||||
entry.setUsed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void paintWindow(final BufferedImage img, final double scaleFactor) {
|
||||
final var imgGraphics = img.createGraphics();
|
||||
try {
|
||||
final var swidth = (int) (this.width * scaleFactor);
|
||||
final var sheight = (int) (this.height * scaleFactor);
|
||||
final var baseColor = new float[3];
|
||||
this.awtColor.getRGBColorComponents(baseColor);
|
||||
Color.RGBtoHSB((int) (baseColor[0] * 255), (int) (baseColor[1] * 255), (int) (baseColor[2] * 255), baseColor);
|
||||
|
||||
final var size = (int) (5 * scaleFactor);
|
||||
|
||||
imgGraphics.setColor(Color.BLACK);
|
||||
imgGraphics.fillRect(0, size, swidth, sheight - size * 3);
|
||||
imgGraphics.fillRect(size, sheight - size * 2, swidth - size * 2, size);
|
||||
|
||||
imgGraphics.setColor(Color.getHSBColor(baseColor[0], baseColor[1], baseColor[2]));
|
||||
if (this.thickBorder) {
|
||||
imgGraphics.fillRect(0, size * 2, size, sheight - size * 4);
|
||||
imgGraphics.fillRect(swidth - size, size * 2, swidth, sheight - size * 4);
|
||||
imgGraphics.fillRect(0, size * 2, swidth, size);
|
||||
}
|
||||
else {
|
||||
imgGraphics.fillRect(0, 0, size, sheight - size * 2);
|
||||
imgGraphics.fillRect(swidth - size, 0, swidth, sheight - size * 2);
|
||||
imgGraphics.fillRect(0, 0, swidth, size);
|
||||
}
|
||||
imgGraphics.fillRect(size * 2, sheight - size, swidth - size * 4, size);
|
||||
imgGraphics.fillPolygon(new int[] { 0, size * 2, size * 2, size }, new int[] { sheight - size * 2, sheight, sheight - size, sheight - size * 2 }, 4);
|
||||
imgGraphics.fillPolygon(new int[] { swidth, swidth - size * 2, swidth - size * 2, swidth - size }, new int[] { sheight - size * 2, sheight, sheight - size, sheight - size * 2 }, 4);
|
||||
|
||||
if (this.thickBorder) {
|
||||
for (var i = 0; i < size * 2; i++) {
|
||||
imgGraphics.setColor(Color.getHSBColor(baseColor[0], baseColor[1], baseColor[2] * ((0.5F / (size * 2) * i) + 0.5F)));
|
||||
imgGraphics.drawLine(0, i, swidth, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
imgGraphics.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static class G2DWindowCacheEntry implements AutoCloseable {
|
||||
|
||||
private BufferedImage image;
|
||||
|
||||
private boolean used;
|
||||
|
||||
public BufferedImage getImage() {
|
||||
return this.image;
|
||||
}
|
||||
|
||||
public void setImage(final BufferedImage image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public boolean isUsed() {
|
||||
return this.used;
|
||||
}
|
||||
|
||||
public void setUsed(final boolean used) {
|
||||
this.used = used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.image != null) {
|
||||
this.image.flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package de.extio.game_engine.renderer.g2d.control.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
public class ComponentRenderingSupport {
|
||||
|
||||
public final static record HSB(float h, float s, float b) {
|
||||
}
|
||||
|
||||
public final static HSB HSB_COMPONENT_BORDER0 = new HSB(0.71f, 0.12f, 0.50f);
|
||||
|
||||
public final static Color COLOR_COMPONENT_BORDER0 = Color.getHSBColor(HSB_COMPONENT_BORDER0.h(), HSB_COMPONENT_BORDER0.s(), HSB_COMPONENT_BORDER0.b());
|
||||
|
||||
public final static HSB HSB_COMPONENT_BORDER1 = new HSB(0.71f, 0.12f, 0.80f);
|
||||
|
||||
public final static Color COLOR_COMPONENT_BORDER1 = Color.getHSBColor(HSB_COMPONENT_BORDER1.h(), HSB_COMPONENT_BORDER1.s(), HSB_COMPONENT_BORDER1.b());
|
||||
|
||||
public final static HSB HSB_COMPONENT_BORDER1_DIS = new HSB(0.71f, 0.15f, 0.20f);
|
||||
|
||||
public final static Color COLOR_COMPONENT_BORDER1_DIS = Color.getHSBColor(HSB_COMPONENT_BORDER1_DIS.h(), HSB_COMPONENT_BORDER1_DIS.s(), HSB_COMPONENT_BORDER1_DIS.b());
|
||||
|
||||
public final static HSB HSB_COMPONENT_BGR = new HSB(0.71f, 0.92f, 0.30f);
|
||||
|
||||
public final static Color COLOR_COMPONENT_BGR = Color.getHSBColor(HSB_COMPONENT_BGR.h(), HSB_COMPONENT_BGR.s(), HSB_COMPONENT_BGR.b());
|
||||
|
||||
public final static HSB HSB_COMPONENT_SELECTED_0 = new HSB(0.199f, 0.83f, 0.50f);
|
||||
|
||||
public final static Color COLOR_COMPONENT_SELECTED_0 = Color.getHSBColor(HSB_COMPONENT_SELECTED_0.h(), HSB_COMPONENT_SELECTED_0.s(), HSB_COMPONENT_SELECTED_0.b());
|
||||
|
||||
public final static HSB HSB_COMPONENT_SELECTED_1 = new HSB(0.199f, 0.83f, 0.90f);
|
||||
|
||||
public final static Color COLOR_COMPONENT_SELECTED_1 = Color.getHSBColor(HSB_COMPONENT_SELECTED_1.h(), HSB_COMPONENT_SELECTED_1.s(), HSB_COMPONENT_SELECTED_1.b());
|
||||
|
||||
public final static Color COLOR_WINDOW_BGR = new Color(0, 0, 0, 180);
|
||||
|
||||
public static void drawDecorativeBorder(final Graphics2D g2d, final int x, final int y, final int w, final int h, final int strength, final Color color) {
|
||||
final var strength2 = strength * 2;
|
||||
final var strength4 = strength * 4;
|
||||
|
||||
g2d.setColor(color);
|
||||
|
||||
g2d.fillRect(x, y + strength2, strength, h - strength4);
|
||||
g2d.fillRect(x + w - strength, y + strength2, strength, h - strength4);
|
||||
g2d.fillRect(x + strength2, y, w - strength4, strength);
|
||||
g2d.fillRect(x + strength2, y + h - strength, w - strength4, strength);
|
||||
|
||||
g2d.fillRect(x + strength, y + strength, strength2, strength2);
|
||||
g2d.fillRect(x + w - strength - strength2, y + strength, strength2, strength2);
|
||||
g2d.fillRect(x + strength, y + h - strength - strength2, strength2, strength2);
|
||||
g2d.fillRect(x + w - strength - strength2, y + h - strength - strength2, strength2, strength2);
|
||||
}
|
||||
|
||||
public static void drawDecorativeBorderFilled(final Graphics2D g2d, final int x, final int y, final int w, final int h, final int strength, final Color color) {
|
||||
g2d.setColor(ComponentRenderingSupport.COLOR_WINDOW_BGR);
|
||||
g2d.fillRect(x + strength * 2, y + strength * 2, w - strength * 4, h - strength * 4);
|
||||
|
||||
drawDecorativeBorder(g2d, x, y, w, h, strength, color);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,17 +6,27 @@ import java.awt.Graphics2D;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class CustomButton extends CustomAbstractButton {
|
||||
|
||||
public CustomButton(final boolean toggle, final ActionListener listener) {
|
||||
private final G2DThemeManager themeManager;
|
||||
|
||||
public CustomButton(final boolean toggle, final ActionListener listener, final G2DThemeManager themeManager) {
|
||||
super(toggle, listener);
|
||||
this.themeManager = themeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
if (this.themeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var g2d = (Graphics2D) g;
|
||||
final Theme theme = this.themeManager.getCurrentTheme();
|
||||
|
||||
float h, s, b;
|
||||
|
||||
@@ -24,24 +34,21 @@ public class CustomButton extends CustomAbstractButton {
|
||||
final var bgrStrength = (this.getWidth() < 48 || this.getHeight() < 48) ? 0 : 2;
|
||||
|
||||
if (this.backgroundColor == null) {
|
||||
if ((this.state & STATE_TOGGLED) == 0) {
|
||||
h = ComponentRenderingSupport.HSB_COMPONENT_BGR.h();
|
||||
s = ComponentRenderingSupport.HSB_COMPONENT_BGR.s();
|
||||
b = ComponentRenderingSupport.HSB_COMPONENT_BGR.b();
|
||||
}
|
||||
else {
|
||||
h = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.b();
|
||||
s = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.s();
|
||||
b = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.b();
|
||||
}
|
||||
// Use theme colors
|
||||
final var baseColor = (this.state & STATE_TOGGLED) == 0 ? theme.getBackgroundNormal() : theme.getBackgroundSelected();
|
||||
h = baseColor.getHue();
|
||||
s = baseColor.getSaturation();
|
||||
b = baseColor.getBrightness();
|
||||
|
||||
if ((this.state & STATE_PRESSED) != 0) {
|
||||
b += 0.40F;
|
||||
b += theme.getPressedBrightnessAdjustment();
|
||||
}
|
||||
else if ((this.state & STATE_HOVERED) != 0) {
|
||||
b += 0.25F;
|
||||
b += theme.getHoverBrightnessAdjustment();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use custom background color
|
||||
final var hsb = new float[3];
|
||||
Color.RGBtoHSB(this.backgroundColor.getRed(), this.backgroundColor.getGreen(), this.backgroundColor.getBlue(), hsb);
|
||||
h = hsb[0];
|
||||
@@ -54,12 +61,14 @@ public class CustomButton extends CustomAbstractButton {
|
||||
b = 0.50F;
|
||||
}
|
||||
if ((this.state & STATE_PRESSED) != 0) {
|
||||
b += 0.40F;
|
||||
b += theme.getPressedBrightnessAdjustment();
|
||||
}
|
||||
else if ((this.state & STATE_HOVERED) != 0) {
|
||||
b += 0.25F;
|
||||
b += theme.getHoverBrightnessAdjustment();
|
||||
}
|
||||
}
|
||||
|
||||
b = Math.max(0.0f, Math.min(1.0f, b));
|
||||
g2d.setColor(Color.getHSBColor(h, s, b));
|
||||
g2d.fillRect(2 + bgrStrength, 2 + bgrStrength, this.getWidth() - 5 - bgrStrength * 2, this.getHeight() - 5 - bgrStrength * 2);
|
||||
|
||||
@@ -70,14 +79,15 @@ public class CustomButton extends CustomAbstractButton {
|
||||
g2d.drawImage(this.icon, 4 + bgrStrength, 4 + bgrStrength, this.getWidth() - 4 - bgrStrength, this.getHeight() - 4 - bgrStrength, 0, 0, this.icon.getWidth(), this.icon.getHeight(), null);
|
||||
}
|
||||
else if (this.caption != null) {
|
||||
// Text color based on state
|
||||
if ((this.state & (STATE_HOVERED | STATE_TOGGLED)) != 0) {
|
||||
g2d.setColor(Color.WHITE);
|
||||
}
|
||||
else if (this.isEnabled()) {
|
||||
g2d.setColor(Color.LIGHT_GRAY);
|
||||
g2d.setColor(theme.getTextNormal().toColor());
|
||||
}
|
||||
else {
|
||||
g2d.setColor(Color.GRAY);
|
||||
g2d.setColor(theme.getTextDisabled().toColor());
|
||||
}
|
||||
final var textDim = G2DDrawFont.getTextDimensions(this.caption, g2d, this.fontSize, this.scaleFactor);
|
||||
G2DDrawFont.renderText(g2d,
|
||||
@@ -89,10 +99,17 @@ public class CustomButton extends CustomAbstractButton {
|
||||
this.caption);
|
||||
}
|
||||
|
||||
var color = (this.state & STATE_HOVERED) != 0 ? ComponentRenderingSupport.COLOR_COMPONENT_SELECTED_0 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER0;
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, 0, 0, this.getWidth() - 1, this.getHeight() - 1, borderStrength, color);
|
||||
color = this.isEnabled() ? (this.state & STATE_HOVERED) != 0 ? ComponentRenderingSupport.COLOR_COMPONENT_SELECTED_1 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER1 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER1_DIS;
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, borderStrength, borderStrength, this.getWidth() - 1 - 2 * borderStrength, this.getHeight() - 1 - 2 * borderStrength, borderStrength, color);
|
||||
// Draw borders using theme colors and pattern renderer
|
||||
var borderColor = (this.state & STATE_HOVERED) != 0 ? theme.getSelectionPrimary().toColor() : theme.getBorderOuter().toColor();
|
||||
final var patternRenderer = this.themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
if (patternRenderer != null) {
|
||||
patternRenderer.drawDecorativeBorder(g2d, 0, 0, this.getWidth() - 1, this.getHeight() - 1, borderStrength, borderColor);
|
||||
|
||||
borderColor = this.isEnabled() ?
|
||||
(this.state & STATE_HOVERED) != 0 ? theme.getSelectionSecondary().toColor() : theme.getBorderInner().toColor() :
|
||||
theme.getBorderInnerDisabled().toColor();
|
||||
patternRenderer.drawDecorativeBorder(g2d, borderStrength, borderStrength, this.getWidth() - 1 - 2 * borderStrength, this.getHeight() - 1 - 2 * borderStrength, borderStrength, borderColor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import de.extio.game_engine.renderer.ThemeManager;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
import de.extio.game_engine.renderer.model.bo.HorizontalAlignment;
|
||||
import de.extio.game_engine.spatial2.model.CoordI2;
|
||||
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
|
||||
@@ -44,6 +46,8 @@ public class CustomLabel extends Component {
|
||||
|
||||
private CoordI2 lastMousePosition;
|
||||
|
||||
private final ThemeManager themeManager;
|
||||
|
||||
public void setCaption(final String caption) {
|
||||
this.caption = caption;
|
||||
}
|
||||
@@ -92,7 +96,8 @@ public class CustomLabel extends Component {
|
||||
return this.lastMousePosition;
|
||||
}
|
||||
|
||||
public CustomLabel(final ActionListener listener) {
|
||||
public CustomLabel(final ActionListener listener, final ThemeManager themeManager) {
|
||||
this.themeManager = themeManager;
|
||||
this.setIgnoreRepaint(true);
|
||||
|
||||
this.addMouseListener(new MouseAdapter() {
|
||||
@@ -146,7 +151,12 @@ public class CustomLabel extends Component {
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
if (this.themeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var g2d = (Graphics2D) g;
|
||||
final Theme theme = this.themeManager.getCurrentTheme();
|
||||
|
||||
if (this.backgroundColor != null) {
|
||||
g2d.setColor(this.backgroundColor);
|
||||
@@ -155,9 +165,9 @@ public class CustomLabel extends Component {
|
||||
|
||||
float h, s, b;
|
||||
if (this.foregroundColor == null) {
|
||||
h = 0.0F;
|
||||
s = 0.0F;
|
||||
b = 0.80F;
|
||||
h = theme.getTextNormal().getHue();
|
||||
s = theme.getTextNormal().getSaturation();
|
||||
b = theme.getTextNormal().getBrightness();
|
||||
}
|
||||
else {
|
||||
final var hsb = Color.RGBtoHSB(this.foregroundColor.getRed(), this.foregroundColor.getGreen(), this.foregroundColor.getBlue(), null);
|
||||
@@ -167,15 +177,17 @@ public class CustomLabel extends Component {
|
||||
}
|
||||
|
||||
if (!this.enabled) {
|
||||
b -= 0.30F;
|
||||
h = theme.getTextDisabled().getHue();
|
||||
s = theme.getTextDisabled().getSaturation();
|
||||
b = theme.getTextDisabled().getBrightness();
|
||||
}
|
||||
else if ((this.state & STATE_PRESSED) != 0) {
|
||||
h = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.b();
|
||||
s = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.s();
|
||||
b = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.b() + 0.4f;
|
||||
h = theme.getSelectionPrimary().getHue();
|
||||
s = theme.getSelectionPrimary().getSaturation();
|
||||
b = theme.getSelectionPrimary().getBrightness() + theme.getPressedBrightnessAdjustment();
|
||||
}
|
||||
else if ((this.state & STATE_HOVERED) != 0) {
|
||||
b += 0.15F;
|
||||
b += theme.getHoverBrightnessAdjustment();
|
||||
}
|
||||
|
||||
h = Math.max(0.0f, Math.min(1.0f, h));
|
||||
|
||||
@@ -10,6 +10,8 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import de.extio.game_engine.renderer.ThemeManager;
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
import de.extio.game_engine.spatial2.model.CoordI2;
|
||||
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
|
||||
|
||||
@@ -44,6 +46,8 @@ public class CustomSlider extends Component {
|
||||
|
||||
private long lastActionEventReleased;
|
||||
|
||||
private final ThemeManager themeManager;
|
||||
|
||||
public void setScaleFactor(final double scaleFactor) {
|
||||
this.scaleFactor = scaleFactor;
|
||||
}
|
||||
@@ -92,9 +96,10 @@ public class CustomSlider extends Component {
|
||||
return this.lastMousePosition;
|
||||
}
|
||||
|
||||
public CustomSlider(final ActionListener listener) {
|
||||
public CustomSlider(final ActionListener listener, final ThemeManager themeManager) {
|
||||
this.setIgnoreRepaint(true);
|
||||
this.actionListener = listener;
|
||||
this.themeManager = themeManager;
|
||||
|
||||
this.addMouseListener(new MouseAdapter() {
|
||||
|
||||
@@ -168,79 +173,87 @@ public class CustomSlider extends Component {
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
if (this.themeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var g2d = (Graphics2D) g;
|
||||
final Theme theme = this.themeManager.getCurrentTheme();
|
||||
|
||||
float h, s, b;
|
||||
if (this.color == null) {
|
||||
h = 0.0F;
|
||||
s = 0.0F;
|
||||
b = 0.80F;
|
||||
if (!this.enabled) {
|
||||
h = theme.getTextDisabled().getHue();
|
||||
s = theme.getTextDisabled().getSaturation();
|
||||
b = theme.getTextDisabled().getBrightness();
|
||||
}
|
||||
else {
|
||||
h = theme.getTextNormal().getHue();
|
||||
s = theme.getTextNormal().getSaturation();
|
||||
b = theme.getTextNormal().getBrightness();
|
||||
}
|
||||
}
|
||||
else {
|
||||
final var hsb = Color.RGBtoHSB(this.color.getRed(), this.color.getGreen(), this.color.getBlue(), null);
|
||||
h = hsb[0];
|
||||
s = hsb[1];
|
||||
b = hsb[2];
|
||||
}
|
||||
if (!this.enabled) {
|
||||
b -= 0.30F;
|
||||
if (!this.enabled) {
|
||||
b -= 0.30F;
|
||||
}
|
||||
}
|
||||
|
||||
// Main line
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, 0, this.getHeight() / 2, this.getWidth(), this.getHeight() / 2, this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, this.getWidth() / 2, 0, this.getWidth() / 2, this.getHeight(), this.horizontal);
|
||||
}
|
||||
|
||||
// Small lines
|
||||
b -= 0.20F;
|
||||
final var length = this.horizontal ? this.getWidth() : this.getHeight();
|
||||
for (var i = 1; i < 10; i++) {
|
||||
final var pos = (int) ((double) length / 10.0 * i);
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, pos, this.getHeight() / 4, pos, this.getHeight() / 4 * 3, !this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, this.getWidth() / 4, pos, this.getWidth() / 4 * 3, pos, !this.horizontal);
|
||||
}
|
||||
}
|
||||
b += 0.20F;
|
||||
|
||||
// Pointer
|
||||
if ((this.state & STATE_HOVERED) != 0 && this.lastMousePosition != null) {
|
||||
try {
|
||||
// Small lines
|
||||
b -= 0.20F;
|
||||
final var length = this.horizontal ? this.getWidth() : this.getHeight();
|
||||
for (var i = 1; i < 10; i++) {
|
||||
final var pos = (int) ((double) length / 10.0 * i);
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, this.lastMousePosition.getX(), 0, this.lastMousePosition.getX(), this.getHeight(), !this.horizontal);
|
||||
this.drawLine(g2d, h, s, b, pos, this.getHeight() / 4, pos, this.getHeight() / 4 * 3, !this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, 0, this.lastMousePosition.getY(), this.getWidth(), this.lastMousePosition.getY(), !this.horizontal);
|
||||
this.drawLine(g2d, h, s, b, this.getWidth() / 4, pos, this.getWidth() / 4 * 3, pos, !this.horizontal);
|
||||
}
|
||||
}
|
||||
catch (final NullPointerException exc) {
|
||||
// AWT MouseAdapter can set this.lastMousePosition null at any time
|
||||
b += 0.20F;
|
||||
|
||||
// Pointer
|
||||
if ((this.state & STATE_HOVERED) != 0 && this.lastMousePosition != null) {
|
||||
try {
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, this.lastMousePosition.getX(), 0, this.lastMousePosition.getX(), this.getHeight(), !this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, 0, this.lastMousePosition.getY(), this.getWidth(), this.lastMousePosition.getY(), !this.horizontal);
|
||||
}
|
||||
}
|
||||
catch (final NullPointerException exc) {
|
||||
// AWT MouseAdapter can set this.lastMousePosition null at any time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Value2
|
||||
if (this.value2 != this.value) {
|
||||
|
||||
// Value2
|
||||
if (this.value2 != this.value) {
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, (int) (this.getWidth() * this.value2), 0, (int) (this.getWidth() * this.value2), this.getHeight(), !this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, 0, (int) (this.getHeight() * (1.0 - this.value2)), this.getWidth(), (int) (this.getHeight() * (1.0 - this.value2)), !this.horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
// Value
|
||||
b += 0.15F;
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, (int) (this.getWidth() * this.value2), 0, (int) (this.getWidth() * this.value2), this.getHeight(), !this.horizontal);
|
||||
this.drawLine(g2d, h, s, b, (int) (this.getWidth() * this.value), 0, (int) (this.getWidth() * this.value), this.getHeight(), !this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, 0, (int) (this.getHeight() * (1.0 - this.value2)), this.getWidth(), (int) (this.getHeight() * (1.0 - this.value2)), !this.horizontal);
|
||||
this.drawLine(g2d, h, s, b, 0, (int) (this.getHeight() * (1.0 - this.value)), this.getWidth(), (int) (this.getHeight() * (1.0 - this.value)), !this.horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
// Value
|
||||
b += 0.15F;
|
||||
if (this.horizontal) {
|
||||
this.drawLine(g2d, h, s, b, (int) (this.getWidth() * this.value), 0, (int) (this.getWidth() * this.value), this.getHeight(), !this.horizontal);
|
||||
}
|
||||
else {
|
||||
this.drawLine(g2d, h, s, b, 0, (int) (this.getHeight() * (1.0 - this.value)), this.getWidth(), (int) (this.getHeight() * (1.0 - this.value)), !this.horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyColor(final Graphics2D g2d, float h, float s, float b) {
|
||||
|
||||
@@ -6,77 +6,91 @@ import java.awt.Graphics2D;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class CustomSwitch extends CustomAbstractButton {
|
||||
|
||||
private boolean drawBorder;
|
||||
private final G2DThemeManager themeManager;
|
||||
|
||||
public CustomSwitch(final boolean toggle, final ActionListener listener) {
|
||||
public CustomSwitch(final boolean toggle, final ActionListener listener, final G2DThemeManager themeManager) {
|
||||
super(toggle, listener);
|
||||
this.themeManager = themeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
if (this.themeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var g2d = (Graphics2D) g;
|
||||
final Theme theme = this.themeManager.getCurrentTheme();
|
||||
|
||||
final var dimY = this.getHeight() - 1;
|
||||
final var dimX = (int) (dimY * 1.5);
|
||||
|
||||
float h, s, b;
|
||||
if ((this.state & STATE_TOGGLED) == 0) {
|
||||
h = ComponentRenderingSupport.HSB_COMPONENT_BGR.h();
|
||||
s = ComponentRenderingSupport.HSB_COMPONENT_BGR.s();
|
||||
b = ComponentRenderingSupport.HSB_COMPONENT_BGR.b();
|
||||
}
|
||||
else {
|
||||
h = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.b();
|
||||
s = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.s();
|
||||
b = ComponentRenderingSupport.HSB_COMPONENT_SELECTED_0.b();
|
||||
}
|
||||
final var baseColor = (this.state & STATE_TOGGLED) == 0 ? theme.getBackgroundNormal() : theme.getBackgroundSelected();
|
||||
h = baseColor.getHue();
|
||||
s = baseColor.getSaturation();
|
||||
b = baseColor.getBrightness();
|
||||
|
||||
if ((this.state & STATE_PRESSED) != 0) {
|
||||
b += 0.40F;
|
||||
b += theme.getPressedBrightnessAdjustment();
|
||||
}
|
||||
else if ((this.state & STATE_HOVERED) != 0) {
|
||||
b += 0.25F;
|
||||
b += theme.getHoverBrightnessAdjustment();
|
||||
}
|
||||
|
||||
b = Math.max(0.0f, Math.min(1.0f, b));
|
||||
final var bodyColor = Color.getHSBColor(h, s, b);
|
||||
Color border0Color;
|
||||
Color border1Color;
|
||||
|
||||
if (dimX < 45) {
|
||||
border0Color = this.isEnabled() ? ComponentRenderingSupport.COLOR_COMPONENT_BORDER1 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER1_DIS;
|
||||
border0Color = this.isEnabled() ? theme.getBorderInner().toColor() : theme.getBorderInnerDisabled().toColor();
|
||||
border1Color = bodyColor;
|
||||
}
|
||||
else {
|
||||
border0Color = ComponentRenderingSupport.COLOR_COMPONENT_BORDER0;
|
||||
border1Color = this.isEnabled() ? ComponentRenderingSupport.COLOR_COMPONENT_BORDER1 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER1_DIS;
|
||||
border0Color = theme.getBorderOuter().toColor();
|
||||
border1Color = this.isEnabled() ? theme.getBorderInner().toColor() : theme.getBorderInnerDisabled().toColor();
|
||||
}
|
||||
|
||||
if ((this.state & STATE_TOGGLED) == 0) {
|
||||
g2d.setColor(bodyColor);
|
||||
g2d.fillRect(8, 8, (int) (dimX / 1.5) - 12, this.getHeight() - 15);
|
||||
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, 6, 4, (int) (dimX / 1.5) - 6, this.getHeight() - 9, 2, border0Color);
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, 8, 6, (int) (dimX / 1.5) - 10, this.getHeight() - 13, 2, border1Color);
|
||||
final var patternRenderer = this.themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
if (patternRenderer != null) {
|
||||
patternRenderer.drawDecorativeBorder(g2d, 6, 4, (int) (dimX / 1.5) - 6, this.getHeight() - 9, 2, border0Color);
|
||||
patternRenderer.drawDecorativeBorder(g2d, 8, 6, (int) (dimX / 1.5) - 10, this.getHeight() - 13, 2, border1Color);
|
||||
}
|
||||
}
|
||||
else {
|
||||
g2d.setColor(bodyColor);
|
||||
g2d.fillRect(dimX - (int) (dimX / 1.5), 8, (int) (dimX / 1.5) - 12, this.getHeight() - 15);
|
||||
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, dimX - (int) (dimX / 1.5) - 3, 4, (int) (dimX / 1.5) - 6, this.getHeight() - 9, 2, border0Color);
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, dimX - (int) (dimX / 1.5) - 1, 6, (int) (dimX / 1.5) - 10, this.getHeight() - 13, 2, border1Color);
|
||||
final var patternRenderer = this.themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
if (patternRenderer != null) {
|
||||
patternRenderer.drawDecorativeBorder(g2d, dimX - (int) (dimX / 1.5) - 3, 4, (int) (dimX / 1.5) - 6, this.getHeight() - 9, 2, border0Color);
|
||||
patternRenderer.drawDecorativeBorder(g2d, dimX - (int) (dimX / 1.5) - 1, 6, (int) (dimX / 1.5) - 10, this.getHeight() - 13, 2, border1Color);
|
||||
}
|
||||
}
|
||||
|
||||
// Text color based on state
|
||||
if ((this.state & STATE_HOVERED) != 0) {
|
||||
g2d.setColor(Color.WHITE);
|
||||
}
|
||||
else if (this.isEnabled()) {
|
||||
g2d.setColor(Color.LIGHT_GRAY);
|
||||
g2d.setColor(theme.getTextNormal().toColor());
|
||||
}
|
||||
else {
|
||||
g2d.setColor(Color.GRAY);
|
||||
g2d.setColor(theme.getTextDisabled().toColor());
|
||||
}
|
||||
|
||||
final var textDim = G2DDrawFont.getTextDimensions(this.caption, g2d, this.fontSize, this.scaleFactor);
|
||||
G2DDrawFont.renderText(g2d,
|
||||
textDim,
|
||||
@@ -87,8 +101,16 @@ public class CustomSwitch extends CustomAbstractButton {
|
||||
this.caption);
|
||||
|
||||
if (this.drawBorder) {
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, 0, 0, this.getWidth() - 1, this.getHeight() - 1, 2, (this.state & STATE_HOVERED) != 0 ? ComponentRenderingSupport.COLOR_COMPONENT_SELECTED_0 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER0);
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, 2, 2, this.getWidth() - 5, this.getHeight() - 5, 2, this.isEnabled() ? (this.state & STATE_HOVERED) != 0 ? ComponentRenderingSupport.COLOR_COMPONENT_SELECTED_1 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER1 : ComponentRenderingSupport.COLOR_COMPONENT_BORDER1_DIS);
|
||||
final var borderColor1 = (this.state & STATE_HOVERED) != 0 ? theme.getSelectionPrimary().toColor() : theme.getBorderOuter().toColor();
|
||||
final var patternRenderer = this.themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
if (patternRenderer != null) {
|
||||
patternRenderer.drawDecorativeBorder(g2d, 0, 0, this.getWidth() - 1, this.getHeight() - 1, 2, borderColor1);
|
||||
|
||||
final var borderColor2 = this.isEnabled() ?
|
||||
(this.state & STATE_HOVERED) != 0 ? theme.getSelectionSecondary().toColor() : theme.getBorderInner().toColor() :
|
||||
theme.getBorderInnerDisabled().toColor();
|
||||
patternRenderer.drawDecorativeBorder(g2d, 2, 2, this.getWidth() - 5, this.getHeight() - 5, 2, borderColor2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,55 +1,33 @@
|
||||
package de.extio.game_engine.renderer.g2d.control.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class CustomWindowCloseButton extends CustomAbstractButton {
|
||||
|
||||
public CustomWindowCloseButton(final boolean toggle, final ActionListener listener) {
|
||||
private final G2DThemeManager themeManager;
|
||||
|
||||
public CustomWindowCloseButton(final boolean toggle, final ActionListener listener, final G2DThemeManager themeManager) {
|
||||
super(toggle, listener);
|
||||
this.themeManager = themeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
if (this.themeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final var g2d = (Graphics2D) g;
|
||||
final var theme = this.themeManager.getCurrentTheme();
|
||||
final var patternRenderer = this.themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
|
||||
final var highlight = (this.state & (STATE_HOVERED | STATE_TOGGLED)) != 0;
|
||||
final var pressed = (this.state & STATE_PRESSED) != 0;
|
||||
|
||||
Color color = null;
|
||||
if (pressed) {
|
||||
color = ComponentRenderingSupport.COLOR_COMPONENT_SELECTED_0;
|
||||
}
|
||||
else if (highlight) {
|
||||
color = ComponentRenderingSupport.COLOR_COMPONENT_BGR;
|
||||
}
|
||||
else if (this.backgroundColor == null) {
|
||||
color = ComponentRenderingSupport.COLOR_COMPONENT_BORDER1;
|
||||
}
|
||||
else {
|
||||
color = this.backgroundColor;
|
||||
}
|
||||
g2d.setColor(color);
|
||||
g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||
|
||||
if (this.isEnabled()) {
|
||||
if (pressed) {
|
||||
g2d.setColor(RgbaColor.YELLOW.toAwtColor());
|
||||
}
|
||||
else if (highlight) {
|
||||
g2d.setColor(ComponentRenderingSupport.COLOR_COMPONENT_SELECTED_1);
|
||||
}
|
||||
else {
|
||||
g2d.setColor(Color.BLACK);
|
||||
}
|
||||
final var textDim = G2DDrawFont.getTextDimensions("X", g2d, 16, this.scaleFactor);
|
||||
G2DDrawFont.renderText(g2d, textDim, 1.0, ((this.getWidth() - textDim.getX()) / 2), ((this.getHeight() - textDim.getY()) / 2), (int) (16 * this.scaleFactor), "X");
|
||||
if (patternRenderer != null) {
|
||||
patternRenderer.drawCloseButton(g2d, this.getWidth(), this.getHeight(), this.isEnabled(), this.state, this.backgroundColor, this.scaleFactor, theme);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,12 @@ import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DMainFrame;
|
||||
import de.extio.game_engine.renderer.model.color.ImmutableRgbaColor;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.renderer.g2d.theme.Theme;
|
||||
import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
|
||||
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
|
||||
|
||||
public class CustomWindowPanel extends Component {
|
||||
|
||||
private static final RgbaColor COLOR_WINDOW = new ImmutableRgbaColor(ComponentRenderingSupport.COLOR_COMPONENT_BORDER1.getRed(), ComponentRenderingSupport.COLOR_COMPONENT_BORDER1.getGreen(), ComponentRenderingSupport.COLOR_COMPONENT_BORDER1.getBlue());
|
||||
|
||||
protected boolean thickBorder;
|
||||
|
||||
protected Color color;
|
||||
@@ -27,6 +25,8 @@ public class CustomWindowPanel extends Component {
|
||||
|
||||
protected boolean dirty = true;
|
||||
|
||||
private final G2DThemeManager themeManager;
|
||||
|
||||
public void setThickBorder(final boolean thickBorder) {
|
||||
this.thickBorder = thickBorder;
|
||||
}
|
||||
@@ -47,7 +47,8 @@ public class CustomWindowPanel extends Component {
|
||||
this.dirty = dirty;
|
||||
}
|
||||
|
||||
public CustomWindowPanel() {
|
||||
public CustomWindowPanel(final G2DThemeManager themeManager) {
|
||||
this.themeManager = themeManager;
|
||||
this.setIgnoreRepaint(true);
|
||||
|
||||
this.addMouseListener(new MouseAdapter() {
|
||||
@@ -103,24 +104,26 @@ public class CustomWindowPanel extends Component {
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics g) {
|
||||
final var g2d = (Graphics2D) g;
|
||||
|
||||
final var strength = Math.max(2, (int) (3 * this.scaleFactor));
|
||||
final var effectiveColor = this.color != null ? this.color : COLOR_WINDOW.toAwtColor();
|
||||
|
||||
final var cMain = effectiveColor;
|
||||
final var rgbaDarker = new Color(effectiveColor.getRed() / 2, effectiveColor.getGreen() / 2, effectiveColor.getBlue() / 2);
|
||||
|
||||
if (this.thickBorder) {
|
||||
final var borderStrength = strength * 2;
|
||||
g2d.setColor(cMain);
|
||||
g2d.fillRect(strength * 2, strength * 2, this.getWidth() - strength * 4, borderStrength);
|
||||
g2d.setColor(rgbaDarker);
|
||||
g2d.fillRect(strength * 2, strength * 2 + borderStrength, this.getWidth() - strength * 4, strength);
|
||||
if (this.themeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentRenderingSupport.drawDecorativeBorder(g2d, 0, 0, this.getWidth(), this.getHeight(), strength, rgbaDarker);
|
||||
ComponentRenderingSupport.drawDecorativeBorderFilled(g2d, strength, strength, this.getWidth() - strength * 2, this.getHeight() - strength * 2, strength, cMain);
|
||||
final var g2d = (Graphics2D) g;
|
||||
final Theme theme = this.themeManager.getCurrentTheme();
|
||||
final var patternRenderer = this.themeManager.getPatternRenderer(theme.getPatternRendererName());
|
||||
|
||||
if (patternRenderer != null) {
|
||||
patternRenderer.drawWindowPanel(g2d,
|
||||
0,
|
||||
0,
|
||||
this.getWidth(),
|
||||
this.getHeight(),
|
||||
this.thickBorder,
|
||||
theme.getBorderInner().toColor(),
|
||||
theme.getBorderOuter().toColor(),
|
||||
this.color != null ? this.color : theme.getWindowBackground().toColor(),
|
||||
this.scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class G2DButtonControlImpl extends G2DBaseControlImpl implements ButtonCo
|
||||
}
|
||||
|
||||
protected void createControl() {
|
||||
this.control = new CustomButton(false, event -> this.performAction());
|
||||
this.control = new CustomButton(false, event -> this.performAction(), ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class G2DLabelControlImpl extends G2DBaseControlImpl implements LabelCont
|
||||
}
|
||||
|
||||
protected void createControl() {
|
||||
this.control = new CustomLabel(event -> this.performAction());
|
||||
this.control = new CustomLabel(event -> this.performAction(), ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ public class G2DSliderControlImpl extends G2DBaseControlImpl implements SliderCo
|
||||
if (this.enabled) {
|
||||
this.performAction();
|
||||
}
|
||||
});
|
||||
}, ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package de.extio.game_engine.renderer.g2d.control.impl;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomSwitch;
|
||||
|
||||
public class G2DSwitchControlImpl extends G2DAbstractToggleButtonControlImpl {
|
||||
|
||||
@Override
|
||||
protected void createControl() {
|
||||
this.control = new CustomSwitch(true, event -> this.performAction());
|
||||
this.control = new CustomSwitch(true, event -> this.performAction(), ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ import javax.swing.table.DefaultTableCellRenderer;
|
||||
import de.extio.game_engine.renderer.RendererData;
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.ComponentRenderingSupport;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomTable;
|
||||
import de.extio.game_engine.renderer.g2d.theme.G2DThemeManager;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.BaseControl;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.TableControl;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
@@ -167,7 +167,8 @@ public class G2DTableControlImpl extends G2DBaseControlImpl implements TableCont
|
||||
this.control.setFont(G2DDrawFont.getFont(this.scaleFactor, this.fontSize));
|
||||
this.control.setRowHeight((int) (this.control.getFont().getSize2D() * 1.25));
|
||||
|
||||
this.control.setBackground(ComponentRenderingSupport.COLOR_COMPONENT_BGR);
|
||||
final G2DThemeManager themeManager = ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager();
|
||||
this.control.setBackground(themeManager.getCurrentTheme().getBackgroundNormal().toColor());
|
||||
this.control.setForeground(Color.WHITE);
|
||||
|
||||
if (this.dataModified || this.scrollPositionModified) {
|
||||
|
||||
@@ -6,9 +6,9 @@ import java.awt.TextComponent;
|
||||
import java.awt.TextField;
|
||||
import java.util.Objects;
|
||||
|
||||
import de.extio.game_engine.renderer.ThemeManager;
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.ComponentRenderingSupport;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomTextArea;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomTextField;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.BaseControl;
|
||||
@@ -119,7 +119,9 @@ public class G2DTextfieldControlImpl extends G2DBaseControlImpl implements Textf
|
||||
}
|
||||
|
||||
private void initTextField() {
|
||||
this.safeInvoke(() -> this.textComponent.setBackground(ComponentRenderingSupport.COLOR_COMPONENT_BGR));
|
||||
final ThemeManager themeManager = ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager();
|
||||
final Color bgColor = themeManager.getCurrentTheme().getBackgroundNormal().toColor();
|
||||
this.safeInvoke(() -> this.textComponent.setBackground(bgColor));
|
||||
this.safeInvoke(() -> this.textComponent.setForeground(Color.WHITE));
|
||||
this.safeInvoke(() -> this.textComponent.setLocation(this.x, this.y));
|
||||
this.safeInvoke(() -> this.textComponent.setSize(this.width, this.height));
|
||||
|
||||
@@ -9,9 +9,9 @@ import javax.swing.JTextField;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererData;
|
||||
import de.extio.game_engine.renderer.ThemeManager;
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.ComponentRenderingSupport;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomJTextArea;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomJTextField;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.BaseControl;
|
||||
@@ -227,7 +227,14 @@ public class G2DTextfieldControlImpl2 extends G2DBaseControlImpl implements Text
|
||||
}
|
||||
|
||||
private void initControl() {
|
||||
this.safeInvoke(() -> this.textComponent.setBackground(this.backgroundColor != null ? this.backgroundColor.toAwtColor() : ComponentRenderingSupport.COLOR_COMPONENT_BGR));
|
||||
final ThemeManager themeManager = ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager();
|
||||
final Color bgColor;
|
||||
if (this.backgroundColor != null) {
|
||||
bgColor = this.backgroundColor.toAwtColor();
|
||||
} else {
|
||||
bgColor = themeManager.getCurrentTheme().getBackgroundNormal().toColor();
|
||||
}
|
||||
this.safeInvoke(() -> this.textComponent.setBackground(bgColor));
|
||||
this.safeInvoke(() -> this.textComponent.setForeground(Color.WHITE));
|
||||
this.safeInvoke(() -> this.textComponent.setFont(G2DDrawFont.getFont(this.scaleFactor, this.fontSize)));
|
||||
if (this.multiLine) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package de.extio.game_engine.renderer.g2d.control.impl;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomButton;
|
||||
|
||||
public class G2DToggleButtonControlImpl extends G2DAbstractToggleButtonControlImpl {
|
||||
|
||||
@Override
|
||||
protected void createControl() {
|
||||
this.control = new CustomButton(true, event -> this.performAction());
|
||||
this.control = new CustomButton(true, event -> this.performAction(), ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.extio.game_engine.renderer.g2d.control.impl;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.renderer.g2d.control.components.CustomWindowCloseButton;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.WindowCloseButtonControl;
|
||||
|
||||
@@ -11,7 +12,7 @@ public class G2DWindowCloseButtonControlImpl extends G2DButtonControlImpl implem
|
||||
|
||||
@Override
|
||||
protected void createControl() {
|
||||
this.control = new CustomWindowCloseButton(false, event -> this.performAction());
|
||||
this.control = new CustomWindowCloseButton(false, event -> this.performAction(), ((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class G2DWindowPanelControlImpl extends G2DBaseControlImpl implements Win
|
||||
}
|
||||
|
||||
protected void createControl() {
|
||||
this.control = new CustomWindowPanel();
|
||||
this.control = new CustomWindowPanel(((G2DRenderer) this.rendererData.getRenderer()).getThemeManager());
|
||||
this.control.setName(this.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
/**
|
||||
* Represents the visual state of a UI component.
|
||||
* Used by the theming system to determine which colors to apply.
|
||||
*/
|
||||
public enum ComponentState {
|
||||
/**
|
||||
* Normal, default state - enabled, not interacted with
|
||||
*/
|
||||
NORMAL,
|
||||
|
||||
/**
|
||||
* Mouse cursor is hovering over the component
|
||||
*/
|
||||
HOVERED,
|
||||
|
||||
/**
|
||||
* Component is currently being pressed/clicked
|
||||
*/
|
||||
PRESSED,
|
||||
|
||||
/**
|
||||
* Component is in toggled/selected state (for toggle buttons, switches)
|
||||
*/
|
||||
TOGGLED,
|
||||
|
||||
/**
|
||||
* Component is disabled and cannot be interacted with
|
||||
*/
|
||||
DISABLED,
|
||||
|
||||
/**
|
||||
* Component has keyboard focus (for text fields)
|
||||
*/
|
||||
FOCUSED
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.extio.game_engine.renderer.ThemeManager;
|
||||
import de.extio.game_engine.renderer.g2d.G2DRenderer;
|
||||
import de.extio.game_engine.resource.StaticResourceService;
|
||||
|
||||
public class G2DThemeManager implements ThemeManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(G2DThemeManager.class);
|
||||
|
||||
private G2DRenderer g2dRenderer;
|
||||
|
||||
private final StaticResourceService staticResourceService;
|
||||
|
||||
private final Map<String, PatternRenderer> patternRenderers;
|
||||
private final Map<String, Theme> themes;
|
||||
private final Theme defaultTheme;
|
||||
|
||||
private Theme currentTheme;
|
||||
|
||||
public G2DThemeManager(
|
||||
final StaticResourceService staticResourceService,
|
||||
final List<PatternRenderer> patternRendererList,
|
||||
final Map<String, Theme> themes,
|
||||
final Theme defaultTheme) {
|
||||
this.staticResourceService = staticResourceService;
|
||||
this.patternRenderers = patternRendererList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
renderer -> renderer.getClass().getSimpleName().substring(0, 1).toLowerCase() + renderer.getClass().getSimpleName().substring(1),
|
||||
Function.identity()));
|
||||
this.themes = Objects.requireNonNull(themes, "themes cannot be null");
|
||||
this.defaultTheme = Objects.requireNonNull(defaultTheme, "defaultTheme cannot be null");
|
||||
|
||||
LOGGER.info("G2DThemeManager initialized with {} pattern renderers: {}", this.patternRenderers.size(), this.patternRenderers.keySet());
|
||||
LOGGER.info("G2DThemeManager initialized with {} themes: {}", this.themes.size(), this.themes.keySet());
|
||||
this.currentTheme = this.defaultTheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAvailableThemeNames() {
|
||||
return this.themes.values().stream()
|
||||
.map(Theme::getName)
|
||||
.distinct()
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentTheme(final String themeName) {
|
||||
if (themeName == null || themeName.isBlank()) {
|
||||
throw new IllegalArgumentException("themeName cannot be null/blank");
|
||||
}
|
||||
|
||||
final var direct = this.themes.get(themeName);
|
||||
if (direct != null) {
|
||||
this.setCurrentTheme(direct);
|
||||
return;
|
||||
}
|
||||
|
||||
final var byDisplayName = this.themes.values().stream()
|
||||
.filter(theme -> theme != null && theme.getName() != null && theme.getName().equalsIgnoreCase(themeName))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (byDisplayName != null) {
|
||||
this.setCurrentTheme(byDisplayName);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setCurrentTheme(this.loadTheme(themeName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Theme getCurrentTheme() {
|
||||
return this.currentTheme;
|
||||
}
|
||||
|
||||
public PatternRenderer getPatternRenderer(final String rendererName) {
|
||||
return this.patternRenderers.get(rendererName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentTheme(final Theme theme) {
|
||||
if (theme == null) {
|
||||
throw new IllegalArgumentException("Theme cannot be null");
|
||||
}
|
||||
|
||||
this.currentTheme = theme;
|
||||
LOGGER.info("Theme switched to: {}", theme.getName());
|
||||
|
||||
this.g2dRenderer.reset();
|
||||
}
|
||||
|
||||
public Theme loadTheme(final String themeName) {
|
||||
Objects.requireNonNull(this.staticResourceService, "staticResourceService");
|
||||
LOGGER.warn("Theme loading from StaticResourceService not yet implemented. Requested theme: {}. Using default theme.", themeName);
|
||||
return this.defaultTheme;
|
||||
}
|
||||
|
||||
public void setG2dRenderer(final G2DRenderer g2dRenderer) {
|
||||
this.g2dRenderer = g2dRenderer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a color in HSB (Hue, Saturation, Brightness) color space.
|
||||
* This allows for easier runtime color manipulation (e.g., brightening on hover).
|
||||
*/
|
||||
public final class HSBColor {
|
||||
|
||||
private final float hue;
|
||||
private final float saturation;
|
||||
private final float brightness;
|
||||
|
||||
/**
|
||||
* Creates an HSB color.
|
||||
*
|
||||
* @param hue Hue component (0.0 to 1.0)
|
||||
* @param saturation Saturation component (0.0 to 1.0)
|
||||
* @param brightness Brightness component (0.0 to 1.0)
|
||||
*/
|
||||
public HSBColor(final float hue, final float saturation, final float brightness) {
|
||||
this.hue = clamp(hue);
|
||||
this.saturation = clamp(saturation);
|
||||
this.brightness = clamp(brightness);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HSB color from an AWT Color.
|
||||
*
|
||||
* @param color The AWT color to convert
|
||||
*/
|
||||
public static HSBColor fromColor(final Color color) {
|
||||
final var hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
|
||||
return new HSBColor(hsb[0], hsb[1], hsb[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this HSB color to an AWT Color.
|
||||
*
|
||||
* @return The AWT Color
|
||||
*/
|
||||
public Color toColor() {
|
||||
return Color.getHSBColor(this.hue, this.saturation, this.brightness);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HSBColor with adjusted brightness.
|
||||
*
|
||||
* @param delta The amount to add to brightness (-1.0 to 1.0)
|
||||
* @return A new HSBColor with adjusted brightness
|
||||
*/
|
||||
public HSBColor adjustBrightness(final float delta) {
|
||||
return new HSBColor(this.hue, this.saturation, this.brightness + delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HSBColor with adjusted saturation.
|
||||
*
|
||||
* @param delta The amount to add to saturation (-1.0 to 1.0)
|
||||
* @return A new HSBColor with adjusted saturation
|
||||
*/
|
||||
public HSBColor adjustSaturation(final float delta) {
|
||||
return new HSBColor(this.hue, this.saturation + delta, this.brightness);
|
||||
}
|
||||
|
||||
public float getHue() {
|
||||
return this.hue;
|
||||
}
|
||||
|
||||
public float getSaturation() {
|
||||
return this.saturation;
|
||||
}
|
||||
|
||||
public float getBrightness() {
|
||||
return this.brightness;
|
||||
}
|
||||
|
||||
private static float clamp(final float value) {
|
||||
return Math.max(0.0f, Math.min(1.0f, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || this.getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final HSBColor hsbColor = (HSBColor) o;
|
||||
return Float.compare(hsbColor.hue, this.hue) == 0 &&
|
||||
Float.compare(hsbColor.saturation, this.saturation) == 0 &&
|
||||
Float.compare(hsbColor.brightness, this.brightness) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.hue, this.saturation, this.brightness);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("HSB(%.2f, %.2f, %.2f)", this.hue, this.saturation, this.brightness);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
/**
|
||||
* Interface for rendering common UI patterns like borders, backgrounds, shadows, etc.
|
||||
* Different implementations can provide different visual styles.
|
||||
*/
|
||||
public interface PatternRenderer {
|
||||
|
||||
/**
|
||||
* Draws a decorative border around a component.
|
||||
*
|
||||
* @param g2d The graphics context
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @param width Width of the border area
|
||||
* @param height Height of the border area
|
||||
* @param strength Border thickness/strength
|
||||
* @param color Border color
|
||||
*/
|
||||
void drawDecorativeBorder(Graphics2D g2d, int x, int y, int width, int height, int strength, Color color);
|
||||
|
||||
/**
|
||||
* Draws a decorative border with a filled background.
|
||||
*
|
||||
* @param g2d The graphics context
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @param width Width of the border area
|
||||
* @param height Height of the border area
|
||||
* @param strength Border thickness/strength
|
||||
* @param borderColor Border color
|
||||
* @param backgroundColor Background fill color
|
||||
*/
|
||||
void drawDecorativeBorderFilled(Graphics2D g2d, int x, int y, int width, int height, int strength, Color borderColor, Color backgroundColor);
|
||||
|
||||
/**
|
||||
* Draws a window panel with border and background.
|
||||
*
|
||||
* @param g2d The graphics context
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @param width Width
|
||||
* @param height Height
|
||||
* @param thickBorder Whether to use thick border style
|
||||
* @param mainColor Main panel color
|
||||
* @param darkerColor Darker shade for borders
|
||||
* @param scaleFactor UI scale factor
|
||||
*/
|
||||
void drawWindowPanel(Graphics2D g2d, int x, int y, int width, int height, boolean thickBorder, Color innerBorderColor, Color outerBorderColor, Color backgroundColor, double scaleFactor);
|
||||
|
||||
/**
|
||||
* Draws a window close button with appropriate styling based on state.
|
||||
*
|
||||
* @param g2d The graphics context
|
||||
* @param width Width of the button
|
||||
* @param height Height of the button
|
||||
* @param enabled Whether the button is enabled
|
||||
* @param state Button state flags (hovered, pressed, toggled)
|
||||
* @param backgroundColor Optional background color override (null to use theme defaults)
|
||||
* @param scaleFactor UI scale factor
|
||||
* @param theme Theme to use for colors
|
||||
*/
|
||||
void drawCloseButton(Graphics2D g2d, int width, int height, boolean enabled, int state, Color backgroundColor, double scaleFactor, Theme theme);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
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;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
|
||||
/**
|
||||
* Default implementation of PatternRenderer that draws borders and panels in a decorative style.
|
||||
* This implementation provides the default theming for UI components.
|
||||
*/
|
||||
@Conditional(G2DRendererCondition.class)
|
||||
@Component
|
||||
public class SpacecraftPatternRenderer 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) {
|
||||
final var strength2 = strength * 2;
|
||||
final var strength4 = strength * 4;
|
||||
|
||||
g2d.setColor(color);
|
||||
|
||||
// Vertical lines
|
||||
g2d.fillRect(x, y + strength2, strength, height - strength4);
|
||||
g2d.fillRect(x + width - strength, y + strength2, strength, height - strength4);
|
||||
|
||||
// Horizontal lines
|
||||
g2d.fillRect(x + strength2, y, width - strength4, strength);
|
||||
g2d.fillRect(x + strength2, y + height - strength, width - strength4, strength);
|
||||
|
||||
// Corner squares
|
||||
g2d.fillRect(x + strength, y + strength, strength2, strength2);
|
||||
g2d.fillRect(x + width - strength - strength2, y + strength, strength2, strength2);
|
||||
g2d.fillRect(x + strength, y + height - strength - strength2, strength2, strength2);
|
||||
g2d.fillRect(x + width - strength - strength2, y + height - strength - strength2, strength2, strength2);
|
||||
}
|
||||
|
||||
@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 + strength, y + strength, width - strength, height - strength);
|
||||
|
||||
// Draw border on top
|
||||
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) {
|
||||
final var strength = Math.max((thickBorder ? 4 : 2), (int) ((thickBorder ? 6 : 3) * scaleFactor));
|
||||
final var strength2 = strength * 2;
|
||||
final var backgroundTransparency = new Color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue(), 180);
|
||||
|
||||
drawDecorativeBorderFilled(g2d, x + strength, y + strength, width - strength2, height - strength2, strength, innerBorderColor, backgroundTransparency);
|
||||
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_HOVERED = 4;
|
||||
final var STATE_TOGGLED = 1;
|
||||
final var STATE_PRESSED = 2;
|
||||
|
||||
final var highlight = (state & (STATE_HOVERED | STATE_TOGGLED)) != 0;
|
||||
final var pressed = (state & STATE_PRESSED) != 0;
|
||||
|
||||
Color bgColor = null;
|
||||
if (pressed) {
|
||||
bgColor = theme.getSelectionPrimary().toColor();
|
||||
}
|
||||
else if (highlight) {
|
||||
bgColor = theme.getBackgroundNormal().toColor();
|
||||
}
|
||||
else if (backgroundColor == null) {
|
||||
bgColor = theme.getBorderInner().toColor();
|
||||
}
|
||||
else {
|
||||
bgColor = backgroundColor;
|
||||
}
|
||||
g2d.setColor(bgColor);
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
|
||||
if (enabled) {
|
||||
if (pressed) {
|
||||
g2d.setColor(RgbaColor.YELLOW.toAwtColor());
|
||||
}
|
||||
else if (highlight) {
|
||||
g2d.setColor(theme.getSelectionSecondary().toColor());
|
||||
}
|
||||
else {
|
||||
g2d.setColor(Color.BLACK);
|
||||
}
|
||||
final var textDim = G2DDrawFont.getTextDimensions("X", g2d, 16, scaleFactor);
|
||||
G2DDrawFont.renderText(g2d, textDim, 1.0, ((width - textDim.getX()) / 2), ((height - textDim.getY()) / 2), (int) (16 * scaleFactor), "X");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
public class SpacecraftThemeFactoryBean implements FactoryBean<Theme> {
|
||||
|
||||
@Override
|
||||
public Theme getObject() {
|
||||
return Theme.builder()
|
||||
.name("Spacecraft")
|
||||
.patternRendererName("spacecraftPatternRenderer")
|
||||
.borderOuter(new HSBColor(0.71f, 0.12f, 0.50f))
|
||||
.borderInner(new HSBColor(0.71f, 0.12f, 0.80f))
|
||||
.borderInnerDisabled(new HSBColor(0.71f, 0.15f, 0.20f))
|
||||
.backgroundNormal(new HSBColor(0.71f, 0.92f, 0.30f))
|
||||
.backgroundSelected(new HSBColor(0.199f, 0.83f, 0.50f))
|
||||
.textNormal(new HSBColor(0.0f, 0.0f, 0.80f))
|
||||
.textDisabled(new HSBColor(0.0f, 0.0f, 0.50f))
|
||||
.selectionPrimary(new HSBColor(0.199f, 0.83f, 0.50f))
|
||||
.selectionSecondary(new HSBColor(0.199f, 0.83f, 0.90f))
|
||||
.windowBackground(new HSBColor(0.71f, 0.6f, 0.05f))
|
||||
.hoverBrightnessAdjustment(0.25f)
|
||||
.pressedBrightnessAdjustment(0.40f)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Theme.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
203
src/main/java/de/extio/game_engine/renderer/g2d/theme/Theme.java
Normal file
203
src/main/java/de/extio/game_engine/renderer/g2d/theme/Theme.java
Normal file
@@ -0,0 +1,203 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
/**
|
||||
* Represents a complete UI theme with all color definitions and pattern renderer.
|
||||
* Themes are element-based rather than component-based, allowing consistent styling across different components.
|
||||
*/
|
||||
public class Theme {
|
||||
|
||||
private final String name;
|
||||
private final String patternRendererName;
|
||||
|
||||
// Element colors - Borders
|
||||
private final HSBColor borderOuter;
|
||||
private final HSBColor borderInner;
|
||||
private final HSBColor borderInnerDisabled;
|
||||
|
||||
// Element colors - Backgrounds
|
||||
private final HSBColor backgroundNormal;
|
||||
private final HSBColor backgroundSelected;
|
||||
|
||||
// Element colors - Text
|
||||
private final HSBColor textNormal;
|
||||
private final HSBColor textDisabled;
|
||||
|
||||
// Element colors - Selection/Highlight
|
||||
private final HSBColor selectionPrimary;
|
||||
private final HSBColor selectionSecondary;
|
||||
|
||||
// Element colors - Window/Panel
|
||||
private final HSBColor windowBackground;
|
||||
|
||||
// Brightness adjustments for states
|
||||
private final float hoverBrightnessAdjustment;
|
||||
private final float pressedBrightnessAdjustment;
|
||||
|
||||
private Theme(final Builder builder) {
|
||||
this.name = builder.name;
|
||||
this.patternRendererName = builder.patternRendererName;
|
||||
this.borderOuter = builder.borderOuter;
|
||||
this.borderInner = builder.borderInner;
|
||||
this.borderInnerDisabled = builder.borderInnerDisabled;
|
||||
this.backgroundNormal = builder.backgroundNormal;
|
||||
this.backgroundSelected = builder.backgroundSelected;
|
||||
this.textNormal = builder.textNormal;
|
||||
this.textDisabled = builder.textDisabled;
|
||||
this.selectionPrimary = builder.selectionPrimary;
|
||||
this.selectionSecondary = builder.selectionSecondary;
|
||||
this.windowBackground = builder.windowBackground;
|
||||
this.hoverBrightnessAdjustment = builder.hoverBrightnessAdjustment;
|
||||
this.pressedBrightnessAdjustment = builder.pressedBrightnessAdjustment;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getPatternRendererName() {
|
||||
return this.patternRendererName;
|
||||
}
|
||||
|
||||
public HSBColor getBorderOuter() {
|
||||
return this.borderOuter;
|
||||
}
|
||||
|
||||
public HSBColor getBorderInner() {
|
||||
return this.borderInner;
|
||||
}
|
||||
|
||||
public HSBColor getBorderInnerDisabled() {
|
||||
return this.borderInnerDisabled;
|
||||
}
|
||||
|
||||
public HSBColor getBackgroundNormal() {
|
||||
return this.backgroundNormal;
|
||||
}
|
||||
|
||||
public HSBColor getBackgroundSelected() {
|
||||
return this.backgroundSelected;
|
||||
}
|
||||
|
||||
public HSBColor getTextNormal() {
|
||||
return this.textNormal;
|
||||
}
|
||||
|
||||
public HSBColor getTextDisabled() {
|
||||
return this.textDisabled;
|
||||
}
|
||||
|
||||
public HSBColor getSelectionPrimary() {
|
||||
return this.selectionPrimary;
|
||||
}
|
||||
|
||||
public HSBColor getSelectionSecondary() {
|
||||
return this.selectionSecondary;
|
||||
}
|
||||
|
||||
public HSBColor getWindowBackground() {
|
||||
return this.windowBackground;
|
||||
}
|
||||
|
||||
public float getHoverBrightnessAdjustment() {
|
||||
return this.hoverBrightnessAdjustment;
|
||||
}
|
||||
|
||||
public float getPressedBrightnessAdjustment() {
|
||||
return this.pressedBrightnessAdjustment;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String name;
|
||||
private String patternRendererName;
|
||||
private HSBColor borderOuter;
|
||||
private HSBColor borderInner;
|
||||
private HSBColor borderInnerDisabled;
|
||||
private HSBColor backgroundNormal;
|
||||
private HSBColor backgroundSelected;
|
||||
private HSBColor textNormal;
|
||||
private HSBColor textDisabled;
|
||||
private HSBColor selectionPrimary;
|
||||
private HSBColor selectionSecondary;
|
||||
private HSBColor windowBackground;
|
||||
private float hoverBrightnessAdjustment = 0.25f;
|
||||
private float pressedBrightnessAdjustment = 0.40f;
|
||||
|
||||
public Builder name(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder patternRendererName(final String patternRendererName) {
|
||||
this.patternRendererName = patternRendererName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder borderOuter(final HSBColor borderOuter) {
|
||||
this.borderOuter = borderOuter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder borderInner(final HSBColor borderInner) {
|
||||
this.borderInner = borderInner;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder borderInnerDisabled(final HSBColor borderInnerDisabled) {
|
||||
this.borderInnerDisabled = borderInnerDisabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder backgroundNormal(final HSBColor backgroundNormal) {
|
||||
this.backgroundNormal = backgroundNormal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder backgroundSelected(final HSBColor backgroundSelected) {
|
||||
this.backgroundSelected = backgroundSelected;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder textNormal(final HSBColor textNormal) {
|
||||
this.textNormal = textNormal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder textDisabled(final HSBColor textDisabled) {
|
||||
this.textDisabled = textDisabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder selectionPrimary(final HSBColor selectionPrimary) {
|
||||
this.selectionPrimary = selectionPrimary;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder selectionSecondary(final HSBColor selectionSecondary) {
|
||||
this.selectionSecondary = selectionSecondary;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder windowBackground(final HSBColor windowBackground) {
|
||||
this.windowBackground = windowBackground;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder hoverBrightnessAdjustment(final float hoverBrightnessAdjustment) {
|
||||
this.hoverBrightnessAdjustment = hoverBrightnessAdjustment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder pressedBrightnessAdjustment(final float pressedBrightnessAdjustment) {
|
||||
this.pressedBrightnessAdjustment = pressedBrightnessAdjustment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Theme build() {
|
||||
return new Theme(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import de.extio.game_engine.renderer.g2d.G2DRendererCondition;
|
||||
|
||||
@Conditional(G2DRendererCondition.class)
|
||||
@Component
|
||||
public class VintagePatternRenderer 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);
|
||||
|
||||
final var size = strength;
|
||||
|
||||
g2d.fillRect(x, y, width, size);
|
||||
g2d.fillRect(x, y, size, height - size * 2);
|
||||
g2d.fillRect(x + width - size, y, size, height - size * 2);
|
||||
g2d.fillRect(x + size * 2, y + height - size, width - size * 4, size);
|
||||
|
||||
g2d.fillPolygon(
|
||||
new int[] { x, x + size * 2, x + size * 2, x + size },
|
||||
new int[] { y + height - size * 2, y + height, y + height - size, y + height - size * 2 },
|
||||
4
|
||||
);
|
||||
g2d.fillPolygon(
|
||||
new int[] { x + width, x + width - size * 2, x + width - size * 2, x + width - size },
|
||||
new int[] { y + height - size * 2, y + height, y + height - size, y + height - size * 2 },
|
||||
4
|
||||
);
|
||||
}
|
||||
|
||||
@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) {
|
||||
g2d.setColor(backgroundColor);
|
||||
g2d.fillRect(x, y + strength, width, height - strength * 3);
|
||||
g2d.fillRect(x + strength, y + height - strength * 2, width - strength * 2, strength);
|
||||
|
||||
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) {
|
||||
final var size = Math.max(3, (int) (5 * scaleFactor));
|
||||
|
||||
final var baseColor = new float[3];
|
||||
innerBorderColor.getRGBColorComponents(baseColor);
|
||||
Color.RGBtoHSB((int) (baseColor[0] * 255), (int) (baseColor[1] * 255), (int) (baseColor[2] * 255), baseColor);
|
||||
|
||||
final var backgroundTransparency = new Color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue(), 180);
|
||||
g2d.setColor(backgroundTransparency);
|
||||
g2d.fillRect(x, y + size, width, height - size * 3);
|
||||
g2d.fillRect(x + size, y + height - size * 2, width - size * 2, size);
|
||||
|
||||
g2d.setColor(Color.getHSBColor(baseColor[0], baseColor[1], baseColor[2]));
|
||||
if (thickBorder) {
|
||||
g2d.fillRect(x, y + size * 2, size, height - size * 4);
|
||||
g2d.fillRect(x + width - size, y + size * 2, size, height - size * 4);
|
||||
g2d.fillRect(x, y + size * 2, width, size);
|
||||
}
|
||||
else {
|
||||
g2d.fillRect(x, y, size, height - size * 2);
|
||||
g2d.fillRect(x + width - size, y, size, height - size * 2);
|
||||
g2d.fillRect(x, y, width, size);
|
||||
}
|
||||
g2d.fillRect(x + size * 2, y + height - size, width - size * 4, size);
|
||||
g2d.fillPolygon(
|
||||
new int[] { x, x + size * 2, x + size * 2, x + size },
|
||||
new int[] { y + height - size * 2, y + height, y + height - size, y + height - size * 2 },
|
||||
4
|
||||
);
|
||||
g2d.fillPolygon(
|
||||
new int[] { x + width, x + width - size * 2, x + width - size * 2, x + width - size },
|
||||
new int[] { y + height - size * 2, y + height, y + height - size, y + height - size * 2 },
|
||||
4
|
||||
);
|
||||
|
||||
if (thickBorder) {
|
||||
for (var i = 0; i < size * 2; i++) {
|
||||
g2d.setColor(Color.getHSBColor(baseColor[0], baseColor[1], baseColor[2] * ((0.5F / (size * 2) * i) + 0.5F)));
|
||||
g2d.drawLine(x, y + i, x + width, y + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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_HOVERED = 4;
|
||||
final var STATE_TOGGLED = 1;
|
||||
final var STATE_PRESSED = 2;
|
||||
|
||||
final var highlight = (state & (STATE_HOVERED | STATE_TOGGLED)) != 0;
|
||||
final var pressed = (state & STATE_PRESSED) != 0;
|
||||
|
||||
final var size = Math.max(2, (int) (3 * scaleFactor));
|
||||
|
||||
Color baseColor = null;
|
||||
if (pressed) {
|
||||
baseColor = theme.getSelectionPrimary().toColor();
|
||||
}
|
||||
else if (highlight) {
|
||||
baseColor = theme.getSelectionSecondary().toColor();
|
||||
}
|
||||
else if (backgroundColor == null) {
|
||||
baseColor = theme.getBorderInner().toColor();
|
||||
}
|
||||
else {
|
||||
baseColor = backgroundColor;
|
||||
}
|
||||
|
||||
final var hsb = Color.RGBtoHSB(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), null);
|
||||
|
||||
g2d.setColor(Color.BLACK);
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
|
||||
g2d.setColor(Color.getHSBColor(hsb[0], hsb[1], hsb[2]));
|
||||
g2d.fillRect(0, 0, width, size);
|
||||
g2d.fillRect(0, 0, size, height);
|
||||
g2d.fillRect(width - size, 0, size, height);
|
||||
g2d.fillRect(0, height - size, width, size);
|
||||
|
||||
if (enabled) {
|
||||
final Color textColor;
|
||||
if (pressed) {
|
||||
textColor = theme.getSelectionPrimary().toColor();
|
||||
}
|
||||
else if (highlight) {
|
||||
textColor = theme.getTextNormal().toColor();
|
||||
}
|
||||
else {
|
||||
textColor = theme.getTextDisabled().toColor();
|
||||
}
|
||||
g2d.setColor(textColor);
|
||||
|
||||
final var crossSize = Math.min(width, height) / 2;
|
||||
final var centerX = width / 2;
|
||||
final var centerY = height / 2;
|
||||
final var crossThickness = Math.max(1, (int) (2 * scaleFactor));
|
||||
|
||||
g2d.fillRect(centerX - crossSize / 2, centerY - crossThickness / 2, crossSize, crossThickness);
|
||||
g2d.fillRect(centerX - crossThickness / 2, centerY - crossSize / 2, crossThickness, crossSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.extio.game_engine.renderer.g2d.theme;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
public class VintageThemeFactoryBean implements FactoryBean<Theme> {
|
||||
|
||||
@Override
|
||||
public Theme getObject() {
|
||||
return Theme.builder()
|
||||
.name("Vintage")
|
||||
.patternRendererName("vintagePatternRenderer")
|
||||
.borderOuter(new HSBColor(0.08f, 0.55f, 0.22f))
|
||||
.borderInner(new HSBColor(0.10f, 0.30f, 0.55f))
|
||||
.borderInnerDisabled(new HSBColor(0.08f, 0.20f, 0.18f))
|
||||
.backgroundNormal(new HSBColor(0.085f, 0.45f, 0.28f))
|
||||
.backgroundSelected(new HSBColor(0.11f, 0.55f, 0.55f))
|
||||
.textNormal(new HSBColor(0.12f, 0.10f, 0.92f))
|
||||
.textDisabled(new HSBColor(0.12f, 0.05f, 0.60f))
|
||||
.selectionPrimary(new HSBColor(0.98f, 0.55f, 0.60f))
|
||||
.selectionSecondary(new HSBColor(0.11f, 0.70f, 0.80f))
|
||||
.windowBackground(new HSBColor(0.08f, 0.60f, 0.12f))
|
||||
.hoverBrightnessAdjustment(0.15f)
|
||||
.pressedBrightnessAdjustment(0.30f)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Theme.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
package de.extio.game_engine.renderer.model.bo;
|
||||
|
||||
import de.extio.game_engine.renderer.model.RenderingBoHasDimension;
|
||||
|
||||
/**
|
||||
* Renders a window
|
||||
*/
|
||||
public interface DrawWindowRenderingBo extends RenderingBoHasDimension {
|
||||
|
||||
DrawWindowRenderingBo setThickBorder(boolean thickBorder);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user