diff --git a/pom.xml b/pom.xml
index ca5097f9..241dc9d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -115,6 +115,7 @@
org/newdawn/slick/GameContainer.*
org/newdawn/slick/Image.*
org/newdawn/slick/Music.*
+ org/newdawn/slick/gui/TextField.*
org/newdawn/slick/openal/AudioInputStream*
org/newdawn/slick/openal/OpenALStreamPlayer*
org/newdawn/slick/openal/SoundStore*
diff --git a/src/itdelatrisu/opsu/OsuGroupList.java b/src/itdelatrisu/opsu/OsuGroupList.java
index d6bbf363..bbfe4a3f 100644
--- a/src/itdelatrisu/opsu/OsuGroupList.java
+++ b/src/itdelatrisu/opsu/OsuGroupList.java
@@ -254,6 +254,7 @@ public class OsuGroupList {
/**
* Returns the OsuGroupNode at an index, disregarding expansions.
+ * @param index the node index
*/
public OsuGroupNode getBaseNode(int index) {
if (index < 0 || index >= size())
diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java
index a38f0316..6c84e7ad 100644
--- a/src/itdelatrisu/opsu/audio/MusicController.java
+++ b/src/itdelatrisu/opsu/audio/MusicController.java
@@ -111,7 +111,10 @@ public class MusicController {
player = new Music(file.getPath(), true);
player.addListener(new MusicListener() {
@Override
- public void musicEnded(Music music) { trackEnded = true; }
+ public void musicEnded(Music music) {
+ if (music == player) // don't fire if music swapped
+ trackEnded = true;
+ }
@Override
public void musicSwapped(Music music, Music newMusic) {}
diff --git a/src/itdelatrisu/opsu/db/OsuDB.java b/src/itdelatrisu/opsu/db/OsuDB.java
index d73c946c..52466eee 100644
--- a/src/itdelatrisu/opsu/db/OsuDB.java
+++ b/src/itdelatrisu/opsu/db/OsuDB.java
@@ -76,12 +76,6 @@ public class OsuDB {
// create the database
createDatabase();
- // retrieve the cache size
- getCacheSize();
-
- // check the database version
- checkVersion();
-
// prepare sql statements
try {
insertStmt = connection.prepareStatement(
@@ -96,6 +90,12 @@ public class OsuDB {
} catch (SQLException e) {
ErrorHandler.error("Failed to prepare beatmap statements.", e, true);
}
+
+ // retrieve the cache size
+ getCacheSize();
+
+ // check the database version
+ checkVersion();
}
/**
diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java
index 8a337c55..c83c25c3 100644
--- a/src/itdelatrisu/opsu/states/SongMenu.java
+++ b/src/itdelatrisu/opsu/states/SongMenu.java
@@ -199,6 +199,9 @@ public class SongMenu extends BasicGameState {
/** Time, in milliseconds, for fading the search bar. */
private int searchTransitionTimer = SEARCH_TRANSITION_TIME;
+ /** The text length of the last string in the search TextField. */
+ private int lastSearchTextLength = -1;
+
// game-related variables
private GameContainer container;
private StateBasedGame game;
@@ -831,11 +834,14 @@ public class SongMenu extends BasicGameState {
if ((c > 31 && c < 127) || key == Input.KEY_BACK) {
searchTimer = 0;
int textLength = search.getText().length();
- if (key == Input.KEY_BACK) {
- if (textLength == 0)
+ if (lastSearchTextLength != textLength) {
+ if (key == Input.KEY_BACK) {
+ if (textLength == 0)
+ searchTransitionTimer = 0;
+ } else if (textLength == 1)
searchTransitionTimer = 0;
- } else if (textLength == 1)
- searchTransitionTimer = 0;
+ lastSearchTextLength = textLength;
+ }
}
break;
}
diff --git a/src/org/newdawn/slick/gui/TextField.java b/src/org/newdawn/slick/gui/TextField.java
new file mode 100644
index 00000000..6696ff9f
--- /dev/null
+++ b/src/org/newdawn/slick/gui/TextField.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2013, Slick2D
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the Slick2D nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.newdawn.slick.gui;
+
+import org.lwjgl.Sys;
+import org.newdawn.slick.Color;
+import org.newdawn.slick.Font;
+import org.newdawn.slick.Graphics;
+import org.newdawn.slick.Input;
+import org.newdawn.slick.geom.Rectangle;
+
+/**
+ * A single text field supporting text entry
+ *
+ * @author kevin
+ */
+@SuppressWarnings("unused")
+public class TextField extends AbstractComponent {
+ /** The key repeat interval */
+ private static final int INITIAL_KEY_REPEAT_INTERVAL = 400;
+ /** The key repeat interval */
+ private static final int KEY_REPEAT_INTERVAL = 50;
+
+ /** 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 int maxCharacter = 10000;
+
+ /** The value stored in the text field */
+ private String value = "";
+
+ /** 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);
+
+ this.font = font;
+
+ setLocation(x, 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;
+ }
+
+ /**
+ * Deactivate the key input handling for this field
+ */
+ public void deactivate() {
+ setFocus(false);
+ }
+
+ /**
+ * Moves the component.
+ *
+ * @param x
+ * X coordinate
+ * @param y
+ * Y coordinate
+ */
+ @Override
+ public void setLocation(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * 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) {
+ if (lastKey != -1) {
+ if (input.isKeyDown(lastKey)) {
+ if (repeatTimer < System.currentTimeMillis()) {
+ repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
+ keyPressed(lastKey, lastChar);
+ }
+ } else {
+ lastKey = -1;
+ }
+ }
+ Rectangle oldClip = g.getClip();
+ g.setWorldClip(x,y,width, height);
+
+ // Someone could have set a color for me to blend...
+ Color clr = g.getColor();
+
+ if (background != null) {
+ g.setColor(background.multiply(clr));
+ g.fillRect(x, y, width, height);
+ }
+ g.setColor(text.multiply(clr));
+ Font temp = g.getFont();
+
+ int cpos = font.getWidth(value.substring(0, cursorPos));
+ int tx = 0;
+ if (cpos > width) {
+ tx = width - cpos - font.getWidth("_");
+ }
+
+ g.translate(tx + 2, 0);
+ g.setFont(font);
+ g.drawString(value, x + 1, y + 1);
+
+ if (hasFocus() && visibleCursor) {
+ g.drawString("_", x + 1 + cpos + 2, y + 1);
+ }
+
+ g.translate(-tx - 2, 0);
+
+ if (border != null) {
+ g.setColor(border.multiply(clr));
+ g.drawRect(x, y, width, height);
+ }
+ g.setColor(clr);
+ g.setFont(temp);
+ g.clearWorldClip();
+ 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()) {
+ cursorPos = value.length();
+ }
+ }
+
+ /**
+ * 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) {
+ value = value.substring(0, maxCharacter);
+ }
+ }
+
+ /**
+ * 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 (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();
+ }
+ }
+
+ }
+ }
+
+ /**
+ * @see org.newdawn.slick.gui.AbstractComponent#setFocus(boolean)
+ */
+ @Override
+ public void setFocus(boolean focus) {
+ lastKey = -1;
+
+ super.setFocus(focus);
+ }
+}