Song menu graphical updates.
- Added "selection-*" images from Xiaounlimited's "Nexus Ivory" skin. These do the same thing as the F1-F3 keyboard buttons in the song menu. - Removed the old wrench icon and replaced it with an "Other Options" button. F1 no longer opens the options menu. - Moved the search bar to under the tabs and better simulate osu! behavior. Removed the old search icon. - Added solid black bars at the top and bottom of the song menu. Moved the top divider closer to the end of the information text. Cropped song button images to fit between the bars. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
|
@ -33,7 +33,8 @@ folder if placed in the `SongPacks` directory.
|
||||||
### First Run
|
### First Run
|
||||||
The `Music Offset` value will likely need to be adjusted when playing for the
|
The `Music Offset` value will likely need to be adjusted when playing for the
|
||||||
first time, or whenever hit objects are out of sync with the music. This and
|
first time, or whenever hit objects are out of sync with the music. This and
|
||||||
other game options can be accessed by clicking the wrench icon in the song menu.
|
other game options can be accessed by clicking the "Other Options" button in
|
||||||
|
the song menu.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
opsu! is distributed as a Maven project.
|
opsu! is distributed as a Maven project.
|
||||||
|
|
BIN
res/options.png
Before Width: | Height: | Size: 2.0 KiB |
BIN
res/search.png
Before Width: | Height: | Size: 2.5 KiB |
BIN
res/selection-mods-over.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
res/selection-mods.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
res/selection-options-over.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
res/selection-options.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
res/selection-random-over.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
res/selection-random.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
res/selection-selectoptions-over.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
res/selection-selectoptions.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
|
@ -368,6 +368,54 @@ public enum GameImage {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Non-Game Components
|
// Non-Game Components
|
||||||
|
SELECTION_MODS ("selection-mods", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_MODS_OVERLAY ("selection-mods-over", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_RANDOM ("selection-random", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_RANDOM_OVERLAY ("selection-random-over", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_OPTIONS ("selection-options", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_OPTIONS_OVERLAY ("selection-options-over", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_OTHER_OPTIONS ("selection-selectoptions", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SELECTION_OTHER_OPTIONS_OVERLAY ("selection-selectoptions-over", "png", false, false) {
|
||||||
|
@Override
|
||||||
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
return img.getScaledCopy((h * 0.115f) / img.getHeight());
|
||||||
|
}
|
||||||
|
},
|
||||||
VOLUME ("volume-bg", "png", false, false) {
|
VOLUME ("volume-bg", "png", false, false) {
|
||||||
@Override
|
@Override
|
||||||
protected Image process_sub(Image img, int w, int h) {
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
@ -383,7 +431,8 @@ public enum GameImage {
|
||||||
MENU_BUTTON_BG ("menu-button-background", "png", false, false) {
|
MENU_BUTTON_BG ("menu-button-background", "png", false, false) {
|
||||||
@Override
|
@Override
|
||||||
protected Image process_sub(Image img, int w, int h) {
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
return img.getScaledCopy(w / 2, h / SongMenu.MAX_SONG_BUTTONS);
|
// TODO: scale these properly (messy due to non-cropped images)
|
||||||
|
return img.getScaledCopy(w / 2, (int) (h * 0.95f) / SongMenu.MAX_SONG_BUTTONS);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MENU_TAB ("selection-tab", "png", false, false) {
|
MENU_TAB ("selection-tab", "png", false, false) {
|
||||||
|
@ -392,18 +441,6 @@ public enum GameImage {
|
||||||
return img.getScaledCopy((h * 0.033f) / img.getHeight());
|
return img.getScaledCopy((h * 0.033f) / img.getHeight());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MENU_SEARCH ("search", "png", false, false) {
|
|
||||||
@Override
|
|
||||||
protected Image process_sub(Image img, int w, int h) {
|
|
||||||
return img.getScaledCopy(Utils.FONT_BOLD.getLineHeight() * 2f / img.getHeight());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MENU_OPTIONS ("options", "png", false, false) {
|
|
||||||
@Override
|
|
||||||
protected Image process_sub(Image img, int w, int h) {
|
|
||||||
return img.getScaledCopy(Utils.FONT_BOLD.getLineHeight() * 2f / img.getHeight());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MENU_MUSICNOTE ("music-note", "png", false, false) {
|
MENU_MUSICNOTE ("music-note", "png", false, false) {
|
||||||
@Override
|
@Override
|
||||||
protected Image process_sub(Image img, int w, int h) {
|
protected Image process_sub(Image img, int w, int h) {
|
||||||
|
|
|
@ -54,38 +54,54 @@ public class OsuGroupNode {
|
||||||
* Draws the button.
|
* Draws the button.
|
||||||
* @param x the x coordinate
|
* @param x the x coordinate
|
||||||
* @param y the y coordinate
|
* @param y the y coordinate
|
||||||
|
* @param headerY the header end y coordinate (for cropping)
|
||||||
|
* @param footerY the footer start y coordinate (for cropping)
|
||||||
* @param grade the highest grade, if any
|
* @param grade the highest grade, if any
|
||||||
* @param focus true if this is the focused node
|
* @param focus true if this is the focused node
|
||||||
*/
|
*/
|
||||||
public void draw(float x, float y, Grade grade, boolean focus) {
|
public void draw(float x, float y, float headerY, float footerY, Grade grade, boolean focus) {
|
||||||
boolean expanded = (osuFileIndex > -1);
|
boolean expanded = (osuFileIndex > -1);
|
||||||
float xOffset = 0f;
|
|
||||||
OsuFile osu;
|
OsuFile osu;
|
||||||
Color textColor = Color.lightGray;
|
|
||||||
Image bg = GameImage.MENU_BUTTON_BG.getImage();
|
Image bg = GameImage.MENU_BUTTON_BG.getImage();
|
||||||
|
Color bgColor;
|
||||||
|
Color textColor = Color.lightGray;
|
||||||
|
|
||||||
|
// draw song button background
|
||||||
if (expanded) { // expanded
|
if (expanded) { // expanded
|
||||||
xOffset = bg.getWidth() / 10f;
|
x -= bg.getWidth() / 10f;
|
||||||
if (focus) {
|
if (focus) {
|
||||||
bg.draw(x - xOffset, y, Color.white);
|
bgColor = Color.white;
|
||||||
textColor = Color.white;
|
textColor = Color.white;
|
||||||
} else
|
} else
|
||||||
bg.draw(x - xOffset, y, Utils.COLOR_BLUE_BUTTON);
|
bgColor = Utils.COLOR_BLUE_BUTTON;
|
||||||
osu = osuFiles.get(osuFileIndex);
|
osu = osuFiles.get(osuFileIndex);
|
||||||
} else {
|
} else {
|
||||||
bg.draw(x, y, Utils.COLOR_ORANGE_BUTTON);
|
bgColor = Utils.COLOR_ORANGE_BUTTON;
|
||||||
osu = osuFiles.get(0);
|
osu = osuFiles.get(0);
|
||||||
}
|
}
|
||||||
|
// crop image if necessary
|
||||||
|
if (y < headerY) {
|
||||||
|
int cropHeight = (int) (headerY - y);
|
||||||
|
Image bgCropped = bg.getSubImage(0, cropHeight, bg.getWidth(), bg.getHeight() - cropHeight);
|
||||||
|
bgCropped.draw(x, headerY, bgColor);
|
||||||
|
} else if (y + bg.getHeight() > footerY) {
|
||||||
|
int cropHeight = (int) (footerY - y);
|
||||||
|
Image bgCropped = bg.getSubImage(0, 0, bg.getWidth(), cropHeight);
|
||||||
|
bgCropped.draw(x, y, bgColor);
|
||||||
|
} else
|
||||||
|
bg.draw(x, y, bgColor);
|
||||||
|
|
||||||
float cx = x + (bg.getWidth() * 0.05f) - xOffset;
|
float cx = x + (bg.getWidth() * 0.05f);
|
||||||
float cy = y + (bg.getHeight() * 0.2f) - 3;
|
float cy = y + (bg.getHeight() * 0.2f) - 3;
|
||||||
|
|
||||||
|
// draw grade
|
||||||
if (grade != Grade.NULL) {
|
if (grade != Grade.NULL) {
|
||||||
Image gradeImg = grade.getMenuImage();
|
Image gradeImg = grade.getMenuImage();
|
||||||
gradeImg.drawCentered(cx - bg.getWidth() * 0.01f + gradeImg.getWidth() / 2f, y + bg.getHeight() / 2.2f);
|
gradeImg.drawCentered(cx - bg.getWidth() * 0.01f + gradeImg.getWidth() / 2f, y + bg.getHeight() / 2.2f);
|
||||||
cx += gradeImg.getWidth();
|
cx += gradeImg.getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw text
|
||||||
Utils.FONT_MEDIUM.drawString(cx, cy, osu.getTitle(), textColor);
|
Utils.FONT_MEDIUM.drawString(cx, cy, osu.getTitle(), textColor);
|
||||||
Utils.FONT_DEFAULT.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() - 4,
|
Utils.FONT_DEFAULT.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() - 4,
|
||||||
String.format("%s // %s", osu.getArtist(), osu.creator), textColor);
|
String.format("%s // %s", osu.getArtist(), osu.creator), textColor);
|
||||||
|
|
|
@ -78,13 +78,13 @@ public class ScoreData implements Comparable<ScoreData> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the base coordinates for drawing.
|
* Initializes the base coordinates for drawing.
|
||||||
* @param width the container width
|
* @param containerWidth the container width
|
||||||
* @param height the container height
|
* @param topY the top y coordinate
|
||||||
*/
|
*/
|
||||||
public static void init(int width, int height) {
|
public static void init(int containerWidth, float topY) {
|
||||||
baseX = width * 0.01f;
|
baseX = containerWidth * 0.01f;
|
||||||
baseY = height * 0.16f;
|
baseY = topY;
|
||||||
buttonWidth = width * 0.4f;
|
buttonWidth = containerWidth * 0.4f;
|
||||||
float gradeHeight = GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f;
|
float gradeHeight = GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f;
|
||||||
buttonHeight = Math.max(gradeHeight, Utils.FONT_DEFAULT.getLineHeight() * 3.03f);
|
buttonHeight = Math.max(gradeHeight, Utils.FONT_DEFAULT.getLineHeight() * 3.03f);
|
||||||
buttonOffset = buttonHeight + gradeHeight / 10f;
|
buttonOffset = buttonHeight + gradeHeight / 10f;
|
||||||
|
|
|
@ -145,21 +145,21 @@ public enum SongSort {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the sort tab.
|
* Initializes the sort tab.
|
||||||
* @param width the container width
|
* @param containerWidth the container width
|
||||||
* @param height the container height
|
* @param bottomY the bottom y coordinate
|
||||||
*/
|
*/
|
||||||
public void init(int width, int height) {
|
public void init(int containerWidth, float bottomY) {
|
||||||
Image tab = GameImage.MENU_TAB.getImage();
|
Image tab = GameImage.MENU_TAB.getImage();
|
||||||
int tabWidth = tab.getWidth();
|
int tabWidth = tab.getWidth();
|
||||||
float buttonX = width / 2f;
|
float buttonX = containerWidth / 2f;
|
||||||
float tabOffset = (width - buttonX - tabWidth) / (SIZE - 1);
|
float tabOffset = (containerWidth - buttonX - tabWidth) / (SIZE - 1);
|
||||||
if (tabOffset > tabWidth) { // prevent tabs from being spaced out
|
if (tabOffset > tabWidth) { // prevent tabs from being spaced out
|
||||||
tabOffset = tabWidth;
|
tabOffset = tabWidth;
|
||||||
buttonX = (width * 0.99f) - (tabWidth * SIZE);
|
buttonX = (containerWidth * 0.99f) - (tabWidth * SIZE);
|
||||||
}
|
}
|
||||||
this.tab = new MenuButton(tab,
|
this.tab = new MenuButton(tab,
|
||||||
(buttonX + (tabWidth / 2f)) + (id * tabOffset),
|
(buttonX + (tabWidth / 2f)) + (id * tabOffset),
|
||||||
(height * 0.15f) - (tab.getHeight() / 2f) - 2f
|
bottomY - (tab.getHeight() / 2f)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,8 @@ public class Utils {
|
||||||
COLOR_GREEN = new Color(137, 201, 79),
|
COLOR_GREEN = new Color(137, 201, 79),
|
||||||
COLOR_LIGHT_ORANGE = new Color(255,192,128),
|
COLOR_LIGHT_ORANGE = new Color(255,192,128),
|
||||||
COLOR_LIGHT_GREEN = new Color(128,255,128),
|
COLOR_LIGHT_GREEN = new Color(128,255,128),
|
||||||
COLOR_LIGHT_BLUE = new Color(128,128,255);
|
COLOR_LIGHT_BLUE = new Color(128,128,255),
|
||||||
|
COLOR_GREEN_SEARCH = new Color(173, 255, 47);
|
||||||
|
|
||||||
/** The default map colors, used when a map does not provide custom colors. */
|
/** The default map colors, used when a map does not provide custom colors. */
|
||||||
public static final Color[] DEFAULT_COMBO = {
|
public static final Color[] DEFAULT_COMBO = {
|
||||||
|
@ -215,16 +216,9 @@ public class Utils {
|
||||||
for (GameMod mod : GameMod.values())
|
for (GameMod mod : GameMod.values())
|
||||||
mod.init(width, height);
|
mod.init(width, height);
|
||||||
|
|
||||||
// initialize sorts
|
|
||||||
for (SongSort sort : SongSort.values())
|
|
||||||
sort.init(width, height);
|
|
||||||
|
|
||||||
// initialize hit objects
|
// initialize hit objects
|
||||||
OsuHitObject.init(width, height);
|
OsuHitObject.init(width, height);
|
||||||
|
|
||||||
// initialize score data buttons
|
|
||||||
ScoreData.init(width, height);
|
|
||||||
|
|
||||||
// initialize download nodes
|
// initialize download nodes
|
||||||
DownloadNode.init(width, height);
|
DownloadNode.init(width, height);
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,12 @@ public class SongMenu extends BasicGameState {
|
||||||
/** Maximum x offset of song buttons for mouse hover, in pixels. */
|
/** Maximum x offset of song buttons for mouse hover, in pixels. */
|
||||||
private static final float MAX_HOVER_OFFSET = 30f;
|
private static final float MAX_HOVER_OFFSET = 30f;
|
||||||
|
|
||||||
|
/** Time, in milliseconds, for the search bar to fade in or out. */
|
||||||
|
private static final int SEARCH_TRANSITION_TIME = 250;
|
||||||
|
|
||||||
|
/** Line width of the header/footer divider. */
|
||||||
|
private static final int DIVIDER_LINE_WIDTH = 4;
|
||||||
|
|
||||||
/** Song node class representing an OsuGroupNode and file index. */
|
/** Song node class representing an OsuGroupNode and file index. */
|
||||||
private static class SongNode {
|
private static class SongNode {
|
||||||
/** Song node. */
|
/** Song node. */
|
||||||
|
@ -136,8 +142,8 @@ public class SongMenu extends BasicGameState {
|
||||||
/** Current index of hovered song button. */
|
/** Current index of hovered song button. */
|
||||||
private int hoverIndex = -1;
|
private int hoverIndex = -1;
|
||||||
|
|
||||||
/** The options button (to enter the "Game Options" menu). */
|
/** The selection buttons. */
|
||||||
private MenuButton optionsButton;
|
private MenuButton selectModsButton, selectRandomButton, selectMapOptionsButton, selectOptionsButton;
|
||||||
|
|
||||||
/** The search textfield. */
|
/** The search textfield. */
|
||||||
private TextField search;
|
private TextField search;
|
||||||
|
@ -146,10 +152,10 @@ public class SongMenu extends BasicGameState {
|
||||||
* Delay timer, in milliseconds, before running another search.
|
* Delay timer, in milliseconds, before running another search.
|
||||||
* This is overridden by character entry (reset) and 'esc' (immediate search).
|
* This is overridden by character entry (reset) and 'esc' (immediate search).
|
||||||
*/
|
*/
|
||||||
private int searchTimer;
|
private int searchTimer = 0;
|
||||||
|
|
||||||
/** Information text to display based on the search query. */
|
/** Information text to display based on the search query. */
|
||||||
private String searchResultString;
|
private String searchResultString = null;
|
||||||
|
|
||||||
/** Loader animation. */
|
/** Loader animation. */
|
||||||
private Animation loader;
|
private Animation loader;
|
||||||
|
@ -184,6 +190,12 @@ public class SongMenu extends BasicGameState {
|
||||||
/** Current start score (topmost score entry). */
|
/** Current start score (topmost score entry). */
|
||||||
private int startScore = 0;
|
private int startScore = 0;
|
||||||
|
|
||||||
|
/** Header and footer end and start y coordinates, respectively. */
|
||||||
|
private float headerY, footerY;
|
||||||
|
|
||||||
|
/** Time, in milliseconds, for fading the search bar. */
|
||||||
|
private int searchTransitionTimer = SEARCH_TRANSITION_TIME;
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private GameContainer container;
|
private GameContainer container;
|
||||||
private StateBasedGame game;
|
private StateBasedGame game;
|
||||||
|
@ -204,26 +216,35 @@ public class SongMenu extends BasicGameState {
|
||||||
int width = container.getWidth();
|
int width = container.getWidth();
|
||||||
int height = container.getHeight();
|
int height = container.getHeight();
|
||||||
|
|
||||||
|
// header/footer coordinates
|
||||||
|
headerY = height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() +
|
||||||
|
Utils.FONT_BOLD.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() +
|
||||||
|
Utils.FONT_SMALL.getLineHeight();
|
||||||
|
footerY = height - GameImage.SELECTION_MODS.getImage().getHeight();
|
||||||
|
|
||||||
|
// initialize sorts
|
||||||
|
for (SongSort sort : SongSort.values())
|
||||||
|
sort.init(width, headerY - SongMenu.DIVIDER_LINE_WIDTH / 2);
|
||||||
|
|
||||||
|
// initialize score data buttons
|
||||||
|
ScoreData.init(width, headerY + height * 0.01f);
|
||||||
|
|
||||||
// song button background & graphics context
|
// song button background & graphics context
|
||||||
Image menuBackground = GameImage.MENU_BUTTON_BG.getImage();
|
Image menuBackground = GameImage.MENU_BUTTON_BG.getImage();
|
||||||
|
|
||||||
// song button coordinates
|
// song button coordinates
|
||||||
buttonX = width * 0.6f;
|
buttonX = width * 0.6f;
|
||||||
buttonY = height * 0.16f;
|
buttonY = headerY;
|
||||||
buttonWidth = menuBackground.getWidth();
|
buttonWidth = menuBackground.getWidth();
|
||||||
buttonHeight = menuBackground.getHeight();
|
buttonHeight = menuBackground.getHeight();
|
||||||
buttonOffset = (height * 0.8f) / MAX_SONG_BUTTONS;
|
buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS;
|
||||||
|
|
||||||
// search
|
// search
|
||||||
searchTimer = 0;
|
int textFieldX = (int) (width * 0.7125f + Utils.FONT_BOLD.getWidth("Search: "));
|
||||||
searchResultString = "Type to search!";
|
int textFieldY = (int) (headerY + Utils.FONT_BOLD.getLineHeight() / 2);
|
||||||
Image searchIcon = GameImage.MENU_SEARCH.getImage();
|
|
||||||
Image tab = GameImage.MENU_TAB.getImage();
|
|
||||||
search = new TextField(
|
search = new TextField(
|
||||||
container, Utils.FONT_DEFAULT,
|
container, Utils.FONT_BOLD, textFieldX, textFieldY,
|
||||||
(int) buttonX + (tab.getWidth() / 2) + searchIcon.getWidth(),
|
(int) (width * 0.99f) - textFieldX, Utils.FONT_BOLD.getLineHeight()
|
||||||
(int) ((height * 0.15f) - (tab.getHeight() * 2.5f)),
|
|
||||||
(int) (buttonWidth / 2), Utils.FONT_DEFAULT.getLineHeight()
|
|
||||||
);
|
);
|
||||||
search.setBackgroundColor(Color.transparent);
|
search.setBackgroundColor(Color.transparent);
|
||||||
search.setBorderColor(Color.transparent);
|
search.setBorderColor(Color.transparent);
|
||||||
|
@ -231,10 +252,22 @@ public class SongMenu extends BasicGameState {
|
||||||
search.setConsumeEvents(false);
|
search.setConsumeEvents(false);
|
||||||
search.setMaxLength(60);
|
search.setMaxLength(60);
|
||||||
|
|
||||||
// options button
|
// selection buttons
|
||||||
Image optionsIcon = GameImage.MENU_OPTIONS.getImage();
|
float selectX = GameImage.MENU_BACK.getImage().getWidth() * 1.75f;
|
||||||
optionsButton = new MenuButton(optionsIcon, search.getX() - (optionsIcon.getWidth() * 1.5f), search.getY());
|
float selectY = height - GameImage.SELECTION_MODS.getImage().getHeight() / 2f;
|
||||||
optionsButton.setHoverExpand(1.75f);
|
float selectOffset = GameImage.SELECTION_MODS.getImage().getWidth() * 1.05f;
|
||||||
|
selectModsButton = new MenuButton(GameImage.SELECTION_MODS_OVERLAY.getImage(),
|
||||||
|
selectX, selectY);
|
||||||
|
selectRandomButton = new MenuButton(GameImage.SELECTION_RANDOM_OVERLAY.getImage(),
|
||||||
|
selectX + selectOffset, selectY);
|
||||||
|
selectMapOptionsButton = new MenuButton(GameImage.SELECTION_OPTIONS_OVERLAY.getImage(),
|
||||||
|
selectX + selectOffset * 2f, selectY);
|
||||||
|
selectOptionsButton = new MenuButton(GameImage.SELECTION_OTHER_OPTIONS_OVERLAY.getImage(),
|
||||||
|
selectX + selectOffset * 3f, selectY);
|
||||||
|
selectModsButton.setHoverFade(0f);
|
||||||
|
selectRandomButton.setHoverFade(0f);
|
||||||
|
selectMapOptionsButton.setHoverFade(0f);
|
||||||
|
selectOptionsButton.setHoverFade(0f);
|
||||||
|
|
||||||
// loader
|
// loader
|
||||||
int loaderDim = GameImage.MENU_MUSICNOTE.getImage().getWidth();
|
int loaderDim = GameImage.MENU_MUSICNOTE.getImage().getWidth();
|
||||||
|
@ -258,19 +291,19 @@ public class SongMenu extends BasicGameState {
|
||||||
GameImage.PLAYFIELD.getImage().draw();
|
GameImage.PLAYFIELD.getImage().draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
// header setup
|
// top/bottom bars
|
||||||
float lowerBound = height * 0.15f;
|
g.setColor(Color.black);
|
||||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
g.fillRect(0, 0, width, headerY);
|
||||||
g.fillRect(0, 0, width, lowerBound);
|
g.fillRect(0, footerY, width, height - footerY);
|
||||||
g.setColor(Utils.COLOR_BLUE_DIVIDER);
|
g.setColor(Utils.COLOR_BLUE_DIVIDER);
|
||||||
g.setLineWidth(2f);
|
g.setLineWidth(DIVIDER_LINE_WIDTH);
|
||||||
g.drawLine(0, lowerBound, width, lowerBound);
|
g.drawLine(0, headerY, width, headerY);
|
||||||
|
g.drawLine(0, footerY - DIVIDER_LINE_WIDTH / 2, width, footerY - DIVIDER_LINE_WIDTH / 2);
|
||||||
g.resetLineWidth();
|
g.resetLineWidth();
|
||||||
|
|
||||||
// header
|
// header
|
||||||
if (focusNode != null) {
|
if (focusNode != null) {
|
||||||
float marginX = width * 0.005f, marginY = height * 0.005f;
|
float marginX = width * 0.005f, marginY = height * 0.005f;
|
||||||
|
|
||||||
Image musicNote = GameImage.MENU_MUSICNOTE.getImage();
|
Image musicNote = GameImage.MENU_MUSICNOTE.getImage();
|
||||||
if (MusicController.isTrackLoading())
|
if (MusicController.isTrackLoading())
|
||||||
loader.draw(marginX, marginY);
|
loader.draw(marginX, marginY);
|
||||||
|
@ -282,14 +315,14 @@ public class SongMenu extends BasicGameState {
|
||||||
if (songInfo == null)
|
if (songInfo == null)
|
||||||
songInfo = focusNode.getInfo();
|
songInfo = focusNode.getInfo();
|
||||||
marginX += 5;
|
marginX += 5;
|
||||||
Utils.FONT_LARGE.drawString(marginX + iconWidth, marginY, songInfo[0], Color.white);
|
Utils.FONT_LARGE.drawString(marginX + iconWidth * 1.05f, marginY, songInfo[0], Color.white);
|
||||||
Utils.FONT_DEFAULT.drawString(marginX + iconWidth, marginY + Utils.FONT_LARGE.getLineHeight() * 0.75f, songInfo[1], Color.white);
|
Utils.FONT_DEFAULT.drawString(marginX + iconWidth * 1.05f, marginY + Utils.FONT_LARGE.getLineHeight() * 0.75f, songInfo[1], Color.white);
|
||||||
float headerY = marginY + iconHeight;
|
float headerTextY = marginY + iconHeight;
|
||||||
Utils.FONT_BOLD.drawString(marginX, headerY, songInfo[2], Color.white);
|
Utils.FONT_BOLD.drawString(marginX, headerTextY, songInfo[2], Color.white);
|
||||||
headerY += Utils.FONT_BOLD.getLineHeight() - 6;
|
headerTextY += Utils.FONT_BOLD.getLineHeight() - 6;
|
||||||
Utils.FONT_DEFAULT.drawString(marginX, headerY, songInfo[3], Color.white);
|
Utils.FONT_DEFAULT.drawString(marginX, headerTextY, songInfo[3], Color.white);
|
||||||
headerY += Utils.FONT_DEFAULT.getLineHeight() - 4;
|
headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 4;
|
||||||
Utils.FONT_SMALL.drawString(marginX, headerY, songInfo[4], Color.white);
|
Utils.FONT_SMALL.drawString(marginX, headerTextY, songInfo[4], Color.white);
|
||||||
}
|
}
|
||||||
|
|
||||||
// song buttons
|
// song buttons
|
||||||
|
@ -300,6 +333,7 @@ public class SongMenu extends BasicGameState {
|
||||||
ScoreData[] scores = getScoreDataForNode(node, false);
|
ScoreData[] scores = getScoreDataForNode(node, false);
|
||||||
node.draw(
|
node.draw(
|
||||||
buttonX - offset, buttonY + (i*buttonOffset),
|
buttonX - offset, buttonY + (i*buttonOffset),
|
||||||
|
headerY + DIVIDER_LINE_WIDTH / 2, footerY - DIVIDER_LINE_WIDTH,
|
||||||
(scores == null) ? Grade.NULL : scores[0].getGrade(),
|
(scores == null) ? Grade.NULL : scores[0].getGrade(),
|
||||||
(node == focusNode)
|
(node == focusNode)
|
||||||
);
|
);
|
||||||
|
@ -324,8 +358,16 @@ public class SongMenu extends BasicGameState {
|
||||||
ScoreData.drawScrollbar(g, startScore, focusScores.length);
|
ScoreData.drawScrollbar(g, startScore, focusScores.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// options button
|
// selection buttons
|
||||||
optionsButton.draw();
|
// TODO
|
||||||
|
// GameImage.SELECTION_MODS.getImage().drawCentered(selectModsButton.getX(), selectModsButton.getY());
|
||||||
|
// selectModsButton.draw();
|
||||||
|
GameImage.SELECTION_RANDOM.getImage().drawCentered(selectRandomButton.getX(), selectRandomButton.getY());
|
||||||
|
selectRandomButton.draw();
|
||||||
|
GameImage.SELECTION_OPTIONS.getImage().drawCentered(selectMapOptionsButton.getX(), selectMapOptionsButton.getY());
|
||||||
|
selectMapOptionsButton.draw();
|
||||||
|
GameImage.SELECTION_OTHER_OPTIONS.getImage().drawCentered(selectOptionsButton.getX(), selectOptionsButton.getY());
|
||||||
|
selectOptionsButton.draw();
|
||||||
|
|
||||||
// sorting tabs
|
// sorting tabs
|
||||||
SongSort currentSort = SongSort.getSort();
|
SongSort currentSort = SongSort.getSort();
|
||||||
|
@ -343,15 +385,37 @@ public class SongMenu extends BasicGameState {
|
||||||
currentSort.draw(true, false);
|
currentSort.draw(true, false);
|
||||||
|
|
||||||
// search
|
// search
|
||||||
Image searchIcon = GameImage.MENU_SEARCH.getImage();
|
boolean searchEmpty = search.getText().isEmpty();
|
||||||
Utils.FONT_BOLD.drawString(
|
int searchX = search.getX(), searchY = search.getY();
|
||||||
search.getX(), search.getY() - Utils.FONT_BOLD.getLineHeight(),
|
float searchBaseX = width * 0.7f;
|
||||||
searchResultString, Color.white
|
float searchTextX = width * 0.7125f;
|
||||||
);
|
float searchRectHeight = Utils.FONT_BOLD.getLineHeight() * 2;
|
||||||
searchIcon.draw(search.getX() - searchIcon.getWidth(),
|
float searchExtraHeight = Utils.FONT_DEFAULT.getLineHeight() * 0.7f;
|
||||||
search.getY() - Utils.FONT_DEFAULT.getLineHeight());
|
float searchProgress = (searchTransitionTimer < SEARCH_TRANSITION_TIME) ?
|
||||||
|
((float) searchTransitionTimer / SEARCH_TRANSITION_TIME) : 1f;
|
||||||
|
float oldAlpha = Utils.COLOR_BLACK_ALPHA.a;
|
||||||
|
if (searchEmpty) {
|
||||||
|
searchRectHeight += (1f - searchProgress) * searchExtraHeight;
|
||||||
|
Utils.COLOR_BLACK_ALPHA.a = 0.5f - searchProgress * 0.3f;
|
||||||
|
} else {
|
||||||
|
searchRectHeight += searchProgress * searchExtraHeight;
|
||||||
|
Utils.COLOR_BLACK_ALPHA.a = 0.2f + searchProgress * 0.3f;
|
||||||
|
}
|
||||||
|
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||||
|
g.fillRect(searchBaseX, headerY + DIVIDER_LINE_WIDTH / 2, width - searchBaseX, searchRectHeight);
|
||||||
|
Utils.COLOR_BLACK_ALPHA.a = oldAlpha;
|
||||||
|
Utils.FONT_BOLD.drawString(searchTextX, searchY, "Search:", Utils.COLOR_GREEN_SEARCH);
|
||||||
|
if (searchEmpty)
|
||||||
|
Utils.FONT_BOLD.drawString(searchX, searchY, "Type to search!", Color.white);
|
||||||
|
else {
|
||||||
g.setColor(Color.white);
|
g.setColor(Color.white);
|
||||||
|
// TODO: why is this needed to correctly position the TextField?
|
||||||
|
search.setLocation(searchX - 3, searchY - 1);
|
||||||
search.render(container, g);
|
search.render(container, g);
|
||||||
|
search.setLocation(searchX, searchY);
|
||||||
|
Utils.FONT_DEFAULT.drawString(searchTextX, searchY + Utils.FONT_BOLD.getLineHeight(),
|
||||||
|
(searchResultString == null) ? "Searching..." : searchResultString, Color.white);
|
||||||
|
}
|
||||||
|
|
||||||
// scroll bar
|
// scroll bar
|
||||||
if (focusNode != null) {
|
if (focusNode != null) {
|
||||||
|
@ -364,7 +428,7 @@ public class SongMenu extends BasicGameState {
|
||||||
else if (startNode.index == focusNode.index)
|
else if (startNode.index == focusNode.index)
|
||||||
startIndex += startNode.osuFileIndex;
|
startIndex += startNode.osuFileIndex;
|
||||||
Utils.drawScrollbar(g, startIndex, totalNodes, MAX_SONG_BUTTONS,
|
Utils.drawScrollbar(g, startIndex, totalNodes, MAX_SONG_BUTTONS,
|
||||||
width, height * 0.16f, 0, buttonHeight, buttonOffset,
|
width, headerY + DIVIDER_LINE_WIDTH / 2, 0, buttonOffset - DIVIDER_LINE_WIDTH * 1.5f, buttonOffset,
|
||||||
Utils.COLOR_BLACK_ALPHA, Color.white, true);
|
Utils.COLOR_BLACK_ALPHA, Color.white, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +458,10 @@ public class SongMenu extends BasicGameState {
|
||||||
Utils.updateVolumeDisplay(delta);
|
Utils.updateVolumeDisplay(delta);
|
||||||
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||||
Utils.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
Utils.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||||
optionsButton.hoverUpdate(delta, mouseX, mouseY);
|
selectModsButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
|
selectRandomButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
|
selectMapOptionsButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
|
selectOptionsButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
|
|
||||||
// beatmap menu timer
|
// beatmap menu timer
|
||||||
if (beatmapMenuTimer > -1) {
|
if (beatmapMenuTimer > -1) {
|
||||||
|
@ -425,7 +492,7 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
// empty search
|
// empty search
|
||||||
if (search.getText().isEmpty())
|
if (search.getText().isEmpty())
|
||||||
searchResultString = "Type to search!";
|
searchResultString = null;
|
||||||
|
|
||||||
// search produced new list: re-initialize it
|
// search produced new list: re-initialize it
|
||||||
startNode = focusNode = null;
|
startNode = focusNode = null;
|
||||||
|
@ -450,23 +517,28 @@ public class SongMenu extends BasicGameState {
|
||||||
searchResultString = "No matches found. Hit 'esc' to reset.";
|
searchResultString = "No matches found. Hit 'esc' to reset.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (searchTransitionTimer < SEARCH_TRANSITION_TIME) {
|
||||||
|
searchTransitionTimer += delta;
|
||||||
|
if (searchTransitionTimer > SEARCH_TRANSITION_TIME)
|
||||||
|
searchTransitionTimer = SEARCH_TRANSITION_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
// slide buttons
|
// slide buttons
|
||||||
int height = container.getHeight();
|
int height = container.getHeight();
|
||||||
float targetY = height * 0.16f;
|
if (buttonY > headerY) {
|
||||||
if (buttonY > targetY) {
|
|
||||||
buttonY -= height * delta / 20000f;
|
buttonY -= height * delta / 20000f;
|
||||||
if (buttonY < targetY)
|
if (buttonY < headerY)
|
||||||
buttonY = targetY;
|
buttonY = headerY;
|
||||||
} else if (buttonY < targetY) {
|
} else if (buttonY < headerY) {
|
||||||
buttonY += height * delta / 20000f;
|
buttonY += height * delta / 20000f;
|
||||||
if (buttonY > targetY)
|
if (buttonY > headerY)
|
||||||
buttonY = targetY;
|
buttonY = headerY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mouse hover
|
// mouse hover
|
||||||
OsuGroupNode node = startNode;
|
|
||||||
boolean isHover = false;
|
boolean isHover = false;
|
||||||
|
if (mouseY > headerY && mouseY < footerY) {
|
||||||
|
OsuGroupNode node = startNode;
|
||||||
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
||||||
float cx = (node.index == OsuGroupList.get().getExpandedIndex()) ? buttonX * 0.9f : buttonX;
|
float cx = (node.index == OsuGroupList.get().getExpandedIndex()) ? buttonX * 0.9f : buttonX;
|
||||||
if ((mouseX > cx && mouseX < cx + buttonWidth) &&
|
if ((mouseX > cx && mouseX < cx + buttonWidth) &&
|
||||||
|
@ -485,6 +557,7 @@ public class SongMenu extends BasicGameState {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!isHover) {
|
if (!isHover) {
|
||||||
hoverOffset = 0f;
|
hoverOffset = 0f;
|
||||||
hoverIndex = -1;
|
hoverIndex = -1;
|
||||||
|
@ -512,8 +585,17 @@ public class SongMenu extends BasicGameState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// options
|
// selection buttons
|
||||||
if (optionsButton.contains(x, y)) {
|
if (selectModsButton.contains(x, y)) {
|
||||||
|
this.keyPressed(Input.KEY_F1, '\0');
|
||||||
|
return;
|
||||||
|
} else if (selectRandomButton.contains(x, y)) {
|
||||||
|
this.keyPressed(Input.KEY_F2, '\0');
|
||||||
|
return;
|
||||||
|
} else if (selectMapOptionsButton.contains(x, y)) {
|
||||||
|
this.keyPressed(Input.KEY_F3, '\0');
|
||||||
|
return;
|
||||||
|
} else if (selectOptionsButton.contains(x, y)) {
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||||
return;
|
return;
|
||||||
|
@ -539,6 +621,7 @@ public class SongMenu extends BasicGameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// song buttons
|
// song buttons
|
||||||
|
if (y > headerY && y < footerY) {
|
||||||
int expandedIndex = OsuGroupList.get().getExpandedIndex();
|
int expandedIndex = OsuGroupList.get().getExpandedIndex();
|
||||||
OsuGroupNode node = startNode;
|
OsuGroupNode node = startNode;
|
||||||
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
||||||
|
@ -581,6 +664,7 @@ public class SongMenu extends BasicGameState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// score buttons
|
// score buttons
|
||||||
if (focusScores != null && ScoreData.areaContains(x, y)) {
|
if (focusScores != null && ScoreData.areaContains(x, y)) {
|
||||||
|
@ -621,6 +705,7 @@ public class SongMenu extends BasicGameState {
|
||||||
// clear search text
|
// clear search text
|
||||||
search.setText("");
|
search.setText("");
|
||||||
searchTimer = SEARCH_DELAY;
|
searchTimer = SEARCH_DELAY;
|
||||||
|
searchTransitionTimer = 0;
|
||||||
} else {
|
} else {
|
||||||
// return to main menu
|
// return to main menu
|
||||||
SoundController.playSound(SoundEffect.MENUBACK);
|
SoundController.playSound(SoundEffect.MENUBACK);
|
||||||
|
@ -629,12 +714,14 @@ public class SongMenu extends BasicGameState {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Input.KEY_F1:
|
case Input.KEY_F1:
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
// TODO: mods menu
|
||||||
game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
// SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
|
// game.enterState();
|
||||||
break;
|
break;
|
||||||
case Input.KEY_F2:
|
case Input.KEY_F2:
|
||||||
if (focusNode == null)
|
if (focusNode == null)
|
||||||
break;
|
break;
|
||||||
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
|
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
|
||||||
// shift key: previous random track
|
// shift key: previous random track
|
||||||
SongNode prev;
|
SongNode prev;
|
||||||
|
@ -718,8 +805,16 @@ public class SongMenu extends BasicGameState {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// wait for user to finish typing
|
// wait for user to finish typing
|
||||||
if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK)
|
// TODO: accept all characters (current conditions are from TextField class)
|
||||||
|
if ((c > 31 && c < 127) || key == Input.KEY_BACK) {
|
||||||
searchTimer = 0;
|
searchTimer = 0;
|
||||||
|
int textLength = search.getText().length();
|
||||||
|
if (key == Input.KEY_BACK) {
|
||||||
|
if (textLength == 0)
|
||||||
|
searchTransitionTimer = 0;
|
||||||
|
} else if (textLength == 1)
|
||||||
|
searchTransitionTimer = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,11 +877,15 @@ public class SongMenu extends BasicGameState {
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
Display.setTitle(game.getTitle());
|
Display.setTitle(game.getTitle());
|
||||||
Utils.getBackButton().resetHover();
|
Utils.getBackButton().resetHover();
|
||||||
optionsButton.resetHover();
|
selectModsButton.resetHover();
|
||||||
|
selectRandomButton.resetHover();
|
||||||
|
selectMapOptionsButton.resetHover();
|
||||||
|
selectOptionsButton.resetHover();
|
||||||
hoverOffset = 0f;
|
hoverOffset = 0f;
|
||||||
hoverIndex = -1;
|
hoverIndex = -1;
|
||||||
startScore = 0;
|
startScore = 0;
|
||||||
beatmapMenuTimer = -1;
|
beatmapMenuTimer = -1;
|
||||||
|
searchTransitionTimer = SEARCH_TRANSITION_TIME;
|
||||||
|
|
||||||
// reset song stack
|
// reset song stack
|
||||||
randomStack = new Stack<SongNode>();
|
randomStack = new Stack<SongNode>();
|
||||||
|
@ -920,7 +1019,8 @@ public class SongMenu extends BasicGameState {
|
||||||
hoverIndex = -1;
|
hoverIndex = -1;
|
||||||
search.setText("");
|
search.setText("");
|
||||||
searchTimer = SEARCH_DELAY;
|
searchTimer = SEARCH_DELAY;
|
||||||
searchResultString = "Type to search!";
|
searchTransitionTimer = SEARCH_TRANSITION_TIME;
|
||||||
|
searchResultString = null;
|
||||||
|
|
||||||
// reload songs in new thread
|
// reload songs in new thread
|
||||||
reloadThread = new Thread() {
|
reloadThread = new Thread() {
|
||||||
|
@ -977,16 +1077,16 @@ public class SongMenu extends BasicGameState {
|
||||||
if (n < 0 && startNode.prev != null) {
|
if (n < 0 && startNode.prev != null) {
|
||||||
startNode = startNode.prev;
|
startNode = startNode.prev;
|
||||||
buttonY += buttonOffset / 4;
|
buttonY += buttonOffset / 4;
|
||||||
if (buttonY > height * 0.18f)
|
if (buttonY > headerY + height * 0.02f)
|
||||||
buttonY = height * 0.18f;
|
buttonY = headerY + height * 0.02f;
|
||||||
n++;
|
n++;
|
||||||
shifted = true;
|
shifted = true;
|
||||||
} else if (n > 0 && startNode.next != null &&
|
} else if (n > 0 && startNode.next != null &&
|
||||||
OsuGroupList.get().getNode(startNode, MAX_SONG_BUTTONS) != null) {
|
OsuGroupList.get().getNode(startNode, MAX_SONG_BUTTONS) != null) {
|
||||||
startNode = startNode.next;
|
startNode = startNode.next;
|
||||||
buttonY -= buttonOffset / 4;
|
buttonY -= buttonOffset / 4;
|
||||||
if (buttonY < height * 0.14f)
|
if (buttonY < headerY - height * 0.02f)
|
||||||
buttonY = height * 0.14f;
|
buttonY = headerY - height * 0.02f;
|
||||||
n--;
|
n--;
|
||||||
shifted = true;
|
shifted = true;
|
||||||
} else
|
} else
|
||||||
|
|