#pragma once #include #include #include #include #include #include namespace renderive::web { template 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(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; using Gallery_Positive_Frequency = Gallery_Number; using Gallery_Axis_Offset = Gallery_Number; using Gallery_Axis_Length = Gallery_Number; using Gallery_Tick_Length = Gallery_Number; using Gallery_Sub_Tick_Length = Gallery_Number; using Gallery_Font_Size = Gallery_Number; using Gallery_Font_Weight = Gallery_Number; using Gallery_Label_Rotation = Gallery_Number; using Gallery_Label_Precision = Gallery_Number; 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 time_visible_count{80}; Gallery_Number time_label_spacing{28}; Gallery_Text time_format{"mm:ss.zzz"}; Gallery_Number time_font_size{11}; bool time_newest_at_start{}; }; struct Gallery_Hover_Properties { bool hover_enabled{true}; Gallery_Number 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 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 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 power_origin{-120}; Gallery_Number power_target{-20}; Gallery_Number 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 power_origin{-120}; Gallery_Number power_target{-20}; Gallery_Number frequency_point_size{192}; Gallery_Number power_point_size{96}; bool interpolate_power{true}; Gallery_Number 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 bins_per_block{64}; Gallery_Number 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 trace_pen_width{2}; Gallery_Number trace_value_min{-1}; Gallery_Number 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 i_origin{-1.25}; Gallery_Number i_target{1.25}; Gallery_Number q_origin{-1.25}; Gallery_Number q_target{1.25}; Gallery_Color point_color{"#49e6c3"}; Gallery_Color anchor_color{"#ffd166"}; Gallery_Number point_lifetime_ms{1800}; Gallery_Constellation_Type constellation_type{Gallery_Constellation_Type::PSK8}; Gallery_Number phase_offset{0}; }; template struct Gallery_Low_Latency_Case_Properties : Properties, Gallery_Low_Latency_Properties {}; using Gallery_Property_Model = std::variant, Gallery_Low_Latency_Case_Properties, Gallery_Low_Latency_Case_Properties, Gallery_Low_Latency_Case_Properties, Gallery_Low_Latency_Case_Properties, Gallery_Low_Latency_Case_Properties, Gallery_Low_Latency_Case_Properties, Gallery_Low_Latency_Case_Properties>; }