Compare commits
3 Commits
e8a0ce88c5
...
161194c8b2
Author | SHA1 | Date | |
---|---|---|---|
161194c8b2 | |||
48603ea2c5 | |||
e2f2a17315 |
@ -88,11 +88,11 @@ static ox::Error toPngFile(
|
|||||||
|
|
||||||
TileSheetEditorImGui::TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path):
|
TileSheetEditorImGui::TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path):
|
||||||
Editor(std::move(path)),
|
Editor(std::move(path)),
|
||||||
m_sctx(sctx),
|
m_sctx{sctx},
|
||||||
m_tctx(m_sctx.tctx),
|
m_tctx{m_sctx.tctx},
|
||||||
m_view(m_sctx, itemPath(), *undoStack()),
|
m_palPicker{"Palette Chooser", keelCtx(sctx), FileExt_npal},
|
||||||
m_model(m_view.model()) {
|
m_view{m_sctx, itemPath(), *undoStack()},
|
||||||
std::ignore = setPaletteSelection();
|
m_model{m_view.model()} {
|
||||||
// connect signal/slots
|
// connect signal/slots
|
||||||
m_subsheetEditor.inputSubmitted.connect(this, &TileSheetEditorImGui::updateActiveSubsheet);
|
m_subsheetEditor.inputSubmitted.connect(this, &TileSheetEditorImGui::updateActiveSubsheet);
|
||||||
m_exportMenu.inputSubmitted.connect(this, &TileSheetEditorImGui::exportSubhseetToPng);
|
m_exportMenu.inputSubmitted.connect(this, &TileSheetEditorImGui::exportSubhseetToPng);
|
||||||
@ -132,10 +132,10 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
|||||||
if (key == turbine::Key::Escape) {
|
if (key == turbine::Key::Escape) {
|
||||||
m_subsheetEditor.close();
|
m_subsheetEditor.close();
|
||||||
m_exportMenu.close();
|
m_exportMenu.close();
|
||||||
|
m_palPicker.close();
|
||||||
}
|
}
|
||||||
auto const popupOpen = m_subsheetEditor.isOpen() || m_exportMenu.isOpen();
|
|
||||||
auto const pal = m_model.pal();
|
auto const pal = m_model.pal();
|
||||||
if (!popupOpen) {
|
if (ig::mainWinHasFocus() && !m_palPathFocused) {
|
||||||
auto const colorCnt = gfx::colorCnt(pal, m_model.palettePage());
|
auto const colorCnt = gfx::colorCnt(pal, m_model.palettePage());
|
||||||
if (key == turbine::Key::Alpha_D) {
|
if (key == turbine::Key::Alpha_D) {
|
||||||
m_tool = TileSheetTool::Draw;
|
m_tool = TileSheetTool::Draw;
|
||||||
@ -183,9 +183,8 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
||||||
auto const popupOpen = m_subsheetEditor.isOpen() || m_exportMenu.isOpen();
|
if (ig::mainWinHasFocus() && m_tool == TileSheetTool::Select) {
|
||||||
if (!popupOpen && m_tool == TileSheetTool::Select) {
|
if (ImGui::IsKeyDown(ImGuiKey_ModCtrl) && !m_palPathFocused) {
|
||||||
if (ImGui::IsKeyDown(ImGuiKey_ModCtrl)) {
|
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_A)) {
|
if (ImGui::IsKeyPressed(ImGuiKey_A)) {
|
||||||
auto const&img = m_model.activeSubSheet();
|
auto const&img = m_model.activeSubSheet();
|
||||||
m_model.setSelection({{}, {img.columns * TileWidth - 1, img.rows * TileHeight - 1}});
|
m_model.setSelection({{}, {img.columns * TileWidth - 1, img.rows * TileHeight - 1}});
|
||||||
@ -277,6 +276,11 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
|||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
m_subsheetEditor.draw(m_tctx);
|
m_subsheetEditor.draw(m_tctx);
|
||||||
m_exportMenu.draw(m_tctx);
|
m_exportMenu.draw(m_tctx);
|
||||||
|
if (auto pal = m_palPicker.draw(m_sctx)) {
|
||||||
|
if (*pal != m_model.palPath()) {
|
||||||
|
oxLogError(m_model.setPalette(*pal));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorImGui::drawSubsheetSelector(
|
void TileSheetEditorImGui::drawSubsheetSelector(
|
||||||
@ -437,20 +441,26 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorImGui::drawPaletteMenu() noexcept {
|
void TileSheetEditorImGui::drawPaletteMenu() noexcept {
|
||||||
|
ig::IDStackItem const idStackItem{"PaletteMenu"};
|
||||||
auto constexpr comboWidthSub = 62;
|
auto constexpr comboWidthSub = 62;
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - comboWidthSub);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - comboWidthSub);
|
||||||
auto constexpr palTags = ImGuiInputTextFlags_ReadOnly;
|
auto constexpr palTags = ImGuiInputTextFlags_ReadOnly;
|
||||||
if (ig::InputText("Palette", m_selectedPalette, palTags)) {
|
if (ig::InputTextWithHint("##Palette", "Path to Palette", m_model.palPath(), palTags)) {
|
||||||
oxLogError(m_model.setPalette(m_selectedPalette));
|
oxLogError(m_model.setPalette(m_model.palPath()));
|
||||||
}
|
}
|
||||||
|
m_palPathFocused = ImGui::IsItemFocused();
|
||||||
if (ig::DragDropTarget const dragDropTarget; dragDropTarget) {
|
if (ig::DragDropTarget const dragDropTarget; dragDropTarget) {
|
||||||
auto const [ref, err] = ig::getDragDropPayload<studio::FileRef>("FileRef");
|
auto const [ref, err] = ig::getDragDropPayload<studio::FileRef>("FileRef");
|
||||||
if (!err && endsWith(ref.path, FileExt_npal)) {
|
if (!err && endsWith(ref.path, FileExt_npal)) {
|
||||||
if (ref.path != m_selectedPalette) {
|
if (ref.path != m_model.palPath()) {
|
||||||
oxLogError(m_model.setPalette(ref.path));
|
oxLogError(m_model.setPalette(ref.path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Browse")) {
|
||||||
|
m_palPicker.open();
|
||||||
|
}
|
||||||
auto const pages = m_model.pal().pages.size();
|
auto const pages = m_model.pal().pages.size();
|
||||||
if (pages > 1) {
|
if (pages > 1) {
|
||||||
ig::IndentStackItem const indentStackItem{20};
|
ig::IndentStackItem const indentStackItem{20};
|
||||||
@ -521,7 +531,6 @@ ox::Error TileSheetEditorImGui::updateActiveSubsheet(ox::StringView const&name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error TileSheetEditorImGui::setPaletteSelection() noexcept {
|
ox::Error TileSheetEditorImGui::setPaletteSelection() noexcept {
|
||||||
m_selectedPalette = m_model.palPath();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <glutils/glutils.hpp>
|
#include <glutils/glutils.hpp>
|
||||||
#include <studio/editor.hpp>
|
#include <studio/editor.hpp>
|
||||||
|
#include <studio/filepickerpopup.hpp>
|
||||||
|
|
||||||
#include "tilesheetpixelgrid.hpp"
|
#include "tilesheetpixelgrid.hpp"
|
||||||
#include "tilesheetpixels.hpp"
|
#include "tilesheetpixels.hpp"
|
||||||
@ -46,17 +47,18 @@ class TileSheetEditorImGui: public studio::Editor {
|
|||||||
constexpr bool isOpen() const noexcept { return m_show; }
|
constexpr bool isOpen() const noexcept { return m_show; }
|
||||||
};
|
};
|
||||||
static constexpr float s_palViewWidth = 300;
|
static constexpr float s_palViewWidth = 300;
|
||||||
ox::String m_selectedPalette;
|
|
||||||
studio::StudioContext &m_sctx;
|
studio::StudioContext &m_sctx;
|
||||||
turbine::Context &m_tctx;
|
turbine::Context &m_tctx;
|
||||||
ox::Vector<ox::String> m_paletteList;
|
ox::Vector<ox::String> m_paletteList;
|
||||||
SubSheetEditor m_subsheetEditor;
|
SubSheetEditor m_subsheetEditor;
|
||||||
ExportMenu m_exportMenu;
|
ExportMenu m_exportMenu;
|
||||||
|
studio::FilePickerPopup m_palPicker;
|
||||||
glutils::FrameBuffer m_framebuffer;
|
glutils::FrameBuffer m_framebuffer;
|
||||||
TileSheetEditorView m_view;
|
TileSheetEditorView m_view;
|
||||||
TileSheetEditorModel &m_model;
|
TileSheetEditorModel &m_model;
|
||||||
ox::Vec2 m_prevMouseDownPos;
|
ox::Vec2 m_prevMouseDownPos;
|
||||||
TileSheetTool m_tool = TileSheetTool::Draw;
|
TileSheetTool m_tool = TileSheetTool::Draw;
|
||||||
|
bool m_palPathFocused{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path);
|
TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path);
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <ox/claw/read.hpp>
|
#include <ox/claw/read.hpp>
|
||||||
#include <ox/std/algorithm.hpp>
|
|
||||||
#include <ox/std/buffer.hpp>
|
|
||||||
#include <ox/std/memory.hpp>
|
#include <ox/std/memory.hpp>
|
||||||
|
|
||||||
#include <turbine/clipboard.hpp>
|
#include <turbine/clipboard.hpp>
|
||||||
@ -86,9 +84,9 @@ void TileSheetEditorModel::copy() {
|
|||||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||||
iterateSelectionRows(*m_selection, [&](int const x, int const y) {
|
iterateSelectionRows(*m_selection, [&](int const x, int const y) {
|
||||||
auto pt = ox::Point{x, y};
|
auto pt = ox::Point{x, y};
|
||||||
const auto&s = activeSubSheet();
|
auto const&s = activeSubSheet();
|
||||||
const auto idx = gfx::idx(s, pt);
|
auto const idx = gfx::idx(s, pt);
|
||||||
const auto c = getPixel(s, idx);
|
auto const c = getPixel(s, idx);
|
||||||
pt -= m_selection->a;
|
pt -= m_selection->a;
|
||||||
cb->addPixel(pt, c);
|
cb->addPixel(pt, c);
|
||||||
});
|
});
|
||||||
@ -149,11 +147,11 @@ size_t TileSheetEditorModel::palettePage() const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const palIdx) noexcept {
|
void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const palIdx) noexcept {
|
||||||
const auto &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
|
auto const &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
|
||||||
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
|
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto idx = gfx::idx(activeSubSheet, pt);
|
auto const idx = gfx::idx(activeSubSheet, pt);
|
||||||
if (m_ongoingDrawCommand) {
|
if (m_ongoingDrawCommand) {
|
||||||
m_updated = m_updated || m_ongoingDrawCommand->append(idx);
|
m_updated = m_updated || m_ongoingDrawCommand->append(idx);
|
||||||
} else if (getPixel(activeSubSheet, idx) != palIdx) {
|
} else if (getPixel(activeSubSheet, idx) != palIdx) {
|
||||||
@ -255,14 +253,16 @@ bool TileSheetEditorModel::updated() const noexcept {
|
|||||||
|
|
||||||
ox::Error TileSheetEditorModel::markUpdatedCmdId(studio::UndoCommand const*cmd) noexcept {
|
ox::Error TileSheetEditorModel::markUpdatedCmdId(studio::UndoCommand const*cmd) noexcept {
|
||||||
m_updated = true;
|
m_updated = true;
|
||||||
const auto cmdId = cmd->commandId();
|
auto const cmdId = cmd->commandId();
|
||||||
if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) {
|
if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) {
|
||||||
OX_RETURN_ERROR(readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).moveTo(m_pal));
|
if (readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).moveTo(m_pal)) {
|
||||||
m_palettePage = ox::min<size_t>(m_pal->pages.size(), 0);
|
m_pal = keel::AssetRef<Palette>{};
|
||||||
|
}
|
||||||
|
m_palettePage = ox::min<size_t>(pal().pages.size(), 0);
|
||||||
paletteChanged.emit();
|
paletteChanged.emit();
|
||||||
}
|
}
|
||||||
auto tsCmd = dynamic_cast<const TileSheetCommand*>(cmd);
|
auto const tsCmd = dynamic_cast<TileSheetCommand const*>(cmd);
|
||||||
auto idx = validateSubSheetIdx(m_img, tsCmd->subsheetIdx());
|
auto const idx = validateSubSheetIdx(m_img, tsCmd->subsheetIdx());
|
||||||
if (idx != m_activeSubsSheetIdx) {
|
if (idx != m_activeSubsSheetIdx) {
|
||||||
setActiveSubsheet(idx);
|
setActiveSubsheet(idx);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,10 @@ void ProjectExplorer::fileOpened(ox::StringViewCR path) const noexcept {
|
|||||||
fileChosen.emit(path);
|
fileChosen.emit(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectExplorer::fileDeleted(ox::StringViewCR path) const noexcept {
|
||||||
|
deleteItem.emit(path);
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept {
|
void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept {
|
||||||
if (ImGui::BeginPopupContextItem("FileMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
if (ImGui::BeginPopupContextItem("FileMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
||||||
if (ImGui::MenuItem("Delete")) {
|
if (ImGui::MenuItem("Delete")) {
|
||||||
|
@ -28,6 +28,8 @@ class ProjectExplorer final: public FileExplorer {
|
|||||||
protected:
|
protected:
|
||||||
void fileOpened(ox::StringViewCR path) const noexcept override;
|
void fileOpened(ox::StringViewCR path) const noexcept override;
|
||||||
|
|
||||||
|
void fileDeleted(ox::StringViewCR path) const noexcept override;
|
||||||
|
|
||||||
void fileContextMenu(ox::StringViewCR path) const noexcept override;
|
void fileContextMenu(ox::StringViewCR path) const noexcept override;
|
||||||
|
|
||||||
void dirContextMenu(ox::StringViewCR path) const noexcept override;
|
void dirContextMenu(ox::StringViewCR path) const noexcept override;
|
||||||
|
@ -225,7 +225,9 @@ void StudioUI::drawTabs() noexcept {
|
|||||||
if (m_activeEditorOnLastDraw != e.get()) [[unlikely]] {
|
if (m_activeEditorOnLastDraw != e.get()) [[unlikely]] {
|
||||||
m_activeEditor->onActivated();
|
m_activeEditor->onActivated();
|
||||||
}
|
}
|
||||||
e->draw(m_sctx);
|
if (open) [[likely]] {
|
||||||
|
e->draw(m_sctx);
|
||||||
|
}
|
||||||
m_activeEditorOnLastDraw = e.get();
|
m_activeEditorOnLastDraw = e.get();
|
||||||
}
|
}
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
|
38
src/olympic/studio/modlib/include/studio/filepickerpopup.hpp
Normal file
38
src/olympic/studio/modlib/include/studio/filepickerpopup.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "popup.hpp"
|
||||||
|
#include "filetreemodel.hpp"
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
class FilePickerPopup {
|
||||||
|
|
||||||
|
private:
|
||||||
|
ox::String m_name;
|
||||||
|
FileExplorer m_explorer;
|
||||||
|
ox::Vector<ox::String> const m_fileExts;
|
||||||
|
bool m_open{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FilePickerPopup(ox::StringParam name, keel::Context &kctx, ox::StringParam fileExt) noexcept;
|
||||||
|
|
||||||
|
explicit FilePickerPopup(ox::StringParam name, keel::Context &kctx, ox::Vector<ox::String> fileExts) noexcept;
|
||||||
|
|
||||||
|
void refresh() noexcept;
|
||||||
|
|
||||||
|
void open() noexcept;
|
||||||
|
|
||||||
|
void close() noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool isOpen() const noexcept;
|
||||||
|
|
||||||
|
ox::Optional<ox::String> draw(StudioContext &ctx) noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
constexpr void safeDelete(class FileTreeModel *m) noexcept;
|
constexpr void safeDelete(class FileTreeModel const *m) noexcept;
|
||||||
|
|
||||||
class FileExplorer: public ox::SignalHandler {
|
class FileExplorer: public ox::SignalHandler {
|
||||||
|
|
||||||
@ -32,8 +32,6 @@ class FileExplorer: public ox::SignalHandler {
|
|||||||
m_kctx{kctx},
|
m_kctx{kctx},
|
||||||
m_fileDraggable{fileDraggable} {}
|
m_fileDraggable{fileDraggable} {}
|
||||||
|
|
||||||
virtual ~FileExplorer() = default;
|
|
||||||
|
|
||||||
void draw(StudioContext &ctx, ImVec2 const &sz) const noexcept;
|
void draw(StudioContext &ctx, ImVec2 const &sz) const noexcept;
|
||||||
|
|
||||||
void setModel(ox::UPtr<FileTreeModel> &&model, bool selectRoot = false) noexcept;
|
void setModel(ox::UPtr<FileTreeModel> &&model, bool selectRoot = false) noexcept;
|
||||||
@ -45,6 +43,8 @@ class FileExplorer: public ox::SignalHandler {
|
|||||||
|
|
||||||
virtual void fileOpened(ox::StringViewCR path) const noexcept;
|
virtual void fileOpened(ox::StringViewCR path) const noexcept;
|
||||||
|
|
||||||
|
virtual void fileDeleted(ox::StringViewCR path) const noexcept;
|
||||||
|
|
||||||
void drawFileContextMenu(ox::CStringViewCR path) const noexcept;
|
void drawFileContextMenu(ox::CStringViewCR path) const noexcept;
|
||||||
|
|
||||||
void drawDirContextMenu(ox::CStringViewCR path) const noexcept;
|
void drawDirContextMenu(ox::CStringViewCR path) const noexcept;
|
||||||
@ -116,7 +116,7 @@ class FileTreeModel {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr void safeDelete(FileTreeModel *m) noexcept {
|
constexpr void safeDelete(FileTreeModel const *m) noexcept {
|
||||||
delete m;
|
delete m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +155,23 @@ TextInput<ox::IString<MaxChars>> InputText(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t MaxChars = 50>
|
||||||
|
TextInput<ox::IString<MaxChars>> InputTextWithHint(
|
||||||
|
ox::CStringViewCR label,
|
||||||
|
ox::CStringViewCR hint,
|
||||||
|
ox::StringViewCR currentText,
|
||||||
|
ImGuiInputTextFlags const flags = 0,
|
||||||
|
ImGuiInputTextCallback const callback = nullptr,
|
||||||
|
void *user_data = nullptr) noexcept {
|
||||||
|
TextInput<ox::IString<MaxChars>> out = {.text = currentText};
|
||||||
|
out.changed = ImGui::InputTextWithHint(
|
||||||
|
label.c_str(), hint.c_str(), out.text.data(), MaxChars + 1, flags, callback, user_data);
|
||||||
|
if (out.changed) {
|
||||||
|
std::ignore = out.text.unsafeResize(ox::strlen(out.text.c_str()));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t StrCap>
|
template<size_t StrCap>
|
||||||
bool InputText(
|
bool InputText(
|
||||||
ox::CStringViewCR label,
|
ox::CStringViewCR label,
|
||||||
|
@ -2,6 +2,7 @@ add_library(
|
|||||||
Studio
|
Studio
|
||||||
configio.cpp
|
configio.cpp
|
||||||
editor.cpp
|
editor.cpp
|
||||||
|
filepickerpopup.cpp
|
||||||
filetreemodel.cpp
|
filetreemodel.cpp
|
||||||
imguiutil.cpp
|
imguiutil.cpp
|
||||||
module.cpp
|
module.cpp
|
||||||
|
75
src/olympic/studio/modlib/src/filepickerpopup.cpp
Normal file
75
src/olympic/studio/modlib/src/filepickerpopup.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <studio/imguiutil.hpp>
|
||||||
|
|
||||||
|
#include <studio/filepickerpopup.hpp>
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
FilePickerPopup::FilePickerPopup(
|
||||||
|
ox::StringParam name,
|
||||||
|
keel::Context &kctx,
|
||||||
|
ox::StringParam fileExt) noexcept:
|
||||||
|
m_name{std::move(name)},
|
||||||
|
m_explorer{kctx},
|
||||||
|
m_fileExts{std::move(fileExt)} {
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePickerPopup::FilePickerPopup(
|
||||||
|
ox::StringParam name,
|
||||||
|
keel::Context &kctx,
|
||||||
|
ox::Vector<ox::String> fileExts) noexcept:
|
||||||
|
m_name{std::move(name)},
|
||||||
|
m_explorer{kctx},
|
||||||
|
m_fileExts{std::move(fileExts)} {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilePickerPopup::refresh() noexcept {
|
||||||
|
m_explorer.setModel(buildFileTreeModel(
|
||||||
|
m_explorer,
|
||||||
|
[this](ox::StringViewCR path, ox::FileStat const &s) {
|
||||||
|
auto const [ext, err] = fileExt(path);
|
||||||
|
return
|
||||||
|
s.fileType == ox::FileType::Directory ||
|
||||||
|
(s.fileType == ox::FileType::NormalFile && !err && m_fileExts.contains(ext));
|
||||||
|
},
|
||||||
|
false).or_value(ox::UPtr<FileTreeModel>{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilePickerPopup::open() noexcept {
|
||||||
|
refresh();
|
||||||
|
m_open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilePickerPopup::close() noexcept {
|
||||||
|
m_explorer.setModel(ox::UPtr<FileTreeModel>{});
|
||||||
|
m_open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilePickerPopup::isOpen() const noexcept {
|
||||||
|
return m_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Optional<ox::String> FilePickerPopup::draw(StudioContext &ctx) noexcept {
|
||||||
|
ox::Optional<ox::String> out;
|
||||||
|
if (!m_open) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
if (ig::BeginPopup(ctx.tctx, m_name, m_open, {380, 340})) {
|
||||||
|
auto const vp = ImGui::GetContentRegionAvail();
|
||||||
|
m_explorer.draw(ctx, {vp.x, vp.y - 30});
|
||||||
|
if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK) {
|
||||||
|
auto p = m_explorer.selectedPath();
|
||||||
|
if (p) {
|
||||||
|
out.emplace(*p);
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -39,6 +39,8 @@ ox::Optional<ox::String> FileExplorer::selectedPath() const {
|
|||||||
|
|
||||||
void FileExplorer::fileOpened(ox::StringViewCR) const noexcept {}
|
void FileExplorer::fileOpened(ox::StringViewCR) const noexcept {}
|
||||||
|
|
||||||
|
void FileExplorer::fileDeleted(ox::StringViewCR) const noexcept {}
|
||||||
|
|
||||||
void FileExplorer::drawFileContextMenu(ox::CStringViewCR path) const noexcept {
|
void FileExplorer::drawFileContextMenu(ox::CStringViewCR path) const noexcept {
|
||||||
ig::IDStackItem const idStackItem{path};
|
ig::IDStackItem const idStackItem{path};
|
||||||
fileContextMenu(path);
|
fileContextMenu(path);
|
||||||
@ -84,7 +86,7 @@ void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
|
|||||||
auto const selected = m_explorer.selected(this) ? ImGuiTreeNodeFlags_Selected : 0;
|
auto const selected = m_explorer.selected(this) ? ImGuiTreeNodeFlags_Selected : 0;
|
||||||
if (!m_children.empty()) {
|
if (!m_children.empty()) {
|
||||||
auto const nodeOpen = ImGui::TreeNodeEx(m_name.c_str(), dirFlags | selected);
|
auto const nodeOpen = ImGui::TreeNodeEx(m_name.c_str(), dirFlags | selected);
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemActivated() || ImGui::IsItemClicked(1)) {
|
||||||
m_explorer.setSelectedNode(this);
|
m_explorer.setSelectedNode(this);
|
||||||
}
|
}
|
||||||
ig::IDStackItem const idStackItem{m_name};
|
ig::IDStackItem const idStackItem{m_name};
|
||||||
@ -97,11 +99,15 @@ void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ImGui::TreeNodeEx(m_name.c_str(), ImGuiTreeNodeFlags_Leaf | selected)) {
|
if (ImGui::TreeNodeEx(m_name.c_str(), ImGuiTreeNodeFlags_Leaf | selected)) {
|
||||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
if (ImGui::IsItemActivated() || ImGui::IsItemClicked(1)) {
|
||||||
|
m_explorer.setSelectedNode(this);
|
||||||
|
}
|
||||||
|
if ((ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) ||
|
||||||
|
(ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter))) {
|
||||||
m_explorer.fileOpened(m_fullPath);
|
m_explorer.fileOpened(m_fullPath);
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)) {
|
||||||
m_explorer.setSelectedNode(this);
|
m_explorer.fileDeleted(m_fullPath);
|
||||||
}
|
}
|
||||||
m_explorer.drawFileContextMenu(m_fullPath);
|
m_explorer.drawFileContextMenu(m_fullPath);
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user