1
0
mirror of synced 2025-02-02 20:37:25 +01:00

Ribbon layout that works !!!

This commit is contained in:
Stepland 2020-01-27 20:06:10 +01:00
parent ec5c4e270b
commit 70548a6fba
11 changed files with 226 additions and 120 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
build*/ build*/
.vscode/ .vscode/
include/imgui*

View File

@ -10,9 +10,13 @@ foreach module : ['system', 'window', 'graphics', 'audio']
sfml += [dependency('sfml-'+module, version : '>=2.5.1')] sfml += [dependency('sfml-'+module, version : '>=2.5.1')]
endforeach endforeach
add_project_link_arguments(['-lstdc++', '-lstdc++fs', '-lm'], language : 'cpp') add_project_link_arguments(['-lstdc++', '-lstdc++fs', '-lm', '-lGL'], language : 'cpp')
sources = [ sources = [
'include/imgui/imgui.cpp',
'include/imgui/imgui_draw.cpp',
'include/imgui/imgui_widgets.cpp',
'include/imgui-sfml/imgui-SFML.cpp',
'src/Main.cpp', 'src/Main.cpp',
'src/Data/Chart.hpp', 'src/Data/Chart.hpp',
'src/Data/KeyMapping.hpp', 'src/Data/KeyMapping.hpp',
@ -37,6 +41,7 @@ sources = [
'src/Resources/CoverAtlas.hpp', 'src/Resources/CoverAtlas.hpp',
'src/Resources/CoverAtlas.cpp', 'src/Resources/CoverAtlas.cpp',
'src/Toolkit/AffineTransform.hpp', 'src/Toolkit/AffineTransform.hpp',
'src/Toolkit/Debuggable.hpp',
'src/Toolkit/EasingFunctions.hpp', 'src/Toolkit/EasingFunctions.hpp',
'src/Toolkit/EasingFunctions.cpp', 'src/Toolkit/EasingFunctions.cpp',
'src/Toolkit/QuickRNG.hpp', 'src/Toolkit/QuickRNG.hpp',
@ -47,7 +52,7 @@ executable(
'jujube', 'jujube',
sources, sources,
dependencies: [sfml], dependencies: [sfml],
include_directories : include_directories('include'), include_directories : include_directories('include', 'include/imgui', 'include/imgui-sfml'),
cpp_args : [ cpp_args : [
'-Wall', '-Wall',
'-Wextra', '-Wextra',

View File

@ -16,7 +16,7 @@ Textures::CoverAltas::CoverAltas() :
sf::Sprite Textures::CoverAltas::at(const fs::path& path) const { sf::Sprite Textures::CoverAltas::at(const fs::path& path) const {
unsigned int index; std::size_t index;
if (path_to_index.find(path) != path_to_index.end()) { if (path_to_index.find(path) != path_to_index.end()) {
index = path_to_index.at(path); index = path_to_index.at(path);
} else { } else {
@ -41,7 +41,7 @@ void Textures::CoverAltas::emplace_back(const fs::path& cover) {
if (!cover_texture.loadFromFile(cover)) { if (!cover_texture.loadFromFile(cover)) {
throw std::invalid_argument("Unable to load cover image : "+cover.string()); throw std::invalid_argument("Unable to load cover image : "+cover.string());
} }
unsigned int next_index = next_available_index(); std::size_t next_index = next_available_index();
auto size = cover_texture.getSize(); auto size = cover_texture.getSize();
auto location = get_detailed_location(next_index); auto location = get_detailed_location(next_index);
sf::Sprite new_cover; sf::Sprite new_cover;
@ -80,12 +80,12 @@ void Textures::CoverAltas::efficient_reload(const std::vector<fs::path>& covers)
} }
} }
Textures::DetailedLocation Textures::get_detailed_location(unsigned int location) { Textures::DetailedLocation Textures::get_detailed_location(std::size_t location) {
return {location / 16, (location % 16) / 4, location % 4}; return {location / 16, (location % 16) / 4, location % 4};
} }
unsigned int Textures::CoverAltas::next_available_index() { std::size_t Textures::CoverAltas::next_available_index() {
unsigned int index = 0; std::size_t index = 0;
while (index_to_path.find(index) != index_to_path.end()) { while (index_to_path.find(index) != index_to_path.end()) {
++index; ++index;
} }

View File

@ -37,17 +37,17 @@ namespace Textures {
void efficient_reload(const std::vector<fs::path>& covers); void efficient_reload(const std::vector<fs::path>& covers);
private: private:
std::unordered_map<fs::path, unsigned int> path_to_index; std::unordered_map<fs::path, std::size_t> path_to_index;
std::unordered_map<unsigned int, fs::path> index_to_path; std::unordered_map<std::size_t, fs::path> index_to_path;
std::vector<std::shared_ptr<sf::RenderTexture>> textures; std::vector<std::shared_ptr<sf::RenderTexture>> textures;
unsigned int next_available_index(); std::size_t next_available_index();
}; };
struct DetailedLocation { struct DetailedLocation {
unsigned int texture_index; std::size_t texture_index;
unsigned int row; std::size_t row;
unsigned int column; std::size_t column;
}; };
DetailedLocation get_detailed_location(unsigned int location); DetailedLocation get_detailed_location(std::size_t location);
} }

View File

@ -1,6 +1,6 @@
#include "ButtonHighlight.hpp" #include "ButtonHighlight.hpp"
MusicSelect::ButtonHighlight::ButtonHighlight(unsigned int t_panel_size) : MusicSelect::ButtonHighlight::ButtonHighlight(std::size_t t_panel_size) :
panel_size(t_panel_size), panel_size(t_panel_size),
highlight({static_cast<float>(t_panel_size-3), static_cast<float>(t_panel_size-3)}), highlight({static_cast<float>(t_panel_size-3), static_cast<float>(t_panel_size-3)}),
time_to_alpha(0.f, 0.25f, 255.f, 0.f) time_to_alpha(0.f, 0.25f, 255.f, 0.f)
@ -23,7 +23,7 @@ void MusicSelect::ButtonHighlight::draw(sf::RenderTarget& target, sf::RenderStat
it = button_presses_history.erase(it); it = button_presses_history.erase(it);
} else { } else {
auto alpha = time_to_alpha.transform(elapsed.asSeconds()); auto alpha = time_to_alpha.transform(elapsed.asSeconds());
highlight.setOutlineColor(sf::Color(255,255,0,static_cast<unsigned int>(alpha))); highlight.setOutlineColor(sf::Color(255,255,0,static_cast<std::size_t>(alpha)));
highlight.setPosition({ highlight.setPosition({
static_cast<float>(coords.x * panel_size) + panel_size/2.f, static_cast<float>(coords.x * panel_size) + panel_size/2.f,
static_cast<float>(coords.y * panel_size) + panel_size/2.f static_cast<float>(coords.y * panel_size) + panel_size/2.f

View File

@ -11,11 +11,11 @@
namespace MusicSelect { namespace MusicSelect {
class ButtonHighlight : public sf::Drawable { class ButtonHighlight : public sf::Drawable {
public: public:
explicit ButtonHighlight(unsigned int t_panel_size); explicit ButtonHighlight(std::size_t t_panel_size);
void button_pressed(Button button); void button_pressed(Button button);
private: private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
unsigned int panel_size; std::size_t panel_size;
mutable sf::RectangleShape highlight; mutable sf::RectangleShape highlight;
mutable std::map<Button, sf::Clock> button_presses_history; mutable std::map<Button, sf::Clock> button_presses_history;
Toolkit::AffineTransform<float> time_to_alpha; Toolkit::AffineTransform<float> time_to_alpha;

View File

@ -1,5 +1,8 @@
#include "MusicSelect.hpp" #include "MusicSelect.hpp"
#include "imgui/imgui.h"
#include "imgui-sfml/imgui-SFML.h"
#include <iostream> #include <iostream>
#include "../../Data/KeyMapping.hpp" #include "../../Data/KeyMapping.hpp"
@ -25,10 +28,13 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
window.create(sf::VideoMode(panel_size*4, panel_size*4), "jujube", sf::Style::Titlebar); window.create(sf::VideoMode(panel_size*4, panel_size*4), "jujube", sf::Style::Titlebar);
window.setFramerateLimit(60); window.setFramerateLimit(60);
ImGui::SFML::Init(window);
bool chart_selected = false; bool chart_selected = false;
sf::Clock imguiClock;
while (not chart_selected) { while (not chart_selected) {
sf::Event event; sf::Event event;
while (window.pollEvent(event)) { while (window.pollEvent(event)) {
ImGui::SFML::ProcessEvent(event);
switch (event.type) { switch (event.type) {
case sf::Event::KeyPressed: case sf::Event::KeyPressed:
handle_key_press(event.key); handle_key_press(event.key);
@ -39,17 +45,30 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
break; break;
} }
} }
ImGui::SFML::Update(window, imguiClock.restart());
window.clear(sf::Color::Black);
ribbon.draw_debug();
window.draw(ribbon); window.draw(ribbon);
window.draw(button_highlight); window.draw(button_highlight);
ImGui::SFML::Render(window);
window.display(); window.display();
window.clear(sf::Color::Black);
} }
ImGui::SFML::Shutdown();
} }
void MusicSelect::Screen::handle_key_press(const sf::Event::KeyEvent& key_event) { void MusicSelect::Screen::handle_key_press(const sf::Event::KeyEvent& key_event) {
auto button = key_mapping.key_to_button(key_event.code); auto button = key_mapping.key_to_button(key_event.code);
if (button) { if (button) {
press_button(*button); press_button(*button);
} else {
switch (key_event.code){
case sf::Keyboard::F12:
ribbon.debug = not ribbon.debug;
break;
default:
break;
}
} }
} }

View File

@ -24,7 +24,7 @@ namespace MusicSelect {
private: private:
// Data // Data
const Data::SongList& song_list; const Data::SongList& song_list;
unsigned int panel_size = 150; std::size_t panel_size = 150;
// Resources // Resources
Resources resources; Resources resources;

View File

@ -1,161 +1,182 @@
#include "Ribbon.hpp" #include "Ribbon.hpp"
#include "imgui/imgui.h"
#include "imgui-sfml/imgui-SFML.h"
#include <cmath>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <map> #include <map>
#include <vector> #include <vector>
#include "Panel.hpp" #include "Panel.hpp"
#include "../../Toolkit/QuickRNG.hpp" #include "../../Toolkit/QuickRNG.hpp"
MusicSelect::MoveAnimation::MoveAnimation(unsigned int previous_pos, unsigned int next_pos, size_t ribbon_size, Direction direction) : 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),
time_factor(t_time_factor),
clock(), clock(),
ease_expo(-7.f) ease_expo(-7.f)
{ {
} }
Toolkit::AffineTransform<float> MusicSelect::MoveAnimation::create_transform(unsigned int previous_pos, unsigned int next_pos, size_t ribbon_size, Direction direction) { Toolkit::AffineTransform<float> MusicSelect::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>(
0.f, 0.f,
1.f, 1.f,
static_cast<float>(previous_pos), static_cast<float>(previous_pos),
static_cast<float>(next_pos-ribbon_size) static_cast<float>(next_pos) - ribbon_size);
); }
} else if (direction == Direction::Right and next_pos < previous_pos) { else if (direction == Direction::Right and next_pos < previous_pos)
{
return Toolkit::AffineTransform<float>( return Toolkit::AffineTransform<float>(
0.f, 0.f,
1.f, 1.f,
static_cast<float>(previous_pos), static_cast<float>(previous_pos),
static_cast<float>(next_pos+ribbon_size) static_cast<float>(next_pos) + ribbon_size);
); }
} else { else
{
return Toolkit::AffineTransform<float>( return Toolkit::AffineTransform<float>(
0.f, 0.f,
1.f, 1.f,
static_cast<float>(previous_pos), static_cast<float>(previous_pos),
static_cast<float>(next_pos) static_cast<float>(next_pos));
);
} }
} }
float MusicSelect::MoveAnimation::get_position() { float MusicSelect::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(
clock.getElapsedTime().asSeconds() clock.getElapsedTime().asSeconds() / time_factor)));
)
)
);
} }
bool MusicSelect::MoveAnimation::ended() { bool MusicSelect::MoveAnimation::ended()
return clock.getElapsedTime() > sf::milliseconds(300); {
return clock.getElapsedTime() / time_factor > sf::milliseconds(300);
} }
void MusicSelect::Ribbon::title_sort(const Data::SongList& song_list) { void MusicSelect::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));
} }
(song_list.songs.begin(), song_list.songs.end()); (song_list.songs.begin(), song_list.songs.end());
std::sort(songs.begin(), songs.end(), Data::Song::sort_by_title); std::sort(songs.begin(), songs.end(), Data::Song::sort_by_title);
std::map<std::string,std::vector<std::shared_ptr<Panel>>> categories; std::map<std::string, std::vector<std::shared_ptr<Panel>>> categories;
for (const auto& song : songs) { for (const auto &song : songs)
if (song.get().title.size() > 0) { {
if (song.get().title.size() > 0)
{
char letter = song.get().title[0]; char letter = song.get().title[0];
if ('A' <= letter and letter <= 'Z') { if ('A' <= letter and letter <= 'Z')
{
categories categories
[std::string(1, letter)] [std::string(1, letter)]
.push_back( .push_back(
std::make_shared<SongPanel>(song) std::make_shared<SongPanel>(song));
); }
} else if ('a' <= letter and letter <= 'z') { else if ('a' <= letter and letter <= 'z')
{
categories categories
[std::string(1, 'A' + (letter - 'a'))] [std::string(1, 'A' + (letter - 'a'))]
.push_back( .push_back(
std::make_shared<SongPanel>(song) std::make_shared<SongPanel>(song));
); }
} else { else
{
categories["?"].push_back(std::make_shared<SongPanel>(song)); categories["?"].push_back(std::make_shared<SongPanel>(song));
} }
} else { }
else
{
categories["?"].push_back(std::make_shared<SongPanel>(song)); categories["?"].push_back(std::make_shared<SongPanel>(song));
} }
} }
layout_from_category_map(categories); layout_from_category_map(categories);
} }
void MusicSelect::Ribbon::test_sort() { void MusicSelect::Ribbon::test_sort()
{
layout.clear(); layout.clear();
layout.push_back( layout.push_back(
{ {std::make_shared<EmptyPanel>(),
std::make_shared<EmptyPanel>(), std::make_shared<CategoryPanel>("A"),
std::make_shared<CategoryPanel>("A"), std::make_shared<CategoryPanel>("truc")});
std::make_shared<CategoryPanel>("truc") for (size_t i = 0; i < 3; i++)
} {
);
for (size_t i = 0; i < 3; i++) {
layout.push_back( layout.push_back(
{ {std::make_shared<EmptyPanel>(),
std::make_shared<EmptyPanel>(), std::make_shared<EmptyPanel>(),
std::make_shared<EmptyPanel>(), std::make_shared<EmptyPanel>()});
std::make_shared<EmptyPanel>()
}
);
} }
} }
void MusicSelect::Ribbon::test2_sort() { void MusicSelect::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};
Toolkit::UniformIntRNG panel_hue_generator{0,255}; Toolkit::UniformIntRNG panel_hue_generator{0, 255};
for (auto &&letter : alphabet) { for (auto &&letter : alphabet)
{
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<MusicSelect::ColorPanel>(
sf::Color( sf::Color(
panel_hue_generator.generate(), panel_hue_generator.generate(),
panel_hue_generator.generate(), panel_hue_generator.generate(),
panel_hue_generator.generate() panel_hue_generator.generate())));
)
)
);
} }
} }
layout_from_category_map(categories); layout_from_category_map(categories);
} }
const std::shared_ptr<MusicSelect::Panel>& MusicSelect::Ribbon::at(unsigned int button_index) const { const std::shared_ptr<MusicSelect::Panel> &MusicSelect::Ribbon::at(std::size_t button_index) const
{
return ( return (
layout layout
.at((position + (button_index % 4)) % layout.size()) .at((position + (button_index % 4)) % layout.size())
.at(button_index / 4) .at(button_index / 4));
);
} }
void MusicSelect::Ribbon::layout_from_category_map(const std::map<std::string, std::vector<std::shared_ptr<MusicSelect::Panel>>>& categories) { void MusicSelect::Ribbon::layout_from_category_map(const std::map<std::string, std::vector<std::shared_ptr<MusicSelect::Panel>>> &categories)
{
layout.clear(); layout.clear();
for (auto &&[category, panels] : categories) { for (auto &&[category, panels] : categories)
if (not panels.empty()) { {
if (not panels.empty())
{
std::vector<std::shared_ptr<Panel>> current_column; std::vector<std::shared_ptr<Panel>> current_column;
current_column.push_back(std::make_shared<CategoryPanel>(category)); current_column.push_back(std::make_shared<CategoryPanel>(category));
for (auto &&panel : panels) { for (auto &&panel : panels)
if (current_column.size() == 3) { {
if (current_column.size() == 3)
{
layout.push_back({current_column[0], current_column[1], current_column[2]}); layout.push_back({current_column[0], current_column[1], current_column[2]});
current_column.clear(); current_column.clear();
} else { }
else
{
current_column.push_back(std::move(panel)); current_column.push_back(std::move(panel));
} }
} }
if (not current_column.empty()) { if (not current_column.empty())
while (current_column.size() < 3) { {
while (current_column.size() < 3)
{
current_column.push_back(std::make_shared<EmptyPanel>()); current_column.push_back(std::make_shared<EmptyPanel>());
} }
layout.push_back({current_column[0], current_column[1], current_column[2]}); layout.push_back({current_column[0], current_column[1], current_column[2]});
@ -164,43 +185,71 @@ void MusicSelect::Ribbon::layout_from_category_map(const std::map<std::string, s
} }
} }
void MusicSelect::Ribbon::move_right() { void MusicSelect::Ribbon::move_right()
move_animation.emplace(position, position + 1, layout.size(), Direction::Right); {
std::size_t old_position = position;
position = (position + 1) % layout.size(); position = (position + 1) % layout.size();
move_animation.emplace(old_position, position, layout.size(), Direction::Right, time_factor);
} }
void MusicSelect::Ribbon::move_left() { void MusicSelect::Ribbon::move_left()
move_animation.emplace(position, static_cast<int>(position)-1, layout.size(), Direction::Left); {
if (position == 0) { std::size_t old_position = position;
if (position == 0)
{
position = layout.size() - 1; position = layout.size() - 1;
} else { }
else
{
position--; position--;
} }
move_animation.emplace(old_position, position, layout.size(), Direction::Left, time_factor);
} }
void MusicSelect::Ribbon::draw(sf::RenderTarget& target, sf::RenderStates states) const { void MusicSelect::Ribbon::draw(sf::RenderTarget &target, sf::RenderStates states) const
if (move_animation) { {
if (not move_animation->ended()) { if (move_animation)
{
if (not move_animation->ended())
{
return draw_with_animation(target, states); return draw_with_animation(target, states);
} else { }
else
{
move_animation.reset(); move_animation.reset();
} }
} }
draw_without_animation(target, states); draw_without_animation(target, states);
} }
void MusicSelect::Ribbon::draw_with_animation(sf::RenderTarget& target, sf::RenderStates states) const { void MusicSelect::Ribbon::draw_with_animation(sf::RenderTarget &target, sf::RenderStates states) const
{
auto float_position = move_animation->get_position(); auto float_position = move_animation->get_position();
unsigned int column_zero = (static_cast<int>(float_position) + layout.size()) % layout.size(); int relative_column_zero = static_cast<int>(std::floor(float_position));
for (int column_offset = -1; column_offset <= 4; column_offset++) { std::size_t column_zero = (relative_column_zero + layout.size()) % layout.size();
unsigned int actual_column = (column_zero + column_offset + layout.size()) % layout.size();
for (int row = 0; row < 3; row++) { if (debug) {
layout.at(actual_column).at(row)->draw( ImGui::Begin("Ribbon Debug"); {
ImGui::Text("float position : %f", float_position);
ImGui::Text("zeroth column : %lu", column_zero);
}
ImGui::End();
}
for (int column_offset = -1; column_offset <= 4; column_offset++)
{
std::size_t actual_column = (column_zero + column_offset + layout.size()) % layout.size();
for (int row = 0; row < 3; row++)
{
layout
.at(actual_column)
.at(row)
->draw(
resources, resources,
target, target,
sf::FloatRect( sf::FloatRect(
(static_cast<float>(column_zero + column_offset)-float_position)*150.f, (static_cast<float>(relative_column_zero + column_offset) - float_position) * 150.f,
row*150.f, row * 150.f,
150.f, 150.f,
150.f 150.f
) )
@ -209,16 +258,22 @@ void MusicSelect::Ribbon::draw_with_animation(sf::RenderTarget& target, sf::Rend
} }
} }
void MusicSelect::Ribbon::draw_without_animation(sf::RenderTarget& target, sf::RenderStates states) const { void MusicSelect::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 + position + layout.size()) % layout.size(); int actual_column_index = (column + position + layout.size()) % layout.size();
for (int row = 0; row < 3; row++) { for (int row = 0; row < 3; row++)
layout.at(actual_column_index).at(row)->draw( {
layout
.at(actual_column_index)
.at(row)
->draw(
resources, resources,
target, target,
sf::FloatRect( sf::FloatRect(
column*150.f, column * 150.f,
row*150.f, row * 150.f,
150.f, 150.f,
150.f 150.f
) )
@ -226,3 +281,14 @@ void MusicSelect::Ribbon::draw_without_animation(sf::RenderTarget& target, sf::R
} }
} }
} }
void MusicSelect::Ribbon::draw_debug()
{
if (debug) {
ImGui::Begin("Ribbon Debug");
{
ImGui::SliderFloat("Time Slowdown Factor", &time_factor, 1.f, 10.f);
}
ImGui::End();
}
}

View File

@ -5,6 +5,7 @@
#include "Panel.hpp" #include "Panel.hpp"
#include "../../Data/SongList.hpp" #include "../../Data/SongList.hpp"
#include "../../Toolkit/AffineTransform.hpp" #include "../../Toolkit/AffineTransform.hpp"
#include "../../Toolkit/Debuggable.hpp"
#include "../../Toolkit/EasingFunctions.hpp" #include "../../Toolkit/EasingFunctions.hpp"
namespace MusicSelect { namespace MusicSelect {
@ -15,37 +16,40 @@ namespace MusicSelect {
}; };
struct MoveAnimation { struct MoveAnimation {
MoveAnimation(unsigned int previous_pos, unsigned int next_pos, size_t ribbon_size, Direction direction); MoveAnimation(int previous_pos, int next_pos, size_t ribbon_size, Direction direction, float& t_time_factor);
Toolkit::AffineTransform<float> normalized_to_pos; Toolkit::AffineTransform<float> normalized_to_pos;
Toolkit::AffineTransform<float> seconds_to_normalized; Toolkit::AffineTransform<float> seconds_to_normalized;
float& time_factor;
sf::Clock clock; sf::Clock clock;
Toolkit::EaseExponential ease_expo; Toolkit::EaseExponential ease_expo;
float get_position(); float get_position();
bool ended(); bool ended();
private: private:
Toolkit::AffineTransform<float> create_transform(unsigned int previous_pos, unsigned int next_pos, size_t ribbon_size, Direction direction); Toolkit::AffineTransform<float> create_transform(int previous_pos, int next_pos, size_t ribbon_size, Direction direction);
}; };
// The Ribbon is the moving part of the Music Select Screen // The Ribbon is the moving part of the Music Select Screen
// It can be sorted in a number of ways // It can be sorted in a number of ways
class Ribbon final : public sf::Drawable { class Ribbon final : public sf::Drawable, public Toolkit::Debuggable {
public: public:
Ribbon(const Resources& t_resources) : resources(t_resources) {}; Ribbon(const Resources& t_resources) : resources(t_resources) {};
void title_sort(const Data::SongList& song_list); void title_sort(const Data::SongList& song_list);
void test_sort(); void test_sort();
void test2_sort(); void test2_sort();
const auto& get_layout() {return layout;}; const auto& get_layout() {return layout;};
const std::shared_ptr<MusicSelect::Panel>& at(unsigned int button_index) const; const std::shared_ptr<MusicSelect::Panel>& at(std::size_t button_index) const;
void move_right(); void move_right();
void move_left(); void move_left();
void draw_debug() override;
private: private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override; void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
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);
std::vector<std::array<std::shared_ptr<Panel>,3>> layout; std::vector<std::array<std::shared_ptr<Panel>,3>> layout;
unsigned int position = 0; std::size_t position = 0;
mutable std::optional<MoveAnimation> move_animation; mutable std::optional<MoveAnimation> move_animation;
const Resources& resources; const Resources& resources;
float time_factor = 1.f;
}; };
} }

View File

@ -0,0 +1,11 @@
#pragma once
namespace Toolkit {
// Classes that can show a debug interface toggled by the boolean
class Debuggable {
public:
virtual ~Debuggable() = default;
virtual void draw_debug() = 0;
bool debug;
};
}