feat(renderer): add MultiLineTextArea control implementation and data structure for enhanced text input capabilities

This commit is contained in:
extio-de
2026-01-25 18:37:40 +01:00
parent 49bffa1459
commit b2b055c9b3
3 changed files with 199 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
import de.extio.game_engine.renderer.g2d.control.impl.G2DBaseControlImpl;
import de.extio.game_engine.renderer.g2d.control.impl.G2DButtonControlImpl;
import de.extio.game_engine.renderer.g2d.control.impl.G2DLabelControlImpl;
import de.extio.game_engine.renderer.g2d.control.impl.G2DMultiLineTextAreaControlImpl;
import de.extio.game_engine.renderer.g2d.control.impl.G2DSetFocusControl;
import de.extio.game_engine.renderer.g2d.control.impl.G2DSliderControlImpl;
import de.extio.game_engine.renderer.g2d.control.impl.G2DSwitchControlImpl;
@@ -64,6 +65,8 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
private TextfieldData textfieldData;
private MultiLineTextAreaData multiLineTextAreaData;
private SliderData sliderData;
private TableData tableData;
@@ -140,6 +143,9 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
else if (data instanceof final TextfieldData textfieldData) {
this.textfieldData = textfieldData;
}
else if (data instanceof final MultiLineTextAreaData multiLineTextAreaData) {
this.multiLineTextAreaData = multiLineTextAreaData;
}
else if (data instanceof final SliderData sliderData) {
this.sliderData = sliderData;
}
@@ -229,6 +235,9 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
else if (this.clazz == TextfieldControl.class) {
control = new G2DTextfieldControlImpl2();
}
else if (this.clazz == MultiLineTextAreaControl.class) {
control = new G2DMultiLineTextAreaControlImpl();
}
else if (this.clazz == ToggleButtonControl.class) {
control = new G2DToggleButtonControlImpl();
}
@@ -355,6 +364,12 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
tfc2.setLastCaptionUpdateTime(this.lastCaptionUpdateTime);
}
}
else if (this.clazz == MultiLineTextAreaControl.class && this.multiLineTextAreaData != null) {
((MultiLineTextAreaControl) control).setCustomData(this.multiLineTextAreaData);
if (control instanceof final G2DMultiLineTextAreaControlImpl mtac) {
mtac.setLastCaptionUpdateTime(this.lastCaptionUpdateTime);
}
}
else {
for (final var customControlConfiguration : this.customControlConfigurations) {
if (customControlConfiguration.getControlClass().equals(this.clazz)) {
@@ -383,6 +398,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
this.windowCloseButtonData = o.windowCloseButtonData;
this.windowPanelData = o.windowPanelData;
this.textfieldData = o.textfieldData;
this.multiLineTextAreaData = o.multiLineTextAreaData;
this.sliderData = o.sliderData;
this.tableData = o.tableData;
this.popupMenuData = o.popupMenuData;
@@ -414,6 +430,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
this.windowCloseButtonData = null;
this.windowPanelData = null;
this.textfieldData = null;
this.multiLineTextAreaData = null;
this.sliderData = null;
this.tableData = null;
this.popupMenuData = null;

View File

@@ -0,0 +1,170 @@
package de.extio.game_engine.renderer.g2d.control.impl;
import java.awt.Graphics2D;
import de.extio.game_engine.renderer.RendererData;
import de.extio.game_engine.renderer.g2d.G2DRenderer;
import de.extio.game_engine.renderer.g2d.control.components.CustomMultiLineTextArea;
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.BaseControl;
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.MultiLineTextAreaControl;
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.MultiLineTextAreaData;
import de.extio.game_engine.renderer.model.color.RgbaColor;
import de.extio.game_engine.renderer.model.event.UiControlEvent;
public class G2DMultiLineTextAreaControlImpl extends G2DBaseControlImpl implements MultiLineTextAreaControl {
private CustomMultiLineTextArea textArea;
private boolean readonly;
private long lastCaptionUpdateTime;
private long lastCaptionUpdateTimeInternal;
private String lastText = "";
private RgbaColor backgroundColor;
private boolean scrollPositionModified;
@Override
public void setCustomData(final MultiLineTextAreaData data) {
if (data != null) {
this.setReadonly(data.readonly());
this.setBackgroundColor(data.backgroundColor());
}
}
public G2DMultiLineTextAreaControlImpl() {
}
private void setBackgroundColor(final RgbaColor color) {
this.modified |= (color == null) ? this.backgroundColor != null : !color.equals(this.backgroundColor);
this.backgroundColor = color;
}
private void setReadonly(final boolean readonly) {
this.modified |= readonly != this.readonly;
this.readonly = readonly;
}
@Override
public BaseControl setCaption(final String caption) {
this.caption = caption;
return this;
}
public void setLastCaptionUpdateTime(final long lastCaptionUpdateTime) {
this.modified |= this.lastCaptionUpdateTime != lastCaptionUpdateTime;
this.lastCaptionUpdateTime = lastCaptionUpdateTime;
}
@Override
public void build() {
super.build();
this.textArea = new CustomMultiLineTextArea(this.rendererData.getThemeManager(), text -> {
this.lastText = text;
this.lastCaptionUpdateTimeInternal = System.currentTimeMillis();
this.rendererData.getEventService().fire(new UiControlEvent(this.id, text));
});
this.textArea.setName(this.id);
this.textArea.setFocusable(true);
this.initControl();
final var mainFrame = ((G2DRenderer) this.rendererData.getRenderer()).getMainFrame();
mainFrame.add(this.textArea);
this.updateAllComponentZOrder();
}
@Override
public void performAction() {
}
@Override
public void render() {
if (this.lastCaptionUpdateTime > this.lastCaptionUpdateTimeInternal && this.caption != null && !this.caption.equals(this.lastText)) {
this.textArea.setText(this.caption);
this.lastText = this.caption;
this.lastCaptionUpdateTimeInternal = this.lastCaptionUpdateTime;
}
final boolean componentDirty = this.textArea.isDirty();
if (this.modified || componentDirty || this.scrollPositionModified) {
this.rebuildBufferedImage();
this.bufferedImageGraphics.setClip(0, 0, this.bufferedImage.getWidth(), this.bufferedImage.getHeight());
this.textArea.setSize(this.bufferedImage.getWidth(), this.bufferedImage.getHeight());
if (this.modified || componentDirty) {
this.initControl();
}
this.textArea.paint(this.bufferedImageGraphics);
this.textArea.setDirty(false);
this.scrollPositionModified = false;
this.updateAllComponentZOrder();
}
else if (this.positionModified) {
this.textArea.setLocation(this.x, this.y);
this.positionModified = false;
this.updateAllComponentZOrder();
}
this.textArea.paint(this.bufferedImageGraphics);
super.render();
}
@Override
public void close() {
if (this.textArea.isFocusOwner()) {
((G2DRenderer) this.rendererData.getRenderer()).getMainFrame().requestFocus();
}
this.textArea.setVisible(false);
this.textArea.invalidate();
((G2DRenderer) this.rendererData.getRenderer()).getMainFrame().remove(this.textArea);
super.close();
}
private void initControl() {
final var theme = this.rendererData.getThemeManager().getCurrentTheme();
final var bgColor = this.backgroundColor != null ? this.backgroundColor.toAwtColor() : theme.getBackgroundNormal().toColor();
final var fgColor = theme.getTextNormal().toColor();
this.textArea.setBackgroundColor(bgColor);
this.textArea.setForegroundColor(fgColor);
this.textArea.setFontSize(this.fontSize);
this.textArea.setScaleFactor(this.scaleFactor);
this.textArea.setLocation(this.x, this.y);
this.textArea.setSize(this.width, this.height);
this.positionModified = false;
this.textArea.setVisible(this.visible);
this.textArea.setEnabled(this.enabled);
this.textArea.setReadonly(this.readonly);
}
@Override
public G2DBaseControlImpl setScaleFactor(final double scaleFactor) {
return super.setScaleFactor(scaleFactor);
}
@Override
public BaseControl setControlGroup(final String controlGroup) {
return super.setControlGroup(controlGroup);
}
@Override
public BaseControl setRendererData(final RendererData RendererData) {
return super.setRendererData(RendererData);
}
@Override
public G2DBaseControlImpl setMainFrameGraphics(final Graphics2D graphics) {
return super.setMainFrameGraphics(graphics);
}
@Override
public BaseControl setControlId(final String id) {
return super.setControlId(id);
}
}

View File

@@ -24,7 +24,9 @@ public interface ControlRenderingBo extends RenderingBoHasDimension {
record WindowPanelData(boolean thickBorder, RgbaColor color) {}
record TextfieldData(boolean multiLine, boolean readonly, RgbaColor backgroundColor) {}
record TextfieldData(boolean readonly, RgbaColor backgroundColor) {}
record MultiLineTextAreaData(boolean readonly, RgbaColor backgroundColor) {}
record SliderData(boolean horizontal, double value, double value2, RgbaColor color) {}
@@ -163,6 +165,15 @@ public interface ControlRenderingBo extends RenderingBoHasDimension {
}
/**
* Multi-line text area (Java2D-based, no Swing)
*/
public static interface MultiLineTextAreaControl extends BaseControl {
void setCustomData(MultiLineTextAreaData data);
}
/**
* Slider
*/