253 lines
6.5 KiB
C++
253 lines
6.5 KiB
C++
#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
|