Skip to content

navigator

Anthony Samms edited this page Jun 1, 2026 · 1 revision

Navigator is a global object that owns and manages the entire browsable song/folder list on the song_select screen. It handles directory traversal, async loading, inline folder expansion, special collections, score refreshing, and all positional animation for the box strip.

A single instance is declared as extern Navigator navigator and shared across all song-select scene variants.

Supporting Types

BoxDef

Parsed from a folder's box.def file. Controls how a folder or collection box appears.

Field Type Description
name string Display name override
texture_index TextureIndex Which skin texture to use for the box background
genre_index GenreIndex Genre classification (drives the scrolling background colour)
collection string Special collection type ("RECENT", "FAVORITE", "NEW", etc.)
back_color optional<ray::Color> Custom background color override
fore_color optional<ray::Color> Custom text color override

CourseStats

Accumulated play statistics for a single difficulty level, used by diff_sort.

Field Description
total Total number of songs at this level
full_combos Songs the player has full-combo'd
clears Songs the player has cleared

Statistics

map<int, map<int, CourseStats>> — keyed by course index (difficulty type) then level (1–10).

InlineState

Tracks the state of an expanded inline folder. When a folder is entered inline, its songs replace the normal list; InlineState records enough information to restore the previous view on exit.

Field Type Description
saved_folder_box unique_ptr<FolderBox> The folder box that was opened
folder_index int Position of that folder in the item list
first_song_index int Index of the first song inserted
songs_count int Number of songs loaded into the inline view
fading_out bool Whether the inline view is currently animating out

Navigator

Public Members

Member Type Description
is_processing bool Set while a background loader thread is active; the scene suppresses input during this time
current_path fs::path The directory currently being displayed
current_search string The active search query, if any

Initialization

void init(std::vector<fs::path> songs_paths);

Stores the root song directories and calls load_current_directory() on the first path. Also launches song_files_thread, which recursively walks all root paths and builds the song_files map (title + subtitle → path) used later for collection searches.

void load_current_directory(const fs::path path);

Aborts any in-progress load, clears the item list, and launches a new loader_thread running load_current_directory_async.

// private
void load_current_directory_async(const fs::path path);

Scans the directory. For each entry it creates the appropriate box type: SongBox for .tja files, FolderBox for sub-directories (with child song count), DanBox for Dan challenge files, and special collection boxes for recognised box.def collection types. Boxes are enqueued thread-safely via enqueue_box(). Sets loading_complete when done.

Collection Loading

Special folders (identified by their box.def's collection field) are loaded by dedicated private methods:

Method Collection type Description
load_from_song_list RECENT, FAVORITE Reads a song_list.txt file and loads songs in that order
load_collection_new NEW Songs whose file modification time is within the last two weeks
load_collection_recommended RECOMMENDED A random selection of up to 10 songs from all known songs
load_collection_search SEARCH Filters all known songs against current_search by title/subtitle
load_collection_difficulty DIFFICULTY Filters all known songs to those that have a chart at the specified course and level

Inline Folder Expansion

When a folder is entered and it has no child sub-folders, its songs are loaded inline rather than navigating into a new directory level.

// private
void begin_inline_load();

Saves the current view into inline_state, replaces the item list with a loading placeholder, and launches load_songs_inline_async.

// private
void load_songs_inline_async(const fs::path path, BoxDef box_def);

Scans the folder's songs and enqueues them into pending_inline_boxes. Back-navigation boxes are inserted every 10 songs.

// private
void exit_inline();

Fades out all inline songs, restores the saved folder box, and rebuilds positions.

Navigation

void move_left();
void move_right();

Move the selection one item left or right and call set_positions() to animate all boxes to their new positions.

void skip_left();
void skip_right();

Jump 10 items in either direction.

// private
void navigate(int delta, bool snap);

Core navigation function. Advances open_index by delta, wrapping around, then calls expand_box() on the newly selected item and close_box() on the previously selected one. If snap is true, positions are set instantly; otherwise they are animated.

void enter_box();
void exit_box();

Enter or exit the currently selected folder box. enter_box() either calls begin_inline_load() (leaf folders) or load_current_directory() (folders with children). exit_box() navigates up to the parent directory.

Difficulty Sort

bool needs_diff_sort() const;

Returns true when the selected folder is a DIFFICULTY collection and the song_select screen should open the diff_sort UI.

void apply_diff_sort(int course, int level);

Stores the filter and reloads the current directory, which will invoke load_collection_difficulty for the stored parameters.

void cancel_diff_sort();

Clears the pending diff sort and restores the previous view.

void enter_diff_select();
void exit_diff_select();

Transition the open box to/from its difficulty-select visual state, driving the diff_fade_in animation.

float get_diff_fade_in();

Returns the current value of the difficulty-select fade animation, used by the scene for overlay blending.

Favorites and Recent

void toggle_favorite(SongBox* song);

Adds or removes the song's title from favorite_songs and rewrites song_list.txt in the configured favorites folder path.

void add_to_recent(const SongBox* song);

Prepends the song to the recent list (capped at 25 entries) and rewrites song_list.txt in the configured recent folder path.

Scoring

void refresh_scores();

Iterates all loaded boxes and calls get_scores() on each, reloading play data from the scores database.

Statistics get_statistics(const fs::path& path);

Computes Statistics for all songs under path. Called asynchronously from the song_select scene to populate the diff_sort overlay.

Search

optional<fs::path> find_song_by_title(const string& title, const string& subtitle);

Looks up a song by exact title and subtitle in the song_files map. Returns the file path if found.

Box Parsing

BoxDef parse_box_def(const fs::path& path);

Reads a box.def file from the given directory and returns a BoxDef with the parsed name, texture, genre, collection type, and colour overrides.

Position Management

// private
void set_positions(bool init, float duration);

Recomputes the target x-position of every box based on its index relative to open_index, then calls move_box() on each. If init is true, positions are applied instantly without animation.

Update

void update(double current_ms);

Calls flush_pending_boxes() to drain the thread-safe box queue into the live items list, then updates all boxes and the genre background animations.

// private
void flush_pending_boxes();

Drains pending_boxes (or pending_inline_boxes when in inline mode) into items, calling load_text() and fade_in() on each new box. Sets positions after each batch.

Drawing

void draw_background();

Draws the tiled, genre-coloured scrolling background. Animates a cross-fade between two genre backgrounds when the selected genre changes.

void draw(bool is_ura);

Iterates all boxes within the visible range and calls their draw() methods. Passes is_ura so song boxes can display the Ura difficulty when active.

void draw_score_history();

Calls draw_score_history() on the currently open SongBox, if any.

Queries

BaseBox* get_current_item();

Returns a pointer to the item at open_index.

bool is_directory(BaseBox* item);
bool is_song(BaseBox* item);

Type-check helpers that return true when the given box is a FolderBox/DanBox or a SongBox respectively.

Clone this wiki locally