更完
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gallery_Renderables_Adminive.h"
|
||||
#include "Gallery_Renderables.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -17,6 +17,18 @@ class Gallery_Controls final {
|
||||
public:
|
||||
using Json = nlohmann::json;
|
||||
|
||||
template <class Object>
|
||||
void add(Object& object) {
|
||||
const auto descriptor = adminive::Type_Descriptor<Object>::get();
|
||||
add(descriptor.name(), descriptor.label(), object);
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
void add(std::string id, Object& object) {
|
||||
add(std::move(id), adminive::Type_Descriptor<Object>::get().label(), object);
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Object>
|
||||
void add(std::string id, std::string title, Object& object) {
|
||||
using Model = adminive::Object_Model_Type<Object>;
|
||||
@@ -37,6 +49,7 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] Json resources() const {
|
||||
Json result = Json::array();
|
||||
for (const auto& entry : entries_) {
|
||||
|
||||
@@ -1176,29 +1176,29 @@ private:
|
||||
}
|
||||
}
|
||||
void register_controls() {
|
||||
controls_.add("scene", "Scene", *session_control_);
|
||||
controls_.add(*session_control_);
|
||||
if (frequency_domain_axis_)
|
||||
controls_.add("frequency_axis", "Frequency axis", *frequency_domain_axis_);
|
||||
controls_.add(*frequency_domain_axis_);
|
||||
if (numeric_domain_axis_)
|
||||
controls_.add("domain_axis", "Domain axis", *numeric_domain_axis_);
|
||||
controls_.add("domain_axis", *numeric_domain_axis_);
|
||||
if (value_axis_)
|
||||
controls_.add("value_axis", "Value axis", *value_axis_);
|
||||
controls_.add("value_axis", *value_axis_);
|
||||
if (time_axis_)
|
||||
controls_.add("time_axis", "Time axis", *time_axis_);
|
||||
controls_.add(*time_axis_);
|
||||
if (spectrum_)
|
||||
controls_.add("spectrum", "Spectrum", *spectrum_);
|
||||
controls_.add(*spectrum_);
|
||||
if (waterfall_)
|
||||
controls_.add("waterfall", "Waterfall", *waterfall_);
|
||||
controls_.add(*waterfall_);
|
||||
if (afterglow_)
|
||||
controls_.add("afterglow", "Afterglow", *afterglow_);
|
||||
controls_.add(*afterglow_);
|
||||
if (sweep_)
|
||||
controls_.add("sweep_spectrum", "Sweep spectrum", *sweep_);
|
||||
controls_.add(*sweep_);
|
||||
if (trace_)
|
||||
controls_.add("frequency_trace", "Frequency trace", *trace_);
|
||||
controls_.add(*trace_);
|
||||
if (selection_)
|
||||
controls_.add("selection_overlay", "Selection overlay", *selection_);
|
||||
controls_.add(*selection_);
|
||||
if (constellation_)
|
||||
controls_.add("constellation", "Constellation", *constellation_);
|
||||
controls_.add(*constellation_);
|
||||
}
|
||||
std::vector<double> spectrum_values(int count, Range power_range = {-120.0, -20.0}) const {
|
||||
count = std::max(count, 2);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "Gallery_Protocol.h"
|
||||
#include "Gallery_Renderables_Adminive.h"
|
||||
#include "Gallery_Renderables.h"
|
||||
#include "Gallery_Session_Control_Adminive.h"
|
||||
|
||||
#include "adminive/adminive.hpp"
|
||||
@@ -489,17 +489,19 @@ std::string Gallery_Protocol::catalog_json() {
|
||||
Json entry = adminive::to_frontend_json<Json>(item);
|
||||
entry["control_count_by_mode"] = Json::object();
|
||||
entry["action_count_by_mode"] = Json::object();
|
||||
const std::size_t controls = gallery_control_count<Gallery_Session_Control>() +
|
||||
gallery_renderable_control_count(item.id);
|
||||
for (const auto mode : frame_modes) {
|
||||
const std::string key(frame_mode_id(mode));
|
||||
const std::size_t mode_controls = control_count(item.id, mode);
|
||||
const std::size_t mode_actions = action_count(item.id, mode);
|
||||
entry["control_count_by_mode"][key] = mode_controls;
|
||||
entry["action_count_by_mode"][key] = mode_actions;
|
||||
controls_total += mode_controls;
|
||||
actions_total += mode_actions;
|
||||
const std::size_t actions = gallery_detail::actions(item.id, mode).size();
|
||||
entry["control_count_by_mode"][key] = controls;
|
||||
entry["action_count_by_mode"][key] = actions;
|
||||
controls_total += controls;
|
||||
actions_total += actions;
|
||||
}
|
||||
entry["control_count"] = control_count(item.id, Gallery_Frame_Mode::Low_Latency);
|
||||
entry["action_count"] = action_count(item.id, Gallery_Frame_Mode::Low_Latency);
|
||||
entry["control_count"] = controls;
|
||||
entry["action_count"] =
|
||||
gallery_detail::actions(item.id, Gallery_Frame_Mode::Low_Latency).size();
|
||||
result["cases"].push_back(std::move(entry));
|
||||
}
|
||||
result["coverage"] = {{"case_count", gallery_detail::cases().size()},
|
||||
@@ -642,67 +644,6 @@ std::optional<Gallery_Control_Patch_Request> Gallery_Protocol::control_patch_req
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t Gallery_Protocol::control_count(std::string_view case_id,
|
||||
Gallery_Frame_Mode frame_mode) {
|
||||
const auto count = [](const auto& self, const Json& fields) -> std::size_t {
|
||||
std::size_t result{};
|
||||
for (const auto& field : fields) {
|
||||
if (field.value("editable", false) && !field.contains("children"))
|
||||
++result;
|
||||
if (field.contains("children"))
|
||||
result += self(self, field.at("children"));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto type_count = [&count]<class T>() {
|
||||
return count(count, adminive::to_descriptor_json<Json, T>().at("fields"));
|
||||
};
|
||||
std::size_t result = type_count.template operator()<Gallery_Session_Control>();
|
||||
if (case_id == "axis_lab")
|
||||
return result + type_count.template operator()<Gallery_Frequency_Axis>() +
|
||||
type_count.template operator()<Gallery_Time_Axis>();
|
||||
if (case_id == "spectrum" || case_id == "selection_overlay") {
|
||||
result += type_count.template operator()<Gallery_Frequency_Axis>() +
|
||||
type_count.template operator()<Gallery_Axis>() +
|
||||
type_count.template operator()<Gallery_Spectrum>();
|
||||
if (case_id == "selection_overlay")
|
||||
result += type_count.template operator()<Gallery_Selection_Rectangle_Overlay>();
|
||||
return result;
|
||||
}
|
||||
if (case_id == "waterfall")
|
||||
return result + type_count.template operator()<Gallery_Frequency_Axis>() +
|
||||
type_count.template operator()<Gallery_Time_Axis>() +
|
||||
type_count.template operator()<Gallery_Waterfall>();
|
||||
if (case_id == "afterglow")
|
||||
return result + type_count.template operator()<Gallery_Frequency_Axis>() +
|
||||
type_count.template operator()<Gallery_Axis>() +
|
||||
type_count.template operator()<Gallery_Afterglow>();
|
||||
if (case_id == "sweep_spectrum")
|
||||
return result + 2 * type_count.template operator()<Gallery_Axis>() +
|
||||
type_count.template operator()<Gallery_Sweep_Spectrum>();
|
||||
if (case_id == "frequency_trace")
|
||||
return result + type_count.template operator()<Gallery_Time_Axis>() +
|
||||
type_count.template operator()<Gallery_Axis>() +
|
||||
type_count.template operator()<Gallery_Frequency_Trace>();
|
||||
if (case_id == "constellation")
|
||||
return result + 2 * type_count.template operator()<Gallery_Axis>() +
|
||||
type_count.template operator()<Gallery_Constellation_Diagram>();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t Gallery_Protocol::control_count(std::string_view case_id) {
|
||||
return control_count(case_id, Gallery_Frame_Mode::Low_Latency);
|
||||
}
|
||||
|
||||
std::size_t Gallery_Protocol::action_count(std::string_view case_id,
|
||||
Gallery_Frame_Mode frame_mode) {
|
||||
return gallery_detail::actions(case_id, frame_mode).size();
|
||||
}
|
||||
|
||||
std::size_t Gallery_Protocol::action_count(std::string_view case_id) {
|
||||
return action_count(case_id, Gallery_Frame_Mode::Low_Latency);
|
||||
}
|
||||
|
||||
bool Gallery_Protocol::action_available(std::string_view case_id,
|
||||
Gallery_Frame_Mode frame_mode,
|
||||
std::string_view action_id) {
|
||||
|
||||
@@ -42,10 +42,6 @@ public:
|
||||
[[nodiscard]] static std::optional<Gallery_Action_Request> action_request(std::string_view message);
|
||||
[[nodiscard]] static std::optional<Gallery_Control_Patch_Request> control_patch_request(
|
||||
std::string_view message);
|
||||
[[nodiscard]] static std::size_t control_count(std::string_view case_id);
|
||||
[[nodiscard]] static std::size_t control_count(std::string_view case_id, Gallery_Frame_Mode frame_mode);
|
||||
[[nodiscard]] static std::size_t action_count(std::string_view case_id);
|
||||
[[nodiscard]] static std::size_t action_count(std::string_view case_id, Gallery_Frame_Mode frame_mode);
|
||||
[[nodiscard]] static bool action_available(std::string_view case_id, Gallery_Frame_Mode frame_mode, std::string_view action_id);
|
||||
};
|
||||
} // namespace renderive::web
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#pragma once
|
||||
|
||||
#include "render_2D/axis/Axis.h"
|
||||
#include "render_2D/axis/Frequency_Axis.h"
|
||||
#include "render_2D/axis/Time_Axis.h"
|
||||
#include "render_2D/plottable/Afterglow.h"
|
||||
#include "render_2D/plottable/Constellation_Diagram.h"
|
||||
#include "render_2D/plottable/Frequency_Trace.h"
|
||||
#include "render_2D/plottable/Selection_Rectangle_Overlay.h"
|
||||
#include "render_2D/plottable/Spectrum.h"
|
||||
#include "render_2D/plottable/Sweep_Spectrum.h"
|
||||
#include "render_2D/plottable/Waterfall.h"
|
||||
#include <structive/property/accessor.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace renderive::web {
|
||||
|
||||
template <class Object, auto Member>
|
||||
struct Gallery_Property_Accessor {
|
||||
using object_type = Object;
|
||||
using Properties = typename Object::Properties;
|
||||
using value_type = std::remove_cvref_t<decltype(std::declval<Properties>().*Member)>;
|
||||
using storage_identity = void;
|
||||
using dependency_spec = structive::No_Property_Dependencies;
|
||||
static constexpr bool readable = true;
|
||||
static constexpr bool writable = true;
|
||||
static constexpr bool synchronized_view_read = false;
|
||||
static constexpr bool trusted_object_access = true;
|
||||
|
||||
value_type read(const Object& object) const {
|
||||
return object.template adminive_read<Member>();
|
||||
}
|
||||
void write(Object& object, value_type value) const {
|
||||
object.template adminive_write<Member>(std::move(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base>
|
||||
class Gallery_Plottable : public Base {
|
||||
public:
|
||||
using Properties = typename Base::Properties;
|
||||
using Base::Base;
|
||||
|
||||
private:
|
||||
template <auto Member>
|
||||
auto adminive_read() const {
|
||||
return this->template property_value<Member>();
|
||||
}
|
||||
template <auto Member, class Value>
|
||||
void adminive_write(Value&& value) {
|
||||
this->template set<Member>(std::forward<Value>(value));
|
||||
}
|
||||
template <class Object, auto Member>
|
||||
friend struct Gallery_Property_Accessor;
|
||||
};
|
||||
|
||||
class Gallery_Spectrum final : public Gallery_Plottable<Spectrum> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Spectrum, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Waterfall final : public Gallery_Plottable<Waterfall> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Waterfall, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Afterglow final : public Gallery_Plottable<Afterglow> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Afterglow, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Sweep_Spectrum final : public Gallery_Plottable<Sweep_Spectrum> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Sweep_Spectrum, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Frequency_Trace final : public Gallery_Plottable<Frequency_Trace> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Frequency_Trace, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Selection_Rectangle_Overlay final
|
||||
: public Gallery_Plottable<Selection_Rectangle_Overlay> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Selection_Rectangle_Overlay, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Constellation_Diagram final
|
||||
: public Gallery_Plottable<Constellation_Diagram> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Constellation_Diagram, Properties>;
|
||||
};
|
||||
|
||||
template <class Base, class Properties_Type>
|
||||
class Gallery_Axis_Base : public Base {
|
||||
public:
|
||||
using Properties = Properties_Type;
|
||||
using Base::Base;
|
||||
|
||||
private:
|
||||
template <auto Member>
|
||||
auto adminive_read() const {
|
||||
return this->read([](const auto& state) {
|
||||
return state.*Member;
|
||||
});
|
||||
}
|
||||
template <auto Member, class Value>
|
||||
void adminive_write(Value&& value) {
|
||||
this->template set<Member>(std::forward<Value>(value));
|
||||
}
|
||||
template <class Object, auto Member>
|
||||
friend struct Gallery_Property_Accessor;
|
||||
};
|
||||
|
||||
class Gallery_Axis final : public Gallery_Axis_Base<Axis, Axis_Properties> {
|
||||
public:
|
||||
using Gallery_Axis_Base::Gallery_Axis_Base;
|
||||
using Builder = detail::Axis_Renderable_Builder<Gallery_Axis, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Frequency_Axis final
|
||||
: public Gallery_Axis_Base<Frequency_Axis, Axis_Properties> {
|
||||
public:
|
||||
using Gallery_Axis_Base::Gallery_Axis_Base;
|
||||
using Builder = detail::Axis_Renderable_Builder<Gallery_Frequency_Axis, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Time_Axis final
|
||||
: public Gallery_Axis_Base<Time_Axis, Time_Axis_Properties> {
|
||||
public:
|
||||
using Gallery_Axis_Base::Gallery_Axis_Base;
|
||||
using Builder = detail::Axis_Renderable_Builder<Gallery_Time_Axis, Properties>;
|
||||
};
|
||||
|
||||
} // namespace renderive::web
|
||||
@@ -1,144 +1,584 @@
|
||||
#pragma once
|
||||
|
||||
#include "render_2D/axis/Axis.h"
|
||||
#include "render_2D/axis/Frequency_Axis.h"
|
||||
#include "render_2D/axis/Time_Axis.h"
|
||||
#include "render_2D/plottable/Afterglow.h"
|
||||
#include "render_2D/plottable/Constellation_Diagram.h"
|
||||
#include "render_2D/plottable/Frequency_Trace.h"
|
||||
#include "render_2D/plottable/Selection_Rectangle_Overlay.h"
|
||||
#include "render_2D/plottable/Spectrum.h"
|
||||
#include "render_2D/plottable/Sweep_Spectrum.h"
|
||||
#include "render_2D/plottable/Waterfall.h"
|
||||
#include <structive/property/accessor.hpp>
|
||||
#include "Gallery_Renderable_Types.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include "adminive/adminive.hpp"
|
||||
#include "adminive/adapters/nlohmann_json.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace renderive::web::gallery_adminive {
|
||||
|
||||
enum class Number_Locale_Choice { Point, Comma };
|
||||
enum class Color_Map_Choice { Spectrum, Ember, Grayscale };
|
||||
|
||||
template <class Enum>
|
||||
struct Enum_Metadata;
|
||||
|
||||
#define RENDERIVE_ENUM_METADATA(Type, ...) \
|
||||
template <> struct Enum_Metadata<Type> { static constexpr auto values = std::array{__VA_ARGS__}; }
|
||||
|
||||
RENDERIVE_ENUM_METADATA(Orientation,
|
||||
std::pair{Orientation::Horizontal, std::string_view{"Horizontal"}},
|
||||
std::pair{Orientation::Vertical, std::string_view{"Vertical"}});
|
||||
RENDERIVE_ENUM_METADATA(Renderable_Cache_Mode,
|
||||
std::pair{Renderable_Cache_Mode::Direct, std::string_view{"Direct"}},
|
||||
std::pair{Renderable_Cache_Mode::Local_Pixel, std::string_view{"Local_Pixel"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Interpolation_Mode,
|
||||
std::pair{Line_Interpolation_Mode::Nearest_Sample, std::string_view{"Nearest_Sample"}},
|
||||
std::pair{Line_Interpolation_Mode::Linear_Value, std::string_view{"Linear_Value"}},
|
||||
std::pair{Line_Interpolation_Mode::Linear_Power_Domain, std::string_view{"Linear_Power_Domain"}},
|
||||
std::pair{Line_Interpolation_Mode::Step_Left, std::string_view{"Step_Left"}},
|
||||
std::pair{Line_Interpolation_Mode::Step_Right, std::string_view{"Step_Right"}},
|
||||
std::pair{Line_Interpolation_Mode::Cubic_Value, std::string_view{"Cubic_Value"}});
|
||||
RENDERIVE_ENUM_METADATA(Image_Interpolation_Mode,
|
||||
std::pair{Image_Interpolation_Mode::Nearest, std::string_view{"Nearest"}},
|
||||
std::pair{Image_Interpolation_Mode::Bilinear, std::string_view{"Bilinear"}},
|
||||
std::pair{Image_Interpolation_Mode::Bicubic, std::string_view{"Bicubic"}});
|
||||
RENDERIVE_ENUM_METADATA(Constellation_Diagram_Type,
|
||||
std::pair{Constellation_Diagram_Type::Psk4, std::string_view{"PSK4"}},
|
||||
std::pair{Constellation_Diagram_Type::Psk8, std::string_view{"PSK8"}},
|
||||
std::pair{Constellation_Diagram_Type::Psk16, std::string_view{"PSK16"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Style,
|
||||
std::pair{Line_Style::None, std::string_view{"None"}},
|
||||
std::pair{Line_Style::Solid, std::string_view{"Solid"}},
|
||||
std::pair{Line_Style::Dash, std::string_view{"Dash"}},
|
||||
std::pair{Line_Style::Dot, std::string_view{"Dot"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Cap,
|
||||
std::pair{Line_Cap::Butt, std::string_view{"Butt"}},
|
||||
std::pair{Line_Cap::Square, std::string_view{"Square"}},
|
||||
std::pair{Line_Cap::Round, std::string_view{"Round"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Join,
|
||||
std::pair{Line_Join::Miter, std::string_view{"Miter"}},
|
||||
std::pair{Line_Join::Bevel, std::string_view{"Bevel"}},
|
||||
std::pair{Line_Join::Round, std::string_view{"Round"}});
|
||||
RENDERIVE_ENUM_METADATA(Brush_Style,
|
||||
std::pair{Brush_Style::None, std::string_view{"None"}},
|
||||
std::pair{Brush_Style::Solid, std::string_view{"Solid"}});
|
||||
RENDERIVE_ENUM_METADATA(Number_Locale_Choice,
|
||||
std::pair{Number_Locale_Choice::Point, std::string_view{"."}},
|
||||
std::pair{Number_Locale_Choice::Comma, std::string_view{","}});
|
||||
RENDERIVE_ENUM_METADATA(Color_Map_Choice,
|
||||
std::pair{Color_Map_Choice::Spectrum, std::string_view{"Spectrum"}},
|
||||
std::pair{Color_Map_Choice::Ember, std::string_view{"Ember"}},
|
||||
std::pair{Color_Map_Choice::Grayscale, std::string_view{"Grayscale"}});
|
||||
|
||||
#undef RENDERIVE_ENUM_METADATA
|
||||
|
||||
template <class Enum>
|
||||
struct Actual_Enum_Adapter {
|
||||
static std::vector<Enum> values() {
|
||||
std::vector<Enum> result;
|
||||
result.reserve(Enum_Metadata<Enum>::values.size());
|
||||
for (const auto& [value, name] : Enum_Metadata<Enum>::values)
|
||||
result.push_back(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string_view name(Enum value) {
|
||||
for (const auto& [candidate, name] : Enum_Metadata<Enum>::values) {
|
||||
if (candidate == value)
|
||||
return name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::optional<Enum> cast(std::string_view name) {
|
||||
for (const auto& [value, candidate] : Enum_Metadata<Enum>::values) {
|
||||
if (candidate == name)
|
||||
return value;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
inline Color blend(Color first, Color second, double amount) {
|
||||
const auto channel = [amount](std::uint8_t a, std::uint8_t b) {
|
||||
return static_cast<std::uint8_t>(std::clamp(
|
||||
std::lround(a + (b - a) * amount), 0L, 255L));
|
||||
};
|
||||
return {channel(first.r, second.r), channel(first.g, second.g),
|
||||
channel(first.b, second.b), channel(first.a, second.a)};
|
||||
}
|
||||
|
||||
inline Color_Map color_map(std::string_view palette) {
|
||||
std::array<Color, 5> stops{
|
||||
Color{5, 10, 25, 255}, Color{20, 52, 112, 255}, Color{39, 196, 181, 255},
|
||||
Color{242, 201, 76, 255}, Color{255, 76, 106, 255}
|
||||
};
|
||||
if (palette == "Ember") {
|
||||
stops = {Color{10, 5, 8, 255}, Color{62, 18, 30, 255}, Color{153, 47, 39, 255},
|
||||
Color{244, 132, 48, 255}, Color{255, 238, 166, 255}};
|
||||
} else if (palette == "Grayscale") {
|
||||
stops = {Color{0, 0, 0, 255}, Color{52, 52, 52, 255}, Color{112, 112, 112, 255},
|
||||
Color{188, 188, 188, 255}, Color{255, 255, 255, 255}};
|
||||
}
|
||||
std::vector<Pixel> colors;
|
||||
colors.reserve(256);
|
||||
for (int index = 0; index < 256; ++index) {
|
||||
const double position = index / 255.0 * (stops.size() - 1);
|
||||
const auto first = static_cast<std::size_t>(std::floor(position));
|
||||
const auto second = std::min(first + 1, stops.size() - 1);
|
||||
colors.push_back(premultiply(blend(stops[first], stops[second], position - first)));
|
||||
}
|
||||
return Color_Map(std::move(colors));
|
||||
}
|
||||
|
||||
inline std::string color_map_name(const Color_Map& value) {
|
||||
for (const std::string_view name : {std::string_view{"Spectrum"},
|
||||
std::string_view{"Ember"},
|
||||
std::string_view{"Grayscale"}}) {
|
||||
if (value.colors() == color_map(name).colors())
|
||||
return std::string(name);
|
||||
}
|
||||
return "Spectrum";
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto editable(std::string name, std::string label, adminive::Field_Control control) {
|
||||
return adminive::field<Member>(std::move(name), std::move(label))
|
||||
.editable().control(control);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto number(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::number);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto boolean(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::boolean);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto select(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::select);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto color(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::color);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property(std::string name, std::string label, adminive::Field_Control control) {
|
||||
return adminive::field(std::move(name), std::move(label),
|
||||
Gallery_Property_Accessor<Object, Member>{})
|
||||
.editable()
|
||||
.unsynchronized()
|
||||
.control(control);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto readonly_property(std::string name, std::string label) {
|
||||
return adminive::field(std::move(name), std::move(label),
|
||||
Gallery_Property_Accessor<Object, Member>{});
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_number(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::number);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_boolean(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::boolean);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_select(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::select);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_color(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::color);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_object(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::automatic);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_text(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::text);
|
||||
}
|
||||
|
||||
} // namespace renderive::web::gallery_adminive
|
||||
|
||||
namespace adminive {
|
||||
|
||||
template <class Validator>
|
||||
struct Renderive_Validator_Metadata {};
|
||||
|
||||
template <class T, T Minimum, T Maximum>
|
||||
struct Renderive_Validator_Metadata<::Range_Validator<T, Minimum, Maximum>> {
|
||||
static constexpr T minimum = Minimum;
|
||||
static constexpr T maximum = Maximum;
|
||||
};
|
||||
|
||||
template <class T, class Validator, class Json>
|
||||
struct Value_Adapter<::Validated_Value<T, Validator>, Json>
|
||||
: Renderive_Validator_Metadata<Validator> {
|
||||
using Storage = ::Validated_Value<T, Validator>;
|
||||
using value_type = T;
|
||||
static const T& read(const Storage& value) noexcept { return value.get(); }
|
||||
static void write(Storage& target, T value) { target = std::move(value); }
|
||||
};
|
||||
|
||||
#define RENDERIVE_ENUM_ADAPTER(Type) \
|
||||
template <> struct Enum_Adapter<renderive::Type> \
|
||||
: renderive::web::gallery_adminive::Actual_Enum_Adapter<renderive::Type> {}
|
||||
|
||||
RENDERIVE_ENUM_ADAPTER(Orientation);
|
||||
RENDERIVE_ENUM_ADAPTER(Renderable_Cache_Mode);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Interpolation_Mode);
|
||||
RENDERIVE_ENUM_ADAPTER(Image_Interpolation_Mode);
|
||||
RENDERIVE_ENUM_ADAPTER(Constellation_Diagram_Type);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Style);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Cap);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Join);
|
||||
RENDERIVE_ENUM_ADAPTER(Brush_Style);
|
||||
#undef RENDERIVE_ENUM_ADAPTER
|
||||
|
||||
template <>
|
||||
struct Enum_Adapter<renderive::web::gallery_adminive::Number_Locale_Choice>
|
||||
: renderive::web::gallery_adminive::Actual_Enum_Adapter<
|
||||
renderive::web::gallery_adminive::Number_Locale_Choice> {};
|
||||
|
||||
template <>
|
||||
struct Enum_Adapter<renderive::web::gallery_adminive::Color_Map_Choice>
|
||||
: renderive::web::gallery_adminive::Actual_Enum_Adapter<
|
||||
renderive::web::gallery_adminive::Color_Map_Choice> {};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Color, Json> {
|
||||
using value_type = std::string;
|
||||
static std::string read(renderive::Color value) {
|
||||
char result[8]{};
|
||||
std::snprintf(result, sizeof(result), "#%02x%02x%02x", value.r, value.g, value.b);
|
||||
return result;
|
||||
}
|
||||
static void write(renderive::Color& target, const std::string& value) {
|
||||
if (value.size() != 7 || value.front() != '#' ||
|
||||
!std::all_of(value.begin() + 1, value.end(), [](unsigned char character) {
|
||||
return std::isxdigit(character) != 0;
|
||||
}))
|
||||
throw std::invalid_argument("color must use #RRGGBB");
|
||||
const auto channel = [&value](std::size_t offset) {
|
||||
return static_cast<std::uint8_t>(std::stoul(value.substr(offset, 2), nullptr, 16));
|
||||
};
|
||||
target.r = channel(1);
|
||||
target.g = channel(3);
|
||||
target.b = channel(5);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Number_Locale, Json> {
|
||||
using Choice = renderive::web::gallery_adminive::Number_Locale_Choice;
|
||||
using value_type = Choice;
|
||||
static Choice read(renderive::Number_Locale value) {
|
||||
return value.decimal_point == ',' ? Choice::Comma : Choice::Point;
|
||||
}
|
||||
static void write(renderive::Number_Locale& target, Choice value) {
|
||||
target.decimal_point = value == Choice::Comma ? ',' : '.';
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, T Minimum, T Maximum, T Default, class Json>
|
||||
struct Value_Adapter<renderive::Clamped_Property<T, Minimum, Maximum, Default>, Json> {
|
||||
using Storage = renderive::Clamped_Property<T, Minimum, Maximum, Default>;
|
||||
using value_type = T;
|
||||
static constexpr T minimum = Minimum;
|
||||
static constexpr T maximum = Maximum;
|
||||
static T read(const Storage& value) noexcept { return value.get(); }
|
||||
static void write(Storage& target, T value) { target = value; }
|
||||
};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Unit_Interval, Json> {
|
||||
using value_type = double;
|
||||
static constexpr double minimum = 0.0;
|
||||
static constexpr double maximum = 1.0;
|
||||
static constexpr double multiple_of = 0.01;
|
||||
static double read(const renderive::Unit_Interval& value) noexcept { return value.get(); }
|
||||
static void write(renderive::Unit_Interval& target, double value) { target = value; }
|
||||
};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Color_Map, Json> {
|
||||
using Choice = renderive::web::gallery_adminive::Color_Map_Choice;
|
||||
using value_type = Choice;
|
||||
static Choice read(const renderive::Color_Map& value) {
|
||||
const auto name = renderive::web::gallery_adminive::color_map_name(value);
|
||||
if (name == "Ember")
|
||||
return Choice::Ember;
|
||||
if (name == "Grayscale")
|
||||
return Choice::Grayscale;
|
||||
return Choice::Spectrum;
|
||||
}
|
||||
static void write(renderive::Color_Map& target, Choice value) {
|
||||
const std::string_view name = value == Choice::Ember ? "Ember" :
|
||||
value == Choice::Grayscale ? "Grayscale" : "Spectrum";
|
||||
target = renderive::web::gallery_adminive::color_map(name);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Range> {
|
||||
static auto get() {
|
||||
using T = renderive::Range;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("range", "Range",
|
||||
number<&T::origin>("origin", "Origin"),
|
||||
number<&T::target>("target", "Target"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Pen> {
|
||||
static auto get() {
|
||||
using T = renderive::Pen;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("pen", "Pen",
|
||||
color<&T::color>("color", "Color"),
|
||||
number<&T::width>("width", "Width"),
|
||||
select<&T::style>("style", "Style"),
|
||||
select<&T::cap>("cap", "Cap"),
|
||||
select<&T::join>("join", "Join"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Brush> {
|
||||
static auto get() {
|
||||
using T = renderive::Brush;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("brush", "Brush",
|
||||
color<&T::color>("color", "Color"),
|
||||
select<&T::style>("style", "Style"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Font> {
|
||||
static auto get() {
|
||||
using T = renderive::Font;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("font", "Font",
|
||||
number<&T::size>("size", "Size"),
|
||||
number<&T::weight>("weight", "Weight"),
|
||||
boolean<&T::italic>("italic", "Italic"));
|
||||
}
|
||||
};
|
||||
|
||||
#define RENDERIVE_AXIS_DESCRIPTOR(GalleryType, Name, Label) \
|
||||
template <> struct Type_Descriptor<renderive::web::GalleryType> { \
|
||||
static auto get() { \
|
||||
using T = renderive::web::GalleryType; \
|
||||
using B = renderive::Axis_Base_Properties; \
|
||||
using P = renderive::Axis_Properties; \
|
||||
using namespace renderive::web::gallery_adminive; \
|
||||
return adminive::object<T>(Name, Label, \
|
||||
readonly_property<T, &B::x>("x", "X"), \
|
||||
readonly_property<T, &B::y>("y", "Y"), \
|
||||
property_select<T, &B::orientation>("orientation", "Orientation"), \
|
||||
readonly_property<T, &B::pixel_length>("pixel_length", "Pixel length"), \
|
||||
property_number<T, &B::tick_length>("tick_length", "Tick length"), \
|
||||
property_number<T, &B::sub_tick_length>("sub_tick_length", "Sub tick length"), \
|
||||
property_color<T, &B::color>("color", "Color"), \
|
||||
property_select<T, &B::locale>("locale", "Decimal separator"), \
|
||||
property_text<T, &B::unit_text>("unit_text", "Unit text"), \
|
||||
property_object<T, &B::unit_text_font>("unit_text_font", "Unit font"), \
|
||||
property_object<T, &B::unit_text_pen>("unit_text_pen", "Unit pen"), \
|
||||
property_object<T, &B::unit_text_background_brush>("unit_text_background_brush", "Unit background"), \
|
||||
property_number<T, &B::label_rotation_degrees>("label_rotation_degrees", "Label rotation"), \
|
||||
property_object<T, &P::coordinates>("coordinates", "Coordinates"), \
|
||||
property_number<T, &P::precision>("precision", "Precision"), \
|
||||
property_boolean<T, &P::wheel>("wheel", "Wheel zoom"), \
|
||||
property_boolean<T, &P::drag>("drag", "Drag pan")); \
|
||||
} \
|
||||
}
|
||||
|
||||
RENDERIVE_AXIS_DESCRIPTOR(Gallery_Axis, "axis", "Axis");
|
||||
RENDERIVE_AXIS_DESCRIPTOR(Gallery_Frequency_Axis, "frequency_axis", "Frequency axis");
|
||||
#undef RENDERIVE_AXIS_DESCRIPTOR
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::web::Gallery_Time_Axis> {
|
||||
static auto get() {
|
||||
using T = renderive::web::Gallery_Time_Axis;
|
||||
using B = renderive::Axis_Base_Properties;
|
||||
using P = renderive::Time_Axis_Properties;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("time_axis", "Time axis",
|
||||
readonly_property<T, &B::x>("x", "X"),
|
||||
readonly_property<T, &B::y>("y", "Y"),
|
||||
property_select<T, &B::orientation>("orientation", "Orientation"),
|
||||
readonly_property<T, &B::pixel_length>("pixel_length", "Pixel length"),
|
||||
property_number<T, &B::tick_length>("tick_length", "Tick length"),
|
||||
property_number<T, &B::sub_tick_length>("sub_tick_length", "Sub tick length"),
|
||||
property_color<T, &B::color>("color", "Color"),
|
||||
property_select<T, &B::locale>("locale", "Decimal separator"),
|
||||
property_text<T, &B::unit_text>("unit_text", "Unit text"),
|
||||
property_object<T, &B::unit_text_font>("unit_text_font", "Unit font"),
|
||||
property_object<T, &B::unit_text_pen>("unit_text_pen", "Unit pen"),
|
||||
property_object<T, &B::unit_text_background_brush>("unit_text_background_brush", "Unit background"),
|
||||
property_number<T, &B::label_rotation_degrees>("label_rotation_degrees", "Label rotation"),
|
||||
property_number<T, &P::visible_count>("visible_count", "Visible points"),
|
||||
property_number<T, &P::tick_label_spacing_px>("tick_label_spacing_px", "Label spacing"),
|
||||
property_text<T, &P::format>("format", "Time format"),
|
||||
property_boolean<T, &P::newest_at_start>("newest_at_start", "Newest at start"));
|
||||
}
|
||||
};
|
||||
|
||||
#define RENDERIVE_GALLERY_DESCRIPTOR(GalleryType, PropertiesType, Name, Label, ...) \
|
||||
template <> struct Type_Descriptor<renderive::web::GalleryType> { \
|
||||
static auto get() { \
|
||||
using T = renderive::web::GalleryType; \
|
||||
using P = renderive::PropertiesType; \
|
||||
using namespace renderive::web::gallery_adminive; \
|
||||
return adminive::object<T>(Name, Label, __VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Spectrum, Spectrum_Properties, "spectrum", "Spectrum",
|
||||
property_number<T, &P::frequency_point_size>("frequency_point_size", "Frequency points"),
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_number<T, &P::center_frequency>("center_frequency", "Center frequency"),
|
||||
property_object<T, &P::sweep_frequency_range>("sweep_frequency_range", "Sweep range"),
|
||||
property_boolean<T, &P::max_hold_visible>("max_hold_visible", "Max hold"),
|
||||
property_boolean<T, &P::min_hold_visible>("min_hold_visible", "Min hold"),
|
||||
property_boolean<T, &P::max_marker_visible>("max_marker_visible", "Max marker"),
|
||||
property_boolean<T, &P::use_min_marker>("use_min_marker", "Use min marker"),
|
||||
property_boolean<T, &P::sweep_region_visible>("sweep_region_visible", "Sweep region"),
|
||||
property_boolean<T, &P::visible_range_only>("visible_range_only", "Visible range only"),
|
||||
property_select<T, &P::interpolation_mode>("interpolation_mode", "Interpolation"),
|
||||
property_object<T, &P::max_brush>("max_brush", "Max brush"),
|
||||
property_object<T, &P::current_brush>("current_brush", "Current brush"),
|
||||
property_object<T, &P::min_brush>("min_brush", "Min brush"),
|
||||
property_object<T, &P::max_pen>("max_pen", "Max pen"),
|
||||
property_object<T, &P::current_pen>("current_pen", "Current pen"),
|
||||
property_object<T, &P::min_pen>("min_pen", "Min pen"),
|
||||
property_object<T, &P::selected_marker_pen>("selected_marker_pen", "Selected marker pen"),
|
||||
property_object<T, &P::marker_pen>("marker_pen", "Marker pen"),
|
||||
property_object<T, &P::middle_frequency_pen>("middle_frequency_pen", "Middle frequency pen"),
|
||||
property_object<T, &P::sweep_region_brush>("sweep_region_brush", "Sweep region brush"),
|
||||
property_boolean<T, &P::tooltip_enabled>("tooltip_enabled", "Tooltip"),
|
||||
property_object<T, &P::tooltip_font>("tooltip_font", "Tooltip font"),
|
||||
property_object<T, &P::tooltip_text_pen>("tooltip_text_pen", "Tooltip text pen"),
|
||||
property_object<T, &P::tooltip_background_brush>("tooltip_background_brush", "Tooltip background"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Waterfall, Waterfall_Properties, "waterfall", "Waterfall",
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_object<T, &P::power_range>("power_range", "Power range"),
|
||||
property_number<T, &P::frequency_bin_count>("frequency_bin_count", "Frequency bins"),
|
||||
property_boolean<T, &P::visible_range_only>("visible_range_only", "Visible range only"),
|
||||
property_select<T, &P::interpolation_mode>("interpolation_mode", "Interpolation"),
|
||||
property_select<T, &P::color_map>("color_map", "Color map"),
|
||||
property_boolean<T, &P::tooltip_enabled>("tooltip_enabled", "Tooltip"),
|
||||
property_object<T, &P::tooltip_font>("tooltip_font", "Tooltip font"),
|
||||
property_object<T, &P::tooltip_text_pen>("tooltip_text_pen", "Tooltip text pen"),
|
||||
property_object<T, &P::tooltip_background_brush>("tooltip_background_brush", "Tooltip background"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Afterglow, Afterglow_Properties, "afterglow", "Afterglow",
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_object<T, &P::power_range>("power_range", "Power range"),
|
||||
property_number<T, &P::frequency_point_size>("frequency_point_size", "Frequency points"),
|
||||
property_number<T, &P::power_point_size>("power_point_size", "Power points"),
|
||||
property_boolean<T, &P::interpolate>("interpolate", "Interpolate power"),
|
||||
property_number<T, &P::attenuation_rate>("attenuation_rate", "Attenuation"),
|
||||
property_select<T, &P::color_map>("color_map", "Color map"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Sweep_Spectrum, Sweep_Spectrum_Properties, "sweep_spectrum", "Sweep spectrum",
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_number<T, &P::bins_per_block>("bins_per_block", "Bins per block"),
|
||||
property_number<T, &P::block_count>("block_count", "Block count"),
|
||||
property_object<T, &P::pen>("pen", "Sweep pen"),
|
||||
property_object<T, &P::current_frequency_pen>("current_frequency_pen", "Current frequency pen"),
|
||||
property_boolean<T, &P::visible_range_only>("visible_range_only", "Visible range only"),
|
||||
property_select<T, &P::interpolation_mode>("interpolation_mode", "Interpolation"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Frequency_Trace, Frequency_Trace_Properties, "frequency_trace", "Frequency trace",
|
||||
property_object<T, &P::pen>("pen", "Trace pen"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Selection_Rectangle_Overlay, Selection_Rectangle_Overlay_Properties, "selection_overlay", "Selection overlay",
|
||||
property_object<T, &P::label_font>("label_font", "Label font"),
|
||||
property_object<T, &P::label_pen>("label_pen", "Label pen"),
|
||||
property_object<T, &P::selection_brush>("selection_brush", "Selection brush"),
|
||||
property_object<T, &P::selection_border_pen>("selection_border_pen", "Selection border"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Constellation_Diagram, Constellation_Diagram_Properties, "constellation", "Constellation diagram",
|
||||
property_object<T, &P::i_range>("i_range", "I range"),
|
||||
property_object<T, &P::q_range>("q_range", "Q range"),
|
||||
property_color<T, &P::point_color>("point_color", "Point color"),
|
||||
property_color<T, &P::anchor_color>("anchor_color", "Anchor color"),
|
||||
property_number<T, &P::point_lifetime_ms>("point_lifetime_ms", "Point lifetime"),
|
||||
property_select<T, &P::type>("type", "Constellation"),
|
||||
property_number<T, &P::phase_offset_radians>("phase_offset_radians", "Phase offset"));
|
||||
|
||||
#undef RENDERIVE_GALLERY_DESCRIPTOR
|
||||
|
||||
} // namespace adminive
|
||||
|
||||
namespace renderive::web {
|
||||
|
||||
template <class Object, auto Member>
|
||||
struct Gallery_Property_Accessor {
|
||||
using object_type = Object;
|
||||
using Properties = typename Object::Properties;
|
||||
using value_type = std::remove_cvref_t<decltype(std::declval<Properties>().*Member)>;
|
||||
using storage_identity = void;
|
||||
using dependency_spec = structive::No_Property_Dependencies;
|
||||
static constexpr bool readable = true;
|
||||
static constexpr bool writable = true;
|
||||
static constexpr bool synchronized_view_read = false;
|
||||
static constexpr bool trusted_object_access = true;
|
||||
template <class Object>
|
||||
std::size_t gallery_control_count() {
|
||||
using Json = nlohmann::json;
|
||||
const auto count_fields = [](const auto& self, const Json& fields) -> std::size_t {
|
||||
std::size_t result{};
|
||||
for (const auto& field : fields) {
|
||||
if (field.value("editable", false) && !field.contains("children"))
|
||||
++result;
|
||||
if (field.contains("children"))
|
||||
result += self(self, field.at("children"));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const Json descriptor = adminive::to_descriptor_json<Json, Object>();
|
||||
return count_fields(count_fields, descriptor.at("fields"));
|
||||
}
|
||||
|
||||
value_type read(const Object& object) const {
|
||||
return object.template adminive_read<Member>();
|
||||
}
|
||||
void write(Object& object, value_type value) const {
|
||||
object.template adminive_write<Member>(std::move(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Base>
|
||||
class Gallery_Plottable : public Base {
|
||||
public:
|
||||
using Properties = typename Base::Properties;
|
||||
using Base::Base;
|
||||
|
||||
private:
|
||||
template <auto Member>
|
||||
auto adminive_read() const {
|
||||
return this->template property_value<Member>();
|
||||
}
|
||||
template <auto Member, class Value>
|
||||
void adminive_write(Value&& value) {
|
||||
this->template set<Member>(std::forward<Value>(value));
|
||||
}
|
||||
template <class Object, auto Member>
|
||||
friend struct Gallery_Property_Accessor;
|
||||
};
|
||||
|
||||
class Gallery_Spectrum final : public Gallery_Plottable<Spectrum> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Spectrum, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Waterfall final : public Gallery_Plottable<Waterfall> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Waterfall, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Afterglow final : public Gallery_Plottable<Afterglow> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Afterglow, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Sweep_Spectrum final : public Gallery_Plottable<Sweep_Spectrum> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Sweep_Spectrum, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Frequency_Trace final : public Gallery_Plottable<Frequency_Trace> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Frequency_Trace, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Selection_Rectangle_Overlay final
|
||||
: public Gallery_Plottable<Selection_Rectangle_Overlay> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Selection_Rectangle_Overlay, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Constellation_Diagram final
|
||||
: public Gallery_Plottable<Constellation_Diagram> {
|
||||
public:
|
||||
using Gallery_Plottable::Gallery_Plottable;
|
||||
using Builder = Renderable_Builder<Gallery_Constellation_Diagram, Properties>;
|
||||
};
|
||||
|
||||
template <class Base, class Properties_Type>
|
||||
class Gallery_Axis_Base : public Base {
|
||||
public:
|
||||
using Properties = Properties_Type;
|
||||
using Base::Base;
|
||||
|
||||
private:
|
||||
template <auto Member>
|
||||
auto adminive_read() const {
|
||||
return this->read([](const auto& state) {
|
||||
return state.*Member;
|
||||
});
|
||||
}
|
||||
template <auto Member, class Value>
|
||||
void adminive_write(Value&& value) {
|
||||
this->template set<Member>(std::forward<Value>(value));
|
||||
}
|
||||
template <class Object, auto Member>
|
||||
friend struct Gallery_Property_Accessor;
|
||||
};
|
||||
|
||||
class Gallery_Axis final : public Gallery_Axis_Base<Axis, Axis_Properties> {
|
||||
public:
|
||||
using Gallery_Axis_Base::Gallery_Axis_Base;
|
||||
using Builder = detail::Axis_Renderable_Builder<Gallery_Axis, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Frequency_Axis final
|
||||
: public Gallery_Axis_Base<Frequency_Axis, Axis_Properties> {
|
||||
public:
|
||||
using Gallery_Axis_Base::Gallery_Axis_Base;
|
||||
using Builder = detail::Axis_Renderable_Builder<Gallery_Frequency_Axis, Properties>;
|
||||
};
|
||||
|
||||
class Gallery_Time_Axis final
|
||||
: public Gallery_Axis_Base<Time_Axis, Time_Axis_Properties> {
|
||||
public:
|
||||
using Gallery_Axis_Base::Gallery_Axis_Base;
|
||||
using Builder = detail::Axis_Renderable_Builder<Gallery_Time_Axis, Properties>;
|
||||
};
|
||||
inline std::size_t gallery_renderable_control_count(std::string_view case_id) {
|
||||
const auto axis = gallery_control_count<Gallery_Axis>();
|
||||
const auto frequency_axis = gallery_control_count<Gallery_Frequency_Axis>();
|
||||
const auto time_axis = gallery_control_count<Gallery_Time_Axis>();
|
||||
if (case_id == "axis_lab")
|
||||
return frequency_axis + time_axis;
|
||||
if (case_id == "spectrum")
|
||||
return frequency_axis + axis + gallery_control_count<Gallery_Spectrum>();
|
||||
if (case_id == "selection_overlay")
|
||||
return frequency_axis + axis + gallery_control_count<Gallery_Spectrum>() +
|
||||
gallery_control_count<Gallery_Selection_Rectangle_Overlay>();
|
||||
if (case_id == "waterfall")
|
||||
return frequency_axis + time_axis + gallery_control_count<Gallery_Waterfall>();
|
||||
if (case_id == "afterglow")
|
||||
return frequency_axis + axis + gallery_control_count<Gallery_Afterglow>();
|
||||
if (case_id == "sweep_spectrum")
|
||||
return 2 * axis + gallery_control_count<Gallery_Sweep_Spectrum>();
|
||||
if (case_id == "frequency_trace")
|
||||
return time_axis + axis + gallery_control_count<Gallery_Frequency_Trace>();
|
||||
if (case_id == "constellation")
|
||||
return 2 * axis + gallery_control_count<Gallery_Constellation_Diagram>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace renderive::web
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gallery_Renderables.h"
|
||||
|
||||
#include "adminive/adminive.hpp"
|
||||
#include "adminive/adapters/nlohmann_json.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace renderive::web::gallery_adminive {
|
||||
|
||||
enum class Number_Locale_Choice { Point, Comma };
|
||||
enum class Color_Map_Choice { Spectrum, Ember, Grayscale };
|
||||
|
||||
template <class Enum>
|
||||
struct Enum_Metadata;
|
||||
|
||||
#define RENDERIVE_ENUM_METADATA(Type, ...) \
|
||||
template <> struct Enum_Metadata<Type> { static constexpr auto values = std::array{__VA_ARGS__}; }
|
||||
|
||||
RENDERIVE_ENUM_METADATA(Orientation,
|
||||
std::pair{Orientation::Horizontal, std::string_view{"Horizontal"}},
|
||||
std::pair{Orientation::Vertical, std::string_view{"Vertical"}});
|
||||
RENDERIVE_ENUM_METADATA(Renderable_Cache_Mode,
|
||||
std::pair{Renderable_Cache_Mode::Direct, std::string_view{"Direct"}},
|
||||
std::pair{Renderable_Cache_Mode::Local_Pixel, std::string_view{"Local_Pixel"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Interpolation_Mode,
|
||||
std::pair{Line_Interpolation_Mode::Nearest_Sample, std::string_view{"Nearest_Sample"}},
|
||||
std::pair{Line_Interpolation_Mode::Linear_Value, std::string_view{"Linear_Value"}},
|
||||
std::pair{Line_Interpolation_Mode::Linear_Power_Domain, std::string_view{"Linear_Power_Domain"}},
|
||||
std::pair{Line_Interpolation_Mode::Step_Left, std::string_view{"Step_Left"}},
|
||||
std::pair{Line_Interpolation_Mode::Step_Right, std::string_view{"Step_Right"}},
|
||||
std::pair{Line_Interpolation_Mode::Cubic_Value, std::string_view{"Cubic_Value"}});
|
||||
RENDERIVE_ENUM_METADATA(Image_Interpolation_Mode,
|
||||
std::pair{Image_Interpolation_Mode::Nearest, std::string_view{"Nearest"}},
|
||||
std::pair{Image_Interpolation_Mode::Bilinear, std::string_view{"Bilinear"}},
|
||||
std::pair{Image_Interpolation_Mode::Bicubic, std::string_view{"Bicubic"}});
|
||||
RENDERIVE_ENUM_METADATA(Constellation_Diagram_Type,
|
||||
std::pair{Constellation_Diagram_Type::Psk4, std::string_view{"PSK4"}},
|
||||
std::pair{Constellation_Diagram_Type::Psk8, std::string_view{"PSK8"}},
|
||||
std::pair{Constellation_Diagram_Type::Psk16, std::string_view{"PSK16"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Style,
|
||||
std::pair{Line_Style::None, std::string_view{"None"}},
|
||||
std::pair{Line_Style::Solid, std::string_view{"Solid"}},
|
||||
std::pair{Line_Style::Dash, std::string_view{"Dash"}},
|
||||
std::pair{Line_Style::Dot, std::string_view{"Dot"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Cap,
|
||||
std::pair{Line_Cap::Butt, std::string_view{"Butt"}},
|
||||
std::pair{Line_Cap::Square, std::string_view{"Square"}},
|
||||
std::pair{Line_Cap::Round, std::string_view{"Round"}});
|
||||
RENDERIVE_ENUM_METADATA(Line_Join,
|
||||
std::pair{Line_Join::Miter, std::string_view{"Miter"}},
|
||||
std::pair{Line_Join::Bevel, std::string_view{"Bevel"}},
|
||||
std::pair{Line_Join::Round, std::string_view{"Round"}});
|
||||
RENDERIVE_ENUM_METADATA(Brush_Style,
|
||||
std::pair{Brush_Style::None, std::string_view{"None"}},
|
||||
std::pair{Brush_Style::Solid, std::string_view{"Solid"}});
|
||||
RENDERIVE_ENUM_METADATA(Number_Locale_Choice,
|
||||
std::pair{Number_Locale_Choice::Point, std::string_view{"."}},
|
||||
std::pair{Number_Locale_Choice::Comma, std::string_view{","}});
|
||||
RENDERIVE_ENUM_METADATA(Color_Map_Choice,
|
||||
std::pair{Color_Map_Choice::Spectrum, std::string_view{"Spectrum"}},
|
||||
std::pair{Color_Map_Choice::Ember, std::string_view{"Ember"}},
|
||||
std::pair{Color_Map_Choice::Grayscale, std::string_view{"Grayscale"}});
|
||||
|
||||
#undef RENDERIVE_ENUM_METADATA
|
||||
|
||||
template <class Enum>
|
||||
struct Actual_Enum_Adapter {
|
||||
static std::vector<Enum> values() {
|
||||
std::vector<Enum> result;
|
||||
result.reserve(Enum_Metadata<Enum>::values.size());
|
||||
for (const auto& [value, name] : Enum_Metadata<Enum>::values)
|
||||
result.push_back(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string_view name(Enum value) {
|
||||
for (const auto& [candidate, name] : Enum_Metadata<Enum>::values) {
|
||||
if (candidate == value)
|
||||
return name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::optional<Enum> cast(std::string_view name) {
|
||||
for (const auto& [value, candidate] : Enum_Metadata<Enum>::values) {
|
||||
if (candidate == name)
|
||||
return value;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
inline Color blend(Color first, Color second, double amount) {
|
||||
const auto channel = [amount](std::uint8_t a, std::uint8_t b) {
|
||||
return static_cast<std::uint8_t>(std::clamp(
|
||||
std::lround(a + (b - a) * amount), 0L, 255L));
|
||||
};
|
||||
return {channel(first.r, second.r), channel(first.g, second.g),
|
||||
channel(first.b, second.b), channel(first.a, second.a)};
|
||||
}
|
||||
|
||||
inline Color_Map color_map(std::string_view palette) {
|
||||
std::array<Color, 5> stops{
|
||||
Color{5, 10, 25, 255}, Color{20, 52, 112, 255}, Color{39, 196, 181, 255},
|
||||
Color{242, 201, 76, 255}, Color{255, 76, 106, 255}
|
||||
};
|
||||
if (palette == "Ember") {
|
||||
stops = {Color{10, 5, 8, 255}, Color{62, 18, 30, 255}, Color{153, 47, 39, 255},
|
||||
Color{244, 132, 48, 255}, Color{255, 238, 166, 255}};
|
||||
} else if (palette == "Grayscale") {
|
||||
stops = {Color{0, 0, 0, 255}, Color{52, 52, 52, 255}, Color{112, 112, 112, 255},
|
||||
Color{188, 188, 188, 255}, Color{255, 255, 255, 255}};
|
||||
}
|
||||
std::vector<Pixel> colors;
|
||||
colors.reserve(256);
|
||||
for (int index = 0; index < 256; ++index) {
|
||||
const double position = index / 255.0 * (stops.size() - 1);
|
||||
const auto first = static_cast<std::size_t>(std::floor(position));
|
||||
const auto second = std::min(first + 1, stops.size() - 1);
|
||||
colors.push_back(premultiply(blend(stops[first], stops[second], position - first)));
|
||||
}
|
||||
return Color_Map(std::move(colors));
|
||||
}
|
||||
|
||||
inline std::string color_map_name(const Color_Map& value) {
|
||||
for (const std::string_view name : {std::string_view{"Spectrum"},
|
||||
std::string_view{"Ember"},
|
||||
std::string_view{"Grayscale"}}) {
|
||||
if (value.colors() == color_map(name).colors())
|
||||
return std::string(name);
|
||||
}
|
||||
return "Spectrum";
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto editable(std::string name, std::string label, adminive::Field_Control control) {
|
||||
return adminive::field<Member>(std::move(name), std::move(label))
|
||||
.editable().control(control);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto number(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::number);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto boolean(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::boolean);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto select(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::select);
|
||||
}
|
||||
|
||||
template <auto Member>
|
||||
auto color(std::string name, std::string label) {
|
||||
return editable<Member>(std::move(name), std::move(label), adminive::Field_Control::color);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property(std::string name, std::string label, adminive::Field_Control control) {
|
||||
return adminive::field(std::move(name), std::move(label),
|
||||
Gallery_Property_Accessor<Object, Member>{})
|
||||
.editable()
|
||||
.unsynchronized()
|
||||
.control(control);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto readonly_property(std::string name, std::string label) {
|
||||
return adminive::field(std::move(name), std::move(label),
|
||||
Gallery_Property_Accessor<Object, Member>{});
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_number(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::number);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_boolean(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::boolean);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_select(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::select);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_color(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::color);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_object(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::automatic);
|
||||
}
|
||||
|
||||
template <class Object, auto Member>
|
||||
auto property_text(std::string name, std::string label) {
|
||||
return property<Object, Member>(std::move(name), std::move(label),
|
||||
adminive::Field_Control::text);
|
||||
}
|
||||
|
||||
} // namespace renderive::web::gallery_adminive
|
||||
|
||||
namespace adminive {
|
||||
|
||||
template <class Validator>
|
||||
struct Renderive_Validator_Metadata {};
|
||||
|
||||
template <class T, T Minimum, T Maximum>
|
||||
struct Renderive_Validator_Metadata<::Range_Validator<T, Minimum, Maximum>> {
|
||||
static constexpr T minimum = Minimum;
|
||||
static constexpr T maximum = Maximum;
|
||||
};
|
||||
|
||||
template <class T, class Validator, class Json>
|
||||
struct Value_Adapter<::Validated_Value<T, Validator>, Json>
|
||||
: Renderive_Validator_Metadata<Validator> {
|
||||
using Storage = ::Validated_Value<T, Validator>;
|
||||
using value_type = T;
|
||||
static const T& read(const Storage& value) noexcept { return value.get(); }
|
||||
static void write(Storage& target, T value) { target = std::move(value); }
|
||||
};
|
||||
|
||||
#define RENDERIVE_ENUM_ADAPTER(Type) \
|
||||
template <> struct Enum_Adapter<renderive::Type> \
|
||||
: renderive::web::gallery_adminive::Actual_Enum_Adapter<renderive::Type> {}
|
||||
|
||||
RENDERIVE_ENUM_ADAPTER(Orientation);
|
||||
RENDERIVE_ENUM_ADAPTER(Renderable_Cache_Mode);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Interpolation_Mode);
|
||||
RENDERIVE_ENUM_ADAPTER(Image_Interpolation_Mode);
|
||||
RENDERIVE_ENUM_ADAPTER(Constellation_Diagram_Type);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Style);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Cap);
|
||||
RENDERIVE_ENUM_ADAPTER(Line_Join);
|
||||
RENDERIVE_ENUM_ADAPTER(Brush_Style);
|
||||
#undef RENDERIVE_ENUM_ADAPTER
|
||||
|
||||
template <>
|
||||
struct Enum_Adapter<renderive::web::gallery_adminive::Number_Locale_Choice>
|
||||
: renderive::web::gallery_adminive::Actual_Enum_Adapter<
|
||||
renderive::web::gallery_adminive::Number_Locale_Choice> {};
|
||||
|
||||
template <>
|
||||
struct Enum_Adapter<renderive::web::gallery_adminive::Color_Map_Choice>
|
||||
: renderive::web::gallery_adminive::Actual_Enum_Adapter<
|
||||
renderive::web::gallery_adminive::Color_Map_Choice> {};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Color, Json> {
|
||||
using value_type = std::string;
|
||||
static std::string read(renderive::Color value) {
|
||||
char result[8]{};
|
||||
std::snprintf(result, sizeof(result), "#%02x%02x%02x", value.r, value.g, value.b);
|
||||
return result;
|
||||
}
|
||||
static void write(renderive::Color& target, const std::string& value) {
|
||||
if (value.size() != 7 || value.front() != '#' ||
|
||||
!std::all_of(value.begin() + 1, value.end(), [](unsigned char character) {
|
||||
return std::isxdigit(character) != 0;
|
||||
}))
|
||||
throw std::invalid_argument("color must use #RRGGBB");
|
||||
const auto channel = [&value](std::size_t offset) {
|
||||
return static_cast<std::uint8_t>(std::stoul(value.substr(offset, 2), nullptr, 16));
|
||||
};
|
||||
target.r = channel(1);
|
||||
target.g = channel(3);
|
||||
target.b = channel(5);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Number_Locale, Json> {
|
||||
using Choice = renderive::web::gallery_adminive::Number_Locale_Choice;
|
||||
using value_type = Choice;
|
||||
static Choice read(renderive::Number_Locale value) {
|
||||
return value.decimal_point == ',' ? Choice::Comma : Choice::Point;
|
||||
}
|
||||
static void write(renderive::Number_Locale& target, Choice value) {
|
||||
target.decimal_point = value == Choice::Comma ? ',' : '.';
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, T Minimum, T Maximum, T Default, class Json>
|
||||
struct Value_Adapter<renderive::Clamped_Property<T, Minimum, Maximum, Default>, Json> {
|
||||
using Storage = renderive::Clamped_Property<T, Minimum, Maximum, Default>;
|
||||
using value_type = T;
|
||||
static constexpr T minimum = Minimum;
|
||||
static constexpr T maximum = Maximum;
|
||||
static T read(const Storage& value) noexcept { return value.get(); }
|
||||
static void write(Storage& target, T value) { target = value; }
|
||||
};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Unit_Interval, Json> {
|
||||
using value_type = double;
|
||||
static constexpr double minimum = 0.0;
|
||||
static constexpr double maximum = 1.0;
|
||||
static constexpr double multiple_of = 0.01;
|
||||
static double read(const renderive::Unit_Interval& value) noexcept { return value.get(); }
|
||||
static void write(renderive::Unit_Interval& target, double value) { target = value; }
|
||||
};
|
||||
|
||||
template <class Json>
|
||||
struct Value_Adapter<renderive::Color_Map, Json> {
|
||||
using Choice = renderive::web::gallery_adminive::Color_Map_Choice;
|
||||
using value_type = Choice;
|
||||
static Choice read(const renderive::Color_Map& value) {
|
||||
const auto name = renderive::web::gallery_adminive::color_map_name(value);
|
||||
if (name == "Ember")
|
||||
return Choice::Ember;
|
||||
if (name == "Grayscale")
|
||||
return Choice::Grayscale;
|
||||
return Choice::Spectrum;
|
||||
}
|
||||
static void write(renderive::Color_Map& target, Choice value) {
|
||||
const std::string_view name = value == Choice::Ember ? "Ember" :
|
||||
value == Choice::Grayscale ? "Grayscale" : "Spectrum";
|
||||
target = renderive::web::gallery_adminive::color_map(name);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Range> {
|
||||
static auto get() {
|
||||
using T = renderive::Range;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("range", "Range",
|
||||
number<&T::origin>("origin", "Origin"),
|
||||
number<&T::target>("target", "Target"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Pen> {
|
||||
static auto get() {
|
||||
using T = renderive::Pen;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("pen", "Pen",
|
||||
color<&T::color>("color", "Color"),
|
||||
number<&T::width>("width", "Width"),
|
||||
select<&T::style>("style", "Style"),
|
||||
select<&T::cap>("cap", "Cap"),
|
||||
select<&T::join>("join", "Join"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Brush> {
|
||||
static auto get() {
|
||||
using T = renderive::Brush;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("brush", "Brush",
|
||||
color<&T::color>("color", "Color"),
|
||||
select<&T::style>("style", "Style"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::Font> {
|
||||
static auto get() {
|
||||
using T = renderive::Font;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("font", "Font",
|
||||
number<&T::size>("size", "Size"),
|
||||
number<&T::weight>("weight", "Weight"),
|
||||
boolean<&T::italic>("italic", "Italic"));
|
||||
}
|
||||
};
|
||||
|
||||
#define RENDERIVE_AXIS_DESCRIPTOR(GalleryType, Name, Label) \
|
||||
template <> struct Type_Descriptor<renderive::web::GalleryType> { \
|
||||
static auto get() { \
|
||||
using T = renderive::web::GalleryType; \
|
||||
using B = renderive::Axis_Base_Properties; \
|
||||
using P = renderive::Axis_Properties; \
|
||||
using namespace renderive::web::gallery_adminive; \
|
||||
return adminive::object<T>(Name, Label, \
|
||||
readonly_property<T, &B::x>("x", "X"), \
|
||||
readonly_property<T, &B::y>("y", "Y"), \
|
||||
property_select<T, &B::orientation>("orientation", "Orientation"), \
|
||||
readonly_property<T, &B::pixel_length>("pixel_length", "Pixel length"), \
|
||||
property_number<T, &B::tick_length>("tick_length", "Tick length"), \
|
||||
property_number<T, &B::sub_tick_length>("sub_tick_length", "Sub tick length"), \
|
||||
property_color<T, &B::color>("color", "Color"), \
|
||||
property_select<T, &B::locale>("locale", "Decimal separator"), \
|
||||
property_text<T, &B::unit_text>("unit_text", "Unit text"), \
|
||||
property_object<T, &B::unit_text_font>("unit_text_font", "Unit font"), \
|
||||
property_object<T, &B::unit_text_pen>("unit_text_pen", "Unit pen"), \
|
||||
property_object<T, &B::unit_text_background_brush>("unit_text_background_brush", "Unit background"), \
|
||||
property_number<T, &B::label_rotation_degrees>("label_rotation_degrees", "Label rotation"), \
|
||||
property_object<T, &P::coordinates>("coordinates", "Coordinates"), \
|
||||
property_number<T, &P::precision>("precision", "Precision"), \
|
||||
property_boolean<T, &P::wheel>("wheel", "Wheel zoom"), \
|
||||
property_boolean<T, &P::drag>("drag", "Drag pan")); \
|
||||
} \
|
||||
}
|
||||
|
||||
RENDERIVE_AXIS_DESCRIPTOR(Gallery_Axis, "gallery_axis", "Axis");
|
||||
RENDERIVE_AXIS_DESCRIPTOR(Gallery_Frequency_Axis, "gallery_frequency_axis", "Frequency axis");
|
||||
#undef RENDERIVE_AXIS_DESCRIPTOR
|
||||
|
||||
template <>
|
||||
struct Type_Descriptor<renderive::web::Gallery_Time_Axis> {
|
||||
static auto get() {
|
||||
using T = renderive::web::Gallery_Time_Axis;
|
||||
using B = renderive::Axis_Base_Properties;
|
||||
using P = renderive::Time_Axis_Properties;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
return adminive::object<T>("gallery_time_axis", "Time axis",
|
||||
readonly_property<T, &B::x>("x", "X"),
|
||||
readonly_property<T, &B::y>("y", "Y"),
|
||||
property_select<T, &B::orientation>("orientation", "Orientation"),
|
||||
readonly_property<T, &B::pixel_length>("pixel_length", "Pixel length"),
|
||||
property_number<T, &B::tick_length>("tick_length", "Tick length"),
|
||||
property_number<T, &B::sub_tick_length>("sub_tick_length", "Sub tick length"),
|
||||
property_color<T, &B::color>("color", "Color"),
|
||||
property_select<T, &B::locale>("locale", "Decimal separator"),
|
||||
property_text<T, &B::unit_text>("unit_text", "Unit text"),
|
||||
property_object<T, &B::unit_text_font>("unit_text_font", "Unit font"),
|
||||
property_object<T, &B::unit_text_pen>("unit_text_pen", "Unit pen"),
|
||||
property_object<T, &B::unit_text_background_brush>("unit_text_background_brush", "Unit background"),
|
||||
property_number<T, &B::label_rotation_degrees>("label_rotation_degrees", "Label rotation"),
|
||||
property_number<T, &P::visible_count>("visible_count", "Visible points"),
|
||||
property_number<T, &P::tick_label_spacing_px>("tick_label_spacing_px", "Label spacing"),
|
||||
property_text<T, &P::format>("format", "Time format"),
|
||||
property_boolean<T, &P::newest_at_start>("newest_at_start", "Newest at start"));
|
||||
}
|
||||
};
|
||||
|
||||
#define RENDERIVE_GALLERY_DESCRIPTOR(GalleryType, PropertiesType, Label, ...) \
|
||||
template <> struct Type_Descriptor<renderive::web::GalleryType> { \
|
||||
static auto get() { \
|
||||
using T = renderive::web::GalleryType; \
|
||||
using P = renderive::PropertiesType; \
|
||||
using namespace renderive::web::gallery_adminive; \
|
||||
return adminive::object<T>(#GalleryType, Label, __VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Spectrum, Spectrum_Properties, "Spectrum",
|
||||
property_number<T, &P::frequency_point_size>("frequency_point_size", "Frequency points"),
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_number<T, &P::center_frequency>("center_frequency", "Center frequency"),
|
||||
property_object<T, &P::sweep_frequency_range>("sweep_frequency_range", "Sweep range"),
|
||||
property_boolean<T, &P::max_hold_visible>("max_hold_visible", "Max hold"),
|
||||
property_boolean<T, &P::min_hold_visible>("min_hold_visible", "Min hold"),
|
||||
property_boolean<T, &P::max_marker_visible>("max_marker_visible", "Max marker"),
|
||||
property_boolean<T, &P::use_min_marker>("use_min_marker", "Use min marker"),
|
||||
property_boolean<T, &P::sweep_region_visible>("sweep_region_visible", "Sweep region"),
|
||||
property_boolean<T, &P::visible_range_only>("visible_range_only", "Visible range only"),
|
||||
property_select<T, &P::interpolation_mode>("interpolation_mode", "Interpolation"),
|
||||
property_object<T, &P::max_brush>("max_brush", "Max brush"),
|
||||
property_object<T, &P::current_brush>("current_brush", "Current brush"),
|
||||
property_object<T, &P::min_brush>("min_brush", "Min brush"),
|
||||
property_object<T, &P::max_pen>("max_pen", "Max pen"),
|
||||
property_object<T, &P::current_pen>("current_pen", "Current pen"),
|
||||
property_object<T, &P::min_pen>("min_pen", "Min pen"),
|
||||
property_object<T, &P::selected_marker_pen>("selected_marker_pen", "Selected marker pen"),
|
||||
property_object<T, &P::marker_pen>("marker_pen", "Marker pen"),
|
||||
property_object<T, &P::middle_frequency_pen>("middle_frequency_pen", "Middle frequency pen"),
|
||||
property_object<T, &P::sweep_region_brush>("sweep_region_brush", "Sweep region brush"),
|
||||
property_boolean<T, &P::tooltip_enabled>("tooltip_enabled", "Tooltip"),
|
||||
property_object<T, &P::tooltip_font>("tooltip_font", "Tooltip font"),
|
||||
property_object<T, &P::tooltip_text_pen>("tooltip_text_pen", "Tooltip text pen"),
|
||||
property_object<T, &P::tooltip_background_brush>("tooltip_background_brush", "Tooltip background"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Waterfall, Waterfall_Properties, "Waterfall",
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_object<T, &P::power_range>("power_range", "Power range"),
|
||||
property_number<T, &P::frequency_bin_count>("frequency_bin_count", "Frequency bins"),
|
||||
property_boolean<T, &P::visible_range_only>("visible_range_only", "Visible range only"),
|
||||
property_select<T, &P::interpolation_mode>("interpolation_mode", "Interpolation"),
|
||||
property_select<T, &P::color_map>("color_map", "Color map"),
|
||||
property_boolean<T, &P::tooltip_enabled>("tooltip_enabled", "Tooltip"),
|
||||
property_object<T, &P::tooltip_font>("tooltip_font", "Tooltip font"),
|
||||
property_object<T, &P::tooltip_text_pen>("tooltip_text_pen", "Tooltip text pen"),
|
||||
property_object<T, &P::tooltip_background_brush>("tooltip_background_brush", "Tooltip background"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Afterglow, Afterglow_Properties, "Afterglow",
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_object<T, &P::power_range>("power_range", "Power range"),
|
||||
property_number<T, &P::frequency_point_size>("frequency_point_size", "Frequency points"),
|
||||
property_number<T, &P::power_point_size>("power_point_size", "Power points"),
|
||||
property_boolean<T, &P::interpolate>("interpolate", "Interpolate power"),
|
||||
property_number<T, &P::attenuation_rate>("attenuation_rate", "Attenuation"),
|
||||
property_select<T, &P::color_map>("color_map", "Color map"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Sweep_Spectrum, Sweep_Spectrum_Properties, "Sweep spectrum",
|
||||
property_object<T, &P::frequency_range>("frequency_range", "Frequency range"),
|
||||
property_number<T, &P::bins_per_block>("bins_per_block", "Bins per block"),
|
||||
property_number<T, &P::block_count>("block_count", "Block count"),
|
||||
property_object<T, &P::pen>("pen", "Sweep pen"),
|
||||
property_object<T, &P::current_frequency_pen>("current_frequency_pen", "Current frequency pen"),
|
||||
property_boolean<T, &P::visible_range_only>("visible_range_only", "Visible range only"),
|
||||
property_select<T, &P::interpolation_mode>("interpolation_mode", "Interpolation"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Frequency_Trace, Frequency_Trace_Properties, "Frequency trace",
|
||||
property_object<T, &P::pen>("pen", "Trace pen"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Selection_Rectangle_Overlay, Selection_Rectangle_Overlay_Properties, "Selection overlay",
|
||||
property_object<T, &P::label_font>("label_font", "Label font"),
|
||||
property_object<T, &P::label_pen>("label_pen", "Label pen"),
|
||||
property_object<T, &P::selection_brush>("selection_brush", "Selection brush"),
|
||||
property_object<T, &P::selection_border_pen>("selection_border_pen", "Selection border"));
|
||||
|
||||
RENDERIVE_GALLERY_DESCRIPTOR(Gallery_Constellation_Diagram, Constellation_Diagram_Properties, "Constellation diagram",
|
||||
property_object<T, &P::i_range>("i_range", "I range"),
|
||||
property_object<T, &P::q_range>("q_range", "Q range"),
|
||||
property_color<T, &P::point_color>("point_color", "Point color"),
|
||||
property_color<T, &P::anchor_color>("anchor_color", "Anchor color"),
|
||||
property_number<T, &P::point_lifetime_ms>("point_lifetime_ms", "Point lifetime"),
|
||||
property_select<T, &P::type>("type", "Constellation"),
|
||||
property_number<T, &P::phase_offset_radians>("phase_offset_radians", "Phase offset"));
|
||||
|
||||
#undef RENDERIVE_GALLERY_DESCRIPTOR
|
||||
|
||||
} // namespace adminive
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gallery_Session_Control.h"
|
||||
#include "Gallery_Renderables_Adminive.h"
|
||||
#include "Gallery_Renderables.h"
|
||||
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
@@ -44,7 +44,7 @@ struct Type_Descriptor<renderive::web::Gallery_Session_Control> {
|
||||
using T = renderive::web::Gallery_Session_Control;
|
||||
using namespace renderive::web::gallery_adminive;
|
||||
const auto dirty = [](T& value) { value.plot_.notify_model_dirty(); };
|
||||
return adminive::object<T>("gallery_session", "Scene",
|
||||
return adminive::object<T>("scene", "Scene",
|
||||
callback_property<T, renderive::Color>(
|
||||
"background_color", "Background", Field_Control::color,
|
||||
[](const T& value) { return value.plot_.background_color(); },
|
||||
|
||||
@@ -293,7 +293,7 @@ TEST(RenderiveWebGallery, AdminiveResourcesPatchTheRealRenderableState) {
|
||||
};
|
||||
|
||||
const auto& spectrum = find_resource(response, "spectrum");
|
||||
EXPECT_EQ(spectrum.at("descriptor").at("name"), "Gallery_Spectrum");
|
||||
EXPECT_EQ(spectrum.at("descriptor").at("name"), "spectrum");
|
||||
EXPECT_TRUE(spectrum.at("data").at("frequency_range").is_object());
|
||||
EXPECT_EQ(spectrum.at("data").at("frequency_point_size"), 512);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user