diff --git a/src/colors.hpp b/src/colors.hpp index e264788..2a8d4d8 100644 --- a/src/colors.hpp +++ b/src/colors.hpp @@ -15,34 +15,37 @@ struct RectangleColors { sf::Color border; }; -struct LinearViewColors { - sf::Color cursor = {66, 150, 250, 170}; - RectangleColors tab_selection = { - .fill = {153, 255, 153, 92}, - .border = {153, 255, 153, 189} - }; - sf::Color normal_tap_note = {255, 213, 0}; - sf::Color conflicting_tap_note = {255, 167, 0}; - sf::Color normal_collision_zone = {230, 179, 0, 80}; - sf::Color conflicting_collision_zone = {255, 0, 0, 145}; - sf::Color normal_long_note = {255, 90, 0, 223}; - sf::Color conflicting_long_note = {255, 26, 0}; - sf::Color selected_note_fill = {255, 255, 255, 127}; - sf::Color selected_note_outline = sf::Color::White; - sf::Color measure_line = sf::Color::White; - sf::Color measure_number = sf::Color::White; - sf::Color beat_line = {255, 255, 255, 127}; - ButtonColors bpm_button = { - .text = {66, 150, 250}, - .button = sf::Color::Transparent, - .hover = {66, 150, 250, 64}, - .active = {66, 150, 250, 127}, - .border = {109, 179, 251} - }; - RectangleColors selection_rect = { - .fill = {144, 189, 255, 64}, - .border = {144, 189, 255} +namespace linear_view { + struct Colors { + sf::Color cursor = {66, 150, 250, 170}; + RectangleColors tab_selection = { + .fill = {153, 255, 153, 92}, + .border = {153, 255, 153, 189} + }; + sf::Color normal_tap_note = {255, 213, 0}; + sf::Color conflicting_tap_note = {255, 167, 0}; + sf::Color normal_collision_zone = {230, 179, 0, 80}; + sf::Color conflicting_collision_zone = {255, 0, 0, 145}; + sf::Color normal_long_note = {255, 90, 0, 223}; + sf::Color conflicting_long_note = {255, 26, 0}; + sf::Color selected_note_fill = {255, 255, 255, 127}; + sf::Color selected_note_outline = sf::Color::White; + sf::Color measure_line = sf::Color::White; + sf::Color measure_number = sf::Color::White; + sf::Color beat_line = {255, 255, 255, 127}; + ButtonColors bpm_button = { + .text = {66, 150, 250}, + .button = sf::Color::Transparent, + .hover = {66, 150, 250, 64}, + .active = {66, 150, 250, 127}, + .border = {109, 179, 251} + }; + RectangleColors selection_rect = { + .fill = {144, 189, 255, 64}, + .border = {144, 189, 255} + }; }; + + const linear_view::Colors default_colors = {}; }; -inline const LinearViewColors default_linear_view_colors = {}; \ No newline at end of file diff --git a/src/config.cpp b/src/config.cpp index c1e9592..72741eb 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -4,9 +4,12 @@ #include #include #include +#include #include "colors.hpp" #include "marker.hpp" +#include "variant_visitor.hpp" +#include "widgets/lane_order.hpp" toml::array config::dump_color(const sf::Color& color) { return toml::array{color.r, color.g, color.b, color.a}; @@ -85,8 +88,8 @@ void config::Marker::dump_as_v1_0_0(toml::table &tbl) { tbl.insert_or_assign("marker", marker_table); } -LinearViewColors config::load_linear_view_colors_from_v1_0_0_table(const toml::table& linear_view) { - auto colors = default_linear_view_colors; +linear_view::Colors config::load_linear_view_colors_from_v1_0_0_table(const toml::table& linear_view) { + auto colors = linear_view::default_colors; const auto colors_node = linear_view["colors"]; load_color(colors_node["cursor"], colors.cursor); load_color(colors_node["tab_selection"]["fill"], colors.tab_selection.fill); @@ -112,7 +115,7 @@ LinearViewColors config::load_linear_view_colors_from_v1_0_0_table(const toml::t return colors; } -void config::dump_linear_view_colors_as_v1_0_0(const LinearViewColors& colors, toml::table& linear_view) { +void config::dump_linear_view_colors_as_v1_0_0(const linear_view::Colors& colors, toml::table& linear_view) { toml::table colors_table{ {"cursor", dump_color(colors.cursor)}, {"tab_selection", toml::table{ @@ -145,15 +148,89 @@ void config::dump_linear_view_colors_as_v1_0_0(const LinearViewColors& colors, t linear_view.insert_or_assign("colors", colors_table); } -void config::LinearView::load_from_v1_0_0_table(const toml::table& tbl) { - if (tbl["linear_view"].is_table()) { - colors = load_linear_view_colors_from_v1_0_0_table(tbl["linear_view"].ref()); +linear_view::Sizes config::load_linear_view_sizes_from_v1_0_0_table(const toml::table& linear_view) { + auto sizes = linear_view::default_sizes; + const auto sizes_node = linear_view["sizes"]; + sizes.timeline_margin = sizes_node["timeline_margin"].value().value_or(sizes.timeline_margin); + sizes.cursor_height = sizes_node["cursor_height"].value().value_or(sizes.cursor_height); + return sizes; +} + +void config::dump_linear_view_sizes_as_v1_0_0(const linear_view::Sizes& sizes, toml::table& linear_view) { + toml::table sizes_table{ + {"timeline_margin", sizes.timeline_margin}, + {"cursor_height", sizes.cursor_height}, + }; + linear_view.insert_or_assign("sizes", sizes_table); +} + +linear_view::LaneOrder config::load_linear_view_lane_order_from_v1_0_0_table(const toml::table& linear_view) { + auto lane_order = linear_view::default_lane_order; + const auto lane_order_node = linear_view["lane_order"]; + const auto type = lane_order_node["type"].value(); + if (not type) { + return lane_order; } + + if (*type == "default") { + return linear_view::lane_order::Default{}; + } else if (*type == "vertical") { + return linear_view::lane_order::Vertical{}; + } else if (*type == "custom") { + const auto order_as_string = lane_order_node["order"].value(); + if (order_as_string) { + return linear_view::lane_order::Custom{*order_as_string}; + } + } + + return lane_order; + + +} + +void config::dump_linear_view_lane_order_as_v1_0_0(const linear_view::LaneOrder& lane_order, toml::table& linear_view) { + const auto _dump = VariantVisitor { + [&](const linear_view::lane_order::Default&) { + linear_view.insert_or_assign( + "lane_order", + toml::table{{"type", "default"}} + ); + }, + [&](const linear_view::lane_order::Vertical&) { + linear_view.insert_or_assign( + "lane_order", + toml::table{{"type", "vertical"}} + ); + }, + [&](const linear_view::lane_order::Custom& custom) { + linear_view.insert_or_assign( + "lane_order", + toml::table{ + {"type", "custom"}, + {"order", custom.as_string} + } + ); + } + }; + std::visit(_dump, lane_order); +} + +void config::LinearView::load_from_v1_0_0_table(const toml::table& tbl) { + if (not tbl["linear_view"].is_table()) { + return; + } + + const auto linear_view_table = tbl["linear_view"].ref(); + colors = load_linear_view_colors_from_v1_0_0_table(linear_view_table); + sizes = load_linear_view_sizes_from_v1_0_0_table(linear_view_table); + lane_order = load_linear_view_lane_order_from_v1_0_0_table(linear_view_table); } void config::LinearView::dump_as_v1_0_0(toml::table& tbl) { toml::table linear_view; dump_linear_view_colors_as_v1_0_0(colors, linear_view); + dump_linear_view_sizes_as_v1_0_0(sizes, linear_view); + dump_linear_view_lane_order_as_v1_0_0(lane_order, linear_view); tbl.insert_or_assign("linear_view", linear_view); } diff --git a/src/config.hpp b/src/config.hpp index c0f5a7a..a33ee00 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -5,7 +5,9 @@ #include #include "colors.hpp" +#include "sizes.hpp" #include "marker.hpp" +#include "widgets/lane_order.hpp" namespace config { @@ -23,11 +25,19 @@ namespace config { void dump_as_v1_0_0(toml::table& tbl); }; - LinearViewColors load_linear_view_colors_from_v1_0_0_table(const toml::table& linear_view); - void dump_linear_view_colors_as_v1_0_0(const LinearViewColors& colors, toml::table& linear_view); + linear_view::Colors load_linear_view_colors_from_v1_0_0_table(const toml::table& linear_view); + void dump_linear_view_colors_as_v1_0_0(const linear_view::Colors& colors, toml::table& linear_view); + + linear_view::Sizes load_linear_view_sizes_from_v1_0_0_table(const toml::table& linear_view); + void dump_linear_view_sizes_as_v1_0_0(const linear_view::Sizes& sizes, toml::table& linear_view); + + linear_view::LaneOrder load_linear_view_lane_order_from_v1_0_0_table(const toml::table& linear_view); + void dump_linear_view_lane_order_as_v1_0_0(const linear_view::LaneOrder& lane_order, toml::table& linear_view); struct LinearView { - LinearViewColors colors; + linear_view::Colors colors; + linear_view::Sizes sizes; + linear_view::LaneOrder lane_order; void load_from_v1_0_0_table(const toml::table& tbl); void dump_as_v1_0_0(toml::table& tbl); diff --git a/src/sizes.hpp b/src/sizes.hpp new file mode 100644 index 0000000..631c957 --- /dev/null +++ b/src/sizes.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace linear_view { + struct Sizes { + int timeline_margin = 130; + int cursor_height = 100; + }; + + const Sizes default_sizes = {}; +} \ No newline at end of file diff --git a/src/widgets/lane_order.cpp b/src/widgets/lane_order.cpp new file mode 100644 index 0000000..ad6843f --- /dev/null +++ b/src/widgets/lane_order.cpp @@ -0,0 +1,61 @@ +#include "lane_order.hpp" + +#include + + +linear_view::lane_order::Custom::Custom() : + lane_to_button({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}) +{ + update_from_array(); +} + +linear_view::lane_order::Custom::Custom(const std::string& as_string_) : + as_string(as_string_) +{ + cleanup_string(); + update_from_string(); +} + +void linear_view::lane_order::Custom::update_from_array() { + std::stringstream ss; + button_to_lane.clear(); + for (std::size_t lane = 0; lane < lane_to_button.size(); lane++) { + const auto button = lane_to_button.at(lane); + if (button) { + ss << letters.at(*button); + button_to_lane[*button] = lane; + } else { + ss << "_"; + } + } + as_string = ss.str(); +} + +void linear_view::lane_order::Custom::cleanup_string() { + as_string.resize(16); + for (auto& c : as_string) { + if (not letter_to_index.contains(c)) { + c = '_'; + } + } +} + +void linear_view::lane_order::Custom::update_from_string() { + lane_to_button = {{ + {}, {}, {}, {}, + {}, {}, {}, {}, + {}, {}, {}, {}, + {}, {}, {}, {} + }}; + button_to_lane.clear(); + const auto upper_bound = std::min(16UL, as_string.length()); + for (std::size_t lane = 0; lane < upper_bound; lane++) { + const auto letter = as_string.at(lane); + const auto pair = letter_to_index.find(letter); + if (pair != letter_to_index.end()) { + const auto button = pair->second; + lane_to_button[lane] = button; + button_to_lane[button] = lane; + } + } +} \ No newline at end of file diff --git a/src/widgets/lane_order.hpp b/src/widgets/lane_order.hpp new file mode 100644 index 0000000..0b28fb6 --- /dev/null +++ b/src/widgets/lane_order.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace linear_view { + namespace lane_order { + struct Default {}; + struct Vertical {}; + struct Custom { + Custom(); + explicit Custom(const std::string& as_string); + std::array, 16> lane_to_button; + std::map button_to_lane; + std::string as_string; + void cleanup_string(); + void update_from_string(); + void update_from_array(); + }; + + const std::array letters = { + "1","2","3","4", + "5","6","7","8", + "9","a","b","c", + "d","e","f","g" + }; + + const std::map letter_to_index = { + {'1', 0}, {'2', 1}, {'3', 2}, {'4', 3}, + {'5', 4}, {'6', 5}, {'7', 6}, {'8', 7}, + {'9', 8}, {'a', 9}, {'b', 10}, {'c', 11}, + {'d', 12}, {'e', 13}, {'f', 14}, {'g', 15}, + }; + } + + using LaneOrder = std::variant; + + const LaneOrder default_lane_order = lane_order::Default{}; +} \ No newline at end of file diff --git a/src/widgets/linear_view.cpp b/src/widgets/linear_view.cpp index c1ba4be..63f3cbf 100644 --- a/src/widgets/linear_view.cpp +++ b/src/widgets/linear_view.cpp @@ -29,6 +29,8 @@ #include "../special_numeric_types.hpp" #include "../toolbox.hpp" #include "../variant_visitor.hpp" +#include "sizes.hpp" +#include "widgets/lane_order.hpp" const std::string font_file = "fonts/NotoSans-Medium.ttf"; @@ -40,8 +42,9 @@ void SelectionRectangle::reset() { LinearView::LinearView(std::filesystem::path assets, config::LinearView& config_) : colors(config_.colors), + sizes(config_.sizes), beats_to_pixels_proportional(0, 1, 0, 100), - lane_order(LaneOrderPresets::Default{}) + lane_order(config_.lane_order) {} void LinearView::draw( @@ -57,12 +60,12 @@ void LinearView::draw( int x = std::max(300, static_cast(size.x)); int y = std::max(300, static_cast(size.y)); - const float timeline_width = static_cast(x) - static_cast(timeline_margin); - const float timeline_left = static_cast(timeline_margin) / 2; + const float timeline_width = static_cast(x) - static_cast(sizes.timeline_margin); + const float timeline_left = static_cast(sizes.timeline_margin) / 2; const float timeline_right = timeline_left + timeline_width; // Just in case, clamp the beat cursor inside the window, with some margin - const float cursor_y = std::clamp(static_cast(cursor_height), 25.f, static_cast(y) - 25.f); + const float cursor_y = std::clamp(static_cast(sizes.cursor_height), 25.f, static_cast(y) - 25.f); // Here we compute the range of visible beats from the size of the window // in pixels, we know by definition that the current beat is exactly at @@ -386,41 +389,34 @@ void LinearView::set_zoom(int newZoom) { reload_transforms(); } -const std::array letters = { - "1","2","3","4", - "5","6","7","8", - "9","a","b","c", - "d","e","f","g" -}; - void LinearView::display_settings() { if (ImGui::Begin("Linear View Settings", &shouldDisplaySettings)) { if (ImGui::CollapsingHeader("Lanes##Linear View Settings")) { if (ImGui::BeginCombo("Order", lane_order_name().c_str())) { if (ImGui::Selectable( "Default", - std::holds_alternative(lane_order) + std::holds_alternative(lane_order) )) { - lane_order = LaneOrderPresets::Default{}; + lane_order = linear_view::lane_order::Default{}; } if (ImGui::Selectable( "Vertical", - std::holds_alternative(lane_order) + std::holds_alternative(lane_order) )) { - lane_order = LaneOrderPresets::Vertical{}; + lane_order = linear_view::lane_order::Vertical{}; } if (ImGui::Selectable( "Custom", - std::holds_alternative(lane_order) + std::holds_alternative(lane_order) )) { - if (not std::holds_alternative(lane_order)) { - lane_order = CustomLaneOrder{}; + if (not std::holds_alternative(lane_order)) { + lane_order = linear_view::lane_order::Custom{}; } } ImGui::EndCombo(); } - if (std::holds_alternative(lane_order)) { - auto& order = std::get(lane_order); + if (std::holds_alternative(lane_order)) { + auto& order = std::get(lane_order); if (ImGui::InputText("Custom", &order.as_string)) { order.cleanup_string(); order.update_from_string(); @@ -431,7 +427,7 @@ void LinearView::display_settings() { } if (ImGui::CollapsingHeader("Colors##Linear View Settings")) { if (ImGui::Button("Reset##Colors##Linear View Settings")) { - colors = default_linear_view_colors; + colors = linear_view::default_colors; } feis::ColorEdit4("Cursor", colors.cursor); feis::ColorEdit4("Measure Lines", colors.measure_line); @@ -468,8 +464,11 @@ void LinearView::display_settings() { } } if (ImGui::CollapsingHeader("Metrics##Linear View Settings")) { - ImGui::DragInt("Cursor Height", &cursor_height); - ImGui::DragInt("Timeline Margin", &timeline_margin); + if (ImGui::Button("Reset##Metrics##Linear View Settings")) { + sizes = linear_view::default_sizes; + } + ImGui::DragInt("Cursor Height", &sizes.cursor_height); + ImGui::DragInt("Timeline Margin", &sizes.timeline_margin); } } ImGui::End(); @@ -486,22 +485,22 @@ void LinearView::reload_transforms() { std::string LinearView::lane_order_name() { const auto name = VariantVisitor { - [](LaneOrderPresets::Default) { return "Default"; }, - [](LaneOrderPresets::Vertical) { return "Vertical"; }, - [](CustomLaneOrder) { return "Custom"; }, + [](linear_view::lane_order::Default) { return "Default"; }, + [](linear_view::lane_order::Vertical) { return "Vertical"; }, + [](linear_view::lane_order::Custom) { return "Custom"; }, }; return std::visit(name, lane_order); } std::optional LinearView::button_to_lane(const better::Position& button) { const auto _button_to_lane = VariantVisitor { - [button](const LaneOrderPresets::Default&){ + [button](const linear_view::lane_order::Default&){ return static_cast>(button.index()); }, - [button](const LaneOrderPresets::Vertical&){ + [button](const linear_view::lane_order::Vertical&){ return static_cast>(button.get_y() + 4 * button.get_x()); }, - [button](const CustomLaneOrder& c){ + [button](const linear_view::lane_order::Custom& c){ const auto pair = c.button_to_lane.find(button.index()); if (pair != c.button_to_lane.end()) { return static_cast>(pair->second); @@ -634,7 +633,7 @@ void LaneOrderPreview(const std::array, 16>& order) for (auto x = 0; x < 4; x++) { const auto index = x + 4*y; ImGui::SetCursorPos(origin + sf::Vector2f{static_cast(x), static_cast(y)} * scale); - ImGui::TextColored(rainbow.at(index), "%s", letters.at(index).c_str()); + ImGui::TextColored(rainbow.at(index), "%s", linear_view::lane_order::letters.at(index).c_str()); if (x != 3) { ImGui::SameLine(); } @@ -651,68 +650,11 @@ void LaneOrderPreview(const std::array, 16>& order) const auto optional_button = order.at(lane); if (optional_button) { const auto button = *optional_button % 16; - ImGui::TextColored(rainbow.at(button), "%s", letters.at(button).c_str()); + ImGui::TextColored(rainbow.at(button), "%s", linear_view::lane_order::letters.at(button).c_str()); } else { ImGui::TextDisabled("_"); } } ImGui::SetCursorPos(origin); ImGui::Dummy(sf::Vector2f{23, 4}*scale); -} - -LinearView::CustomLaneOrder::CustomLaneOrder() : - lane_to_button({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}) -{ - update_from_array(); -} - -void LinearView::CustomLaneOrder::update_from_array() { - std::stringstream ss; - button_to_lane.clear(); - for (std::size_t lane = 0; lane < lane_to_button.size(); lane++) { - const auto button = lane_to_button.at(lane); - if (button) { - ss << letters.at(*button); - button_to_lane[*button] = lane; - } else { - ss << "_"; - } - } - as_string = ss.str(); -} - -const std::map letter_to_index = { - {'1', 0}, {'2', 1}, {'3', 2}, {'4', 3}, - {'5', 4}, {'6', 5}, {'7', 6}, {'8', 7}, - {'9', 8}, {'a', 9}, {'b', 10}, {'c', 11}, - {'d', 12}, {'e', 13}, {'f', 14}, {'g', 15}, -}; - -void LinearView::CustomLaneOrder::cleanup_string() { - as_string.resize(16); - for (auto& c : as_string) { - if (not letter_to_index.contains(c)) { - c = '_'; - } - } -} - -void LinearView::CustomLaneOrder::update_from_string() { - lane_to_button = {{ - {}, {}, {}, {}, - {}, {}, {}, {}, - {}, {}, {}, {}, - {}, {}, {}, {} - }}; - button_to_lane.clear(); - const auto upper_bound = std::min(16UL, as_string.length()); - for (std::size_t lane = 0; lane < upper_bound; lane++) { - const auto letter = as_string.at(lane); - const auto pair = letter_to_index.find(letter); - if (pair != letter_to_index.end()) { - const auto button = pair->second; - lane_to_button[lane] = button; - button_to_lane[button] = lane; - } - } } \ No newline at end of file diff --git a/src/widgets/linear_view.hpp b/src/widgets/linear_view.hpp index b3da2d5..426fc6e 100644 --- a/src/widgets/linear_view.hpp +++ b/src/widgets/linear_view.hpp @@ -1,16 +1,20 @@ #pragma once +#include + +#include #include #include #include #include -#include #include "../better_timing.hpp" #include "../chart_state.hpp" #include "../toolbox.hpp" -#include "config.hpp" -#include "imgui.h" +#include "../colors.hpp" +#include "../config.hpp" +#include "../sizes.hpp" +#include "lane_order.hpp" struct SelectionRectangle { sf::Vector2f start = {-1, -1}; @@ -43,11 +47,12 @@ public: void display_settings(); -private: - LinearViewColors& colors; - int timeline_margin = 130; - int cursor_height = 100; + +private: + linear_view::Colors& colors; + linear_view::Sizes& sizes; + AffineTransform beats_to_pixels_proportional; void reload_transforms(); @@ -58,22 +63,7 @@ private: bool started_selection_inside_window = false; bool any_bpm_button_hovered = false; - struct LaneOrderPresets { - struct Default {}; - struct Vertical {}; - }; - - struct CustomLaneOrder { - CustomLaneOrder(); - std::array, 16> lane_to_button; - std::map button_to_lane; - std::string as_string; - void cleanup_string(); - void update_from_string(); - void update_from_array(); - }; - - std::variant lane_order; + linear_view::LaneOrder& lane_order; std::string lane_order_name(); std::optional button_to_lane(const better::Position& button); }; diff --git a/src/widgets/meson.build b/src/widgets/meson.build index 617d4c5..4e2545a 100644 --- a/src/widgets/meson.build +++ b/src/widgets/meson.build @@ -1,5 +1,6 @@ sources += files([ 'blank_screen.cpp', 'density_graph.cpp', + 'lane_order.cpp', 'linear_view.cpp' ]) \ No newline at end of file