1
0
mirror of synced 2025-02-13 00:44:28 +01:00

rewrite recursive song search

This commit is contained in:
Stepland 2023-08-06 01:03:30 +02:00
parent 907a53a5b4
commit c09b5d49c4
19 changed files with 92 additions and 124 deletions

View File

@ -21,7 +21,8 @@ dependencies = [
dependency('gl'), dependency('gl'),
cc.find_library('atomic'), cc.find_library('atomic'),
dependency('nowide'), dependency('nowide'),
dependency('nlohmann_json') dependency('nlohmann_json'),
dependency('fmt')
] ]
if host_machine.system() == 'linux' if host_machine.system() == 'linux'

View File

@ -1,4 +1,5 @@
#include "Preferences.hpp" #include "Preferences.hpp"
#include "fmt/core.h"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -82,8 +83,8 @@ namespace Data {
prefs_file >> j; prefs_file >> j;
j.get_to(*this); j.get_to(*this);
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << "Error while loading data/preferences.json : " << e.what() << '\n'; fmt::print("Error while loading data/preferences.json : {}\n", e.what());
std::cerr << "Using fallback preferences instead" << '\n'; fmt::print("Using fallback preferences instead\n");
return; return;
} }
key_mapping = Input::KeyMapping{key_mapping.m_button_to_key}; key_mapping = Input::KeyMapping{key_mapping.m_button_to_key};

View File

@ -1,17 +1,20 @@
#include "Song.hpp" #include "Song.hpp"
#include <algorithm> #include <algorithm>
#include <filesystem>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <ranges>
#include <span>
#include <stdexcept> #include <stdexcept>
#include <fmt/core.h>
#include <memon/memon.hpp> #include <memon/memon.hpp>
#include "../Toolkit/UTF8Strings.hpp"
#include "../Toolkit/UTF8SFMLRedefinitions.hpp" #include "../Toolkit/UTF8SFMLRedefinitions.hpp"
namespace fs = std::filesystem;
namespace Data { namespace Data {
bool cmp_dif_name::operator()(const std::string &a, const std::string &b) const { bool cmp_dif_name::operator()(const std::string &a, const std::string &b) const {
@ -46,58 +49,30 @@ namespace Data {
} }
} }
SongList::SongList(const std::filesystem::path& jujube_path) : SongList load_song_list(const std::filesystem::path& jujube_path) {
songs() SongList songs;
{ const std::filesystem::path song_folder = jujube_path / "songs";
std::filesystem::path song_folder = jujube_path/"songs"; if (not std::filesystem::is_directory(song_folder)) {
fmt::print(
"Tried searching for songs in {} but the folder does not exist !\n",
path_to_utf8_encoded_string(song_folder)
);
return songs;
}
if (std::filesystem::exists(song_folder) and std::filesystem::is_directory(song_folder)) { for (const auto& dir_entry : std::filesystem::recursive_directory_iterator(song_folder)) {
for (const auto& dir_item : std::filesystem::directory_iterator(song_folder)) { if (not dir_entry.is_regular_file() or dir_entry.path().extension() != ".memon") {
if (dir_item.is_directory()) { continue;
songs.splice(songs.end(), recursiveSongSearch(dir_item.path()));
}
} }
} auto song = std::make_shared<MemonSong>(dir_entry.path());
std::cout << "Loaded Data::SongList, found " << songs.size() << " songs" << '\n';
}
std::list<std::shared_ptr<Song>> recursiveSongSearch(std::filesystem::path song_or_pack) {
std::list<std::shared_ptr<Song>> res;
// First try : any .memo file in the folder ?
std::filesystem::directory_iterator folder_memo{song_or_pack};
if (
std::any_of(
std::filesystem::begin(folder_memo),
std::filesystem::end(folder_memo),
[](const std::filesystem::directory_entry& de) {return de.path().extension() == ".memo";}
)
) {
throw std::invalid_argument("jujube does not support .memo files for now ...");
}
// Second try : any .memon file in the folder ?
// if yes get the first one
std::filesystem::directory_iterator folder_memon{song_or_pack};
auto memon_path = std::find_if(
std::filesystem::begin(folder_memon),
std::filesystem::end(folder_memon),
[](const std::filesystem::directory_entry& de) {return de.path().extension() == ".memon";}
);
if (memon_path != std::filesystem::end(folder_memon)) {
auto song = std::make_shared<MemonSong>(memon_path->path());
if (not song->chart_levels.empty()) { if (not song->chart_levels.empty()) {
res.push_back(song); songs.push_back(song);
}
return res;
}
// Nothing found : recurse in subfolders
for (auto& p : std::filesystem::directory_iterator(song_or_pack)) {
if (p.is_directory()) {
res.splice(res.end(), recursiveSongSearch(p));
} }
} }
return res;
fmt::print("Loaded song list, found {} songs\n", songs.size());
return songs;
} }
TimeBounds SongDifficulty::get_time_bounds() const { TimeBounds SongDifficulty::get_time_bounds() const {

View File

@ -2,13 +2,13 @@
#include <filesystem> #include <filesystem>
#include <iterator> #include <iterator>
#include <list>
#include <map> #include <map>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <variant> #include <variant>
#include <vector>
#include <SFML/Audio.hpp> #include <SFML/Audio.hpp>
@ -80,20 +80,12 @@ namespace Data {
/* /*
struct MemoSong : public Song { struct MemoSong : public Song {
explicit MemoSong(const std::unordered_map<std::string, fs::path>& memo_paths); explicit MemoSong(const std::unordered_map<std::string, std::filesystem::path>& memo_paths);
private: private:
std::unordered_map<std::string, fs::path> memo_paths; std::unordered_map<std::string, std::filesystem::path> memo_paths;
}; };
*/ */
// Class holding all the necessary song data to run the Music Select screen using SongList = std::vector<std::shared_ptr<Song>>;
class SongList { SongList load_song_list(const std::filesystem::path& jujube_path);
public:
SongList(const std::filesystem::path& jujube_path);
std::list<std::shared_ptr<Song>> songs;
};
// Returns the folders conscidered to contain a valid song
// classic memo files should have the .memo extension
std::list<std::shared_ptr<Song>> recursiveSongSearch(std::filesystem::path song_or_pack);
} }

View File

@ -21,6 +21,7 @@
#include "Screens/Results/Results.hpp" #include "Screens/Results/Results.hpp"
#include "Toolkit/UTF8Strings.hpp" #include "Toolkit/UTF8Strings.hpp"
#include "fmt/core.h"
#if defined(__unix__) && defined(__linux__) #if defined(__unix__) && defined(__linux__)
#include <X11/Xlib.h> #include <X11/Xlib.h>
@ -35,7 +36,7 @@ int main() {
// Load prefs, music, markers // Load prefs, music, markers
const std::filesystem::path jujube_path = utf8_encoded_string_to_path(whereami::executable_dir()); const std::filesystem::path jujube_path = utf8_encoded_string_to_path(whereami::executable_dir());
Data::Preferences preferences{jujube_path}; Data::Preferences preferences{jujube_path};
Data::SongList song_list{jujube_path}; auto song_list = Data::load_song_list(jujube_path);
Resources::SharedResources shared_resources{preferences}; Resources::SharedResources shared_resources{preferences};
MusicSelect::ScreenResources music_select_resources{shared_resources}; MusicSelect::ScreenResources music_select_resources{shared_resources};
if (shared_resources.markers.find(preferences.options.marker) == shared_resources.markers.end()) { if (shared_resources.markers.find(preferences.options.marker) == shared_resources.markers.end()) {
@ -64,9 +65,9 @@ int main() {
while (window.isOpen()) { while (window.isOpen()) {
auto chart = music_select.select_chart(window); auto chart = music_select.select_chart(window);
if (chart) { if (chart) {
std::cout << "Selected Chart : " << chart->song.title << " [" << chart->difficulty << "]" << '\n'; fmt::print("Selected Chart : {} [{}]\n", chart->song.title, chart->difficulty);
} else { } else {
std::cout << "Exited MusicSelect::Screen without selecting a chart" << '\n'; fmt::print("Exited MusicSelect::Screen without selecting a chart\n");
break; break;
} }

View File

@ -5,13 +5,13 @@
#include <stdexcept> #include <stdexcept>
namespace Resources { namespace Resources {
LNMarker::LNMarker(const fs::path& t_folder) : LNMarker::LNMarker(const std::filesystem::path& t_folder) :
folder(t_folder) folder(t_folder)
{ {
if (not fs::is_directory(folder)) { if (not std::filesystem::is_directory(folder)) {
throw std::invalid_argument(folder.string()+" is not a folder"); throw std::invalid_argument(folder.string()+" is not a folder");
} }
if (not fs::exists(folder/"long.json")) { if (not std::filesystem::exists(folder/"long.json")) {
throw std::invalid_argument("LNMarker folder ( "+folder.string()+" ) has no long.json file"); throw std::invalid_argument("LNMarker folder ( "+folder.string()+" ) has no long.json file");
} }
std::ifstream marker_json{folder/"long.json"}; std::ifstream marker_json{folder/"long.json"};
@ -128,7 +128,7 @@ namespace Resources {
j.at("tip").at("cycle").get_to(m.tip_cycle); j.at("tip").at("cycle").get_to(m.tip_cycle);
} }
LNMarkers::LNMarkers(const fs::path& jujube_path) { LNMarkers::LNMarkers(const std::filesystem::path& jujube_path) {
load_from_folder(jujube_path/"markers"/"long"); load_from_folder(jujube_path/"markers"/"long");
load_from_folder(jujube_path/"assets"/"markers"/"long"); load_from_folder(jujube_path/"assets"/"markers"/"long");
if (empty()) { if (empty()) {
@ -136,9 +136,9 @@ namespace Resources {
} }
} }
void LNMarkers::load_from_folder(const fs::path& lnmarkers_folder) { void LNMarkers::load_from_folder(const std::filesystem::path& lnmarkers_folder) {
if (fs::exists(lnmarkers_folder)) { if (std::filesystem::exists(lnmarkers_folder)) {
for (auto& p : fs::directory_iterator(lnmarkers_folder)) { for (auto& p : std::filesystem::directory_iterator(lnmarkers_folder)) {
if (p.is_directory()) { if (p.is_directory()) {
try { try {
LNMarker m{p.path()}; LNMarker m{p.path()};

View File

@ -11,11 +11,9 @@
#include "SpriteSheet.hpp" #include "SpriteSheet.hpp"
#include "SplitSpriteSheet.hpp" #include "SplitSpriteSheet.hpp"
namespace fs = std::filesystem;
namespace Resources { namespace Resources {
struct LNMarker { struct LNMarker {
LNMarker(const fs::path& folder); LNMarker(const std::filesystem::path& folder);
std::optional<sf::Sprite> get_tail_sprite(sf::Time delta) const; std::optional<sf::Sprite> get_tail_sprite(sf::Time delta) const;
@ -29,7 +27,7 @@ namespace Resources {
std::optional<sf::Sprite> get_highlight_sprite(sf::Time delta) const; std::optional<sf::Sprite> get_highlight_sprite(sf::Time delta) const;
fs::path folder; std::filesystem::path folder;
std::string name; std::string name;
std::size_t fps; std::size_t fps;
std::size_t size; std::size_t size;
@ -46,8 +44,8 @@ namespace Resources {
class LNMarkers : public std::map<std::string, LNMarker> { class LNMarkers : public std::map<std::string, LNMarker> {
public: public:
LNMarkers(const fs::path& jujube_path); LNMarkers(const std::filesystem::path& jujube_path);
private: private:
void load_from_folder(const fs::path& lnmarkers_folder); void load_from_folder(const std::filesystem::path& lnmarkers_folder);
}; };
} }

View File

@ -8,8 +8,6 @@
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
namespace fs = std::filesystem;
namespace Resources { namespace Resources {
void from_json(const nlohmann::json& j, Marker& m) { void from_json(const nlohmann::json& j, Marker& m) {
@ -24,13 +22,13 @@ namespace Resources {
j.at("perfect").get_to(m.perfect); j.at("perfect").get_to(m.perfect);
} }
Marker::Marker(const fs::path& marker_folder) : Marker::Marker(const std::filesystem::path& marker_folder) :
folder(marker_folder) folder(marker_folder)
{ {
if (not fs::is_directory(folder)) { if (not std::filesystem::is_directory(folder)) {
throw std::invalid_argument(folder.string()+" is not a folder"); throw std::invalid_argument(folder.string()+" is not a folder");
} }
if (not fs::exists(folder/"marker.json")) { if (not std::filesystem::exists(folder/"marker.json")) {
throw std::invalid_argument("Marker folder ( "+folder.string()+" ) has no marker.json file"); throw std::invalid_argument("Marker folder ( "+folder.string()+" ) has no marker.json file");
} }
std::ifstream marker_json{folder/"marker.json"}; std::ifstream marker_json{folder/"marker.json"};
@ -96,7 +94,7 @@ namespace Resources {
return sprite_sheet.get_sprite(frame, size); return sprite_sheet.get_sprite(frame, size);
} }
Markers::Markers(const fs::path& jujube_path) { Markers::Markers(const std::filesystem::path& jujube_path) {
load_from_folder(jujube_path/"markers"/"tap"); load_from_folder(jujube_path/"markers"/"tap");
load_from_folder(jujube_path/"assets"/"markers"/"tap"); load_from_folder(jujube_path/"assets"/"markers"/"tap");
if (empty()) { if (empty()) {
@ -104,9 +102,9 @@ namespace Resources {
} }
} }
void Markers::load_from_folder(const fs::path& markers_folder) { void Markers::load_from_folder(const std::filesystem::path& markers_folder) {
if (fs::exists(markers_folder)) { if (std::filesystem::exists(markers_folder)) {
for (auto& p : fs::directory_iterator(markers_folder)) { for (auto& p : std::filesystem::directory_iterator(markers_folder)) {
if (p.is_directory()) { if (p.is_directory()) {
try { try {
Marker m{p.path()}; Marker m{p.path()};

View File

@ -10,8 +10,6 @@
#include "SpriteSheet.hpp" #include "SpriteSheet.hpp"
namespace fs = std::filesystem;
namespace Resources { namespace Resources {
enum class MarkerAnimation { enum class MarkerAnimation {
APPROACH, APPROACH,
@ -23,13 +21,13 @@ namespace Resources {
}; };
struct Marker { struct Marker {
explicit Marker(const fs::path& marker_folder); explicit Marker(const std::filesystem::path& marker_folder);
std::optional<sf::Sprite> get_sprite(const MarkerAnimation& state, const sf::Time seconds) const; std::optional<sf::Sprite> get_sprite(const MarkerAnimation& state, const sf::Time seconds) const;
std::optional<sf::Sprite> get_sprite(const MarkerAnimation& state, const float seconds) const; std::optional<sf::Sprite> get_sprite(const MarkerAnimation& state, const float seconds) const;
std::optional<sf::Sprite> get_sprite(const MarkerAnimation& state, const std::size_t frame) const; std::optional<sf::Sprite> get_sprite(const MarkerAnimation& state, const std::size_t frame) const;
const SpriteSheet& get_sprite_sheet_from_enum(const MarkerAnimation& state) const; const SpriteSheet& get_sprite_sheet_from_enum(const MarkerAnimation& state) const;
fs::path folder; std::filesystem::path folder;
std::string name; std::string name;
std::size_t size; // the side length in pixels std::size_t size; // the side length in pixels
std::size_t fps; // classic jubeat markers are 30 fps std::size_t fps; // classic jubeat markers are 30 fps
@ -45,8 +43,8 @@ namespace Resources {
class Markers : public std::map<std::string, Marker> { class Markers : public std::map<std::string, Marker> {
public: public:
Markers(const fs::path& jujube_path); Markers(const std::filesystem::path& jujube_path);
private: private:
void load_from_folder(const fs::path& markers_folder); void load_from_folder(const std::filesystem::path& markers_folder);
}; };
} }

View File

@ -7,14 +7,14 @@
namespace Resources { namespace Resources {
void from_json(const nlohmann::json& j, SplitSpriteSheet& s) { void from_json(const nlohmann::json& j, SplitSpriteSheet& s) {
s.tex_path = fs::path{j.at("sprite_sheet").get<std::string>()}; s.tex_path = std::filesystem::path{j.at("sprite_sheet").get<std::string>()};
j.at("count").get_to(s.count); j.at("count").get_to(s.count);
j.at("columns").get_to(s.columns); j.at("columns").get_to(s.columns);
j.at("rows").get_to(s.rows); j.at("rows").get_to(s.rows);
} }
void SplitSpriteSheet::load_and_check( void SplitSpriteSheet::load_and_check(
const fs::path& folder, const std::filesystem::path& folder,
std::size_t size, std::size_t size,
std::size_t fps, std::size_t fps,
const Toolkit::DurationInFrames& max_duration const Toolkit::DurationInFrames& max_duration

View File

@ -9,20 +9,18 @@
#include "../Toolkit/DurationInFrames.hpp" #include "../Toolkit/DurationInFrames.hpp"
namespace fs = std::filesystem;
namespace Resources { namespace Resources {
// SpriteSheet where individual sprites get their own texture // SpriteSheet where individual sprites get their own texture
// (when you cant to tile an animated sprite for ex.) // (when you cant to tile an animated sprite for ex.)
struct SplitSpriteSheet { struct SplitSpriteSheet {
std::vector<sf::Texture> textures; std::vector<sf::Texture> textures;
fs::path tex_path; std::filesystem::path tex_path;
std::size_t count; std::size_t count;
std::size_t columns; std::size_t columns;
std::size_t rows; std::size_t rows;
void load_and_check( void load_and_check(
const fs::path& folder, const std::filesystem::path& folder,
std::size_t size, std::size_t size,
std::size_t fps, std::size_t fps,
const Toolkit::DurationInFrames& max_duration const Toolkit::DurationInFrames& max_duration

View File

@ -5,14 +5,14 @@
namespace Resources { namespace Resources {
void from_json(const nlohmann::json& j, SpriteSheet& s) { void from_json(const nlohmann::json& j, SpriteSheet& s) {
s.tex_path = fs::path{j.at("sprite_sheet").get<std::string>()}; s.tex_path = std::filesystem::path{j.at("sprite_sheet").get<std::string>()};
j.at("count").get_to(s.count); j.at("count").get_to(s.count);
j.at("columns").get_to(s.columns); j.at("columns").get_to(s.columns);
j.at("rows").get_to(s.rows); j.at("rows").get_to(s.rows);
} }
void SpriteSheet::load_and_check( void SpriteSheet::load_and_check(
const fs::path& folder, const std::filesystem::path& folder,
std::size_t size, std::size_t size,
std::size_t fps, std::size_t fps,
const Toolkit::DurationInFrames& max_duration const Toolkit::DurationInFrames& max_duration

View File

@ -9,18 +9,16 @@
#include "../Toolkit/DurationInFrames.hpp" #include "../Toolkit/DurationInFrames.hpp"
namespace fs = std::filesystem;
namespace Resources { namespace Resources {
struct SpriteSheet { struct SpriteSheet {
sf::Texture tex; sf::Texture tex;
fs::path tex_path; std::filesystem::path tex_path;
std::size_t count; std::size_t count;
std::size_t columns; std::size_t columns;
std::size_t rows; std::size_t rows;
void load_and_check( void load_and_check(
const fs::path& folder, const std::filesystem::path& folder,
std::size_t size, std::size_t size,
std::size_t fps, std::size_t fps,
const Toolkit::DurationInFrames& max_duration const Toolkit::DurationInFrames& max_duration

View File

@ -7,7 +7,7 @@ namespace MusicSelect {
std::mutex openFromFile_mutex; std::mutex openFromFile_mutex;
MusicLoop::MusicLoop(fs::path music_path, std::optional<sf::Music::TimeSpan> t_loop) { MusicLoop::MusicLoop(std::filesystem::path music_path, std::optional<sf::Music::TimeSpan> t_loop) {
music = std::make_unique<sf::Music>(); music = std::make_unique<sf::Music>();
{ {
std::lock_guard<std::mutex> lock{openFromFile_mutex}; std::lock_guard<std::mutex> lock{openFromFile_mutex};
@ -33,7 +33,7 @@ namespace MusicSelect {
}; };
} }
void MusicPreview::play_async(std::optional<fs::path> music_path, std::optional<sf::Music::TimeSpan> loop) { void MusicPreview::play_async(std::optional<std::filesystem::path> music_path, std::optional<sf::Music::TimeSpan> loop) {
if (not music_path.has_value()) { if (not music_path.has_value()) {
return; return;
} }
@ -53,7 +53,7 @@ namespace MusicSelect {
} }
} }
void MusicPreview::play(std::optional<fs::path> music_path, std::optional<sf::Music::TimeSpan> loop) { void MusicPreview::play(std::optional<std::filesystem::path> music_path, std::optional<sf::Music::TimeSpan> loop) {
std::thread(&MusicPreview::play_async, this, music_path, loop).detach(); std::thread(&MusicPreview::play_async, this, music_path, loop).detach();
} }

View File

@ -9,13 +9,11 @@
#include "../../Toolkit/AffineTransform.hpp" #include "../../Toolkit/AffineTransform.hpp"
namespace fs = std::filesystem;
// In this file define stuff to try to handle creating sf::Music objects // In this file define stuff to try to handle creating sf::Music objects
// and starting their playback asynchronously while trying to keep some thread-safety // and starting their playback asynchronously while trying to keep some thread-safety
namespace MusicSelect { namespace MusicSelect {
struct MusicLoop { struct MusicLoop {
MusicLoop(fs::path music_path, std::optional<sf::Music::TimeSpan> t_loop); MusicLoop(std::filesystem::path music_path, std::optional<sf::Music::TimeSpan> t_loop);
std::unique_ptr<sf::Music> music; std::unique_ptr<sf::Music> music;
sf::Music::TimeSpan loop; sf::Music::TimeSpan loop;
Toolkit::AffineTransform<float> fade_out = {0.f, 1.f, 0.f, 1.f}; // placeholder value Toolkit::AffineTransform<float> fade_out = {0.f, 1.f, 0.f, 1.f}; // placeholder value
@ -23,11 +21,11 @@ namespace MusicSelect {
class MusicPreview { class MusicPreview {
public: public:
MusicPreview() = default; MusicPreview() = default;
void play(std::optional<fs::path> music_path, std::optional<sf::Music::TimeSpan> loop); void play(std::optional<std::filesystem::path> music_path, std::optional<sf::Music::TimeSpan> loop);
void stop(); void stop();
void update(); void update();
private: private:
void play_async(std::optional<fs::path> music_path, std::optional<sf::Music::TimeSpan> loop); void play_async(std::optional<std::filesystem::path> music_path, std::optional<sf::Music::TimeSpan> loop);
std::optional<MusicLoop> m_music_loop; std::optional<MusicLoop> m_music_loop;
std::mutex m_music_loop_mutex; std::mutex m_music_loop_mutex;
}; };

View File

@ -13,10 +13,10 @@
#include "Panels/Panel.hpp" #include "Panels/Panel.hpp"
#include "PanelLayout.hpp" #include "PanelLayout.hpp"
MusicSelect::Screen::Screen(const Data::SongList& t_song_list, ScreenResources& t_resources) : MusicSelect::Screen::Screen(const Data::SongList& song_list_, ScreenResources& t_resources) :
HoldsResources(t_resources), HoldsResources(t_resources),
song_list(t_song_list), song_list(song_list_),
ribbon(PanelLayout::title_sort(t_song_list, t_resources), t_resources), ribbon(PanelLayout::title_sort(song_list_, t_resources), t_resources),
song_info(t_resources), song_info(t_resources),
main_option_page(t_resources), main_option_page(t_resources),
options_button(t_resources), options_button(t_resources),

View File

@ -27,7 +27,7 @@ namespace MusicSelect {
// it loads a cache of available songs in the song_list attribute // it loads a cache of available songs in the song_list attribute
class Screen : public Toolkit::Debuggable, public HoldsResources { class Screen : public Toolkit::Debuggable, public HoldsResources {
public: public:
Screen(const Data::SongList& t_song_list, ScreenResources& t_resources); Screen(const Data::SongList& song_list, ScreenResources& t_resources);
std::optional<Data::SongDifficulty> select_chart(sf::RenderWindow& window); std::optional<Data::SongDifficulty> select_chart(sf::RenderWindow& window);
void draw_debug(sf::RenderWindow& window); void draw_debug(sf::RenderWindow& window);
private: private:

View File

@ -59,10 +59,7 @@ namespace MusicSelect {
} }
PanelLayout PanelLayout::title_sort(const Data::SongList& song_list, ScreenResources& t_resources) { PanelLayout PanelLayout::title_sort(const Data::SongList& song_list, ScreenResources& t_resources) {
std::vector<std::shared_ptr<const Data::Song>> songs; Data::SongList songs = song_list;
for (auto &&song : song_list.songs) {
songs.push_back(song);
}
std::sort( std::sort(
songs.begin(), songs.begin(),
songs.end(), songs.end(),

13
subprojects/fmt.wrap Normal file
View File

@ -0,0 +1,13 @@
[wrap-file]
directory = fmt-9.1.0
source_url = https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz
source_filename = fmt-9.1.0.tar.gz
source_hash = 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2
patch_filename = fmt_9.1.0-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_9.1.0-2/get_patch
patch_hash = 23e8c4829f3e63f509b5643fe6bb87cbed39eae9594c451b338475d14d051967
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_9.1.0-2/fmt-9.1.0.tar.gz
wrapdb_version = 9.1.0-2
[provide]
fmt = fmt_dep