2016-12-11 01:17:30 +01:00
|
|
|
/*
|
|
|
|
* opsu!dance - fork of opsu! with cursordance auto
|
|
|
|
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package yugecin.opsudance.ui;
|
|
|
|
|
|
|
|
import itdelatrisu.opsu.GameImage;
|
|
|
|
import itdelatrisu.opsu.Utils;
|
2016-12-11 02:18:50 +01:00
|
|
|
import itdelatrisu.opsu.audio.SoundController;
|
|
|
|
import itdelatrisu.opsu.audio.SoundEffect;
|
2017-01-30 00:53:28 +01:00
|
|
|
import itdelatrisu.opsu.ui.*;
|
2017-01-29 11:28:24 +01:00
|
|
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
2017-05-27 02:10:32 +02:00
|
|
|
import org.lwjgl.input.Keyboard;
|
2016-12-11 02:08:35 +01:00
|
|
|
import org.newdawn.slick.*;
|
2017-01-29 11:28:24 +01:00
|
|
|
import org.newdawn.slick.gui.TextField;
|
2017-01-19 16:03:53 +01:00
|
|
|
import yugecin.opsudance.core.DisplayContainer;
|
|
|
|
import yugecin.opsudance.core.state.OverlayOpsuState;
|
2017-03-26 22:57:10 +02:00
|
|
|
import yugecin.opsudance.options.*;
|
2017-01-29 11:28:24 +01:00
|
|
|
import yugecin.opsudance.utils.FontUtil;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-30 00:53:28 +01:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
import static yugecin.opsudance.options.Options.*;
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
public class OptionsOverlay extends OverlayOpsuState {
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
private final DisplayContainer displayContainer;
|
2016-12-11 02:08:35 +01:00
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private static final float BG_ALPHA = 0.7f;
|
|
|
|
private static final float LINEALPHA = 0.8f;
|
|
|
|
private static final Color COL_BG = new Color(Color.black);
|
|
|
|
private static final Color COL_WHITE = new Color(1f, 1f, 1f);
|
|
|
|
private static final Color COL_PINK = new Color(235, 117, 139);
|
|
|
|
private static final Color COL_CYAN = new Color(88, 218, 254);
|
|
|
|
private static final Color COL_GREY = new Color(55, 55, 57);
|
|
|
|
private static final Color COL_BLUE = new Color(Colors.BLUE_BACKGROUND);
|
|
|
|
private static final Color COL_COMBOBOX_HOVER = new Color(185, 19, 121);
|
2017-05-28 16:11:05 +02:00
|
|
|
private static final Color COL_NAV_BG = new Color(COL_BG);
|
|
|
|
private static final Color COL_NAV_INDICATOR = new Color(COL_PINK);
|
|
|
|
private static final Color COL_NAV_WHITE = new Color(COL_WHITE);
|
|
|
|
private static final Color COL_NAV_FILTERED = new Color(37, 37, 37);
|
|
|
|
private static final Color COL_NAV_INACTIVE = new Color(153, 153, 153);
|
|
|
|
private static final Color COL_NAV_FILTERED_HOVERED = new Color(58, 58, 58);
|
2017-01-29 11:28:24 +01:00
|
|
|
|
|
|
|
private static final float INDICATOR_ALPHA = 0.8f;
|
|
|
|
private static final Color COL_INDICATOR = new Color(Color.black);
|
|
|
|
|
|
|
|
|
|
|
|
/** Duration, in ms, of the show (slide-in) animation. */
|
|
|
|
private static final int SHOWANIMATIONTIME = 1000;
|
|
|
|
/** Current value of the animation timer. */
|
|
|
|
private int animationtime;
|
|
|
|
/** Duration, in ms, of the hide animation. */
|
|
|
|
private int hideAnimationTime;
|
|
|
|
/** How much the show animation progressed when the hide request was made. */
|
|
|
|
private float hideAnimationStartProgress;
|
|
|
|
|
|
|
|
/** Target duration, in ms, of the move animation for the indicator. */
|
|
|
|
private static final int INDICATORMOVEANIMATIONTIME = 166;
|
|
|
|
/** Selected option indicator virtual position. */
|
|
|
|
private int indicatorPos;
|
|
|
|
/** Selected option indicator offset to next position. */
|
|
|
|
private int indicatorOffsetToNextPos;
|
|
|
|
/** Selected option indicator move to next position animation time past. */
|
|
|
|
private int indicatorMoveAnimationTime;
|
|
|
|
/** Target duration, in ms, of the fadeout animation for the indicator. */
|
|
|
|
private static final int INDICATORHIDEANIMATIONTIME = 500;
|
|
|
|
/** Selected option indicator hide animation time past. */
|
|
|
|
private int indicatorHideAnimationTime;
|
|
|
|
|
2017-01-19 19:23:31 +01:00
|
|
|
private Listener listener;
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
private Image sliderBallImg;
|
|
|
|
private Image checkOnImg;
|
|
|
|
private Image checkOffImg;
|
2017-01-29 11:28:24 +01:00
|
|
|
private Image searchImg;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private OptionTab[] sections;
|
2017-05-28 16:11:05 +02:00
|
|
|
private OptionTab activeSection;
|
|
|
|
private OptionTab hoveredNavigationEntry;
|
2016-12-11 16:41:56 +01:00
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private Option hoverOption;
|
|
|
|
private Option selectedOption;
|
2016-12-11 16:41:56 +01:00
|
|
|
|
2016-12-11 10:08:22 +01:00
|
|
|
private int sliderOptionStartX;
|
|
|
|
private int sliderOptionLength;
|
|
|
|
private boolean isAdjustingSlider;
|
2016-12-11 16:41:56 +01:00
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private final HashMap<ListOption, DropdownMenu<Object>> dropdownMenus;
|
2017-01-30 00:53:28 +01:00
|
|
|
private final LinkedList<DropdownMenu<Object>> visibleDropdownMenus;
|
|
|
|
private int dropdownMenuPaddingY;
|
|
|
|
private DropdownMenu<Object> openDropdownMenu;
|
|
|
|
private int openDropdownVirtualY;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private int finalWidth;
|
2016-12-11 01:17:30 +01:00
|
|
|
private int width;
|
|
|
|
private int height;
|
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
private int navButtonSize;
|
|
|
|
private int navStartY;
|
|
|
|
private int navExpadedWidth;
|
|
|
|
private int navWidth;
|
|
|
|
private int navHoverTime;
|
|
|
|
private int navIndicatorSize;
|
|
|
|
|
2016-12-11 01:17:30 +01:00
|
|
|
private int optionWidth;
|
|
|
|
private int optionStartX;
|
|
|
|
private int optionStartY;
|
|
|
|
private int optionHeight;
|
2017-01-29 11:28:24 +01:00
|
|
|
private int optionTextOffsetY;
|
|
|
|
|
|
|
|
private int controlImageSize;
|
|
|
|
private int controlImagePadding;
|
|
|
|
|
|
|
|
private static final int LINEWIDTH = 3;
|
|
|
|
private int paddingRight;
|
|
|
|
private int paddingLeft;
|
|
|
|
private int paddingTextLeft;
|
|
|
|
|
|
|
|
private int textOptionsY;
|
|
|
|
private int textChangeY;
|
|
|
|
private int posSearchY;
|
|
|
|
private int textSearchYOffset;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-29 15:33:01 +01:00
|
|
|
private final KineticScrolling scrollHandler;
|
2016-12-11 10:20:22 +01:00
|
|
|
private int maxScrollOffset;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2016-12-11 02:26:31 +01:00
|
|
|
private int mousePressY;
|
|
|
|
|
2016-12-11 12:31:52 +01:00
|
|
|
private boolean keyEntryLeft;
|
|
|
|
private boolean keyEntryRight;
|
|
|
|
|
2016-12-11 16:32:21 +01:00
|
|
|
private int prevMouseX;
|
|
|
|
private int prevMouseY;
|
|
|
|
|
2016-12-12 18:41:26 +01:00
|
|
|
private int sliderSoundDelay;
|
|
|
|
|
2017-02-03 16:24:26 +01:00
|
|
|
private int sectionLineHeight;
|
|
|
|
|
2017-01-29 15:33:01 +01:00
|
|
|
private final TextField searchField;
|
2017-01-29 11:28:24 +01:00
|
|
|
private String lastSearchText;
|
|
|
|
|
|
|
|
public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] sections) {
|
2017-01-19 16:03:53 +01:00
|
|
|
this.displayContainer = displayContainer;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
this.sections = sections;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-01-30 00:53:28 +01:00
|
|
|
dropdownMenus = new HashMap<>();
|
|
|
|
visibleDropdownMenus = new LinkedList<>();
|
|
|
|
|
2017-05-27 00:37:02 +02:00
|
|
|
searchField = new TextField(null, 0, 0, 0, 0);
|
2017-01-29 22:55:11 +01:00
|
|
|
searchField.setMaxLength(20);
|
|
|
|
|
2017-01-29 15:33:01 +01:00
|
|
|
scrollHandler = new KineticScrolling();
|
2017-01-29 16:23:52 +01:00
|
|
|
scrollHandler.setAllowOverScroll(true);
|
2017-01-19 16:03:53 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 19:23:31 +01:00
|
|
|
public void setListener(Listener listener) {
|
|
|
|
this.listener = listener;
|
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public void revalidate() {
|
|
|
|
super.revalidate();
|
2016-12-12 18:46:57 +01:00
|
|
|
|
2017-01-29 23:00:22 +01:00
|
|
|
finalWidth = Math.max((int) (displayContainer.width * 0.36f), 340); // 0.321f
|
2017-01-19 16:03:53 +01:00
|
|
|
height = displayContainer.height;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
|
|
|
// calculate positions
|
2017-05-28 16:11:05 +02:00
|
|
|
float navIconWidthRatio = displayContainer.isWidescreen() ? 0.046875f : 0.065f;
|
|
|
|
// non-widescreen ratio is not accurate
|
|
|
|
navButtonSize = (int) (displayContainer.width * navIconWidthRatio);
|
|
|
|
navIndicatorSize = navButtonSize / 10;
|
|
|
|
navExpadedWidth = (int) (finalWidth * 0.45f) - navButtonSize;
|
2017-01-29 11:28:24 +01:00
|
|
|
paddingRight = (int) (displayContainer.width * 0.009375f); // not so accurate
|
2017-05-28 16:11:05 +02:00
|
|
|
paddingLeft = navButtonSize + (int) (displayContainer.width * 0.0180f); // not so accurate
|
2017-01-29 13:23:08 +01:00
|
|
|
paddingTextLeft = paddingLeft + LINEWIDTH + (int) (displayContainer.width * 0.00625f); // not so accurate
|
2017-01-29 11:28:24 +01:00
|
|
|
optionStartX = paddingTextLeft;
|
|
|
|
textOptionsY = Fonts.LARGE.getLineHeight() * 2;
|
|
|
|
textChangeY = textOptionsY + Fonts.LARGE.getLineHeight();
|
|
|
|
posSearchY = textChangeY + Fonts.MEDIUM.getLineHeight() * 2;
|
|
|
|
textSearchYOffset = Fonts.MEDIUM.getLineHeight() / 2;
|
|
|
|
optionStartY = posSearchY + Fonts.MEDIUM.getLineHeight() + Fonts.LARGE.getLineHeight();
|
2017-02-03 16:24:26 +01:00
|
|
|
sectionLineHeight = (int) (Fonts.LARGE.getLineHeight() * 1.5f);
|
2017-01-29 11:28:24 +01:00
|
|
|
|
2017-01-30 00:53:28 +01:00
|
|
|
if (active) {
|
|
|
|
width = finalWidth;
|
|
|
|
optionWidth = width - optionStartX - paddingRight;
|
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
optionHeight = (int) (Fonts.MEDIUM.getLineHeight() * 1.3f);
|
|
|
|
optionTextOffsetY = (int) ((optionHeight - Fonts.MEDIUM.getLineHeight()) / 2f);
|
|
|
|
controlImageSize = (int) (Fonts.MEDIUM.getLineHeight() * 0.7f);
|
|
|
|
controlImagePadding = (optionHeight - controlImageSize) / 2;
|
|
|
|
|
|
|
|
sliderBallImg = GameImage.CONTROL_SLIDER_BALL.getImage().getScaledCopy(controlImageSize, controlImageSize);
|
|
|
|
checkOnImg = GameImage.CONTROL_CHECK_ON.getImage().getScaledCopy(controlImageSize, controlImageSize);
|
|
|
|
checkOffImg = GameImage.CONTROL_CHECK_OFF.getImage().getScaledCopy(controlImageSize, controlImageSize);
|
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
int navTotalHeight = 0;
|
2017-01-30 00:53:28 +01:00
|
|
|
dropdownMenus.clear();
|
|
|
|
for (OptionTab section : sections) {
|
|
|
|
if (section.options == null) {
|
2017-05-28 16:11:05 +02:00
|
|
|
navTotalHeight += navButtonSize;
|
2017-01-30 00:53:28 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-26 22:57:10 +02:00
|
|
|
for (final Option option : section.options) {
|
|
|
|
if (!(option instanceof ListOption)) {
|
2017-01-30 00:53:28 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-26 22:57:10 +02:00
|
|
|
final ListOption listOption = (ListOption) option;
|
|
|
|
Object[] items = listOption.getListItems();
|
2017-01-30 00:53:28 +01:00
|
|
|
DropdownMenu<Object> menu = new DropdownMenu<Object>(displayContainer, items, 0, 0, 0) {
|
|
|
|
@Override
|
|
|
|
public void itemSelected(int index, Object item) {
|
2017-03-26 22:57:10 +02:00
|
|
|
listOption.clickListItem(index);
|
2017-01-30 00:53:28 +01:00
|
|
|
openDropdownMenu = null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// not the best way to determine the selected option AT ALL, but seems like it's the only one right now...
|
|
|
|
String selectedValue = option.getValueString();
|
|
|
|
int idx = 0;
|
|
|
|
for (Object item : items) {
|
|
|
|
if (item.toString().equals(selectedValue)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
menu.setSelectedIndex(idx);
|
|
|
|
menu.setBackgroundColor(COL_BG);
|
|
|
|
menu.setBorderColor(Color.transparent);
|
|
|
|
menu.setChevronDownColor(COL_WHITE);
|
|
|
|
menu.setChevronRightColor(COL_BG);
|
|
|
|
menu.setHighlightColor(COL_COMBOBOX_HOVER);
|
|
|
|
menu.setTextColor(COL_WHITE);
|
2017-02-03 16:27:06 +01:00
|
|
|
dropdownMenuPaddingY = (optionHeight - menu.getHeight()) / 2;
|
2017-03-26 22:57:10 +02:00
|
|
|
dropdownMenus.put(listOption, menu);
|
2017-01-30 00:53:28 +01:00
|
|
|
}
|
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
navStartY = (height - navTotalHeight) / 2;
|
2017-01-29 11:28:24 +01:00
|
|
|
|
|
|
|
int searchImgSize = (int) (Fonts.LARGE.getLineHeight() * 0.75f);
|
|
|
|
searchImg = GameImage.SEARCH.getImage().getScaledCopy(searchImgSize, searchImgSize);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public void onRender(Graphics g) {
|
2017-05-28 16:11:05 +02:00
|
|
|
g.setClip(navButtonSize, 0, width - navButtonSize, height);
|
2017-01-29 11:28:24 +01:00
|
|
|
|
2016-12-11 01:17:30 +01:00
|
|
|
// bg
|
2017-01-29 11:28:24 +01:00
|
|
|
g.setColor(COL_BG);
|
2017-05-28 16:11:05 +02:00
|
|
|
g.fillRect(navButtonSize, 0, width, height);
|
2016-12-11 01:17:30 +01:00
|
|
|
|
|
|
|
// title
|
|
|
|
renderTitle();
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
renderIndicator(g);
|
2016-12-11 01:17:30 +01:00
|
|
|
|
|
|
|
// options
|
|
|
|
renderOptions(g);
|
2017-01-30 00:53:28 +01:00
|
|
|
if (openDropdownMenu != null) {
|
|
|
|
openDropdownMenu.render(g);
|
|
|
|
if (!openDropdownMenu.isOpen()) {
|
|
|
|
openDropdownMenu = null;
|
|
|
|
}
|
|
|
|
}
|
2017-01-29 11:28:24 +01:00
|
|
|
|
|
|
|
renderSearch(g);
|
2016-12-11 11:07:28 +01:00
|
|
|
|
|
|
|
// scrollbar
|
2017-01-29 11:28:24 +01:00
|
|
|
g.setColor(COL_WHITE);
|
2017-01-29 15:33:01 +01:00
|
|
|
g.fillRect(width - 5, scrollHandler.getPosition() / maxScrollOffset * (height - 45), 5, 45);
|
2016-12-11 11:07:28 +01:00
|
|
|
g.clearClip();
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
renderNavigation(g);
|
|
|
|
|
2016-12-11 02:33:50 +01:00
|
|
|
// UI
|
2017-02-02 01:06:56 +01:00
|
|
|
UI.getBackButton().draw(g);
|
2016-12-11 02:33:50 +01:00
|
|
|
|
|
|
|
// tooltip
|
2017-01-19 16:03:53 +01:00
|
|
|
renderTooltip(g);
|
2016-12-11 12:31:52 +01:00
|
|
|
|
2016-12-11 12:47:33 +01:00
|
|
|
// key input options
|
2016-12-12 23:22:12 +01:00
|
|
|
if (keyEntryLeft || keyEntryRight) {
|
2016-12-11 12:31:52 +01:00
|
|
|
renderKeyEntry(g);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
private void renderNavigation(Graphics g) {
|
|
|
|
navWidth = navButtonSize;
|
|
|
|
if (navHoverTime >= 600) {
|
|
|
|
navWidth += navExpadedWidth;
|
|
|
|
} else if (navHoverTime > 300) {
|
|
|
|
AnimationEquation anim = AnimationEquation.IN_EXPO;
|
|
|
|
if (displayContainer.mouseX < navWidth) {
|
|
|
|
anim = AnimationEquation.OUT_EXPO;
|
|
|
|
}
|
|
|
|
float progress = anim.calc((navHoverTime - 300f) / 300f);
|
|
|
|
navWidth += (int) (progress * navExpadedWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
g.setClip(0, 0, navWidth, height);
|
|
|
|
g.setColor(COL_NAV_BG);
|
|
|
|
g.fillRect(0, 0, navWidth, displayContainer.height);
|
|
|
|
int y = navStartY;
|
|
|
|
float iconSize = navButtonSize / 2.5f;
|
|
|
|
float iconPadding = iconSize * 0.75f;
|
|
|
|
int fontOffsetX = navButtonSize + navIndicatorSize;
|
|
|
|
int fontOffsetY = (navButtonSize - Fonts.MEDIUM.getLineHeight()) / 2;
|
|
|
|
for (OptionTab section : sections) {
|
|
|
|
if (section.icon == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Color iconCol = COL_NAV_INACTIVE;
|
|
|
|
Color fontCol = COL_NAV_WHITE;
|
|
|
|
if (section == activeSection) {
|
|
|
|
iconCol = COL_NAV_WHITE;
|
|
|
|
g.fillRect(0, y, navWidth, navButtonSize);
|
|
|
|
g.setColor(COL_NAV_INDICATOR);
|
|
|
|
g.fillRect(navWidth - navIndicatorSize, y, navIndicatorSize, navButtonSize);
|
|
|
|
} else if (section == hoveredNavigationEntry) {
|
|
|
|
iconCol = COL_NAV_WHITE;
|
|
|
|
}
|
|
|
|
if (section.filtered) {
|
|
|
|
iconCol = fontCol = COL_NAV_FILTERED;
|
|
|
|
if (section == hoveredNavigationEntry) {
|
|
|
|
iconCol = COL_NAV_FILTERED_HOVERED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
section.icon.getImage().draw(iconPadding, y + iconPadding, iconSize, iconSize, iconCol);
|
|
|
|
if (navHoverTime > 0) {
|
|
|
|
Fonts.MEDIUM.drawString(fontOffsetX, y + fontOffsetY, section.name, fontCol);
|
|
|
|
}
|
|
|
|
y += navButtonSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
g.clearClip();
|
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private void renderIndicator(Graphics g) {
|
|
|
|
g.setColor(COL_INDICATOR);
|
|
|
|
int indicatorPos = this.indicatorPos;
|
|
|
|
if (indicatorMoveAnimationTime > 0) {
|
|
|
|
indicatorMoveAnimationTime += displayContainer.renderDelta;
|
|
|
|
if (indicatorMoveAnimationTime > INDICATORMOVEANIMATIONTIME) {
|
|
|
|
indicatorMoveAnimationTime = 0;
|
|
|
|
indicatorPos += indicatorOffsetToNextPos;
|
|
|
|
indicatorOffsetToNextPos = 0;
|
|
|
|
this.indicatorPos = indicatorPos;
|
|
|
|
} else {
|
|
|
|
indicatorPos += AnimationEquation.OUT_BACK.calc((float) indicatorMoveAnimationTime / INDICATORMOVEANIMATIONTIME) * indicatorOffsetToNextPos;
|
|
|
|
}
|
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
g.fillRect(navButtonSize, indicatorPos - scrollHandler.getPosition(), width, optionHeight);
|
2017-01-29 11:28:24 +01:00
|
|
|
}
|
|
|
|
|
2016-12-11 12:31:52 +01:00
|
|
|
private void renderKeyEntry(Graphics g) {
|
2017-01-29 11:28:24 +01:00
|
|
|
g.setColor(COL_BG);
|
|
|
|
g.fillRect(0, 0, displayContainer.width, height);
|
|
|
|
g.setColor(COL_WHITE);
|
2016-12-11 12:31:52 +01:00
|
|
|
String prompt = (keyEntryLeft) ? "Please press the new left-click key." : "Please press the new right-click key.";
|
2017-01-29 11:28:24 +01:00
|
|
|
int y = (displayContainer.height - Fonts.LARGE.getLineHeight()) / 2;
|
|
|
|
FontUtil.drawCentered(Fonts.LARGE, displayContainer.width, 0, y, prompt, COL_WHITE);
|
2016-12-11 02:33:50 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
private void renderTooltip(Graphics g) {
|
2016-12-11 02:33:50 +01:00
|
|
|
if (hoverOption != null) {
|
2017-03-26 22:57:10 +02:00
|
|
|
String tip = hoverOption.description;
|
|
|
|
if (hoverOption instanceof NumericOption) {
|
2017-01-29 11:28:24 +01:00
|
|
|
tip = "(" + hoverOption.getValueString() + ") " + tip;
|
|
|
|
}
|
2017-01-29 22:55:11 +01:00
|
|
|
UI.updateTooltip(displayContainer.renderDelta, tip, true);
|
2017-01-19 16:03:53 +01:00
|
|
|
UI.drawTooltip(g);
|
2016-12-11 02:33:50 +01:00
|
|
|
}
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void renderOptions(Graphics g) {
|
2017-01-30 00:53:28 +01:00
|
|
|
visibleDropdownMenus.clear();
|
2017-01-29 15:33:01 +01:00
|
|
|
int y = -scrollHandler.getIntPosition() + optionStartY;
|
2017-01-29 11:28:24 +01:00
|
|
|
maxScrollOffset = optionStartY;
|
2016-12-11 10:20:22 +01:00
|
|
|
boolean render = true;
|
2017-01-29 11:28:24 +01:00
|
|
|
int sectionIndex = 0;
|
2017-01-29 14:19:54 +01:00
|
|
|
for (; sectionIndex < sections.length && render; sectionIndex++) {
|
2017-01-29 11:28:24 +01:00
|
|
|
OptionTab section = sections[sectionIndex];
|
|
|
|
if (section.filtered) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int lineStartY = (int) (y + Fonts.LARGE.getLineHeight() * 0.6f);
|
2017-05-28 16:11:05 +02:00
|
|
|
if (section.options == null) {
|
|
|
|
FontUtil.drawRightAligned(Fonts.XLARGE, width, -paddingRight,
|
|
|
|
(int) (y + Fonts.XLARGE.getLineHeight() * 0.3f), section.name.toUpperCase(),
|
|
|
|
COL_CYAN);
|
|
|
|
} else {
|
|
|
|
Fonts.MEDIUMBOLD.drawString(paddingTextLeft, lineStartY, section.name, COL_WHITE);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
2017-02-03 16:24:26 +01:00
|
|
|
y += sectionLineHeight;
|
|
|
|
maxScrollOffset += sectionLineHeight;
|
2017-01-29 11:28:24 +01:00
|
|
|
if (section.options == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int lineHeight = (int) (Fonts.LARGE.getLineHeight() * 0.9f);
|
|
|
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
2017-03-26 22:57:10 +02:00
|
|
|
Option option = section.options[optionIndex];
|
2017-01-29 11:28:24 +01:00
|
|
|
if (!option.showCondition() || option.isFiltered()) {
|
2016-12-11 01:17:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-01-30 00:53:28 +01:00
|
|
|
if (y > -optionHeight || (openDropdownMenu != null && openDropdownMenu.equals(dropdownMenus.get(option)))) {
|
2017-01-29 11:28:24 +01:00
|
|
|
renderOption(g, option, y);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
y += optionHeight;
|
2017-01-29 11:28:24 +01:00
|
|
|
maxScrollOffset += optionHeight;
|
|
|
|
lineHeight += optionHeight;
|
2016-12-11 01:17:30 +01:00
|
|
|
if (y > height) {
|
2016-12-11 10:20:22 +01:00
|
|
|
render = false;
|
2017-01-30 10:23:48 +01:00
|
|
|
while (++optionIndex < section.options.length) {
|
|
|
|
option = section.options[optionIndex];
|
|
|
|
if (option.showCondition() && !option.isFiltered()) {
|
|
|
|
maxScrollOffset += optionHeight;
|
|
|
|
}
|
|
|
|
}
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
}
|
2017-01-29 11:28:24 +01:00
|
|
|
g.setColor(COL_GREY);
|
|
|
|
g.fillRect(paddingLeft, lineStartY, LINEWIDTH, lineHeight);
|
|
|
|
}
|
|
|
|
// iterate over skipped options to correctly calculate max scroll offset
|
2017-01-29 14:19:54 +01:00
|
|
|
for (; sectionIndex < sections.length; sectionIndex++) {
|
2017-01-30 10:23:48 +01:00
|
|
|
if (sections[sectionIndex].filtered) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-29 11:28:24 +01:00
|
|
|
maxScrollOffset += Fonts.LARGE.getLineHeight() * 1.5f;
|
2017-01-30 10:23:48 +01:00
|
|
|
if (sections[sectionIndex].options == null) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-26 22:57:10 +02:00
|
|
|
for (Option option : sections[sectionIndex].options) {
|
2017-01-30 10:23:48 +01:00
|
|
|
if (option.showCondition() && !option.isFiltered()) {
|
|
|
|
maxScrollOffset += optionHeight;
|
|
|
|
}
|
2017-01-29 11:28:24 +01:00
|
|
|
}
|
|
|
|
}
|
2017-01-30 00:53:28 +01:00
|
|
|
if (openDropdownMenu != null) {
|
|
|
|
maxScrollOffset = Math.max(maxScrollOffset, openDropdownVirtualY + openDropdownMenu.getHeight());
|
2017-01-29 14:10:46 +01:00
|
|
|
}
|
2017-01-30 00:53:28 +01:00
|
|
|
maxScrollOffset -= height * 2 / 3;
|
2017-01-29 11:28:24 +01:00
|
|
|
if (maxScrollOffset < 0) {
|
|
|
|
maxScrollOffset = 0;
|
|
|
|
}
|
2017-01-30 00:53:28 +01:00
|
|
|
scrollHandler.setMinMax(0, maxScrollOffset);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private void renderOption(Graphics g, Option option, int y) {
|
|
|
|
if (option instanceof ListOption) {
|
|
|
|
renderListOption(g, (ListOption) option, y);
|
|
|
|
} else if (option instanceof ToggleOption) {
|
|
|
|
renderCheckOption((ToggleOption) option, y);
|
|
|
|
} else if (option instanceof NumericOption) {
|
|
|
|
renderSliderOption(g, (NumericOption) option, y);
|
|
|
|
} else if (option instanceof GenericOption) {
|
|
|
|
renderGenericOption((GenericOption) option, y);
|
2016-12-11 02:08:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private void renderListOption(Graphics g, ListOption option, int y) {
|
2017-01-30 00:53:28 +01:00
|
|
|
// draw option name
|
2017-03-26 22:57:10 +02:00
|
|
|
int nameWith = Fonts.MEDIUM.getWidth(option.name);
|
|
|
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.name, COL_WHITE);
|
2017-01-30 00:53:28 +01:00
|
|
|
nameWith += 15;
|
|
|
|
int comboboxStartX = optionStartX + nameWith;
|
|
|
|
int comboboxWidth = optionWidth - nameWith;
|
|
|
|
if (comboboxWidth < controlImageSize) {
|
2017-01-29 11:28:24 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-01-30 00:53:28 +01:00
|
|
|
DropdownMenu<Object> dropdown = dropdownMenus.get(option);
|
|
|
|
if (dropdown == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
visibleDropdownMenus.add(dropdown);
|
|
|
|
dropdown.setWidth(comboboxWidth);
|
|
|
|
dropdown.x = comboboxStartX;
|
|
|
|
dropdown.y = y + dropdownMenuPaddingY;
|
|
|
|
if (dropdown.isOpen()) {
|
|
|
|
openDropdownMenu = dropdown;
|
|
|
|
openDropdownVirtualY = maxScrollOffset;
|
|
|
|
return;
|
2016-12-11 11:07:28 +01:00
|
|
|
}
|
2017-01-30 00:53:28 +01:00
|
|
|
dropdown.render(g);
|
2016-12-11 02:08:35 +01:00
|
|
|
}
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private void renderCheckOption(ToggleOption option, int y) {
|
|
|
|
if (option.state) {
|
2017-01-29 11:28:24 +01:00
|
|
|
checkOnImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
2016-12-11 02:08:35 +01:00
|
|
|
} else {
|
2017-01-29 11:28:24 +01:00
|
|
|
checkOffImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
2016-12-11 02:08:35 +01:00
|
|
|
}
|
2017-03-26 22:57:10 +02:00
|
|
|
Fonts.MEDIUM.drawString(optionStartX + 30, y + optionTextOffsetY, option.name, COL_WHITE);
|
2016-12-11 02:08:35 +01:00
|
|
|
}
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private void renderSliderOption(Graphics g, NumericOption option, int y) {
|
2017-01-29 11:28:24 +01:00
|
|
|
final int padding = 10;
|
2017-03-26 22:57:10 +02:00
|
|
|
int nameLen = Fonts.MEDIUM.getWidth(option.name);
|
|
|
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.name, COL_WHITE);
|
2017-01-29 11:28:24 +01:00
|
|
|
int sliderLen = optionWidth - nameLen - padding;
|
|
|
|
if (sliderLen <= 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int sliderStartX = optionStartX + nameLen + padding;
|
|
|
|
int sliderEndX = optionStartX + optionWidth;
|
2016-12-11 10:08:22 +01:00
|
|
|
|
|
|
|
if (hoverOption == option) {
|
|
|
|
if (!isAdjustingSlider) {
|
|
|
|
sliderOptionLength = sliderLen;
|
2017-01-29 11:28:24 +01:00
|
|
|
sliderOptionStartX = sliderStartX;
|
2016-12-11 10:08:22 +01:00
|
|
|
} else {
|
|
|
|
sliderLen = sliderOptionLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
float sliderValue = (float) (option.val - option.min) / (option.max - option.min);
|
2017-01-29 11:28:24 +01:00
|
|
|
float sliderBallPos = sliderStartX + (int) ((sliderLen - controlImageSize) * sliderValue);
|
|
|
|
|
2016-12-11 02:08:35 +01:00
|
|
|
g.setLineWidth(3f);
|
2017-01-29 11:28:24 +01:00
|
|
|
g.setColor(COL_PINK);
|
|
|
|
if (sliderValue > 0.0001f) {
|
|
|
|
g.drawLine(sliderStartX, y + optionHeight / 2, sliderBallPos, y + optionHeight / 2);
|
|
|
|
}
|
|
|
|
sliderBallImg.draw(sliderBallPos, y + controlImagePadding, COL_PINK);
|
|
|
|
if (sliderValue < 0.999f) {
|
|
|
|
float a = COL_PINK.a;
|
|
|
|
COL_PINK.a *= 0.45f;
|
|
|
|
g.setColor(COL_PINK);
|
2017-01-29 13:42:46 +01:00
|
|
|
g.drawLine(sliderBallPos + controlImageSize + 1, y + optionHeight / 2, sliderEndX, y + optionHeight / 2);
|
2017-01-29 11:28:24 +01:00
|
|
|
COL_PINK.a = a;
|
|
|
|
}
|
2016-12-11 02:08:35 +01:00
|
|
|
}
|
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
private void renderGenericOption(GenericOption option, int y) {
|
2016-12-11 02:08:35 +01:00
|
|
|
String value = option.getValueString();
|
|
|
|
int valueLen = Fonts.MEDIUM.getWidth(value);
|
2017-03-26 22:57:10 +02:00
|
|
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.name, COL_WHITE);
|
2017-01-29 11:28:24 +01:00
|
|
|
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y + optionTextOffsetY, value, COL_BLUE);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private void renderTitle() {
|
2017-05-28 16:11:05 +02:00
|
|
|
int textWidth = width - navButtonSize;
|
|
|
|
FontUtil.drawCentered(Fonts.LARGE, textWidth, navButtonSize,
|
|
|
|
textOptionsY - scrollHandler.getIntPosition(), "Options", COL_WHITE);
|
|
|
|
FontUtil.drawCentered(Fonts.MEDIUM, textWidth, navButtonSize,
|
|
|
|
textChangeY - scrollHandler.getIntPosition(), "Change the way opsu! behaves", COL_PINK);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private void renderSearch(Graphics g) {
|
2017-01-29 15:33:01 +01:00
|
|
|
int ypos = posSearchY + textSearchYOffset - scrollHandler.getIntPosition();
|
|
|
|
if (scrollHandler.getIntPosition() > posSearchY) {
|
2017-01-29 11:28:24 +01:00
|
|
|
ypos = textSearchYOffset;
|
|
|
|
g.setColor(COL_BG);
|
2017-05-28 16:11:05 +02:00
|
|
|
g.fillRect(navButtonSize, 0, width, textSearchYOffset * 2 + Fonts.LARGE.getLineHeight());
|
2017-01-29 11:28:24 +01:00
|
|
|
}
|
|
|
|
String searchText = "Type to search!";
|
|
|
|
if (lastSearchText.length() > 0) {
|
|
|
|
searchText = lastSearchText;
|
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
FontUtil.drawCentered(Fonts.LARGE, width, navButtonSize, ypos, searchText, COL_WHITE);
|
|
|
|
int imgPosX = navButtonSize + (width - Fonts.LARGE.getWidth(searchText)) / 2 - searchImg.getWidth() - 10;
|
2017-01-29 11:28:24 +01:00
|
|
|
searchImg.draw(imgPosX, ypos + Fonts.LARGE.getLineHeight() * 0.25f, COL_WHITE);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public void hide() {
|
2017-01-29 22:55:11 +01:00
|
|
|
searchField.setFocused(false);
|
2017-01-19 16:03:53 +01:00
|
|
|
acceptInput = false;
|
|
|
|
SoundController.playSound(SoundEffect.MENUBACK);
|
2017-01-29 11:28:24 +01:00
|
|
|
hideAnimationTime = animationtime;
|
|
|
|
hideAnimationStartProgress = (float) animationtime / SHOWANIMATIONTIME;
|
2017-01-19 16:03:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void show() {
|
2017-05-28 16:11:05 +02:00
|
|
|
navHoverTime = 0;
|
2017-01-29 11:28:24 +01:00
|
|
|
indicatorPos = -optionHeight;
|
|
|
|
indicatorOffsetToNextPos = 0;
|
|
|
|
indicatorMoveAnimationTime = 0;
|
|
|
|
indicatorHideAnimationTime = 0;
|
2017-01-19 16:03:53 +01:00
|
|
|
acceptInput = true;
|
|
|
|
active = true;
|
2017-01-29 11:28:24 +01:00
|
|
|
animationtime = 0;
|
|
|
|
resetSearch();
|
2017-01-19 16:03:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPreRenderUpdate() {
|
|
|
|
int mouseX = displayContainer.mouseX;
|
|
|
|
int mouseY = displayContainer.mouseY;
|
|
|
|
int delta = displayContainer.renderDelta;
|
|
|
|
|
2017-05-28 16:15:11 +02:00
|
|
|
int prevscrollpos = scrollHandler.getIntPosition();
|
2017-01-29 15:33:01 +01:00
|
|
|
scrollHandler.update(delta);
|
2017-05-28 16:15:11 +02:00
|
|
|
boolean scrollPositionChanged = prevscrollpos != scrollHandler.getIntPosition();
|
2017-01-29 15:33:01 +01:00
|
|
|
|
2017-01-30 00:53:28 +01:00
|
|
|
if (openDropdownMenu == null) {
|
|
|
|
for (DropdownMenu<Object> menu : visibleDropdownMenus) {
|
|
|
|
menu.updateHover(mouseX, mouseY);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
openDropdownMenu.updateHover(mouseX, mouseY);
|
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
updateShowHideAnimation(delta);
|
|
|
|
if (animationtime <= 0) {
|
|
|
|
active = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-12 18:41:26 +01:00
|
|
|
if (sliderSoundDelay > 0) {
|
|
|
|
sliderSoundDelay -= delta;
|
|
|
|
}
|
2017-01-29 13:23:08 +01:00
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
if (mouseX < navWidth) {
|
|
|
|
if (navHoverTime < 600) {
|
|
|
|
navHoverTime += delta;
|
|
|
|
}
|
|
|
|
} else if (navHoverTime > 0) {
|
|
|
|
navHoverTime -= delta;
|
|
|
|
}
|
|
|
|
|
2017-05-28 16:15:11 +02:00
|
|
|
if (!scrollPositionChanged && (mouseX - prevMouseX == 0 && mouseY - prevMouseY == 0)) {
|
2017-01-29 11:28:24 +01:00
|
|
|
updateIndicatorAlpha();
|
2016-12-11 16:32:21 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
updateActiveSection();
|
|
|
|
updateHoverNavigation(mouseX, mouseY);
|
2016-12-11 16:32:21 +01:00
|
|
|
prevMouseX = mouseX;
|
|
|
|
prevMouseY = mouseY;
|
2016-12-11 01:17:30 +01:00
|
|
|
updateHoverOption(mouseX, mouseY);
|
2017-01-29 11:28:24 +01:00
|
|
|
updateIndicatorAlpha();
|
2016-12-11 01:17:30 +01:00
|
|
|
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
2016-12-11 10:08:22 +01:00
|
|
|
if (isAdjustingSlider) {
|
2017-03-26 22:57:10 +02:00
|
|
|
int sliderValue = ((NumericOption) hoverOption).val;
|
2017-01-19 16:03:53 +01:00
|
|
|
updateSliderOption();
|
2017-03-26 22:57:10 +02:00
|
|
|
if (((NumericOption) hoverOption).val - sliderValue != 0 && sliderSoundDelay <= 0) {
|
2016-12-12 18:41:26 +01:00
|
|
|
sliderSoundDelay = 90;
|
|
|
|
SoundController.playSound(SoundEffect.MENUHIT);
|
|
|
|
}
|
2016-12-11 10:08:22 +01:00
|
|
|
}
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
private void updateHoverNavigation(int mouseX, int mouseY) {
|
|
|
|
hoveredNavigationEntry = null;
|
|
|
|
if (mouseX >= navWidth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int y = navStartY;
|
|
|
|
for (OptionTab section : sections) {
|
|
|
|
if (section.options != null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int nextY = y + navButtonSize;
|
|
|
|
if (y <= mouseY && mouseY < nextY) {
|
|
|
|
hoveredNavigationEntry = section;
|
|
|
|
}
|
|
|
|
y = nextY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private void updateIndicatorAlpha() {
|
|
|
|
if (hoverOption == null) {
|
|
|
|
if (indicatorHideAnimationTime < INDICATORHIDEANIMATIONTIME) {
|
|
|
|
indicatorHideAnimationTime += displayContainer.renderDelta;
|
|
|
|
if (indicatorHideAnimationTime > INDICATORHIDEANIMATIONTIME) {
|
|
|
|
indicatorHideAnimationTime = INDICATORHIDEANIMATIONTIME;
|
|
|
|
}
|
|
|
|
float progress = AnimationEquation.IN_CUBIC.calc((float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME);
|
|
|
|
COL_INDICATOR.a = (1f - progress) * INDICATOR_ALPHA;
|
|
|
|
}
|
|
|
|
} else if (indicatorHideAnimationTime > 0) {
|
|
|
|
indicatorHideAnimationTime -= displayContainer.renderDelta * 3;
|
|
|
|
if (indicatorHideAnimationTime < 0) {
|
|
|
|
indicatorHideAnimationTime = 0;
|
|
|
|
}
|
|
|
|
COL_INDICATOR.a = (1f - (float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME) * INDICATOR_ALPHA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void updateShowHideAnimation(int delta) {
|
|
|
|
if (acceptInput && animationtime >= SHOWANIMATIONTIME) {
|
|
|
|
// animation already finished
|
|
|
|
width = finalWidth;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
optionWidth = width - optionStartX - paddingRight;
|
|
|
|
|
|
|
|
// if acceptInput is false, it means that we're currently hiding ourselves
|
|
|
|
float progress;
|
2017-05-28 16:11:05 +02:00
|
|
|
// navigation elemenst fade out with a different animation
|
|
|
|
float navProgress;
|
2017-01-29 11:28:24 +01:00
|
|
|
if (acceptInput) {
|
|
|
|
animationtime += delta;
|
|
|
|
if (animationtime >= SHOWANIMATIONTIME) {
|
|
|
|
animationtime = SHOWANIMATIONTIME;
|
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
progress = (float) animationtime / SHOWANIMATIONTIME;
|
|
|
|
navProgress = Utils.clamp(progress * 10f, 0f, 1f);
|
|
|
|
progress = AnimationEquation.OUT_EXPO.calc(progress);
|
2017-01-29 11:28:24 +01:00
|
|
|
} else {
|
|
|
|
animationtime -= delta;
|
|
|
|
if (animationtime < 0) {
|
|
|
|
animationtime = 0;
|
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
progress = (float) animationtime / hideAnimationTime;
|
|
|
|
navProgress = hideAnimationStartProgress * AnimationEquation.IN_CIRC.calc(progress);
|
|
|
|
progress = hideAnimationStartProgress * AnimationEquation.IN_EXPO.calc(progress);
|
2017-01-29 11:28:24 +01:00
|
|
|
}
|
2017-05-28 16:11:05 +02:00
|
|
|
width = navButtonSize + (int) (progress * (finalWidth - navButtonSize));
|
|
|
|
COL_NAV_FILTERED.a = COL_NAV_INACTIVE.a = COL_NAV_FILTERED_HOVERED.a = COL_NAV_INDICATOR.a =
|
|
|
|
COL_NAV_WHITE.a = COL_NAV_BG.a = navProgress;
|
2017-01-29 11:28:24 +01:00
|
|
|
COL_BG.a = BG_ALPHA * progress;
|
|
|
|
COL_WHITE.a = progress;
|
|
|
|
COL_PINK.a = progress;
|
|
|
|
COL_CYAN.a = progress;
|
|
|
|
COL_GREY.a = progress * LINEALPHA;
|
|
|
|
COL_BLUE.a = progress;
|
|
|
|
COL_COMBOBOX_HOVER.a = progress;
|
|
|
|
COL_INDICATOR.a = progress * (1f - (float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME) * INDICATOR_ALPHA;
|
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public boolean onMousePressed(int button, int x, int y) {
|
2016-12-11 12:31:52 +01:00
|
|
|
if (keyEntryLeft || keyEntryRight) {
|
|
|
|
keyEntryLeft = keyEntryRight = false;
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2016-12-11 12:31:52 +01:00
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
if (x > width) {
|
|
|
|
return false;
|
2016-12-11 11:07:28 +01:00
|
|
|
}
|
|
|
|
|
2017-01-29 15:33:01 +01:00
|
|
|
scrollHandler.pressed();
|
|
|
|
|
2016-12-11 02:26:31 +01:00
|
|
|
mousePressY = y;
|
2016-12-12 18:49:26 +01:00
|
|
|
selectedOption = hoverOption;
|
2016-12-11 01:17:30 +01:00
|
|
|
|
2017-03-26 22:57:10 +02:00
|
|
|
if (hoverOption != null && hoverOption instanceof NumericOption) {
|
2017-01-30 00:53:28 +01:00
|
|
|
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
|
|
|
|
if (isAdjustingSlider) {
|
|
|
|
updateSliderOption();
|
2016-12-11 11:07:28 +01:00
|
|
|
}
|
2016-12-11 10:08:22 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2016-12-11 02:26:31 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public boolean onMouseReleased(int button, int x, int y) {
|
2016-12-11 02:26:31 +01:00
|
|
|
selectedOption = null;
|
2017-01-19 19:23:31 +01:00
|
|
|
if (isAdjustingSlider && listener != null) {
|
|
|
|
listener.onSaveOption(hoverOption);
|
2016-12-11 16:32:21 +01:00
|
|
|
}
|
2016-12-11 10:08:22 +01:00
|
|
|
isAdjustingSlider = false;
|
|
|
|
sliderOptionLength = 0;
|
2016-12-11 02:26:31 +01:00
|
|
|
|
2017-01-30 00:53:28 +01:00
|
|
|
if (openDropdownMenu != null) {
|
|
|
|
openDropdownMenu.mouseReleased(button);
|
|
|
|
updateHoverOption(x, y);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
for (DropdownMenu<Object> menu : visibleDropdownMenus) {
|
|
|
|
menu.mouseReleased(button);
|
|
|
|
if (menu.isOpen()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 15:33:01 +01:00
|
|
|
scrollHandler.released();
|
|
|
|
|
2016-12-11 02:26:31 +01:00
|
|
|
// check if clicked, not dragged
|
|
|
|
if (Math.abs(y - mousePressY) >= 5) {
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2016-12-11 02:26:31 +01:00
|
|
|
}
|
2016-12-11 02:08:35 +01:00
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
if (x > finalWidth) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-12 18:43:01 +01:00
|
|
|
if (hoverOption != null) {
|
2017-03-26 22:57:10 +02:00
|
|
|
if (hoverOption instanceof ToggleOption) {
|
|
|
|
((ToggleOption) hoverOption).toggle();
|
2017-01-19 19:23:31 +01:00
|
|
|
if (listener != null) {
|
|
|
|
listener.onSaveOption(hoverOption);
|
|
|
|
}
|
2016-12-12 18:43:01 +01:00
|
|
|
SoundController.playSound(SoundEffect.MENUHIT);
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2017-03-26 22:57:10 +02:00
|
|
|
} else if (hoverOption == OPTION_KEY_LEFT) {
|
2016-12-12 18:43:01 +01:00
|
|
|
keyEntryLeft = true;
|
2017-03-26 22:57:10 +02:00
|
|
|
} else if (hoverOption == OPTION_KEY_RIGHT) {
|
2016-12-12 18:43:01 +01:00
|
|
|
keyEntryLeft = true;
|
|
|
|
}
|
2016-12-12 23:22:12 +01:00
|
|
|
}
|
2016-12-11 02:14:43 +01:00
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
if (hoveredNavigationEntry != null && !hoveredNavigationEntry.filtered) {
|
|
|
|
int sectionPosition = 0;
|
|
|
|
for (OptionTab section : sections) {
|
|
|
|
if (section == hoveredNavigationEntry) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (section.filtered) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sectionPosition += sectionLineHeight;
|
|
|
|
if (section.options == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (Option option : section.options) {
|
|
|
|
if (!option.isFiltered() && option.showCondition()) {
|
|
|
|
sectionPosition += optionHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
scrollHandler.scrollToPosition(sectionPosition);
|
|
|
|
}
|
|
|
|
|
2017-01-27 20:56:44 +01:00
|
|
|
if (UI.getBackButton().contains(x, y)){
|
|
|
|
hide();
|
|
|
|
if (listener != null) {
|
|
|
|
listener.onLeaveOptionsMenu();
|
|
|
|
}
|
2017-01-19 19:23:31 +01:00
|
|
|
}
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public boolean onMouseDragged(int oldx, int oldy, int newx, int newy) {
|
2016-12-11 10:08:22 +01:00
|
|
|
if (!isAdjustingSlider) {
|
2017-01-29 15:33:01 +01:00
|
|
|
int diff = newy - oldy;
|
|
|
|
if (diff != 0) {
|
|
|
|
scrollHandler.dragged(-diff);
|
|
|
|
}
|
2016-12-11 10:08:22 +01:00
|
|
|
}
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public boolean onMouseWheelMoved(int delta) {
|
2016-12-11 10:08:22 +01:00
|
|
|
if (!isAdjustingSlider) {
|
2017-01-29 15:33:01 +01:00
|
|
|
scrollHandler.scrollOffset(-delta);
|
2016-12-11 10:08:22 +01:00
|
|
|
}
|
2017-01-19 16:03:53 +01:00
|
|
|
return true;
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public boolean onKeyPressed(int key, char c) {
|
2016-12-11 12:31:52 +01:00
|
|
|
if (keyEntryRight) {
|
2017-03-26 22:57:10 +02:00
|
|
|
if (Utils.isValidGameKey(key)) {
|
|
|
|
OPTION_KEY_RIGHT.intval = key;
|
|
|
|
}
|
2016-12-11 12:31:52 +01:00
|
|
|
keyEntryRight = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyEntryLeft) {
|
2017-03-26 22:57:10 +02:00
|
|
|
if (Utils.isValidGameKey(key)) {
|
|
|
|
OPTION_KEY_LEFT.intval = key;
|
|
|
|
}
|
2016-12-11 12:31:52 +01:00
|
|
|
keyEntryLeft = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-05-27 02:10:32 +02:00
|
|
|
if (key == Keyboard.KEY_ESCAPE) {
|
2017-01-30 00:53:28 +01:00
|
|
|
if (openDropdownMenu != null) {
|
|
|
|
openDropdownMenu.keyPressed(key, c);
|
2016-12-11 11:57:17 +01:00
|
|
|
return true;
|
2017-01-19 19:23:31 +01:00
|
|
|
}
|
2017-01-29 11:28:24 +01:00
|
|
|
if (lastSearchText.length() != 0) {
|
|
|
|
resetSearch();
|
|
|
|
updateHoverOption(prevMouseX, prevMouseY);
|
|
|
|
return true;
|
|
|
|
}
|
2017-01-19 19:23:31 +01:00
|
|
|
hide();
|
|
|
|
if (listener != null) {
|
|
|
|
listener.onLeaveOptionsMenu();
|
|
|
|
}
|
|
|
|
return true;
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
2017-01-19 19:23:31 +01:00
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
searchField.keyPressed(key, c);
|
|
|
|
if (!searchField.getText().equals(lastSearchText)) {
|
|
|
|
lastSearchText = searchField.getText().toLowerCase();
|
|
|
|
updateSearch();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:03:53 +01:00
|
|
|
@Override
|
|
|
|
public boolean onKeyReleased(int key, char c) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void updateSliderOption() {
|
2017-03-26 22:57:10 +02:00
|
|
|
NumericOption o = (NumericOption) hoverOption;
|
|
|
|
int value = o.min + Math.round((float) (o.max - o.min) * (displayContainer.mouseX - sliderOptionStartX) / (sliderOptionLength));
|
|
|
|
o.setValue(Utils.clamp(value, o.min, o.max));
|
2016-12-11 16:32:21 +01:00
|
|
|
}
|
|
|
|
|
2017-05-28 16:11:05 +02:00
|
|
|
private void updateActiveSection() {
|
|
|
|
// active section is the one that is visible in the top half of the screen
|
|
|
|
activeSection = sections[0];
|
|
|
|
int virtualY = optionStartY;
|
|
|
|
for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
|
|
|
|
OptionTab section = sections[sectionIndex];
|
|
|
|
if (section.filtered) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
virtualY += sectionLineHeight;
|
|
|
|
if (virtualY > scrollHandler.getPosition() + height / 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (section.options == null) {
|
|
|
|
activeSection = section;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
|
|
|
Option option = section.options[optionIndex];
|
|
|
|
if (option.isFiltered() || !option.showCondition()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
virtualY += optionHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 01:17:30 +01:00
|
|
|
private void updateHoverOption(int mouseX, int mouseY) {
|
2017-01-30 00:53:28 +01:00
|
|
|
if (openDropdownMenu != null || keyEntryLeft || keyEntryRight) {
|
2016-12-11 11:07:28 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-12-11 02:23:02 +01:00
|
|
|
if (selectedOption != null) {
|
|
|
|
hoverOption = selectedOption;
|
|
|
|
return;
|
|
|
|
}
|
2016-12-11 01:17:30 +01:00
|
|
|
hoverOption = null;
|
2017-01-29 11:28:24 +01:00
|
|
|
if (mouseX > width) {
|
2016-12-11 01:17:30 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-29 15:33:01 +01:00
|
|
|
int mouseVirtualY = scrollHandler.getIntPosition() + mouseY - optionStartY;
|
2017-01-29 11:28:24 +01:00
|
|
|
for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
|
|
|
|
OptionTab section = sections[sectionIndex];
|
|
|
|
if (section.filtered) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-02-03 16:24:26 +01:00
|
|
|
mouseVirtualY -= sectionLineHeight;
|
2017-01-29 11:28:24 +01:00
|
|
|
if (section.options == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
2017-03-26 22:57:10 +02:00
|
|
|
Option option = section.options[optionIndex];
|
2017-01-29 11:28:24 +01:00
|
|
|
if (option.isFiltered() || !option.showCondition()) {
|
2016-12-11 01:17:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mouseVirtualY <= optionHeight) {
|
2017-05-28 16:11:05 +02:00
|
|
|
if (mouseX > navWidth && mouseVirtualY >= 0) {
|
2017-01-29 15:33:01 +01:00
|
|
|
int indicatorPos = scrollHandler.getIntPosition() + mouseY - mouseVirtualY;
|
2017-01-29 11:28:24 +01:00
|
|
|
if (indicatorPos != this.indicatorPos + indicatorOffsetToNextPos) {
|
|
|
|
this.indicatorPos += indicatorOffsetToNextPos; // finish the current moving animation
|
|
|
|
indicatorOffsetToNextPos = indicatorPos - this.indicatorPos;
|
|
|
|
indicatorMoveAnimationTime = 1; // starts animation
|
|
|
|
}
|
2016-12-11 01:17:30 +01:00
|
|
|
hoverOption = option;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mouseVirtualY -= optionHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 11:28:24 +01:00
|
|
|
private void resetSearch() {
|
|
|
|
for (OptionTab section : sections) {
|
|
|
|
section.filtered = false;
|
|
|
|
if (section.options == null) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-26 22:57:10 +02:00
|
|
|
for (Option opt : section.options) {
|
2017-01-29 11:28:24 +01:00
|
|
|
opt.filter(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
searchField.setText("");
|
|
|
|
lastSearchText = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
private void updateSearch() {
|
|
|
|
OptionTab lastBigSection = null;
|
|
|
|
boolean lastBigSectionMatches = false;
|
2017-01-29 16:53:14 +01:00
|
|
|
for (OptionTab section : sections) {
|
2017-01-29 11:28:24 +01:00
|
|
|
boolean sectionMatches = section.name.toLowerCase().contains(lastSearchText);
|
|
|
|
if (section.options == null) {
|
|
|
|
lastBigSectionMatches = sectionMatches;
|
|
|
|
lastBigSection = section;
|
2017-05-28 16:11:05 +02:00
|
|
|
if (!lastBigSectionMatches) {
|
|
|
|
section.filtered = true;
|
|
|
|
}
|
2017-01-29 11:28:24 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-01-29 16:53:14 +01:00
|
|
|
section.filtered = true;
|
2017-03-26 22:57:10 +02:00
|
|
|
for (Option option : section.options) {
|
2017-01-29 11:28:24 +01:00
|
|
|
if (lastBigSectionMatches || sectionMatches) {
|
2017-01-29 16:53:14 +01:00
|
|
|
section.filtered = false;
|
2017-01-29 11:28:24 +01:00
|
|
|
option.filter(null);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!option.filter(lastSearchText)) {
|
2017-01-29 16:53:14 +01:00
|
|
|
section.filtered = false;
|
2017-05-28 16:11:05 +02:00
|
|
|
//noinspection ConstantConditions
|
2017-01-29 16:53:14 +01:00
|
|
|
lastBigSection.filtered = false;
|
2017-01-29 11:28:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateHoverOption(prevMouseX, prevMouseY);
|
|
|
|
}
|
|
|
|
|
2017-01-19 19:23:31 +01:00
|
|
|
public interface Listener {
|
|
|
|
void onLeaveOptionsMenu();
|
2017-03-26 22:57:10 +02:00
|
|
|
void onSaveOption(Option option);
|
2016-12-11 01:17:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|