enchanced optionmenu
This commit is contained in:
parent
90f764c5bb
commit
7e135550e0
Binary file not shown.
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 430 B |
|
@ -242,6 +242,7 @@ public enum GameImage {
|
||||||
REPLAY_PLAYBACK_HALF ("playback-half", "png", false, false),
|
REPLAY_PLAYBACK_HALF ("playback-half", "png", false, false),
|
||||||
|
|
||||||
// Non-Game Components
|
// Non-Game Components
|
||||||
|
SEARCH ("search", "png", false, false),
|
||||||
CONTROL_SLIDER_BALL ("control-sliderball", "png", false, false),
|
CONTROL_SLIDER_BALL ("control-sliderball", "png", false, false),
|
||||||
CONTROL_CHECK_ON ("control-check-on", "png", false, false),
|
CONTROL_CHECK_ON ("control-check-on", "png", false, false),
|
||||||
CONTROL_CHECK_OFF ("control-check-off", "png", false, false),
|
CONTROL_CHECK_OFF ("control-check-off", "png", false, false),
|
||||||
|
|
|
@ -421,6 +421,7 @@ public class Options {
|
||||||
SHOW_UNICODE ("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) {
|
SHOW_UNICODE ("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) {
|
||||||
@Override
|
@Override
|
||||||
public void click() {
|
public void click() {
|
||||||
|
super.click();
|
||||||
if (bool) {
|
if (bool) {
|
||||||
try {
|
try {
|
||||||
Fonts.LARGE.loadGlyphs();
|
Fonts.LARGE.loadGlyphs();
|
||||||
|
@ -1009,6 +1010,12 @@ public class Options {
|
||||||
/** Whether or not this is a numeric option. */
|
/** Whether or not this is a numeric option. */
|
||||||
private OptionType type = OptionType.OTHER;
|
private OptionType type = OptionType.OTHER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this option should not be shown in the optionsmenu because it does
|
||||||
|
* not match the search string.
|
||||||
|
*/
|
||||||
|
private boolean filtered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for internal options (not displayed in-game).
|
* Constructor for internal options (not displayed in-game).
|
||||||
* @param displayName the option name, as displayed in the configuration file
|
* @param displayName the option name, as displayed in the configuration file
|
||||||
|
@ -1193,6 +1200,29 @@ public class Options {
|
||||||
return defaultVal;
|
return defaultVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the filtered flag for this option based on the given searchString.
|
||||||
|
* @param searchString the searched string or null to reset the filtered flag
|
||||||
|
* @return true if this option does need to be filtered
|
||||||
|
*/
|
||||||
|
public boolean filter(String searchString) {
|
||||||
|
if (searchString == null || searchString.length() == 0) {
|
||||||
|
filtered = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
filtered = !(displayName.toLowerCase().contains(searchString) || description.toLowerCase().contains(searchString));
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this option should be filtered (= not shown) because it does not
|
||||||
|
* match the search string.
|
||||||
|
* @return true if the option shouldn't be shown.
|
||||||
|
*/
|
||||||
|
public boolean isFiltered() {
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Map of option display names to GameOptions. */
|
/** Map of option display names to GameOptions. */
|
||||||
|
|
|
@ -326,7 +326,7 @@ public class Game extends ComplexOpsuState {
|
||||||
this.instanceContainer = instanceContainer;
|
this.instanceContainer = instanceContainer;
|
||||||
mirrorCursor = new Cursor(true);
|
mirrorCursor = new Cursor(true);
|
||||||
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
|
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
|
||||||
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.storyboardOptions, 0);
|
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.storyboardOptions);
|
||||||
this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
|
this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
|
||||||
storyboardOverlay.show();
|
storyboardOverlay.show();
|
||||||
moveStoryboardOverlay.show();
|
moveStoryboardOverlay.show();
|
||||||
|
|
|
@ -20,46 +20,65 @@ package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options.GameOption;
|
import itdelatrisu.opsu.Options.GameOption;
|
||||||
|
|
||||||
import yugecin.opsudance.ui.OptionsOverlay;
|
|
||||||
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
|
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
|
||||||
|
|
||||||
public class OptionsMenu {
|
public class OptionsMenu {
|
||||||
|
|
||||||
public static final OptionTab[] normalOptions = new OptionsOverlay.OptionTab[]{
|
public static final OptionTab[] normalOptions = new OptionTab[] {
|
||||||
new OptionTab("Display", new GameOption[]{
|
new OptionTab("GENERAL", null),
|
||||||
|
new OptionTab("LANGUAGE", new GameOption[]{
|
||||||
|
GameOption.SHOW_UNICODE,
|
||||||
|
}),
|
||||||
|
new OptionTab("GRAPHICS", null),
|
||||||
|
new OptionTab("RENDERER", new GameOption[] {
|
||||||
GameOption.SCREEN_RESOLUTION,
|
GameOption.SCREEN_RESOLUTION,
|
||||||
GameOption.FULLSCREEN,
|
|
||||||
GameOption.ALLOW_LARGER_RESOLUTIONS,
|
GameOption.ALLOW_LARGER_RESOLUTIONS,
|
||||||
GameOption.SKIN,
|
GameOption.FULLSCREEN,
|
||||||
|
// TODO d: UPS option
|
||||||
GameOption.TARGET_FPS,
|
GameOption.TARGET_FPS,
|
||||||
GameOption.SHOW_FPS,
|
GameOption.SHOW_FPS,
|
||||||
GameOption.SHOW_UNICODE,
|
|
||||||
GameOption.SCREENSHOT_FORMAT,
|
GameOption.SCREENSHOT_FORMAT,
|
||||||
|
}),
|
||||||
|
new OptionTab("SLIDER OPTIONS", new GameOption[]{
|
||||||
|
GameOption.SNAKING_SLIDERS,
|
||||||
|
GameOption.FALLBACK_SLIDERS,
|
||||||
|
GameOption.SHRINKING_SLIDERS,
|
||||||
|
GameOption.MERGING_SLIDERS,
|
||||||
|
//GameOption.MERGING_SLIDERS_MIRROR_POOL,
|
||||||
|
GameOption.DRAW_SLIDER_ENDCIRCLES,
|
||||||
|
}),
|
||||||
|
new OptionTab("SKIN", null),
|
||||||
|
new OptionTab("SKIN", new GameOption[]{
|
||||||
|
GameOption.SKIN,
|
||||||
|
GameOption.IGNORE_BEATMAP_SKINS,
|
||||||
GameOption.DYNAMIC_BACKGROUND,
|
GameOption.DYNAMIC_BACKGROUND,
|
||||||
GameOption.LOAD_HD_IMAGES,
|
GameOption.LOAD_HD_IMAGES,
|
||||||
GameOption.LOAD_VERBOSE,
|
GameOption.LOAD_VERBOSE,
|
||||||
GameOption.COLOR_MAIN_MENU_LOGO,
|
GameOption.COLOR_MAIN_MENU_LOGO,
|
||||||
}),
|
}),
|
||||||
new OptionTab("Music", new GameOption[] {
|
new OptionTab("CURSOR", new GameOption[]{
|
||||||
|
GameOption.CURSOR_SIZE,
|
||||||
|
GameOption.NEW_CURSOR,
|
||||||
|
GameOption.DISABLE_CURSOR
|
||||||
|
// TODO use combo colour as tint for slider ball option
|
||||||
|
}),
|
||||||
|
new OptionTab("AUDIO", null),
|
||||||
|
new OptionTab("VOLUME", new GameOption[]{
|
||||||
GameOption.MASTER_VOLUME,
|
GameOption.MASTER_VOLUME,
|
||||||
GameOption.MUSIC_VOLUME,
|
GameOption.MUSIC_VOLUME,
|
||||||
GameOption.EFFECT_VOLUME,
|
GameOption.EFFECT_VOLUME,
|
||||||
GameOption.HITSOUND_VOLUME,
|
GameOption.HITSOUND_VOLUME,
|
||||||
GameOption.SAMPLE_VOLUME_OVERRIDE,
|
GameOption.SAMPLE_VOLUME_OVERRIDE,
|
||||||
|
}),
|
||||||
|
new OptionTab("MISC", new GameOption[] {
|
||||||
GameOption.MUSIC_OFFSET,
|
GameOption.MUSIC_OFFSET,
|
||||||
GameOption.DISABLE_SOUNDS,
|
GameOption.DISABLE_SOUNDS,
|
||||||
GameOption.ENABLE_THEME_SONG
|
GameOption.ENABLE_THEME_SONG
|
||||||
}),
|
}),
|
||||||
new OptionTab("Gameplay", new GameOption[] {
|
new OptionTab("GAMEPLAY", null),
|
||||||
|
new OptionTab("GENERAL", new GameOption[] {
|
||||||
GameOption.BACKGROUND_DIM,
|
GameOption.BACKGROUND_DIM,
|
||||||
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
||||||
GameOption.IGNORE_BEATMAP_SKINS,
|
|
||||||
GameOption.SNAKING_SLIDERS,
|
|
||||||
GameOption.SHRINKING_SLIDERS,
|
|
||||||
GameOption.FALLBACK_SLIDERS,
|
|
||||||
GameOption.MERGING_SLIDERS,
|
|
||||||
//GameOption.MERGING_SLIDERS_MIRROR_POOL,
|
|
||||||
GameOption.DRAW_SLIDER_ENDCIRCLES,
|
|
||||||
GameOption.SHOW_HIT_LIGHTING,
|
GameOption.SHOW_HIT_LIGHTING,
|
||||||
GameOption.SHOW_HIT_ANIMATIONS,
|
GameOption.SHOW_HIT_ANIMATIONS,
|
||||||
GameOption.SHOW_COMBO_BURSTS,
|
GameOption.SHOW_COMBO_BURSTS,
|
||||||
|
@ -70,26 +89,30 @@ public class OptionsMenu {
|
||||||
GameOption.MAP_END_DELAY,
|
GameOption.MAP_END_DELAY,
|
||||||
GameOption.EPILEPSY_WARNING,
|
GameOption.EPILEPSY_WARNING,
|
||||||
}),
|
}),
|
||||||
new OptionTab("Input", new GameOption[] {
|
new OptionTab("INPUT", null),
|
||||||
|
new OptionTab("KEY MAPPING", new GameOption[]{
|
||||||
GameOption.KEY_LEFT,
|
GameOption.KEY_LEFT,
|
||||||
GameOption.KEY_RIGHT,
|
GameOption.KEY_RIGHT,
|
||||||
|
}),
|
||||||
|
new OptionTab("MOUSE", new GameOption[] {
|
||||||
GameOption.DISABLE_MOUSE_WHEEL,
|
GameOption.DISABLE_MOUSE_WHEEL,
|
||||||
GameOption.DISABLE_MOUSE_BUTTONS,
|
GameOption.DISABLE_MOUSE_BUTTONS,
|
||||||
GameOption.CURSOR_SIZE,
|
|
||||||
GameOption.NEW_CURSOR,
|
|
||||||
GameOption.DISABLE_CURSOR
|
|
||||||
}),
|
}),
|
||||||
new OptionTab("Custom", new GameOption[] {
|
new OptionTab("CUSTOM", null),
|
||||||
|
new OptionTab("DIFFICULTY", new GameOption[]{
|
||||||
GameOption.FIXED_CS,
|
GameOption.FIXED_CS,
|
||||||
GameOption.FIXED_HP,
|
GameOption.FIXED_HP,
|
||||||
GameOption.FIXED_AR,
|
GameOption.FIXED_AR,
|
||||||
GameOption.FIXED_OD,
|
GameOption.FIXED_OD,
|
||||||
|
}),
|
||||||
|
new OptionTab("MISC", new GameOption[] {
|
||||||
GameOption.CHECKPOINT,
|
GameOption.CHECKPOINT,
|
||||||
GameOption.REPLAY_SEEKING,
|
GameOption.REPLAY_SEEKING,
|
||||||
GameOption.DISABLE_UPDATER,
|
GameOption.DISABLE_UPDATER,
|
||||||
GameOption.ENABLE_WATCH_SERVICE
|
GameOption.ENABLE_WATCH_SERVICE
|
||||||
}),
|
}),
|
||||||
new OptionTab("Dance", new GameOption[] {
|
new OptionTab("DANCE", null),
|
||||||
|
new OptionTab("MOVER", new GameOption[]{
|
||||||
GameOption.DANCE_MOVER,
|
GameOption.DANCE_MOVER,
|
||||||
GameOption.DANCE_EXGON_DELAY,
|
GameOption.DANCE_EXGON_DELAY,
|
||||||
GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS,
|
GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS,
|
||||||
|
@ -100,39 +123,55 @@ public class OptionsMenu {
|
||||||
GameOption.DANCE_SLIDER_MOVER_TYPE,
|
GameOption.DANCE_SLIDER_MOVER_TYPE,
|
||||||
GameOption.DANCE_SPINNER,
|
GameOption.DANCE_SPINNER,
|
||||||
GameOption.DANCE_SPINNER_DELAY,
|
GameOption.DANCE_SPINNER_DELAY,
|
||||||
|
}),
|
||||||
|
new OptionTab("SLIDER OPTIONS", new GameOption[]{
|
||||||
GameOption.DANCE_LAZY_SLIDERS,
|
GameOption.DANCE_LAZY_SLIDERS,
|
||||||
GameOption.DANCE_CIRCLE_STREAMS,
|
|
||||||
GameOption.DANCE_ONLY_CIRCLE_STACKS,
|
|
||||||
GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
|
GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
|
||||||
GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
|
GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
|
||||||
|
}),
|
||||||
|
new OptionTab("CIRCLE MOVEMENTS", new GameOption[]{
|
||||||
|
GameOption.DANCE_CIRCLE_STREAMS,
|
||||||
|
GameOption.DANCE_ONLY_CIRCLE_STACKS,
|
||||||
|
}),
|
||||||
|
new OptionTab("MIRROR", new GameOption[] {
|
||||||
GameOption.DANCE_MIRROR,
|
GameOption.DANCE_MIRROR,
|
||||||
}),
|
}),
|
||||||
new OptionTab("Dance display", new GameOption[] {
|
new OptionTab("ADVANCED DISPLAY", null),
|
||||||
|
new OptionTab("OBJECTS", new GameOption[]{
|
||||||
GameOption.DANCE_DRAW_APPROACH,
|
GameOption.DANCE_DRAW_APPROACH,
|
||||||
GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
|
GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
|
||||||
GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
|
GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
|
||||||
GameOption.DANCE_RGB_OBJECT_INC,
|
GameOption.DANCE_RGB_OBJECT_INC,
|
||||||
|
GameOption.DANCE_HIDE_OBJECTS,
|
||||||
|
}),
|
||||||
|
new OptionTab("CURSOR", new GameOption[]{
|
||||||
GameOption.DANCE_CURSOR_COLOR_OVERRIDE,
|
GameOption.DANCE_CURSOR_COLOR_OVERRIDE,
|
||||||
GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
|
GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
|
||||||
GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL,
|
GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL,
|
||||||
GameOption.DANCE_RGB_CURSOR_INC,
|
GameOption.DANCE_RGB_CURSOR_INC,
|
||||||
GameOption.DANCE_CURSOR_TRAIL_OVERRIDE,
|
GameOption.DANCE_CURSOR_TRAIL_OVERRIDE,
|
||||||
GameOption.DANCE_REMOVE_BG,
|
}),
|
||||||
GameOption.DANCE_HIDE_OBJECTS,
|
new OptionTab("MISC", new GameOption[] {
|
||||||
GameOption.DANCE_HIDE_UI,
|
GameOption.DANCE_HIDE_UI,
|
||||||
|
GameOption.DANCE_REMOVE_BG,
|
||||||
GameOption.DANCE_ENABLE_SB,
|
GameOption.DANCE_ENABLE_SB,
|
||||||
}),
|
}),
|
||||||
new OptionTab ("Pippi", new GameOption[] {
|
new OptionTab ("PIPPI", null),
|
||||||
|
new OptionTab ("GENERAL", new GameOption[]{
|
||||||
GameOption.PIPPI_ENABLE,
|
GameOption.PIPPI_ENABLE,
|
||||||
GameOption.PIPPI_RADIUS_PERCENT,
|
GameOption.PIPPI_RADIUS_PERCENT,
|
||||||
|
}),
|
||||||
|
new OptionTab ("ANGLE MULTIPLIERS", new GameOption[]{
|
||||||
GameOption.PIPPI_ANGLE_INC_MUL,
|
GameOption.PIPPI_ANGLE_INC_MUL,
|
||||||
GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
|
GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
|
||||||
|
}),
|
||||||
|
new OptionTab ("MISC", new GameOption[] {
|
||||||
GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
|
GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
|
||||||
GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
|
GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final OptionTab[] storyboardOptions = new OptionsOverlay.OptionTab[]{
|
public static final OptionTab[] storyboardOptions = new OptionTab[] {
|
||||||
new OptionTab("Gameplay", new GameOption[] {
|
new OptionTab("Gameplay", new GameOption[] {
|
||||||
GameOption.BACKGROUND_DIM,
|
GameOption.BACKGROUND_DIM,
|
||||||
GameOption.DANCE_REMOVE_BG,
|
GameOption.DANCE_REMOVE_BG,
|
||||||
|
|
|
@ -328,7 +328,7 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) {
|
public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) {
|
||||||
super(displayContainer);
|
super(displayContainer);
|
||||||
this.instanceContainer = instanceContainer;
|
this.instanceContainer = instanceContainer;
|
||||||
optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.normalOptions, 0);
|
optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.normalOptions);
|
||||||
overlays.add(optionsOverlay);
|
overlays.add(optionsOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,16 +96,7 @@ public class TextField extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(Graphics g) {
|
public void render(Graphics g) {
|
||||||
if (lastKey != -1) {
|
performKeyRepeat();
|
||||||
if (displayContainer.input.isKeyDown(lastKey)) {
|
|
||||||
if (repeatTimer < System.currentTimeMillis()) {
|
|
||||||
repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
|
|
||||||
keyPressed(lastKey, lastChar);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lastKey = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rectangle oldClip = g.getClip();
|
Rectangle oldClip = g.getClip();
|
||||||
g.setWorldClip(x,y,width, height);
|
g.setWorldClip(x,y,width, height);
|
||||||
|
|
||||||
|
@ -145,6 +136,20 @@ public class TextField extends Component {
|
||||||
g.setClip(oldClip);
|
g.setClip(oldClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void performKeyRepeat() {
|
||||||
|
if (lastKey == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!displayContainer.input.isKeyDown(lastKey)) {
|
||||||
|
lastKey = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (repeatTimer < System.currentTimeMillis()) {
|
||||||
|
repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
|
||||||
|
keyPressed(lastKey, lastChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,32 +26,76 @@ import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
import itdelatrisu.opsu.ui.Colors;
|
import itdelatrisu.opsu.ui.Colors;
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
import itdelatrisu.opsu.ui.MenuButton;
|
|
||||||
import itdelatrisu.opsu.ui.UI;
|
import itdelatrisu.opsu.ui.UI;
|
||||||
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
import org.newdawn.slick.*;
|
import org.newdawn.slick.*;
|
||||||
|
import org.newdawn.slick.gui.TextField;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.state.OverlayOpsuState;
|
import yugecin.opsudance.core.state.OverlayOpsuState;
|
||||||
|
import yugecin.opsudance.utils.FontUtil;
|
||||||
|
|
||||||
public class OptionsOverlay extends OverlayOpsuState {
|
public class OptionsOverlay extends OverlayOpsuState {
|
||||||
|
|
||||||
private final DisplayContainer displayContainer;
|
private final DisplayContainer displayContainer;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
private Listener listener;
|
private Listener listener;
|
||||||
|
|
||||||
private Image sliderBallImg;
|
private Image sliderBallImg;
|
||||||
private Image checkOnImg;
|
private Image checkOnImg;
|
||||||
private Image checkOffImg;
|
private Image checkOffImg;
|
||||||
|
private Image chevronDownImg;
|
||||||
|
private Image chevronRightImg;
|
||||||
|
private Image searchImg;
|
||||||
|
|
||||||
private OptionTab[] tabs;
|
private OptionTab[] sections;
|
||||||
private int selectedTab;
|
|
||||||
|
|
||||||
private GameOption hoverOption;
|
private GameOption hoverOption;
|
||||||
private GameOption selectedOption;
|
private GameOption selectedOption;
|
||||||
|
private GameOption selectedListOption;
|
||||||
|
|
||||||
private int sliderOptionStartX;
|
private int sliderOptionStartX;
|
||||||
private int sliderOptionLength;
|
private int sliderOptionLength;
|
||||||
private boolean isAdjustingSlider;
|
private boolean isAdjustingSlider;
|
||||||
|
|
||||||
|
private static final int LISTOPENANIMATIONTIME = 200;
|
||||||
|
private static final int LISTCLOSEANIMATIONTIME = 175;
|
||||||
|
private int listAnimationTime;
|
||||||
private boolean isListOptionOpen;
|
private boolean isListOptionOpen;
|
||||||
private int listItemHeight;
|
private int listItemHeight;
|
||||||
private int listStartX;
|
private int listStartX;
|
||||||
|
@ -60,6 +104,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
private int listHeight;
|
private int listHeight;
|
||||||
private int listHoverIndex;
|
private int listHoverIndex;
|
||||||
|
|
||||||
|
private int finalWidth;
|
||||||
private int width;
|
private int width;
|
||||||
private int height;
|
private int height;
|
||||||
|
|
||||||
|
@ -67,6 +112,20 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
private int optionStartX;
|
private int optionStartX;
|
||||||
private int optionStartY;
|
private int optionStartY;
|
||||||
private int optionHeight;
|
private int optionHeight;
|
||||||
|
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;
|
||||||
|
|
||||||
private int scrollOffset;
|
private int scrollOffset;
|
||||||
private int maxScrollOffset;
|
private int maxScrollOffset;
|
||||||
|
@ -81,13 +140,16 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
|
|
||||||
private int sliderSoundDelay;
|
private int sliderSoundDelay;
|
||||||
|
|
||||||
public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] tabs, int defaultSelectedTabIndex) {
|
private TextField searchField;
|
||||||
|
private String lastSearchText;
|
||||||
|
|
||||||
|
public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] sections) {
|
||||||
this.displayContainer = displayContainer;
|
this.displayContainer = displayContainer;
|
||||||
|
|
||||||
this.tabs = tabs;
|
this.sections = sections;
|
||||||
selectedTab = defaultSelectedTabIndex;
|
|
||||||
|
|
||||||
listHoverIndex = -1;
|
listHoverIndex = -1;
|
||||||
|
searchField = new TextField(displayContainer, null, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setListener(Listener listener) {
|
public void setListener(Listener listener) {
|
||||||
|
@ -98,74 +160,62 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
public void revalidate() {
|
public void revalidate() {
|
||||||
super.revalidate();
|
super.revalidate();
|
||||||
|
|
||||||
sliderBallImg = GameImage.CONTROL_SLIDER_BALL.getImage().getScaledCopy(20, 20);
|
finalWidth = Math.max((int) (displayContainer.width * 0.321f), 340);
|
||||||
checkOnImg = GameImage.CONTROL_CHECK_ON.getImage().getScaledCopy(20, 20);
|
|
||||||
checkOffImg = GameImage.CONTROL_CHECK_OFF.getImage().getScaledCopy(20, 20);
|
|
||||||
|
|
||||||
width = displayContainer.width;
|
|
||||||
height = displayContainer.height;
|
height = displayContainer.height;
|
||||||
|
|
||||||
// calculate positions
|
// calculate positions
|
||||||
optionWidth = width / 2;
|
paddingRight = (int) (displayContainer.width * 0.009375f); // not so accurate
|
||||||
optionHeight = (int) ((Fonts.MEDIUM.getLineHeight()) * 1.1f);
|
paddingLeft = (int) (displayContainer.width * 0.0180f); // not so accurate
|
||||||
|
paddingTextLeft = paddingLeft + LINEWIDTH + (int) (displayContainer.width * 0.00625); // not so accurate
|
||||||
|
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();
|
||||||
|
|
||||||
|
optionHeight = (int) (Fonts.MEDIUM.getLineHeight() * 1.3f);
|
||||||
|
optionTextOffsetY = (int) ((optionHeight - Fonts.MEDIUM.getLineHeight()) / 2f);
|
||||||
listItemHeight = (int) (optionHeight * 4f / 5f);
|
listItemHeight = (int) (optionHeight * 4f / 5f);
|
||||||
optionStartX = optionWidth / 2;
|
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);
|
||||||
|
|
||||||
|
chevronDownImg = GameImage.CHEVRON_DOWN.getImage().getScaledCopy(controlImageSize, controlImageSize);
|
||||||
|
chevronRightImg = GameImage.CHEVRON_RIGHT.getImage().getScaledCopy(controlImageSize, controlImageSize);
|
||||||
|
chevronRightImg.setImageColor(0f, 0f, 0f);
|
||||||
|
|
||||||
|
int searchImgSize = (int) (Fonts.LARGE.getLineHeight() * 0.75f);
|
||||||
|
searchImg = GameImage.SEARCH.getImage().getScaledCopy(searchImgSize, searchImgSize);
|
||||||
|
|
||||||
// initialize tabs
|
|
||||||
Image tabImage = GameImage.MENU_TAB.getImage();
|
|
||||||
float tabX = width * 0.032f + (tabImage.getWidth() / 3);
|
|
||||||
float tabY = Fonts.XLARGE.getLineHeight() + Fonts.DEFAULT.getLineHeight() + height * 0.015f - (tabImage.getHeight() / 2f);
|
|
||||||
int tabOffset = Math.min(tabImage.getWidth(), width / tabs.length);
|
|
||||||
maxScrollOffset = Fonts.MEDIUM.getLineHeight() * 2 * tabs.length;
|
|
||||||
scrollOffset = 0;
|
scrollOffset = 0;
|
||||||
for (OptionTab tab : tabs) {
|
|
||||||
/*
|
|
||||||
if (defaultSelectedTabIndex-- > 0) {
|
|
||||||
scrollOffset += Fonts.MEDIUM.getLineHeight() * 2;
|
|
||||||
scrollOffset += tab.options.length * optionHeight;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
maxScrollOffset += tab.options.length * optionHeight;
|
|
||||||
tab.button = new MenuButton(tabImage, tabX, tabY);
|
|
||||||
tabX += tabOffset;
|
|
||||||
if (tabX + tabOffset > width) {
|
|
||||||
tabX = 0;
|
|
||||||
tabY += GameImage.MENU_TAB.getImage().getHeight() / 2f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
maxScrollOffset += -optionStartY - optionHeight;
|
|
||||||
|
|
||||||
// calculate other positions
|
|
||||||
optionStartY = (int) (tabY + tabImage.getHeight() / 2 + 2); // +2 for the separator line
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRender(Graphics g) {
|
public void onRender(Graphics g) {
|
||||||
|
g.setClip(0, 0, width, height);
|
||||||
|
|
||||||
// bg
|
// bg
|
||||||
g.setColor(Colors.BLACK_ALPHA_75);
|
g.setColor(COL_BG);
|
||||||
g.fillRect(0, 0, width, height);
|
g.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
// title
|
// title
|
||||||
renderTitle();
|
renderTitle();
|
||||||
|
|
||||||
// option tabs
|
renderIndicator(g);
|
||||||
renderTabs();
|
|
||||||
|
|
||||||
// line separator
|
|
||||||
g.setColor(Color.white);
|
|
||||||
g.setLineWidth(2f);
|
|
||||||
g.drawLine(0, optionStartY - 1, width, optionStartY - 1);
|
|
||||||
g.resetLineWidth();
|
|
||||||
|
|
||||||
// options
|
// options
|
||||||
renderOptions(g);
|
renderOptions(g);
|
||||||
if (isListOptionOpen) {
|
|
||||||
renderOpenList(g);
|
renderOpenList(g);
|
||||||
}
|
|
||||||
|
renderSearch(g);
|
||||||
|
|
||||||
// scrollbar
|
// scrollbar
|
||||||
g.setColor(Color.white);
|
g.setColor(COL_WHITE);
|
||||||
g.fillRoundRect(optionStartX + optionWidth + 15, optionStartY + ((float) scrollOffset / (maxScrollOffset)) * (height - optionStartY - 45), 10, 45, 2);
|
g.fillRect(width - 5, ((float) scrollOffset / (maxScrollOffset)) * (height - 45), 5, 45);
|
||||||
g.clearClip();
|
g.clearClip();
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
@ -180,184 +230,301 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.fillRect(0, indicatorPos - scrollOffset, width, optionHeight);
|
||||||
|
}
|
||||||
|
|
||||||
private void renderKeyEntry(Graphics g) {
|
private void renderKeyEntry(Graphics g) {
|
||||||
g.setColor(Colors.BLACK_ALPHA_75);
|
g.setColor(COL_BG);
|
||||||
g.fillRect(0, 0, width, height);
|
g.fillRect(0, 0, displayContainer.width, height);
|
||||||
g.setColor(Color.white);
|
g.setColor(COL_WHITE);
|
||||||
String prompt = (keyEntryLeft) ? "Please press the new left-click key." : "Please press the new right-click key.";
|
String prompt = (keyEntryLeft) ? "Please press the new left-click key." : "Please press the new right-click key.";
|
||||||
Fonts.LARGE.drawString((width - Fonts.LARGE.getWidth(prompt)) / 2, (height - Fonts.LARGE.getLineHeight()) / 2, prompt);
|
int y = (displayContainer.height - Fonts.LARGE.getLineHeight()) / 2;
|
||||||
|
FontUtil.drawCentered(Fonts.LARGE, displayContainer.width, 0, y, prompt, COL_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderTooltip(Graphics g) {
|
private void renderTooltip(Graphics g) {
|
||||||
if (hoverOption != null) {
|
if (hoverOption != null) {
|
||||||
UI.updateTooltip(displayContainer.renderDelta, hoverOption.getDescription(), false);
|
String tip = hoverOption.getDescription();
|
||||||
|
if (hoverOption.getType() == OptionType.NUMERIC) {
|
||||||
|
tip = "(" + hoverOption.getValueString() + ") " + tip;
|
||||||
|
}
|
||||||
|
UI.updateTooltip(displayContainer.renderDelta, tip, false);
|
||||||
UI.drawTooltip(g);
|
UI.drawTooltip(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderOptions(Graphics g) {
|
private void renderOptions(Graphics g) {
|
||||||
g.setClip(0, optionStartY, width, height - optionStartY);
|
|
||||||
listStartX = listStartY = listWidth = listHeight = 0; // render out of the screen
|
|
||||||
int y = -scrollOffset + optionStartY;
|
int y = -scrollOffset + optionStartY;
|
||||||
selectedTab = 0;
|
maxScrollOffset = optionStartY;
|
||||||
maxScrollOffset = Fonts.MEDIUM.getLineHeight() * 2 * tabs.length;
|
|
||||||
boolean render = true;
|
boolean render = true;
|
||||||
for (int tabIndex = 0; tabIndex < tabs.length; tabIndex++) {
|
int lastNonSkippedSectionIndex = 0;
|
||||||
OptionTab tab = tabs[tabIndex];
|
int sectionIndex = 0;
|
||||||
if (y > 0) {
|
for (; sectionIndex < sections.length; sectionIndex++) {
|
||||||
if (render) {
|
lastNonSkippedSectionIndex = sectionIndex;
|
||||||
int x = optionStartX + (optionWidth - Fonts.LARGE.getWidth(tab.name)) / 2;
|
OptionTab section = sections[sectionIndex];
|
||||||
Fonts.LARGE.drawString(x, y + Fonts.LARGE.getLineHeight() * 0.6f, tab.name, Color.cyan);
|
if (section.filtered) {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
selectedTab++;
|
|
||||||
}
|
|
||||||
y += Fonts.MEDIUM.getLineHeight() * 2;
|
|
||||||
for (int optionIndex = 0; optionIndex < tab.options.length; optionIndex++) {
|
|
||||||
GameOption option = tab.options[optionIndex];
|
|
||||||
if (!option.showCondition()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
maxScrollOffset += optionHeight;
|
int lineStartY = (int) (y + Fonts.LARGE.getLineHeight() * 0.6f);
|
||||||
if ((y > 0 && render) || (isListOptionOpen && hoverOption == option)) {
|
if (render) {
|
||||||
renderOption(g, option, y, option == hoverOption);
|
if (section.options == null) {
|
||||||
|
FontUtil.drawRightAligned(Fonts.XLARGE, width, -paddingRight, (int) (y + Fonts.XLARGE.getLineHeight() * 0.3f), section.name, COL_CYAN);
|
||||||
|
} else {
|
||||||
|
Fonts.MEDIUMBOLD.drawString(paddingTextLeft, lineStartY, section.name, COL_WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y += Fonts.LARGE.getLineHeight() * 1.5f;
|
||||||
|
maxScrollOffset += Fonts.LARGE.getLineHeight() * 1.5f;
|
||||||
|
if (section.options == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int lineHeight = (int) (Fonts.LARGE.getLineHeight() * 0.9f);
|
||||||
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
||||||
|
GameOption option = section.options[optionIndex];
|
||||||
|
if (!option.showCondition() || option.isFiltered()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((y > -optionHeight && render) || (isListOptionOpen && hoverOption == option)) {
|
||||||
|
renderOption(g, option, y);
|
||||||
}
|
}
|
||||||
y += optionHeight;
|
y += optionHeight;
|
||||||
|
maxScrollOffset += optionHeight;
|
||||||
|
lineHeight += optionHeight;
|
||||||
if (y > height) {
|
if (y > height) {
|
||||||
render = false;
|
render = false;
|
||||||
tabIndex = tabs.length;
|
sectionIndex = sections.length;
|
||||||
|
maxScrollOffset += (section.options.length - optionIndex - 1) * optionHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g.setColor(COL_GREY);
|
||||||
|
g.fillRect(paddingLeft, lineStartY, LINEWIDTH, lineHeight);
|
||||||
|
}
|
||||||
|
// iterate over skipped options to correctly calculate max scroll offset
|
||||||
|
for (sectionIndex = lastNonSkippedSectionIndex + 1; sectionIndex < sections.length; sectionIndex++) {
|
||||||
|
maxScrollOffset += Fonts.LARGE.getLineHeight() * 1.5f;
|
||||||
|
if (sections[sectionIndex].options != null) {
|
||||||
|
maxScrollOffset += sections[sectionIndex].options.length * optionHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxScrollOffset -= height * 2 / 3;
|
||||||
|
if (maxScrollOffset < 0) {
|
||||||
|
maxScrollOffset = 0;
|
||||||
|
}
|
||||||
|
if (scrollOffset > maxScrollOffset) {
|
||||||
|
scrollOffset = maxScrollOffset;
|
||||||
}
|
}
|
||||||
maxScrollOffset -= optionStartY - optionHeight * 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderOpenList(Graphics g) {
|
private void renderOpenList(Graphics g) {
|
||||||
|
if (!isListOptionOpen && listAnimationTime == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float progress;
|
||||||
|
int listItemHeight;
|
||||||
|
if (isListOptionOpen) {
|
||||||
|
listAnimationTime = Math.min(LISTOPENANIMATIONTIME, listAnimationTime + displayContainer.renderDelta);
|
||||||
|
progress = (float) listAnimationTime / LISTOPENANIMATIONTIME;
|
||||||
|
} else {
|
||||||
|
listAnimationTime -= displayContainer.renderDelta;
|
||||||
|
if (listAnimationTime <= 0) {
|
||||||
|
listAnimationTime = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
progress = (float) listAnimationTime / LISTCLOSEANIMATIONTIME;
|
||||||
|
}
|
||||||
|
listItemHeight = (int) (this.listItemHeight * progress);
|
||||||
|
listHeight = (int) (this.listHeight * progress);
|
||||||
|
final int borderRadius = 6;
|
||||||
|
float blackAlphaA = Colors.BLACK_ALPHA_85.a;
|
||||||
|
float whiteA = COL_WHITE.a;
|
||||||
|
float bgA = COL_BG.a;
|
||||||
|
COL_WHITE.a *= progress;
|
||||||
|
COL_BG.a *= progress;
|
||||||
|
Colors.BLACK_ALPHA_85.a *= progress;
|
||||||
g.setColor(Colors.BLACK_ALPHA_85);
|
g.setColor(Colors.BLACK_ALPHA_85);
|
||||||
g.fillRect(listStartX, listStartY, listWidth, listHeight);
|
g.fillRoundRect(listStartX, listStartY, listWidth, listHeight, borderRadius, 15);
|
||||||
|
Object[] listItems = selectedListOption.getListItems();
|
||||||
if (listHoverIndex != -1) {
|
if (listHoverIndex != -1) {
|
||||||
g.setColor(Colors.ORANGE_BUTTON);
|
g.setColor(COL_COMBOBOX_HOVER);
|
||||||
|
if (listHoverIndex == 0) {
|
||||||
|
g.fillRoundRect(listStartX, listStartY + listHoverIndex * listItemHeight, listWidth, listItemHeight, borderRadius, 15);
|
||||||
|
g.fillRect(listStartX, listStartY + listHoverIndex * listItemHeight + listItemHeight / 2, listWidth, listItemHeight / 2);
|
||||||
|
} else if (listHoverIndex == listItems.length - 1) {
|
||||||
|
g.fillRoundRect(listStartX, listStartY + listHoverIndex * listItemHeight, listWidth, listItemHeight, borderRadius, 15);
|
||||||
|
g.fillRect(listStartX, listStartY + listHoverIndex * listItemHeight, listWidth, listItemHeight / 2);
|
||||||
|
} else {
|
||||||
g.fillRect(listStartX, listStartY + listHoverIndex * listItemHeight, listWidth, listItemHeight);
|
g.fillRect(listStartX, listStartY + listHoverIndex * listItemHeight, listWidth, listItemHeight);
|
||||||
}
|
}
|
||||||
g.setLineWidth(1f);
|
chevronRightImg.draw(listStartX + 2, listStartY + listHoverIndex * listItemHeight + (listItemHeight - controlImageSize) / 2, COL_BG);
|
||||||
g.setColor(Color.white);
|
}
|
||||||
g.drawRect(listStartX, listStartY, listWidth, listHeight);
|
|
||||||
Object[] listItems = hoverOption.getListItems();
|
|
||||||
int y = listStartY;
|
int y = listStartY;
|
||||||
|
String selectedValue = selectedListOption.getValueString();
|
||||||
for (Object item : listItems) {
|
for (Object item : listItems) {
|
||||||
Fonts.MEDIUM.drawString(listStartX + 20, y - Fonts.MEDIUM.getLineHeight() * 0.05f, item.toString());
|
String text = item.toString();
|
||||||
|
Font font;
|
||||||
|
if (text.equals(selectedValue)) {
|
||||||
|
font = Fonts.MEDIUMBOLD;
|
||||||
|
} else {
|
||||||
|
font = Fonts.MEDIUM;
|
||||||
|
}
|
||||||
|
font.drawString(listStartX + 20, y - Fonts.MEDIUM.getLineHeight() * 0.05f, item.toString(), COL_WHITE);
|
||||||
y += listItemHeight;
|
y += listItemHeight;
|
||||||
}
|
}
|
||||||
|
COL_BG.a = bgA;
|
||||||
|
COL_WHITE.a = whiteA;
|
||||||
|
Colors.BLACK_ALPHA_85.a = blackAlphaA;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderOption(Graphics g, GameOption option, int y, boolean focus) {
|
private void renderOption(Graphics g, GameOption option, int y) {
|
||||||
Color col = focus ? Colors.GREEN : Colors.WHITE_FADE;
|
|
||||||
OptionType type = option.getType();
|
OptionType type = option.getType();
|
||||||
Object[] listItems = option.getListItems();
|
Object[] listItems = option.getListItems();
|
||||||
if (listItems != null) {
|
if (listItems != null) {
|
||||||
renderListOption(g, option, y, col, listItems);
|
renderListOption(g, option, y, listItems);
|
||||||
} else if (type == OptionType.BOOLEAN) {
|
} else if (type == OptionType.BOOLEAN) {
|
||||||
renderCheckOption(g, option, y, col);
|
renderCheckOption(option, y);
|
||||||
} else if (type == OptionType.NUMERIC) {
|
} else if (type == OptionType.NUMERIC) {
|
||||||
renderSliderOption(g, option, y, col);
|
renderSliderOption(g, option, y);
|
||||||
} else {
|
} else {
|
||||||
renderGenericOption(g, option, y, col);
|
renderGenericOption(option, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderListOption(Graphics g, GameOption option, int y, Color textColor, Object[] listItems) {
|
private void renderListOption(Graphics g, GameOption option, int y, Object[] listItems) {
|
||||||
int nameLen = Fonts.MEDIUM.getWidth(option.getName());
|
int nameLen = Fonts.MEDIUM.getWidth(option.getName());
|
||||||
Fonts.MEDIUM.drawString(optionStartX, y, option.getName(), textColor);
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
||||||
int padding = (int) (optionHeight / 10f);
|
final int padding = (int) (optionHeight / 10f);
|
||||||
nameLen += 20;
|
nameLen += 15;
|
||||||
int itemStart = optionStartX + nameLen;
|
final int comboboxStartX = optionStartX + nameLen;
|
||||||
int itemWidth = optionWidth - nameLen;
|
final int comboboxWidth = optionWidth - nameLen;
|
||||||
Color backColor = Colors.BLACK_ALPHA;
|
final int borderRadius = 6;
|
||||||
if (hoverOption == option && listHoverIndex == -1) {
|
if (comboboxWidth <= controlImageSize) {
|
||||||
backColor = Colors.ORANGE_BUTTON;
|
return;
|
||||||
|
}
|
||||||
|
Color backColor = COL_BG;
|
||||||
|
if (hoverOption == option
|
||||||
|
&& comboboxStartX <= displayContainer.mouseX && displayContainer.mouseX < comboboxStartX + comboboxWidth
|
||||||
|
&& y + padding <= displayContainer.mouseY && displayContainer.mouseY < y + padding + listItemHeight) {
|
||||||
|
backColor = COL_COMBOBOX_HOVER;
|
||||||
}
|
}
|
||||||
g.setColor(backColor);
|
g.setColor(backColor);
|
||||||
g.fillRect(itemStart, y + padding, itemWidth, listItemHeight);
|
g.fillRoundRect(comboboxStartX, y + padding, comboboxWidth, listItemHeight, borderRadius, 15);
|
||||||
g.setColor(Color.white);
|
Fonts.MEDIUM.drawString(comboboxStartX + 4, y + optionTextOffsetY, option.getValueString(), COL_WHITE);
|
||||||
g.setLineWidth(1f);
|
chevronDownImg.draw(width - paddingRight - controlImageSize / 3 - controlImageSize, y + controlImagePadding, COL_WHITE);
|
||||||
g.drawRect(itemStart, y + padding, itemWidth, listItemHeight);
|
|
||||||
Fonts.MEDIUM.drawString(itemStart + 20, y, option.getValueString(), Color.white);
|
|
||||||
if (isListOptionOpen && hoverOption == option) {
|
if (isListOptionOpen && hoverOption == option) {
|
||||||
listStartX = optionStartX + nameLen;
|
listStartX = comboboxStartX;
|
||||||
listStartY = y + padding + listItemHeight;
|
listStartY = y + optionHeight;
|
||||||
listWidth = itemWidth;
|
listWidth = comboboxWidth;
|
||||||
listHeight = listItems.length * listItemHeight;
|
listHeight = listItems.length * listItemHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderCheckOption(Graphics g, GameOption option, int y, Color textColor) {
|
private void renderCheckOption(GameOption option, int y) {
|
||||||
if (option.getBooleanValue()) {
|
if (option.getBooleanValue()) {
|
||||||
checkOnImg.draw(optionStartX, y + optionHeight / 2 - 10, Color.pink);
|
checkOnImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
||||||
} else {
|
} else {
|
||||||
checkOffImg.draw(optionStartX, y + optionHeight / 2 - 10, Color.pink);
|
checkOffImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
||||||
}
|
}
|
||||||
Fonts.MEDIUM.drawString(optionStartX + 30, y, option.getName(), textColor);
|
Fonts.MEDIUM.drawString(optionStartX + 30, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderSliderOption(Graphics g, GameOption option, int y, Color textColor) {
|
private void renderSliderOption(Graphics g, GameOption option, int y) {
|
||||||
String value = option.getValueString();
|
final int padding = 10;
|
||||||
int nameLen = Fonts.MEDIUM.getWidth(option.getName());
|
int nameLen = Fonts.MEDIUM.getWidth(option.getName());
|
||||||
int valueLen = Fonts.MEDIUM.getWidth(value);
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
||||||
Fonts.MEDIUM.drawString(optionStartX, y, option.getName(), textColor);
|
int sliderLen = optionWidth - nameLen - padding;
|
||||||
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y, value, Colors.BLUE_BACKGROUND);
|
if (sliderLen <= 1) {
|
||||||
int sliderLen = optionWidth - nameLen - valueLen - 50;
|
return;
|
||||||
|
}
|
||||||
|
int sliderStartX = optionStartX + nameLen + padding;
|
||||||
|
int sliderEndX = optionStartX + optionWidth;
|
||||||
|
|
||||||
if (hoverOption == option) {
|
if (hoverOption == option) {
|
||||||
if (!isAdjustingSlider) {
|
if (!isAdjustingSlider) {
|
||||||
sliderOptionLength = sliderLen;
|
sliderOptionLength = sliderLen;
|
||||||
sliderOptionStartX = optionStartX + nameLen + 25;
|
sliderOptionStartX = sliderStartX;
|
||||||
} else {
|
} else {
|
||||||
sliderLen = sliderOptionLength;
|
sliderLen = sliderOptionLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.setColor(Color.pink);
|
float sliderValue = (float) (option.getIntegerValue() - option.getMinValue()) / (option.getMaxValue() - option.getMinValue());
|
||||||
|
float sliderBallPos = sliderStartX + (int) ((sliderLen - controlImageSize) * sliderValue);
|
||||||
|
|
||||||
g.setLineWidth(3f);
|
g.setLineWidth(3f);
|
||||||
g.drawLine(optionStartX + nameLen + 25, y + optionHeight / 2, optionStartX + nameLen + 25 + sliderLen, y + optionHeight / 2);
|
g.setColor(COL_PINK);
|
||||||
float sliderValue = (float) (sliderLen + 10) * (option.getIntegerValue() - option.getMinValue()) / (option.getMaxValue() - option.getMinValue());
|
if (sliderValue > 0.0001f) {
|
||||||
sliderBallImg.draw(optionStartX + nameLen + 25 + sliderValue - 10, y + optionHeight / 2 - 10, Color.pink);
|
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);
|
||||||
|
g.drawLine(sliderBallPos + controlImageSize, y + optionHeight / 2, sliderEndX, y + optionHeight / 2);
|
||||||
|
COL_PINK.a = a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderGenericOption(Graphics g, GameOption option, int y, Color textColor) {
|
private void renderGenericOption(GameOption option, int y) {
|
||||||
String value = option.getValueString();
|
String value = option.getValueString();
|
||||||
int valueLen = Fonts.MEDIUM.getWidth(value);
|
int valueLen = Fonts.MEDIUM.getWidth(value);
|
||||||
Fonts.MEDIUM.drawString(optionStartX, y, option.getName(), textColor);
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
||||||
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y, value, Colors.BLUE_BACKGROUND);
|
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y + optionTextOffsetY, value, COL_BLUE);
|
||||||
}
|
|
||||||
|
|
||||||
public void renderTabs() {
|
|
||||||
for (int i = 0; i < tabs.length; i++) {
|
|
||||||
OptionTab tab = tabs[i];
|
|
||||||
boolean hovering = tab.button.contains(displayContainer.mouseX, displayContainer.mouseY);
|
|
||||||
UI.drawTab(tab.button.getX(), tab.button.getY(), tab.name, i == selectedTab, hovering);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderTitle() {
|
private void renderTitle() {
|
||||||
float marginX = width * 0.015f;
|
FontUtil.drawCentered(Fonts.LARGE, width, 0, textOptionsY - scrollOffset, "Options", COL_WHITE);
|
||||||
float marginY = height * 0.01f;
|
FontUtil.drawCentered(Fonts.MEDIUM, width, 0, textChangeY - scrollOffset, "Change the way opsu! behaves", COL_PINK);
|
||||||
Fonts.XLARGE.drawString(marginX, marginY, "Options", Color.white);
|
}
|
||||||
marginX += Fonts.XLARGE.getWidth("Options") * 1.2f;
|
|
||||||
marginY += Fonts.XLARGE.getLineHeight() * 0.9f - Fonts.DEFAULT.getLineHeight();
|
private void renderSearch(Graphics g) {
|
||||||
Fonts.DEFAULT.drawString(marginX, marginY, "Change the way opsu! behaves", Color.white);
|
int ypos = posSearchY + textSearchYOffset - scrollOffset;
|
||||||
|
if (scrollOffset > posSearchY) {
|
||||||
|
ypos = textSearchYOffset;
|
||||||
|
g.setColor(COL_BG);
|
||||||
|
g.fillRect(0, 0, width, textSearchYOffset * 2 + Fonts.LARGE.getLineHeight());
|
||||||
|
}
|
||||||
|
String searchText = "Type to search!";
|
||||||
|
if (lastSearchText.length() > 0) {
|
||||||
|
searchText = lastSearchText;
|
||||||
|
}
|
||||||
|
FontUtil.drawCentered(Fonts.LARGE, width, 0, ypos, searchText, COL_WHITE);
|
||||||
|
int imgPosX = (width - Fonts.LARGE.getWidth(searchText)) / 2 - searchImg.getWidth() - 10;
|
||||||
|
searchImg.draw(imgPosX, ypos + Fonts.LARGE.getLineHeight() * 0.25f, COL_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hide() {
|
public void hide() {
|
||||||
acceptInput = false;
|
acceptInput = false;
|
||||||
SoundController.playSound(SoundEffect.MENUBACK);
|
SoundController.playSound(SoundEffect.MENUBACK);
|
||||||
active = false;
|
hideAnimationTime = animationtime;
|
||||||
|
hideAnimationStartProgress = (float) animationtime / SHOWANIMATIONTIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void show() {
|
public void show() {
|
||||||
|
indicatorPos = -optionHeight;
|
||||||
|
indicatorOffsetToNextPos = 0;
|
||||||
|
indicatorMoveAnimationTime = 0;
|
||||||
|
indicatorHideAnimationTime = 0;
|
||||||
acceptInput = true;
|
acceptInput = true;
|
||||||
active = true;
|
active = true;
|
||||||
|
animationtime = 0;
|
||||||
|
resetSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -366,15 +533,25 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
int mouseY = displayContainer.mouseY;
|
int mouseY = displayContainer.mouseY;
|
||||||
int delta = displayContainer.renderDelta;
|
int delta = displayContainer.renderDelta;
|
||||||
|
|
||||||
|
searchField.performKeyRepeat();
|
||||||
|
|
||||||
|
updateShowHideAnimation(delta);
|
||||||
|
if (animationtime <= 0) {
|
||||||
|
active = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (sliderSoundDelay > 0) {
|
if (sliderSoundDelay > 0) {
|
||||||
sliderSoundDelay -= delta;
|
sliderSoundDelay -= delta;
|
||||||
}
|
}
|
||||||
if (mouseX - prevMouseX == 0 && mouseY - prevMouseY == 0) {
|
if (mouseX - prevMouseX == 0 && mouseY - prevMouseY == 0) {
|
||||||
|
updateIndicatorAlpha();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
prevMouseX = mouseX;
|
prevMouseX = mouseX;
|
||||||
prevMouseY = mouseY;
|
prevMouseY = mouseY;
|
||||||
updateHoverOption(mouseX, mouseY);
|
updateHoverOption(mouseX, mouseY);
|
||||||
|
updateIndicatorAlpha();
|
||||||
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||||
if (isAdjustingSlider) {
|
if (isAdjustingSlider) {
|
||||||
int sliderValue = hoverOption.getIntegerValue();
|
int sliderValue = hoverOption.getIntegerValue();
|
||||||
|
@ -392,6 +569,59 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (acceptInput) {
|
||||||
|
animationtime += delta;
|
||||||
|
if (animationtime >= SHOWANIMATIONTIME) {
|
||||||
|
animationtime = SHOWANIMATIONTIME;
|
||||||
|
}
|
||||||
|
progress = AnimationEquation.OUT_EXPO.calc((float) animationtime / SHOWANIMATIONTIME);
|
||||||
|
} else {
|
||||||
|
animationtime -= delta;
|
||||||
|
if (animationtime < 0) {
|
||||||
|
animationtime = 0;
|
||||||
|
}
|
||||||
|
progress = hideAnimationStartProgress * AnimationEquation.IN_EXPO.calc((float) animationtime / hideAnimationTime);
|
||||||
|
}
|
||||||
|
width = (int) (progress * finalWidth);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMousePressed(int button, int x, int y) {
|
public boolean onMousePressed(int button, int x, int y) {
|
||||||
if (keyEntryLeft || keyEntryRight) {
|
if (keyEntryLeft || keyEntryRight) {
|
||||||
|
@ -400,7 +630,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isListOptionOpen) {
|
if (isListOptionOpen) {
|
||||||
if (y > optionStartY && listStartX <= x && x < listStartX + listWidth && listStartY <= y && y < listStartY + listHeight) {
|
if (listStartX <= x && x < listStartX + listWidth && listStartY <= y && y < listStartY + listHeight) {
|
||||||
if (0 <= listHoverIndex && listHoverIndex < hoverOption.getListItems().length) {
|
if (0 <= listHoverIndex && listHoverIndex < hoverOption.getListItems().length) {
|
||||||
hoverOption.clickListItem(listHoverIndex);
|
hoverOption.clickListItem(listHoverIndex);
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
|
@ -410,9 +640,14 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||||
}
|
}
|
||||||
isListOptionOpen = false;
|
isListOptionOpen = false;
|
||||||
|
listAnimationTime = LISTCLOSEANIMATIONTIME;
|
||||||
listHoverIndex = -1;
|
listHoverIndex = -1;
|
||||||
updateHoverOption(x, y);
|
updateHoverOption(x, y);
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x > width) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mousePressY = y;
|
mousePressY = y;
|
||||||
|
@ -421,6 +656,8 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
if (hoverOption != null) {
|
if (hoverOption != null) {
|
||||||
if (hoverOption.getListItems() != null) {
|
if (hoverOption.getListItems() != null) {
|
||||||
isListOptionOpen = true;
|
isListOptionOpen = true;
|
||||||
|
selectedListOption = hoverOption;
|
||||||
|
listAnimationTime = 0;
|
||||||
} else if (hoverOption.getType() == OptionType.NUMERIC) {
|
} else if (hoverOption.getType() == OptionType.NUMERIC) {
|
||||||
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
|
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
|
||||||
if (isAdjustingSlider) {
|
if (isAdjustingSlider) {
|
||||||
|
@ -446,6 +683,10 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (x > finalWidth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (hoverOption != null) {
|
if (hoverOption != null) {
|
||||||
if (hoverOption.getType() == OptionType.BOOLEAN) {
|
if (hoverOption.getType() == OptionType.BOOLEAN) {
|
||||||
hoverOption.click();
|
hoverOption.click();
|
||||||
|
@ -461,6 +702,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// check if tab was clicked
|
// check if tab was clicked
|
||||||
int tScrollOffset = 0;
|
int tScrollOffset = 0;
|
||||||
for (OptionTab tab : tabs) {
|
for (OptionTab tab : tabs) {
|
||||||
|
@ -472,6 +714,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
tScrollOffset += Fonts.MEDIUM.getLineHeight() * 2;
|
tScrollOffset += Fonts.MEDIUM.getLineHeight() * 2;
|
||||||
tScrollOffset += tab.options.length * optionHeight;
|
tScrollOffset += tab.options.length * optionHeight;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if (UI.getBackButton().contains(x, y)){
|
if (UI.getBackButton().contains(x, y)){
|
||||||
hide();
|
hide();
|
||||||
|
@ -516,9 +759,15 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
if (key == Input.KEY_ESCAPE) {
|
if (key == Input.KEY_ESCAPE) {
|
||||||
if (isListOptionOpen) {
|
if (isListOptionOpen) {
|
||||||
isListOptionOpen = false;
|
isListOptionOpen = false;
|
||||||
|
listAnimationTime = LISTCLOSEANIMATIONTIME;
|
||||||
listHoverIndex = -1;
|
listHoverIndex = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (lastSearchText.length() != 0) {
|
||||||
|
resetSearch();
|
||||||
|
updateHoverOption(prevMouseX, prevMouseY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
hide();
|
hide();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onLeaveOptionsMenu();
|
listener.onLeaveOptionsMenu();
|
||||||
|
@ -526,7 +775,13 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
searchField.keyPressed(key, c);
|
||||||
|
if (!searchField.getText().equals(lastSearchText)) {
|
||||||
|
lastSearchText = searchField.getText().toLowerCase();
|
||||||
|
updateSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -550,20 +805,33 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hoverOption = null;
|
hoverOption = null;
|
||||||
if (mouseY < optionStartY || mouseX < optionStartX || mouseX > optionStartX + optionWidth) {
|
if (mouseX > width) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mouseVirtualY = scrollOffset + mouseY - optionStartY;
|
int mouseVirtualY = scrollOffset + mouseY - optionStartY;
|
||||||
for (OptionTab tab : tabs) {
|
for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
|
||||||
mouseVirtualY -= Fonts.MEDIUM.getLineHeight() * 2;
|
OptionTab section = sections[sectionIndex];
|
||||||
for (int optionIndex = 0; optionIndex < tab.options.length; optionIndex++) {
|
if (section.filtered) {
|
||||||
GameOption option = tab.options[optionIndex];
|
continue;
|
||||||
if (!option.showCondition()) {
|
}
|
||||||
|
mouseVirtualY -= Fonts.LARGE.getLineHeight() * 1.5f;
|
||||||
|
if (section.options == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
||||||
|
GameOption option = section.options[optionIndex];
|
||||||
|
if (option.isFiltered() || !option.showCondition()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mouseVirtualY <= optionHeight) {
|
if (mouseVirtualY <= optionHeight) {
|
||||||
if (mouseVirtualY >= 0) {
|
if (mouseVirtualY >= 0) {
|
||||||
|
int indicatorPos = scrollOffset + mouseY - mouseVirtualY;
|
||||||
|
if (indicatorPos != this.indicatorPos + indicatorOffsetToNextPos) {
|
||||||
|
this.indicatorPos += indicatorOffsetToNextPos; // finish the current moving animation
|
||||||
|
indicatorOffsetToNextPos = indicatorPos - this.indicatorPos;
|
||||||
|
indicatorMoveAnimationTime = 1; // starts animation
|
||||||
|
}
|
||||||
hoverOption = option;
|
hoverOption = option;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -573,11 +841,59 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetSearch() {
|
||||||
|
for (OptionTab section : sections) {
|
||||||
|
section.filtered = false;
|
||||||
|
if (section.options == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (GameOption opt : section.options) {
|
||||||
|
opt.filter(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
searchField.setText("");
|
||||||
|
lastSearchText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSearch() {
|
||||||
|
OptionTab lastBigSection = null;
|
||||||
|
boolean lastBigSectionMatches = false;
|
||||||
|
for (int sectionIndex = 0; sectionIndex < sections.length; sectionIndex++) {
|
||||||
|
OptionTab section = sections[sectionIndex];
|
||||||
|
boolean sectionMatches = section.name.toLowerCase().contains(lastSearchText);
|
||||||
|
if (section.options == null) {
|
||||||
|
lastBigSectionMatches = sectionMatches;
|
||||||
|
lastBigSection = section;
|
||||||
|
section.filtered = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean allOptionsHidden = true;
|
||||||
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
||||||
|
GameOption option = section.options[optionIndex];
|
||||||
|
if (lastBigSectionMatches || sectionMatches) {
|
||||||
|
allOptionsHidden = false;
|
||||||
|
option.filter(null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!option.filter(lastSearchText)) {
|
||||||
|
allOptionsHidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allOptionsHidden) {
|
||||||
|
section.filtered = true;
|
||||||
|
} else {
|
||||||
|
lastBigSection.filtered = false;
|
||||||
|
section.filtered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateHoverOption(prevMouseX, prevMouseY);
|
||||||
|
}
|
||||||
|
|
||||||
public static class OptionTab {
|
public static class OptionTab {
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
public final GameOption[] options;
|
public final GameOption[] options;
|
||||||
private MenuButton button;
|
private boolean filtered;
|
||||||
|
|
||||||
public OptionTab(String name, GameOption[] options) {
|
public OptionTab(String name, GameOption[] options) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
35
src/yugecin/opsudance/utils/FontUtil.java
Normal file
35
src/yugecin/opsudance/utils/FontUtil.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 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.utils;
|
||||||
|
|
||||||
|
import org.newdawn.slick.Color;
|
||||||
|
import org.newdawn.slick.Font;
|
||||||
|
|
||||||
|
public class FontUtil {
|
||||||
|
|
||||||
|
public static void drawCentered(Font font, int width, int xoffset, int y, String text, Color color) {
|
||||||
|
int x = (width - font.getWidth(text)) / 2;
|
||||||
|
font.drawString(x + xoffset, y, text, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawRightAligned(Font font, int width, int xoffset, int y, String text, Color color) {
|
||||||
|
int x = width - font.getWidth(text);
|
||||||
|
font.drawString(x + xoffset, y, text, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user