tidy GUI codes
This commit is contained in:
parent
b463e112aa
commit
7ee26d431e
@ -71,8 +71,6 @@ target_sources(nf7
|
||||
common/dir_item.hh
|
||||
common/factory.hh
|
||||
common/file_base.hh
|
||||
common/file_holder.hh
|
||||
common/file_holder.cc
|
||||
common/font_queue.hh
|
||||
common/future.hh
|
||||
common/generic_context.hh
|
||||
@ -88,10 +86,7 @@ target_sources(nf7
|
||||
common/gui.hh
|
||||
common/gui.cc
|
||||
common/gui_config.hh
|
||||
common/gui_context.hh
|
||||
common/gui_dnd.hh
|
||||
common/gui_file.hh
|
||||
common/gui_file.cc
|
||||
common/gui_node.hh
|
||||
common/gui_timeline.hh
|
||||
common/gui_timeline.cc
|
||||
|
@ -1,134 +0,0 @@
|
||||
#include "common/file_holder.hh"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
nf7::File* FileHolder::Find(std::string_view name) const noexcept {
|
||||
return name == id_? file_: nullptr;
|
||||
}
|
||||
void FileHolder::Handle(const nf7::File::Event& ev) noexcept {
|
||||
switch (ev.type) {
|
||||
case nf7::File::Event::kAdd:
|
||||
SetUp();
|
||||
break;
|
||||
case nf7::File::Event::kRemove:
|
||||
TearDown();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void FileHolder::Update() noexcept {
|
||||
if (own()) {
|
||||
ImGui::PushID(this);
|
||||
file_->Update();
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void FileHolder::SetUp() noexcept {
|
||||
const bool first_setup = !file_;
|
||||
|
||||
if (own()) {
|
||||
file_ = std::get<std::shared_ptr<nf7::File>>(entity_).get();
|
||||
if (owner_->id() && file_->id() == 0) {
|
||||
file_->MoveUnder(*owner_, id_);
|
||||
}
|
||||
|
||||
} else if (ref()) {
|
||||
if (owner_->id()) {
|
||||
try {
|
||||
file_ = &owner_->ResolveOrThrow(path());
|
||||
} catch (nf7::File::NotFoundException&) {
|
||||
file_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file_) {
|
||||
auto mem = own()? file_->interface<nf7::Memento>(): nullptr;
|
||||
|
||||
// init watcher
|
||||
if (file_->id() && !watcher_) {
|
||||
watcher_.emplace(file_->env());
|
||||
watcher_->Watch(file_->id());
|
||||
|
||||
watcher_->AddHandler(nf7::File::Event::kUpdate, [this, mem](auto&) {
|
||||
if (mem) {
|
||||
auto ptag = std::exchange(tag_, mem->Save());
|
||||
if (ptag != tag_) {
|
||||
onChildMementoChange();
|
||||
if (mem_) mem_->Commit(); // commit owner's memento
|
||||
}
|
||||
}
|
||||
onChildUpdate();
|
||||
owner_->Touch();
|
||||
});
|
||||
}
|
||||
|
||||
// memento setup
|
||||
if (first_setup && mem) {
|
||||
if (!tag_) {
|
||||
tag_ = mem->Save();
|
||||
} else {
|
||||
mem->Restore(tag_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void FileHolder::TearDown() noexcept {
|
||||
if (!owner_->id()) return;
|
||||
if (own()) {
|
||||
file_->Isolate();
|
||||
}
|
||||
file_ = nullptr;
|
||||
watcher_ = std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
FileHolder::Tag::Tag(const Tag& src) noexcept {
|
||||
if (src.target_) {
|
||||
entity_ = src.target_->entity_;
|
||||
tag_ = src.target_->tag_;
|
||||
} else {
|
||||
entity_ = src.entity_;
|
||||
tag_ = src.tag_;
|
||||
}
|
||||
}
|
||||
FileHolder::Tag& FileHolder::Tag::operator=(const Tag& src) noexcept {
|
||||
if (!src.target_ && target_) {
|
||||
// restore
|
||||
target_->TearDown();
|
||||
target_->entity_ = src.entity_;
|
||||
target_->tag_ = src.tag_;
|
||||
target_->SetUp();
|
||||
} else if (!src.target_ && !target_) {
|
||||
// shallow copy
|
||||
entity_ = src.entity_;
|
||||
tag_ = src.tag_;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void FileHolder::Tag::SetTarget(nf7::FileHolder& h) noexcept {
|
||||
assert(!target_);
|
||||
|
||||
target_ = &h;
|
||||
|
||||
h.TearDown();
|
||||
if (std::holds_alternative<nf7::File::Path>(entity_)) {
|
||||
h.Emplace(std::move(std::get<nf7::File::Path>(entity_)));
|
||||
} else if (std::holds_alternative<std::shared_ptr<nf7::File>>(entity_)) {
|
||||
h.Emplace(std::get<std::shared_ptr<nf7::File>>(entity_)->Clone(h.env()));
|
||||
}
|
||||
entity_ = std::monostate {};
|
||||
tag_ = nullptr;
|
||||
h.SetUp();
|
||||
}
|
||||
|
||||
} // namespace nf7
|
@ -1,189 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/std/variant.hpp>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/file_base.hh"
|
||||
#include "common/generic_watcher.hh"
|
||||
#include "common/memento.hh"
|
||||
#include "common/mutable_memento.hh"
|
||||
#include "common/yas_nf7.hh"
|
||||
#include "common/yas_std_variant.hh"
|
||||
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
class FileHolder : public nf7::FileBase::Feature {
|
||||
public:
|
||||
class Tag;
|
||||
|
||||
class EmptyException final : public nf7::Exception {
|
||||
public:
|
||||
using nf7::Exception::Exception;
|
||||
};
|
||||
|
||||
using Entity = std::variant<
|
||||
std::monostate, nf7::File::Path, std::shared_ptr<nf7::File>>;
|
||||
|
||||
FileHolder(nf7::FileBase& owner, std::string_view id,
|
||||
nf7::MutableMemento* mem = nullptr) noexcept :
|
||||
nf7::FileBase::Feature(owner),
|
||||
owner_(&owner), mem_(mem), id_(id) {
|
||||
}
|
||||
FileHolder(nf7::FileBase& owner, std::string_view id,
|
||||
nf7::MutableMemento& mem) noexcept :
|
||||
FileHolder(owner, id, &mem) {
|
||||
}
|
||||
FileHolder(const FileHolder&) = delete;
|
||||
FileHolder(FileHolder&&) = delete;
|
||||
FileHolder& operator=(const FileHolder&) = delete;
|
||||
FileHolder& operator=(FileHolder&&) = delete;
|
||||
|
||||
void Serialize(nf7::Serializer& ar) const {
|
||||
ar(entity_);
|
||||
}
|
||||
void Deserialize(nf7::Deserializer& ar) {
|
||||
try {
|
||||
ar(entity_);
|
||||
} catch (nf7::Exception&) {
|
||||
entity_ = std::monostate {};
|
||||
ar.env().Throw(std::current_exception());
|
||||
}
|
||||
SetUp();
|
||||
}
|
||||
|
||||
void Emplace(nf7::File::Path&& path) noexcept {
|
||||
TearDown();
|
||||
tag_ = nullptr;
|
||||
entity_ = std::move(path);
|
||||
SetUp();
|
||||
|
||||
onEmplace();
|
||||
if (mem_) mem_->Commit();
|
||||
}
|
||||
void Emplace(std::unique_ptr<nf7::File>&& f) noexcept {
|
||||
TearDown();
|
||||
tag_ = nullptr;
|
||||
entity_ = std::move(f);
|
||||
SetUp();
|
||||
|
||||
onEmplace();
|
||||
if (mem_) mem_->Commit();
|
||||
}
|
||||
|
||||
nf7::File& GetFileOrThrow() {
|
||||
if (auto f = GetFile()) {
|
||||
return *f;
|
||||
}
|
||||
throw EmptyException {"holder is empty"};
|
||||
}
|
||||
nf7::File* GetFile() noexcept {
|
||||
SetUp();
|
||||
return file_;
|
||||
}
|
||||
|
||||
// nf7::FileBase::Feature methods
|
||||
nf7::File* Find(std::string_view name) const noexcept override;
|
||||
void Handle(const nf7::File::Event&) noexcept override;
|
||||
void Update() noexcept override;
|
||||
|
||||
bool own() const noexcept {
|
||||
return std::holds_alternative<std::shared_ptr<nf7::File>>(entity_);
|
||||
}
|
||||
bool ref() const noexcept {
|
||||
return std::holds_alternative<nf7::File::Path>(entity_);
|
||||
}
|
||||
bool empty() const noexcept {
|
||||
return std::holds_alternative<std::monostate>(entity_);
|
||||
}
|
||||
|
||||
nf7::File& owner() const noexcept { return *owner_; }
|
||||
nf7::Env& env() const noexcept { return owner_->env(); }
|
||||
const std::string& id() const noexcept { return id_; }
|
||||
|
||||
nf7::File* file() const noexcept { return file_; }
|
||||
nf7::File::Path path() const noexcept {
|
||||
assert(!empty());
|
||||
return own()? nf7::File::Path {{id_}}: std::get<nf7::File::Path>(entity_);
|
||||
}
|
||||
|
||||
// called when kUpdate event is happened on the child
|
||||
std::function<void(void)> onChildUpdate = [](){};
|
||||
|
||||
// called when the child's memento tag id is changed
|
||||
std::function<void(void)> onChildMementoChange = [](){};
|
||||
|
||||
// called right before returning from Emplace()
|
||||
std::function<void(void)> onEmplace = [](){};
|
||||
|
||||
private:
|
||||
nf7::File* const owner_;
|
||||
nf7::MutableMemento* const mem_;
|
||||
|
||||
const std::string id_;
|
||||
|
||||
Entity entity_;
|
||||
std::shared_ptr<nf7::Memento::Tag> tag_;
|
||||
|
||||
nf7::File* file_ = nullptr;
|
||||
|
||||
std::optional<nf7::GenericWatcher> watcher_;
|
||||
|
||||
|
||||
void SetUp() noexcept;
|
||||
void TearDown() noexcept;
|
||||
};
|
||||
|
||||
// to save/restore FileHolder's changes through GenericMemento
|
||||
class FileHolder::Tag final {
|
||||
public:
|
||||
Tag() = default;
|
||||
Tag(const Tag&) noexcept;
|
||||
Tag& operator=(const Tag&) noexcept;
|
||||
Tag(Tag&&) = default;
|
||||
Tag& operator=(Tag&&) = default;
|
||||
|
||||
void SetTarget(nf7::FileHolder& h) noexcept;
|
||||
|
||||
private:
|
||||
nf7::FileHolder* target_ = nullptr;
|
||||
|
||||
Entity entity_;
|
||||
std::shared_ptr<nf7::Memento::Tag> tag_;
|
||||
};
|
||||
|
||||
} // namespace nf7
|
||||
|
||||
|
||||
namespace yas::detail {
|
||||
|
||||
template <size_t F>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
nf7::FileHolder> {
|
||||
public:
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const nf7::FileHolder& h) {
|
||||
h.Serialize(ar);
|
||||
return ar;
|
||||
}
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, nf7::FileHolder& h) {
|
||||
h.Deserialize(ar);
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace yas::detail
|
@ -6,6 +6,8 @@
|
||||
#include <imgui.h>
|
||||
#include <imgui_stdlib.h>
|
||||
|
||||
#include <ImNodes.h>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/gui_dnd.hh"
|
||||
@ -69,4 +71,66 @@ bool PathButton(const char* id, nf7::File::Path& p, nf7::File&) noexcept {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ContextStack(const nf7::Context& ctx) noexcept {
|
||||
for (auto p = ctx.parent(); p; p = p->parent()) {
|
||||
auto f = ctx.env().GetFile(p->initiator());
|
||||
|
||||
const auto path = f? f->abspath().Stringify(): "[missing file]";
|
||||
|
||||
ImGui::TextUnformatted(path.c_str());
|
||||
ImGui::TextDisabled("%s", p->GetDescription().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void NodeSocket() noexcept {
|
||||
auto win = ImGui::GetCurrentWindow();
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
const auto lh = std::max(win->DC.CurrLineSize.y, em);
|
||||
const auto rad = em/2 / ImNodes::CanvasState().Zoom;
|
||||
const auto sz = ImVec2(rad*2, lh);
|
||||
const auto pos = ImGui::GetCursorScreenPos() + sz/2;
|
||||
|
||||
auto dlist = ImGui::GetWindowDrawList();
|
||||
dlist->AddCircleFilled(
|
||||
pos, rad, IM_COL32(100, 100, 100, 100));
|
||||
dlist->AddCircleFilled(
|
||||
pos, rad*.8f, IM_COL32(200, 200, 200, 200));
|
||||
|
||||
ImGui::Dummy(sz);
|
||||
}
|
||||
void NodeInputSockets(std::span<const std::string> names) noexcept {
|
||||
ImGui::BeginGroup();
|
||||
for (auto& name : names) {
|
||||
if (ImNodes::BeginInputSlot(name.c_str(), 1)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
nf7::gui::NodeSocket();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
ImNodes::EndSlot();
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
void NodeOutputSockets(std::span<const std::string> names) noexcept {
|
||||
float maxw = 0;
|
||||
for (auto& name : names) {
|
||||
maxw = std::max(maxw, ImGui::CalcTextSize(name.c_str()).x);
|
||||
}
|
||||
|
||||
ImGui::BeginGroup();
|
||||
for (auto& name : names) {
|
||||
const auto w = ImGui::CalcTextSize(name.c_str()).x;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+maxw-w);
|
||||
if (ImNodes::BeginOutputSlot(name.c_str(), 1)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
ImGui::SameLine();
|
||||
nf7::gui::NodeSocket();
|
||||
ImNodes::EndSlot();
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
||||
|
@ -1,10 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
// widgets
|
||||
bool PathButton(const char* id, nf7::File::Path&, nf7::File&) noexcept;
|
||||
void ContextStack(const nf7::Context&) noexcept;
|
||||
|
||||
void NodeSocket() noexcept;
|
||||
void NodeInputSockets(std::span<const std::string>) noexcept;
|
||||
void NodeOutputSockets(std::span<const std::string>) noexcept;
|
||||
|
||||
|
||||
// stringify utility
|
||||
inline std::string GetContextDisplayName(const nf7::Context& ctx) noexcept {
|
||||
auto f = ctx.env().GetFile(ctx.initiator());
|
||||
|
||||
const auto initiator =
|
||||
f? f->abspath().Stringify(): std::string {"<owner missing>"};
|
||||
|
||||
char buf[32];
|
||||
std::snprintf(buf, sizeof(buf), "(0x%0" PRIXPTR ")", reinterpret_cast<uintptr_t>(&ctx));
|
||||
|
||||
return initiator + " " + buf;
|
||||
}
|
||||
inline std::string GetParentContextDisplayName(const nf7::Context& ctx) noexcept {
|
||||
if (auto parent = ctx.parent()) {
|
||||
return nf7::gui::GetContextDisplayName(*parent);
|
||||
} else if (ctx.depth() == 0) {
|
||||
return "(isolated)";
|
||||
} else {
|
||||
return "<owner disappeared> MEMORY LEAK? ;(";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
||||
|
@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
inline std::string GetContextDisplayName(const nf7::Context& ctx) noexcept {
|
||||
auto f = ctx.env().GetFile(ctx.initiator());
|
||||
|
||||
const auto initiator =
|
||||
f? f->abspath().Stringify(): std::string {"<owner missing>"};
|
||||
|
||||
char buf[32];
|
||||
std::snprintf(buf, sizeof(buf), "(0x%0" PRIXPTR ")", reinterpret_cast<uintptr_t>(&ctx));
|
||||
|
||||
return initiator + " " + buf;
|
||||
}
|
||||
|
||||
inline std::string GetParentContextDisplayName(const nf7::Context& ctx) noexcept {
|
||||
if (auto parent = ctx.parent()) {
|
||||
return nf7::gui::GetContextDisplayName(*parent);
|
||||
} else if (ctx.depth() == 0) {
|
||||
return "(isolated)";
|
||||
} else {
|
||||
return "<owner disappeared> MEMORY LEAK? ;(";
|
||||
}
|
||||
}
|
||||
|
||||
inline void ContextStack(const nf7::Context& ctx) noexcept {
|
||||
for (auto p = ctx.parent(); p; p = p->parent()) {
|
||||
auto f = ctx.env().GetFile(p->initiator());
|
||||
|
||||
const auto path = f? f->abspath().Stringify(): "[missing file]";
|
||||
|
||||
ImGui::TextUnformatted(path.c_str());
|
||||
ImGui::TextDisabled("%s", p->GetDescription().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
@ -1,252 +0,0 @@
|
||||
#include "common/gui_file.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_stdlib.h>
|
||||
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/generic_context.hh"
|
||||
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
static nf7::DirItem* GetDirItem(nf7::FileHolder& h, nf7::DirItem::Flags f) noexcept
|
||||
try {
|
||||
auto& d = h.GetFileOrThrow().interfaceOrThrow<nf7::DirItem>();
|
||||
return d.flags() & f? &d: nullptr;
|
||||
} catch (nf7::Exception&) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool FileFactory::Update() noexcept {
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
ImGui::PushItemWidth(16*em);
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
name_ = "new_file";
|
||||
type_filter_ = "";
|
||||
}
|
||||
|
||||
bool submit = false;
|
||||
ImGui::InputTextWithHint("##type_filter", "search...", &type_filter_);
|
||||
if (ImGui::BeginListBox("type", {16*em, 8*em})) {
|
||||
for (const auto& reg : nf7::File::registry()) {
|
||||
const auto& t = *reg.second;
|
||||
|
||||
const bool match =
|
||||
t.flags().contains("nf7::File::TypeInfo::Factory") &&
|
||||
(type_filter_.empty() ||
|
||||
t.name().find(type_filter_) != std::string::npos) &&
|
||||
filter_(t);
|
||||
|
||||
const bool sel = (type_ == &t);
|
||||
if (!match) {
|
||||
if (sel) type_ = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr auto kSelectableFlags =
|
||||
ImGuiSelectableFlags_SpanAllColumns |
|
||||
ImGuiSelectableFlags_AllowItemOverlap;
|
||||
if (ImGui::Selectable(t.name().c_str(), sel, kSelectableFlags)) {
|
||||
type_ = &t;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
t.UpdateTooltip();
|
||||
ImGui::EndTooltip();
|
||||
|
||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||
submit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Spacing();
|
||||
|
||||
if (flags_ & kNameInput) {
|
||||
if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere();
|
||||
ImGui::InputText("name", &name_);
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
// input validation
|
||||
bool err = false;
|
||||
if (type_ == nullptr) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("type is not selected");
|
||||
err = true;
|
||||
}
|
||||
if (flags_ & kNameInput) {
|
||||
try {
|
||||
nf7::File::Path::ValidateTerm(name_);
|
||||
} catch (Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("invalid name: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
if (flags_ & kNameDupCheck) {
|
||||
if (owner_->Find(name_)) {
|
||||
ImGui::Bullet(); ImGui::Text("name duplicated");
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (ImGui::Button("ok")) {
|
||||
submit = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
const auto path = owner_->abspath().Stringify();
|
||||
if (flags_ & kNameInput) {
|
||||
ImGui::SetTooltip(
|
||||
"create %s as '%s' on '%s'", type_->name().c_str(), name_.c_str(), path.c_str());
|
||||
} else {
|
||||
ImGui::SetTooltip("create %s on '%s'", type_->name().c_str(), path.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return submit && !err;
|
||||
}
|
||||
|
||||
|
||||
std::string FileHolderEditor::GetDisplayText() const noexcept {
|
||||
std::string text;
|
||||
if (holder_->own()) {
|
||||
text = "[OWN] " + holder_->GetFile()->type().name();
|
||||
} else if (holder_->ref()) {
|
||||
text = "[REF] "s + holder_->path().Stringify();
|
||||
} else if (holder_->empty()) {
|
||||
text = "(empty)";
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
void FileHolderEditor::Button(float w, bool small) noexcept {
|
||||
ImGui::PushID(this);
|
||||
ImGui::BeginGroup();
|
||||
const auto text = GetDisplayText();
|
||||
|
||||
const bool open = small?
|
||||
ImGui::SmallButton(text.c_str()):
|
||||
ImGui::Button(text.c_str(), {w, 0});
|
||||
if (open) {
|
||||
ImGui::OpenPopup("FileHolderEmplacePopup_FromButton");
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
Tooltip();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
UpdateEmplacePopup("FileHolderEmplacePopup_FromButton");
|
||||
ImGui::PopID();
|
||||
}
|
||||
void FileHolderEditor::ButtonWithLabel(const char* name) noexcept {
|
||||
ImGui::PushID(this);
|
||||
ImGui::BeginGroup();
|
||||
Button(ImGui::CalcItemWidth());
|
||||
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::TextUnformatted(name);
|
||||
ImGui::EndGroup();
|
||||
ImGui::PopID();
|
||||
}
|
||||
void FileHolderEditor::Tooltip() noexcept {
|
||||
ImGui::TextUnformatted(GetDisplayText().c_str());
|
||||
ImGui::Indent();
|
||||
if (auto a = GetDirItem(*holder_, nf7::DirItem::kTooltip)) {
|
||||
a->UpdateTooltip();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileHolderEditor::Update() noexcept {
|
||||
ImGui::PushID(this);
|
||||
if (std::exchange(open_emplace_, false)) {
|
||||
ImGui::OpenPopup("FileHolderEmplacePopup_FromMenu");
|
||||
}
|
||||
UpdateEmplacePopup("FileHolderEmplacePopup_FromMenu");
|
||||
ImGui::PopID();
|
||||
}
|
||||
void FileHolderEditor::UpdateEmplacePopup(const char* id) noexcept {
|
||||
if (ImGui::BeginPopup(id)) {
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
if (holder_->ref()) {
|
||||
type_ = kRef;
|
||||
path_ = holder_->path().Stringify();
|
||||
} else {
|
||||
type_ = kOwn;
|
||||
path_ = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::RadioButton("own", type_ == kOwn)) { type_ = kOwn; }
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("ref", type_ == kRef)) { type_ = kRef; }
|
||||
|
||||
switch (type_) {
|
||||
case kOwn:
|
||||
if (factory_.Update()) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto& f = holder_->owner();
|
||||
f.env().ExecMain(
|
||||
std::make_shared<nf7::GenericContext>(f),
|
||||
[this]() {
|
||||
holder_->Emplace(factory_.Create(holder_->owner().env()));
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case kRef:
|
||||
ImGui::InputText("path", &path_);
|
||||
|
||||
bool missing = false;
|
||||
try {
|
||||
auto path = nf7::File::Path::Parse(path_);
|
||||
try {
|
||||
holder_->owner().ResolveOrThrow(path);
|
||||
} catch (nf7::File::NotFoundException&) {
|
||||
missing = true;
|
||||
}
|
||||
if (ImGui::Button("apply")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
auto& f = holder_->owner();
|
||||
f.env().ExecMain(
|
||||
std::make_shared<nf7::GenericContext>(f),
|
||||
[this, p = std::move(path)]() mutable {
|
||||
holder_->Emplace(std::move(p));
|
||||
});
|
||||
}
|
||||
} catch (nf7::Exception& e) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted(e.msg().c_str());
|
||||
}
|
||||
if (missing) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("the file is missing :(");
|
||||
}
|
||||
break;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/file_base.hh"
|
||||
#include "common/file_holder.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
class FileFactory final {
|
||||
public:
|
||||
enum Flag : uint8_t {
|
||||
kNameInput = 1 << 0,
|
||||
kNameDupCheck = 1 << 1,
|
||||
};
|
||||
using Flags = uint8_t;
|
||||
using Filter = std::function<bool(const nf7::File::TypeInfo&)>;
|
||||
|
||||
FileFactory(nf7::File& owner, Filter&& filter, Flags flags = 0) noexcept :
|
||||
owner_(&owner), filter_(std::move(filter)), flags_(flags) {
|
||||
}
|
||||
FileFactory(const FileFactory&) = delete;
|
||||
FileFactory(FileFactory&&) = default;
|
||||
FileFactory& operator=(const FileFactory&) = delete;
|
||||
FileFactory& operator=(FileFactory&&) = delete;
|
||||
|
||||
bool Update() noexcept;
|
||||
std::unique_ptr<nf7::File> Create(nf7::Env& env) noexcept {
|
||||
return type_? type_->Create(env): nullptr;
|
||||
}
|
||||
|
||||
const std::string& name() const noexcept { return name_; }
|
||||
const nf7::File::TypeInfo& type() const noexcept { return *type_; }
|
||||
|
||||
private:
|
||||
nf7::File* const owner_;
|
||||
const Filter filter_;
|
||||
const Flags flags_;
|
||||
|
||||
std::string name_;
|
||||
const nf7::File::TypeInfo* type_ = nullptr;
|
||||
std::string type_filter_;
|
||||
};
|
||||
|
||||
class FileHolderEditor final : public nf7::FileBase::Feature {
|
||||
public:
|
||||
enum Type {
|
||||
kOwn,
|
||||
kRef,
|
||||
};
|
||||
|
||||
FileHolderEditor(nf7::FileBase& f, nf7::FileHolder& h, FileFactory::Filter&& filter) noexcept :
|
||||
nf7::FileBase::Feature(f),
|
||||
holder_(&h), factory_(h.owner(), std::move(filter)) {
|
||||
}
|
||||
FileHolderEditor(const FileHolderEditor&) = delete;
|
||||
FileHolderEditor(FileHolderEditor&&) = default;
|
||||
FileHolderEditor& operator=(const FileHolderEditor&) = delete;
|
||||
FileHolderEditor& operator=(FileHolderEditor&&) = delete;
|
||||
|
||||
std::string GetDisplayText() const noexcept;
|
||||
|
||||
void Button(float w = 0, bool = false) noexcept;
|
||||
void SmallButton() noexcept { Button(0, true); }
|
||||
void ButtonWithLabel(const char* id) noexcept;
|
||||
void Tooltip() noexcept;
|
||||
void ItemWidget(const char*) noexcept;
|
||||
|
||||
void Update() noexcept override;
|
||||
|
||||
private:
|
||||
nf7::FileHolder* const holder_;
|
||||
|
||||
bool open_emplace_ = false;
|
||||
|
||||
Type type_;
|
||||
FileFactory factory_;
|
||||
std::string path_;
|
||||
|
||||
void UpdateEmplacePopup(const char*) noexcept;
|
||||
};
|
||||
|
||||
} // namespace nf7::gui
|
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <ImNodes.h>
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
inline void NodeSocket() noexcept {
|
||||
auto win = ImGui::GetCurrentWindow();
|
||||
|
||||
const auto em = ImGui::GetFontSize();
|
||||
const auto lh = std::max(win->DC.CurrLineSize.y, em);
|
||||
const auto rad = em/2 / ImNodes::CanvasState().Zoom;
|
||||
const auto sz = ImVec2(rad*2, lh);
|
||||
const auto pos = ImGui::GetCursorScreenPos() + sz/2;
|
||||
|
||||
auto dlist = ImGui::GetWindowDrawList();
|
||||
dlist->AddCircleFilled(
|
||||
pos, rad, IM_COL32(100, 100, 100, 100));
|
||||
dlist->AddCircleFilled(
|
||||
pos, rad*.8f, IM_COL32(200, 200, 200, 200));
|
||||
|
||||
ImGui::Dummy(sz);
|
||||
}
|
||||
|
||||
inline void NodeInputSockets(std::span<const std::string> names) noexcept {
|
||||
ImGui::BeginGroup();
|
||||
for (auto& name : names) {
|
||||
if (ImNodes::BeginInputSlot(name.c_str(), 1)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
nf7::gui::NodeSocket();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
ImNodes::EndSlot();
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
inline void NodeOutputSockets(std::span<const std::string> names) noexcept {
|
||||
float maxw = 0;
|
||||
for (auto& name : names) {
|
||||
maxw = std::max(maxw, ImGui::CalcTextSize(name.c_str()).x);
|
||||
}
|
||||
|
||||
ImGui::BeginGroup();
|
||||
for (auto& name : names) {
|
||||
const auto w = ImGui::CalcTextSize(name.c_str()).x;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+maxw-w);
|
||||
if (ImNodes::BeginOutputSlot(name.c_str(), 1)) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
ImGui::SameLine();
|
||||
nf7::gui::NodeSocket();
|
||||
ImNodes::EndSlot();
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
} // namespacce nf7::gui
|
@ -21,9 +21,8 @@
|
||||
#include "common/file_base.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/gui_config.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/logger_ref.hh"
|
||||
#include "common/luajit_nfile_importer.hh"
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/gui_value.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/node.hh"
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <imgui_stdlib.h>
|
||||
|
||||
#include <ImNodes.h>
|
||||
@ -28,10 +29,8 @@
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/gui_config.hh"
|
||||
#include "common/gui_context.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/gui_window.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/memento.hh"
|
||||
@ -1095,6 +1094,11 @@ void Network::NetworkEditor() noexcept {
|
||||
ItemAdder(pos);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::MenuItem("add terminal")) {
|
||||
ExecAddItem(
|
||||
std::make_unique<Item>(next_++, std::make_unique<Terminal>(env())),
|
||||
pos);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("undo", nullptr, false, !!history_.prev())) {
|
||||
UnDo();
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/generic_watcher.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/gui_dnd.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/logger_ref.hh"
|
||||
#include "common/memento.hh"
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/node.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
@ -191,11 +190,7 @@ try {
|
||||
ssla_ = nullptr;
|
||||
la_ = nullptr;
|
||||
}
|
||||
} catch (nf7::ExpiredException&) {
|
||||
ss->Finish();
|
||||
} catch (nf7::FileHolder::EmptyException&) {
|
||||
ss->Finish();
|
||||
} catch (nf7::File::NotImplementedException&) {
|
||||
} catch (nf7::Exception&) {
|
||||
ss->Finish();
|
||||
}
|
||||
void Call::Lambda::Abort() noexcept {
|
||||
|
@ -25,8 +25,7 @@
|
||||
#include "common/file_base.hh"
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_context.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/gui_timeline.hh"
|
||||
#include "common/gui_window.hh"
|
||||
#include "common/life.hh"
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/node.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
#include "common/yas_std_atomic.hh"
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <ImNodes.h>
|
||||
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/utility/usertype.hpp>
|
||||
|
||||
@ -15,7 +17,7 @@
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/node.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_config.hh"
|
||||
#include "common/gui_node.hh"
|
||||
#include "common/gui.hh"
|
||||
#include "common/gui_window.hh"
|
||||
#include "common/life.hh"
|
||||
#include "common/logger_ref.hh"
|
||||
|
Loading…
x
Reference in New Issue
Block a user