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:
Jeffrey Han 2015-09-09 18:57:01 -04:00
parent 7f1193bb77
commit 831c297ece
2 changed files with 142 additions and 75 deletions

View File

@ -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();
} }

View File

@ -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