-
Notifications
You must be signed in to change notification settings - Fork 167
update ScreenSelectMusic's SortMenu UIUX and data structure #666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: itgmania-beta
Are you sure you want to change the base?
update ScreenSelectMusic's SortMenu UIUX and data structure #666
Conversation
| @@ -0,0 +1,86 @@ | |||
| local ShowSongSearch, ShowTestInput, ShowLeaderboard, ShowDownloads, ShowPracticeMode, ShowSelectProfile, ShowSetSummary, ShowLoadNewSongs, ChangeSort, ChangeMode, ChangeStyle, AddSongToFavorites, AddFavoritesRow, AddPlaylistsRows, GetChangeableStylesRows, DownloadsExist = unpack(LoadActor("./SortMenuHelpers.lua", ...)) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a better way to do an "import" like this in StepMania-flavored Lua?
0a6b722 to
f03b896
Compare
|
Give me, like, one more day to add to language files to the best of my ability and to clean up one more piece of code. |
692e680 to
679e19b
Compare
Okay, I'm good now. :) I included an additional commit to incorporate @CrashCringle12's proposed changes from #665 that exposed the SortMenu's |
a2c3cb6 to
e0110ca
Compare
|
@SimplyViper16 @JustMoneko @TheBreak1 Can you help proofread the machine translation I used in this PR? Thank you for considering! |
e0110ca to
04d4e5f
Compare
|
Re: translation |
|
Bit late, but made a pr. You can also copy this if it's easier for you: |
This changes the UI for ScreenSelectMusic's SortMenu's choices (like
"sort by title", "sort by artist", "change style to double") visually
distinct from folders-of-choices (like "Sorts", "Options").
Folders-of-choices now:
* have a background quad
* have left-aligned text
* include a folder icon
This also changes the UX of SSM's SortMenu folder to behave similar to
the engine's MusicWheel: toggling a folder open reveals new rows below
it, and opening one new folder auto-closes the previously-open folder.
The previous UX was to fully drill-down-into a folder when opening it,
replacing all rows in the SortMenu with only the choices available in the new
folder.
---
On the code side of things, this moves code out of default.lua:
* moves InputHandlers into a discrete directory for InputHandlers
* moves all SongSearch code into the existing SongSearch directory
It also restructures SortMenu's primary `wheel_choices` data structure
to use key/value pairs: name (string), open (boolean), children (table).
The `children` table is an array with each item in the format of
{{ top_text, bottom_text, action_if_chosen()}, condition_to_be_visible }
It also moves "action" code (what happens when the user presses START on
a given choice in the SortMenu) out of SortMenu_InputHandler, and into a
dedicated file for reusable helper functions, and those helper functions
are referenced as the 3rd element in each child row (denoted above as
action_if_chosen).
The SortMenu_InputHandler was previously making some complicated
inferences to determine what kind of row it was operating on, like
knowing the current row was a folder because the top_text started with
the substring "Category", or knowing the current row was a playlist
because it had a `new_overlay` key.
It worked, but I think the new structure is cleaner and hopefully easier
to future devs to jump into -- the function to dictate what happens when
a row is chosen is bundled with that row.
1cb16ce to
d5fa5df
Compare
|
Just to confirm -- is #665 still required or would this PR cover it? |
|
Still reading through, but is there a way to create top level options (ones that aren't part of any folder?). I think that is a useful thing to support, especially if people want to have customized menus with quicker to access options. |
This should cover #665, though @CrashCringle12 should sign off on that actually being the case. :^)
I removed support for choices-not-in-any-folder, though could add it to this PR without UI changes fairly easily. But, I wouldn't be in favor of that. When thinking about the SorMenu and the issues I've had interacting with it over time (too many choices in the past, getting lost navigating it more recently), I designed this PR for:
Allowing choices-in-folders and choices-not-in-folders to coexist feels like different interaction model, one I hadn't considered, so I'd need to think about how to present that. |
|
I do agree with the sort menu having the sort of choice overload, but one thing that has been brought by a good number of people is that with the current nesting, their more oft used options now take longer to get to (switch profile, leaderboard, etc.). While I don't think any choices-not-in-folders need to be default atm, I think the functionality should exist for people who want to lift their often used options out of a folder which will reduce an additional button press for them, especially now that it can be manipulated with modules. |
As an example "P1 Recently Played" and "P2 Recently Played" being turned into 1 "My Recently Played" (or something like that) and clicking on that calls a function similar to I think that would clean up a lot of the options and make it a lot easier for folks to scroll through. |
|
Thanks for the thorough review, @CrashCringle12! The bugs you found could be fixed, but you've given me a lot to think about (e.g. choices that affect both players vs. choices that affect one player) and I'm no longer confident this PR is a good change I want to work more on. I'll reflect on it for a week or so and respond here. |
With user-supplied modules editing the contents of SSM's SortMenu, it's not safe to assume strings exist in SL language files. We can use THEME:HasString() to check if a string exists in the language file for the current lanague, localize it using THEME:GetString() if so and fall back on using the literal string supplied to SortMenuRows if not.
Since user-supplied modules and curious end-users can modify the contents of SSM's SortMenu, it's not safe to assume all choices will be valid. This adds validation to SSM's SortMenu for * ChangeSort() * ChangeStyle() * ChangeMode() helper functions. If an invalid Sort, Style, or Mode is supplied to these helpers, warn the user usig ITGm's lua.ReportScriptError() and play SL's "common invalid" sound effect.
495b749 to
263ac2a
Compare
* make the SortMenu slightly taller to accommodate: 1 item with focus in the middle 2 full items above, 2 full items below 1 half-item above, 1 half-item above * change SortMenu's masks and bottom-help-text to set y-offet using SortMenu's dimensions, rather than hardcoded magic numbers * add inline comments noting where responsive layout (i.e. if the SortMenu grows taller or shorter in the future) could be improved but are outside the scope of this current PR effort
f311c0f to
d902056
Compare
I also added validation to some SortMenu helper functions in 263ac2a, since I figured user-supplied modules may try to set invalid SortOrders or Styles.
Fixed in d9a4f14
Added Switch Profile to Common in d9a4f14. It's also in Advanced.
Should be fixed by d9a4f14
Condensed distinct "P1 Favorites" and "P2 Favorites" WheelItems into just "Favorites" in d9a4f14
I appreciate that you're thinking about this, and I think further reorganization of this SortMenu can be a separate PR effort led by someone else. Working on this SortMenu reskin over the past month has helped show me all the ways the UX model still falls short (too many similar-looking, secret-context-dependent choices crammed into too small a space), so the next time I work on this, it'll be a wholly-new overlay with different UIUX. For now, I think this is a minor improvement over the previous SortMenu. |
When the SortMenu builds its simple array of WheelItems to prsent to the
player, I'd previously relied the first index of each WheelItem as both
top_text (like "Change Sort To" and "Feeling Salty?") *and* a flag to
determine if this WheelItem represented a folder or a choice. I was
using code like
if (info[1] == "ToggleFolder") then
where top_text "ToggleFolder" was a special value. That worked so long
as we could ensure every top_text value existed in SL's language files:
it's a choice if the string exists, and
it's a folder if the string doesn't exist, because there was no
"ToggleFolder" in en.ini
Since SortMenu modules need to add their own folders and choices, they
can't rely on text that exists in SL's language files; they'll more than
likely need to provide strings for top_text and bottom_text as-is,
without any THEME:GetString() localization.
That means we cannot rely on (info[1]=="ToggleFodler") as a flag.
(Probably never should have, but hey.)
WheelItems are now shaped like:
`{ top_text, bottom_text, action_if_chosen, is_folder}`
`top_text` and `bottom_text` are strings
`action_if_chosen` is a reference to a function, and
`is_folder` is a boolean
SL modules should be able to add folders and choices to SSM's SortMenu
like
`
t["ScreenSelectMusic"] = Def.ActorFrame {
ModuleCommand=function(self)
local sortmenu = SCREENMAN:GetTopScreen():GetChild("Overlay"):GetChild("SortMenu")
table.insert(sortmenu.wheel_options,
{
name="Profile Sorts",
open=false,
children={
{ {"Show", "My Recently Played", ProfileSortRecent}, atLeastOneProfile },
{ {"Show", "My High Scores", ProfileSortTopGrades}, atLeastOneProfile },
{ {"Show", "My Most Played", ProfileSortPopularity}, atLeastOneProfile },
}
}
)
end
}
`
In this^ example, text like "Show" and "My High Scores" will be
presented as-is, no localization strings from SL's language files
necessary.
SortMenu_InputHandler calls the action_if_chosen functions for each WheelItem -- we may as well have those functions return false if they hit an error condition so that SortMenu_InputHandler can respond (i.e. play the "common invalid" sound effect).
I'd previously added separate SortMenu WheelItems for "P1 Favorites" and "P2 Favorites". CrashCringle suggested condensing those to a single "Favorites" and letting MenuButton input dictate which favorites the MusicWheel then showed.
For SSM's SortMenu, a folder's children can have conditions that are * absent (always add this row to the Sort Menu) * an expression that evaluates to boolean (evaluate it once at screen init) * a function that returns a boolean (evaluate it each time AssessAvailableChoicesCommand is called) A folder could have children whose conditions are all functions, which could all evaluate to false, which means we should evaluate those functions before adding a WheelItem for the folder, or else we could get a folder with 0 children.
1d3a3a6 to
2f461f3
Compare
UIUX Changes
This changes the UI for ScreenSelectMusic's SortMenu's choices (like "sort by title", "sort by artist", "change style to double") visually distinct from folders-of-choices (like "Sorts", "Options").
Folders-of-choices now:
The recent change that allowed the SortMenu to use a folder/nested-choice structure was a good change(!), though I sometimes found myself getting visually lost in the menu. My primary goal with this PR was to make folder-rows more visually distinct from choice-rows.
The folder icon comes from https://github.com/tailwindlabs/heroicons, which is MIT licenced.
This also changes the UX of SSM's SortMenu folder to behave similar to the engine's MusicWheel: toggling a folder open reveals new rows below it, and opening one new folder auto-closes the previously-open folder.
ScreenFlow.mp4
Code Changes
On the code side of things, there's 3 main changes:
wheel_choicesinto discrete filewheel_choicesdata structure to an array of keyed tables, each representing one folder:name(string)open(boolean)children(table).The
childrentable is an array with each item in the format ofMy motivation was to have a data structure with a more-clear distinction between a folder-row and a choice-row.
You can see this new structure here:
Simply-Love-SM5/BGAnimations/ScreenSelectMusic overlay/SortMenu/SortMenuRows.lua
Lines 4 to 84 in e0110ca
action_if_chosen).The SortMenu_InputHandler was previously making some complicated inferences to determine what kind of row it was operating on, like knowing the current row was a folder because the top_text started with the substring "Category", or knowing the current row was a playlist because it had a
new_overlaykey. It worked, but the long if-else chain could be tricky for an unfamiliar dev to work with.I think the new structure should be easier for future devs to jump into — the function to dictate what happens when a row is chosen is bundled with that row.
In all, I changed a lot of code, so feel free to ask questions! I did try to write lots of new inline comments where I thought they'd help.
It'd be good if @CrashCringle12 could test this branch and both ensure I didn't break existing functionality and give feedback.