From 6919d81c1298a5130a931c1a232fc55a328cf9a0 Mon Sep 17 00:00:00 2001 From: extio-de Date: Sat, 27 Dec 2025 18:43:32 +0100 Subject: [PATCH] feat(renderer): add CustomWindowPanel and WindowPanelControl for enhanced UI rendering --- .../renderer/container/Window.java | 13 +- .../renderer/g2d/G2DMainFrame.java | 136 ++++++++++-------- .../renderer/g2d/control/G2DDrawControl.java | 10 ++ .../control/components/CustomWindowPanel.java | 126 ++++++++++++++++ .../impl/G2DWindowPanelControlImpl.java | 93 ++++++++++++ .../renderer/model/bo/ControlRenderingBo.java | 15 ++ 6 files changed, 328 insertions(+), 65 deletions(-) create mode 100644 src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomWindowPanel.java create mode 100644 src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DWindowPanelControlImpl.java diff --git a/src/main/java/de/extio/game_engine/renderer/container/Window.java b/src/main/java/de/extio/game_engine/renderer/container/Window.java index 5f00e75..df61714 100644 --- a/src/main/java/de/extio/game_engine/renderer/container/Window.java +++ b/src/main/java/de/extio/game_engine/renderer/container/Window.java @@ -9,7 +9,7 @@ import de.extio.game_engine.renderer.RendererControl; 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.bo.DrawWindowRenderingBo; +import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.WindowPanelControl; import de.extio.game_engine.renderer.model.event.UiControlEvent; import de.extio.game_engine.renderer.work.RendererWorkingSet; import de.extio.game_engine.renderer.work.RenderingBoPool; @@ -49,13 +49,16 @@ public class Window extends Container { return; } - final var windowFrame = this.rendererWorkingSet.getOrAcquire(this.id, "windowFrame", DrawWindowRenderingBo.class) - .setThickBorder(true) + final var windowPanel = this.renderingBoPool.acquire(this.id + "_WindowPanel", ControlRenderingBo.class) + .setType(WindowPanelControl.class) + .setCustomData(true) + .setEnabled(true) + .setVisible(true) .withDimensionAbsolute(this.area.getDimension()) .withPositionAbsoluteAnchorTopLeft(this.area.getPosition()) .setZIndex(this.zIndex) .setLayer(RenderingBoLayer.UI_BGR); - this.rendererWorkingSet.put(this.id, windowFrame); + this.rendererWorkingSet.put(this.id, windowPanel); if (this.closeButton) { this.closeButtonName = this.id + "_CloseButton"; @@ -67,7 +70,7 @@ public class Window extends Container { .withDimensionAbsolute(this.area.getDimension()) .withPositionAbsoluteAnchorTopLeft(this.area.getPosition()) .setZIndex(this.zIndex) - .setLayer(RenderingBoLayer.UI1); + .setLayer(RenderingBoLayer.UI_TOP); this.rendererWorkingSet.put(this.id, closeButtonBo); } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/G2DMainFrame.java b/src/main/java/de/extio/game_engine/renderer/g2d/G2DMainFrame.java index 87f9392..d8a48c7 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/G2DMainFrame.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/G2DMainFrame.java @@ -149,9 +149,7 @@ public class G2DMainFrame extends Frame { @Override public void mouseReleased(final MouseEvent e) { try { - final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); - G2DMainFrame.this.rendererData.getEventService().fire(new MouseClickEvent(false, G2DMainFrame.getModifiers(e), e.getButton(), rawCoord, scaleCoord)); + G2DMainFrame.this.handleMouseReleased(e, ImmutableCoordI2.zero()); } catch (final Exception exc) { LOGGER.warn(exc.getMessage()); @@ -161,10 +159,7 @@ public class G2DMainFrame extends Frame { @Override public void mousePressed(final MouseEvent e) { try { - G2DMainFrame.this.requestFocus(); - final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); - G2DMainFrame.this.rendererData.getEventService().fire(new MouseClickEvent(true, G2DMainFrame.getModifiers(e), e.getButton(), rawCoord, scaleCoord)); + G2DMainFrame.this.handleMousePressed(e, ImmutableCoordI2.zero()); } catch (final Exception exc) { LOGGER.warn(exc.getMessage()); @@ -175,7 +170,7 @@ public class G2DMainFrame extends Frame { public void mouseExited(final MouseEvent e) { try { final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); + final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); G2DMainFrame.this.rendererData.getEventService().fire(new MouseExitEvent(G2DMainFrame.getModifiers(e), rawCoord, scaleCoord)); } catch (final Exception exc) { @@ -187,7 +182,7 @@ public class G2DMainFrame extends Frame { public void mouseEntered(final MouseEvent e) { try { final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); + final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); G2DMainFrame.this.rendererData.getEventService().fire(new MouseEnterEvent(G2DMainFrame.getModifiers(e), rawCoord, scaleCoord)); } catch (final Exception exc) { @@ -205,66 +200,23 @@ public class G2DMainFrame extends Frame { @Override public void mouseMoved(final MouseEvent e) { - final var button = this.getButton(e); - - try { - final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); - G2DMainFrame.this.rendererData.getEventService().fire(new MouseMoveEvent(false, G2DMainFrame.getModifiers(e), button, rawCoord, scaleCoord)); - } - catch (final Exception exc) { - if ("Engine not started up yet".equals(exc.getMessage())) { - return; - } - LOGGER.error(exc.getMessage(), exc); - } + G2DMainFrame.this.handleMouseMoved(e, ImmutableCoordI2.zero()); } @Override public void mouseDragged(final MouseEvent e) { - final var button = this.getButton(e); - - try { - final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); - G2DMainFrame.this.rendererData.getEventService().fire(new MouseMoveEvent(true, G2DMainFrame.getModifiers(e), button, rawCoord, scaleCoord)); - } - catch (final Exception exc) { - if ("Engine not started up yet".equals(exc.getMessage())) { - return; - } - LOGGER.error(exc.getMessage(), exc); - } + G2DMainFrame.this.handleMouseDragged(e, ImmutableCoordI2.zero()); } - private int getButton(final MouseEvent e) { - var button = MouseEvent.NOBUTTON; - if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) { - button = MouseEvent.BUTTON1; - } - else if ((e.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) { - button = MouseEvent.BUTTON2; - } - else if ((e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0) { - button = MouseEvent.BUTTON3; - } - return button; - } }); this.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(final MouseWheelEvent e) { - try { - final var rawCoord = ImmutableCoordI2.create(e.getX(), e.getY()); - final var scaleCoord = G2DMainFrame.this.scaleCoord(rawCoord); - G2DMainFrame.this.rendererData.getEventService().fire(new MouseClickEvent(true, G2DMainFrame.getModifiers(e), e.getWheelRotation() == -1 ? 4 : 5, rawCoord, scaleCoord)); - } - catch (final Exception exc) { - LOGGER.warn(exc.getMessage()); - } + G2DMainFrame.this.handleWheelMoved(e, ImmutableCoordI2.zero()); } + }); this.aWTEventListener = new AWTEventListener() { @@ -454,6 +406,70 @@ public class G2DMainFrame extends Frame { this.setSize((int) Math.min(bounds.getWidth(), RendererControl.REFERENCE_RESOLUTION.getX()), (int) Math.min(bounds.getHeight(), RendererControl.REFERENCE_RESOLUTION.getY())); } + public void handleMouseReleased(final MouseEvent e, final CoordI2 offset) { + final var rawCoord = ImmutableCoordI2.create(e.getX() + offset.getX(), e.getY() + offset.getY()); + final var scaleCoord = this.scaleCoord(rawCoord); + this.rendererData.getEventService().fire(new MouseClickEvent(false, G2DMainFrame.getModifiers(e), e.getButton(), rawCoord, scaleCoord)); + } + + public void handleMousePressed(final MouseEvent e, final CoordI2 offset) { + this.requestFocus(); + final var rawCoord = ImmutableCoordI2.create(e.getX() + offset.getX(), e.getY() + offset.getY()); + final var scaleCoord = this.scaleCoord(rawCoord); + this.rendererData.getEventService().fire(new MouseClickEvent(true, G2DMainFrame.getModifiers(e), e.getButton(), rawCoord, scaleCoord)); + } + + public void handleMouseMoved(final MouseEvent e, final CoordI2 offset) { + final var button = getMouseButton(e); + + try { + final var rawCoord = ImmutableCoordI2.create(e.getX() + offset.getX(), e.getY() + offset.getY()); + final var scaleCoord = this.scaleCoord(rawCoord); + this.rendererData.getEventService().fire(new MouseMoveEvent(false, G2DMainFrame.getModifiers(e), button, rawCoord, scaleCoord)); + } + catch (final Exception exc) { + LOGGER.warn(exc.getMessage(), exc); + } + } + + public void handleMouseDragged(final MouseEvent e, final CoordI2 offset) { + final var button = getMouseButton(e); + + try { + final var rawCoord = ImmutableCoordI2.create(e.getX() + offset.getX(), e.getY() + offset.getY()); + final var scaleCoord = this.scaleCoord(rawCoord); + this.rendererData.getEventService().fire(new MouseMoveEvent(true, G2DMainFrame.getModifiers(e), button, rawCoord, scaleCoord)); + } + catch (final Exception exc) { + LOGGER.warn(exc.getMessage(), exc); + } + } + + public void handleWheelMoved(final MouseWheelEvent e, final CoordI2 offset) { + try { + final var rawCoord = ImmutableCoordI2.create(e.getX() + offset.getX(), e.getY() + offset.getY()); + final var scaleCoord = this.scaleCoord(rawCoord); + this.rendererData.getEventService().fire(new MouseClickEvent(true, G2DMainFrame.getModifiers(e), e.getWheelRotation() == -1 ? 4 : 5, rawCoord, scaleCoord)); + } + catch (final Exception exc) { + LOGGER.warn(exc.getMessage()); + } + } + + private static int getMouseButton(final MouseEvent e) { + var button = MouseEvent.NOBUTTON; + if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) { + button = MouseEvent.BUTTON1; + } + else if ((e.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0) { + button = MouseEvent.BUTTON2; + } + else if ((e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0) { + button = MouseEvent.BUTTON3; + } + return button; + } + private static int getModifiers(final InputEvent event) { var result = 0; @@ -472,14 +488,14 @@ public class G2DMainFrame extends Frame { return result; } - + private CoordI2 scaleCoord(final CoordI2 rawCoord) { final var scaleFactor = ((G2DRendererControl) this.rendererData.getRendererControl()).getScaleFactor(); return ImmutableCoordI2.create((int) (rawCoord.getX() / scaleFactor), (int) (rawCoord.getY() / scaleFactor)); } private static final List COMPONENT_Z_ORDER_PAIRS = new ArrayList<>(); - + public void recalculateAllComponentZOrder() { synchronized (getTreeLock()) { try { @@ -514,7 +530,7 @@ public class G2DMainFrame extends Frame { } } - private static record ComponentZOrderPair (Component component, int effectiveLayer) { + private static record ComponentZOrderPair(Component component, int effectiveLayer) { } - + } diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java b/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java index 76cd85a..721308f 100644 --- a/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java +++ b/src/main/java/de/extio/game_engine/renderer/g2d/control/G2DDrawControl.java @@ -24,6 +24,7 @@ import de.extio.game_engine.renderer.g2d.control.impl.G2DTextfieldControlImpl2; import de.extio.game_engine.renderer.g2d.control.impl.G2DToggleButtonControlImpl; import de.extio.game_engine.renderer.g2d.control.impl.G2DTooltipControl; import de.extio.game_engine.renderer.g2d.control.impl.G2DWindowCloseButtonControlImpl; +import de.extio.game_engine.renderer.g2d.control.impl.G2DWindowPanelControlImpl; 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; @@ -156,6 +157,9 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen else if (this.clazz == WindowCloseButtonControl.class) { control = new G2DWindowCloseButtonControlImpl(); } + else if (this.clazz == WindowPanelControl.class) { + control = new G2DWindowPanelControlImpl(); + } else if (this.clazz == SliderControl.class) { control = new G2DSliderControlImpl(); } @@ -263,6 +267,12 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen ((WindowCloseButtonControl) control).setThickBorder(((Boolean) this.customData).booleanValue()); } } + else if (this.clazz == WindowPanelControl.class) { + ((WindowPanelControl) control).setColor(this.color); + if (this.customData instanceof Boolean) { + ((WindowPanelControl) control).setThickBorder(((Boolean) this.customData).booleanValue()); + } + } else if (this.clazz == SliderControl.class) { ((SliderControl) control).setColor(this.color); if (this.customData instanceof Boolean) { diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomWindowPanel.java b/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomWindowPanel.java new file mode 100644 index 0000000..c68aa82 --- /dev/null +++ b/src/main/java/de/extio/game_engine/renderer/g2d/control/components/CustomWindowPanel.java @@ -0,0 +1,126 @@ +package de.extio.game_engine.renderer.g2d.control.components; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +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.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; + + protected double scaleFactor; + + protected boolean dirty = true; + + public void setThickBorder(final boolean thickBorder) { + this.thickBorder = thickBorder; + } + + public void setColor(final Color color) { + this.color = color; + } + + public void setScaleFactor(final double scaleFactor) { + this.scaleFactor = scaleFactor; + } + + public boolean isDirty() { + return this.dirty; + } + + public void setDirty(final boolean dirty) { + this.dirty = dirty; + } + + public CustomWindowPanel() { + this.setIgnoreRepaint(true); + + this.addMouseListener(new MouseAdapter() { + + @Override + public void mouseReleased(final MouseEvent e) { + if (CustomWindowPanel.this.getParent() instanceof final G2DMainFrame mainFrame) { + mainFrame.handleMouseReleased(e, ImmutableCoordI2.create(CustomWindowPanel.this.getX(), CustomWindowPanel.this.getY())); + } + } + + @Override + public void mousePressed(final MouseEvent e) { + if (CustomWindowPanel.this.getParent() instanceof final G2DMainFrame mainFrame) { + mainFrame.handleMousePressed(e, ImmutableCoordI2.create(CustomWindowPanel.this.getX(), CustomWindowPanel.this.getY())); + } + } + + }); + + this.addMouseMotionListener(new MouseMotionListener() { + + @Override + public void mouseDragged(final MouseEvent e) { + if (CustomWindowPanel.this.getParent() instanceof final G2DMainFrame mainFrame) { + mainFrame.handleMouseDragged(e, ImmutableCoordI2.create(CustomWindowPanel.this.getX(), CustomWindowPanel.this.getY())); + } + } + + @Override + public void mouseMoved(final MouseEvent e) { + if (CustomWindowPanel.this.getParent() instanceof final G2DMainFrame mainFrame) { + mainFrame.handleMouseMoved(e, ImmutableCoordI2.create(CustomWindowPanel.this.getX(), CustomWindowPanel.this.getY())); + } + } + }); + + this.addMouseWheelListener(new MouseWheelListener() { + + @Override + public void mouseWheelMoved(final MouseWheelEvent e) { + if (CustomWindowPanel.this.getParent() instanceof final G2DMainFrame mainFrame) { + mainFrame.handleWheelMoved(e, ImmutableCoordI2.create(CustomWindowPanel.this.getX(), CustomWindowPanel.this.getY())); + } + } + }); + } + + @Override + public void update(final Graphics g) { + // + } + + @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); + } + + 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); + } + +} diff --git a/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DWindowPanelControlImpl.java b/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DWindowPanelControlImpl.java new file mode 100644 index 0000000..45cf413 --- /dev/null +++ b/src/main/java/de/extio/game_engine/renderer/g2d/control/impl/G2DWindowPanelControlImpl.java @@ -0,0 +1,93 @@ +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.CustomWindowPanel; +import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.WindowPanelControl; +import de.extio.game_engine.renderer.model.color.RgbaColor; + +public class G2DWindowPanelControlImpl extends G2DBaseControlImpl implements WindowPanelControl { + + protected CustomWindowPanel control; + + protected boolean thickBorder; + + protected RgbaColor color; + + @Override + public boolean isThickBorder() { + return this.thickBorder; + } + + @Override + public void setThickBorder(final boolean thickBorder) { + this.modified |= thickBorder != this.thickBorder; + this.thickBorder = thickBorder; + } + + @Override + public RgbaColor getColor() { + return this.color; + } + + @Override + public void setColor(final RgbaColor color) { + this.modified |= (color == null) ? this.color != null : !color.equals(this.color); + this.color = color; + } + + @Override + public void build() { + super.build(); + + this.createControl(); + this.initControl(); + final var mainFrame = ((G2DRenderer) this.rendererData.getRenderer()).getMainFrame(); + mainFrame.add(this.control); + this.updateAllComponentZOrder(); + } + + @Override + public void performAction() { + // Window panel is decorative, no action needed + } + + @Override + public void render() { + if (this.modified || this.control.isDirty()) { + this.initControl(); + this.rebuildBufferedImage(); + this.control.paint(this.bufferedImageGraphics); + this.control.setDirty(false); + this.updateAllComponentZOrder(); + } + + super.render(); + } + + @Override + public void close() { + this.control.setVisible(false); + this.control.invalidate(); + ((G2DRenderer) this.rendererData.getRenderer()).getMainFrame().remove(this.control); + + this.thickBorder = false; + this.color = null; + + super.close(); + } + + protected void createControl() { + this.control = new CustomWindowPanel(); + this.control.setName(this.id); + } + + protected void initControl() { + this.control.setLocation(this.x, this.y); + this.control.setSize(this.width, this.height); + this.control.setScaleFactor(this.scaleFactor); + this.control.setThickBorder(this.thickBorder); + this.control.setColor(this.color != null ? this.color.toAwtColor() : null); + this.control.setVisible(this.visible); + } + +} diff --git a/src/main/java/de/extio/game_engine/renderer/model/bo/ControlRenderingBo.java b/src/main/java/de/extio/game_engine/renderer/model/bo/ControlRenderingBo.java index 00771e3..a8a505e 100644 --- a/src/main/java/de/extio/game_engine/renderer/model/bo/ControlRenderingBo.java +++ b/src/main/java/de/extio/game_engine/renderer/model/bo/ControlRenderingBo.java @@ -165,6 +165,21 @@ public interface ControlRenderingBo extends RenderingBoHasDimension { } + /** + * Window panel (decorative container) + */ + public static interface WindowPanelControl extends BaseControl { + + boolean isThickBorder(); + + void setThickBorder(boolean thickBorder); + + RgbaColor getColor(); + + void setColor(RgbaColor color); + + } + /** * Text field */