@@ -6,6 +6,7 @@
|
||||
#include <modulus/types.hpp>
|
||||
#include <vamp_style.hpp>
|
||||
|
||||
|
||||
namespace vamp_pico {
|
||||
|
||||
constexpr auto display_width = std::int32_t{320};
|
||||
@@ -20,9 +21,9 @@ public:
|
||||
auto init() -> void;
|
||||
auto fill(std::uint16_t color) -> void;
|
||||
auto fill_rect(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height, std::uint16_t color) -> void;
|
||||
auto draw_text(std::int32_t x, std::int32_t y, std::char_t const* text, std::uint16_t color, std::int32_t scale = 2) -> void;
|
||||
auto show_boot(std::char_t const* line1, std::char_t const* line2, std::uint16_t accent) -> void;
|
||||
auto show_remote(vamp_style::color status, std::char_t const* title, std::char_t const* part, std::uint32_t page, std::uint32_t pages, std::bool_t active) -> void;
|
||||
auto draw_text(std::int32_t x, std::int32_t y, std::char_t const *text, std::uint16_t color, std::int32_t scale = 2) -> void;
|
||||
auto show_boot(std::char_t const *line1, std::char_t const *line2, std::uint16_t accent) -> void;
|
||||
auto show_remote(vamp_style::color status, std::char_t const *title, std::char_t const *part, std::uint32_t page, std::uint32_t pages, std::bool_t active) -> void;
|
||||
private:
|
||||
std::bool_t remote_valid_{};
|
||||
vamp_style::color last_status_{};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_pico {
|
||||
|
||||
struct remote_display_state {
|
||||
@@ -17,9 +18,9 @@ struct remote_display_state {
|
||||
std::uint32_t pages{};
|
||||
};
|
||||
|
||||
auto parse_remote_display_body(std::string_view body, vamp_pico::remote_display_state& state) -> std::bool_t;
|
||||
auto post_remote_command(vamp_protocol::page_command command, vamp_pico::remote_display_state& state) -> std::bool_t;
|
||||
auto parse_remote_display_body(std::string_view body, vamp_pico::remote_display_state &state) -> std::bool_t;
|
||||
auto post_remote_command(vamp_protocol::page_command command, vamp_pico::remote_display_state &state) -> std::bool_t;
|
||||
auto heartbeat() -> std::bool_t;
|
||||
auto fetch_remote_display(vamp_pico::remote_display_state& state) -> std::bool_t;
|
||||
auto fetch_remote_display(vamp_pico::remote_display_state &state) -> std::bool_t;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_pico {
|
||||
|
||||
struct touch_point {
|
||||
@@ -13,7 +14,7 @@ struct touch_point {
|
||||
|
||||
struct touch_controller {
|
||||
auto init() -> void;
|
||||
auto read(touch_point& point) -> std::bool_t;
|
||||
auto read(touch_point &point) -> std::bool_t;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_protocol {
|
||||
|
||||
constexpr std::char_t root_path[] = "/";
|
||||
@@ -20,9 +21,9 @@ enum class page_command {
|
||||
SELECT,
|
||||
};
|
||||
|
||||
auto page_command_path(vamp_protocol::page_command command) -> std::char_t const*;
|
||||
auto page_command_legacy_path(vamp_protocol::page_command command) -> std::char_t const*;
|
||||
auto page_command_name(vamp_protocol::page_command command) -> std::char_t const*;
|
||||
auto page_command_display_label(vamp_protocol::page_command command) -> std::char_t const*;
|
||||
auto page_command_path(vamp_protocol::page_command command) -> std::char_t const *;
|
||||
auto page_command_legacy_path(vamp_protocol::page_command command) -> std::char_t const *;
|
||||
auto page_command_name(vamp_protocol::page_command command) -> std::char_t const *;
|
||||
auto page_command_display_label(vamp_protocol::page_command command) -> std::char_t const *;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_style {
|
||||
|
||||
struct color {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_style {
|
||||
|
||||
constexpr auto ui_font_path = std::string_view{"/usr/share/product-vamp/fonts/petaluma/PetalumaScript.otf"};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct command_line {
|
||||
@@ -19,7 +20,7 @@ struct command_line {
|
||||
std::bool_t ensure_database{};
|
||||
};
|
||||
|
||||
auto parse_command_line(std::int32_t argc, std::char_t** argv) -> std::expected<vamp_zero::command_line, modulus::error>;
|
||||
auto parse_command_line(std::int32_t argc, std::char_t **argv) -> std::expected<vamp_zero::command_line, modulus::error>;
|
||||
auto run(vamp_zero::command_line command) -> std::expected<void, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,20 +11,18 @@
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
class audio_controller {
|
||||
public:
|
||||
audio_controller(vamp_zero::audio_config config, sonus::engine engine);
|
||||
audio_controller(vamp_zero::audio_controller const&) = delete;
|
||||
auto operator=(vamp_zero::audio_controller const&) -> vamp_zero::audio_controller& = delete;
|
||||
audio_controller(vamp_zero::audio_controller const &) = delete;
|
||||
auto operator=(vamp_zero::audio_controller const &) -> vamp_zero::audio_controller & = delete;
|
||||
~audio_controller();
|
||||
|
||||
auto sync(vamp_zero::app_state const& state) -> void;
|
||||
|
||||
auto sync(vamp_zero::app_state const &state) -> void;
|
||||
private:
|
||||
auto make_metronome_config(vamp_zero::app_state const& state) const -> sonus::metronome_config;
|
||||
|
||||
auto make_metronome_config(vamp_zero::app_state const &state) const -> sonus::metronome_config;
|
||||
vamp_zero::audio_config config_{};
|
||||
sonus::engine engine_;
|
||||
mutable std::mutex mutex_{};
|
||||
@@ -32,6 +30,6 @@ private:
|
||||
std::uint32_t last_metronome_bpm_{};
|
||||
};
|
||||
|
||||
auto create_audio_controller(vamp_zero::audio_config const& config) -> std::expected<std::unique_ptr<vamp_zero::audio_controller>, modulus::error>;
|
||||
auto create_audio_controller(vamp_zero::audio_config const &config) -> std::expected<std::unique_ptr<vamp_zero::audio_controller>, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <vamp_style.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto to_luma(vamp_style::color value) -> luma::color;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <modulus/types.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct runtime_config {
|
||||
@@ -67,7 +68,7 @@ struct config {
|
||||
luma::application_config display{.title = "Product Vamp"};
|
||||
};
|
||||
|
||||
auto parse_config(boost::json::value const& value) -> std::expected<vamp_zero::config, modulus::error>;
|
||||
auto load_config(std::string const& path) -> std::expected<vamp_zero::config, modulus::error>;
|
||||
auto parse_config(boost::json::value const &value) -> std::expected<vamp_zero::config, modulus::error>;
|
||||
auto load_config(std::string const &path) -> std::expected<vamp_zero::config, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto async_ensure_database(boost::asio::any_io_executor executor, vamp_zero::database_config config) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
enum class error_code : std::int32_t {
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
namespace vamp_zero {
|
||||
|
||||
auto parse_score_document(std::string_view json, std::string source_path = {}) -> std::expected<vamp_zero::score_document, modulus::error>;
|
||||
auto load_performance_library(std::string const& assets_path) -> std::expected<vamp_zero::library_state, modulus::error>;
|
||||
auto load_practice_library(std::string const& assets_path) -> std::expected<vamp_zero::practice_library, modulus::error>;
|
||||
auto load_performance_library(std::string const &assets_path) -> std::expected<vamp_zero::library_state, modulus::error>;
|
||||
auto load_practice_library(std::string const &assets_path) -> std::expected<vamp_zero::practice_library, modulus::error>;
|
||||
auto group_library_parts(std::vector<vamp_zero::library_part> parts) -> vamp_zero::library_state;
|
||||
auto group_practice_exercises(std::vector<vamp_zero::practice_exercise> exercises) -> vamp_zero::practice_library;
|
||||
|
||||
|
||||
@@ -9,21 +9,22 @@
|
||||
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto selected_group(vamp_zero::app_state const& state) -> vamp_zero::song_group const*;
|
||||
auto selected_part(vamp_zero::app_state const& state) -> vamp_zero::library_part const*;
|
||||
auto active_part(vamp_zero::app_state const& state) -> vamp_zero::library_part const*;
|
||||
auto selected_practice_type(vamp_zero::app_state const& state) -> vamp_zero::practice_type_group const*;
|
||||
auto selected_practice_lesson(vamp_zero::app_state const& state) -> vamp_zero::practice_lesson_group const*;
|
||||
auto selected_practice_exercise(vamp_zero::app_state const& state) -> vamp_zero::practice_exercise const*;
|
||||
auto active_practice(vamp_zero::app_state const& state) -> vamp_zero::practice_exercise const*;
|
||||
auto supports_key_selection(vamp_zero::practice_exercise const& exercise) -> std::bool_t;
|
||||
auto selected_practice_variant(vamp_zero::app_state const& state, vamp_zero::practice_exercise const& exercise) -> vamp_zero::practice_exercise::score_variant const*;
|
||||
auto selected_practice_key(vamp_zero::app_state const& state, vamp_zero::practice_exercise const& exercise) -> std::optional<std::string_view>;
|
||||
auto practice_key_row_count(vamp_zero::app_state const& state) -> std::size_t;
|
||||
auto effective_practice_key(vamp_zero::app_state const& state, vamp_zero::practice_exercise const& exercise) -> std::string;
|
||||
auto active_pages(vamp_zero::app_state const& state) -> std::size_t;
|
||||
auto practice_fallback_menu(vamp_zero::app_state const& state) -> vamp_zero::app_mode;
|
||||
auto selected_group(vamp_zero::app_state const &state) -> vamp_zero::song_group const *;
|
||||
auto selected_part(vamp_zero::app_state const &state) -> vamp_zero::library_part const *;
|
||||
auto active_part(vamp_zero::app_state const &state) -> vamp_zero::library_part const *;
|
||||
auto selected_practice_type(vamp_zero::app_state const &state) -> vamp_zero::practice_type_group const *;
|
||||
auto selected_practice_lesson(vamp_zero::app_state const &state) -> vamp_zero::practice_lesson_group const *;
|
||||
auto selected_practice_exercise(vamp_zero::app_state const &state) -> vamp_zero::practice_exercise const *;
|
||||
auto active_practice(vamp_zero::app_state const &state) -> vamp_zero::practice_exercise const *;
|
||||
auto supports_key_selection(vamp_zero::practice_exercise const &exercise) -> std::bool_t;
|
||||
auto selected_practice_variant(vamp_zero::app_state const &state, vamp_zero::practice_exercise const &exercise) -> vamp_zero::practice_exercise::score_variant const *;
|
||||
auto selected_practice_key(vamp_zero::app_state const &state, vamp_zero::practice_exercise const &exercise) -> std::optional<std::string_view>;
|
||||
auto practice_key_row_count(vamp_zero::app_state const &state) -> std::size_t;
|
||||
auto effective_practice_key(vamp_zero::app_state const &state, vamp_zero::practice_exercise const &exercise) -> std::string;
|
||||
auto active_pages(vamp_zero::app_state const &state) -> std::size_t;
|
||||
auto practice_fallback_menu(vamp_zero::app_state const &state) -> vamp_zero::app_mode;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto parse_notation_document(std::string_view json, std::string source_path) -> std::expected<score_document, modulus::error>;
|
||||
auto written_quarters(score_written_duration const& written) -> double;
|
||||
auto written_quarters(score_written_duration const &written) -> std::float64_t;
|
||||
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto apply_app_command(vamp_zero::app_state state, vamp_protocol::page_command command) -> vamp_zero::app_state;
|
||||
auto app_status_json(vamp_zero::app_state const& state) -> boost::json::value;
|
||||
auto remote_display_text(vamp_zero::app_state const& state) -> std::string;
|
||||
auto validate_app_state(vamp_zero::app_state const& state) -> std::expected<void, modulus::error>;
|
||||
auto app_status_json(vamp_zero::app_state const &state) -> boost::json::value;
|
||||
auto remote_display_text(vamp_zero::app_state const &state) -> std::string;
|
||||
auto validate_app_state(vamp_zero::app_state const &state) -> std::expected<void, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <charconv>
|
||||
#include <concepts>
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
#include <modulus/result.hpp>
|
||||
|
||||
#include <vamp_zero/errors.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
template <std::integral VALUE>
|
||||
requires(!std::is_same_v<VALUE, std::bool_t>)
|
||||
auto parse_integer(std::string_view text, std::string_view name) -> std::expected<VALUE, modulus::error> {
|
||||
auto invalid = [&](std::string_view reason) {
|
||||
return modulus::fail<VALUE>(
|
||||
make_error(error_code::INVALID_ARGUMENT, std::string{name} + " " + std::string{reason}));
|
||||
};
|
||||
if (text.empty()) {
|
||||
return invalid("must be an integer");
|
||||
}
|
||||
auto value = VALUE{};
|
||||
auto end = text.data() + text.size();
|
||||
auto parsed = std::from_chars(text.data(), end, value);
|
||||
if (parsed.ec == std::errc::result_out_of_range) {
|
||||
return invalid("is out of range");
|
||||
}
|
||||
if (parsed.ec != std::errc{} || parsed.ptr != end) {
|
||||
return invalid("must be an integer");
|
||||
}
|
||||
return modulus::success(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,19 +13,18 @@
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
class control_state {
|
||||
public:
|
||||
using observer = std::function<void(vamp_zero::app_state)>;
|
||||
|
||||
control_state(vamp_zero::config config, vamp_zero::app_state state);
|
||||
auto config() const -> vamp_zero::config;
|
||||
auto snapshot() const -> vamp_zero::app_state;
|
||||
auto apply(vamp_protocol::page_command command) -> vamp_zero::app_state;
|
||||
auto heartbeat() -> vamp_zero::app_state;
|
||||
auto refresh_connection() -> std::optional<vamp_zero::app_state>;
|
||||
auto set_observer(vamp_zero::control_state::observer observer) -> void;
|
||||
auto set_observer(std::function<void(vamp_zero::app_state)> observer) -> void;
|
||||
private:
|
||||
auto pico_connected_locked() const -> std::bool_t;
|
||||
auto snapshot_locked() const -> vamp_zero::app_state;
|
||||
@@ -33,10 +32,10 @@ private:
|
||||
vamp_zero::config config_{};
|
||||
vamp_zero::app_state state_{};
|
||||
std::chrono::steady_clock::time_point last_heartbeat_{};
|
||||
vamp_zero::control_state::observer observer_{};
|
||||
std::function<void(vamp_zero::app_state)> observer_{};
|
||||
};
|
||||
|
||||
auto make_router(vamp_zero::control_state& state) -> ligo::service_router;
|
||||
auto portal_status_json(vamp_zero::config const& config, vamp_zero::app_state const& state) -> boost::json::value;
|
||||
auto make_router(vamp_zero::control_state &state) -> ligo::service_router;
|
||||
auto portal_status_json(vamp_zero::config const &config, vamp_zero::app_state const &state) -> boost::json::value;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
enum class score_accidental_mark {
|
||||
@@ -100,11 +101,11 @@ struct score_system_range {
|
||||
constexpr auto score_measures_per_system = std::size_t{4};
|
||||
constexpr auto score_systems_per_page = std::size_t{3};
|
||||
|
||||
auto notated_accidentals_for_measure(vamp_zero::score_measure const& measure, std::string_view inherited_key_signature) -> std::vector<vamp_zero::score_accidental_mark>;
|
||||
auto score_system_ranges(vamp_zero::score_document const& score) -> std::vector<vamp_zero::score_system_range>;
|
||||
auto score_page_count(vamp_zero::score_document const& score) -> std::size_t;
|
||||
auto layout_score_page(luma::rect bounds, vamp_zero::score_document const& score, std::size_t page_index) -> vamp_zero::score_page_layout;
|
||||
auto draw_score_layout(luma::draw_context& context, vamp_zero::score_page_layout const& layout) -> void;
|
||||
auto draw_score_page(luma::draw_context& context, luma::rect bounds, vamp_zero::score_document const& score, std::size_t page_index) -> void;
|
||||
auto notated_accidentals_for_measure(vamp_zero::score_measure const &measure, std::string_view inherited_key_signature) -> std::vector<vamp_zero::score_accidental_mark>;
|
||||
auto score_system_ranges(vamp_zero::score_document const &score) -> std::vector<vamp_zero::score_system_range>;
|
||||
auto score_page_count(vamp_zero::score_document const &score) -> std::size_t;
|
||||
auto layout_score_page(luma::rect bounds, vamp_zero::score_document const &score, std::size_t page_index) -> vamp_zero::score_page_layout;
|
||||
auto draw_score_layout(luma::draw_context &context, vamp_zero::score_page_layout const &layout) -> void;
|
||||
auto draw_score_page(luma::draw_context &context, luma::rect bounds, vamp_zero::score_document const &score, std::size_t page_index) -> void;
|
||||
|
||||
}
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct score_time {
|
||||
std::int64_t numerator{};
|
||||
std::int64_t denominator{1};
|
||||
auto quarters() const -> double { return static_cast<double>(numerator) / static_cast<double>(denominator); }
|
||||
auto quarters() const -> double {
|
||||
return static_cast<double>(numerator) / static_cast<double>(denominator);
|
||||
}
|
||||
};
|
||||
|
||||
struct score_written_duration {
|
||||
@@ -181,7 +184,6 @@ struct practice_exercise {
|
||||
std::size_t measure_count{};
|
||||
std::size_t total_pages{};
|
||||
};
|
||||
|
||||
std::string id{};
|
||||
std::string practice_type_id{};
|
||||
std::string practice_type_title{};
|
||||
@@ -261,7 +263,7 @@ struct app_state {
|
||||
|
||||
auto to_string(vamp_zero::hardware_mode value) -> std::string;
|
||||
auto to_string(vamp_zero::app_mode value) -> std::string;
|
||||
auto practice_key_names() -> std::vector<std::string_view> const&;
|
||||
auto practice_key_names() -> std::vector<std::string_view> const &;
|
||||
auto practice_type_supports_key_selection(std::string_view practice_type_id) -> std::bool_t;
|
||||
|
||||
}
|
||||
|
||||
@@ -32,23 +32,21 @@ struct ui_state {
|
||||
|
||||
class zero_ui {
|
||||
public:
|
||||
using command_handler = std::function<void(vamp_protocol::page_command)>;
|
||||
|
||||
zero_ui(boost::asio::any_io_executor executor, luma::application_config config, command_handler command_handler = {});
|
||||
zero_ui(boost::asio::any_io_executor executor, luma::application_config config, std::function<void(vamp_protocol::page_command)> command_handler = {});
|
||||
auto run() -> std::expected<void, modulus::error>;
|
||||
auto stop() -> void;
|
||||
auto publish(vamp_zero::ui_state state) -> std::expected<void, modulus::error>;
|
||||
auto snapshot() const -> vamp_zero::ui_state;
|
||||
private:
|
||||
auto handle_touch(luma::touch_event const& event) -> std::bool_t;
|
||||
auto handle_touch(luma::touch_event const &event) -> std::bool_t;
|
||||
auto send_touch_command(vamp_protocol::page_command command) -> void;
|
||||
auto arm_pending_tap() -> void;
|
||||
auto cancel_pending_tap_locked() -> void;
|
||||
auto make_root(vamp_zero::ui_state const& state) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
|
||||
auto make_root(vamp_zero::ui_state const &state) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
|
||||
boost::asio::any_io_executor executor_;
|
||||
boost::asio::steady_timer tap_timer_;
|
||||
luma::application application_;
|
||||
command_handler command_handler_{};
|
||||
std::function<void(vamp_protocol::page_command)> command_handler_{};
|
||||
std::shared_ptr<vamp_zero::score_draw_cache> score_cache_{};
|
||||
mutable std::mutex mutex_{};
|
||||
vamp_zero::ui_state state_{};
|
||||
@@ -60,6 +58,6 @@ private:
|
||||
std::bool_t pending_tap_{};
|
||||
};
|
||||
|
||||
auto make_ui_state(vamp_zero::config const& config, vamp_zero::app_state app) -> vamp_zero::ui_state;
|
||||
auto make_ui_state(vamp_zero::config const &config, vamp_zero::app_state app) -> vamp_zero::ui_state;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user