功能比较完善的一版
This commit is contained in:
+44
-69
@@ -97,7 +97,7 @@ public:
|
||||
nlohmann::json schema() const override {
|
||||
nlohmann::json components = nlohmann::json::array();
|
||||
for (const auto& descriptor : descriptors) components.push_back(descriptor->schema());
|
||||
return {{"protocol", "aethera.plot.inspector"}, {"version", 1}, {"components", std::move(components)}};
|
||||
return {{"protocol", "aethera.plot.inspector"}, {"version", 2}, {"components", std::move(components)}};
|
||||
}
|
||||
nlohmann::json write_prop(std::string_view component, std::string_view key, const nlohmann::json& value) override {
|
||||
const auto found = std::ranges::find_if(descriptors, [&](const auto& item) { return item->id() == component; });
|
||||
@@ -145,6 +145,7 @@ std::unique_ptr<detail::Renderable_Descriptor> make_scene_component(Scene_Object
|
||||
using Definition = typename Scene_Object::Attached_Object;
|
||||
using Prop = typename Definition::Prop;
|
||||
using Adapter = detail::Renderable_Adapter<Scene_Object,
|
||||
detail::Prop_Field<&Prop::viewport, "viewport", "Final scene viewport in physical pixels.">,
|
||||
detail::Prop_Field<&Prop::background, "background", "Scene clear color.">,
|
||||
detail::Prop_Field<&Prop::view_active, "view_active", "Whether the scene publishes rendered frames.">,
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_rebuilt, "taskflow_rebuilt", "Whether the scene task graph was rebuilt.">,
|
||||
@@ -154,7 +155,7 @@ std::unique_ptr<detail::Renderable_Descriptor> make_scene_component(Scene_Object
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_max_predecessors, "taskflow_max_predecessors", "Maximum direct predecessors of a task.">,
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_max_successors, "taskflow_max_successors", "Maximum direct successors of a task.">,
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_execution_time_ns, "taskflow_execution_time_ns", "Scene graph execution time in nanoseconds.">>;
|
||||
return detail::make_renderable_descriptor("scene", "Scene", "scene", Adapter{scene});
|
||||
return detail::make_renderable_descriptor("scene", "场景", "scene", Adapter{scene});
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -169,33 +170,14 @@ std::unique_ptr<detail::Renderable_Descriptor> make_scene_component<Scene_3D>(Sc
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_max_predecessors, "taskflow_max_predecessors", "Maximum direct predecessors of a task.">,
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_max_successors, "taskflow_max_successors", "Maximum direct successors of a task.">,
|
||||
detail::State_Field<Scene::Base_Tag, &Scene::State::taskflow_execution_time_ns, "taskflow_execution_time_ns", "Scene graph execution time in nanoseconds.">>;
|
||||
return detail::make_renderable_descriptor("scene", "Scene", "scene", Adapter{scene});
|
||||
return detail::make_renderable_descriptor("scene", "场景", "scene", Adapter{scene});
|
||||
}
|
||||
|
||||
template <typename Axis_Object>
|
||||
std::unique_ptr<detail::Renderable_Descriptor> make_axis_component(
|
||||
std::string id, std::string label, Axis_Object& axis) {
|
||||
using Adapter = detail::Renderable_Adapter<Axis_Object,
|
||||
Prop_Field<&Abs_Axis::Prop::position, "position", "Axis origin in viewport pixels.">,
|
||||
Prop_Field<&Abs_Axis::Prop::canvas_size, "canvas_size", "Axis canvas extent.">,
|
||||
Prop_Field<&Abs_Axis::Prop::pixel_length, "pixel_length", "Signed axis length in pixels.">,
|
||||
Prop_Field<&Abs_Axis::Prop::orientation, "orientation", "Axis orientation.">,
|
||||
Prop_Field<&Abs_Axis::Prop::tick_length, "tick_length", "Major tick length.">,
|
||||
Prop_Field<&Abs_Axis::Prop::sub_tick_length, "sub_tick_length", "Minor tick length.">,
|
||||
Prop_Field<&Abs_Axis::Prop::axis_pen, "axis_pen", "Axis line and tick style.">,
|
||||
Prop_Field<&Abs_Axis::Prop::unit_text, "unit_text", "Axis unit label.">,
|
||||
Prop_Field<&Abs_Axis::Prop::unit_text_font, "unit_text_font", "Axis label font.">,
|
||||
Prop_Field<&Abs_Axis::Prop::unit_text_pen, "unit_text_pen", "Axis label foreground.">,
|
||||
Prop_Field<&Abs_Axis::Prop::unit_text_background_brush, "unit_text_background_brush", "Axis label background.">,
|
||||
Prop_Field<&Abs_Axis::Prop::label_rotation_degrees, "label_rotation_degrees", "Tick label rotation.">,
|
||||
Prop_Field<&Numeric_Axis::Prop::coordinate_range, "coordinate_range", "Visible coordinate range.">,
|
||||
Prop_Field<&Numeric_Axis::Prop::precision, "precision", "Maximum decimal precision.">,
|
||||
Prop_Field<&Numeric_Axis::Prop::locale, "locale", "Numeric label locale.">,
|
||||
Prop_Field<&Numeric_Axis::Prop::wheel_enabled, "wheel_enabled", "Allows wheel zoom.">,
|
||||
Prop_Field<&Numeric_Axis::Prop::drag_enabled, "drag_enabled", "Allows pointer drag panning.">>;
|
||||
return make_renderable_component<Axis_Object,
|
||||
Prop_Field<&Abs_Axis::Prop::position, "position", "Axis origin in viewport pixels.">,
|
||||
Prop_Field<&Abs_Axis::Prop::canvas_size, "canvas_size", "Axis canvas extent.">,
|
||||
Prop_Field<&Abs_Axis::Prop::pixel_length, "pixel_length", "Signed axis length in pixels.">,
|
||||
Prop_Field<&Abs_Axis::Prop::orientation, "orientation", "Axis orientation.">,
|
||||
Prop_Field<&Abs_Axis::Prop::tick_length, "tick_length", "Major tick length.">,
|
||||
@@ -219,7 +201,6 @@ std::unique_ptr<detail::Renderable_Descriptor> make_axis_component<Time_Axis_Obj
|
||||
std::string id, std::string label, Time_Axis_Object& axis) {
|
||||
return make_renderable_component<Time_Axis_Object,
|
||||
Prop_Field<&Abs_Axis::Prop::position, "position", "Axis origin in viewport pixels.">,
|
||||
Prop_Field<&Abs_Axis::Prop::canvas_size, "canvas_size", "Axis canvas extent.">,
|
||||
Prop_Field<&Abs_Axis::Prop::pixel_length, "pixel_length", "Signed axis length in pixels.">,
|
||||
Prop_Field<&Abs_Axis::Prop::orientation, "orientation", "Axis orientation.">,
|
||||
Prop_Field<&Abs_Axis::Prop::tick_length, "tick_length", "Major tick length.">,
|
||||
@@ -251,7 +232,7 @@ std::unique_ptr<Plot::Scene_View> make_scene_view(
|
||||
using State = typename Definition::State;
|
||||
std::vector<std::unique_ptr<detail::Renderable_Descriptor>> components;
|
||||
components.push_back(make_scene_component(scene));
|
||||
components.push_back(make_renderable_component<Object, Fields...>("plot", "Plot Renderable", "renderable", object));
|
||||
components.push_back(make_renderable_component<Object, Fields...>("plot", "主绘图组件", "renderable", object));
|
||||
std::size_t axis_index{};
|
||||
const auto append_owned = [&](const auto& owned) {
|
||||
using Owned = std::remove_cvref_t<decltype(owned)>;
|
||||
@@ -259,7 +240,7 @@ std::unique_ptr<Plot::Scene_View> make_scene_view(
|
||||
|| std::same_as<typename Owned::element_type, Numeric_Axis_Object>
|
||||
|| std::same_as<typename Owned::element_type, Time_Axis_Object>) {
|
||||
const auto id = axis_index++ == 0 ? "axis-x" : "axis-y";
|
||||
components.push_back(make_axis_component(id, id == std::string_view{"axis-x"} ? "Horizontal Axis" : "Vertical Axis", *owned));
|
||||
components.push_back(make_axis_component(id, id == std::string_view{"axis-x"} ? "横向坐标轴" : "纵向坐标轴", *owned));
|
||||
}
|
||||
};
|
||||
(append_owned(owned_objects), ...);
|
||||
@@ -269,51 +250,46 @@ std::unique_ptr<Plot::Scene_View> make_scene_view(
|
||||
std::forward<Owned_Objects>(owned_objects)...);
|
||||
}
|
||||
|
||||
Frequency_Axis_Object::Builder frequency_axis_builder(Size canvas) {
|
||||
Frequency_Axis_Object::Builder frequency_axis_builder() {
|
||||
Frequency_Axis_Object::Builder builder;
|
||||
builder
|
||||
.set(&Abs_Axis::Prop::orientation, Axis_Orientation::horizontal)
|
||||
.set(&Abs_Axis::Prop::position, Point_F{64.0, 370.0})
|
||||
.set(&Abs_Axis::Prop::pixel_length, 620.0)
|
||||
.set(&Abs_Axis::Prop::canvas_size, canvas)
|
||||
.set(&Numeric_Axis::Prop::coordinate_range, Axis_Range{0.0, 100.0});
|
||||
return builder;
|
||||
}
|
||||
|
||||
Numeric_Axis_Object::Builder numeric_axis_builder(
|
||||
Axis_Orientation orientation, Point_F position, Axis_Pixel_Length length,
|
||||
Axis_Range range, Size canvas) {
|
||||
Axis_Range range) {
|
||||
Numeric_Axis_Object::Builder builder;
|
||||
builder
|
||||
.set(&Abs_Axis::Prop::orientation, orientation)
|
||||
.set(&Abs_Axis::Prop::position, position)
|
||||
.set(&Abs_Axis::Prop::pixel_length, length)
|
||||
.set(&Abs_Axis::Prop::canvas_size, canvas)
|
||||
.set(&Numeric_Axis::Prop::coordinate_range, range);
|
||||
return builder;
|
||||
}
|
||||
|
||||
Time_Axis_Object::Builder time_axis_builder(
|
||||
Axis_Orientation orientation, Point_F position, Axis_Pixel_Length length, Size canvas) {
|
||||
Axis_Orientation orientation, Point_F position, Axis_Pixel_Length length) {
|
||||
Time_Axis_Object::Builder builder;
|
||||
builder
|
||||
.set(&Abs_Axis::Prop::orientation, orientation)
|
||||
.set(&Abs_Axis::Prop::position, position)
|
||||
.set(&Abs_Axis::Prop::pixel_length, length)
|
||||
.set(&Abs_Axis::Prop::canvas_size, canvas);
|
||||
.set(&Abs_Axis::Prop::pixel_length, length);
|
||||
return builder;
|
||||
}
|
||||
|
||||
template <typename... Axes>
|
||||
void resize_axes(Size viewport, Axes*... axes) {
|
||||
void resize_axes(Scene_2D* scene, Size viewport, Axes*... axes) {
|
||||
const Size previous_viewport = scene->template read_prop<Render_Scene_2D::Base_Tag>().viewport;
|
||||
if (previous_viewport == viewport || previous_viewport.empty()) return;
|
||||
const auto resize_axis = [&](auto* axis) {
|
||||
const auto layout = axis->template read_prop<Abs_Axis::Base_Tag>();
|
||||
if (layout.canvas_size == viewport) return;
|
||||
const double horizontal_scale = layout.canvas_size.width > 0
|
||||
? static_cast<double>(viewport.width) / layout.canvas_size.width : 1.0;
|
||||
const double vertical_scale = layout.canvas_size.height > 0
|
||||
? static_cast<double>(viewport.height) / layout.canvas_size.height : 1.0;
|
||||
axis->template set<&Abs_Axis::Prop::canvas_size>(viewport);
|
||||
const double horizontal_scale = static_cast<double>(viewport.width) / previous_viewport.width;
|
||||
const double vertical_scale = static_cast<double>(viewport.height) / previous_viewport.height;
|
||||
axis->template set<&Abs_Axis::Prop::position>(Point_F{
|
||||
layout.position.x * horizontal_scale,
|
||||
layout.position.y * vertical_scale});
|
||||
@@ -373,9 +349,9 @@ void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
|
||||
|
||||
std::shared_ptr<Plot> make_spectrum_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto frequency = *frequency_axis_builder(canvas).build();
|
||||
auto frequency = *frequency_axis_builder().build();
|
||||
auto vertical = *numeric_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-110.0, 0.0}, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-110.0, 0.0}).build();
|
||||
Impl<Spectrum>::Builder spectrum_builder(frequency.get(), vertical.get());
|
||||
spectrum_builder.set(&Spectrum::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set(&Spectrum::Prop::max_hold_visible, true);
|
||||
@@ -386,8 +362,8 @@ std::shared_ptr<Plot> make_spectrum_plot(asio::any_io_executor executor) {
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(spectrum.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = spectrum.get(), frequency = frequency.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, vertical);
|
||||
auto update = [scene = scene.get(), raw = spectrum.get(), frequency = frequency.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, vertical);
|
||||
if (event.input) return;
|
||||
std::array<double, 256> samples{};
|
||||
for (std::size_t i = 0; i < samples.size(); ++i) {
|
||||
@@ -433,9 +409,9 @@ std::shared_ptr<Plot> make_spectrum_plot(asio::any_io_executor executor) {
|
||||
std::shared_ptr<Plot> make_frequency_trace_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto time = *time_axis_builder(
|
||||
Axis_Orientation::horizontal, {64.0, 370.0}, 620.0, canvas).build();
|
||||
Axis_Orientation::horizontal, {64.0, 370.0}, 620.0).build();
|
||||
auto vertical = *numeric_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-1.2, 1.2}, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-1.2, 1.2}).build();
|
||||
auto trace = *Impl<Frequency_Trace>::Builder(time.get(), vertical.get()).build();
|
||||
Scene_2D::Builder scene_builder;
|
||||
scene_builder.set(&Render_Scene_2D::Prop::viewport, canvas)
|
||||
@@ -443,8 +419,8 @@ std::shared_ptr<Plot> make_frequency_trace_plot(asio::any_io_executor executor)
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(trace.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = trace.get(), time = time.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, time, vertical);
|
||||
auto update = [scene = scene.get(), raw = trace.get(), time = time.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, time, vertical);
|
||||
if (event.input) return;
|
||||
constexpr double day_milliseconds = 86'400'000.0;
|
||||
raw->append_sample(Time_Of_Day{static_cast<std::int64_t>(
|
||||
@@ -465,9 +441,9 @@ std::shared_ptr<Plot> make_frequency_trace_plot(asio::any_io_executor executor)
|
||||
|
||||
std::shared_ptr<Plot> make_sweep_spectrum_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto frequency = *frequency_axis_builder(canvas).build();
|
||||
auto frequency = *frequency_axis_builder().build();
|
||||
auto vertical = *numeric_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-110.0, 0.0}, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-110.0, 0.0}).build();
|
||||
Impl<Sweep_Spectrum>::Builder sweep_builder(frequency.get(), vertical.get());
|
||||
sweep_builder.set(&Sweep_Spectrum::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set(&Sweep_Spectrum::Prop::bins_per_block, std::size_t{8})
|
||||
@@ -479,8 +455,8 @@ std::shared_ptr<Plot> make_sweep_spectrum_plot(asio::any_io_executor executor) {
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(sweep.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = sweep.get(), frequency = frequency.get(), vertical = vertical.get(), block_index = std::size_t{}](const Plot_Event& event) mutable {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, vertical);
|
||||
auto update = [scene = scene.get(), raw = sweep.get(), frequency = frequency.get(), vertical = vertical.get(), block_index = std::size_t{}](const Plot_Event& event) mutable {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, vertical);
|
||||
if (event.input) return;
|
||||
const auto& state = raw->template read_prop<Sweep_Spectrum::Base_Tag>();
|
||||
const std::size_t block_count = std::max<std::size_t>(1, state.block_count);
|
||||
@@ -517,9 +493,9 @@ std::shared_ptr<Plot> make_sweep_spectrum_plot(asio::any_io_executor executor) {
|
||||
|
||||
std::shared_ptr<Plot> make_afterglow_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto frequency = *frequency_axis_builder(canvas).build();
|
||||
auto frequency = *frequency_axis_builder().build();
|
||||
auto vertical = *numeric_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-110.0, 0.0}, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-110.0, 0.0}).build();
|
||||
Impl<Afterglow>::Builder afterglow_builder(frequency.get(), vertical.get());
|
||||
afterglow_builder.set(&Afterglow::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set(&Afterglow::Prop::power_range, Axis_Range{-110.0, 0.0})
|
||||
@@ -531,8 +507,8 @@ std::shared_ptr<Plot> make_afterglow_plot(asio::any_io_executor executor) {
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(afterglow.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = afterglow.get(), frequency = frequency.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, vertical);
|
||||
auto update = [scene = scene.get(), raw = afterglow.get(), frequency = frequency.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, vertical);
|
||||
if (event.input) return;
|
||||
std::array<double, 192> values{};
|
||||
for (std::size_t i = 0; i < values.size(); ++i)
|
||||
@@ -561,9 +537,9 @@ std::shared_ptr<Plot> make_afterglow_plot(asio::any_io_executor executor) {
|
||||
|
||||
std::shared_ptr<Plot> make_waterfall_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto frequency = *frequency_axis_builder(canvas).build();
|
||||
auto frequency = *frequency_axis_builder().build();
|
||||
auto time = *time_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0).build();
|
||||
Impl<Waterfall>::Builder waterfall_builder(frequency.get(), time.get());
|
||||
waterfall_builder.set(&Waterfall::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set(&Waterfall::Prop::power_range, Axis_Range{-110.0, 0.0});
|
||||
@@ -574,8 +550,8 @@ std::shared_ptr<Plot> make_waterfall_plot(asio::any_io_executor executor) {
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(waterfall.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = waterfall.get(), frequency = frequency.get(), time = time.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, time);
|
||||
auto update = [scene = scene.get(), raw = waterfall.get(), frequency = frequency.get(), time = time.get()](const Plot_Event& event) {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, time);
|
||||
if (event.input) return;
|
||||
std::array<double, 192> values{};
|
||||
for (std::size_t i = 0; i < values.size(); ++i)
|
||||
@@ -610,9 +586,9 @@ std::shared_ptr<Plot> make_waterfall_plot(asio::any_io_executor executor) {
|
||||
std::shared_ptr<Plot> make_constellation_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto horizontal = *numeric_axis_builder(
|
||||
Axis_Orientation::horizontal, {64.0, 370.0}, 620.0, {-1.2, 1.2}, canvas).build();
|
||||
Axis_Orientation::horizontal, {64.0, 370.0}, 620.0, {-1.2, 1.2}).build();
|
||||
auto vertical = *numeric_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-1.2, 1.2}, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {-1.2, 1.2}).build();
|
||||
Impl<Constellation_Diagram>::Builder constellation_builder(horizontal.get(), vertical.get());
|
||||
constellation_builder.set(&Constellation_Diagram::Prop::i_range, Axis_Range{-1.2, 1.2})
|
||||
.set(&Constellation_Diagram::Prop::q_range, Axis_Range{-1.2, 1.2});
|
||||
@@ -623,8 +599,8 @@ std::shared_ptr<Plot> make_constellation_plot(asio::any_io_executor executor) {
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(constellation.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = constellation.get(), horizontal = horizontal.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, horizontal, vertical);
|
||||
auto update = [scene = scene.get(), raw = constellation.get(), horizontal = horizontal.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, horizontal, vertical);
|
||||
if (event.input) return;
|
||||
const auto& state = raw->template read_prop<Constellation_Diagram::Base_Tag>();
|
||||
const int anchor_count = static_cast<int>(state.type);
|
||||
@@ -658,9 +634,9 @@ std::shared_ptr<Plot> make_constellation_plot(asio::any_io_executor executor) {
|
||||
std::shared_ptr<Plot> make_selection_overlay_plot(asio::any_io_executor executor) {
|
||||
constexpr Size canvas{720, 420};
|
||||
auto horizontal = *numeric_axis_builder(
|
||||
Axis_Orientation::horizontal, {64.0, 370.0}, 620.0, {0.0, 100.0}, canvas).build();
|
||||
Axis_Orientation::horizontal, {64.0, 370.0}, 620.0, {0.0, 100.0}).build();
|
||||
auto vertical = *numeric_axis_builder(
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {0.0, 100.0}, canvas).build();
|
||||
Axis_Orientation::vertical, {64.0, 370.0}, -320.0, {0.0, 100.0}).build();
|
||||
auto selection = *Impl<Selection_Rectangle_Overlay>::Builder(horizontal.get(), vertical.get()).build();
|
||||
Scene_2D::Builder scene_builder;
|
||||
scene_builder.set(&Render_Scene_2D::Prop::viewport, canvas)
|
||||
@@ -668,8 +644,8 @@ std::shared_ptr<Plot> make_selection_overlay_plot(asio::any_io_executor executor
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(selection.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [horizontal = horizontal.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, horizontal, vertical);
|
||||
auto update = [scene = scene.get(), horizontal = horizontal.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes(scene, {static_cast<int>(event.width), static_cast<int>(event.height)}, horizontal, vertical);
|
||||
};
|
||||
auto view = make_scene_view<
|
||||
Prop_Field<&Selection_Rectangle_Overlay::Prop::label_font, "label_font", "Font used for labels attached to selected regions.">,
|
||||
@@ -787,7 +763,6 @@ void Plot::attach(const void* owner, Frame_Handler handler) {
|
||||
std::lock_guard lock(d->handlers_mutex);
|
||||
d->handlers.insert_or_assign(owner, std::move(handler));
|
||||
}
|
||||
submit({});
|
||||
}
|
||||
|
||||
void Plot::detach(const void* owner) {
|
||||
@@ -835,7 +810,7 @@ std::shared_ptr<Plot> make_datoviz_point_plot(asio::any_io_executor executor) {
|
||||
detail::State_Field<Point_Visual::Base_Tag, &Point_Visual::State::prepared_revision, "prepared_revision", "Property revision represented by the currently prepared GPU data.">>;
|
||||
std::vector<std::unique_ptr<detail::Renderable_Descriptor>> components;
|
||||
components.push_back(make_scene_component(*scene));
|
||||
components.push_back(detail::make_renderable_descriptor("plot", "Point Visual", "visual", Adapter{*visual}));
|
||||
components.push_back(detail::make_renderable_descriptor("plot", "主绘图组件", "visual", Adapter{*visual}));
|
||||
auto view = std::make_unique<Scene_View_Model<decltype(visual)>>(
|
||||
std::move(components),
|
||||
[](const Plot_Event&) {}, std::move(visual));
|
||||
|
||||
@@ -224,18 +224,82 @@ constexpr std::string_view protocol_editor() {
|
||||
return "json";
|
||||
}
|
||||
|
||||
inline std::string_view protocol_field_label(std::string_view key) {
|
||||
static constexpr std::pair<std::string_view, std::string_view> labels[] = {
|
||||
{"position", "位置"}, {"viewport", "视口尺寸"}, {"background", "背景颜色"},
|
||||
{"clear_color", "清屏颜色"}, {"view_active", "启用视图"},
|
||||
{"pixel_length", "轴线长度"}, {"orientation", "轴线方向"}, {"tick_length", "主刻度长度"},
|
||||
{"sub_tick_length", "次刻度长度"}, {"axis_pen", "轴线画笔"}, {"unit_text", "单位文字"},
|
||||
{"unit_text_font", "单位字体"}, {"unit_text_pen", "单位文字画笔"},
|
||||
{"unit_text_background_brush", "单位文字背景"}, {"label_rotation_degrees", "标签旋转角度"},
|
||||
{"coordinate_range", "坐标范围"}, {"precision", "小数精度"}, {"locale", "数字区域格式"},
|
||||
{"wheel_enabled", "允许滚轮缩放"}, {"drag_enabled", "允许拖动平移"},
|
||||
{"visible_count", "可见数量"}, {"tick_label_spacing_px", "刻度文字间距"},
|
||||
{"estimated_label_width_px", "预计标签宽度"}, {"format", "时间格式"},
|
||||
{"newest_at_start", "最新数据置于起点"}, {"center_frequency", "中心频率"},
|
||||
{"partition_count", "分区数量"}, {"partition_mode", "分区模式"},
|
||||
{"interpolation_mode", "插值模式"}, {"visible_range_only", "仅处理可见范围"},
|
||||
{"frequency_range", "频率范围"}, {"power_range", "功率范围"}, {"i_range", "同相范围"},
|
||||
{"q_range", "正交范围"}, {"phase_offset_radians", "相位偏移"}, {"pen", "画笔"},
|
||||
{"samples", "样本数据"}, {"rows", "瀑布图行数据"}, {"color_map", "颜色映射"},
|
||||
{"tooltip_enabled", "启用提示框"}, {"tooltip_font", "提示框字体"},
|
||||
{"tooltip_text_pen", "提示文字画笔"}, {"tooltip_background_brush", "提示框背景"},
|
||||
{"frequency_bin_count", "频率箱数量"}, {"frequency_point_size", "频率网格数量"},
|
||||
{"power_point_size", "功率网格数量"}, {"attenuation_rate", "衰减速率"},
|
||||
{"interpolate", "启用插值"}, {"spectra", "频谱历史"}, {"blocks", "扫频块数据"},
|
||||
{"bins_per_block", "每块频点数"}, {"block_count", "扫频块数量"},
|
||||
{"max_hold_visible", "显示最大保持"}, {"min_hold_visible", "显示最小保持"},
|
||||
{"max_marker_visible", "显示最大标记"}, {"min_marker_visible", "显示最小标记"},
|
||||
{"sweep_region_visible", "显示扫频区域"}, {"sweep_frequency_range", "扫频范围"},
|
||||
{"max_brush", "最大保持画刷"}, {"current_brush", "当前曲线画刷"},
|
||||
{"min_brush", "最小保持画刷"}, {"max_pen", "最大保持画笔"},
|
||||
{"current_pen", "当前曲线画笔"}, {"min_pen", "最小保持画笔"},
|
||||
{"selected_marker_pen", "选中标记画笔"}, {"marker_pen", "标记画笔"},
|
||||
{"middle_frequency_pen", "中心频率画笔"}, {"sweep_region_brush", "扫频区域画刷"},
|
||||
{"current_frequency_pen", "当前频率指示线"}, {"custom_markers", "自定义标记"},
|
||||
{"selected_marker", "当前选中标记"}, {"point_lifetime_ms", "点保留时间"},
|
||||
{"type", "星座类型"}, {"point_color", "数据点颜色"}, {"anchor_color", "参考点颜色"},
|
||||
{"points", "星座点数据"}, {"label_font", "标签字体"}, {"label_pen", "标签画笔"},
|
||||
{"selection_brush", "选区画刷"}, {"selection_border_pen", "选区边框画笔"},
|
||||
{"selected_regions", "已选区域"}, {"transform", "空间变换"}, {"visible", "是否可见"},
|
||||
{"depth_test", "深度测试"}, {"items", "项目数据"},
|
||||
{"prepare_dirty", "准备阶段待更新"}, {"paint_dirty", "绘制阶段待更新"},
|
||||
{"prepare_executed", "准备阶段已执行"}, {"paint_executed", "绘制阶段已执行"},
|
||||
{"prepare_graph_rebuilt", "准备任务图已重建"}, {"paint_graph_rebuilt", "绘制任务图已重建"},
|
||||
{"prepare_task_count", "准备任务数量"}, {"paint_task_count", "绘制任务数量"},
|
||||
{"prepare_execution_time_ns", "准备耗时"}, {"paint_execution_time_ns", "绘制耗时"},
|
||||
{"taskflow_rebuilt", "场景任务图已重建"}, {"renderable_count", "可渲染对象数量"},
|
||||
{"taskflow_task_count", "场景任务数量"}, {"taskflow_dependency_count", "任务依赖数量"},
|
||||
{"taskflow_max_predecessors", "最大前驱数量"}, {"taskflow_max_successors", "最大后继数量"},
|
||||
{"taskflow_execution_time_ns", "场景执行耗时"}, {"next_tick", "下一时间刻度"},
|
||||
{"sample_count", "样本数量"}, {"rendered_point_count", "已绘制点数量"},
|
||||
{"selectable_marker_count", "可选标记数量"}, {"stored_block_count", "已保存数据块数量"},
|
||||
{"stored_point_count", "已保存数据点数量"}, {"history_count", "历史帧数量"},
|
||||
{"latest_spectrum_point_count", "最新频谱点数量"}, {"rendered_cell_count", "已绘制单元数量"},
|
||||
{"row_count", "瀑布图行数量"}, {"point_count", "数据点数量"},
|
||||
{"selected_region_count", "已选区域数量"}, {"item_count", "项目数量"},
|
||||
{"prepared_item_count", "已准备项目数量"}, {"prepared_revision", "已准备修订号"}
|
||||
};
|
||||
const auto found = std::ranges::find_if(labels, [key](const auto& entry) { return entry.first == key; });
|
||||
return found == std::end(labels) ? key : found->second;
|
||||
}
|
||||
|
||||
template <typename Adapter>
|
||||
nlohmann::json adapter_schema(const Adapter& adapter, std::string_view id, std::string_view label, std::string_view kind) {
|
||||
nlohmann::json properties = nlohmann::json::array();
|
||||
nlohmann::json fields = nlohmann::json::array();
|
||||
nlohmann::json state = nlohmann::json::object();
|
||||
structive::type_descriptor<Adapter>().for_each_property([&](auto, const auto& field) {
|
||||
using Field = std::remove_cvref_t<decltype(field)>;
|
||||
using Value = typename Field::value_type;
|
||||
const auto value = field.accessor.read(adapter);
|
||||
if (field.template attribute<Renderable_Field_Role_Category>().value == Renderable_Field_Role::prop) {
|
||||
nlohmann::json item{{"key", field.key()}, {"editor", protocol_editor<Value>()},
|
||||
{"description", std::string(Field::accessor_type::description.view())},
|
||||
{"value", encode_protocol_value(value)}};
|
||||
const bool editable = field.template attribute<Renderable_Field_Role_Category>().value == Renderable_Field_Role::prop;
|
||||
const auto field_label = protocol_field_label(field.key());
|
||||
nlohmann::json item{{"key", field.key()}, {"label", field_label}, {"editor", protocol_editor<Value>()},
|
||||
{"editable", editable},
|
||||
{"description", std::string(field_label) + "。协议字段:" + std::string(field.key()) + "。"},
|
||||
{"technical_description", std::string(Field::accessor_type::description.view())},
|
||||
{"value", encode_protocol_value(value)}};
|
||||
if (editable) {
|
||||
if constexpr (std::is_enum_v<Value>) {
|
||||
item["options"] = nlohmann::json::array();
|
||||
for (const auto enum_value : magic_enum::enum_values<Value>()) {
|
||||
@@ -243,13 +307,13 @@ nlohmann::json adapter_schema(const Adapter& adapter, std::string_view id, std::
|
||||
item["options"].push_back({{"value", name}, {"label", name}});
|
||||
}
|
||||
}
|
||||
properties.push_back(std::move(item));
|
||||
} else {
|
||||
state[field.key()] = encode_protocol_value(value);
|
||||
}
|
||||
fields.push_back(std::move(item));
|
||||
});
|
||||
return {{"id", id}, {"label", label}, {"kind", kind},
|
||||
{"properties", std::move(properties)}, {"state", std::move(state)}};
|
||||
{"fields", std::move(fields)}, {"state", std::move(state)}};
|
||||
}
|
||||
|
||||
template <typename Adapter>
|
||||
|
||||
Reference in New Issue
Block a user