From 81b71d5703f028f022ba2ac49601b12c20593107 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 22:36:09 +0100 Subject: [PATCH] convert download state --- src/itdelatrisu/opsu/Opsu.java | 2 +- .../opsu/states/DownloadsMenu.java | 302 +++++++------- src/itdelatrisu/opsu/states/MainMenu.java | 10 +- src/itdelatrisu/opsu/ui/DropdownMenu.java | 372 +++++------------- .../core/inject/OpsuDanceInjector.java | 6 +- 5 files changed, 262 insertions(+), 430 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index de11aab1..7547cb0d 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -93,7 +93,7 @@ public class Opsu extends StateBasedGame { addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); addState(new GameRanking(STATE_GAMERANKING)); addState(new OptionsMenu(STATE_OPTIONSMENU)); - addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); + //addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); } /** diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index df4435bc..ed6e47ec 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -51,17 +51,15 @@ import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; import org.newdawn.slick.SlickException; import org.newdawn.slick.gui.TextField; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; -import org.newdawn.slick.state.transition.FadeInTransition; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.ComplexOpsuState; /** * Downloads menu. @@ -69,7 +67,10 @@ import org.newdawn.slick.util.Log; * Players are able to download beatmaps off of various servers and import them * from this state. */ -public class DownloadsMenu extends BasicGameState { +public class DownloadsMenu extends ComplexOpsuState { + + private final InstanceContainer instanceContainer; + /** Delay time, in milliseconds, between each search. */ private static final int SEARCH_DELAY = 700; @@ -288,45 +289,42 @@ public class DownloadsMenu extends BasicGameState { } } - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - - public DownloadsMenu(int state) { - this.state = state; + public DownloadsMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + this.instanceContainer = instanceContainer; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); + public void revalidate() { + super.revalidate(); - int width = container.getWidth(); - int height = container.getHeight(); - float baseX = width * 0.024f; - float searchY = (height * 0.04f) + Fonts.LARGE.getLineHeight(); - float searchWidth = width * 0.3f; + components.clear(); + + int width = displayContainer.width; + int height = displayContainer.height; + int baseX = (int) (width * 0.024f); + int searchY = (int) (height * 0.04f + Fonts.LARGE.getLineHeight()); + int searchWidth = (int) (width * 0.3f); // search searchTimer = SEARCH_DELAY; searchResultString = "Loading data from server..."; - search = new TextField( - container, Fonts.DEFAULT, (int) baseX, (int) searchY, - (int) searchWidth, Fonts.MEDIUM.getLineHeight() - ); + search = new TextField(displayContainer, Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) { + @Override + public boolean isFocusable() { + return false; + } + }; + search.setFocused(true); search.setBackgroundColor(Colors.BLACK_BG_NORMAL); search.setBorderColor(Color.white); search.setTextColor(Color.white); - search.setConsumeEvents(false); search.setMaxLength(255); + components.add(search); // page buttons - float pageButtonY = height * 0.2f; - float pageButtonWidth = width * 0.7f; + int pageButtonY = (int) (height * 0.2f); + int pageButtonWidth = (int) (width * 0.7f); Image prevImg = GameImage.MUSIC_PREVIOUS.getImage(); Image nextImg = GameImage.MUSIC_NEXT.getImage(); prevPage = new MenuButton(prevImg, baseX + prevImg.getWidth() / 2f, @@ -337,25 +335,25 @@ public class DownloadsMenu extends BasicGameState { nextPage.setHoverExpand(1.5f); // buttons - float buttonMarginX = width * 0.004f; - float buttonHeight = height * 0.038f; - float resetWidth = width * 0.085f; - float rankedWidth = width * 0.15f; - float lowerWidth = width * 0.12f; - float topButtonY = searchY + Fonts.MEDIUM.getLineHeight() / 2f; - float lowerButtonY = height * 0.995f - searchY - buttonHeight / 2f; + int buttonMarginX = (int) (width * 0.004f); + int buttonHeight = (int) (height * 0.038f); + int resetWidth = (int) (width * 0.085f); + int rankedWidth = (int) (width * 0.15f); + int lowerWidth = (int) (width * 0.12f); + int topButtonY = (int) (searchY + Fonts.MEDIUM.getLineHeight() / 2f); + int lowerButtonY = (int) (height * 0.995f - searchY - buttonHeight / 2f); Image button = GameImage.MENU_BUTTON_MID.getImage(); Image buttonL = GameImage.MENU_BUTTON_LEFT.getImage(); Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage(); buttonL = buttonL.getScaledCopy(buttonHeight / buttonL.getHeight()); buttonR = buttonR.getScaledCopy(buttonHeight / buttonR.getHeight()); int lrButtonWidth = buttonL.getWidth() + buttonR.getWidth(); - Image resetButtonImage = button.getScaledCopy((int) resetWidth - lrButtonWidth, (int) buttonHeight); - Image rankedButtonImage = button.getScaledCopy((int) rankedWidth - lrButtonWidth, (int) buttonHeight); - Image lowerButtonImage = button.getScaledCopy((int) lowerWidth - lrButtonWidth, (int) buttonHeight); - float resetButtonWidth = resetButtonImage.getWidth() + lrButtonWidth; - float rankedButtonWidth = rankedButtonImage.getWidth() + lrButtonWidth; - float lowerButtonWidth = lowerButtonImage.getWidth() + lrButtonWidth; + Image resetButtonImage = button.getScaledCopy(resetWidth - lrButtonWidth, buttonHeight); + Image rankedButtonImage = button.getScaledCopy(rankedWidth - lrButtonWidth, buttonHeight); + Image lowerButtonImage = button.getScaledCopy(lowerWidth - lrButtonWidth, buttonHeight); + int resetButtonWidth = resetButtonImage.getWidth() + lrButtonWidth; + int rankedButtonWidth = rankedButtonImage.getWidth() + lrButtonWidth; + int lowerButtonWidth = lowerButtonImage.getWidth() + lrButtonWidth; clearButton = new MenuButton(lowerButtonImage, buttonL, buttonR, width * 0.75f + buttonMarginX + lowerButtonWidth / 2f, lowerButtonY); importButton = new MenuButton(lowerButtonImage, buttonL, buttonR, @@ -374,8 +372,8 @@ public class DownloadsMenu extends BasicGameState { // dropdown menu int serverWidth = (int) (width * 0.12f); - serverMenu = new DropdownMenu(container, SERVERS, - baseX + searchWidth + buttonMarginX * 3f + resetButtonWidth + rankedButtonWidth, searchY, serverWidth) { + int x = baseX + searchWidth + buttonMarginX * 3 + resetButtonWidth + rankedButtonWidth; + serverMenu = new DropdownMenu(displayContainer, SERVERS, x, searchY, serverWidth) { @Override public void itemSelected(int index, DownloadServer item) { resultList = null; @@ -388,13 +386,14 @@ public class DownloadsMenu extends BasicGameState { searchResultString = "Loading data from server..."; lastQuery = null; pageDir = Page.RESET; - if (searchQuery != null) + if (searchQuery != null) { searchQuery.interrupt(); + } resetSearchTimer(); } @Override - public boolean menuClicked(int index) { + public boolean canSelect(int index) { // block input during beatmap importing if (importThread != null) return false; @@ -406,28 +405,25 @@ public class DownloadsMenu extends BasicGameState { serverMenu.setBackgroundColor(Colors.BLACK_BG_HOVER); serverMenu.setBorderColor(Color.black); serverMenu.setChevronRightColor(Color.white); + components.add(serverMenu); } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { - int width = container.getWidth(); - int height = container.getHeight(); - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - boolean inDropdownMenu = serverMenu.contains(mouseX, mouseY); + public void render(Graphics g) { + super.render(g); // background GameImage.SEARCH_BG.getImage().draw(); // title - Fonts.LARGE.drawString(width * 0.024f, height * 0.03f, "Download Beatmaps!", Color.white); + Fonts.LARGE.drawString(displayContainer.width * 0.024f, displayContainer.height * 0.03f, "Download Beatmaps!", Color.white); // search g.setColor(Color.white); g.setLineWidth(2f); - search.render(container, g); + search.render(g); Fonts.BOLD.drawString( - search.getX() + search.getWidth() * 0.01f, search.getY() + search.getHeight() * 1.3f, + search.x + search.width * 0.01f, search.y + search.height * 1.3f, searchResultString, Color.white ); @@ -446,7 +442,7 @@ public class DownloadsMenu extends BasicGameState { if (index >= nodes.length) break; nodes[index].drawResult(g, offset + i * DownloadNode.getButtonOffset(), - DownloadNode.resultContains(mouseX, mouseY - offset, i) && !inDropdownMenu, + DownloadNode.resultContains(displayContainer.mouseX, displayContainer.mouseY - offset, i) && !serverMenu.isHovered(), (index == focusResult), (previewID == nodes[index].getID())); } g.clearClip(); @@ -457,9 +453,9 @@ public class DownloadsMenu extends BasicGameState { // pages if (nodes.length > 0) { - float baseX = width * 0.024f; - float buttonY = height * 0.2f; - float buttonWidth = width * 0.7f; + float baseX = displayContainer.width * 0.024f; + float buttonY = displayContainer.height * 0.2f; + float buttonWidth = displayContainer.width * 0.7f; Fonts.BOLD.drawString( baseX + (buttonWidth - Fonts.BOLD.getWidth("Page 1")) / 2f, buttonY - Fonts.BOLD.getLineHeight() * 1.3f, @@ -473,11 +469,11 @@ public class DownloadsMenu extends BasicGameState { } // downloads - float downloadsX = width * 0.75f, downloadsY = search.getY(); + float downloadsX = displayContainer.width * 0.75f, downloadsY = search.y; g.setColor(Colors.BLACK_BG_NORMAL); g.fillRect(downloadsX, downloadsY, - width * 0.25f, height - downloadsY * 2f); - Fonts.LARGE.drawString(downloadsX + width * 0.015f, downloadsY + height * 0.015f, "Downloads", Color.white); + displayContainer.width * 0.25f, displayContainer.height - downloadsY * 2f); + Fonts.LARGE.drawString(downloadsX + displayContainer.width * 0.015f, downloadsY + displayContainer.height * 0.015f, "Downloads", Color.white); int downloadsSize = DownloadList.get().size(); if (downloadsSize > 0) { int maxDownloadsShown = DownloadNode.maxDownloadsShown(); @@ -493,7 +489,7 @@ public class DownloadsMenu extends BasicGameState { if (node == null) break; node.drawDownload(g, i * DownloadNode.getInfoHeight() + offset, index, - DownloadNode.downloadContains(mouseX, mouseY - offset, i)); + DownloadNode.downloadContains(displayContainer.mouseX, displayContainer.mouseY - offset, i)); } g.clearClip(); @@ -510,13 +506,13 @@ public class DownloadsMenu extends BasicGameState { rankedButton.draw(Color.magenta); // dropdown menu - serverMenu.render(container, g); + serverMenu.render(g); // importing beatmaps if (importThread != null) { // darken the screen g.setColor(Colors.BLACK_ALPHA); - g.fillRect(0, 0, width, height); + g.fillRect(0, 0, displayContainer.width, displayContainer.height); UI.drawLoadingProgress(g); } @@ -529,8 +525,10 @@ public class DownloadsMenu extends BasicGameState { } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + super.preRenderUpdate(); + + int delta = displayContainer.renderDelta; UI.update(delta); if (importThread == null) MusicController.loopTrackIfEnded(false); @@ -547,11 +545,12 @@ public class DownloadsMenu extends BasicGameState { // focus new beatmap // NOTE: This can't be called in another thread because it makes OpenGL calls. - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(importedNode, -1, true, true); + instanceContainer.provide(SongMenu.class).setFocus(importedNode, -1, true, true); } importThread = null; } - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; UI.getBackButton().hoverUpdate(delta, mouseX, mouseY); prevPage.hoverUpdate(delta, mouseX, mouseY); nextPage.hoverUpdate(delta, mouseX, mouseY); @@ -572,7 +571,6 @@ public class DownloadsMenu extends BasicGameState { focusTimer += delta; // search - search.setFocus(true); searchTimer += delta; if (searchTimer >= SEARCH_DELAY && importThread == null) { searchTimer = 0; @@ -608,24 +606,26 @@ public class DownloadsMenu extends BasicGameState { } @Override - public int getID() { return state; } + public boolean mousePressed(int button, int x, int y) { + if (super.mousePressed(button, x, y)) { + return true; + } - @Override - public void mousePressed(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } // block input during beatmap importing - if (importThread != null) - return; + if (importThread != null) { + return true; + } // back if (UI.getBackButton().contains(x, y)) { SoundController.playSound(SoundEffect.MENUBACK); - ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); - game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); - return; + instanceContainer.provide(MainMenu.class).reset(); + displayContainer.switchState(MainMenu.class); + return true; } // search results @@ -694,11 +694,12 @@ public class DownloadsMenu extends BasicGameState { } }.start(); } - return; + return true; } - if (isLoaded) - return; + if (isLoaded) { + return true; + } SoundController.playSound(SoundEffect.MENUCLICK); if (index == focusResult) { @@ -725,7 +726,7 @@ public class DownloadsMenu extends BasicGameState { break; } } - return; + return true; } // pages @@ -741,7 +742,7 @@ public class DownloadsMenu extends BasicGameState { searchQuery.interrupt(); resetSearchTimer(); } - return; + return true; } if (pageResultTotal < totalResults && nextPage.contains(x, y)) { if (lastQueryDir == Page.NEXT && searchQuery != null && !searchQuery.isComplete()) @@ -753,7 +754,7 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - return; + return true; } } } @@ -763,7 +764,7 @@ public class DownloadsMenu extends BasicGameState { if (clearButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); DownloadList.get().clearInactiveDownloads(); - return; + return true; } if (importButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); @@ -771,7 +772,7 @@ public class DownloadsMenu extends BasicGameState { // import songs in new thread importThread = new BeatmapImportThread(); importThread.start(); - return; + return true; } if (resetButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); @@ -781,7 +782,7 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - return; + return true; } if (rankedButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); @@ -791,7 +792,7 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - return; + return true; } // downloads @@ -807,8 +808,9 @@ public class DownloadsMenu extends BasicGameState { if (DownloadNode.downloadIconContains(x, y - offset, i)) { SoundController.playSound(SoundEffect.MENUCLICK); DownloadNode node = DownloadList.get().getNode(index); - if (node == null) - return; + if (node == null) { + return true; + } Download dl = node.getDownload(); switch (dl.getStatus()) { case CANCELLED: @@ -822,62 +824,78 @@ public class DownloadsMenu extends BasicGameState { dl.cancel(); break; } - return; + return true; } } } + return false; } @Override - public void mouseReleased(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + public boolean mouseReleased(int button, int x, int y) { + if (super.mouseReleased(button, x, y)) { + return true; + } + + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } startDownloadIndexPos.released(); startResultPos.released(); + return true; } @Override - public void mouseWheelMoved(int newValue) { + public boolean mouseWheelMoved(int newValue) { // change volume - if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) { + if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) { UI.changeVolume((newValue < 0) ? -1 : 1); - return; + return true; } // block input during beatmap importing - if (importThread != null) - return; + if (importThread != null) { + return true; + } int shift = (newValue < 0) ? 1 : -1; - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - scrollLists(mouseX, mouseY, shift); + scrollLists(displayContainer.mouseX, displayContainer.mouseY, shift); + return true; } @Override - public void mouseDragged(int oldx, int oldy, int newx, int newy) { + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { // block input during beatmap importing - if (importThread != null) - return; - - // check mouse button - if (!input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON) && - !input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) - return; + if (importThread != null) { + return true; + } int diff = newy - oldy; - if (diff == 0) - return; + if (diff == 0) { + return false; + } + startDownloadIndexPos.dragged(-diff); startResultPos.dragged(-diff); + return true; } @Override - public void keyPressed(int key, char c) { + public boolean keyReleased(int key, char c) { + return super.keyReleased(key, c); + } + + @Override + public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; + } + // block input during beatmap importing - if (importThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) - return; + if (importThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) { + return true; + } switch (key) { case Input.KEY_ESCAPE: @@ -892,16 +910,16 @@ public class DownloadsMenu extends BasicGameState { } else { // return to main menu SoundController.playSound(SoundEffect.MENUBACK); - ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); - game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); + instanceContainer.provide(MainMenu.class).reset(); + displayContainer.switchState(MainMenu.class); } - break; + return true; case Input.KEY_ENTER: if (!search.getText().isEmpty()) { pageDir = Page.RESET; resetSearchTimer(); } - break; + return true; case Input.KEY_F5: SoundController.playSound(SoundEffect.MENUCLICK); lastQuery = null; @@ -909,30 +927,31 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - break; + return true; case Input.KEY_F7: // TODO d //Options.setNextFPS(container); - break; + return true; case Input.KEY_F10: Options.toggleMouseDisabled(); - break; + return true; case Input.KEY_F12: Utils.takeScreenShot(); - break; - default: - // wait for user to finish typing - if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) { - searchTimer = 0; - pageDir = Page.RESET; - } - break; + return true; } + // wait for user to finish typing + if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) { + search.keyPressed(key, c); + searchTimer = 0; + pageDir = Page.RESET; + } + return true; } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); + UI.enter(); prevPage.resetHover(); nextPage.resetHover(); @@ -940,7 +959,6 @@ public class DownloadsMenu extends BasicGameState { importButton.resetHover(); resetButton.resetHover(); rankedButton.resetHover(); - serverMenu.activate(); serverMenu.reset(); focusResult = -1; startResultPos.setPosition(0); @@ -954,10 +972,10 @@ public class DownloadsMenu extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) - throws SlickException { - search.setFocus(false); - serverMenu.deactivate(); + public void leave() { + super.leave(); + + focusComponent(search); SoundController.stopTrack(); MusicController.resume(); } diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index a91e7fef..d1f63a9e 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -553,8 +553,7 @@ public class MainMenu extends BaseOpsuState { // downloads button actions if (downloadsButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUHIT); - // TODO //displayContainer.switchState(DownloadsMenu.class); - //game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); + displayContainer.switchState(DownloadsMenu.class); return true; } @@ -659,9 +658,8 @@ public class MainMenu extends BaseOpsuState { enterSongMenu(); return true; case Input.KEY_D: - // TODO - //SoundController.playSound(SoundEffect.MENUHIT); - //game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); + SoundController.playSound(SoundEffect.MENUHIT); + displayContainer.switchState(DownloadsMenu.class); return true; case Input.KEY_R: nextTrack(true); @@ -754,7 +752,7 @@ public class MainMenu extends BaseOpsuState { Class state = SongMenu.class; if (BeatmapSetList.get().getMapSetCount() == 0) { instanceContainer.provide(DownloadsMenu.class).notifyOnLoad("Download some beatmaps to get started!"); - // TODO d state = DownloadsMenu.class; + state = DownloadsMenu.class; } displayContainer.switchState(state); } diff --git a/src/itdelatrisu/opsu/ui/DropdownMenu.java b/src/itdelatrisu/opsu/ui/DropdownMenu.java index 5204c257..095ead77 100644 --- a/src/itdelatrisu/opsu/ui/DropdownMenu.java +++ b/src/itdelatrisu/opsu/ui/DropdownMenu.java @@ -27,152 +27,62 @@ import org.newdawn.slick.Font; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; import org.newdawn.slick.UnicodeFont; -import org.newdawn.slick.gui.AbstractComponent; -import org.newdawn.slick.gui.GUIContext; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.components.Component; + +public class DropdownMenu extends Component { -/** - * Simple dropdown menu. - *

- * Basic usage: - *

    - *
  • Override {@link #menuClicked(int)} to perform actions when the menu is clicked - * (e.g. play a sound effect, block input under certain conditions). - *
  • Override {@link #itemSelected(int, Object)} to perform actions when a new item is selected. - *
  • Call {@link #activate()}/{@link #deactivate()} whenever the component is needed - * (e.g. in a state's {@code enter} and {@code leave} events. - *
- * - * @param the type of the elements in the menu - */ -public class DropdownMenu extends AbstractComponent { - /** Padding ratios for drawing. */ private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f; - /** Whether this component is active. */ - private boolean active; + private final DisplayContainer displayContainer; - /** The menu items. */ private E[] items; - - /** The menu item names. */ private String[] itemNames; + private int selectedItemIndex = 0; + private boolean expanded; - /** The index of the selected item. */ - private int itemIndex = 0; - - /** Whether the menu is expanded. */ - private boolean expanded = false; - - /** The expanding animation progress. */ private AnimatedValue expandProgress = new AnimatedValue(300, 0f, 1f, AnimationEquation.LINEAR); - /** The last update time, in milliseconds. */ - private long lastUpdateTime; - - /** The top-left coordinates. */ - private float x, y; - - /** The width and height of the dropdown menu. */ - private int width, height; - - /** The height of the base item. */ private int baseHeight; - - /** The vertical offset between items. */ private float offsetY; - /** The colors to use. */ - private Color - textColor = Color.white, backgroundColor = Color.black, - highlightColor = Colors.BLUE_DIVIDER, borderColor = Colors.BLUE_DIVIDER, - chevronDownColor = textColor, chevronRightColor = backgroundColor; + private Color textColor = Color.white; + private Color backgroundColor = Color.black; + private Color highlightColor = Colors.BLUE_DIVIDER; + private Color borderColor = Colors.BLUE_DIVIDER; + private Color chevronDownColor = textColor; + private Color chevronRightColor = backgroundColor; - /** The fonts to use. */ - private UnicodeFont fontNormal = Fonts.MEDIUM, fontSelected = Fonts.MEDIUMBOLD; + private UnicodeFont fontNormal = Fonts.MEDIUM; + private UnicodeFont fontSelected = Fonts.MEDIUMBOLD; - /** The chevron images. */ - private Image chevronDown, chevronRight; + private Image chevronDown; + private Image chevronRight; - /** Should the next click be blocked? */ - private boolean blockClick = false; - - /** - * 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 x the top-left x coordinate - * @param y the top-left y coordinate - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y) { - this(container, items, x, y, 0); - } - - /** - * 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 x the top-left x coordinate - * @param y the top-left y coordinate - * @param normal the normal font - * @param selected the font for the selected item - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y, UnicodeFont normal, UnicodeFont selected) { - this(container, items, x, y, 0, normal, selected); - } - - /** - * 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 x the top-left x coordinate - * @param y the top-left y coordinate - * @param width the menu width - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y, int width) { - super(container); + public DropdownMenu(DisplayContainer displayContainer, E[] items, int x, int y, int width) { + this.displayContainer = displayContainer; init(items, x, y, width); } - /** - * 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 x the top-left x coordinate - * @param y the top-left y coordinate - * @param width the menu width - * @param normal the normal font - * @param selected the font for the selected item - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y, int width, UnicodeFont normal, UnicodeFont selected) { - super(container); - this.fontNormal = normal; - this.fontSelected = selected; - init(items, x, y, width); - } - - /** - * Returns the maximum item width from the list. - */ private int getMaxItemWidth() { int maxWidth = 0; - for (int i = 0; i < itemNames.length; i++) { - int w = fontSelected.getWidth(itemNames[i]); - if (w > maxWidth) + for (String itemName : itemNames) { + int w = fontSelected.getWidth(itemName); + if (w > maxWidth) { maxWidth = w; + } } return maxWidth; } - /** - * Initializes the component. - */ - private void init(E[] items, float x, float y, int width) { + @SuppressWarnings("SuspiciousNameCombination") + private void init(E[] items, int x, int y, int width) { this.items = items; this.itemNames = new String[items.length]; - for (int i = 0; i < itemNames.length; i++) + for (int i = 0; i < itemNames.length; i++) { itemNames[i] = items[i].toString(); + } this.x = x; this.y = y; this.baseHeight = fontNormal.getLineHeight(); @@ -188,77 +98,27 @@ public class DropdownMenu extends AbstractComponent { } @Override - public void setLocation(int x, int y) { - this.x = x; - this.y = y; + public void updateHover(int x, int y) { + this.hovered = this.x <= x && x <= this.x + width && this.y <= y && y <= this.y + (expanded ? height : baseHeight); + } + + public boolean baseContains(int x, int y) { + return (x > this.x && x < this.x + width && y > this.y && y < this.y + baseHeight); } @Override - public int getX() { return (int) x; } + public void render(Graphics g) { + int delta = displayContainer.renderDelta; - @Override - public int getY() { return (int) y; } - - @Override - public int getWidth() { return width; } - - @Override - public int getHeight() { return (expanded) ? height : 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. - * @return true if open, false otherwise - */ - public boolean isOpen() { return expanded; } - - /** - * Opens or closes the dropdown menu. - * @param flag true to open, false to close - */ - public void open(boolean flag) { this.expanded = flag; } - - /** - * Returns true if the coordinates are within the menu bounds. - * @param cx the x coordinate - * @param cy the y coordinate - */ - public boolean contains(float cx, float cy) { - return (cx > x && cx < x + width && ( - (cy > y && cy < y + baseHeight) || - (expanded && cy > y + offsetY && cy < y + height))); - } - - /** - * Returns true if the coordinates are within the base item bounds. - * @param cx the x coordinate - * @param cy the y coordinate - */ - public boolean baseContains(float cx, float cy) { - return (cx > x && cx < x + width && cy > y && cy < y + baseHeight); - } - - @Override - public void render(GUIContext container, Graphics g) throws SlickException { // update animation - long time = container.getTime(); - if (lastUpdateTime > 0) { - int delta = (int) (time - lastUpdateTime); - expandProgress.update((expanded) ? delta : -delta * 2); - } - this.lastUpdateTime = time; + expandProgress.update((expanded) ? delta : -delta * 2); // get parameters - Input input = container.getInput(); - int idx = getIndexAt(input.getMouseX(), input.getMouseY()); + int idx = getIndexAt(displayContainer.mouseY); float t = expandProgress.getValue(); - if (expanded) + if (expanded) { t = AnimationEquation.OUT_CUBIC.calc(t); + } // background and border Color oldGColor = g.getColor(); @@ -293,12 +153,12 @@ public class DropdownMenu extends AbstractComponent { // text chevronDown.draw(x + width - chevronDown.getWidth() - width * CHEVRON_X, y + (baseHeight - chevronDown.getHeight()) / 2f, chevronDownColor); - fontNormal.drawString(x + (width * 0.03f), y + (fontNormal.getPaddingTop() + fontNormal.getPaddingBottom()) / 2f, itemNames[itemIndex], textColor); + fontNormal.drawString(x + (width * 0.03f), y + (fontNormal.getPaddingTop() + fontNormal.getPaddingBottom()) / 2f, itemNames[selectedItemIndex], textColor); float oldTextAlpha = textColor.a; textColor.a *= t; if (expanded || t >= 0.0001) { for (int i = 0; i < itemNames.length; i++) { - Font f = (i == itemIndex) ? fontSelected : fontNormal; + Font f = (i == selectedItemIndex) ? fontSelected : fontNormal; if (i == idx && t >= 0.999) chevronRight.draw(x, y + offsetY + (offsetY * i) + (offsetY - chevronRight.getHeight()) / 2f, chevronRightColor); f.drawString(x + chevronRight.getWidth(), y + offsetY + (offsetY * i * t), itemNames[i], textColor); @@ -310,131 +170,89 @@ public class DropdownMenu extends AbstractComponent { /** * Returns the index of the item at the given location, -1 for the base item, * and -2 if there is no item at the location. - * @param cx the x coordinate - * @param cy the y coordinate + * @param y the y coordinate */ - private int getIndexAt(float cx, float cy) { - if (!contains(cx, cy)) + private int getIndexAt(int y) { + if (!hovered) { return -2; - if (cy <= y + baseHeight) + } + if (y <= this.y + baseHeight) { return -1; - if (!expanded) + } + if (!expanded) { return -2; - return (int) ((cy - (y + offsetY)) / offsetY); + } + return (int) ((y - (this.y + offsetY)) / offsetY); } - /** - * Resets the menu state. - */ public void reset() { this.expanded = false; - this.lastUpdateTime = 0; expandProgress.setTime(0); - blockClick = false; + } + + + @Override + public void setFocused(boolean focused) { + super.setFocused(focused); + expanded = focused; } @Override - public void mousePressed(int button, int x, int y) { - if (!active) - return; + public boolean isFocusable() { + return true; + } - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + @Override + public void mouseReleased(int button) { + super.mouseReleased(button); - int idx = getIndexAt(x, y); + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return; + } + + int idx = getIndexAt(displayContainer.mouseY); if (idx == -2) { this.expanded = false; return; } - if (!menuClicked(idx)) + if (!canSelect(selectedItemIndex)) { return; - this.expanded = (idx == -1) ? !expanded : false; - if (idx >= 0 && itemIndex != idx) { - this.itemIndex = idx; - itemSelected(idx, items[idx]); } - blockClick = true; - consumeEvent(); - } - - @Override - public void mouseClicked(int button, int x, int y, int clickCount) { - if (!active) - return; - - if (blockClick) { - blockClick = false; - consumeEvent(); + this.expanded = (idx == -1) && !expanded; + if (idx >= 0 && selectedItemIndex != idx) { + this.selectedItemIndex = idx; + itemSelected(idx, items[selectedItemIndex]); } } - /** - * 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. - * @param index the list item index - * @throws IllegalArgumentException if {@code index} is negative or greater than or equal to size - */ - public void setSelectedIndex(int index) { - if (index < 0 || index >= items.length) - throw new IllegalArgumentException(); - this.itemIndex = index; + protected boolean canSelect(int index) { + return true; } - /** - * Returns the index of the selected item. - */ - public int getSelectedIndex() { return itemIndex; } + protected void itemSelected(int index, E item) { + } - /** - * Returns the selected item. - */ - public E getSelectedItem() { return items[itemIndex]; } + public E getSelectedItem() { + return items[selectedItemIndex]; + } - /** - * Returns the item at the given index. - * @param index the list item index - */ - public E getItemAt(int index) { return items[index]; } + public void setBackgroundColor(Color c) { + this.backgroundColor = c; + } - /** - * Returns the number of items in the list. - */ - public int getItemCount() { return items.length; } + public void setHighlightColor(Color c) { + this.highlightColor = c; + } - /** Sets the text color. */ - public void setTextColor(Color c) { this.textColor = c; } + public void setBorderColor(Color c) { + this.borderColor = c; + } - /** Sets the background color. */ - public void setBackgroundColor(Color c) { this.backgroundColor = c; } + public void setChevronDownColor(Color c) { + this.chevronDownColor = c; + } - /** Sets the highlight color. */ - public void setHighlightColor(Color c) { this.highlightColor = c; } - - /** Sets the border color. */ - public void setBorderColor(Color c) { this.borderColor = c; } - - /** Sets the down chevron color. */ - public void setChevronDownColor(Color c) { this.chevronDownColor = c; } - - /** Sets the right chevron color. */ - public void setChevronRightColor(Color c) { this.chevronRightColor = c; } + public void setChevronRightColor(Color c) { + this.chevronRightColor = c; + } } diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 499d5221..df63f5a9 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -17,10 +17,7 @@ */ package yugecin.opsudance.core.inject; -import itdelatrisu.opsu.states.ButtonMenu; -import itdelatrisu.opsu.states.MainMenu; -import itdelatrisu.opsu.states.SongMenu; -import itdelatrisu.opsu.states.Splash; +import itdelatrisu.opsu.states.*; import yugecin.opsudance.PreStartupInitializer; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.events.EventBus; @@ -59,6 +56,7 @@ public class OpsuDanceInjector extends Injector { bind(MainMenu.class).asEagerSingleton(); bind(ButtonMenu.class).asEagerSingleton(); bind(SongMenu.class).asEagerSingleton(); + bind(DownloadsMenu.class).asEagerSingleton(); } }