move an implementation of System/Dir's NewFilePopup to common utility
This commit is contained in:
parent
27469b640e
commit
3dfad9768b
@ -49,6 +49,7 @@ target_sources(nf7
|
||||
common/file_ref.hh
|
||||
common/generic_context.hh
|
||||
common/generic_type_info.hh
|
||||
common/gui_file.hh
|
||||
common/gui_window.hh
|
||||
common/logger.hh
|
||||
common/logger_pool.hh
|
||||
|
131
common/gui_file.hh
Normal file
131
common/gui_file.hh
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
enum FileCreatePopupFlag : uint8_t {
|
||||
kNameInput = 1 << 0,
|
||||
kNameDupCheck = 1 << 1,
|
||||
};
|
||||
template <uint8_t kFlags>
|
||||
struct FileCreatePopup final {
|
||||
public:
|
||||
FileCreatePopup(std::vector<std::string>&& type_flags_and,
|
||||
std::vector<std::string>&& type_flags_or = {},
|
||||
std::string_view default_name = "new_file") noexcept :
|
||||
type_flags_and_(std::move(type_flags_and)),
|
||||
type_flags_or_(std::move(type_flags_or)),
|
||||
default_name_(default_name) {
|
||||
}
|
||||
|
||||
bool Update(nf7::File& owner) noexcept {
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
ImGui::PushItemWidth(16*em);
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
name_ = default_name_;
|
||||
type_filter_ = "";
|
||||
}
|
||||
|
||||
if constexpr (kFlags & FileCreatePopupFlag::kNameInput) {
|
||||
if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere();
|
||||
ImGui::InputText("name", &name_);
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
if (ImGui::BeginListBox("type", {16*em, 4*em})) {
|
||||
for (const auto& reg : nf7::File::registry()) {
|
||||
const auto& t = *reg.second;
|
||||
|
||||
const auto flag_matcher =
|
||||
[&t](const auto& flag) { return t.flags().contains(flag); };
|
||||
const bool flag_and_match = std::all_of(
|
||||
type_flags_and_.begin(), type_flags_and_.end(), flag_matcher);
|
||||
const bool flag_or_match =
|
||||
type_flags_or_.empty() ||
|
||||
std::any_of(type_flags_or_.begin(), type_flags_or_.end(), flag_matcher);
|
||||
if (!flag_and_match || !flag_or_match) continue;
|
||||
|
||||
const bool name_match =
|
||||
type_filter_.empty() || t.name().find(type_filter_) != std::string::npos;
|
||||
|
||||
const bool sel = (type_ == &t);
|
||||
if (!name_match) {
|
||||
if (sel) type_ = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
constexpr auto kSelectableFlags =
|
||||
ImGuiSelectableFlags_SpanAllColumns |
|
||||
ImGuiSelectableFlags_AllowItemOverlap;
|
||||
if (ImGui::Selectable(t.name().c_str(), sel, kSelectableFlags)) {
|
||||
type_ = &t;
|
||||
}
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::InputTextWithHint("##type_filter", "search...", &type_filter_);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Spacing();
|
||||
|
||||
// input validation
|
||||
bool err = false;
|
||||
if (type_ == nullptr) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("type is not selected");
|
||||
err = true;
|
||||
}
|
||||
if constexpr (kFlags & FileCreatePopupFlag::kNameInput) {
|
||||
try {
|
||||
nf7::File::Path::ValidateTerm(name_);
|
||||
} catch (Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("invalid name: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
if constexpr (kFlags & FileCreatePopupFlag::kNameDupCheck) {
|
||||
if (owner.Find(name_)) {
|
||||
ImGui::Bullet(); ImGui::Text("name duplicated");
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
if (!err) {
|
||||
if (ImGui::Button("ok")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
ret = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
const auto path = owner.abspath().Stringify();
|
||||
if constexpr (kFlags & FileCreatePopupFlag::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 ret;
|
||||
}
|
||||
|
||||
const std::string& name() const noexcept { return name_; }
|
||||
const nf7::File::TypeInfo& type() const noexcept { return *type_; }
|
||||
|
||||
private:
|
||||
std::vector<std::string> type_flags_and_;
|
||||
std::vector<std::string> type_flags_or_;
|
||||
std::string default_name_;
|
||||
|
||||
std::string name_;
|
||||
const nf7::File::TypeInfo* type_;
|
||||
std::string type_filter_;
|
||||
};
|
||||
|
||||
} // namespace nf7
|
@ -15,6 +15,7 @@
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_file.hh"
|
||||
#include "common/gui_window.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
#include "common/yas.hh"
|
||||
@ -136,83 +137,18 @@ void Dir::Update() noexcept {
|
||||
|
||||
// new item popup
|
||||
if (ImGui::BeginPopup("NewItemPopup")) {
|
||||
static const TypeInfo* selecting = nullptr;
|
||||
static std::string filter = "";
|
||||
static std::string name = "";
|
||||
static nf7::gui::FileCreatePopup<
|
||||
nf7::gui::kNameInput | nf7::gui::kNameDupCheck> p(
|
||||
{"File_Factory", "DirItem"});
|
||||
ImGui::TextUnformatted("System/Dir: adding new file...");
|
||||
if (p.Update(*this)) {
|
||||
auto ctx = std::make_shared<GenericContext>(env(), id());
|
||||
ctx->description() = "adding new file on "+abspath().Stringify();
|
||||
|
||||
ImGui::PushItemWidth(16*em);
|
||||
ImGui::TextUnformatted("System/Dir: adding new item...");
|
||||
|
||||
if (ImGui::IsWindowAppearing()) ImGui::SetKeyboardFocusHere();
|
||||
ImGui::InputText("name", &name);
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::InputTextWithHint("type", "search", &filter);
|
||||
if (ImGui::BeginListBox("##type_list", {16*em, 4*em})) {
|
||||
for (const auto& reg : registry()) {
|
||||
const auto& t = *reg.second;
|
||||
if (!t.flags().contains("DirItem")) continue;
|
||||
if (!t.flags().contains("File_Factory")) continue;
|
||||
|
||||
const bool name_match =
|
||||
filter.empty() || t.name().find(filter) != std::string::npos;
|
||||
|
||||
const bool sel = (selecting == &t);
|
||||
if (!name_match) {
|
||||
if (sel) selecting = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::PushID(&t);
|
||||
constexpr auto kFlags =
|
||||
ImGuiSelectableFlags_SpanAllColumns |
|
||||
ImGuiSelectableFlags_AllowItemOverlap;
|
||||
if (ImGui::Selectable("##selectable", sel, kFlags)) {
|
||||
selecting = &t;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(t.name().c_str());
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Spacing();
|
||||
|
||||
// input validation
|
||||
bool err = false;
|
||||
if (selecting == nullptr) {
|
||||
ImGui::Bullet(); ImGui::TextUnformatted("type is not selected");
|
||||
err = true;
|
||||
}
|
||||
try {
|
||||
Path::ValidateTerm(name);
|
||||
} catch (Exception& e) {
|
||||
ImGui::Bullet(); ImGui::Text("invalid name: %s", e.msg().c_str());
|
||||
err = true;
|
||||
}
|
||||
if (items_.find(name) != items_.end()) {
|
||||
ImGui::Bullet(); ImGui::Text("name duplicated");
|
||||
err = true;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (ImGui::Button("ok")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
auto ctx = std::make_shared<GenericContext>(env(), id());
|
||||
ctx->description() = "adding new file on "+abspath().Stringify();
|
||||
|
||||
auto task = [this, name = std::move(name), type = selecting]() {
|
||||
Add(name, type->Create(env()));
|
||||
};
|
||||
env().ExecMain(ctx, std::move(task));
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"create %s as '%s' on '%s'",
|
||||
selecting->name().c_str(), name.c_str(), abspath().Stringify().c_str());
|
||||
}
|
||||
auto task = [this, name = p.name(), &type = p.type()]() {
|
||||
Add(name, type.Create(env()));
|
||||
};
|
||||
env().ExecMain(ctx, std::move(task));
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user