Made DropdownMenu extend Slick's AbstractComponent class.
Clicks and animation updates are now handled internally within the DropdownMenu class, which should simplify usage a bit. Override menuClicked() and itemSelected() instead for event handling. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
7f1193bb77
commit
831c297ece
|
@ -331,8 +331,35 @@ public class DownloadsMenu extends BasicGameState {
|
||||||
|
|
||||||
// dropdown menu
|
// dropdown menu
|
||||||
int serverWidth = (int) (width * 0.12f);
|
int serverWidth = (int) (width * 0.12f);
|
||||||
serverMenu = new DropdownMenu<DownloadServer>(SERVERS,
|
serverMenu = new DropdownMenu<DownloadServer>(container, SERVERS,
|
||||||
baseX + searchWidth + buttonMarginX * 3f + resetButtonWidth + rankedButtonWidth, searchY, serverWidth);
|
baseX + searchWidth + buttonMarginX * 3f + resetButtonWidth + rankedButtonWidth, searchY, serverWidth) {
|
||||||
|
@Override
|
||||||
|
public void itemSelected(int index, DownloadServer item) {
|
||||||
|
resultList = null;
|
||||||
|
startResult = 0;
|
||||||
|
focusResult = -1;
|
||||||
|
totalResults = 0;
|
||||||
|
page = 0;
|
||||||
|
pageResultTotal = 1;
|
||||||
|
pageDir = Page.RESET;
|
||||||
|
searchResultString = "Loading data from server...";
|
||||||
|
lastQuery = null;
|
||||||
|
pageDir = Page.RESET;
|
||||||
|
if (searchQuery != null)
|
||||||
|
searchQuery.interrupt();
|
||||||
|
resetSearchTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean menuClicked(int index) {
|
||||||
|
// block input during beatmap importing
|
||||||
|
if (importThread != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
serverMenu.setBackgroundColor(Colors.BLACK_BG_HOVER);
|
serverMenu.setBackgroundColor(Colors.BLACK_BG_HOVER);
|
||||||
serverMenu.setBorderColor(Color.black);
|
serverMenu.setBorderColor(Color.black);
|
||||||
serverMenu.setChevronRightColor(Color.white);
|
serverMenu.setChevronRightColor(Color.white);
|
||||||
|
@ -428,7 +455,7 @@ public class DownloadsMenu extends BasicGameState {
|
||||||
rankedButton.draw(Color.magenta);
|
rankedButton.draw(Color.magenta);
|
||||||
|
|
||||||
// dropdown menu
|
// dropdown menu
|
||||||
serverMenu.draw(g, mouseX, mouseY);
|
serverMenu.render(container, g);
|
||||||
|
|
||||||
// importing beatmaps
|
// importing beatmaps
|
||||||
if (importThread != null) {
|
if (importThread != null) {
|
||||||
|
@ -460,7 +487,6 @@ public class DownloadsMenu extends BasicGameState {
|
||||||
importButton.hoverUpdate(delta, mouseX, mouseY);
|
importButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
resetButton.hoverUpdate(delta, mouseX, mouseY);
|
resetButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
rankedButton.hoverUpdate(delta, mouseX, mouseY);
|
rankedButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
serverMenu.update(delta);
|
|
||||||
|
|
||||||
// focus timer
|
// focus timer
|
||||||
if (focusResult != -1 && focusTimer < FOCUS_DELAY)
|
if (focusResult != -1 && focusTimer < FOCUS_DELAY)
|
||||||
|
@ -523,29 +549,6 @@ public class DownloadsMenu extends BasicGameState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dropdown menu
|
|
||||||
int oldServerIndex = serverMenu.getSelectedIndex(), serverMenuClickResult = serverMenu.click(x, y);
|
|
||||||
if (serverMenuClickResult > -2) {
|
|
||||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
|
||||||
if (serverMenuClickResult == -1 || serverMenuClickResult == oldServerIndex)
|
|
||||||
return;
|
|
||||||
|
|
||||||
resultList = null;
|
|
||||||
startResult = 0;
|
|
||||||
focusResult = -1;
|
|
||||||
totalResults = 0;
|
|
||||||
page = 0;
|
|
||||||
pageResultTotal = 1;
|
|
||||||
pageDir = Page.RESET;
|
|
||||||
searchResultString = "Loading data from server...";
|
|
||||||
lastQuery = null;
|
|
||||||
pageDir = Page.RESET;
|
|
||||||
if (searchQuery != null)
|
|
||||||
searchQuery.interrupt();
|
|
||||||
resetSearchTimer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// search results
|
// search results
|
||||||
DownloadNode[] nodes = resultList;
|
DownloadNode[] nodes = resultList;
|
||||||
if (nodes != null) {
|
if (nodes != null) {
|
||||||
|
@ -865,6 +868,7 @@ public class DownloadsMenu extends BasicGameState {
|
||||||
importButton.resetHover();
|
importButton.resetHover();
|
||||||
resetButton.resetHover();
|
resetButton.resetHover();
|
||||||
rankedButton.resetHover();
|
rankedButton.resetHover();
|
||||||
|
serverMenu.activate();
|
||||||
serverMenu.reset();
|
serverMenu.reset();
|
||||||
focusResult = -1;
|
focusResult = -1;
|
||||||
startResult = 0;
|
startResult = 0;
|
||||||
|
@ -881,6 +885,7 @@ public class DownloadsMenu extends BasicGameState {
|
||||||
public void leave(GameContainer container, StateBasedGame game)
|
public void leave(GameContainer container, StateBasedGame game)
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
search.setFocus(false);
|
search.setFocus(false);
|
||||||
|
serverMenu.deactivate();
|
||||||
SoundController.stopTrack();
|
SoundController.stopTrack();
|
||||||
MusicController.resume();
|
MusicController.resume();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,31 @@ import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Font;
|
import org.newdawn.slick.Font;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
|
import org.newdawn.slick.Input;
|
||||||
|
import org.newdawn.slick.SlickException;
|
||||||
import org.newdawn.slick.UnicodeFont;
|
import org.newdawn.slick.UnicodeFont;
|
||||||
|
import org.newdawn.slick.gui.AbstractComponent;
|
||||||
|
import org.newdawn.slick.gui.GUIContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple dropdown menu.
|
* Simple dropdown menu.
|
||||||
|
* <p>
|
||||||
|
* Basic usage:
|
||||||
|
* <ul>
|
||||||
|
* <li>Override {@link #menuClicked(int)} to perform actions when the menu is clicked
|
||||||
|
* (e.g. play a sound effect, block input under certain conditions).
|
||||||
|
* <li>Override {@link #itemSelected(int, Object)} to perform actions when a new item is selected.
|
||||||
|
* <li>Call {@link #activate()}/{@link #deactivate()} whenever the component is needed
|
||||||
|
* (e.g. in a state's {@code enter} and {@code leave} events.
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class DropdownMenu<E> {
|
public class DropdownMenu<E> extends AbstractComponent {
|
||||||
/** Padding ratios for drawing. */
|
/** Padding ratios for drawing. */
|
||||||
private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f;
|
private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f;
|
||||||
|
|
||||||
|
/** Whether this component is active. */
|
||||||
|
private boolean active;
|
||||||
|
|
||||||
/** The menu items. */
|
/** The menu items. */
|
||||||
private E[] items;
|
private E[] items;
|
||||||
|
|
||||||
|
@ -50,6 +66,9 @@ public class DropdownMenu<E> {
|
||||||
/** The expanding animation progress. */
|
/** The expanding animation progress. */
|
||||||
private AnimatedValue expandProgress = new AnimatedValue(300, 0f, 1f, AnimationEquation.LINEAR);
|
private AnimatedValue expandProgress = new AnimatedValue(300, 0f, 1f, AnimationEquation.LINEAR);
|
||||||
|
|
||||||
|
/** The last update time, in milliseconds. */
|
||||||
|
private long lastUpdateTime;
|
||||||
|
|
||||||
/** The top-left coordinates. */
|
/** The top-left coordinates. */
|
||||||
private float x, y;
|
private float x, y;
|
||||||
|
|
||||||
|
@ -76,39 +95,44 @@ public class DropdownMenu<E> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new dropdown menu.
|
* Creates a new dropdown menu.
|
||||||
|
* @param container the container rendering this menu
|
||||||
* @param items the list of items (with names given as their {@code toString()} methods)
|
* @param items the list of items (with names given as their {@code toString()} methods)
|
||||||
* @param x the top-left x coordinate
|
* @param x the top-left x coordinate
|
||||||
* @param y the top-left y coordinate
|
* @param y the top-left y coordinate
|
||||||
*/
|
*/
|
||||||
public DropdownMenu(E[] items, float x, float y) {
|
public DropdownMenu(GUIContext container, E[] items, float x, float y) {
|
||||||
this(items, x, y, 0);
|
this(container, items, x, y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new dropdown menu with the given fonts.
|
* Creates a new dropdown menu with the given fonts.
|
||||||
|
* @param container the container rendering this menu
|
||||||
* @param items the list of items (with names given as their {@code toString()} methods)
|
* @param items the list of items (with names given as their {@code toString()} methods)
|
||||||
* @param x the top-left x coordinate
|
* @param x the top-left x coordinate
|
||||||
* @param y the top-left y coordinate
|
* @param y the top-left y coordinate
|
||||||
* @param normal the normal font
|
* @param normal the normal font
|
||||||
* @param selected the font for the selected item
|
* @param selected the font for the selected item
|
||||||
*/
|
*/
|
||||||
public DropdownMenu(E[] items, float x, float y, UnicodeFont normal, UnicodeFont selected) {
|
public DropdownMenu(GUIContext container, E[] items, float x, float y, UnicodeFont normal, UnicodeFont selected) {
|
||||||
this(items, x, y, 0, normal, selected);
|
this(container, items, x, y, 0, normal, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new dropdown menu with the given width.
|
* Creates a new dropdown menu with the given width.
|
||||||
|
* @param container the container rendering this menu
|
||||||
* @param items the list of items (with names given as their {@code toString()} methods)
|
* @param items the list of items (with names given as their {@code toString()} methods)
|
||||||
* @param x the top-left x coordinate
|
* @param x the top-left x coordinate
|
||||||
* @param y the top-left y coordinate
|
* @param y the top-left y coordinate
|
||||||
* @param width the menu width
|
* @param width the menu width
|
||||||
*/
|
*/
|
||||||
public DropdownMenu(E[] items, float x, float y, int width) {
|
public DropdownMenu(GUIContext container, E[] items, float x, float y, int width) {
|
||||||
|
super(container);
|
||||||
init(items, x, y, width);
|
init(items, x, y, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new dropdown menu with the given width and fonts.
|
* Creates a new dropdown menu with the given width and fonts.
|
||||||
|
* @param container the container rendering this menu
|
||||||
* @param items the list of items (with names given as their {@code toString()} methods)
|
* @param items the list of items (with names given as their {@code toString()} methods)
|
||||||
* @param x the top-left x coordinate
|
* @param x the top-left x coordinate
|
||||||
* @param y the top-left y coordinate
|
* @param y the top-left y coordinate
|
||||||
|
@ -116,7 +140,8 @@ public class DropdownMenu<E> {
|
||||||
* @param normal the normal font
|
* @param normal the normal font
|
||||||
* @param selected the font for the selected item
|
* @param selected the font for the selected item
|
||||||
*/
|
*/
|
||||||
public DropdownMenu(E[] items, float x, float y, int width, UnicodeFont normal, UnicodeFont selected) {
|
public DropdownMenu(GUIContext container, E[] items, float x, float y, int width, UnicodeFont normal, UnicodeFont selected) {
|
||||||
|
super(container);
|
||||||
this.fontNormal = normal;
|
this.fontNormal = normal;
|
||||||
this.fontSelected = selected;
|
this.fontSelected = selected;
|
||||||
init(items, x, y, width);
|
init(items, x, y, width);
|
||||||
|
@ -157,15 +182,29 @@ public class DropdownMenu<E> {
|
||||||
this.width = Math.max(width, minWidth);
|
this.width = Math.max(width, minWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the width of the menu.
|
public void setLocation(int x, int y) {
|
||||||
*/
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() { return (int) x; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() { return (int) y; }
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getWidth() { return width; }
|
public int getWidth() { return width; }
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the height of the base item.
|
public int getHeight() { return (expanded) ? height : baseHeight; }
|
||||||
*/
|
|
||||||
public int getHeight() { return baseHeight; }
|
/** Activates the component. */
|
||||||
|
public void activate() { this.active = true; }
|
||||||
|
|
||||||
|
/** Deactivates the component. */
|
||||||
|
public void deactivate() { this.active = false; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the dropdown menu is currently open.
|
* Returns whether the dropdown menu is currently open.
|
||||||
|
@ -199,14 +238,19 @@ public class DropdownMenu<E> {
|
||||||
return (cx > x && cx < x + width && cy > y && cy < y + baseHeight);
|
return (cx > x && cx < x + width && cy > y && cy < y + baseHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Draws the dropdown menu.
|
public void render(GUIContext container, Graphics g) throws SlickException {
|
||||||
* @param g the graphics context
|
// update animation
|
||||||
* @param cx the mouse x coordinate
|
long time = container.getTime();
|
||||||
* @param cy the mouse y coordinate
|
if (lastUpdateTime > 0) {
|
||||||
*/
|
int delta = (int) (time - lastUpdateTime);
|
||||||
public void draw(Graphics g, float cx, float cy) {
|
expandProgress.update((expanded) ? delta : -delta * 2);
|
||||||
int idx = getIndexAt(cx, cy);
|
}
|
||||||
|
this.lastUpdateTime = time;
|
||||||
|
|
||||||
|
// get parameters
|
||||||
|
Input input = container.getInput();
|
||||||
|
int idx = getIndexAt(input.getMouseX(), input.getMouseY());
|
||||||
float t = expandProgress.getValue();
|
float t = expandProgress.getValue();
|
||||||
if (expanded)
|
if (expanded)
|
||||||
t = AnimationEquation.OUT_CUBIC.calc(t);
|
t = AnimationEquation.OUT_CUBIC.calc(t);
|
||||||
|
@ -274,40 +318,58 @@ public class DropdownMenu<E> {
|
||||||
return (int) ((cy - (y + offsetY)) / offsetY);
|
return (int) ((cy - (y + offsetY)) / offsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the animations by a delta interval.
|
|
||||||
* @param delta the delta interval since the last call
|
|
||||||
*/
|
|
||||||
public void update(int delta) {
|
|
||||||
expandProgress.update((expanded) ? delta : -delta * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a click at the given location.
|
|
||||||
* If the base item is clicked and the menu is unexpanded, it will be expanded;
|
|
||||||
* in all other cases, the menu will be unexpanded. If an item different from
|
|
||||||
* the current one is selected, that item will be selected.
|
|
||||||
* @param cx the x coordinate
|
|
||||||
* @param cy the y coordinate
|
|
||||||
* @return the index of the item at the given location, -1 for the base item,
|
|
||||||
* and -2 if there is no item at the location
|
|
||||||
*/
|
|
||||||
public int click(float cx, float cy) {
|
|
||||||
int idx = getIndexAt(cx, cy);
|
|
||||||
this.expanded = (idx == -1) ? !expanded : false;
|
|
||||||
if (idx >= 0)
|
|
||||||
this.itemIndex = idx;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the menu state.
|
* Resets the menu state.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
this.expanded = false;
|
this.expanded = false;
|
||||||
|
this.lastUpdateTime = 0;
|
||||||
expandProgress.setTime(0);
|
expandProgress.setTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(int button, int x, int y) {
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (button == Input.MOUSE_MIDDLE_BUTTON)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int idx = getIndexAt(x, y);
|
||||||
|
if (idx == -2) {
|
||||||
|
this.expanded = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!menuClicked(idx))
|
||||||
|
return;
|
||||||
|
this.expanded = (idx == -1) ? !expanded : false;
|
||||||
|
if (idx >= 0 && itemIndex != idx) {
|
||||||
|
this.itemIndex = idx;
|
||||||
|
itemSelected(idx, items[idx]);
|
||||||
|
}
|
||||||
|
consumeEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification that a new item was selected (via override).
|
||||||
|
* @param index the index of the item selected
|
||||||
|
* @param item the item selected
|
||||||
|
*/
|
||||||
|
public void itemSelected(int index, E item) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification that the menu was clicked (via override).
|
||||||
|
* @param index the index of the item clicked, or -1 for the base item
|
||||||
|
* @return true to process the click, or false to block/intercept it
|
||||||
|
*/
|
||||||
|
public boolean menuClicked(int index) { return true; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFocus(boolean focus) { /* does not currently use the "focus" concept */ }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(int button, int x, int y) { /* does not currently use the "focus" concept */ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the item at the given index.
|
* Selects the item at the given index.
|
||||||
* @param index the list item index
|
* @param index the list item index
|
||||||
|
|
Loading…
Reference in New Issue
Block a user