Fix empty song folder crashing music select screen
This commit is contained in:
parent
7f53534a1f
commit
f9922c341a
1
TODO.md
1
TODO.md
@ -11,6 +11,7 @@
|
|||||||
- Handling Resolution changes
|
- Handling Resolution changes
|
||||||
- Make Panels Drawable and Transformable
|
- Make Panels Drawable and Transformable
|
||||||
- Make Ribbon Transformable
|
- Make Ribbon Transformable
|
||||||
|
- Fix jujube crashing on empty layout
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Preference persistency system
|
- Preference persistency system
|
||||||
|
@ -105,4 +105,29 @@ namespace MusicSelect {
|
|||||||
rect.setSize({bounds.width, bounds.height});
|
rect.setSize({bounds.width, bounds.height});
|
||||||
rect.setPosition({bounds.left, bounds.top});
|
rect.setPosition({bounds.left, bounds.top});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ColoredMessagePanel::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
||||||
|
states.transform *= getTransform();
|
||||||
|
sf::RectangleShape frame{{m_size*0.9f, m_size*0.9f}};
|
||||||
|
frame.setFillColor(sf::Color::Black);
|
||||||
|
frame.setOutlineThickness(1.f);
|
||||||
|
frame.setOutlineColor(m_color);
|
||||||
|
frame.setOrigin(frame.getSize().x / 2.f, frame.getSize().y / 2.f);
|
||||||
|
frame.setPosition(m_size/2.f, m_size/2.f);
|
||||||
|
target.draw(frame, states);
|
||||||
|
|
||||||
|
sf::Text message;
|
||||||
|
message.setFont(m_resources.noto_sans_medium);
|
||||||
|
message.setString(m_message);
|
||||||
|
message.setCharacterSize(static_cast<unsigned int>(0.1f*m_size));
|
||||||
|
message.setFillColor(m_color);
|
||||||
|
auto bounds = message.getLocalBounds();
|
||||||
|
message.setOrigin(bounds.left+bounds.width*0.5f, bounds.top+bounds.height*0.5f);
|
||||||
|
auto biggest_side = std::max(bounds.width, bounds.height);
|
||||||
|
if (biggest_side > m_size*0.8f) {
|
||||||
|
message.setScale(m_size*0.8f / biggest_side, m_size*0.8f / biggest_side);
|
||||||
|
}
|
||||||
|
message.setPosition(m_size*0.5f, m_size*0.5f);
|
||||||
|
target.draw(message, states);
|
||||||
|
}
|
||||||
}
|
}
|
@ -32,6 +32,16 @@ namespace MusicSelect {
|
|||||||
void draw(sf::RenderTarget& target, sf::RenderStates states) const override {return;};
|
void draw(sf::RenderTarget& target, sf::RenderStates states) const override {return;};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ColoredMessagePanel final : public Panel {
|
||||||
|
public:
|
||||||
|
ColoredMessagePanel(const float& size, Resources& resources, const sf::Color& color, const std::string& message) : Panel(size, resources), m_color(color), m_message(message) {};
|
||||||
|
void click(Ribbon& ribbon, std::size_t from_button_index) override {return;};
|
||||||
|
private:
|
||||||
|
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||||
|
const sf::Color m_color;
|
||||||
|
const std::string m_message;
|
||||||
|
};
|
||||||
|
|
||||||
class ColorPanel final : public Panel {
|
class ColorPanel final : public Panel {
|
||||||
public:
|
public:
|
||||||
ColorPanel(const float& size, Resources& resources, const sf::Color& t_color) : Panel(size, resources), m_color(t_color) {};
|
ColorPanel(const float& size, Resources& resources, const sf::Color& t_color) : Panel(size, resources), m_color(t_color) {};
|
||||||
|
@ -13,16 +13,18 @@
|
|||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/SongList.hpp"
|
||||||
#include "../../Toolkit/QuickRNG.hpp"
|
#include "../../Toolkit/QuickRNG.hpp"
|
||||||
|
|
||||||
MusicSelect::MoveAnimation::MoveAnimation(int previous_pos, int next_pos, size_t ribbon_size, Direction direction, float &t_time_factor) :
|
|
||||||
|
namespace MusicSelect {
|
||||||
|
MoveAnimation::MoveAnimation(int previous_pos, int next_pos, size_t ribbon_size, Direction direction, float &t_time_factor) :
|
||||||
normalized_to_pos(create_transform(previous_pos, next_pos, ribbon_size, direction)),
|
normalized_to_pos(create_transform(previous_pos, next_pos, ribbon_size, direction)),
|
||||||
seconds_to_normalized(0.f, 0.3f, 0.f, 1.f),
|
seconds_to_normalized(0.f, 0.3f, 0.f, 1.f),
|
||||||
m_time_factor(t_time_factor),
|
m_time_factor(t_time_factor),
|
||||||
clock(),
|
clock(),
|
||||||
ease_expo(-7.f)
|
ease_expo(-7.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Toolkit::AffineTransform<float> MusicSelect::MoveAnimation::create_transform(int previous_pos, int next_pos, size_t ribbon_size, Direction direction) {
|
Toolkit::AffineTransform<float> MoveAnimation::create_transform(int previous_pos, int next_pos, size_t ribbon_size, Direction direction) {
|
||||||
// We first deal with cases were we cross the end of the ribbon
|
// We first deal with cases were we cross the end of the ribbon
|
||||||
if (direction == Direction::Left and next_pos > previous_pos) {
|
if (direction == Direction::Left and next_pos > previous_pos) {
|
||||||
return Toolkit::AffineTransform<float>(
|
return Toolkit::AffineTransform<float>(
|
||||||
@ -46,9 +48,9 @@ Toolkit::AffineTransform<float> MusicSelect::MoveAnimation::create_transform(int
|
|||||||
static_cast<float>(next_pos)
|
static_cast<float>(next_pos)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float MusicSelect::MoveAnimation::get_position() {
|
float MoveAnimation::get_position() {
|
||||||
return normalized_to_pos.transform(
|
return normalized_to_pos.transform(
|
||||||
ease_expo.transform(
|
ease_expo.transform(
|
||||||
seconds_to_normalized.clampedTransform(
|
seconds_to_normalized.clampedTransform(
|
||||||
@ -56,24 +58,24 @@ float MusicSelect::MoveAnimation::get_position() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MusicSelect::MoveAnimation::ended() {
|
bool MoveAnimation::ended() {
|
||||||
return clock.getElapsedTime() / m_time_factor > sf::milliseconds(300);
|
return clock.getElapsedTime() / m_time_factor > sf::milliseconds(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicSelect::Ribbon::Ribbon(Resources& t_resources, float& panel_size, float& panel_spacing) :
|
Ribbon::Ribbon(Resources& t_resources, float& panel_size, float& panel_spacing) :
|
||||||
m_layout(),
|
m_layout(),
|
||||||
m_move_animation(),
|
m_move_animation(),
|
||||||
m_resources(t_resources),
|
m_resources(t_resources),
|
||||||
empty_song(),
|
empty_song(),
|
||||||
m_panel_size(panel_size),
|
m_panel_size(panel_size),
|
||||||
m_panel_spacing(panel_spacing)
|
m_panel_spacing(panel_spacing)
|
||||||
{
|
{
|
||||||
std::cout << "Loaded MusicSelect::Ribbon" << std::endl;
|
std::cout << "Loaded Ribbon" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::title_sort(const Data::SongList &song_list) {
|
void Ribbon::title_sort(const Data::SongList &song_list) {
|
||||||
std::vector<std::reference_wrapper<const Data::Song>> songs;
|
std::vector<std::reference_wrapper<const Data::Song>> songs;
|
||||||
for (auto &&song : song_list.songs) {
|
for (auto &&song : song_list.songs) {
|
||||||
songs.push_back(std::cref(song));
|
songs.push_back(std::cref(song));
|
||||||
@ -103,9 +105,9 @@ void MusicSelect::Ribbon::title_sort(const Data::SongList &song_list) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout_from_category_map(categories);
|
layout_from_category_map(categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::test_sort() {
|
void Ribbon::test_sort() {
|
||||||
m_layout.clear();
|
m_layout.clear();
|
||||||
m_layout.push_back({
|
m_layout.push_back({
|
||||||
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
||||||
@ -119,9 +121,10 @@ void MusicSelect::Ribbon::test_sort() {
|
|||||||
std::make_shared<EmptyPanel>(m_panel_size, m_resources)
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
fill_layout();
|
||||||
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::test2_sort() {
|
void Ribbon::test2_sort() {
|
||||||
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
|
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
|
||||||
Toolkit::UniformIntRNG category_size_generator{1, 10};
|
Toolkit::UniformIntRNG category_size_generator{1, 10};
|
||||||
@ -130,7 +133,7 @@ void MusicSelect::Ribbon::test2_sort() {
|
|||||||
auto category_size = category_size_generator.generate();
|
auto category_size = category_size_generator.generate();
|
||||||
for (int i = 0; i < category_size; i++) {
|
for (int i = 0; i < category_size; i++) {
|
||||||
categories[std::string(1, letter)].push_back(
|
categories[std::string(1, letter)].push_back(
|
||||||
std::make_shared<MusicSelect::ColorPanel>(
|
std::make_shared<ColorPanel>(
|
||||||
m_panel_size, m_resources,
|
m_panel_size, m_resources,
|
||||||
sf::Color(
|
sf::Color(
|
||||||
panel_hue_generator.generate(),
|
panel_hue_generator.generate(),
|
||||||
@ -142,9 +145,9 @@ void MusicSelect::Ribbon::test2_sort() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout_from_category_map(categories);
|
layout_from_category_map(categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::test_song_cover_sort() {
|
void Ribbon::test_song_cover_sort() {
|
||||||
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
|
std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
|
||||||
Toolkit::UniformIntRNG category_size_generator{1, 10};
|
Toolkit::UniformIntRNG category_size_generator{1, 10};
|
||||||
@ -152,31 +155,31 @@ void MusicSelect::Ribbon::test_song_cover_sort() {
|
|||||||
auto category_size = category_size_generator.generate();
|
auto category_size = category_size_generator.generate();
|
||||||
for (int i = 0; i < category_size; i++) {
|
for (int i = 0; i < category_size; i++) {
|
||||||
categories[std::string(1, letter)].push_back(
|
categories[std::string(1, letter)].push_back(
|
||||||
std::make_shared<MusicSelect::SongPanel>(m_panel_size, m_resources, this->empty_song)
|
std::make_shared<SongPanel>(m_panel_size, m_resources, this->empty_song)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout_from_category_map(categories);
|
layout_from_category_map(categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::size_t MusicSelect::Ribbon::get_layout_column(const std::size_t& button_index) const {
|
std::size_t Ribbon::get_layout_column(const std::size_t& button_index) const {
|
||||||
return (m_position + (button_index % 4)) % m_layout.size();
|
return (m_position + (button_index % 4)) % m_layout.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<MusicSelect::Panel> &MusicSelect::Ribbon::get_panel_under_button(std::size_t button_index) const {
|
const std::shared_ptr<Panel> &Ribbon::get_panel_under_button(std::size_t button_index) const {
|
||||||
return (
|
return (
|
||||||
m_layout
|
m_layout
|
||||||
.at(this->get_layout_column(button_index))
|
.at(this->get_layout_column(button_index))
|
||||||
.at(button_index / 4)
|
.at(button_index / 4)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::click_on(std::size_t button_index) {
|
void Ribbon::click_on(std::size_t button_index) {
|
||||||
this->get_panel_under_button(button_index)->click(*this, button_index);
|
this->get_panel_under_button(button_index)->click(*this, button_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::layout_from_category_map(const std::map<std::string, std::vector<std::shared_ptr<MusicSelect::Panel>>> &categories) {
|
void Ribbon::layout_from_category_map(const std::map<std::string, std::vector<std::shared_ptr<Panel>>> &categories) {
|
||||||
m_layout.clear();
|
m_layout.clear();
|
||||||
for (auto &&[category, panels] : categories) {
|
for (auto &&[category, panels] : categories) {
|
||||||
if (not panels.empty()) {
|
if (not panels.empty()) {
|
||||||
@ -198,15 +201,16 @@ void MusicSelect::Ribbon::layout_from_category_map(const std::map<std::string, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
fill_layout();
|
||||||
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::move_right() {
|
void Ribbon::move_right() {
|
||||||
std::size_t old_position = m_position;
|
std::size_t old_position = m_position;
|
||||||
m_position = (m_position + 1) % m_layout.size();
|
m_position = (m_position + 1) % m_layout.size();
|
||||||
m_move_animation.emplace(old_position, m_position, m_layout.size(), Direction::Right, m_time_factor);
|
m_move_animation.emplace(old_position, m_position, m_layout.size(), Direction::Right, m_time_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::move_left() {
|
void Ribbon::move_left() {
|
||||||
std::size_t old_position = m_position;
|
std::size_t old_position = m_position;
|
||||||
if (m_position == 0) {
|
if (m_position == 0) {
|
||||||
m_position = m_layout.size() - 1;
|
m_position = m_layout.size() - 1;
|
||||||
@ -214,9 +218,9 @@ void MusicSelect::Ribbon::move_left() {
|
|||||||
m_position--;
|
m_position--;
|
||||||
}
|
}
|
||||||
m_move_animation.emplace(old_position, m_position, m_layout.size(), Direction::Left, m_time_factor);
|
m_move_animation.emplace(old_position, m_position, m_layout.size(), Direction::Left, m_time_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::move_to_next_category(const std::size_t& from_button_index) {
|
void Ribbon::move_to_next_category(const std::size_t& from_button_index) {
|
||||||
std::size_t old_position = m_position;
|
std::size_t old_position = m_position;
|
||||||
std::size_t from_column = this->get_layout_column(from_button_index);
|
std::size_t from_column = this->get_layout_column(from_button_index);
|
||||||
|
|
||||||
@ -229,7 +233,7 @@ void MusicSelect::Ribbon::move_to_next_category(const std::size_t& from_button_i
|
|||||||
if (std::any_of(
|
if (std::any_of(
|
||||||
column.begin(),
|
column.begin(),
|
||||||
column.end(),
|
column.end(),
|
||||||
[](std::shared_ptr<MusicSelect::Panel> panel) -> bool {
|
[](std::shared_ptr<Panel> panel) -> bool {
|
||||||
return (std::dynamic_pointer_cast<CategoryPanel>(panel).get() != nullptr);
|
return (std::dynamic_pointer_cast<CategoryPanel>(panel).get() != nullptr);
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
@ -245,9 +249,9 @@ void MusicSelect::Ribbon::move_to_next_category(const std::size_t& from_button_i
|
|||||||
m_position = next_category_column - onscreen_clicked_column;
|
m_position = next_category_column - onscreen_clicked_column;
|
||||||
m_move_animation.emplace(old_position, m_position, m_layout.size(), Direction::Right, m_time_factor);
|
m_move_animation.emplace(old_position, m_position, m_layout.size(), Direction::Right, m_time_factor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::draw(sf::RenderTarget &target, sf::RenderStates states) const {
|
void Ribbon::draw(sf::RenderTarget &target, sf::RenderStates states) const {
|
||||||
states.transform *= getTransform();
|
states.transform *= getTransform();
|
||||||
if (m_move_animation) {
|
if (m_move_animation) {
|
||||||
if (not m_move_animation->ended()) {
|
if (not m_move_animation->ended()) {
|
||||||
@ -257,9 +261,9 @@ void MusicSelect::Ribbon::draw(sf::RenderTarget &target, sf::RenderStates states
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
draw_without_animation(target, states);
|
draw_without_animation(target, states);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::draw_with_animation(sf::RenderTarget &target, sf::RenderStates states) const {
|
void Ribbon::draw_with_animation(sf::RenderTarget &target, sf::RenderStates states) const {
|
||||||
auto float_position = m_move_animation->get_position();
|
auto float_position = m_move_animation->get_position();
|
||||||
int relative_column_zero = static_cast<int>(std::floor(float_position));
|
int relative_column_zero = static_cast<int>(std::floor(float_position));
|
||||||
std::size_t column_zero = (relative_column_zero + m_layout.size()) % m_layout.size();
|
std::size_t column_zero = (relative_column_zero + m_layout.size()) % m_layout.size();
|
||||||
@ -283,9 +287,9 @@ void MusicSelect::Ribbon::draw_with_animation(sf::RenderTarget &target, sf::Rend
|
|||||||
target.draw(*panel, states);
|
target.draw(*panel, states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::draw_without_animation(sf::RenderTarget &target, sf::RenderStates states) const {
|
void Ribbon::draw_without_animation(sf::RenderTarget &target, sf::RenderStates states) const {
|
||||||
for (int column = -1; column <= 4; column++) {
|
for (int column = -1; column <= 4; column++) {
|
||||||
int actual_column_index = (column + m_position + m_layout.size()) % m_layout.size();
|
int actual_column_index = (column + m_position + m_layout.size()) % m_layout.size();
|
||||||
for (int row = 0; row < 3; row++) {
|
for (int row = 0; row < 3; row++) {
|
||||||
@ -294,9 +298,9 @@ void MusicSelect::Ribbon::draw_without_animation(sf::RenderTarget &target, sf::R
|
|||||||
target.draw(*panel, states);
|
target.draw(*panel, states);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Ribbon::draw_debug() {
|
void Ribbon::draw_debug() {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
ImGui::Begin("Ribbon Debug", &debug); {
|
ImGui::Begin("Ribbon Debug", &debug); {
|
||||||
ImGui::SliderFloat("Time Slowdown Factor", &m_time_factor, 1.f, 10.f);
|
ImGui::SliderFloat("Time Slowdown Factor", &m_time_factor, 1.f, 10.f);
|
||||||
@ -319,4 +323,23 @@ void MusicSelect::Ribbon::draw_debug() {
|
|||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obligatory steps before the drawing functions can use the layout without crashing
|
||||||
|
void Ribbon::fill_layout() {
|
||||||
|
if (m_layout.empty()) {
|
||||||
|
m_layout.push_back({
|
||||||
|
std::make_shared<ColoredMessagePanel>(m_panel_size, m_resources, sf::Color::Red, "- EMPTY -"),
|
||||||
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
||||||
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while (m_layout.size() < 4) {
|
||||||
|
m_layout.push_back({
|
||||||
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
||||||
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
||||||
|
std::make_shared<EmptyPanel>(m_panel_size, m_resources),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ namespace MusicSelect {
|
|||||||
void draw_with_animation(sf::RenderTarget& target, sf::RenderStates states) const;
|
void draw_with_animation(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||||
void draw_without_animation(sf::RenderTarget& target, sf::RenderStates states) const;
|
void draw_without_animation(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||||
void layout_from_category_map(const std::map<std::string,std::vector<std::shared_ptr<Panel>>>& categories);
|
void layout_from_category_map(const std::map<std::string,std::vector<std::shared_ptr<Panel>>>& categories);
|
||||||
|
void fill_layout();
|
||||||
std::size_t get_layout_column(const std::size_t& button_index) const;
|
std::size_t get_layout_column(const std::size_t& button_index) const;
|
||||||
std::vector<std::array<std::shared_ptr<Panel>,3>> m_layout;
|
std::vector<std::array<std::shared_ptr<Panel>,3>> m_layout;
|
||||||
std::size_t m_position = 0;
|
std::size_t m_position = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user