215 lines
5.6 KiB
C++
215 lines
5.6 KiB
C++
/*
|
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
|
|
#include <imgui.h>
|
|
|
|
#include <studio/imguiutil.hpp>
|
|
|
|
#include "newmenu.hpp"
|
|
|
|
namespace studio {
|
|
|
|
NewMenu::NewMenu(keel::Context &kctx) noexcept: m_kctx{kctx} {
|
|
setTitle("New Item");
|
|
}
|
|
|
|
void NewMenu::open() noexcept {
|
|
m_stage = Stage::Opening;
|
|
m_selectedType = 0;
|
|
m_itemName = "";
|
|
m_typeName = "";
|
|
m_useDefaultPath = true;
|
|
m_explorer.setModel(buildFileTreeModel(
|
|
m_explorer,
|
|
[](ox::StringViewCR, ox::FileStat const&s) {
|
|
return s.fileType == ox::FileType::Directory;
|
|
}).or_value(ox::UPtr<FileTreeModel>{}));
|
|
}
|
|
|
|
void NewMenu::openPath(ox::StringViewCR path) noexcept {
|
|
open();
|
|
m_useDefaultPath = false;
|
|
std::ignore = m_explorer.setSelectedPath(path);
|
|
}
|
|
|
|
void NewMenu::close() noexcept {
|
|
m_stage = Stage::Closed;
|
|
m_open = false;
|
|
}
|
|
|
|
bool NewMenu::isOpen() const noexcept {
|
|
return m_open;
|
|
}
|
|
|
|
void NewMenu::draw(Context &sctx) noexcept {
|
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
|
close();
|
|
return;
|
|
}
|
|
switch (m_stage) {
|
|
case Stage::Opening:
|
|
ImGui::OpenPopup(title().c_str());
|
|
m_stage = Stage::NewItemType;
|
|
m_open = true;
|
|
[[fallthrough]];
|
|
case Stage::NewItemType:
|
|
drawNewItemType(sctx);
|
|
break;
|
|
case Stage::NewItemTransitioningToPath:
|
|
case Stage::NewItemPath:
|
|
drawNewItemPath(sctx);
|
|
break;
|
|
case Stage::NewItemTemplate:
|
|
drawNewItemTemplate(sctx);
|
|
break;
|
|
case Stage::Closed:
|
|
m_open = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void NewMenu::addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept {
|
|
m_types.emplace_back(std::move(im));
|
|
std::sort(
|
|
m_types.begin(), m_types.end(),
|
|
[](ox::UPtr<ItemMaker> const&im1, ox::UPtr<ItemMaker> const&im2) {
|
|
return im1->typeDisplayName() < im2->typeDisplayName();
|
|
});
|
|
}
|
|
|
|
void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept {
|
|
for (auto const&im : m_types) {
|
|
if (im->installTemplate(tmplt)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void NewMenu::drawNewItemType(Context const&sctx) noexcept {
|
|
setSize({280, 180});
|
|
drawWindow(sctx.tctx, m_open, [this] {
|
|
ig::ListBox("Item Type", [&](size_t const i) -> ox::CStringView {
|
|
return m_types[i]->typeDisplayName();
|
|
}, m_types.size(), m_selectedType, {200, 100});
|
|
auto const&im = *m_types[m_selectedType];
|
|
drawFirstPageButtons(im.itemTemplates().size() == 1 ?
|
|
Stage::NewItemTransitioningToPath : Stage::NewItemTemplate);
|
|
if (m_stage == Stage::NewItemTransitioningToPath || m_stage == Stage::NewItemTemplate) {
|
|
if (m_useDefaultPath) {
|
|
std::ignore = m_explorer.setSelectedPath(im.defaultPath());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void NewMenu::drawNewItemTemplate(Context const&sctx) noexcept {
|
|
setSize({280, 180});
|
|
drawWindow(sctx.tctx, m_open, [this] {
|
|
auto const&templates =
|
|
m_types[m_selectedType]->itemTemplates();
|
|
ig::ListBox("Template", [&](size_t const i) -> ox::CStringView {
|
|
return templates[i]->name();
|
|
}, templates.size(), m_selectedTemplate, {200, 100});
|
|
drawButtons(Stage::NewItemTransitioningToPath);
|
|
});
|
|
}
|
|
|
|
void NewMenu::drawNewItemPath(Context &sctx) noexcept {
|
|
setSize({380, 340});
|
|
drawWindow(sctx.tctx, m_open, [this, &sctx] {
|
|
if (m_stage == Stage::NewItemTransitioningToPath) [[unlikely]] {
|
|
ImGui::SetKeyboardFocusHere();
|
|
m_stage = Stage::NewItemPath;
|
|
}
|
|
ig::InputText("Name", m_itemName);
|
|
ImGui::NewLine();
|
|
ImGui::Text("Path");
|
|
auto const vp = ImGui::GetContentRegionAvail();
|
|
m_explorer.draw(sctx, {vp.x, vp.y - 50});
|
|
drawLastPageButtons(sctx);
|
|
});
|
|
}
|
|
|
|
void NewMenu::drawButtons(Stage const next) noexcept {
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
|
|
constexpr ImVec2 btnSz{60, 20};
|
|
if (ImGui::Button("Back", btnSz)) {
|
|
if (auto const p = m_prev.back(); p.ok()) {
|
|
m_stage = *p.value;
|
|
}
|
|
m_prev.pop_back();
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Next", btnSz)) {
|
|
m_prev.emplace_back(m_stage);
|
|
m_stage = next;
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Cancel", btnSz)) {
|
|
ImGui::CloseCurrentPopup();
|
|
m_stage = Stage::Closed;
|
|
}
|
|
}
|
|
|
|
void NewMenu::drawFirstPageButtons(Stage const next) noexcept {
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
|
|
constexpr ImVec2 btnSz{60, 20};
|
|
if (ImGui::Button("Next", btnSz)) {
|
|
m_prev.emplace_back(m_stage);
|
|
m_stage = next;
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Cancel", btnSz)) {
|
|
ImGui::CloseCurrentPopup();
|
|
m_stage = Stage::Closed;
|
|
}
|
|
}
|
|
|
|
void NewMenu::drawLastPageButtons(Context &sctx) noexcept {
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
|
|
constexpr ImVec2 btnSz{60, 20};
|
|
if (ImGui::Button("Back", btnSz)) {
|
|
if (auto const p = m_prev.back(); p.ok()) {
|
|
m_stage = *p.value;
|
|
}
|
|
m_prev.pop_back();
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Finish", btnSz)) {
|
|
finish(sctx);
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Quit", btnSz)) {
|
|
ImGui::CloseCurrentPopup();
|
|
m_stage = Stage::Closed;
|
|
}
|
|
}
|
|
|
|
void NewMenu::finish(Context &sctx) noexcept {
|
|
if (m_itemName.len() == 0) {
|
|
oxLogError(ox::Error{1, "New file error: no file name"});
|
|
return;
|
|
}
|
|
auto const &im = *m_types[m_selectedType];
|
|
auto const path = sfmt("{}/{}.{}",
|
|
m_explorer.selectedPath().or_value(ox::String{}), m_itemName, im.fileExt());
|
|
if (sctx.project->exists(path)) {
|
|
oxLogError(ox::Error{1, "New file error: file already exists"});
|
|
return;
|
|
}
|
|
if (auto const err = im.write(sctx, path, m_selectedTemplate)) {
|
|
oxLogError(err);
|
|
return;
|
|
}
|
|
finished.emit(path);
|
|
m_stage = Stage::Closed;
|
|
}
|
|
|
|
}
|