Merge commit 'b212d4b73cd746fe45912e9685666e87bddb649e'
All checks were successful
Build / build (push) Successful in 4m8s
All checks were successful
Build / build (push) Successful in 4m8s
This commit is contained in:
commit
80bab935da
@ -185,8 +185,7 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
|
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
|
||||||
const auto pathLen = ox::strlen(path);
|
for (auto i = 0u; i < path.len() && path[0] == '/'; i++) {
|
||||||
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
|
|
||||||
path = substr(path, 1);
|
path = substr(path, 1);
|
||||||
}
|
}
|
||||||
return {path.data(), path.bytes()};
|
return {path.data(), path.bytes()};
|
||||||
|
3
deps/nostalgia/release-notes.md
vendored
3
deps/nostalgia/release-notes.md
vendored
@ -4,6 +4,8 @@
|
|||||||
* Add PaletteV5 to accommodate namespace change.
|
* Add PaletteV5 to accommodate namespace change.
|
||||||
* Add TileSheetV5. TileSheetV5 retains the bpp field for the sake of
|
* Add TileSheetV5. TileSheetV5 retains the bpp field for the sake of
|
||||||
CompactTileSheet, but always store it pixel as 8 bpp for itself.
|
CompactTileSheet, but always store it pixel as 8 bpp for itself.
|
||||||
|
* Add ability to move subsheets in the subsheet tree.
|
||||||
|
* Add Flip X and Flip Y button for TileSheet Editor.
|
||||||
* Replace file picker combo boxes with a browse button and file picker, and
|
* Replace file picker combo boxes with a browse button and file picker, and
|
||||||
support for dragging files from the project explorer.
|
support for dragging files from the project explorer.
|
||||||
* Add ability to create directories.
|
* Add ability to create directories.
|
||||||
@ -12,3 +14,4 @@
|
|||||||
* Ctrl-<num key> keyboard shortcuts for jumping between tabs.
|
* Ctrl-<num key> keyboard shortcuts for jumping between tabs.
|
||||||
* Fix Palette Editor to ignore keyboard input when popups are open.
|
* Fix Palette Editor to ignore keyboard input when popups are open.
|
||||||
* Palette Editor move color mechanism now uses drag and drop.
|
* Palette Editor move color mechanism now uses drag and drop.
|
||||||
|
* Add ability to reorder Palette pages.
|
||||||
|
29
deps/nostalgia/sample_project/Palettes/Dirt.npal
vendored
29
deps/nostalgia/sample_project/Palettes/Dirt.npal
vendored
@ -1 +1,28 @@
|
|||||||
K1;0f75977f-1c52-45f8-9793-52ea2dc200a0;M2;net.drinkingtea.nostalgia.core.Palette;1;ûÿ³Ö
|
K1;0f75977f-1c52-45f8-9793-52ea2dc200a0;O1;net.drinkingtea.nostalgia.gfx.Palette;5;{
|
||||||
|
"colorNames" :
|
||||||
|
[
|
||||||
|
"Color 1",
|
||||||
|
"Color 2"
|
||||||
|
],
|
||||||
|
"pages" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"colors" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"a" : 1,
|
||||||
|
"b" : 31,
|
||||||
|
"g" : 31,
|
||||||
|
"r" : 31
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a" : 1,
|
||||||
|
"b" : 22,
|
||||||
|
"g" : 22,
|
||||||
|
"r" : 22
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" : "Page 1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
37
deps/nostalgia/sample_project/Palettes/Logo.npal
vendored
37
deps/nostalgia/sample_project/Palettes/Logo.npal
vendored
@ -1 +1,36 @@
|
|||||||
K1;c79f21e2-f74f-4ad9-90ed-32b0ef7da6ed;M2;net.drinkingtea.nostalgia.core.Palette;1;PÛ{³ÖCˆ
|
K1;c79f21e2-f74f-4ad9-90ed-32b0ef7da6ed;O1;net.drinkingtea.nostalgia.gfx.Palette;5;{
|
||||||
|
"colorNames" :
|
||||||
|
[
|
||||||
|
"Color 1",
|
||||||
|
"Color 2",
|
||||||
|
"Color 3",
|
||||||
|
"Color 4"
|
||||||
|
],
|
||||||
|
"pages" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"colors" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"b" : 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b" : 22,
|
||||||
|
"g" : 22,
|
||||||
|
"r" : 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b" : 27,
|
||||||
|
"g" : 27,
|
||||||
|
"r" : 27
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b" : 20,
|
||||||
|
"g" : 8,
|
||||||
|
"r" : 8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" : "Page 1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
deps/nostalgia/sample_project/TileSheets/Logo.nts
vendored
BIN
deps/nostalgia/sample_project/TileSheets/Logo.nts
vendored
Binary file not shown.
@ -289,7 +289,7 @@ constexpr ox::Error repair(TileSheetV4 &ts) noexcept {
|
|||||||
|
|
||||||
|
|
||||||
struct TileSheetV5 {
|
struct TileSheetV5 {
|
||||||
using SubSheetIdx = ox::Vector<std::size_t, 4>;
|
using SubSheetIdx = ox::Vector<uint32_t, 4>;
|
||||||
|
|
||||||
struct SubSheet {
|
struct SubSheet {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet.SubSheet";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet.SubSheet";
|
||||||
@ -445,24 +445,26 @@ TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubShe
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
TileSheet::SubSheet const&getSubSheet(
|
TileSheet::SubSheet const&getSubSheet(
|
||||||
TileSheet::SubSheetIdx const&idx,
|
ox::SpanView<uint32_t> const&idx,
|
||||||
std::size_t idxIt,
|
std::size_t idxIt,
|
||||||
TileSheet::SubSheet const&pSubsheet) noexcept;
|
TileSheet::SubSheet const&pSubsheet) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
TileSheet::SubSheet &getSubSheet(
|
TileSheet::SubSheet &getSubSheet(
|
||||||
TileSheet::SubSheetIdx const&idx,
|
ox::SpanView<uint32_t> const&idx,
|
||||||
std::size_t idxIt,
|
std::size_t idxIt,
|
||||||
TileSheet::SubSheet &pSubsheet) noexcept;
|
TileSheet::SubSheet &pSubsheet) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, TileSheet::SubSheetIdx const&idx) noexcept;
|
TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, ox::SpanView<uint32_t> const &idx) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
TileSheet::SubSheet &getSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept;
|
TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx) noexcept;
|
||||||
|
|
||||||
ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept;
|
ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept;
|
||||||
|
|
||||||
|
ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx, TileSheet::SubSheet ss) noexcept;
|
||||||
|
|
||||||
ox::Error rmSubSheet(
|
ox::Error rmSubSheet(
|
||||||
TileSheet &ts,
|
TileSheet &ts,
|
||||||
TileSheet::SubSheetIdx const&idx,
|
TileSheet::SubSheetIdx const&idx,
|
||||||
|
@ -1,18 +1,6 @@
|
|||||||
target_sources(
|
|
||||||
NostalgiaCore-Studio PRIVATE
|
|
||||||
commands/addcolorcommand.cpp
|
|
||||||
commands/addpagecommand.cpp
|
|
||||||
commands/applycolorallpagescommand.cpp
|
|
||||||
commands/duplicatepagecommand.cpp
|
|
||||||
commands/movecolorcommand.cpp
|
|
||||||
commands/removecolorcommand.cpp
|
|
||||||
commands/removepagecommand.cpp
|
|
||||||
commands/renamepagecommand.cpp
|
|
||||||
commands/updatecolorcommand.cpp
|
|
||||||
commands/updatecolorinfocommand.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_sources(
|
target_sources(
|
||||||
NostalgiaCore-Studio-ImGui PRIVATE
|
NostalgiaCore-Studio-ImGui PRIVATE
|
||||||
paletteeditor-imgui.cpp
|
paletteeditor-imgui.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(commands)
|
15
deps/nostalgia/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/CMakeLists.txt
vendored
Normal file
15
deps/nostalgia/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
target_sources(
|
||||||
|
NostalgiaCore-Studio PRIVATE
|
||||||
|
addcolorcommand.cpp
|
||||||
|
addpagecommand.cpp
|
||||||
|
applycolorallpagescommand.cpp
|
||||||
|
duplicatepagecommand.cpp
|
||||||
|
movecolorcommand.cpp
|
||||||
|
movepagecommand.cpp
|
||||||
|
removecolorcommand.cpp
|
||||||
|
removepagecommand.cpp
|
||||||
|
renamepagecommand.cpp
|
||||||
|
updatecolorcommand.cpp
|
||||||
|
updatecolorinfocommand.cpp
|
||||||
|
)
|
@ -12,6 +12,7 @@ enum class PaletteEditorCommandId {
|
|||||||
AddPage,
|
AddPage,
|
||||||
DuplicatePage,
|
DuplicatePage,
|
||||||
RemovePage,
|
RemovePage,
|
||||||
|
MovePage,
|
||||||
AddColor,
|
AddColor,
|
||||||
RemoveColor,
|
RemoveColor,
|
||||||
UpdateColorInfo,
|
UpdateColorInfo,
|
||||||
|
40
deps/nostalgia/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.cpp
vendored
Normal file
40
deps/nostalgia/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.cpp
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "commands.hpp"
|
||||||
|
|
||||||
|
#include "movepagecommand.hpp"
|
||||||
|
|
||||||
|
namespace nostalgia::gfx {
|
||||||
|
|
||||||
|
MovePageCommand::MovePageCommand(
|
||||||
|
Palette &pal,
|
||||||
|
size_t const srcIdx,
|
||||||
|
size_t const dstIdx) noexcept:
|
||||||
|
m_pal(pal),
|
||||||
|
m_srcIdx(srcIdx),
|
||||||
|
m_dstIdx(dstIdx) {}
|
||||||
|
|
||||||
|
int MovePageCommand::commandId() const noexcept {
|
||||||
|
return static_cast<int>(PaletteEditorCommandId::MovePage);
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error MovePageCommand::redo() noexcept {
|
||||||
|
movePage(m_srcIdx, m_dstIdx);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error MovePageCommand::undo() noexcept {
|
||||||
|
movePage(m_dstIdx, m_srcIdx);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void MovePageCommand::movePage(
|
||||||
|
size_t const srcIdx, size_t const dstIdx) noexcept {
|
||||||
|
auto page = std::move(m_pal.pages[srcIdx]);
|
||||||
|
std::ignore = m_pal.pages.erase(srcIdx);
|
||||||
|
m_pal.pages.emplace(dstIdx, std::move(page));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
deps/nostalgia/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.hpp
vendored
Normal file
35
deps/nostalgia/src/nostalgia/modules/gfx/src/studio/paletteeditor/commands/movepagecommand.hpp
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <studio/studio.hpp>
|
||||||
|
|
||||||
|
#include <nostalgia/gfx/palette.hpp>
|
||||||
|
|
||||||
|
namespace nostalgia::gfx {
|
||||||
|
|
||||||
|
class MovePageCommand: public studio::UndoCommand {
|
||||||
|
private:
|
||||||
|
Palette &m_pal;
|
||||||
|
std::size_t const m_srcIdx = 0;
|
||||||
|
std::size_t const m_dstIdx = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MovePageCommand(Palette &pal, size_t srcIdx, size_t dstIdx) noexcept;
|
||||||
|
|
||||||
|
~MovePageCommand() noexcept override = default;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int commandId() const noexcept override;
|
||||||
|
|
||||||
|
ox::Error redo() noexcept override;
|
||||||
|
|
||||||
|
ox::Error undo() noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void movePage(size_t srcIdx, size_t dstIdx) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
#include "commands/applycolorallpagescommand.hpp"
|
#include "commands/applycolorallpagescommand.hpp"
|
||||||
#include "commands/duplicatepagecommand.hpp"
|
#include "commands/duplicatepagecommand.hpp"
|
||||||
#include "commands/movecolorcommand.hpp"
|
#include "commands/movecolorcommand.hpp"
|
||||||
|
#include "commands/movepagecommand.hpp"
|
||||||
#include "commands/removecolorcommand.hpp"
|
#include "commands/removecolorcommand.hpp"
|
||||||
#include "commands/removepagecommand.hpp"
|
#include "commands/removepagecommand.hpp"
|
||||||
#include "commands/renamepagecommand.hpp"
|
#include "commands/renamepagecommand.hpp"
|
||||||
@ -19,6 +20,7 @@
|
|||||||
|
|
||||||
#include "paletteeditor-imgui.hpp"
|
#include "paletteeditor-imgui.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace nostalgia::gfx {
|
namespace nostalgia::gfx {
|
||||||
|
|
||||||
namespace ig = studio::ig;
|
namespace ig = studio::ig;
|
||||||
@ -33,6 +35,16 @@ OX_MODEL_BEGIN(ColorDragDrop)
|
|||||||
OX_MODEL_FIELD(i)
|
OX_MODEL_FIELD(i)
|
||||||
OX_MODEL_END()
|
OX_MODEL_END()
|
||||||
|
|
||||||
|
struct PageDragDrop {
|
||||||
|
static constexpr auto TypeName = "nostalgia.gfx.PageDragDrop";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
uint32_t page{};
|
||||||
|
};
|
||||||
|
|
||||||
|
OX_MODEL_BEGIN(PageDragDrop)
|
||||||
|
OX_MODEL_FIELD(page)
|
||||||
|
OX_MODEL_END()
|
||||||
|
|
||||||
void PaletteEditorImGui::PageRenameDialog::draw(turbine::Context &tctx) noexcept {
|
void PaletteEditorImGui::PageRenameDialog::draw(turbine::Context &tctx) noexcept {
|
||||||
if (!m_show) {
|
if (!m_show) {
|
||||||
return;
|
return;
|
||||||
@ -235,6 +247,16 @@ void PaletteEditorImGui::drawPagesEditor() noexcept {
|
|||||||
if (ImGui::Selectable("##PageRow", i == m_page, ImGuiSelectableFlags_SpanAllColumns)) {
|
if (ImGui::Selectable("##PageRow", i == m_page, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||||
m_page = i;
|
m_page = i;
|
||||||
}
|
}
|
||||||
|
std::ignore = ig::dragDropSource([this, i] {
|
||||||
|
ImGui::Text("%s", m_pal.pages[i].name.c_str());
|
||||||
|
return ig::setDragDropPayload(PageDragDrop{i});
|
||||||
|
}, ImGuiDragDropFlags_SourceAllowNullID);
|
||||||
|
if (ig::DragDropTarget const d; d) {
|
||||||
|
auto const [src, err] = ig::getDragDropPayload<PageDragDrop>();
|
||||||
|
if (!err) {
|
||||||
|
std::ignore = pushCommand<MovePageCommand>(m_pal, src.page, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
|
@ -5,6 +5,7 @@ target_sources(
|
|||||||
deletetilescommand.cpp
|
deletetilescommand.cpp
|
||||||
drawcommand.cpp
|
drawcommand.cpp
|
||||||
flipcommand.cpp
|
flipcommand.cpp
|
||||||
|
movesubsheetcommand.cpp
|
||||||
inserttilescommand.cpp
|
inserttilescommand.cpp
|
||||||
palettechangecommand.cpp
|
palettechangecommand.cpp
|
||||||
rmsubsheetcommand.cpp
|
rmsubsheetcommand.cpp
|
||||||
|
@ -15,9 +15,10 @@ enum class CommandId {
|
|||||||
AddSubSheet,
|
AddSubSheet,
|
||||||
RmSubSheet,
|
RmSubSheet,
|
||||||
DeleteTile,
|
DeleteTile,
|
||||||
FlipXCommand,
|
FlipX,
|
||||||
FlipYCommand,
|
FlipY,
|
||||||
InsertTile,
|
InsertTile,
|
||||||
|
MoveSubSheet,
|
||||||
UpdateSubSheet,
|
UpdateSubSheet,
|
||||||
Cut,
|
Cut,
|
||||||
Paste,
|
Paste,
|
||||||
|
@ -31,7 +31,7 @@ ox::Error FlipXCommand::undo() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int FlipXCommand::commandId() const noexcept {
|
int FlipXCommand::commandId() const noexcept {
|
||||||
return static_cast<int>(CommandId::FlipXCommand);
|
return static_cast<int>(CommandId::FlipX);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheetIdx const &FlipXCommand::subsheetIdx() const noexcept {
|
TileSheet::SubSheetIdx const &FlipXCommand::subsheetIdx() const noexcept {
|
||||||
@ -62,7 +62,7 @@ ox::Error FlipYCommand::undo() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int FlipYCommand::commandId() const noexcept {
|
int FlipYCommand::commandId() const noexcept {
|
||||||
return static_cast<int>(CommandId::FlipYCommand);
|
return static_cast<int>(CommandId::FlipY);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheetIdx const &FlipYCommand::subsheetIdx() const noexcept {
|
TileSheet::SubSheetIdx const &FlipYCommand::subsheetIdx() const noexcept {
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "movesubsheetcommand.hpp"
|
||||||
|
|
||||||
|
namespace nostalgia::gfx {
|
||||||
|
|
||||||
|
MoveSubSheetCommand::MoveSubSheetCommand(
|
||||||
|
TileSheet &img,
|
||||||
|
TileSheet::SubSheetIdx src,
|
||||||
|
TileSheet::SubSheetIdx dst) noexcept:
|
||||||
|
m_img{img},
|
||||||
|
m_src{std::move(src)},
|
||||||
|
m_dst{std::move(dst)} {
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error MoveSubSheetCommand::redo() noexcept {
|
||||||
|
m_active = &m_dst;
|
||||||
|
TileSheet::SubSheet ss = std::move(getSubSheet(m_img, m_src));
|
||||||
|
OX_RETURN_ERROR(rmSubSheet(m_img, m_src));
|
||||||
|
return insertSubSheet(m_img, m_dst, std::move(ss));
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error MoveSubSheetCommand::undo() noexcept {
|
||||||
|
m_active = &m_src;
|
||||||
|
TileSheet::SubSheet ss = std::move(getSubSheet(m_img, m_dst));
|
||||||
|
OX_RETURN_ERROR(rmSubSheet(m_img, m_dst));
|
||||||
|
return insertSubSheet(m_img, m_src, std::move(ss));
|
||||||
|
}
|
||||||
|
|
||||||
|
int MoveSubSheetCommand::commandId() const noexcept {
|
||||||
|
return static_cast<int>(CommandId::MoveSubSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
TileSheet::SubSheetIdx const&MoveSubSheetCommand::subsheetIdx() const noexcept {
|
||||||
|
return *m_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "commands.hpp"
|
||||||
|
|
||||||
|
namespace nostalgia::gfx {
|
||||||
|
|
||||||
|
class MoveSubSheetCommand: public TileSheetCommand {
|
||||||
|
private:
|
||||||
|
TileSheet &m_img;
|
||||||
|
TileSheet::SubSheetIdx m_src;
|
||||||
|
TileSheet::SubSheetIdx m_dst;
|
||||||
|
TileSheet::SubSheetIdx *m_active = &m_dst;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MoveSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept;
|
||||||
|
|
||||||
|
ox::Error redo() noexcept final;
|
||||||
|
|
||||||
|
ox::Error undo() noexcept final;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int commandId() const noexcept final;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -15,6 +15,16 @@ namespace nostalgia::gfx {
|
|||||||
|
|
||||||
namespace ig = studio::ig;
|
namespace ig = studio::ig;
|
||||||
|
|
||||||
|
struct SubSheetRef {
|
||||||
|
static constexpr auto TypeName = "nostalgia.gfx.studio.SubSheetRef";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
TileSheet::SubSheetIdx subsheet{};
|
||||||
|
};
|
||||||
|
|
||||||
|
OX_MODEL_BEGIN(SubSheetRef)
|
||||||
|
OX_MODEL_FIELD(subsheet)
|
||||||
|
OX_MODEL_END()
|
||||||
|
|
||||||
struct TileSheetEditorConfig {
|
struct TileSheetEditorConfig {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetEditorConfig";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetEditorConfig";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
@ -204,7 +214,7 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
|||||||
ImGui::BeginChild("Controls", {s_palViewWidth - 8, paneSize.y}, true);
|
ImGui::BeginChild("Controls", {s_palViewWidth - 8, paneSize.y}, true);
|
||||||
{
|
{
|
||||||
auto const controlsSize = ImGui::GetContentRegionAvail();
|
auto const controlsSize = ImGui::GetContentRegionAvail();
|
||||||
ImGui::BeginChild("ToolBox", {s_palViewWidth - 24, 30}, true);
|
ImGui::BeginChild("ToolBox", {168, 32}, true);
|
||||||
{
|
{
|
||||||
auto const btnSz = ImVec2{45, 14};
|
auto const btnSz = ImVec2{45, 14};
|
||||||
if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) {
|
if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) {
|
||||||
@ -222,9 +232,10 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::BeginChild("OperationsBox", {s_palViewWidth - 24, ig::BtnSz.y + 17}, true);
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginChild("OperationsBox", {0, 32}, true);
|
||||||
{
|
{
|
||||||
auto constexpr btnSz = ImVec2{55, ig::BtnSz.y};
|
auto constexpr btnSz = ImVec2{55, 16};
|
||||||
if (ig::PushButton("Flip X", btnSz)) {
|
if (ig::PushButton("Flip X", btnSz)) {
|
||||||
oxLogError(m_model.flipX());
|
oxLogError(m_model.flipX());
|
||||||
}
|
}
|
||||||
@ -309,6 +320,16 @@ void TileSheetEditorImGui::drawSubsheetSelector(
|
|||||||
| (rowSelected ? ImGuiTreeNodeFlags_Selected : 0);
|
| (rowSelected ? ImGuiTreeNodeFlags_Selected : 0);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
auto const open = ImGui::TreeNodeEx(lbl.c_str(), flags);
|
auto const open = ImGui::TreeNodeEx(lbl.c_str(), flags);
|
||||||
|
std::ignore = ig::dragDropSource([&subsheet, &path] {
|
||||||
|
ImGui::Text("%s", subsheet.name.c_str());
|
||||||
|
return ig::setDragDropPayload(SubSheetRef{path});
|
||||||
|
});
|
||||||
|
if (ig::DragDropTarget const dragDropTarget; dragDropTarget) {
|
||||||
|
auto const [ref, err] = ig::getDragDropPayload<SubSheetRef>();
|
||||||
|
if (!err) {
|
||||||
|
oxLogError(m_model.moveSubSheet(ref.subsheet, path));
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
setActiveSubsheet(path);
|
setActiveSubsheet(path);
|
||||||
@ -330,7 +351,7 @@ void TileSheetEditorImGui::drawSubsheetSelector(
|
|||||||
ImGui::Text("--");
|
ImGui::Text("--");
|
||||||
}
|
}
|
||||||
if (open) {
|
if (open) {
|
||||||
for (auto i = 0ul; auto &child : subsheet.subsheets) {
|
for (uint32_t i{}; auto &child : subsheet.subsheets) {
|
||||||
path.push_back(i);
|
path.push_back(i);
|
||||||
ImGui::PushID(static_cast<int>(i));
|
ImGui::PushID(static_cast<int>(i));
|
||||||
ig::IndentStackItem const indentStackItem{-indentReduce};
|
ig::IndentStackItem const indentStackItem{-indentReduce};
|
||||||
|
@ -45,7 +45,7 @@ class TileSheetEditorImGui: public studio::Editor {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
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 = 335;
|
||||||
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;
|
||||||
@ -58,6 +58,7 @@ class TileSheetEditorImGui: public studio::Editor {
|
|||||||
ox::Vec2 m_prevMouseDownPos;
|
ox::Vec2 m_prevMouseDownPos;
|
||||||
TileSheetTool m_tool = TileSheetTool::Draw;
|
TileSheetTool m_tool = TileSheetTool::Draw;
|
||||||
bool m_palPathFocused{};
|
bool m_palPathFocused{};
|
||||||
|
ox::Vector<ox::UPtr<studio::UndoCommand>, 1> m_deferredCmds;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path);
|
TileSheetEditorImGui(studio::StudioContext &sctx, ox::StringParam path);
|
||||||
|
@ -11,18 +11,19 @@
|
|||||||
|
|
||||||
#include <nostalgia/gfx/ptidxconv.hpp>
|
#include <nostalgia/gfx/ptidxconv.hpp>
|
||||||
|
|
||||||
#include "commands/commands.hpp"
|
|
||||||
#include "commands/addsubsheetcommand.hpp"
|
#include "commands/addsubsheetcommand.hpp"
|
||||||
|
#include "commands/commands.hpp"
|
||||||
#include "commands/cutpastecommand.hpp"
|
#include "commands/cutpastecommand.hpp"
|
||||||
#include "commands/deletetilescommand.hpp"
|
#include "commands/deletetilescommand.hpp"
|
||||||
#include "commands/drawcommand.hpp"
|
#include "commands/drawcommand.hpp"
|
||||||
|
#include "commands/flipcommand.hpp"
|
||||||
#include "commands/inserttilescommand.hpp"
|
#include "commands/inserttilescommand.hpp"
|
||||||
#include "commands/palettechangecommand.hpp"
|
#include "commands/palettechangecommand.hpp"
|
||||||
#include "commands/rmsubsheetcommand.hpp"
|
#include "commands/rmsubsheetcommand.hpp"
|
||||||
#include "commands/updatesubsheetcommand.hpp"
|
#include "commands/updatesubsheetcommand.hpp"
|
||||||
#include "tilesheeteditormodel.hpp"
|
#include "tilesheeteditormodel.hpp"
|
||||||
|
|
||||||
#include "commands/flipcommand.hpp"
|
#include "commands/movesubsheetcommand.hpp"
|
||||||
|
|
||||||
namespace nostalgia::gfx {
|
namespace nostalgia::gfx {
|
||||||
|
|
||||||
@ -303,6 +304,10 @@ ox::Error TileSheetEditorModel::flipY() noexcept {
|
|||||||
return pushCommand(ox::make<FlipYCommand>(m_img, m_activeSubsSheetIdx, a, b));
|
return pushCommand(ox::make<FlipYCommand>(m_img, m_activeSubsSheetIdx, a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error TileSheetEditorModel::moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept {
|
||||||
|
return pushCommand(ox::make<MoveSubSheetCommand>(m_img, std::move(src), std::move(dst)));
|
||||||
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::getFillPixels(
|
void TileSheetEditorModel::getFillPixels(
|
||||||
TileSheet::SubSheet const&activeSubSheet,
|
TileSheet::SubSheet const&activeSubSheet,
|
||||||
ox::Span<bool> pixels,
|
ox::Span<bool> pixels,
|
||||||
|
@ -130,6 +130,8 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
|
|
||||||
ox::Error flipY() noexcept;
|
ox::Error flipY() noexcept;
|
||||||
|
|
||||||
|
ox::Error moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getFillPixels(
|
void getFillPixels(
|
||||||
TileSheet::SubSheet const&activeSubSheet,
|
TileSheet::SubSheet const&activeSubSheet,
|
||||||
|
@ -177,7 +177,7 @@ TileSheet::SubSheetIdx validateSubSheetIdx(
|
|||||||
pIdx.resize(pIdxIt);
|
pIdx.resize(pIdxIt);
|
||||||
return std::move(pIdx);
|
return std::move(pIdx);
|
||||||
} else {
|
} else {
|
||||||
currentIdx = pSubsheet.subsheets.size() - 1;
|
currentIdx = static_cast<uint32_t>(pSubsheet.subsheets.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return validateSubSheetIdx(std::move(pIdx), pIdxIt + 1, pSubsheet.subsheets[currentIdx]);
|
return validateSubSheetIdx(std::move(pIdx), pIdxIt + 1, pSubsheet.subsheets[currentIdx]);
|
||||||
@ -188,7 +188,7 @@ TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubShe
|
|||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheet const&getSubSheet(
|
TileSheet::SubSheet const&getSubSheet(
|
||||||
TileSheet::SubSheetIdx const&idx,
|
ox::SpanView<uint32_t> const &idx,
|
||||||
std::size_t const idxIt,
|
std::size_t const idxIt,
|
||||||
TileSheet::SubSheet const &pSubsheet) noexcept {
|
TileSheet::SubSheet const &pSubsheet) noexcept {
|
||||||
if (idxIt == idx.size()) {
|
if (idxIt == idx.size()) {
|
||||||
@ -202,7 +202,7 @@ TileSheet::SubSheet const&getSubSheet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheet &getSubSheet(
|
TileSheet::SubSheet &getSubSheet(
|
||||||
TileSheet::SubSheetIdx const&idx,
|
ox::SpanView<uint32_t> const &idx,
|
||||||
std::size_t const idxIt,
|
std::size_t const idxIt,
|
||||||
TileSheet::SubSheet &pSubsheet) noexcept {
|
TileSheet::SubSheet &pSubsheet) noexcept {
|
||||||
if (idxIt == idx.size()) {
|
if (idxIt == idx.size()) {
|
||||||
@ -211,11 +211,11 @@ TileSheet::SubSheet &getSubSheet(
|
|||||||
return getSubSheet(idx, idxIt + 1, pSubsheet.subsheets[idx[idxIt]]);
|
return getSubSheet(idx, idxIt + 1, pSubsheet.subsheets[idx[idxIt]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, TileSheet::SubSheetIdx const&idx) noexcept {
|
TileSheet::SubSheet const&getSubSheet(TileSheet const &ts, ox::SpanView<uint32_t> const &idx) noexcept {
|
||||||
return gfx::getSubSheet(idx, 0, ts.subsheet);
|
return gfx::getSubSheet(idx, 0, ts.subsheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheet &getSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept {
|
TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const&idx) noexcept {
|
||||||
return gfx::getSubSheet(idx, 0, ts.subsheet);
|
return gfx::getSubSheet(idx, 0, ts.subsheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +227,20 @@ ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept
|
|||||||
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 0", parent.columns, parent.rows);
|
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 0", parent.columns, parent.rows);
|
||||||
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 1", 1, 1);
|
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 1", 1, 1);
|
||||||
}
|
}
|
||||||
return ox::Error(0);
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const&idx, TileSheet::SubSheet ss) noexcept {
|
||||||
|
if (idx.empty()) {
|
||||||
|
return ox::Error{1, "invalid insert idx"};
|
||||||
|
}
|
||||||
|
auto &parent = getSubSheet(ts, {idx.data(), idx.size() - 1});
|
||||||
|
auto const insertIdx = idx[idx.size() - 1];
|
||||||
|
if (insertIdx > parent.subsheets.size()) {
|
||||||
|
return ox::Error{1, "invalid insert idx"};
|
||||||
|
}
|
||||||
|
parent.subsheets.emplace(insertIdx, std::move(ss));
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error rmSubSheet(
|
ox::Error rmSubSheet(
|
||||||
|
@ -295,7 +295,9 @@ class AssetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error reloadAsset(ox::StringViewCR assetId) noexcept {
|
ox::Error reloadAsset(ox::StringViewCR assetId) noexcept {
|
||||||
|
if (m_fileUpdated.contains(assetId)) {
|
||||||
m_fileUpdated[assetId]->emit(assetId);
|
m_fileUpdated[assetId]->emit(assetId);
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ProjectExplorer::dirContextMenu(ox::StringViewCR path) const noexcept {
|
void ProjectExplorer::dirContextMenu(ox::StringViewCR path) const noexcept {
|
||||||
if (ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
if (path.len() && ImGui::BeginPopupContextItem("DirMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
||||||
if (ImGui::MenuItem("Add Item")) {
|
if (ImGui::MenuItem("Add Item")) {
|
||||||
addItem.emit(path);
|
addItem.emit(path);
|
||||||
}
|
}
|
||||||
|
@ -41,18 +41,35 @@ void RenameFile::draw(StudioContext &ctx) noexcept {
|
|||||||
case Stage::Opening:
|
case Stage::Opening:
|
||||||
ImGui::OpenPopup(title().c_str());
|
ImGui::OpenPopup(title().c_str());
|
||||||
m_open = true;
|
m_open = true;
|
||||||
|
m_fileExists = false;
|
||||||
m_stage = Stage::Open;
|
m_stage = Stage::Open;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case Stage::Open:
|
case Stage::Open:
|
||||||
setSize({250, 0});
|
setSize({250, 0});
|
||||||
drawWindow(ctx.tctx, m_open, [this] {
|
drawWindow(ctx.tctx, m_open, [this, &ctx] {
|
||||||
if (ImGui::IsWindowAppearing()) {
|
if (ImGui::IsWindowAppearing()) {
|
||||||
ImGui::SetKeyboardFocusHere();
|
ImGui::SetKeyboardFocusHere();
|
||||||
}
|
}
|
||||||
ig::InputText("Name", m_name);
|
m_fileExists = !ig::InputText("Name", m_name) && m_fileExists;
|
||||||
|
auto const nameInputFocused = ImGui::IsItemFocused();
|
||||||
|
if (m_fileExists) {
|
||||||
|
ImGui::Text("File %s already exists.", m_name.c_str());
|
||||||
|
} else {
|
||||||
ImGui::Text("%s%s", m_path.c_str(), m_name.c_str());
|
ImGui::Text("%s%s", m_path.c_str(), m_name.c_str());
|
||||||
if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK) {
|
}
|
||||||
moveFile.emit(m_oldPath, m_path + m_name);
|
bool b{};
|
||||||
|
auto const response = ig::PopupControlsOkCancel(b);
|
||||||
|
if (response == ig::PopupResponse::OK ||
|
||||||
|
(nameInputFocused && ImGui::IsKeyPressed(ImGuiKey_Enter))) {
|
||||||
|
auto const newPath = m_path + m_name;
|
||||||
|
if (!ctx.project->exists(newPath)) {
|
||||||
|
moveFile.emit(m_oldPath, newPath);
|
||||||
|
close();
|
||||||
|
} else {
|
||||||
|
m_open = true;
|
||||||
|
m_fileExists = true;
|
||||||
|
}
|
||||||
|
} else if (response == ig::PopupResponse::Cancel) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -21,6 +21,7 @@ class RenameFile: public Popup {
|
|||||||
ox::String m_oldPath;
|
ox::String m_oldPath;
|
||||||
ox::String m_path;
|
ox::String m_path;
|
||||||
ox::IString<255> m_name;
|
ox::IString<255> m_name;
|
||||||
|
bool m_fileExists{};
|
||||||
bool m_open{};
|
bool m_open{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -349,10 +349,6 @@ void StudioUI::handleKeyInput() noexcept {
|
|||||||
m_activeEditorUpdatePending = m_activeEditor;
|
m_activeEditorUpdatePending = m_activeEditor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_0)) {
|
|
||||||
m_activeEditor = m_editors[10 < m_editors.size() ? 10 : range].get();
|
|
||||||
m_activeEditorUpdatePending = m_activeEditor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,6 +392,18 @@ ox::Error StudioUI::handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR ne
|
|||||||
return m_projectExplorer.refreshProjectTreeModel();
|
return m_projectExplorer.refreshProjectTreeModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error StudioUI::handleDeleteFile(ox::StringViewCR path) noexcept {
|
||||||
|
for (size_t i{}; auto &e : m_editors) {
|
||||||
|
if (path == e->itemPath()) {
|
||||||
|
oxLogError(m_editors.erase(i).error);
|
||||||
|
oxLogError(closeFile(path));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return m_projectExplorer.refreshProjectTreeModel();
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
|
ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::filesystem::create_directories(toStdStringView(path), ec);
|
std::filesystem::create_directories(toStdStringView(path), ec);
|
||||||
@ -416,7 +424,7 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
|
|||||||
m_newDirDialog.newDir.connect(m_sctx.project, &Project::mkdir);
|
m_newDirDialog.newDir.connect(m_sctx.project, &Project::mkdir);
|
||||||
m_project->dirAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
m_project->dirAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
||||||
m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
||||||
m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
m_project->fileDeleted.connect(this, &StudioUI::handleDeleteFile);
|
||||||
m_project->fileMoved.connect(this, &StudioUI::handleMoveFile);
|
m_project->fileMoved.connect(this, &StudioUI::handleMoveFile);
|
||||||
m_openFiles.clear();
|
m_openFiles.clear();
|
||||||
m_editors.clear();
|
m_editors.clear();
|
||||||
@ -499,12 +507,16 @@ ox::Error StudioUI::queueFileMove(ox::StringParam src, ox::StringParam dst) noex
|
|||||||
|
|
||||||
void StudioUI::procFileMoves() noexcept {
|
void StudioUI::procFileMoves() noexcept {
|
||||||
for (auto const &m : m_queuedMoves) {
|
for (auto const &m : m_queuedMoves) {
|
||||||
|
if (!m_project->exists(m.b)) {
|
||||||
oxLogError(m_project->moveItem(m.a, m.b));
|
oxLogError(m_project->moveItem(m.a, m.b));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
m_queuedMoves.clear();
|
m_queuedMoves.clear();
|
||||||
for (auto const &m : m_queuedDirMoves) {
|
for (auto const &m : m_queuedDirMoves) {
|
||||||
|
if (!m_project->exists(m.b)) {
|
||||||
oxLogError(m_project->moveDir(m.a, m.b));
|
oxLogError(m_project->moveDir(m.a, m.b));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
m_queuedDirMoves.clear();
|
m_queuedDirMoves.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,8 @@ class StudioUI: public ox::SignalHandler {
|
|||||||
|
|
||||||
ox::Error handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id) noexcept;
|
ox::Error handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id) noexcept;
|
||||||
|
|
||||||
|
ox::Error handleDeleteFile(ox::StringViewCR path) noexcept;
|
||||||
|
|
||||||
ox::Error createOpenProject(ox::StringViewCR path) noexcept;
|
ox::Error createOpenProject(ox::StringViewCR path) noexcept;
|
||||||
|
|
||||||
ox::Error openProjectPath(ox::StringParam path) noexcept;
|
ox::Error openProjectPath(ox::StringParam path) noexcept;
|
||||||
|
@ -88,7 +88,7 @@ FileTreeModel::FileTreeModel(
|
|||||||
void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
|
void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
|
||||||
constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
||||||
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_fileType == ox::FileType::Directory) {
|
||||||
auto const nodeOpen = ImGui::TreeNodeEx(m_name.c_str(), dirFlags | selected);
|
auto const nodeOpen = ImGui::TreeNodeEx(m_name.c_str(), dirFlags | selected);
|
||||||
if (ImGui::IsItemActivated() || ImGui::IsItemClicked(1)) {
|
if (ImGui::IsItemActivated() || ImGui::IsItemClicked(1)) {
|
||||||
m_explorer.setSelectedNode(this);
|
m_explorer.setSelectedNode(this);
|
||||||
@ -104,7 +104,8 @@ void FileTreeModel::draw(turbine::Context &tctx) const noexcept {
|
|||||||
if (ig::DragDropTarget const dragDropTarget; dragDropTarget) {
|
if (ig::DragDropTarget const dragDropTarget; dragDropTarget) {
|
||||||
auto const [ref, err] = ig::getDragDropPayload<FileRef>("FileRef");
|
auto const [ref, err] = ig::getDragDropPayload<FileRef>("FileRef");
|
||||||
if (!err) {
|
if (!err) {
|
||||||
auto const name = substr(ref.path, find(ref.path.rbegin(), ref.path.rend(), '/').offset() + 1);
|
auto const name = substr(
|
||||||
|
ref.path, find(ref.path.rbegin(), ref.path.rend(), '/').offset() + 1);
|
||||||
if (ref.isDir) {
|
if (ref.isDir) {
|
||||||
m_explorer.dirMoved(ref.path, sfmt("{}/{}", m_fullPath, name));
|
m_explorer.dirMoved(ref.path, sfmt("{}/{}", m_fullPath, name));
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,13 +64,11 @@ PopupResponse PopupControlsOkCancel(
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::SetCursorPosX(popupWidth - 118);
|
ImGui::SetCursorPosX(popupWidth - 118);
|
||||||
if (ImGui::Button(ok.c_str(), btnSz)) {
|
if (ImGui::Button(ok.c_str(), btnSz)) {
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
popupOpen = false;
|
popupOpen = false;
|
||||||
out = PopupResponse::OK;
|
out = PopupResponse::OK;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::IsKeyDown(ImGuiKey_Escape) || ImGui::Button(cancel.c_str(), btnSz)) {
|
if (ImGui::IsKeyDown(ImGuiKey_Escape) || ImGui::Button(cancel.c_str(), btnSz)) {
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
popupOpen = false;
|
popupOpen = false;
|
||||||
out = PopupResponse::Cancel;
|
out = PopupResponse::Cancel;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,13 @@ static ox::Result<ox::Vector<ox::String>> listAllRecursive(ox::FileSystem &fs, o
|
|||||||
return std::move(out);
|
return std::move(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static constexpr bool isParentOf(ox::StringViewCR parent, ox::StringViewCR child) noexcept {
|
||||||
|
if (endsWith(child, "/")) {
|
||||||
|
return beginsWith(child, parent);
|
||||||
|
}
|
||||||
|
return beginsWith(sfmt("{}/", child), parent);
|
||||||
|
}
|
||||||
|
|
||||||
Project::Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir):
|
Project::Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir):
|
||||||
m_kctx(ctx),
|
m_kctx(ctx),
|
||||||
@ -99,6 +106,9 @@ ox::Error Project::moveItem(ox::StringViewCR src, ox::StringViewCR dest) noexcep
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error Project::moveDir(ox::StringViewCR src, ox::StringViewCR dest) noexcept {
|
ox::Error Project::moveDir(ox::StringViewCR src, ox::StringViewCR dest) noexcept {
|
||||||
|
if (isParentOf(src, dest)) {
|
||||||
|
return ox::Error{1, "cannot move parent to a child directory"};
|
||||||
|
}
|
||||||
OX_REQUIRE(files, listAllRecursive(m_fs, src));
|
OX_REQUIRE(files, listAllRecursive(m_fs, src));
|
||||||
OX_RETURN_ERROR(m_fs.move(src, dest));
|
OX_RETURN_ERROR(m_fs.move(src, dest));
|
||||||
fileMoved.emit(src, dest, ox::UUID{});
|
fileMoved.emit(src, dest, ox::UUID{});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user