implement sub-dockspace feature on System/ImGui
This commit is contained in:
parent
e8e0322e66
commit
267c25f798
@ -96,6 +96,7 @@ target_sources(nf7
|
||||
common/gui_value.hh
|
||||
common/gui_value.cc
|
||||
common/gui_window.hh
|
||||
common/gui_window.cc
|
||||
common/history.hh
|
||||
common/life.hh
|
||||
common/logger.hh
|
||||
|
47
common/gui_window.cc
Normal file
47
common/gui_window.cc
Normal file
@ -0,0 +1,47 @@
|
||||
#include "common/gui_window.hh"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
|
||||
namespace nf7::gui {
|
||||
|
||||
bool Window::MenuItem() noexcept {
|
||||
return ImGui::MenuItem(title_.c_str(), nullptr, &shown_);
|
||||
}
|
||||
|
||||
void Window::Handle(const nf7::File::Event& e) noexcept {
|
||||
switch (e.type) {
|
||||
case nf7::File::Event::kReqFocus:
|
||||
SetFocus();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::Update() noexcept {
|
||||
const auto idstr = id();
|
||||
auto win = ImGui::FindWindowByName(idstr.c_str());
|
||||
|
||||
if (std::exchange(set_focus_, false)) {
|
||||
shown_ = true;
|
||||
ImGui::SetNextWindowFocus();
|
||||
|
||||
// activate parent windows recursively
|
||||
auto node = win && win->DockNode? win->DockNode->HostWindow: nullptr;
|
||||
while (node) {
|
||||
ImGui::SetWindowFocus(node->Name);
|
||||
node = node->ParentWindow;
|
||||
}
|
||||
}
|
||||
if (!shown_) return;
|
||||
|
||||
onConfig();
|
||||
if (ImGui::Begin(idstr.c_str(), &shown_)) {
|
||||
onUpdate();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace nf7::gui
|
@ -5,8 +5,6 @@
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/utility/usertype.hpp>
|
||||
|
||||
@ -43,9 +41,8 @@ class Window : public nf7::FileBase::Feature {
|
||||
shown_ = true;
|
||||
set_focus_ = true;
|
||||
}
|
||||
bool MenuItem() noexcept {
|
||||
return ImGui::MenuItem(title_.c_str(), nullptr, &shown_);
|
||||
}
|
||||
|
||||
bool MenuItem() noexcept;
|
||||
|
||||
std::string id() const noexcept { return ConcatId(*owner_, title_); }
|
||||
bool shown() const noexcept { return shown_; }
|
||||
@ -64,29 +61,8 @@ class Window : public nf7::FileBase::Feature {
|
||||
bool shown_;
|
||||
|
||||
|
||||
void Handle(const nf7::File::Event& e) noexcept override {
|
||||
switch (e.type) {
|
||||
case nf7::File::Event::kReqFocus:
|
||||
SetFocus();
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Update() noexcept override {
|
||||
if (std::exchange(set_focus_, false)) {
|
||||
ImGui::SetNextWindowFocus();
|
||||
shown_ = true;
|
||||
}
|
||||
if (!shown_) return;
|
||||
|
||||
onConfig();
|
||||
if (ImGui::Begin(id().c_str(), &shown_)) {
|
||||
onUpdate();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
void Handle(const nf7::File::Event&) noexcept override;
|
||||
void Update() noexcept override;
|
||||
};
|
||||
|
||||
} // namespace nf7::gui
|
||||
|
@ -237,6 +237,11 @@ void Dir::UpdateTree() noexcept {
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
// send nf7::File::Event::kReqFocus on double click
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||
env().Handle({.id = file.id(), .type = nf7::File::Event::kReqFocus});
|
||||
}
|
||||
|
||||
// context menu
|
||||
if (ImGui::BeginPopupContextItem()) {
|
||||
if (ImGui::MenuItem("copy path")) {
|
||||
|
@ -3,19 +3,27 @@
|
||||
#include <string_view>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/std/string.hpp>
|
||||
#include <yas/types/std/string_view.hpp>
|
||||
#include <yas/types/std/vector.hpp>
|
||||
#include <yas/types/utility/usertype.hpp>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/dir_item.hh"
|
||||
#include "common/generic_memento.hh"
|
||||
#include "common/generic_type_info.hh"
|
||||
#include "common/gui_config.hh"
|
||||
#include "common/gui_window.hh"
|
||||
#include "common/ptr_selector.hh"
|
||||
#include "common/util_algorithm.hh"
|
||||
|
||||
|
||||
using namespace std::literals;
|
||||
@ -28,12 +36,49 @@ class ImGui_ final : public nf7::File, public nf7::DirItem {
|
||||
public:
|
||||
static inline const nf7::GenericTypeInfo<ImGui_> kType = {"System/ImGui", {}};
|
||||
|
||||
struct Data {
|
||||
std::vector<std::string> dockspaces;
|
||||
|
||||
void serialize(auto& ar) {
|
||||
ar(dockspaces);
|
||||
nf7::util::Uniq(dockspaces);
|
||||
}
|
||||
|
||||
std::string Stringify() const noexcept {
|
||||
YAML::Emitter st;
|
||||
st << YAML::BeginMap;
|
||||
st << YAML::Key << "dockspaces";
|
||||
st << YAML::Value << dockspaces;
|
||||
st << YAML::EndMap;
|
||||
return {st.c_str(), st.size()};
|
||||
}
|
||||
void Parse(const std::string& str)
|
||||
try {
|
||||
const auto yaml = YAML::Load(str);
|
||||
|
||||
Data d;
|
||||
d.dockspaces = yaml["dockspaces"].as<std::vector<std::string>>();
|
||||
|
||||
if (nf7::util::Uniq(d.dockspaces) > 0) {
|
||||
throw nf7::Exception {"workspace name duplication"};
|
||||
}
|
||||
|
||||
*this = std::move(d);
|
||||
} catch (YAML::Exception& e) {
|
||||
throw nf7::Exception {e.what()};
|
||||
}
|
||||
};
|
||||
|
||||
ImGui_(nf7::Env& env) noexcept :
|
||||
nf7::File(kType, env), nf7::DirItem(nf7::DirItem::kEarlyUpdate) {
|
||||
nf7::File(kType, env),
|
||||
nf7::DirItem(nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kEarlyUpdate),
|
||||
mem_({}, *this) {
|
||||
}
|
||||
|
||||
ImGui_(nf7::Deserializer& ar) : ImGui_(ar.env()) {
|
||||
std::string config;
|
||||
ar(config);
|
||||
ar(config, mem_.data());
|
||||
|
||||
if (config.size() > 0) {
|
||||
ImGui::LoadIniSettingsFromMemory(config.data(), config.size());
|
||||
@ -42,40 +87,74 @@ class ImGui_ final : public nf7::File, public nf7::DirItem {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
size_t n;
|
||||
const char* config = ImGui::SaveIniSettingsToMemory(&n);
|
||||
ar(std::string_view(config, n));
|
||||
ar(std::string_view(config, n), mem_.data());
|
||||
}
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<ImGui_>(env);
|
||||
}
|
||||
|
||||
void Update() noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<nf7::DirItem>(t).Select(this);
|
||||
}
|
||||
|
||||
private:
|
||||
nf7::GenericMemento<Data> mem_;
|
||||
};
|
||||
|
||||
|
||||
void ImGui_::Update() noexcept {
|
||||
constexpr auto kFlags =
|
||||
ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||
ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoNavFocus;
|
||||
const auto id = nf7::gui::Window::ConcatId(*this, "Docking Root");
|
||||
const auto em = ImGui::GetFontSize();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0});
|
||||
ImGui::SetNextWindowBgAlpha(0.f);
|
||||
if (ImGui::Begin(id.c_str(), nullptr, kFlags)) {
|
||||
const auto vp = ImGui::GetMainViewport();
|
||||
ImGui::SetWindowPos({0, 0}, ImGuiCond_Always);
|
||||
ImGui::SetWindowSize(vp->Size, ImGuiCond_Always);
|
||||
ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
|
||||
|
||||
bool mod = false;
|
||||
auto& ds = mem_->dockspaces;
|
||||
for (auto itr = ds.begin(); itr < ds.end();) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0});
|
||||
{
|
||||
const auto id = *itr + " - " + nf7::gui::Window::ConcatId(*this, "Dockspace");
|
||||
|
||||
ImGui::SetNextWindowSize({8*em, 8*em}, ImGuiCond_FirstUseEver);
|
||||
|
||||
bool shown = true;
|
||||
const bool active = ImGui::Begin(id.c_str(), &shown);
|
||||
ImGui::DockSpace(ImGui::GetID("_DOCK_SPACE"), {0, 0}, active? 0: ImGuiDockNodeFlags_KeepAliveOnly);
|
||||
ImGui::End();
|
||||
|
||||
if (shown) {
|
||||
++itr;
|
||||
} else {
|
||||
itr = ds.erase(itr);
|
||||
mod = true;
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar(1);
|
||||
|
||||
ImGui::DockSpace(ImGui::GetID("DockSpace"), {0, 0},
|
||||
ImGuiDockNodeFlags_PassthruCentralNode);
|
||||
}
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar(1);
|
||||
if (mod) {
|
||||
mem_.Commit();
|
||||
}
|
||||
}
|
||||
void ImGui_::UpdateMenu() noexcept {
|
||||
if (ImGui::MenuItem("add workspace")) {
|
||||
size_t i = 0;
|
||||
auto& ds = mem_->dockspaces;
|
||||
for (;; ++i) {
|
||||
const auto name = std::to_string(i);
|
||||
if (ds.end() == std::find(ds.begin(), ds.end(), name)) {
|
||||
ds.push_back(name);
|
||||
mem_.Commit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ImGui::BeginMenu("config")) {
|
||||
nf7::gui::Config(mem_);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user