Ribbon layout that works !!!
This commit is contained in:
parent
ec5c4e270b
commit
70548a6fba
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
build*/
|
build*/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
include/imgui*
|
@ -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',
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
11
src/Toolkit/Debuggable.hpp
Normal file
11
src/Toolkit/Debuggable.hpp
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user