Files
Renderive/web_server/app/Gallery_Controls.h
T
2026-08-12 21:31:02 +08:00

137 lines
4.5 KiB
C++

#pragma once
#include "Gallery_Capture_Json.h"
#include "Gallery_Observer_Adminive.h"
#include "Gallery_Renderables.h"
#include <renderive/scene/base/Scene_Base.hpp>
#include <nlohmann/json.hpp>
#include <algorithm>
#include <array>
#include <charconv>
#include <concepts>
#include <functional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
namespace renderive::web {
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);
}
[[nodiscard]] Json resources() const {
Json result = Json::array();
for (const auto& entry : entries_) {
Json resource = entry.resource();
resource["target"] = entry.id;
resource["view"]["title"] = entry.title;
result.push_back(std::move(resource));
}
return result;
}
[[nodiscard]] Json observers(const Scene_Base& scene) const {
Json result = Json::array();
const auto topology = scene.topology_snapshot();
for (std::size_t index = 0; index < topology.renderables.size(); ++index) {
const auto* renderable =
dynamic_cast<const renderive::Renderable*>(topology.renderables[index].get());
if (!renderable)
continue;
const Entry* entry = find(renderable);
std::string title = entry ? entry->title : renderable->object_name();
if (title.empty())
title = "渲染节点 " + std::to_string(index + 1);
Json resource{
{"descriptor", adminive::to_descriptor_json<
Json, renderive::Renderable_Observation>()},
{"data", adminive::to_frontend_json<Json>(renderable->observation())},
{"target", entry ? entry->id : node_id(index)},
{"title", std::move(title)}
};
result.push_back(std::move(resource));
}
return result;
}
[[nodiscard]] Json render_plan(const Scene_Base& scene) const {
return gallery_render_plan_json(scene);
}
[[nodiscard]] adminive::Update_Result apply(std::string_view target,
const Json& patch) const {
for (const auto& entry : entries_) {
if (entry.id == target)
return entry.apply(patch);
}
adminive::Update_Result result;
result.success = false;
result.message = "unknown gallery control target: " + std::string(target);
return result;
}
private:
struct Entry {
std::string id;
std::string title;
std::function<Json()> resource;
std::function<adminive::Update_Result(const Json&)> apply;
renderive::Renderable* renderable{};
};
template <class Object>
void add(std::string id, std::string title, Object& object) {
using Model = adminive::Object_Model_Type<Object>;
auto* target = &object;
renderive::Renderable* renderable{};
if constexpr (std::derived_from<Object, renderive::Renderable>)
renderable = target;
entries_.push_back({
std::move(id), std::move(title),
[target] {
return Json{
{"descriptor", adminive::to_descriptor_json<Json, Object>()},
{"view", adminive::to_view_json<Json, Model>(
adminive::describe_edit_view<Model>())},
{"data", adminive::to_frontend_json<Json>(*target)}
};
},
[target](const Json& patch) {
return adminive::apply_frontend_patch<Json>(*target, patch);
},
renderable
});
}
[[nodiscard]] const Entry* find(const Renderable_Base* renderable) const noexcept {
const auto found = std::find_if(entries_.begin(), entries_.end(),
[renderable](const Entry& entry) { return entry.renderable == renderable; });
return found == entries_.end() ? nullptr : &*found;
}
static std::string node_id(std::size_t index) {
return "renderable-" + std::to_string(index);
}
std::vector<Entry> entries_;
};
} // namespace renderive::web