From 36cfe3813a8a7f07682e8a540c3ed59aa2781793 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 22:35:57 +0100 Subject: [PATCH] taking over components --- src/org/newdawn/slick/gui/TextField.java | 526 +++++------------- .../core/components/ActionListener.java | 24 + .../opsudance/core/components/Component.java | 60 ++ .../core/state/ComplexOpsuState.java | 124 +++++ 4 files changed, 334 insertions(+), 400 deletions(-) create mode 100644 src/yugecin/opsudance/core/components/ActionListener.java create mode 100644 src/yugecin/opsudance/core/components/Component.java create mode 100644 src/yugecin/opsudance/core/state/ComplexOpsuState.java diff --git a/src/org/newdawn/slick/gui/TextField.java b/src/org/newdawn/slick/gui/TextField.java index 6696ff9f..a989d2c4 100644 --- a/src/org/newdawn/slick/gui/TextField.java +++ b/src/org/newdawn/slick/gui/TextField.java @@ -34,232 +34,70 @@ import org.newdawn.slick.Font; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; import org.newdawn.slick.geom.Rectangle; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.components.ActionListener; +import yugecin.opsudance.core.components.Component; /** * A single text field supporting text entry * * @author kevin */ -@SuppressWarnings("unused") -public class TextField extends AbstractComponent { - /** The key repeat interval */ +public class TextField extends Component { + private static final int INITIAL_KEY_REPEAT_INTERVAL = 400; - /** The key repeat interval */ private static final int KEY_REPEAT_INTERVAL = 50; + + private final DisplayContainer displayContainer; - /** The width of the field */ - private int width; - - /** The height of the field */ - private int height; - - /** The location in the X coordinate */ - protected int x; - - /** The location in the Y coordinate */ - protected int y; - - /** The maximum number of characters allowed to be input */ + private String value = ""; + private Font font; private int maxCharacter = 10000; - /** The value stored in the text field */ - private String value = ""; + private Color borderCol = Color.white; + private Color textCol = Color.white; + private Color backgroundCol = new Color(0, 0, 0, 0.5f); - /** The font used to render text in the field */ - private Font font; - - /** The border color - null if no border */ - private Color border = Color.white; - - /** The text color */ - private Color text = Color.white; - - /** The background color - null if no background */ - private Color background = new Color(0, 0, 0, 0.5f); - - /** The current cursor position */ private int cursorPos; - - /** True if the cursor should be visible */ - private boolean visibleCursor = true; - - /** The last key pressed */ private int lastKey = -1; - - /** The last character pressed */ private char lastChar = 0; - - /** The time since last key repeat */ private long repeatTimer; - - /** The text before the paste in */ - private String oldText; - - /** The cursor position before the paste */ - private int oldCursorPos; - - /** True if events should be consumed by the field */ - private boolean consume = true; - - /** - * Create a new text field - * - * @param container - * The container rendering this field - * @param font - * The font to use in the text field - * @param x - * The x coordinate of the top left corner of the text field - * @param y - * The y coordinate of the top left corner of the text field - * @param width - * The width of the text field - * @param height - * The height of the text field - * @param listener - * The listener to add to the text field - */ - public TextField(GUIContext container, Font font, int x, int y, int width, - int height, ComponentListener listener) { - this(container,font,x,y,width,height); - addListener(listener); - } - - /** - * Create a new text field - * - * @param container - * The container rendering this field - * @param font - * The font to use in the text field - * @param x - * The x coordinate of the top left corner of the text field - * @param y - * The y coordinate of the top left corner of the text field - * @param width - * The width of the text field - * @param height - * The height of the text field - */ - public TextField(GUIContext container, Font font, int x, int y, int width, - int height) { - super(container); + private ActionListener listener; + + public TextField(DisplayContainer displayContainer, Font font, int x, int y, int width, int height) { + this.displayContainer = displayContainer; this.font = font; - - setLocation(x, y); + this.x = x; + this.y = y; this.width = width; this.height = height; } - /** - * Indicate if the input events should be consumed by this field - * - * @param consume True if events should be consumed by this field - */ - public void setConsumeEvents(boolean consume) { - this.consume = consume; + public void setListener(ActionListener listener) { + this.listener = listener; } - - /** - * Deactivate the key input handling for this field - */ - public void deactivate() { - setFocus(false); + + public void setBorderColor(Color border) { + this.borderCol = border; } - - /** - * Moves the component. - * - * @param x - * X coordinate - * @param y - * Y coordinate - */ + + public void setTextColor(Color text) { + this.textCol = text; + } + + public void setBackgroundColor(Color background) { + this.backgroundCol = background; + } + @Override - public void setLocation(int x, int y) { - this.x = x; - this.y = y; + public boolean isFocusable() { + return true; } - /** - * Returns the position in the X coordinate - * - * @return x - */ - @Override - public int getX() { - return x; - } - - /** - * Returns the position in the Y coordinate - * - * @return y - */ - @Override - public int getY() { - return y; - } - - /** - * Get the width of the component - * - * @return The width of the component - */ - @Override - public int getWidth() { - return width; - } - - /** - * Get the height of the component - * - * @return The height of the component - */ - @Override - public int getHeight() { - return height; - } - - /** - * Set the background color. Set to null to disable the background - * - * @param color - * The color to use for the background - */ - public void setBackgroundColor(Color color) { - background = color; - } - - /** - * Set the border color. Set to null to disable the border - * - * @param color - * The color to use for the border - */ - public void setBorderColor(Color color) { - border = color; - } - - /** - * Set the text color. - * - * @param color - * The color to use for the text - */ - public void setTextColor(Color color) { - text = color; - } - - /** - * @see org.newdawn.slick.gui.AbstractComponent#render(org.newdawn.slick.gui.GUIContext, - * org.newdawn.slick.Graphics) - */ - @Override - public void render(GUIContext container, Graphics g) { + public void render(Graphics g) { if (lastKey != -1) { - if (input.isKeyDown(lastKey)) { + if (displayContainer.input.isKeyDown(lastKey)) { if (repeatTimer < System.currentTimeMillis()) { repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL; keyPressed(lastKey, lastChar); @@ -274,11 +112,11 @@ public class TextField extends AbstractComponent { // Someone could have set a color for me to blend... Color clr = g.getColor(); - if (background != null) { - g.setColor(background.multiply(clr)); + if (backgroundCol != null) { + g.setColor(backgroundCol.multiply(clr)); g.fillRect(x, y, width, height); } - g.setColor(text.multiply(clr)); + g.setColor(textCol.multiply(clr)); Font temp = g.getFont(); int cpos = font.getWidth(value.substring(0, cursorPos)); @@ -291,14 +129,14 @@ public class TextField extends AbstractComponent { g.setFont(font); g.drawString(value, x + 1, y + 1); - if (hasFocus() && visibleCursor) { - g.drawString("_", x + 1 + cpos + 2, y + 1); + if (focused) { + g.drawString("|", x + 1 + cpos + 2, y + 1); } g.translate(-tx - 2, 0); - if (border != null) { - g.setColor(border.multiply(clr)); + if (borderCol != null) { + g.setColor(borderCol.multiply(clr)); g.drawRect(x, y, width, height); } g.setColor(clr); @@ -307,21 +145,10 @@ public class TextField extends AbstractComponent { g.setClip(oldClip); } - /** - * Get the value in the text field - * - * @return The value in the text field - */ public String getText() { return value; } - /** - * Set the value to be displayed in the text field - * - * @param value - * The value to be displayed in the text field - */ public void setText(String value) { this.value = value; if (cursorPos > value.length()) { @@ -329,35 +156,6 @@ public class TextField extends AbstractComponent { } } - /** - * Set the position of the cursor - * - * @param pos - * The new position of the cursor - */ - public void setCursorPos(int pos) { - cursorPos = pos; - if (cursorPos > value.length()) { - cursorPos = value.length(); - } - } - - /** - * Indicate whether the mouse cursor should be visible or not - * - * @param visibleCursor - * True if the mouse cursor should be visible - */ - public void setCursorVisible(boolean visibleCursor) { - this.visibleCursor = visibleCursor; - } - - /** - * Set the length of the allowed input - * - * @param length - * The length of the allowed input - */ public void setMaxLength(int length) { maxCharacter = length; if (value.length() > maxCharacter) { @@ -365,173 +163,101 @@ public class TextField extends AbstractComponent { } } - /** - * Do the paste into the field, overrideable for custom behaviour - * - * @param text The text to be pasted in - */ protected void doPaste(String text) { - recordOldPosition(); - for (int i=0;i 0) { + cursorPos--; + } + // Nobody more will be notified + if (consume) { + container.getInput().consumeEvent(); + } + */ } else if (key == Input.KEY_RIGHT) { /* + if (cursorPos < value.length()) { + cursorPos++; + } + // Nobody more will be notified + if (consume) { + container.getInput().consumeEvent(); + } + */ } else if (key == Input.KEY_BACK) { + if ((cursorPos > 0) && (value.length() > 0)) { + if (displayContainer.input.isKeyDown(Input.KEY_LCONTROL) || displayContainer.input.isKeyDown(Input.KEY_RCONTROL)) { + int sp = 0; + boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1)); + boolean charSeen = false; + for (int i = cursorPos - 1; i >= 0; i--) { + boolean isSpace = Character.isWhitespace(value.charAt(i)); + if (!startSpace && isSpace) { + sp = i; + break; + } else if (startSpace) { + if (charSeen && isSpace) { + sp = i + 1; + break; + } else if (!charSeen && !isSpace) + charSeen = true; + } + } + if (cursorPos < value.length()) + value = value.substring(0, sp) + value.substring(cursorPos); + else + value = value.substring(0, sp); + cursorPos = sp; + } else { + if (cursorPos < value.length()) { + value = value.substring(0, cursorPos - 1) + + value.substring(cursorPos); + } else { + value = value.substring(0, cursorPos - 1); } - return; - } */ - - // alt and control keys don't come through here - /* if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) { - return; - } */ - if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) { - return; - } - } - - if (lastKey != key) { - lastKey = key; - repeatTimer = System.currentTimeMillis() + INITIAL_KEY_REPEAT_INTERVAL; - } else { - repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL; - } - lastChar = c; - - if (key == Input.KEY_LEFT) { /* - if (cursorPos > 0) { cursorPos--; } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - */ } else if (key == Input.KEY_RIGHT) { /* - if (cursorPos < value.length()) { - cursorPos++; - } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - */ } else if (key == Input.KEY_BACK) { - if ((cursorPos > 0) && (value.length() > 0)) { - if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) { - int sp = 0; - boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1)); - boolean charSeen = false; - for (int i = cursorPos - 1; i >= 0; i--) { - boolean isSpace = Character.isWhitespace(value.charAt(i)); - if (!startSpace && isSpace) { - sp = i; - break; - } else if (startSpace) { - if (charSeen && isSpace) { - sp = i + 1; - break; - } else if (!charSeen && !isSpace) - charSeen = true; - } - } - if (cursorPos < value.length()) - value = value.substring(0, sp) + value.substring(cursorPos); - else - value = value.substring(0, sp); - cursorPos = sp; - } else { - if (cursorPos < value.length()) { - value = value.substring(0, cursorPos - 1) - + value.substring(cursorPos); - } else { - value = value.substring(0, cursorPos - 1); - } - cursorPos--; - } - } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - } else if (key == Input.KEY_DELETE) { - if (value.length() > cursorPos) { - value = value.substring(0,cursorPos) + value.substring(cursorPos+1); - } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - } else if ((c < 127) && (c > 31) && (value.length() < maxCharacter)) { - if (cursorPos < value.length()) { - value = value.substring(0, cursorPos) + c - + value.substring(cursorPos); - } else { - value = value.substring(0, cursorPos) + c; - } - cursorPos++; - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - } else if (key == Input.KEY_RETURN) { - notifyListeners(); - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } } - + } else if (key == Input.KEY_DELETE) { + if (value.length() > cursorPos) { + value = value.substring(0,cursorPos) + value.substring(cursorPos+1); + } + } else if ((c < 127) && (c > 31) && (value.length() < maxCharacter)) { + if (cursorPos < value.length()) { + value = value.substring(0, cursorPos) + c + + value.substring(cursorPos); + } else { + value = value.substring(0, cursorPos) + c; + } + cursorPos++; + } else if (key == Input.KEY_RETURN) { + if (listener != null) { + listener.onAction(); + } } + } - /** - * @see org.newdawn.slick.gui.AbstractComponent#setFocus(boolean) - */ - @Override - public void setFocus(boolean focus) { - lastKey = -1; - - super.setFocus(focus); - } } diff --git a/src/yugecin/opsudance/core/components/ActionListener.java b/src/yugecin/opsudance/core/components/ActionListener.java new file mode 100644 index 00000000..b1e05733 --- /dev/null +++ b/src/yugecin/opsudance/core/components/ActionListener.java @@ -0,0 +1,24 @@ +/* + * opsu!dance - fork of opsu! with cursordance auto + * Copyright (C) 2017 yugecin + * + * opsu!dance is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu!dance is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!dance. If not, see . + */ +package yugecin.opsudance.core.components; + +public interface ActionListener { + + void onAction(); + +} diff --git a/src/yugecin/opsudance/core/components/Component.java b/src/yugecin/opsudance/core/components/Component.java new file mode 100644 index 00000000..20e4f777 --- /dev/null +++ b/src/yugecin/opsudance/core/components/Component.java @@ -0,0 +1,60 @@ +/* + * opsu!dance - fork of opsu! with cursordance auto + * Copyright (C) 2017 yugecin + * + * opsu!dance is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu!dance is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!dance. If not, see . + */ +package yugecin.opsudance.core.components; + +import org.newdawn.slick.Graphics; + +public abstract class Component { + + public int width; + public int height; + public int x; + public int y; + + protected boolean focused; + protected boolean hovered; + + public abstract boolean isFocusable(); + + public boolean isHovered() { + return hovered; + } + + public void updateHover(int x, int y) { + this.hovered = this.x <= x && x <= this.x + width && this.y <= y && y <= this.y + height; + } + + public void mouseReleased(int button) { + } + + public void preRenderUpdate() { + } + + public abstract void render(Graphics g); + + public void keyPressed(int key, char c) { + } + + public void keyReleased(int key, char c) { + } + + public void setFocused(boolean focused) { + this.focused = focused; + } + +} diff --git a/src/yugecin/opsudance/core/state/ComplexOpsuState.java b/src/yugecin/opsudance/core/state/ComplexOpsuState.java new file mode 100644 index 00000000..ff3da952 --- /dev/null +++ b/src/yugecin/opsudance/core/state/ComplexOpsuState.java @@ -0,0 +1,124 @@ +/* + * opsu!dance - fork of opsu! with cursordance auto + * Copyright (C) 2017 yugecin + * + * opsu!dance is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu!dance is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!dance. If not, see . + */ +package yugecin.opsudance.core.state; + +import org.newdawn.slick.Graphics; +import org.newdawn.slick.Input; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.components.Component; + +import java.util.LinkedList; + +public class ComplexOpsuState extends BaseOpsuState { + + protected final LinkedList components; + + private Component focusedComponent; + + public ComplexOpsuState(DisplayContainer displayContainer) { + super(displayContainer); + this.components = new LinkedList<>(); + } + + public final void focusComponent(Component component) { + if (!component.isFocusable()) { + return; + } + if (focusedComponent != null) { + focusedComponent.setFocused(false); + } + focusedComponent = component; + component.setFocused(true); + } + + public boolean isAnyComponentFocused() { + return focusedComponent != null; + } + + @Override + public boolean mouseReleased(int button, int x, int y) { + if (focusedComponent == null) { + for (Component component : components) { + if (!component.isFocusable()) { + continue; + } + component.updateHover(x, y); + if (component.isHovered()) { + focusedComponent = component; + focusedComponent.setFocused(true); + return true; + } + } + return false; + } + focusedComponent.updateHover(x, y); + if (focusedComponent.isHovered()) { + focusedComponent.mouseReleased(button); + return true; + } + focusedComponent.setFocused(false); + focusedComponent = null; + return false; + } + + @Override + public void preRenderUpdate() { + super.preRenderUpdate(); + for (Component component : components) { + component.updateHover(displayContainer.mouseX, displayContainer.mouseY); + component.preRenderUpdate(); + } + } + + @Override + public void render(Graphics g) { + super.render(g); + for (Component component : components) { + component.render(g); + } + } + + @Override + public boolean keyReleased(int key, char c) { + if (focusedComponent != null) { + if (key == Input.KEY_ESCAPE) { + focusedComponent.setFocused(false); + focusedComponent = null; + return true; + } + focusedComponent.keyReleased(key, c); + return true; + } + return false; + } + + @Override + public boolean keyPressed(int key, char c) { + if (focusedComponent != null) { + if (key == Input.KEY_ESCAPE) { + focusedComponent.setFocused(false); + focusedComponent = null; + return true; + } + focusedComponent.keyPressed(key, c); + return true; + } + return false; + } + +}