add UpdateConfig() to nf7::DirItem
This commit is contained in:
parent
f90dbc295b
commit
5f21f0c926
@ -66,6 +66,7 @@ target_sources(nf7
|
||||
common/gui_file.cc
|
||||
common/gui_node.hh
|
||||
common/gui_popup.hh
|
||||
common/gui_popup.cc
|
||||
common/gui_timeline.hh
|
||||
common/gui_timeline.cc
|
||||
common/gui_value.hh
|
||||
@ -96,6 +97,7 @@ target_sources(nf7
|
||||
common/task.hh
|
||||
common/thread.hh
|
||||
common/timed_queue.hh
|
||||
common/util_string.hh
|
||||
common/value.hh
|
||||
common/yas_audio.hh
|
||||
common/yas_imgui.hh
|
||||
|
@ -14,7 +14,8 @@ class DirItem : public File::Interface {
|
||||
kTree = 1 << 0,
|
||||
kMenu = 1 << 1,
|
||||
kTooltip = 1 << 2,
|
||||
kDragDropTarget = 1 << 3,
|
||||
kWidget = 1 << 3,
|
||||
kDragDropTarget = 1 << 4,
|
||||
};
|
||||
using Flags = uint8_t;
|
||||
|
||||
@ -29,6 +30,7 @@ class DirItem : public File::Interface {
|
||||
virtual void UpdateTree() noexcept { }
|
||||
virtual void UpdateMenu() noexcept { }
|
||||
virtual void UpdateTooltip() noexcept { }
|
||||
virtual void UpdateWidget() noexcept { }
|
||||
virtual void UpdateDragDropTarget() noexcept { }
|
||||
|
||||
Flags flags() const noexcept { return flags_; }
|
||||
|
@ -68,11 +68,14 @@ class FileHolder : public nf7::FileBase::Feature {
|
||||
}
|
||||
|
||||
nf7::File& GetFileOrThrow() {
|
||||
SetUp();
|
||||
if (!file_) {
|
||||
throw EmptyException {"holder is empty"};
|
||||
if (auto f = GetFile()) {
|
||||
return *f;
|
||||
}
|
||||
return *file_;
|
||||
throw EmptyException {"holder is empty"};
|
||||
}
|
||||
nf7::File* GetFile() noexcept {
|
||||
SetUp();
|
||||
return file_;
|
||||
}
|
||||
|
||||
// nf7::FileBase::Feature methods
|
||||
|
@ -95,7 +95,6 @@ bool FileFactory::Update() noexcept {
|
||||
bool ret = false;
|
||||
if (!err) {
|
||||
if (ImGui::Button("ok")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
ret = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
@ -115,11 +114,11 @@ bool FileFactory::Update() noexcept {
|
||||
std::string FileHolderEditor::GetDisplayText() const noexcept {
|
||||
std::string text;
|
||||
if (holder_->own()) {
|
||||
text = "OWN: " + holder_->file()->type().name();
|
||||
text = "[OWN] " + holder_->GetFile()->type().name();
|
||||
} else if (holder_->ref()) {
|
||||
text = "REF: "s + holder_->path().Stringify();
|
||||
text = "[REF] "s + holder_->path().Stringify();
|
||||
} else if (holder_->empty()) {
|
||||
text = "(NULL)";
|
||||
text = "(empty)";
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
@ -131,12 +130,11 @@ void FileHolderEditor::Button(float w, bool small) noexcept {
|
||||
ImGui::BeginGroup();
|
||||
const auto text = GetDisplayText();
|
||||
|
||||
open_ |= small?
|
||||
const bool open = small?
|
||||
ImGui::SmallButton(text.c_str()):
|
||||
ImGui::Button(text.c_str(), {w, 0});
|
||||
if (ImGui::BeginPopupContextItem()) {
|
||||
MenuItems();
|
||||
ImGui::EndPopup();
|
||||
if (open) {
|
||||
ImGui::OpenPopup("FileHolderEmplacePopup_FromButton");
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
@ -144,6 +142,8 @@ void FileHolderEditor::Button(float w, bool small) noexcept {
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
UpdateEmplacePopup("FileHolderEmplacePopup_FromButton");
|
||||
ImGui::PopID();
|
||||
}
|
||||
void FileHolderEditor::ButtonWithLabel(const char* name) noexcept {
|
||||
@ -163,34 +163,28 @@ void FileHolderEditor::Tooltip() noexcept {
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
void FileHolderEditor::MenuItems() noexcept {
|
||||
if (ImGui::MenuItem("emplace")) {
|
||||
open_ = true;
|
||||
}
|
||||
if (auto a = GetDirItem(*holder_, nf7::DirItem::kMenu)) {
|
||||
ImGui::Separator();
|
||||
a->UpdateMenu();
|
||||
}
|
||||
}
|
||||
void FileHolderEditor::MenuWithTooltip(const char* name) noexcept {
|
||||
if (ImGui::BeginMenu(name)) {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
Tooltip();
|
||||
ImGui::EndTooltip();
|
||||
void FileHolderEditor::ItemWidget(const char* title) noexcept {
|
||||
if (auto d = GetDirItem(*holder_, nf7::DirItem::kWidget)) {
|
||||
if (ImGui::CollapsingHeader(title, ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::PushID(d);
|
||||
ImGui::Indent();
|
||||
d->UpdateWidget();
|
||||
ImGui::Unindent();
|
||||
ImGui::PopID();
|
||||
}
|
||||
MenuItems();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void FileHolderEditor::Update() noexcept {
|
||||
ImGui::PushID(this);
|
||||
|
||||
if (std::exchange(open_, false)) {
|
||||
ImGui::OpenPopup("FileHolderEditorPopup");
|
||||
if (std::exchange(open_emplace_, false)) {
|
||||
ImGui::OpenPopup("FileHolderEmplacePopup_FromMenu");
|
||||
}
|
||||
if (ImGui::BeginPopup("FileHolderEditorPopup")) {
|
||||
UpdateEmplacePopup("FileHolderEmplacePopup_FromMenu");
|
||||
ImGui::PopID();
|
||||
}
|
||||
void FileHolderEditor::UpdateEmplacePopup(const char* id) noexcept {
|
||||
if (ImGui::BeginPopup(id)) {
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
if (holder_->ref()) {
|
||||
type_ = kRef;
|
||||
@ -208,6 +202,8 @@ void FileHolderEditor::Update() noexcept {
|
||||
switch (type_) {
|
||||
case kOwn:
|
||||
if (factory_.Update()) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto& f = holder_->owner();
|
||||
f.env().ExecMain(
|
||||
std::make_shared<nf7::GenericContext>(f),
|
||||
@ -247,8 +243,6 @@ void FileHolderEditor::Update() noexcept {
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
||||
|
@ -69,19 +69,20 @@ class FileHolderEditor final : public nf7::FileBase::Feature {
|
||||
void SmallButton() noexcept { Button(0, true); }
|
||||
void ButtonWithLabel(const char* id) noexcept;
|
||||
void Tooltip() noexcept;
|
||||
void MenuItems() noexcept;
|
||||
void MenuWithTooltip(const char* name) noexcept;
|
||||
void ItemWidget(const char*) noexcept;
|
||||
|
||||
void Update() noexcept override;
|
||||
|
||||
private:
|
||||
nf7::FileHolder* const holder_;
|
||||
|
||||
bool open_ = false;
|
||||
bool open_emplace_ = false;
|
||||
|
||||
Type type_;
|
||||
FileFactory factory_;
|
||||
std::string path_;
|
||||
|
||||
void UpdateEmplacePopup(const char*) noexcept;
|
||||
};
|
||||
|
||||
} // namespace nf7::gui
|
||||
|
46
common/gui_popup.cc
Normal file
46
common/gui_popup.cc
Normal file
@ -0,0 +1,46 @@
|
||||
#include "common/gui_popup.hh"
|
||||
|
||||
#include <imgui_stdlib.h>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
void IOSocketListPopup::Update() noexcept {
|
||||
if (Popup::Begin()) {
|
||||
ImGui::InputTextMultiline("inputs", &is_);
|
||||
ImGui::InputTextMultiline("outputs", &os_);
|
||||
|
||||
const auto iterm = nf7::util::SplitAndValidate(is_, nf7::File::Path::ValidateTerm);
|
||||
const auto oterm = nf7::util::SplitAndValidate(os_, nf7::File::Path::ValidateTerm);
|
||||
|
||||
if (iterm) {
|
||||
ImGui::Bullet();
|
||||
ImGui::Text("invalid input name: %.*s", (int) iterm->size(), iterm->data());
|
||||
}
|
||||
if (oterm) {
|
||||
ImGui::Bullet();
|
||||
ImGui::Text("invalid output name: %.*s", (int) oterm->size(), oterm->data());
|
||||
}
|
||||
ImGui::Bullet();
|
||||
ImGui::TextDisabled("duplicated names are removed automatically");
|
||||
|
||||
if (!iterm && !oterm && ImGui::Button("ok")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
std::vector<std::string> iv, ov;
|
||||
|
||||
nf7::util::SplitAndAppend(iv, is_);
|
||||
nf7::util::Uniq(iv);
|
||||
|
||||
nf7::util::SplitAndAppend(ov, os_);
|
||||
nf7::util::Uniq(ov);
|
||||
|
||||
onSubmit(std::move(iv), std::move(ov));
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
@ -1,9 +1,14 @@
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common/file_base.hh"
|
||||
#include "common/util_string.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
@ -31,4 +36,29 @@ class Popup {
|
||||
std::optional<ImGuiPopupFlags> open_flags_;
|
||||
};
|
||||
|
||||
class IOSocketListPopup final :
|
||||
public nf7::FileBase::Feature, private Popup {
|
||||
public:
|
||||
IOSocketListPopup(const char* name = "IOSocketListPopup",
|
||||
ImGuiWindowFlags flags = 0) noexcept :
|
||||
Popup(name, flags) {
|
||||
}
|
||||
|
||||
void Open(std::span<const std::string> iv,
|
||||
std::span<const std::string> ov) noexcept {
|
||||
is_ = "";
|
||||
nf7::util::JoinAndAppend(is_, iv);
|
||||
os_ = "";
|
||||
nf7::util::JoinAndAppend(os_, ov);
|
||||
Popup::Open();
|
||||
}
|
||||
void Update() noexcept override;
|
||||
|
||||
std::function<void(std::vector<std::string>&&, std::vector<std::string>&&)> onSubmit =
|
||||
[](auto&&, auto&&){};
|
||||
|
||||
private:
|
||||
std::string is_, os_;
|
||||
};
|
||||
|
||||
} // namespace nf7::gui
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/gui_popup.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/logger_ref.hh"
|
||||
#include "common/luajit_obj.hh"
|
||||
@ -31,6 +32,7 @@
|
||||
#include "common/node.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
#include "common/task.hh"
|
||||
#include "common/util_string.hh"
|
||||
|
||||
|
||||
using namespace std::literals;
|
||||
@ -59,8 +61,10 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
};
|
||||
|
||||
Node(Env& env, Data&& data = {}) noexcept :
|
||||
nf7::FileBase(kType, env, {&obj_, &obj_editor_}),
|
||||
nf7::DirItem(nf7::DirItem::kMenu | nf7::DirItem::kTooltip),
|
||||
nf7::FileBase(kType, env, {&obj_, &obj_editor_, &socket_popup_}),
|
||||
nf7::DirItem(nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kTooltip |
|
||||
nf7::DirItem::kWidget),
|
||||
life_(*this),
|
||||
log_(std::make_shared<nf7::LoggerRef>()),
|
||||
obj_(*this, "obj_factory"),
|
||||
@ -69,6 +73,16 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
mem_.data().obj.SetTarget(obj_);
|
||||
mem_.CommitAmend();
|
||||
|
||||
socket_popup_.onSubmit = [this](auto&& i, auto&& o) {
|
||||
this->env().ExecMain(
|
||||
std::make_shared<nf7::GenericContext>(*this),
|
||||
[this, i = std::move(i), o = std::move(o)]() {
|
||||
mem_.data().inputs = std::move(i);
|
||||
mem_.data().outputs = std::move(o);
|
||||
mem_.Commit();
|
||||
});
|
||||
};
|
||||
|
||||
obj_.onChildMementoChange = [this]() { mem_.Commit(); };
|
||||
obj_.onEmplace = [this]() { mem_.Commit(); };
|
||||
|
||||
@ -79,9 +93,8 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
Node(Env& env, Deserializer& ar) : Node(env) {
|
||||
ar(obj_, data().desc, data().inputs, data().outputs);
|
||||
|
||||
// sanitize (remove duplicated sockets)
|
||||
Uniq(data().inputs);
|
||||
Uniq(data().outputs);
|
||||
nf7::util::Uniq(data().inputs);
|
||||
nf7::util::Uniq(data().outputs);
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
ar(obj_, data().desc, data().inputs, data().outputs);
|
||||
@ -100,10 +113,9 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
}
|
||||
|
||||
void Handle(const Event&) noexcept override;
|
||||
void Update() noexcept override;
|
||||
static void UpdateList(std::vector<std::string>&) noexcept;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateTooltip() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<
|
||||
@ -117,42 +129,17 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
|
||||
nf7::Task<std::shared_ptr<nf7::luajit::Ref>>::Holder fetch_;
|
||||
|
||||
const char* popup_ = nullptr;
|
||||
|
||||
nf7::FileHolder obj_;
|
||||
nf7::gui::FileHolderEditor obj_editor_;
|
||||
|
||||
nf7::gui::IOSocketListPopup socket_popup_;
|
||||
|
||||
nf7::GenericMemento<Data> mem_;
|
||||
const Data& data() const noexcept { return mem_.data(); }
|
||||
Data& data() noexcept { return mem_.data(); }
|
||||
|
||||
|
||||
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> FetchHandler() noexcept;
|
||||
|
||||
static void Uniq(std::vector<std::string>& v) {
|
||||
for (auto itr = v.begin(); itr < v.end();) {
|
||||
if (v.end() != std::find(itr+1, v.end(), *itr)) {
|
||||
itr = v.erase(itr);
|
||||
} else {
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void Join(std::string& str, const std::vector<std::string>& vec) noexcept {
|
||||
str.clear();
|
||||
for (const auto& name : vec) str += name + "\n";
|
||||
}
|
||||
static void Split(std::vector<std::string>& vec, const std::string& str) {
|
||||
vec.clear();
|
||||
for (size_t i = 0; i < str.size(); ++i) {
|
||||
auto j = str.find('\n', i);
|
||||
if (j == std::string::npos) j = str.size();
|
||||
auto name = str.substr(i, j-i);
|
||||
File::Path::ValidateTerm(name);
|
||||
vec.push_back(std::move(name));
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Node::Lambda final : public nf7::Node::Lambda,
|
||||
@ -320,82 +307,8 @@ void Node::Handle(const Event& ev) noexcept {
|
||||
return;
|
||||
}
|
||||
}
|
||||
void Node::Update() noexcept {
|
||||
nf7::FileBase::Update();
|
||||
|
||||
const auto& style = ImGui::GetStyle();
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
if (const char* popup = std::exchange(popup_, nullptr)) {
|
||||
ImGui::OpenPopup(popup);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("ConfigPopup")) {
|
||||
static std::string desc;
|
||||
static std::string in, out;
|
||||
static std::vector<std::string> invec, outvec;
|
||||
|
||||
ImGui::TextUnformatted("LuaJIT/Node: config");
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
desc = desc;
|
||||
Join(in, data().inputs);
|
||||
Join(out, data().outputs);
|
||||
}
|
||||
|
||||
obj_editor_.ButtonWithLabel("obj factory");
|
||||
|
||||
const auto w = ImGui::CalcItemWidth()/2 - style.ItemSpacing.x/2;
|
||||
|
||||
ImGui::InputTextMultiline("description", &desc, {0, 4*em});
|
||||
ImGui::BeginGroup();
|
||||
ImGui::TextUnformatted("input:");
|
||||
ImGui::InputTextMultiline("##input", &in, {w, 0});
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
ImGui::TextUnformatted("output:");
|
||||
ImGui::InputTextMultiline("##output", &out, {w, 0});
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine(0, style.ItemInnerSpacing.x);
|
||||
ImGui::TextUnformatted("sockets");
|
||||
|
||||
bool err = false;
|
||||
try {
|
||||
Split(invec, in);
|
||||
} catch (nf7::Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("invalid inputs: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
try {
|
||||
Split(outvec, out);
|
||||
} catch (nf7::Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("invalid outputs: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (!err && ImGui::Button("ok")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*this, "rebuilding node");
|
||||
env().ExecMain(ctx, [&]() mutable {
|
||||
data().desc = std::move(desc);
|
||||
data().inputs = std::move(invec);
|
||||
data().outputs = std::move(outvec);
|
||||
mem_.Commit();
|
||||
});
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
void Node::UpdateMenu() noexcept {
|
||||
if (ImGui::MenuItem("config")) {
|
||||
popup_ = "ConfigPopup";
|
||||
}
|
||||
|
||||
obj_editor_.MenuWithTooltip("factory");
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("try fetch handler")) {
|
||||
if (ImGui::MenuItem("fetch handler")) {
|
||||
FetchHandler();
|
||||
}
|
||||
}
|
||||
@ -435,6 +348,26 @@ void Node::UpdateTooltip() noexcept {
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
void Node::UpdateWidget() noexcept {
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
ImGui::TextUnformatted("LuaJIT/Node: config");
|
||||
obj_editor_.ButtonWithLabel("obj factory");
|
||||
|
||||
ImGui::InputTextMultiline("description", &data().desc, {0, 4*em});
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
mem_.Commit();
|
||||
}
|
||||
|
||||
if (ImGui::Button("input/output list")) {
|
||||
socket_popup_.Open(data().inputs, data().outputs);
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
obj_editor_.ItemWidget("obj factory");
|
||||
|
||||
socket_popup_.Update();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nf7
|
||||
|
@ -65,7 +65,8 @@ class Obj final : public nf7::FileBase, public nf7::DirItem, public nf7::luajit:
|
||||
Obj(Env& env, Data&& data = {}) noexcept :
|
||||
nf7::FileBase(kType, env, {&src_, &src_editor_}),
|
||||
nf7::DirItem(nf7::DirItem::kTooltip |
|
||||
nf7::DirItem::kMenu),
|
||||
nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kWidget),
|
||||
life_(*this),
|
||||
log_(std::make_shared<nf7::LoggerRef>()),
|
||||
src_(*this, "src"),
|
||||
@ -94,6 +95,7 @@ class Obj final : public nf7::FileBase, public nf7::DirItem, public nf7::luajit:
|
||||
void Handle(const Event&) noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateTooltip() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
|
||||
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Build() noexcept override;
|
||||
|
||||
@ -284,9 +286,7 @@ void Obj::DropCache() noexcept {
|
||||
}
|
||||
|
||||
void Obj::UpdateMenu() noexcept {
|
||||
src_editor_.MenuWithTooltip("src");
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("try build")) {
|
||||
if (ImGui::MenuItem("build")) {
|
||||
Build();
|
||||
}
|
||||
if (ImGui::MenuItem("drop cache", nullptr, nullptr, !!cache_)) {
|
||||
@ -300,6 +300,12 @@ void Obj::UpdateTooltip() noexcept {
|
||||
src_editor_.Tooltip();
|
||||
ImGui::Unindent();
|
||||
}
|
||||
void Obj::UpdateWidget() noexcept {
|
||||
ImGui::TextUnformatted("LuaJIT/Obj: config");
|
||||
src_editor_.ButtonWithLabel("src");
|
||||
ImGui::Spacing();
|
||||
src_editor_.ItemWidget("src");
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nf7
|
||||
|
@ -77,13 +77,17 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
ItemList&& items = {},
|
||||
NodeLinkStore&& links = {}) :
|
||||
nf7::FileBase(kType, env, {&add_popup_, &socket_popup_}),
|
||||
nf7::DirItem(nf7::DirItem::kMenu | nf7::DirItem::kTooltip),
|
||||
nf7::DirItem(nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kTooltip |
|
||||
nf7::DirItem::kWidget),
|
||||
life_(*this),
|
||||
win_(*this, "Editor Node/Network", win),
|
||||
items_(std::move(items)), links_(std::move(links)),
|
||||
add_popup_(*this), socket_popup_(*this) {
|
||||
add_popup_(*this) {
|
||||
socket_popup_.onSubmit = [this](auto&& i, auto&& o) {
|
||||
ExecSwapSocket(std::move(i), std::move(o));
|
||||
};
|
||||
Initialize();
|
||||
win_.shown() = true;
|
||||
}
|
||||
~Network() noexcept {
|
||||
history_.Clear();
|
||||
@ -108,11 +112,13 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
|
||||
File* Find(std::string_view name) const noexcept;
|
||||
|
||||
void Handle(const Event& ev) noexcept override;
|
||||
|
||||
void Update() noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateTooltip() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
void UpdateNode(Node::Editor&) noexcept override;
|
||||
void Handle(const Event& ev) noexcept override;
|
||||
|
||||
std::shared_ptr<Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<Node::Lambda>&) noexcept override;
|
||||
@ -150,6 +156,8 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
std::vector<std::string> inputs_, outputs_;
|
||||
|
||||
// GUI popup
|
||||
nf7::gui::IOSocketListPopup socket_popup_;
|
||||
|
||||
class AddPopup final : public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||
public:
|
||||
static bool TypeFilter(const nf7::File::TypeInfo& t) noexcept {
|
||||
@ -170,24 +178,6 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
nf7::gui::FileFactory factory_;
|
||||
ImVec2 pos_;
|
||||
} add_popup_;
|
||||
class SocketPopup final : public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||
public:
|
||||
SocketPopup(Network& owner) noexcept :
|
||||
nf7::gui::Popup("SocketPopup"), owner_(&owner) {
|
||||
}
|
||||
|
||||
void Open() noexcept;
|
||||
void Update() noexcept override;
|
||||
|
||||
static std::string Join(std::span<const std::string>) noexcept;
|
||||
static std::vector<std::string> Parse(std::string_view);
|
||||
|
||||
private:
|
||||
Network* const owner_;
|
||||
|
||||
std::string inputs_;
|
||||
std::string outputs_;
|
||||
} socket_popup_;
|
||||
|
||||
|
||||
void Initialize();
|
||||
@ -205,6 +195,8 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
[this]() { history_.ReDo(); Touch(); });
|
||||
}
|
||||
|
||||
void ExecSwapSocket(std::vector<std::string>&&, std::vector<std::string>&&) noexcept;
|
||||
|
||||
Item& GetItem(ItemId id) const {
|
||||
auto itr = item_map_.find(id);
|
||||
if (itr == item_map_.end()) {
|
||||
@ -575,6 +567,12 @@ class Network::SocketSwapCommand final : public nf7::History::Command {
|
||||
std::swap(owner_->outputs_, pair_.out);
|
||||
}
|
||||
};
|
||||
void Network::ExecSwapSocket(std::vector<std::string>&& i, std::vector<std::string>&& o) noexcept {
|
||||
auto cmd = std::make_unique<SocketSwapCommand>(
|
||||
*this, SocketSwapCommand::Pair {std::move(i), std::move(o)});
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*this);
|
||||
history_.Add(std::move(cmd)).ExecApply(ctx);
|
||||
}
|
||||
|
||||
// A command that add or remove a Node.
|
||||
class Network::Item::SwapCommand final : public nf7::History::Command {
|
||||
@ -1030,9 +1028,6 @@ void Network::Update() noexcept {
|
||||
const auto pos = mouse - canvas_pos - canvas_.Offset/canvas_.Zoom;
|
||||
add_popup_.Open(pos);
|
||||
}
|
||||
if (ImGui::MenuItem("I/O sockets")) {
|
||||
socket_popup_.Open();
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("undo", nullptr, false, !!history_.prev())) {
|
||||
UnDo();
|
||||
@ -1044,6 +1039,10 @@ void Network::Update() noexcept {
|
||||
if (ImGui::MenuItem("reset canvas zoom")) {
|
||||
canvas_.Zoom = 1.f;
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("I/O socket list")) {
|
||||
socket_popup_.Open(inputs_, outputs_);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
@ -1057,11 +1056,26 @@ void Network::Update() noexcept {
|
||||
}
|
||||
}
|
||||
void Network::UpdateMenu() noexcept {
|
||||
ImGui::MenuItem("shown", nullptr, &win_.shown());
|
||||
if (ImGui::MenuItem("I/O sockets")) {
|
||||
socket_popup_.Open(inputs_, outputs_);
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("Network Editor", nullptr, &win_.shown());
|
||||
}
|
||||
void Network::UpdateTooltip() noexcept {
|
||||
ImGui::Text("nodes active: %zu", items_.size());
|
||||
}
|
||||
void Network::UpdateWidget() noexcept {
|
||||
ImGui::TextUnformatted("Node/Network");
|
||||
if (ImGui::Button("open network editor")) {
|
||||
win_.shown() = true;
|
||||
}
|
||||
if (ImGui::Button("I/O sockets")) {
|
||||
socket_popup_.Open(inputs_, outputs_);
|
||||
}
|
||||
|
||||
socket_popup_.Update();
|
||||
}
|
||||
void Network::UpdateNode(Node::Editor&) noexcept {
|
||||
}
|
||||
|
||||
@ -1114,6 +1128,8 @@ void Network::AddPopup::Update() noexcept {
|
||||
if (nf7::gui::Popup::Begin()) {
|
||||
ImGui::TextUnformatted("Node/Network: adding new Node...");
|
||||
if (factory_.Update()) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto item = std::make_unique<Item>(owner_->next_++, factory_.Create(owner_->env()));
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*owner_, "adding new node");
|
||||
|
||||
@ -1130,65 +1146,6 @@ void Network::AddPopup::Update() noexcept {
|
||||
}
|
||||
|
||||
|
||||
void Network::SocketPopup::Open() noexcept {
|
||||
nf7::gui::Popup::Open();
|
||||
inputs_ = Join(owner_->inputs_);
|
||||
outputs_ = Join(owner_->outputs_);
|
||||
}
|
||||
void Network::SocketPopup::Update() noexcept {
|
||||
if (nf7::gui::Popup::Begin()) {
|
||||
ImGui::InputTextMultiline("input", &inputs_);
|
||||
ImGui::InputTextMultiline("output", &outputs_);
|
||||
try {
|
||||
auto p = Network::SocketSwapCommand::Pair {
|
||||
.in = Parse(inputs_),
|
||||
.out = Parse(outputs_),
|
||||
};
|
||||
if (ImGui::Button("ok")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
auto cmd = std::make_unique<Network::SocketSwapCommand>(*owner_, std::move(p));
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*owner_, "updating IO sockets");
|
||||
owner_->history_.Add(std::move(cmd)).ExecApply(ctx);
|
||||
}
|
||||
} catch (nf7::Exception& e) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted(e.msg().c_str());
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
std::string Network::SocketPopup::Join(std::span<const std::string> items) noexcept {
|
||||
std::stringstream st;
|
||||
for (const auto& item : items) {
|
||||
st << item << '\n';
|
||||
}
|
||||
return st.str();
|
||||
}
|
||||
std::vector<std::string> Network::SocketPopup::Parse(std::string_view str) {
|
||||
if (str.size() > 10*1024) {
|
||||
throw nf7::Exception {"too long text"};
|
||||
}
|
||||
|
||||
std::vector<std::string> ret;
|
||||
std::string_view::size_type pos = 0;
|
||||
while (pos < str.size()) {
|
||||
auto next = str.find('\n', pos);
|
||||
if (next == std::string_view::npos) {
|
||||
next = str.size();
|
||||
}
|
||||
const auto name = str.substr(pos, next-pos);
|
||||
pos = next+1;
|
||||
|
||||
nf7::File::Path::ValidateTerm(name);
|
||||
if (ret.end() != std::find(ret.begin(), ret.end(), name)) {
|
||||
throw nf7::Exception {"name duplication ("+std::string{name}+")"};
|
||||
}
|
||||
|
||||
ret.push_back(std::string {name});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Network::Initiator::UpdateNode(nf7::Node::Editor& ed) noexcept {
|
||||
ImGui::TextUnformatted("INITIATOR");
|
||||
|
||||
|
@ -143,13 +143,10 @@ class Adaptor::Session final : public nf7::Sequencer::Session {
|
||||
}
|
||||
|
||||
const nf7::Value* Peek(std::string_view name) noexcept override {
|
||||
assert(parent_);
|
||||
auto itr = vars_.find(std::string {name});
|
||||
return itr != vars_.end()? &itr->second: nullptr;
|
||||
}
|
||||
std::optional<nf7::Value> Receive(std::string_view name) noexcept override {
|
||||
assert(parent_);
|
||||
|
||||
auto itr = vars_.find(std::string {name});
|
||||
if (itr == vars_.end()) {
|
||||
return std::nullopt;
|
||||
@ -160,7 +157,8 @@ class Adaptor::Session final : public nf7::Sequencer::Session {
|
||||
}
|
||||
|
||||
void Send(std::string_view name, nf7::Value&& v) noexcept override {
|
||||
assert(parent_);
|
||||
if (done_) return;
|
||||
|
||||
auto itr = outs_.find(std::string {name});
|
||||
if (itr != outs_.end()) {
|
||||
parent_->Send(itr->second, std::move(v));
|
||||
@ -170,7 +168,7 @@ class Adaptor::Session final : public nf7::Sequencer::Session {
|
||||
void Finish() noexcept override {
|
||||
assert(parent_);
|
||||
parent_->Finish();
|
||||
parent_ = nullptr;
|
||||
done_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -178,6 +176,8 @@ class Adaptor::Session final : public nf7::Sequencer::Session {
|
||||
|
||||
std::unordered_map<std::string, nf7::Value> vars_;
|
||||
std::unordered_map<std::string, std::string> outs_;
|
||||
|
||||
bool done_ = false;
|
||||
};
|
||||
class Adaptor::Lambda final : public nf7::Sequencer::Lambda,
|
||||
public std::enable_shared_from_this<Adaptor::Lambda> {
|
||||
|
@ -249,6 +249,8 @@ void Call::UpdateParamPanel(Sequencer::Editor&) noexcept {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("callee's lambda is created for each session");
|
||||
}
|
||||
ImGui::Spacing();
|
||||
callee_editor_.ItemWidget("callee");
|
||||
}
|
||||
}
|
||||
void Call::UpdateTooltip(Sequencer::Editor&) noexcept {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/file_base.hh"
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_context.hh"
|
||||
@ -44,7 +45,7 @@ using namespace std::literals;
|
||||
namespace nf7 {
|
||||
namespace {
|
||||
|
||||
class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
class TL final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
public:
|
||||
static inline const nf7::GenericTypeInfo<TL> kType = {
|
||||
"Sequencer/Timeline", {"nf7::DirItem"}};
|
||||
@ -71,12 +72,17 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
std::vector<std::unique_ptr<Layer>>&& layers = {},
|
||||
ItemId next = 1,
|
||||
const nf7::gui::Window* win = nullptr) noexcept :
|
||||
nf7::File(kType, env), nf7::DirItem(nf7::DirItem::kMenu),
|
||||
nf7::FileBase(kType, env, {&popup_socket_, &popup_add_item_}),
|
||||
nf7::DirItem(nf7::DirItem::kMenu | nf7::DirItem::kWidget),
|
||||
life_(*this),
|
||||
length_(length), layers_(std::move(layers)), next_(next),
|
||||
win_(*this, "Timeline Editor", win), tl_("timeline"),
|
||||
popup_add_item_(*this), popup_config_(*this) {
|
||||
popup_add_item_(*this) {
|
||||
ApplySeqSocketChanges();
|
||||
|
||||
popup_socket_.onSubmit = [this](auto&& i, auto&& o) {
|
||||
ExecChangeSeqSocket(std::move(i), std::move(o));
|
||||
};
|
||||
}
|
||||
~TL() noexcept {
|
||||
history_.Clear();
|
||||
@ -104,6 +110,7 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
void Handle(const Event& ev) noexcept;
|
||||
void Update() noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
|
||||
void UpdateEditorWindow() noexcept;
|
||||
void UpdateLambdaSelector() noexcept;
|
||||
@ -139,8 +146,11 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
nf7::gui::Timeline tl_;
|
||||
|
||||
|
||||
// popup
|
||||
struct AddItemPopup final : nf7::gui::Popup {
|
||||
// GUI popup
|
||||
nf7::gui::IOSocketListPopup popup_socket_;
|
||||
|
||||
struct AddItemPopup final :
|
||||
public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||
public:
|
||||
AddItemPopup(TL& f) noexcept :
|
||||
Popup("AddItemPopup"),
|
||||
@ -153,7 +163,7 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
target_layer_ = &l;
|
||||
Popup::Open();
|
||||
}
|
||||
void Update() noexcept;
|
||||
void Update() noexcept override;
|
||||
|
||||
private:
|
||||
TL* const owner_;
|
||||
@ -163,27 +173,6 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
|
||||
nf7::gui::FileFactory factory_;
|
||||
} popup_add_item_;
|
||||
struct ConfigPopup final : nf7::gui::Popup {
|
||||
public:
|
||||
ConfigPopup(TL& f) noexcept :
|
||||
Popup("ConfigPopup"), owner_(&f) {
|
||||
}
|
||||
|
||||
void Open() noexcept {
|
||||
inputs_ = StringifySocketList(owner_->seq_inputs_);
|
||||
outputs_ = StringifySocketList(owner_->seq_outputs_);
|
||||
error_ = "";
|
||||
Popup::Open();
|
||||
}
|
||||
void Update() noexcept;
|
||||
|
||||
private:
|
||||
TL* const owner_;
|
||||
|
||||
std::string inputs_;
|
||||
std::string outputs_;
|
||||
std::string error_;
|
||||
} popup_config_;
|
||||
|
||||
|
||||
// GUI temporary params
|
||||
@ -226,6 +215,7 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
void AttachLambda(const std::shared_ptr<TL::Lambda>&) noexcept;
|
||||
|
||||
// socket operation
|
||||
void ExecChangeSeqSocket(std::vector<std::string>&&, std::vector<std::string>&&) noexcept;
|
||||
void ApplySeqSocketChanges() noexcept {
|
||||
inputs_ = seq_inputs_;
|
||||
inputs_.push_back("_exec");
|
||||
@ -233,42 +223,6 @@ class TL final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
outputs_ = seq_outputs_;
|
||||
outputs_.push_back("_cursor");
|
||||
}
|
||||
static std::vector<std::string> ParseSocketList(std::string_view names) {
|
||||
const auto n = names.size();
|
||||
|
||||
std::vector<std::string> ret;
|
||||
size_t begin = 0;
|
||||
|
||||
for (size_t i = 0; i <= n; ++i) {
|
||||
if (i == n || names[i] == '\n') {
|
||||
const auto name = names.substr(begin, i-begin);
|
||||
if (name.size() > 0) {
|
||||
ret.push_back(std::string {name});
|
||||
}
|
||||
begin = i+1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ValidateSocketList(ret);
|
||||
return ret;
|
||||
}
|
||||
static void ValidateSocketList(const std::vector<std::string>& a) {
|
||||
for (size_t i = 0; i < a.size(); ++i) {
|
||||
File::Path::ValidateTerm(a[i]);
|
||||
for (size_t j = i+1; j < a.size(); ++j) {
|
||||
if (a[i] == a[j]) {
|
||||
throw nf7::Exception {"name duplication: "+a[i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static std::string StringifySocketList(const std::vector<std::string>& a) noexcept {
|
||||
std::stringstream st;
|
||||
for (auto& name : a) {
|
||||
st << name << '\n';
|
||||
}
|
||||
return st.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1228,6 +1182,14 @@ class TL::ConfigModifyCommand final : public nf7::History::Command {
|
||||
}
|
||||
}
|
||||
};
|
||||
void TL::ExecChangeSeqSocket(std::vector<std::string>&& i, std::vector<std::string>&& o) noexcept {
|
||||
auto cmd = ConfigModifyCommand::Builder {*this}.
|
||||
inputs(std::move(i)).
|
||||
outputs(std::move(o)).
|
||||
Build();
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*this, "updating I/O socket list");
|
||||
history_.Add(std::move(cmd)).ExecApply(ctx);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<nf7::File> TL::Clone(nf7::Env& env) const noexcept {
|
||||
@ -1238,6 +1200,8 @@ std::unique_ptr<nf7::File> TL::Clone(nf7::Env& env) const noexcept {
|
||||
return std::make_unique<TL>(env, length_, std::move(layers), next, &win_);
|
||||
}
|
||||
void TL::Handle(const Event& ev) noexcept {
|
||||
nf7::FileBase::Handle(ev);
|
||||
|
||||
switch (ev.type) {
|
||||
case Event::kAdd:
|
||||
if (layers_.size() == 0) {
|
||||
@ -1268,15 +1232,14 @@ void TL::Handle(const Event& ev) noexcept {
|
||||
}
|
||||
|
||||
void TL::Update() noexcept {
|
||||
nf7::FileBase::Update();
|
||||
|
||||
for (const auto& layer : layers_) {
|
||||
for (const auto& item : layer->items()) {
|
||||
item->file().Update();
|
||||
}
|
||||
}
|
||||
|
||||
popup_add_item_.Update();
|
||||
popup_config_.Update();
|
||||
|
||||
UpdateEditorWindow();
|
||||
UpdateParamPanelWindow();
|
||||
|
||||
@ -1288,6 +1251,15 @@ void TL::Update() noexcept {
|
||||
void TL::UpdateMenu() noexcept {
|
||||
ImGui::MenuItem("Editor", nullptr, &win_.shown());
|
||||
}
|
||||
void TL::UpdateWidget() noexcept {
|
||||
ImGui::TextUnformatted("Sequencer/Timeline");
|
||||
|
||||
if (ImGui::Button("I/O socket list")) {
|
||||
popup_socket_.Open(seq_inputs_, seq_outputs_);
|
||||
}
|
||||
|
||||
popup_socket_.Update();
|
||||
}
|
||||
void TL::UpdateEditorWindow() noexcept {
|
||||
const auto kInit = []() {
|
||||
const auto em = ImGui::GetFontSize();
|
||||
@ -1324,8 +1296,8 @@ void TL::UpdateEditorWindow() noexcept {
|
||||
ExecReDo();
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("config")) {
|
||||
popup_config_.Open();
|
||||
if (ImGui::MenuItem("I/O socket list")) {
|
||||
popup_socket_.Open(seq_inputs_, seq_outputs_);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
@ -1638,33 +1610,6 @@ void TL::AddItemPopup::Update() noexcept {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
void TL::ConfigPopup::Update() noexcept {
|
||||
if (Popup::Begin()) {
|
||||
ImGui::TextUnformatted("Sequencer/Timeline: updating config...");
|
||||
ImGui::InputTextMultiline("inputs", &inputs_);
|
||||
ImGui::InputTextMultiline("outputs", &outputs_);
|
||||
|
||||
if (ImGui::Button("ok")) {
|
||||
try {
|
||||
auto cmd = ConfigModifyCommand::Builder(*owner_).
|
||||
inputs(ParseSocketList(inputs_)).
|
||||
outputs(ParseSocketList(outputs_)).
|
||||
Build();
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*owner_, "updating config");
|
||||
owner_->history_.Add(std::move(cmd)).ExecApply(ctx);
|
||||
} catch (nf7::Exception& e) {
|
||||
error_ = e.msg();
|
||||
}
|
||||
}
|
||||
if (error_.size() > 0) {
|
||||
ImGui::Bullet();
|
||||
ImGui::TextUnformatted(error_.c_str());
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nf7
|
||||
|
@ -16,10 +16,12 @@
|
||||
|
||||
#include "common/dir.hh"
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/file_base.hh"
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_dnd.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/gui_popup.hh"
|
||||
#include "common/gui_window.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
#include "common/yas_nf7.hh"
|
||||
@ -28,7 +30,7 @@
|
||||
namespace nf7 {
|
||||
namespace {
|
||||
|
||||
class Dir final : public File,
|
||||
class Dir final : public nf7::FileBase,
|
||||
public nf7::Dir,
|
||||
public nf7::DirItem {
|
||||
public:
|
||||
@ -38,15 +40,13 @@ class Dir final : public File,
|
||||
using ItemMap = std::map<std::string, std::unique_ptr<File>>;
|
||||
|
||||
Dir(Env& env, ItemMap&& items = {}, const gui::Window* src = nullptr) noexcept :
|
||||
File(kType, env),
|
||||
DirItem(nf7::DirItem::kTree |
|
||||
nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kTooltip |
|
||||
nf7::DirItem::kDragDropTarget),
|
||||
factory_(*this, [](auto& t) { return t.flags().contains("nf7::DirItem"); },
|
||||
nf7::gui::FileFactory::kNameInput |
|
||||
nf7::gui::FileFactory::kNameDupCheck),
|
||||
items_(std::move(items)), win_(*this, "TreeView System/Dir", src) {
|
||||
nf7::FileBase(kType, env, {&widget_popup_, &add_popup_, &rename_popup_}),
|
||||
nf7::DirItem(nf7::DirItem::kTree |
|
||||
nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kTooltip |
|
||||
nf7::DirItem::kDragDropTarget),
|
||||
items_(std::move(items)), win_(*this, "TreeView System/Dir", src),
|
||||
widget_popup_(*this), add_popup_(*this), rename_popup_(*this) {
|
||||
}
|
||||
|
||||
Dir(Env& env, Deserializer& ar) : Dir(env) {
|
||||
@ -96,6 +96,7 @@ class Dir final : public File,
|
||||
void UpdateDragDropTarget() noexcept override;
|
||||
|
||||
void Handle(const Event& ev) noexcept override {
|
||||
nf7::FileBase::Handle(ev);
|
||||
switch (ev.type) {
|
||||
case Event::kAdd:
|
||||
for (const auto& item : items_) item.second->MoveUnder(*this, item.first);
|
||||
@ -117,12 +118,6 @@ class Dir final : public File,
|
||||
}
|
||||
|
||||
private:
|
||||
const char* popup_ = nullptr;
|
||||
|
||||
std::string rename_target_;
|
||||
|
||||
nf7::gui::FileFactory factory_;
|
||||
|
||||
// persistent params
|
||||
ItemMap items_;
|
||||
gui::Window win_;
|
||||
@ -130,6 +125,66 @@ class Dir final : public File,
|
||||
std::unordered_set<std::string> opened_;
|
||||
|
||||
|
||||
// GUI popup
|
||||
class WidgetPopup final :
|
||||
public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||
public:
|
||||
WidgetPopup(Dir& owner) noexcept :
|
||||
nf7::gui::Popup("WidgetPopup"), owner_(&owner) {
|
||||
}
|
||||
|
||||
void Open(nf7::File& f) noexcept {
|
||||
target_ = &f;
|
||||
nf7::gui::Popup::Open();
|
||||
}
|
||||
void Update() noexcept override;
|
||||
|
||||
private:
|
||||
Dir* owner_;
|
||||
nf7::File* target_ = nullptr;
|
||||
} widget_popup_;
|
||||
|
||||
class AddPopup final :
|
||||
public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||
public:
|
||||
AddPopup(Dir& owner) noexcept :
|
||||
nf7::gui::Popup("AddPopup"),
|
||||
owner_(&owner),
|
||||
factory_(owner, [](auto& t) { return t.flags().contains("nf7::DirItem"); },
|
||||
nf7::gui::FileFactory::kNameInput |
|
||||
nf7::gui::FileFactory::kNameDupCheck) {
|
||||
}
|
||||
|
||||
using nf7::gui::Popup::Open;
|
||||
void Update() noexcept override;
|
||||
|
||||
private:
|
||||
Dir* owner_;
|
||||
nf7::gui::FileFactory factory_;
|
||||
} add_popup_;
|
||||
|
||||
class RenamePopup final :
|
||||
public nf7::FileBase::Feature, private nf7::gui::Popup {
|
||||
public:
|
||||
RenamePopup(Dir& owner) noexcept :
|
||||
nf7::gui::Popup("RenamePopup"),
|
||||
owner_(&owner) {
|
||||
}
|
||||
|
||||
void Open(std::string_view before) noexcept {
|
||||
before_ = before;
|
||||
after_ = "";
|
||||
nf7::gui::Popup::Open();
|
||||
}
|
||||
void Update() noexcept override;
|
||||
|
||||
private:
|
||||
Dir* owner_;
|
||||
std::string before_;
|
||||
std::string after_;
|
||||
} rename_popup_;
|
||||
|
||||
|
||||
std::string GetUniqueName(std::string_view name) const noexcept {
|
||||
auto ret = std::string {name};
|
||||
while (Find(ret)) {
|
||||
@ -140,6 +195,8 @@ class Dir final : public File,
|
||||
};
|
||||
|
||||
void Dir::Update() noexcept {
|
||||
nf7::FileBase::Update();
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
// update children
|
||||
@ -149,74 +206,6 @@ void Dir::Update() noexcept {
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (const auto popup = std::exchange(popup_, nullptr)) {
|
||||
ImGui::OpenPopup(popup);
|
||||
}
|
||||
|
||||
// new item popup
|
||||
if (ImGui::BeginPopup("NewItemPopup")) {
|
||||
ImGui::TextUnformatted("System/Dir: adding new file...");
|
||||
if (factory_.Update()) {
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*this, "adding new item");
|
||||
auto task = [this]() { Add(factory_.name(), factory_.Create(env())); };
|
||||
env().ExecMain(ctx, std::move(task));
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// rename popup
|
||||
if (ImGui::BeginPopup("RenamePopup")) {
|
||||
static std::string new_name;
|
||||
ImGui::TextUnformatted("System/Dir: renaming an exsting item...");
|
||||
ImGui::InputText("before", &rename_target_);
|
||||
|
||||
bool submit = false;
|
||||
if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere();
|
||||
if (ImGui::InputText("after", &new_name, ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
submit = true;
|
||||
}
|
||||
|
||||
bool err = false;
|
||||
if (!Find(rename_target_)) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("before is invalid: missing target");
|
||||
err = true;
|
||||
}
|
||||
if (Find(new_name)) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("after is invalid: duplicated name");
|
||||
err = true;
|
||||
}
|
||||
try {
|
||||
Path::ValidateTerm(new_name);
|
||||
} catch (Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("after is invalid: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (ImGui::Button("ok")) {
|
||||
submit = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"rename '%s' to '%s' on '%s'",
|
||||
rename_target_.c_str(), new_name.c_str(), abspath().Stringify().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (submit) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*this, "renaming item");
|
||||
auto task = [this, before = std::move(rename_target_), after = std::move(new_name)]() {
|
||||
auto f = Remove(before);
|
||||
if (!f) throw Exception("missing target");
|
||||
Add(after, std::move(f));
|
||||
};
|
||||
env().ExecMain(ctx, std::move(task));
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// tree view window
|
||||
const auto kInit = [em]() {
|
||||
ImGui::SetNextWindowSize({8*em, 8*em}, ImGuiCond_FirstUseEver);
|
||||
@ -267,6 +256,12 @@ void Dir::UpdateTree() noexcept {
|
||||
opened_.erase(name);
|
||||
}
|
||||
|
||||
if (ditem && (ditem->flags() & DirItem::kWidget)) {
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||
widget_popup_.Open(file);
|
||||
}
|
||||
}
|
||||
|
||||
// tooltip
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
@ -283,6 +278,11 @@ void Dir::UpdateTree() noexcept {
|
||||
|
||||
// context menu
|
||||
if (ImGui::BeginPopupContextItem()) {
|
||||
if (ditem && (ditem->flags() & DirItem::kWidget)) {
|
||||
if (ImGui::MenuItem("open widget")) {
|
||||
widget_popup_.Open(file);
|
||||
}
|
||||
}
|
||||
if (ImGui::MenuItem("copy path")) {
|
||||
ImGui::SetClipboardText(file.abspath().Stringify().c_str());
|
||||
}
|
||||
@ -294,8 +294,7 @@ void Dir::UpdateTree() noexcept {
|
||||
[this, name]() { Remove(name); });
|
||||
}
|
||||
if (ImGui::MenuItem("rename")) {
|
||||
rename_target_ = name;
|
||||
popup_ = "RenamePopup";
|
||||
rename_popup_.Open(name);
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("renew")) {
|
||||
@ -309,7 +308,7 @@ void Dir::UpdateTree() noexcept {
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("add new sibling")) {
|
||||
popup_ = "NewItemPopup";
|
||||
add_popup_.Open();
|
||||
}
|
||||
|
||||
if (ditem && (ditem->flags() & DirItem::kMenu)) {
|
||||
@ -356,7 +355,7 @@ void Dir::UpdateTree() noexcept {
|
||||
}
|
||||
void Dir::UpdateMenu() noexcept {
|
||||
if (ImGui::MenuItem("add new child")) {
|
||||
popup_ = "NewItemPopup";
|
||||
add_popup_.Open();
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("TreeView", nullptr, &win_.shown());
|
||||
@ -391,5 +390,83 @@ try {
|
||||
} catch (nf7::Exception&) {
|
||||
}
|
||||
|
||||
void Dir::WidgetPopup::Update() noexcept {
|
||||
if (nf7::gui::Popup::Begin()) {
|
||||
if (auto item = target_->interface<nf7::DirItem>()) {
|
||||
ImGui::PushID(item);
|
||||
item->UpdateWidget();
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
void Dir::AddPopup::Update() noexcept {
|
||||
if (nf7::gui::Popup::Begin()) {
|
||||
ImGui::TextUnformatted("System/Dir: adding new file...");
|
||||
if (factory_.Update()) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto& env = owner_->env();
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*owner_, "adding new item");
|
||||
auto task = [this, &env]() { owner_->Add(factory_.name(), factory_.Create(env)); };
|
||||
env.ExecMain(ctx, std::move(task));
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
void Dir::RenamePopup::Update() noexcept {
|
||||
if (nf7::gui::Popup::Begin()) {
|
||||
ImGui::TextUnformatted("System/Dir: renaming an exsting item...");
|
||||
ImGui::InputText("before", &before_);
|
||||
|
||||
bool submit = false;
|
||||
if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere();
|
||||
if (ImGui::InputText("after", &after_, ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
submit = true;
|
||||
}
|
||||
|
||||
bool err = false;
|
||||
if (!Find(before_)) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("before is invalid: missing target");
|
||||
err = true;
|
||||
}
|
||||
if (Find(after_)) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("after is invalid: duplicated name");
|
||||
err = true;
|
||||
}
|
||||
try {
|
||||
Path::ValidateTerm(after_);
|
||||
} catch (Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("after is invalid: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (ImGui::Button("ok")) {
|
||||
submit = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"rename '%s' to '%s' on '%s'",
|
||||
before_.c_str(), after_.c_str(),
|
||||
owner_->abspath().Stringify().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (submit) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto ctx = std::make_shared<nf7::GenericContext>(*owner_, "renaming item");
|
||||
auto task = [this, before = std::move(before_), after = std::move(after_)]() {
|
||||
auto f = owner_->Remove(before);
|
||||
if (!f) throw Exception("missing target");
|
||||
owner_->Add(after, std::move(f));
|
||||
};
|
||||
owner_->env().ExecMain(ctx, std::move(task));
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nf7
|
||||
|
@ -44,7 +44,10 @@ class NativeFile final : public File,
|
||||
}
|
||||
|
||||
NativeFile(Env& env, const std::filesystem::path& path = "", std::string_view mode = "") noexcept :
|
||||
File(kType, env), DirItem(DirItem::kMenu | DirItem::kTooltip),
|
||||
nf7::File(kType, env),
|
||||
nf7::DirItem(
|
||||
nf7::DirItem::kTooltip |
|
||||
nf7::DirItem::kWidget),
|
||||
npath_(path), mode_(mode) {
|
||||
}
|
||||
|
||||
@ -59,8 +62,8 @@ class NativeFile final : public File,
|
||||
}
|
||||
|
||||
void Update() noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateTooltip() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
|
||||
void Handle(const Event& ev) noexcept override {
|
||||
switch (ev.type) {
|
||||
@ -82,8 +85,6 @@ class NativeFile final : public File,
|
||||
private:
|
||||
std::shared_ptr<nf7::AsyncBufferAdaptor> buf_;
|
||||
|
||||
const char* popup_ = nullptr;
|
||||
|
||||
// persistent params
|
||||
std::filesystem::path npath_;
|
||||
std::string mode_;
|
||||
@ -114,11 +115,20 @@ void NativeFile::Update() noexcept {
|
||||
}
|
||||
} catch (std::filesystem::filesystem_error&) {
|
||||
}
|
||||
}
|
||||
void NativeFile::UpdateTooltip() noexcept {
|
||||
ImGui::Text("basepath: %s", env().npath().generic_string().c_str());
|
||||
ImGui::Text("path : %s", npath_.generic_string().c_str());
|
||||
ImGui::Text("mode : %s", mode_.c_str());
|
||||
}
|
||||
void NativeFile::UpdateWidget() noexcept {
|
||||
ImGui::TextUnformatted("System/NativeFile");
|
||||
|
||||
if (const auto popup = std::exchange(popup_, nullptr)) {
|
||||
ImGui::OpenPopup(popup);
|
||||
if (ImGui::Button("change referencee")) {
|
||||
ImGui::OpenPopup("ReplaceReferenceePopup");
|
||||
}
|
||||
if (ImGui::BeginPopup("ConfigPopup")) {
|
||||
|
||||
if (ImGui::BeginPopup("ReplaceReferenceePopup")) {
|
||||
static std::string path;
|
||||
static bool flag_exlock;
|
||||
static bool flag_readable;
|
||||
@ -161,16 +171,6 @@ void NativeFile::Update() noexcept {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
void NativeFile::UpdateMenu() noexcept {
|
||||
if (ImGui::MenuItem("config")) {
|
||||
popup_ = "ConfigPopup";
|
||||
}
|
||||
}
|
||||
void NativeFile::UpdateTooltip() noexcept {
|
||||
ImGui::Text("basepath: %s", env().npath().generic_string().c_str());
|
||||
ImGui::Text("path : %s", npath_.generic_string().c_str());
|
||||
ImGui::Text("mode : %s", mode_.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nf7
|
||||
|
Loading…
x
Reference in New Issue
Block a user