252 lines
11 KiB
C++
252 lines
11 KiB
C++
#pragma once
|
|
#include <cctype>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <utility>
|
|
#include <variant>
|
|
namespace renderive::web {
|
|
template <class T, T Minimum, T Maximum, T Step>
|
|
class Gallery_Number final {
|
|
public:
|
|
using value_type = T;
|
|
static constexpr T minimum = Minimum;
|
|
static constexpr T maximum = Maximum;
|
|
static constexpr T step = Step;
|
|
constexpr explicit Gallery_Number(T value) : value_(checked(value)) {}
|
|
constexpr Gallery_Number& operator=(T value) {
|
|
value_ = checked(value);
|
|
return *this;
|
|
}
|
|
constexpr operator T() const noexcept {
|
|
return value_;
|
|
}
|
|
constexpr T value() const noexcept {
|
|
return value_;
|
|
}
|
|
private:
|
|
static constexpr T checked(T value) {
|
|
if(value < Minimum || value > Maximum)
|
|
throw std::out_of_range("value is outside the declared range");
|
|
return value;
|
|
}
|
|
T value_;
|
|
};
|
|
class Gallery_Text final {
|
|
public:
|
|
explicit Gallery_Text(std::string value) : value_(checked(std::move(value))) {}
|
|
Gallery_Text& operator=(std::string value) {
|
|
value_ = checked(std::move(value));
|
|
return *this;
|
|
}
|
|
const std::string& value() const noexcept {
|
|
return value_;
|
|
}
|
|
private:
|
|
static std::string checked(std::string value) {
|
|
if(value.size() > 160)
|
|
throw std::out_of_range("text is longer than 160 bytes");
|
|
return value;
|
|
}
|
|
std::string value_;
|
|
};
|
|
class Gallery_Color final {
|
|
public:
|
|
explicit Gallery_Color(std::string value) : value_(checked(std::move(value))) {}
|
|
Gallery_Color& operator=(std::string value) {
|
|
value_ = checked(std::move(value));
|
|
return *this;
|
|
}
|
|
const std::string& value() const noexcept {
|
|
return value_;
|
|
}
|
|
private:
|
|
static std::string checked(std::string value) {
|
|
if(value.size() != 7 || value.front() != '#')
|
|
throw std::invalid_argument("color must use #RRGGBB");
|
|
for(const char character : std::string_view(value).substr(1)) {
|
|
if(!std::isxdigit(static_cast<unsigned char>(character)))
|
|
throw std::invalid_argument("color must use #RRGGBB");
|
|
}
|
|
return value;
|
|
}
|
|
std::string value_;
|
|
};
|
|
enum class Gallery_Cache_Mode { Direct, Local_Pixel };
|
|
enum class Gallery_Axis_Orientation { Horizontal, Vertical };
|
|
enum class Gallery_Decimal_Separator { Dot, Comma };
|
|
enum class Gallery_Line_Interpolation { Nearest_Sample, Linear_Value, Linear_Power_Domain, Step_Left, Step_Right, Cubic_Value };
|
|
enum class Gallery_Image_Interpolation { Nearest, Bilinear, Bicubic };
|
|
enum class Gallery_Color_Map { Spectrum, Ember, Grayscale };
|
|
enum class Gallery_Constellation_Type { PSK4, PSK8, PSK16 };
|
|
using Gallery_Frequency = Gallery_Number<double, -10'000'000'000.0, 10'000'000'000.0, 1'000.0>;
|
|
using Gallery_Positive_Frequency = Gallery_Number<double, 0.01, 1'000'000'000.0, 1.0>;
|
|
using Gallery_Axis_Offset = Gallery_Number<int, -160, 160, 1>;
|
|
using Gallery_Axis_Length = Gallery_Number<double, 25.0, 125.0, 1.0>;
|
|
using Gallery_Tick_Length = Gallery_Number<int, -24, 24, 1>;
|
|
using Gallery_Sub_Tick_Length = Gallery_Number<int, -16, 16, 1>;
|
|
using Gallery_Font_Size = Gallery_Number<double, 6.0, 36.0, 1.0>;
|
|
using Gallery_Font_Weight = Gallery_Number<int, 100, 900, 100>;
|
|
using Gallery_Label_Rotation = Gallery_Number<int, -90, 90, 1>;
|
|
using Gallery_Label_Precision = Gallery_Number<int, 0, 9, 1>;
|
|
struct Gallery_Common_Properties {
|
|
Gallery_Color background_color{"#07111f"};
|
|
bool performance_overlay{};
|
|
bool renderable_visible{true};
|
|
Gallery_Cache_Mode cache_mode{Gallery_Cache_Mode::Local_Pixel};
|
|
Gallery_Text object_name{"Gallery_Renderable"};
|
|
};
|
|
struct Gallery_Low_Latency_Properties {
|
|
bool frequency_limit_enabled{true};
|
|
Gallery_Positive_Frequency max_render_fps{30};
|
|
bool consumer_feedback_enabled{true};
|
|
bool consumer_pixel_feedback_enabled{};
|
|
bool consumer_presentation_feedback_enabled{true};
|
|
bool consumer_manual_feedback_enabled{};
|
|
Gallery_Positive_Frequency consumer_manual_fps{60};
|
|
};
|
|
struct Gallery_Axis_Properties {
|
|
Gallery_Axis_Orientation axis_orientation{Gallery_Axis_Orientation::Horizontal};
|
|
Gallery_Axis_Offset axis_x_offset{0};
|
|
Gallery_Axis_Offset axis_y_offset{0};
|
|
Gallery_Axis_Length axis_length_percent{100};
|
|
Gallery_Tick_Length tick_length{8};
|
|
Gallery_Sub_Tick_Length sub_tick_length{4};
|
|
Gallery_Color axis_color{"#7691b8"};
|
|
Gallery_Decimal_Separator decimal_separator{Gallery_Decimal_Separator::Dot};
|
|
Gallery_Text unit_text{"Hz"};
|
|
Gallery_Font_Size unit_font_size{12};
|
|
Gallery_Font_Weight unit_font_weight{500};
|
|
bool unit_font_italic{};
|
|
Gallery_Color unit_pen_color{"#dce9ff"};
|
|
Gallery_Color unit_background_color{"#07111f"};
|
|
Gallery_Label_Rotation label_rotation{0};
|
|
Gallery_Frequency coord_origin{88'000'000};
|
|
Gallery_Frequency coord_target{108'000'000};
|
|
Gallery_Label_Precision label_precision{2};
|
|
bool use_wheel{true};
|
|
bool use_drag{true};
|
|
};
|
|
struct Gallery_Time_Axis_Properties {
|
|
Gallery_Number<int, 8, 400, 1> time_visible_count{80};
|
|
Gallery_Number<int, 0, 120, 1> time_label_spacing{28};
|
|
Gallery_Text time_format{"mm:ss.zzz"};
|
|
Gallery_Number<double, 6.0, 32.0, 1.0> time_font_size{11};
|
|
bool time_newest_at_start{};
|
|
};
|
|
struct Gallery_Hover_Properties {
|
|
bool hover_enabled{true};
|
|
Gallery_Number<double, 6.0, 32.0, 1.0> hover_font_size{12};
|
|
Gallery_Color hover_text_color{"#ffffff"};
|
|
Gallery_Color hover_background{"#111827"};
|
|
};
|
|
struct Gallery_Axis_Lab_Properties : Gallery_Common_Properties, Gallery_Axis_Properties, Gallery_Time_Axis_Properties {};
|
|
struct Gallery_Spectrum_Properties : Gallery_Common_Properties, Gallery_Axis_Properties, Gallery_Hover_Properties {
|
|
Gallery_Number<int, 16, 4096, 16> frequency_point_size{512};
|
|
Gallery_Frequency frequency_origin{88'000'000};
|
|
Gallery_Frequency frequency_target{108'000'000};
|
|
Gallery_Frequency center_frequency{98'000'000};
|
|
Gallery_Frequency sweep_origin{94'000'000};
|
|
Gallery_Frequency sweep_target{102'000'000};
|
|
bool max_hold_visible{true};
|
|
bool min_hold_visible{};
|
|
bool max_marker_visible{true};
|
|
bool use_min_marker{};
|
|
bool sweep_region_visible{true};
|
|
bool visible_range_only{true};
|
|
Gallery_Line_Interpolation line_interpolation{Gallery_Line_Interpolation::Linear_Value};
|
|
Gallery_Color max_brush{"#332810"};
|
|
Gallery_Color current_brush{"#0e3a35"};
|
|
Gallery_Color min_brush{"#19213a"};
|
|
Gallery_Color max_pen{"#ffd166"};
|
|
Gallery_Color current_pen{"#35e6b2"};
|
|
Gallery_Color min_pen{"#7aa2ff"};
|
|
Gallery_Color selected_marker_pen{"#ff4d8d"};
|
|
Gallery_Color marker_pen{"#ff7a59"};
|
|
Gallery_Color middle_frequency_pen{"#6bc8ff"};
|
|
Gallery_Color sweep_region_brush{"#293257"};
|
|
};
|
|
struct Gallery_Selection_Overlay_Properties : Gallery_Spectrum_Properties {
|
|
Gallery_Number<double, 6.0, 32.0, 1.0> selection_font_size{12};
|
|
Gallery_Color selection_label_pen{"#ffffff"};
|
|
Gallery_Color selection_brush{"#173b66"};
|
|
Gallery_Color selection_border{"#7dd3fc"};
|
|
};
|
|
struct Gallery_Waterfall_Properties : Gallery_Common_Properties, Gallery_Axis_Properties, Gallery_Time_Axis_Properties, Gallery_Hover_Properties {
|
|
Gallery_Frequency frequency_origin{88'000'000};
|
|
Gallery_Frequency frequency_target{108'000'000};
|
|
Gallery_Number<double, -240.0, 120.0, 1.0> power_origin{-120};
|
|
Gallery_Number<double, -240.0, 120.0, 1.0> power_target{-20};
|
|
Gallery_Number<int, 16, 2048, 16> frequency_bin_count{256};
|
|
bool visible_range_only{true};
|
|
Gallery_Image_Interpolation image_interpolation{Gallery_Image_Interpolation::Nearest};
|
|
Gallery_Color_Map color_map{Gallery_Color_Map::Spectrum};
|
|
};
|
|
struct Gallery_Afterglow_Properties : Gallery_Common_Properties, Gallery_Axis_Properties {
|
|
Gallery_Frequency frequency_origin{88'000'000};
|
|
Gallery_Frequency frequency_target{108'000'000};
|
|
Gallery_Number<double, -240.0, 120.0, 1.0> power_origin{-120};
|
|
Gallery_Number<double, -240.0, 120.0, 1.0> power_target{-20};
|
|
Gallery_Number<int, 16, 1024, 8> frequency_point_size{192};
|
|
Gallery_Number<int, 8, 512, 8> power_point_size{96};
|
|
bool interpolate_power{true};
|
|
Gallery_Number<double, 0.01, 1.0, 0.01> attenuation_rate{0.18};
|
|
Gallery_Color_Map color_map{Gallery_Color_Map::Spectrum};
|
|
};
|
|
struct Gallery_Sweep_Spectrum_Properties : Gallery_Common_Properties, Gallery_Axis_Properties {
|
|
Gallery_Sweep_Spectrum_Properties() {
|
|
coord_origin = 0;
|
|
coord_target = 300;
|
|
unit_text = "MHz";
|
|
}
|
|
Gallery_Frequency frequency_origin{0};
|
|
Gallery_Frequency frequency_target{300};
|
|
Gallery_Number<int, 2, 1024, 1> bins_per_block{64};
|
|
Gallery_Number<int, 1, 128, 1> block_count{8};
|
|
Gallery_Color sweep_pen{"#ffd166"};
|
|
Gallery_Color current_frequency_pen{"#ff5d73"};
|
|
bool visible_range_only{true};
|
|
Gallery_Line_Interpolation line_interpolation{Gallery_Line_Interpolation::Linear_Value};
|
|
};
|
|
struct Gallery_Frequency_Trace_Properties : Gallery_Common_Properties, Gallery_Axis_Properties, Gallery_Time_Axis_Properties {
|
|
Gallery_Frequency_Trace_Properties() {
|
|
coord_origin = -1;
|
|
coord_target = 1;
|
|
unit_text = "value";
|
|
}
|
|
Gallery_Color trace_pen{"#35e6b2"};
|
|
Gallery_Number<double, 0.25, 12.0, 0.25> trace_pen_width{2};
|
|
Gallery_Number<double, -1'000'000.0, 1'000'000.0, 0.1> trace_value_min{-1};
|
|
Gallery_Number<double, -1'000'000.0, 1'000'000.0, 0.1> trace_value_max{1};
|
|
};
|
|
struct Gallery_Constellation_Properties : Gallery_Common_Properties, Gallery_Axis_Properties {
|
|
Gallery_Constellation_Properties() {
|
|
coord_origin = -1.25;
|
|
coord_target = 1.25;
|
|
unit_text = "I / Q";
|
|
}
|
|
Gallery_Number<double, -1000.0, 1000.0, 0.05> i_origin{-1.25};
|
|
Gallery_Number<double, -1000.0, 1000.0, 0.05> i_target{1.25};
|
|
Gallery_Number<double, -1000.0, 1000.0, 0.05> q_origin{-1.25};
|
|
Gallery_Number<double, -1000.0, 1000.0, 0.05> q_target{1.25};
|
|
Gallery_Color point_color{"#49e6c3"};
|
|
Gallery_Color anchor_color{"#ffd166"};
|
|
Gallery_Number<int, 50, 20'000, 50> point_lifetime_ms{1800};
|
|
Gallery_Constellation_Type constellation_type{Gallery_Constellation_Type::PSK8};
|
|
Gallery_Number<double, -6.283185307, 6.283185307, 0.05> phase_offset{0};
|
|
};
|
|
template <class Properties>
|
|
struct Gallery_Low_Latency_Case_Properties : Properties, Gallery_Low_Latency_Properties {};
|
|
using Gallery_Property_Model = std::variant<Gallery_Axis_Lab_Properties, Gallery_Spectrum_Properties,
|
|
Gallery_Afterglow_Properties, Gallery_Sweep_Spectrum_Properties, Gallery_Waterfall_Properties,
|
|
Gallery_Frequency_Trace_Properties, Gallery_Selection_Overlay_Properties,
|
|
Gallery_Constellation_Properties, Gallery_Low_Latency_Case_Properties<Gallery_Axis_Lab_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Spectrum_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Afterglow_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Sweep_Spectrum_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Waterfall_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Frequency_Trace_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Selection_Overlay_Properties>,
|
|
Gallery_Low_Latency_Case_Properties<Gallery_Constellation_Properties>>;
|
|
}
|