replace InputNode and OutputNode to Node/Network/Terminal
This commit is contained in:
parent
b7085b6ec5
commit
bb9b276e18
@ -58,7 +58,6 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
|||||||
}
|
}
|
||||||
|
|
||||||
class InternalNode;
|
class InternalNode;
|
||||||
class ChildNode;
|
|
||||||
|
|
||||||
class Item;
|
class Item;
|
||||||
class Lambda;
|
class Lambda;
|
||||||
@ -68,9 +67,7 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
|||||||
|
|
||||||
// special Node types
|
// special Node types
|
||||||
class Initiator;
|
class Initiator;
|
||||||
class InputOrOutput;
|
class Terminal;
|
||||||
class Input;
|
|
||||||
class Output;
|
|
||||||
|
|
||||||
using ItemId = uint64_t;
|
using ItemId = uint64_t;
|
||||||
using ItemList = std::vector<std::unique_ptr<Item>>;
|
using ItemList = std::vector<std::unique_ptr<Item>>;
|
||||||
@ -146,10 +143,14 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
|||||||
// GUI popup
|
// GUI popup
|
||||||
class AddPopup final : public nf7::FileBase::Feature, private nf7::gui::Popup {
|
class AddPopup final : public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||||
public:
|
public:
|
||||||
|
static bool TypeFilter(const nf7::File::TypeInfo& t) noexcept {
|
||||||
|
return
|
||||||
|
t.flags().contains("nf7::Node") ||
|
||||||
|
t.name().find("Node/Network/") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
AddPopup(Network& owner) noexcept :
|
AddPopup(Network& owner) noexcept :
|
||||||
nf7::gui::Popup("AddPopup"),
|
nf7::gui::Popup("AddPopup"), owner_(&owner), factory_(owner, TypeFilter) {
|
||||||
owner_(&owner),
|
|
||||||
factory_(owner, [](auto& t) { return t.flags().contains("nf7::Node"); }) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Open(const ImVec2& pos) noexcept;
|
void Open(const ImVec2& pos) noexcept;
|
||||||
@ -235,30 +236,6 @@ class Network::InternalNode : public nf7::File::Interface {
|
|||||||
const Flags flags_;
|
const Flags flags_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ChildNode is a File where it can be supposed that owner is Node/Network.
|
|
||||||
class Network::ChildNode : public nf7::File {
|
|
||||||
public:
|
|
||||||
using nf7::File::File;
|
|
||||||
|
|
||||||
void Handle(const Event& ev) noexcept override {
|
|
||||||
switch (ev.type) {
|
|
||||||
case Event::kAdd:
|
|
||||||
owner_ = dynamic_cast<Network*>(parent());
|
|
||||||
assert(owner_);
|
|
||||||
return;
|
|
||||||
case Event::kRemove:
|
|
||||||
owner_ = nullptr;
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Network& owner() const noexcept { assert(owner_); return *owner_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Network* owner_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Item holds an entity of File, and its watcher
|
// Item holds an entity of File, and its watcher
|
||||||
// to manage a Node owned by Node/Network.
|
// to manage a Node owned by Node/Network.
|
||||||
@ -654,15 +631,14 @@ class Network::Item::MoveCommand final : public nf7::History::Command {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// An implementation of ChildNode that emits a pulse
|
// Node that emits a pulse when Network lambda receives the first input.
|
||||||
// when Network lambda receives the first input.
|
class Network::Initiator final : public nf7::File,
|
||||||
class Network::Initiator final : public Network::ChildNode,
|
|
||||||
public nf7::Memento,
|
public nf7::Memento,
|
||||||
public nf7::Node,
|
public nf7::Node,
|
||||||
public Network::InternalNode {
|
public Network::InternalNode {
|
||||||
public:
|
public:
|
||||||
static inline const GenericTypeInfo<Initiator> kType = {
|
static inline const GenericTypeInfo<Initiator> kType = {
|
||||||
"Node/Network/Initiator", {"nf7::Node"}};
|
"Node/Network/Initiator", {}};
|
||||||
static void UpdateTypeTooltip() noexcept {
|
static void UpdateTypeTooltip() noexcept {
|
||||||
ImGui::TextUnformatted(
|
ImGui::TextUnformatted(
|
||||||
"Emits a pulse immediately when Node/Network gets the first input.");
|
"Emits a pulse immediately when Node/Network gets the first input.");
|
||||||
@ -670,7 +646,7 @@ class Network::Initiator final : public Network::ChildNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Initiator(Env& env, bool enable_auto = false) noexcept :
|
Initiator(Env& env, bool enable_auto = false) noexcept :
|
||||||
ChildNode(kType, env), InternalNode(InternalNode::kInputHandler),
|
File(kType, env), InternalNode(InternalNode::kInputHandler),
|
||||||
enable_auto_(enable_auto) {
|
enable_auto_(enable_auto) {
|
||||||
output_ = {"out"};
|
output_ = {"out"};
|
||||||
}
|
}
|
||||||
@ -746,99 +722,111 @@ class Network::Initiator final : public Network::ChildNode,
|
|||||||
bool enable_auto_;
|
bool enable_auto_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A base implementation of ChildNode
|
// Node that emits/receives input or output.
|
||||||
// that has useful methods for Input or Output Node on Node/Network.
|
class Network::Terminal : public nf7::File,
|
||||||
class Network::InputOrOutput : public Network::ChildNode {
|
public nf7::Node,
|
||||||
|
public Network::InternalNode {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
static inline const GenericTypeInfo<Terminal> kType = {
|
||||||
kInput,
|
"Node/Network/Terminal", {}};
|
||||||
kOutput,
|
|
||||||
};
|
enum Type { kInput, kOutput, };
|
||||||
InputOrOutput(const TypeInfo& type, Env& env, std::string_view name, Type stype) noexcept :
|
Terminal(Env& env, std::string_view name = "", Type stype = kInput) noexcept :
|
||||||
ChildNode(type, env), mem_(*this, std::string(name)), type_(stype) {
|
nf7::File(kType, env),
|
||||||
|
Network::InternalNode(Network::InternalNode::kInputHandler |
|
||||||
|
Network::InternalNode::kOutputEmitter),
|
||||||
|
life_(*this), mem_(*this, Data { .type = stype, .name = std::string {name} }) {
|
||||||
|
Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateSelector() noexcept {
|
Terminal(nf7::Env& env, Deserializer& ar) : Terminal(env) {
|
||||||
const auto& socks = type_ == kInput? owner().input_: owner().output_;
|
ar(data().type, data().name);
|
||||||
|
Commit();
|
||||||
auto& name = mem_.data();
|
|
||||||
ImGui::BeginGroup();
|
|
||||||
ImGui::SetNextItemWidth(8*ImGui::GetFontSize());
|
|
||||||
if (ImGui::BeginCombo("##name", mem_.data().c_str())) {
|
|
||||||
for (const auto& sock : socks) {
|
|
||||||
if (ImGui::Selectable(sock.c_str())) {
|
|
||||||
if (name != sock) {
|
|
||||||
name = sock;
|
|
||||||
mem_.Commit();
|
|
||||||
env().Handle({ .id = id(), .type = Event::kUpdate, });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
if (socks.end() == std::find(socks.begin(), socks.end(), name)) {
|
|
||||||
ImGui::TextUnformatted("SOCKET MISSING X(");
|
|
||||||
}
|
|
||||||
ImGui::EndGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
nf7::GenericMemento<std::string> mem_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type type_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// An implementation of ChildNode that emits an input value when Node/Network receives.
|
|
||||||
class Network::Input final : public Network::InputOrOutput,
|
|
||||||
public Network::InternalNode,
|
|
||||||
public nf7::Node {
|
|
||||||
public:
|
|
||||||
static inline const GenericTypeInfo<Input> kType = {"Node/Network/Input", {}};
|
|
||||||
|
|
||||||
Input(Env& env, std::string_view name) noexcept :
|
|
||||||
InputOrOutput(kType, env, name, kInput),
|
|
||||||
InternalNode(InternalNode::kInputHandler) {
|
|
||||||
output_ = {"out"};
|
|
||||||
}
|
|
||||||
|
|
||||||
Input(Env& env, Deserializer& ar) : Input(env, "") {
|
|
||||||
ar(mem_.data());
|
|
||||||
}
|
}
|
||||||
void Serialize(Serializer& ar) const noexcept override {
|
void Serialize(Serializer& ar) const noexcept override {
|
||||||
ar(mem_.data());
|
ar(data().type, data().name);
|
||||||
}
|
}
|
||||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||||
return std::make_unique<Input>(env, mem_.data());
|
return std::make_unique<Network::Terminal>(env, data().name, data().type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node::Lambda> CreateLambda(
|
std::shared_ptr<Node::Lambda> CreateLambda(
|
||||||
const std::shared_ptr<Node::Lambda>& parent) noexcept override {
|
const std::shared_ptr<nf7::Node::Lambda>& parent) noexcept override {
|
||||||
class Emitter final : public Node::Lambda,
|
return std::make_shared<Emitter>(*this, parent);
|
||||||
public std::enable_shared_from_this<Emitter> {
|
|
||||||
public:
|
|
||||||
Emitter(Input& f, const std::shared_ptr<Node::Lambda>& parent, std::string_view name) noexcept :
|
|
||||||
Node::Lambda(f, parent), name_(name) {
|
|
||||||
}
|
|
||||||
void Handle(std::string_view name, const Value& v,
|
|
||||||
const std::shared_ptr<Node::Lambda>& caller) noexcept override {
|
|
||||||
if (name != name_) return;
|
|
||||||
caller->Handle("out", v, shared_from_this());
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
};
|
|
||||||
return std::make_unique<Emitter>(*this, parent, mem_.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateNode(Editor&) noexcept override {
|
void UpdateNode(nf7::Node::Editor&) noexcept override {
|
||||||
ImGui::TextUnformatted("Node/Network/Input");
|
ImGui::TextUnformatted("Node/Network/Terminal");
|
||||||
if (ImNodes::BeginOutputSlot("out", 1)) {
|
switch (data().type) {
|
||||||
UpdateSelector();
|
case kInput:
|
||||||
ImGui::SameLine();
|
if (ImNodes::BeginOutputSlot("out", 1)) {
|
||||||
ImGui::AlignTextToFramePadding();
|
UpdateSelector();
|
||||||
nf7::gui::NodeSocket();
|
ImGui::SameLine();
|
||||||
ImNodes::EndSlot();
|
nf7::gui::NodeSocket();
|
||||||
|
ImNodes::EndSlot();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kOutput:
|
||||||
|
if (ImNodes::BeginInputSlot("in", 1)) {
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
nf7::gui::NodeSocket();
|
||||||
|
ImGui::SameLine();
|
||||||
|
UpdateSelector();
|
||||||
|
ImNodes::EndSlot();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto net = owner()) {
|
||||||
|
const auto& socks = data().type == kInput? net->input_: net->output_;
|
||||||
|
if (socks.end() == std::find(socks.begin(), socks.end(), data().name)) {
|
||||||
|
ImGui::TextUnformatted("SOCKET MISSING X(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void UpdateSelector() noexcept {
|
||||||
|
auto net = owner();
|
||||||
|
if (!net) {
|
||||||
|
ImGui::TextUnformatted("parent must be Node/Network");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& name = data().name;
|
||||||
|
ImGui::SetNextItemWidth(12*ImGui::GetFontSize());
|
||||||
|
if (ImGui::BeginCombo("##name", name.c_str())) {
|
||||||
|
ImGui::PushID("input");
|
||||||
|
if (net->input_.size() > 0) {
|
||||||
|
ImGui::TextDisabled("inputs");
|
||||||
|
} else {
|
||||||
|
ImGui::TextDisabled("no input");
|
||||||
|
}
|
||||||
|
for (const auto& sock : net->input_) {
|
||||||
|
if (ImGui::Selectable(sock.c_str())) {
|
||||||
|
if (data().type != kInput || name != sock) {
|
||||||
|
Commit(kInput, sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::PushID("output");
|
||||||
|
if (net->output_.size() > 0) {
|
||||||
|
ImGui::TextDisabled("outputs");
|
||||||
|
} else {
|
||||||
|
ImGui::TextDisabled("no output");
|
||||||
|
}
|
||||||
|
for (const auto& sock : net->output_) {
|
||||||
|
if (ImGui::Selectable(sock.c_str())) {
|
||||||
|
if (data().type != kOutput || name != sock) {
|
||||||
|
Commit(kOutput, sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,67 +834,76 @@ class Network::Input final : public Network::InputOrOutput,
|
|||||||
return InterfaceSelector<
|
return InterfaceSelector<
|
||||||
Network::InternalNode, nf7::Node, nf7::Memento>(t).Select(this, &mem_);
|
Network::InternalNode, nf7::Node, nf7::Memento>(t).Select(this, &mem_);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// An implementation of ChildNode that passes an input to a caller of Node/Network's lambda.
|
private:
|
||||||
class Network::Output final : public Network::InputOrOutput,
|
nf7::Life<Terminal> life_;
|
||||||
public nf7::Node, public Network::InternalNode {
|
|
||||||
public:
|
|
||||||
static inline const GenericTypeInfo<Output> kType = {"Node/Network/Output", {}};
|
|
||||||
|
|
||||||
Output(Env& env, std::string_view name) noexcept :
|
struct Data {
|
||||||
InputOrOutput(kType, env, name, kOutput),
|
Type type;
|
||||||
InternalNode(InternalNode::kOutputEmitter) {
|
std::string name;
|
||||||
input_ = {"in"};
|
};
|
||||||
}
|
nf7::GenericMemento<Data> mem_;
|
||||||
|
|
||||||
Output(Env& env, Deserializer& ar) : Output(env, "") {
|
|
||||||
ar(mem_.data());
|
|
||||||
}
|
|
||||||
void Serialize(Serializer& ar) const noexcept override {
|
|
||||||
ar(mem_.data());
|
|
||||||
}
|
|
||||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
|
||||||
return std::make_unique<Output>(env, mem_.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Node::Lambda> CreateLambda(
|
Data& data() noexcept { return mem_.data(); }
|
||||||
const std::shared_ptr<Node::Lambda>& parent) noexcept override {
|
const Data& data() const noexcept { return mem_.data(); }
|
||||||
class Emitter final : public Node::Lambda,
|
Network* owner() noexcept { return dynamic_cast<Network*>(parent()); }
|
||||||
public std::enable_shared_from_this<Emitter> {
|
|
||||||
public:
|
|
||||||
Emitter(Output& f, const std::shared_ptr<Network::Lambda>& parent, std::string_view name) noexcept :
|
|
||||||
Node::Lambda(f, parent), name_(name) {
|
|
||||||
assert(parent);
|
|
||||||
}
|
|
||||||
void Handle(std::string_view name, const Value& v,
|
|
||||||
const std::shared_ptr<Node::Lambda>& caller) noexcept override {
|
|
||||||
if (name != "in") return;
|
|
||||||
caller->Handle(name_, std::move(v), shared_from_this());
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
};
|
|
||||||
return std::make_shared<Emitter>(
|
|
||||||
*this, std::dynamic_pointer_cast<Network::Lambda>(parent), mem_.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateNode(Editor&) noexcept override {
|
|
||||||
ImGui::TextUnformatted("Node/Network/Output");
|
void Commit() noexcept {
|
||||||
if (ImNodes::BeginInputSlot("in", 1)) {
|
Commit(data().type, data().name);
|
||||||
ImGui::AlignTextToFramePadding();
|
}
|
||||||
nf7::gui::NodeSocket();
|
void Commit(Type type, std::string_view name) noexcept {
|
||||||
ImGui::SameLine();
|
data() = Data { .type = type, .name = std::string {name}, };
|
||||||
UpdateSelector();
|
|
||||||
ImNodes::EndSlot();
|
input_ = {};
|
||||||
|
output_ = {};
|
||||||
|
switch (type) {
|
||||||
|
case kInput:
|
||||||
|
output_ = {"out"};
|
||||||
|
break;
|
||||||
|
case kOutput:
|
||||||
|
input_ = {"in"};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
mem_.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
class Emitter final : public nf7::Node::Lambda,
|
||||||
return InterfaceSelector<
|
public std::enable_shared_from_this<Emitter> {
|
||||||
Network::InternalNode, nf7::Node, nf7::Memento>(t).
|
public:
|
||||||
Select(this, &mem_);
|
Emitter(Terminal& f, const std::shared_ptr<nf7::Node::Lambda>& node) noexcept :
|
||||||
}
|
nf7::Node::Lambda(f, node), f_(f.life_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Handle(std::string_view name, const nf7::Value& v,
|
||||||
|
const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept override
|
||||||
|
try {
|
||||||
|
f_.EnforceAlive();
|
||||||
|
|
||||||
|
const auto& data = f_->data();
|
||||||
|
switch (data.type) {
|
||||||
|
case kInput:
|
||||||
|
if (name == data.name) {
|
||||||
|
caller->Handle(name, v, shared_from_this());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kOutput:
|
||||||
|
caller->Handle(data.name, v, shared_from_this());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (nf7::Exception&) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nf7::Life<Terminal>::Ref f_;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user