123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
- package org.openzen.drawablegui;
-
- import org.openzen.drawablegui.draw.DDrawSurface;
- import org.openzen.drawablegui.draw.DDrawnRectangle;
- import org.openzen.drawablegui.draw.DDrawnShape;
- import org.openzen.drawablegui.draw.DDrawnText;
- import org.openzen.drawablegui.listeners.ListenerHandle;
- import org.openzen.drawablegui.live.LiveObject;
- import org.openzen.drawablegui.live.LiveString;
- import org.openzen.drawablegui.live.MutableLiveObject;
- import org.openzen.drawablegui.live.MutableLiveString;
- import org.openzen.drawablegui.style.DDimension;
- import org.openzen.drawablegui.style.DStyleClass;
- import org.openzen.drawablegui.style.DStylePath;
-
- /**
- *
- * @author Hoofdgebruiker
- */
- public class DInputField implements DComponent {
- public final MutableLiveString value;
- private final ListenerHandle<LiveString.Listener> valueListener;
-
- private final DStyleClass styleClass;
- private final MutableLiveObject<DSizing> sizing = DSizing.create();
- private DIRectangle bounds = DIRectangle.EMPTY;
- private final DDimension preferredWidth;
-
- private DDrawSurface surface;
- private int z;
- private DInputFieldStyle style;
- private DFontMetrics fontMetrics;
- private int cursorFrom = -1;
- private int cursorTo = -1;
-
- private Runnable onEnter = null;
- private Runnable onEscape = null;
-
- private boolean cursorBlink = true;
- private DTimerHandle blinkTimer;
-
- private DDrawnShape shape;
- private DDrawnText text;
- private DDrawnRectangle cursor;
- private DDrawnRectangle selection;
-
- public DInputField(DStyleClass styleClass, MutableLiveString value, DDimension preferredWidth) {
- this.styleClass = styleClass;
- this.value = value;
- this.preferredWidth = preferredWidth;
-
- valueListener = value.addListener((oldValue, newValue) -> handleValueUpdated(newValue));
- cursorFrom = 0;
- cursorTo = value.getValue().length();
- }
-
- public void setOnEnter(Runnable onEnter) {
- this.onEnter = onEnter;
- }
-
- public void setOnEscape(Runnable onEscape) {
- this.onEscape = onEscape;
- }
-
- @Override
- public void close() {
- valueListener.close();
- unmount();
- }
-
- @Override
- public void mount(DStylePath parent, int z, DDrawSurface surface) {
- this.surface = surface;
- this.z = z;
-
- DStylePath path = parent.getChild("input", styleClass);
- style = new DInputFieldStyle(surface.getStylesheet(path));
- fontMetrics = surface.getFontMetrics(style.font);
-
- sizing.setValue(new DSizing(
- preferredWidth.evalInt(surface.getContext()) + style.margin.getHorizontal() + style.border.getPaddingHorizontal(),
- fontMetrics.getAscent() + fontMetrics.getDescent() + style.margin.getVertical() + style.border.getPaddingVertical()));
-
- if (blinkTimer != null)
- blinkTimer.close();
- blinkTimer = surface.getContext().setTimer(300, this::blink);
-
- if (text != null)
- text.close();
- text = surface.drawText(
- z + 2,
- style.font,
- style.color,
- bounds.x + style.margin.left + style.border.getPaddingLeft(),
- bounds.y + style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent(),
- value.getValue());
-
- if (cursor != null)
- cursor.close();
- cursor = surface.fillRect(z + 2, DIRectangle.EMPTY, cursorBlink ? style.cursorColor : 0);
-
- if (selection != null)
- selection.close();
- selection = surface.fillRect(z + 1, DIRectangle.EMPTY, 0);
-
- setCursor(cursorFrom, cursorTo);
- }
-
- @Override
- public void unmount() {
- blinkTimer.close();
-
- if (style != null)
- style.border.close();
- if (shape != null)
- shape.close();
- if (text != null)
- text.close();
- if (cursor != null)
- cursor.close();
- if (selection != null)
- selection.close();
- }
-
- private void blink() {
- cursorBlink = !cursorBlink;
- cursor.setColor(cursorBlink ? style.cursorColor : 0);
- }
-
- @Override
- public LiveObject<DSizing> getSizing() {
- return sizing;
- }
-
- @Override
- public DIRectangle getBounds() {
- return bounds;
- }
-
- @Override
- public int getBaselineY() {
- return style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent();
- }
-
- @Override
- public void setBounds(DIRectangle bounds) {
- this.bounds = bounds;
- setCursor(cursorFrom, cursorTo);
-
- if (shape != null)
- shape.close();
- shape = surface.fillPath(z, style.shape.instance(style.margin.apply(bounds)), DTransform2D.IDENTITY, style.backgroundColor);
- text.setPosition(
- bounds.x + style.margin.left + style.border.getPaddingLeft(),
- bounds.y + style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent());
- style.border.update(surface, z, bounds);
- }
-
- @Override
- public void onMouseEnter(DMouseEvent e) {
- surface.getContext().setCursor(DUIContext.Cursor.TEXT);
- }
-
- @Override
- public void onMouseExit(DMouseEvent e) {
- surface.getContext().setCursor(DUIContext.Cursor.NORMAL);
- }
-
- @Override
- public void onMouseClick(DMouseEvent e) {
- surface.getContext().getWindow().focus(this);
- }
-
- @Override
- public void onKeyPressed(DKeyEvent e) {
- boolean shift = e.has(DKeyEvent.SHIFT);
- switch (e.keyCode) {
- case UP:
- setCursor(0, 0);
- break;
- case DOWN:
- setCursor(value.getValue().length(), value.getValue().length());
- break;
- case LEFT: {
- int to = Math.max(0, cursorTo - 1);
- setCursor(shift ? cursorFrom : to, to);
- break;
- }
- case RIGHT: {
- int to = Math.min(value.getValue().length(), cursorTo + 1);
- setCursor(shift ? cursorFrom : to, to);
- break;
- }
- case DELETE:
- delete();
- break;
- case BACKSPACE:
- backspace();
- break;
- case ENTER:
- enter();
- break;
- case ESCAPE:
- escape();
- break;
- default:
- if (e.character == DKeyEvent.CHAR_UNDEFINED)
- return;
-
- insert(Character.toString(e.character));
- break;
- }
- }
-
- private void setCursor(int from, int to) {
- cursorFrom = from;
- cursorTo = to;
-
- int cursorXFrom = fontMetrics.getWidth(value.getValue(), 0, Math.min(cursorFrom, cursorTo));
- int cursorXTo = fontMetrics.getWidth(value.getValue(), 0, Math.max(cursorFrom, cursorTo));
- if (cursorFrom != cursorTo) {
- selection.setRectangle(new DIRectangle(
- bounds.x + style.margin.left + style.border.getPaddingLeft() + cursorXFrom,
- bounds.y + style.margin.top + style.border.getPaddingTop(),
- cursorXTo - cursorXFrom,
- fontMetrics.getAscent() + fontMetrics.getDescent()));
- selection.setColor(style.selectionColor);
- } else {
- selection.setColor(0);
- }
-
- cursor.setRectangle(new DIRectangle(
- bounds.x + style.margin.left + style.border.getPaddingLeft() + cursorXTo,
- bounds.y + style.margin.top + style.border.getPaddingTop(),
- style.cursorWidth,
- fontMetrics.getAscent() + fontMetrics.getDescent()));
- }
-
- private void handleValueUpdated(String newValue) {
- if (text != null)
- text.close();
- text = surface.drawText(
- z + 2,
- style.font,
- style.color,
- bounds.x + style.margin.left + style.border.getPaddingLeft(),
- bounds.y + style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent(),
- value.getValue());
- }
-
- private void backspace() {
- if (cursorFrom == 0 && cursorTo == 0)
- return;
-
- if (cursorFrom == cursorTo) {
- value.setValue(value.getValue().substring(0, cursorFrom - 1) + value.getValue().substring(cursorFrom));
- setCursor(cursorFrom - 1, cursorTo - 1);
- } else {
- int from = Math.min(cursorFrom, cursorTo);
- int to = Math.max(cursorFrom, cursorTo);
- setCursor(from, from);
- value.setValue(value.getValue().substring(0, from) + value.getValue().substring(to));
- }
- }
-
- private void delete() {
- if (cursorFrom == 0 && cursorTo == 0)
- return;
-
- if (cursorFrom == cursorTo) {
- if (cursorFrom < value.getValue().length()) {
- value.setValue(value.getValue().substring(0, cursorFrom) + value.getValue().substring(cursorFrom + 1));
- }
- } else {
- int from = Math.min(cursorFrom, cursorTo);
- int to = Math.max(cursorFrom, cursorTo);
- setCursor(from, from);
- value.setValue(value.getValue().substring(0, from) + value.getValue().substring(to));
- }
- }
-
- private void insert(String value) {
- int from = Math.min(cursorFrom, cursorTo);
- int to = Math.max(cursorFrom, cursorTo);
- this.value.setValue(this.value.getValue().substring(0, from) + value + this.value.getValue().substring(to));
- setCursor(from + value.length(), from + value.length());
- }
-
- private void enter() {
- if (onEnter != null)
- onEnter.run();
- }
-
- private void escape() {
- if (onEscape != null)
- onEscape.run();
- }
- }
|