Basic category layout
This commit is contained in:
parent
59960de2bb
commit
12b5283a71
@ -1,7 +1,7 @@
|
|||||||
project(
|
project(
|
||||||
'jujube',
|
'jujube',
|
||||||
'cpp',
|
'cpp',
|
||||||
default_options : ['cpp_std=c++17'],
|
default_options : ['cpp_std=c++20'],
|
||||||
version : '0.1.0-alpha',
|
version : '0.1.0-alpha',
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,6 +23,8 @@ sources = [
|
|||||||
'src/Data/SongList.hpp',
|
'src/Data/SongList.hpp',
|
||||||
'src/Data/SongList.cpp',
|
'src/Data/SongList.cpp',
|
||||||
# 'src/Screens/Gameplay.hpp',
|
# 'src/Screens/Gameplay.hpp',
|
||||||
|
'src/Screens/MusicSelect/ButtonHighlight.hpp',
|
||||||
|
'src/Screens/MusicSelect/ButtonHighlight.cpp',
|
||||||
'src/Screens/MusicSelect/MusicSelect.hpp',
|
'src/Screens/MusicSelect/MusicSelect.hpp',
|
||||||
'src/Screens/MusicSelect/MusicSelect.cpp',
|
'src/Screens/MusicSelect/MusicSelect.cpp',
|
||||||
'src/Screens/MusicSelect/Panel.hpp',
|
'src/Screens/MusicSelect/Panel.hpp',
|
||||||
@ -34,6 +36,9 @@ sources = [
|
|||||||
# 'src/Screens/Result.hpp',
|
# 'src/Screens/Result.hpp',
|
||||||
'src/Resources/CoverAtlas.hpp',
|
'src/Resources/CoverAtlas.hpp',
|
||||||
'src/Resources/CoverAtlas.cpp',
|
'src/Resources/CoverAtlas.cpp',
|
||||||
|
'src/Toolkit/QuickRNG.hpp',
|
||||||
|
'src/Toolkit/QuickRNG.cpp',
|
||||||
|
'src/Toolkit/AffineTransform.hpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
|
@ -1,10 +1,35 @@
|
|||||||
#include "KeyMapping.hpp"
|
#include "KeyMapping.hpp"
|
||||||
|
|
||||||
ButtonCoords toCoord(Button panel) {
|
ButtonCoords toCoords(Button button) {
|
||||||
auto num = static_cast<int>(panel);
|
auto num = static_cast<unsigned int>(button);
|
||||||
return {num % 4, num / 4};
|
return {num % 4, num / 4};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int toIndex(Button button) {
|
||||||
|
return static_cast<unsigned int>(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Button> fromCoords(ButtonCoords button_coords) {
|
||||||
|
if (
|
||||||
|
button_coords.x >= 0 and
|
||||||
|
button_coords.x < 4 and
|
||||||
|
button_coords.y >= 0 and
|
||||||
|
button_coords.y < 4
|
||||||
|
) {
|
||||||
|
return static_cast<Button>(button_coords.x + 4*button_coords.y);
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Button> fromIndex(unsigned int index) {
|
||||||
|
if (index >= 0 and index < 16) {
|
||||||
|
return static_cast<Button>(index);
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyMapping::KeyMapping() {
|
KeyMapping::KeyMapping() {
|
||||||
m_key_to_button[sf::Keyboard::Num1] = Button::B1;
|
m_key_to_button[sf::Keyboard::Num1] = Button::B1;
|
||||||
m_key_to_button[sf::Keyboard::Num2] = Button::B2;
|
m_key_to_button[sf::Keyboard::Num2] = Button::B2;
|
||||||
@ -28,27 +53,27 @@ KeyMapping::KeyMapping() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyMapping::setPanelToKey(const Button& panel, const sf::Keyboard::Key& key) {
|
void KeyMapping::setPanelToKey(const Button& button, const sf::Keyboard::Key& key) {
|
||||||
if (m_key_to_button.find(key) != m_key_to_button.end()) {
|
if (m_key_to_button.find(key) != m_key_to_button.end()) {
|
||||||
m_button_to_key.erase(m_key_to_button[key]);
|
m_button_to_key.erase(m_key_to_button[key]);
|
||||||
m_key_to_button.erase(key);
|
m_key_to_button.erase(key);
|
||||||
}
|
}
|
||||||
m_button_to_key[panel] = key;
|
m_button_to_key[button] = key;
|
||||||
m_key_to_button[key] = panel;
|
m_key_to_button[key] = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Button> KeyMapping::key_to_button(const sf::Keyboard::Key& key) {
|
std::optional<Button> KeyMapping::key_to_button(const sf::Keyboard::Key& key) {
|
||||||
try {
|
if (m_key_to_button.find(key) == m_key_to_button.end()) {
|
||||||
return m_key_to_button.at(key);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
return {};
|
return {};
|
||||||
|
} else {
|
||||||
|
return m_key_to_button.at(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<sf::Keyboard::Key> KeyMapping::button_to_key(const Button& panel) {
|
std::optional<sf::Keyboard::Key> KeyMapping::button_to_key(const Button& button) {
|
||||||
try {
|
if (m_button_to_key.find(button) == m_button_to_key.end()) {
|
||||||
return m_button_to_key.at(panel);
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
return {};
|
return {};
|
||||||
|
} else {
|
||||||
|
return m_button_to_key.at(button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,10 @@ struct ButtonCoords {
|
|||||||
unsigned int y;
|
unsigned int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonCoords toCoord(Button button);
|
ButtonCoords toCoords(Button button);
|
||||||
|
unsigned int toIndex(Button button);
|
||||||
|
std::optional<Button> fromCoords(ButtonCoords button_coords);
|
||||||
|
std::optional<Button> fromIndex(unsigned int index);
|
||||||
|
|
||||||
class KeyMapping {
|
class KeyMapping {
|
||||||
public:
|
public:
|
||||||
|
35
src/Screens/MusicSelect/ButtonHighlight.cpp
Normal file
35
src/Screens/MusicSelect/ButtonHighlight.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "ButtonHighlight.hpp"
|
||||||
|
|
||||||
|
MusicSelect::ButtonHighlight::ButtonHighlight(unsigned int t_panel_size) :
|
||||||
|
panel_size(t_panel_size),
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
highlight.setFillColor(sf::Color::Transparent);
|
||||||
|
highlight.setOutlineThickness(1.f);
|
||||||
|
highlight.setOrigin(highlight.getSize().x / 2.f, highlight.getSize().y / 2.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSelect::ButtonHighlight::button_pressed(Button button) {
|
||||||
|
button_presses_history[button].restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSelect::ButtonHighlight::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
||||||
|
auto it = button_presses_history.begin();
|
||||||
|
while (it != button_presses_history.end()) {
|
||||||
|
auto elapsed = it->second.getElapsedTime();
|
||||||
|
auto coords = toCoords(it->first);
|
||||||
|
if (elapsed > sf::milliseconds(250)) {
|
||||||
|
it = button_presses_history.erase(it);
|
||||||
|
} else {
|
||||||
|
auto alpha = time_to_alpha.transform(elapsed.asSeconds());
|
||||||
|
highlight.setOutlineColor(sf::Color(255,255,0,static_cast<unsigned int>(alpha)));
|
||||||
|
highlight.setPosition({
|
||||||
|
static_cast<float>(coords.x * panel_size) + panel_size/2.f,
|
||||||
|
static_cast<float>(coords.y * panel_size) + panel_size/2.f
|
||||||
|
});
|
||||||
|
target.draw(highlight, states);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
src/Screens/MusicSelect/ButtonHighlight.hpp
Normal file
23
src/Screens/MusicSelect/ButtonHighlight.hpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
#include "../../Data/KeyMapping.hpp"
|
||||||
|
#include "../../Toolkit/AffineTransform.hpp"
|
||||||
|
|
||||||
|
namespace MusicSelect {
|
||||||
|
class ButtonHighlight : public sf::Drawable {
|
||||||
|
public:
|
||||||
|
explicit ButtonHighlight(unsigned int t_panel_size);
|
||||||
|
void button_pressed(Button button);
|
||||||
|
private:
|
||||||
|
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||||
|
unsigned int panel_size;
|
||||||
|
mutable sf::RectangleShape highlight;
|
||||||
|
mutable std::map<Button, sf::Clock> button_presses_history;
|
||||||
|
Toolkit::AffineTransform<float> time_to_alpha;
|
||||||
|
};
|
||||||
|
}
|
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
|
MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
|
||||||
song_list(t_song_list),
|
song_list(t_song_list),
|
||||||
ribbon(MusicSelect::Ribbon::test_sort())
|
ribbon(MusicSelect::Ribbon::test2_sort()),
|
||||||
|
button_highlight(panel_size)
|
||||||
{
|
{
|
||||||
for (const auto& song : song_list.songs) {
|
for (const auto& song : song_list.songs) {
|
||||||
if (song.cover) {
|
if (song.cover) {
|
||||||
@ -21,7 +22,7 @@ MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
|
|||||||
|
|
||||||
void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
||||||
|
|
||||||
window.create(sf::VideoMode(600,600), "jujube", sf::Style::None);
|
window.create(sf::VideoMode(panel_size*4, panel_size*4), "jujube", sf::Style::Titlebar);
|
||||||
window.setFramerateLimit(60);
|
window.setFramerateLimit(60);
|
||||||
bool chart_selected = false;
|
bool chart_selected = false;
|
||||||
while (not chart_selected) {
|
while (not chart_selected) {
|
||||||
@ -29,13 +30,16 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
|||||||
while (window.pollEvent(event)) {
|
while (window.pollEvent(event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case sf::Event::KeyPressed:
|
case sf::Event::KeyPressed:
|
||||||
handle_key(event.key);
|
handle_key_press(event.key);
|
||||||
break;
|
break;
|
||||||
|
case sf::Event::MouseButtonPressed:
|
||||||
|
handle_mouse_click(event.mouseButton);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// drawing the ribbon
|
|
||||||
|
// draw the ribbon
|
||||||
for (size_t panel = 0; panel < 12; panel++) {
|
for (size_t panel = 0; panel < 12; panel++) {
|
||||||
ribbon.at(panel)->draw(
|
ribbon.at(panel)->draw(
|
||||||
resources,
|
resources,
|
||||||
@ -48,10 +52,43 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
window.draw(button_highlight);
|
||||||
window.display();
|
window.display();
|
||||||
window.clear(sf::Color::Black);
|
window.clear(sf::Color::Black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSelect::Screen::handle_key(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);
|
||||||
|
if (button) {
|
||||||
|
press_button(*button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSelect::Screen::handle_mouse_click(const sf::Event::MouseButtonEvent& mouse_button_event) {
|
||||||
|
if (mouse_button_event.button == sf::Mouse::Left) {
|
||||||
|
int clicked_panel_index = (mouse_button_event.x / panel_size) + 4 * (mouse_button_event.y / panel_size);
|
||||||
|
auto button = fromIndex(clicked_panel_index);
|
||||||
|
if (button) {
|
||||||
|
press_button(*button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSelect::Screen::press_button(const Button& button) {
|
||||||
|
button_highlight.button_pressed(button);
|
||||||
|
auto index = toIndex(button);
|
||||||
|
if (index < 12) {
|
||||||
|
ribbon.at(index)->click(*this);
|
||||||
|
} else {
|
||||||
|
switch (button) {
|
||||||
|
case Button::B13:
|
||||||
|
ribbon.move_left();
|
||||||
|
break;
|
||||||
|
case Button::B14:
|
||||||
|
ribbon.move_right();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
#include "../../Data/SongList.hpp"
|
#include "../../Data/SongList.hpp"
|
||||||
#include "../../Data/Chart.hpp"
|
#include "../../Data/Chart.hpp"
|
||||||
#include "../../Data/KeyMapping.hpp"
|
#include "../../Data/KeyMapping.hpp"
|
||||||
|
#include "../../Toolkit/AffineTransform.hpp"
|
||||||
#include "Ribbon.hpp"
|
#include "Ribbon.hpp"
|
||||||
#include "Resources.hpp"
|
#include "Resources.hpp"
|
||||||
|
#include "ButtonHighlight.hpp"
|
||||||
|
|
||||||
namespace MusicSelect {
|
namespace MusicSelect {
|
||||||
|
|
||||||
@ -22,6 +24,7 @@ namespace MusicSelect {
|
|||||||
private:
|
private:
|
||||||
// Data
|
// Data
|
||||||
const Data::SongList& song_list;
|
const Data::SongList& song_list;
|
||||||
|
unsigned int panel_size = 150;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
Resources resources;
|
Resources resources;
|
||||||
@ -29,8 +32,14 @@ namespace MusicSelect {
|
|||||||
// State
|
// State
|
||||||
Ribbon ribbon;
|
Ribbon ribbon;
|
||||||
std::optional<std::reference_wrapper<SongPanel>> selected_panel;
|
std::optional<std::reference_wrapper<SongPanel>> selected_panel;
|
||||||
|
ButtonHighlight button_highlight;
|
||||||
|
|
||||||
KeyMapping key_mapping;
|
KeyMapping key_mapping;
|
||||||
void handle_key(const sf::Event::KeyEvent& key_event);
|
// converts a key press into a button press
|
||||||
|
void handle_key_press(const sf::Event::KeyEvent& key_event);
|
||||||
|
// converts a mouse click into a button press
|
||||||
|
void handle_mouse_click(const sf::Event::MouseButtonEvent& mouse_button_event);
|
||||||
|
// chooses what happens for each button
|
||||||
|
void press_button(const Button& button);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,14 @@
|
|||||||
|
|
||||||
#include "MusicSelect.hpp"
|
#include "MusicSelect.hpp"
|
||||||
|
|
||||||
|
void MusicSelect::ColorPanel::draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) {
|
||||||
|
sf::RectangleShape panel{{area.width*0.9f, area.height*0.9f}};
|
||||||
|
panel.setFillColor(this->color);
|
||||||
|
panel.setOrigin(panel.getSize().x / 2.f, panel.getSize().y / 2.f);
|
||||||
|
panel.setPosition(area.left+area.width/2.f, area.top+area.height/2.f);
|
||||||
|
target.draw(panel);
|
||||||
|
}
|
||||||
|
|
||||||
void MusicSelect::CategoryPanel::click(Screen& screen) {
|
void MusicSelect::CategoryPanel::click(Screen& screen) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace MusicSelect {
|
|||||||
class Screen;
|
class Screen;
|
||||||
|
|
||||||
// A Panel holds anything that can go under a button on the moving part
|
// A Panel holds anything that can go under a button on the moving part
|
||||||
// of the music select screen, be it nothing, a sort indicator, or a song
|
// of the music select screen, be it nothing, a category indicator, or a song
|
||||||
class Panel {
|
class Panel {
|
||||||
public:
|
public:
|
||||||
// What happens when you click on the panel
|
// What happens when you click on the panel
|
||||||
@ -27,6 +27,15 @@ namespace MusicSelect {
|
|||||||
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override {return;};
|
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override {return;};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ColorPanel final : public Panel {
|
||||||
|
public:
|
||||||
|
explicit ColorPanel(const sf::Color& t_color) : color(t_color) {};
|
||||||
|
void click(Screen& screen) override {return;};
|
||||||
|
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override;
|
||||||
|
private:
|
||||||
|
const sf::Color color;
|
||||||
|
};
|
||||||
|
|
||||||
class CategoryPanel final : public Panel {
|
class CategoryPanel final : public Panel {
|
||||||
public:
|
public:
|
||||||
explicit CategoryPanel(const std::string& t_label) : label(t_label) {};
|
explicit CategoryPanel(const std::string& t_label) : label(t_label) {};
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#include "Ribbon.hpp"
|
#include "Ribbon.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Panel.hpp"
|
#include "Panel.hpp"
|
||||||
|
#include "../../Toolkit/QuickRNG.hpp"
|
||||||
|
|
||||||
MusicSelect::Ribbon MusicSelect::Ribbon::title_sort(const Data::SongList& song_list) {
|
MusicSelect::Ribbon MusicSelect::Ribbon::title_sort(const Data::SongList& song_list) {
|
||||||
std::map<char,std::vector<Data::Song>> categories;
|
std::map<char,std::vector<Data::Song>> categories;
|
||||||
@ -23,18 +25,18 @@ MusicSelect::Ribbon MusicSelect::Ribbon::title_sort(const Data::SongList& song_l
|
|||||||
}
|
}
|
||||||
Ribbon ribbon;
|
Ribbon ribbon;
|
||||||
for (auto& [letter, songs] : categories) {
|
for (auto& [letter, songs] : categories) {
|
||||||
std::vector<std::unique_ptr<Panel>> panels;
|
std::vector<std::shared_ptr<Panel>> panels;
|
||||||
panels.emplace_back(
|
panels.emplace_back(
|
||||||
std::make_unique<CategoryPanel>(
|
std::make_shared<CategoryPanel>(
|
||||||
std::string(1, letter)
|
std::string(1, letter)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
std::sort(songs.begin(), songs.end(), Data::Song::sort_by_title);
|
std::sort(songs.begin(), songs.end(), Data::Song::sort_by_title);
|
||||||
for (const auto& song : songs) {
|
for (const auto& song : songs) {
|
||||||
panels.push_back(std::make_unique<SongPanel>(song));
|
panels.push_back(std::make_shared<SongPanel>(song));
|
||||||
}
|
}
|
||||||
while (panels.size() % 3 != 0) {
|
while (panels.size() % 3 != 0) {
|
||||||
panels.push_back(std::make_unique<EmptyPanel>());
|
panels.push_back(std::make_shared<EmptyPanel>());
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < panels.size(); i += 3) {
|
for (size_t i = 0; i < panels.size(); i += 3) {
|
||||||
ribbon.layout.emplace_back();
|
ribbon.layout.emplace_back();
|
||||||
@ -50,27 +52,86 @@ MusicSelect::Ribbon MusicSelect::Ribbon::test_sort() {
|
|||||||
Ribbon ribbon;
|
Ribbon ribbon;
|
||||||
ribbon.layout.push_back(
|
ribbon.layout.push_back(
|
||||||
{
|
{
|
||||||
std::make_unique<EmptyPanel>(),
|
std::make_shared<EmptyPanel>(),
|
||||||
std::make_unique<CategoryPanel>("A"),
|
std::make_shared<CategoryPanel>("A"),
|
||||||
std::make_unique<CategoryPanel>("truc")
|
std::make_shared<CategoryPanel>("truc")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
ribbon.layout.push_back(
|
ribbon.layout.push_back(
|
||||||
{
|
{
|
||||||
std::make_unique<EmptyPanel>(),
|
std::make_shared<EmptyPanel>(),
|
||||||
std::make_unique<EmptyPanel>(),
|
std::make_shared<EmptyPanel>(),
|
||||||
std::make_unique<EmptyPanel>()
|
std::make_shared<EmptyPanel>()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ribbon;
|
return ribbon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unique_ptr<MusicSelect::Panel>& MusicSelect::Ribbon::at(unsigned int button_index) const {
|
MusicSelect::Ribbon MusicSelect::Ribbon::test2_sort() {
|
||||||
|
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
std::map<std::string, std::list<std::shared_ptr<Panel>>> categories;
|
||||||
|
Toolkit::UniformIntRNG category_size_generator{1,10};
|
||||||
|
Toolkit::UniformIntRNG panel_hue_generator{0,255};
|
||||||
|
for (auto &&letter : alphabet) {
|
||||||
|
auto category_size = category_size_generator.generate();
|
||||||
|
for (int i = 0; i < category_size; i++) {
|
||||||
|
categories[std::string(1, letter)].push_back(
|
||||||
|
std::make_shared<MusicSelect::ColorPanel>(
|
||||||
|
sf::Color(
|
||||||
|
panel_hue_generator.generate(),
|
||||||
|
panel_hue_generator.generate(),
|
||||||
|
panel_hue_generator.generate()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ribbon::layout_from_map(categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<MusicSelect::Panel>& MusicSelect::Ribbon::at(unsigned int 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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MusicSelect::Ribbon MusicSelect::Ribbon::layout_from_map(const std::map<std::string, std::list<std::shared_ptr<MusicSelect::Panel>>>& categories) {
|
||||||
|
Ribbon ribbon;
|
||||||
|
for (auto &&[category, panels] : categories) {
|
||||||
|
if (not panels.empty()) {
|
||||||
|
std::vector<std::shared_ptr<Panel>> current_column;
|
||||||
|
current_column.push_back(std::make_shared<CategoryPanel>(category));
|
||||||
|
for (auto &&panel : panels) {
|
||||||
|
if (current_column.size() == 3) {
|
||||||
|
ribbon.layout.push_back({current_column[0], current_column[1], current_column[2]});
|
||||||
|
current_column.clear();
|
||||||
|
} else {
|
||||||
|
current_column.push_back(std::move(panel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (not current_column.empty()) {
|
||||||
|
while (current_column.size() < 3) {
|
||||||
|
current_column.push_back(std::make_shared<EmptyPanel>());
|
||||||
|
}
|
||||||
|
ribbon.layout.push_back({current_column[0], current_column[1], current_column[2]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ribbon;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSelect::Ribbon::move_right() {
|
||||||
|
position = (position + 1) % layout.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSelect::Ribbon::move_left() {
|
||||||
|
if (position == 0) {
|
||||||
|
position = layout.size() - 1;
|
||||||
|
} else {
|
||||||
|
position--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,10 +11,14 @@ namespace MusicSelect {
|
|||||||
Ribbon() = default;
|
Ribbon() = default;
|
||||||
static Ribbon title_sort(const Data::SongList& song_list);
|
static Ribbon title_sort(const Data::SongList& song_list);
|
||||||
static Ribbon test_sort();
|
static Ribbon test_sort();
|
||||||
|
static Ribbon test2_sort();
|
||||||
const auto& get_layout() {return layout;};
|
const auto& get_layout() {return layout;};
|
||||||
const std::unique_ptr<MusicSelect::Panel>& at(unsigned int button_index) const;
|
const std::shared_ptr<MusicSelect::Panel>& at(unsigned int button_index) const;
|
||||||
|
void move_right();
|
||||||
|
void move_left();
|
||||||
private:
|
private:
|
||||||
std::vector<std::array<std::unique_ptr<Panel>,3>> layout;
|
static Ribbon layout_from_map(const std::map<std::string,std::list<std::shared_ptr<Panel>>>& categories);
|
||||||
|
std::vector<std::array<std::shared_ptr<Panel>,3>> layout;
|
||||||
unsigned int position = 0;
|
unsigned int position = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
40
src/Toolkit/AffineTransform.hpp
Normal file
40
src/Toolkit/AffineTransform.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Toolkit {
|
||||||
|
template<typename T>
|
||||||
|
class AffineTransform {
|
||||||
|
public:
|
||||||
|
AffineTransform(T low_input, T high_input, T low_output, T high_output):
|
||||||
|
m_low_input(low_input),
|
||||||
|
m_high_input(high_input),
|
||||||
|
m_low_output(low_output),
|
||||||
|
m_high_output(high_output)
|
||||||
|
{
|
||||||
|
if (low_input == high_input) {
|
||||||
|
throw std::invalid_argument("low and high input values for affine transform must be different !");
|
||||||
|
}
|
||||||
|
m_a = (high_output-low_output)/(high_input-low_input);
|
||||||
|
m_b = (high_input*low_output - high_output*low_input)/(high_input-low_input);
|
||||||
|
};
|
||||||
|
T transform(T val) const {return m_a*val + m_b;};
|
||||||
|
T clampedTransform(T val) const { return transform(std::clamp(val,m_low_input,m_high_input));};
|
||||||
|
T backwards_transform(T val) const {
|
||||||
|
// if we're too close to zero
|
||||||
|
if (std::abs(m_a) < 10e-10) {
|
||||||
|
throw std::runtime_error("Can't apply backwards transformation, coefficient is too close to zero");
|
||||||
|
} else {
|
||||||
|
return (val-m_b)/m_a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void setB(T b) {
|
||||||
|
m_b = b;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
T m_a;
|
||||||
|
T m_b;
|
||||||
|
T m_low_input;
|
||||||
|
T m_high_input;
|
||||||
|
T m_low_output;
|
||||||
|
T m_high_output;
|
||||||
|
};
|
||||||
|
}
|
11
src/Toolkit/QuickRNG.cpp
Normal file
11
src/Toolkit/QuickRNG.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "QuickRNG.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
Toolkit::UniformIntRNG::UniformIntRNG(int min, int max) : m_distribution(min, max) {
|
||||||
|
std::random_device rd;
|
||||||
|
m_generator = std::mt19937{rd()};
|
||||||
|
}
|
||||||
|
|
||||||
|
int Toolkit::UniformIntRNG::generate() {
|
||||||
|
return m_distribution(m_generator);
|
||||||
|
}
|
14
src/Toolkit/QuickRNG.hpp
Normal file
14
src/Toolkit/QuickRNG.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace Toolkit {
|
||||||
|
class UniformIntRNG {
|
||||||
|
public:
|
||||||
|
UniformIntRNG(int min, int max);
|
||||||
|
int generate();
|
||||||
|
private:
|
||||||
|
std::mt19937 m_generator;
|
||||||
|
std::uniform_int_distribution<> m_distribution;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user