Squashed 'deps/nostalgia/' changes from e78c4050..857587c1
857587c1 [studio] Cleanup eb3d53c9 [studio] Cleanup 14d58f3f [studio] Fix Navigation shortcuts for non-Mac systems 5f239790 [studio,nostalgia/gfx/studio/tilesheet] Fix copy/cut/paste enablement when there is no selection 58e0ecb4 [studio] Make FilePickerPopup accept on double click of a file 8838bf42 [studio] Fix to properly copy file that has the same name as deleted file bddc544d [nostalgia] Update release notes a9437191 [studio,turbine] Add support for mouse back/forward buttons 9d8da7cc [ox/std] Make strToInt return error for empty string 394b568e [studio] Add Back/Forward navigation 78e9f70d [nostalgia] Update release notes 12e5623f [ox/logconn] Add exception handling for logger thread cfdfb0a8 [studio] Fix file deletion to close file even if not active 56e66530 [studio] Cleanup 7415ce4b [nostalgia/gfx/studio] Cleanup 05f42150 [olympic] Add new loc command to Makefile 8ea2bc69 [nostalgia] Update release notes c7809241 [studio] Add [DEBUG] tag to About in debug builds 8c538560 [nostalgia/gfx/studio/palette] Make RGB key shortcuts work when color channel inputs are focused c3e75bdb [nostalgia/gfx/studio/tilesheet] Cleanup git-subtree-dir: deps/nostalgia git-subtree-split: 857587c18b4695eacd31457e3c30b4971b4e46e8
This commit is contained in:
@@ -15,11 +15,24 @@ namespace studio {
|
||||
class StudioUI;
|
||||
|
||||
struct Context {
|
||||
StudioUI &ui;
|
||||
Project *project = nullptr;
|
||||
turbine::Context &tctx;
|
||||
Context(StudioUI &pUi, turbine::Context &pTctx) noexcept:
|
||||
ui(pUi), tctx(pTctx) {}
|
||||
public:
|
||||
friend void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept;
|
||||
friend void navigateBack(Context &ctx) noexcept;
|
||||
friend void navigateForward(Context &ctx) noexcept;
|
||||
friend StudioUI;
|
||||
StudioUI &ui;
|
||||
Project *project = nullptr;
|
||||
turbine::Context &tctx;
|
||||
protected:
|
||||
struct NavPath {
|
||||
ox::String filePath;
|
||||
ox::String navArgs;
|
||||
};
|
||||
size_t navIdx{};
|
||||
ox::Vector<NavPath> navStack;
|
||||
std::function<void(ox::StringParam filePath, ox::StringParam navArgs)> navCallback;
|
||||
Context(StudioUI &pUi, turbine::Context &pTctx) noexcept:
|
||||
ui{pUi}, tctx{pTctx} {}
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -27,6 +40,15 @@ inline keel::Context &keelCtx(Context &ctx) noexcept {
|
||||
return keelCtx(ctx.tctx);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline keel::Context const &keelCtx(Context const &ctx) noexcept {
|
||||
return keelCtx(ctx.tctx);
|
||||
}
|
||||
|
||||
void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs = "") noexcept;
|
||||
|
||||
void navigateBack(Context &ctx) noexcept;
|
||||
|
||||
void navigateForward(Context &ctx) noexcept;
|
||||
|
||||
}
|
||||
|
@@ -13,7 +13,11 @@ class FilePickerPopup {
|
||||
|
||||
private:
|
||||
ox::String m_name;
|
||||
FileExplorer m_explorer;
|
||||
struct Explorer: public FileExplorer {
|
||||
mutable bool opened{};
|
||||
explicit Explorer(keel::Context &kctx);
|
||||
void fileOpened(ox::StringViewCR path) const noexcept override;
|
||||
} m_explorer;
|
||||
ox::Vector<ox::String> const m_fileExts;
|
||||
bool m_open{};
|
||||
|
||||
@@ -33,6 +37,10 @@ class FilePickerPopup {
|
||||
|
||||
ox::Optional<ox::String> draw(Context &ctx) noexcept;
|
||||
|
||||
private:
|
||||
[[nodiscard]]
|
||||
ox::Optional<ox::String> handlePick() noexcept;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -46,14 +46,14 @@ ox::Result<T> getDragDropPayload() noexcept {
|
||||
static_cast<size_t>(payload->DataSize)});
|
||||
}
|
||||
|
||||
ox::Error setDragDropPayload(ox::CStringViewCR name, auto const&obj) noexcept {
|
||||
ox::Error setDragDropPayload(ox::CStringViewCR name, auto const &obj) noexcept {
|
||||
OX_REQUIRE(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
||||
ImGui::SetDragDropPayload(name.c_str(), buff.data(), buff.size());
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error setDragDropPayload(T const&obj) noexcept {
|
||||
ox::Error setDragDropPayload(T const &obj) noexcept {
|
||||
OX_REQUIRE(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
||||
ImGui::SetDragDropPayload(ox::ModelTypeName_v<T>, buff.data(), buff.size());
|
||||
return {};
|
||||
@@ -77,7 +77,7 @@ class DragDropSource {
|
||||
}
|
||||
};
|
||||
|
||||
auto dragDropSource(auto const&cb, ImGuiDragDropFlags const flags = 0) noexcept {
|
||||
auto dragDropSource(auto const &cb, ImGuiDragDropFlags const flags = 0) noexcept {
|
||||
if constexpr(ox::is_same_v<decltype(cb()), ox::Error>) {
|
||||
if (ig::DragDropSource const tgt{flags}; tgt) [[unlikely]] {
|
||||
return cb();
|
||||
@@ -108,7 +108,7 @@ class DragDropTarget {
|
||||
}
|
||||
};
|
||||
|
||||
auto dragDropTarget(auto const&cb) noexcept {
|
||||
auto dragDropTarget(auto const &cb) noexcept {
|
||||
if constexpr(ox::is_same_v<decltype(cb()), ox::Error>) {
|
||||
if (ig::DragDropTarget const tgt; tgt) [[unlikely]] {
|
||||
return cb();
|
||||
@@ -124,7 +124,7 @@ auto dragDropTarget(auto const&cb) noexcept {
|
||||
|
||||
class ChildStackItem {
|
||||
public:
|
||||
explicit ChildStackItem(ox::CStringViewCR id, ImVec2 const&sz = {}) noexcept;
|
||||
explicit ChildStackItem(ox::CStringViewCR id, ImVec2 const &sz = {}) noexcept;
|
||||
~ChildStackItem() noexcept;
|
||||
};
|
||||
|
||||
@@ -146,7 +146,7 @@ class IndentStackItem {
|
||||
|
||||
void centerNextWindow(turbine::Context &ctx) noexcept;
|
||||
|
||||
bool PushButton(ox::CStringViewCR lbl, ImVec2 const&btnSz = BtnSz) noexcept;
|
||||
bool PushButton(ox::CStringViewCR lbl, ImVec2 const &btnSz = BtnSz) noexcept;
|
||||
|
||||
template<typename Str>
|
||||
struct TextInput {
|
||||
@@ -234,7 +234,7 @@ PopupResponse PopupControlsOk(
|
||||
ox::CStringViewCR ok);
|
||||
|
||||
[[nodiscard]]
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringViewCR popupName, bool &show, ImVec2 const&sz = {285, 0});
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringViewCR popupName, bool &show, ImVec2 const &sz = {285, 0});
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -266,7 +266,7 @@ bool ComboBox(ox::CStringView lbl, ox::Span<const ox::String> list, size_t &sele
|
||||
*/
|
||||
bool ComboBox(
|
||||
ox::CStringViewCR lbl,
|
||||
std::function<ox::CStringView(size_t)> const&f,
|
||||
std::function<ox::CStringView(size_t)> const &f,
|
||||
size_t strCnt,
|
||||
size_t &selectedIdx) noexcept;
|
||||
|
||||
@@ -278,10 +278,10 @@ bool FileComboBox(
|
||||
|
||||
bool ListBox(
|
||||
ox::CStringViewCR name,
|
||||
std::function<ox::CStringView(size_t)> const&f,
|
||||
std::function<ox::CStringView(size_t)> const &f,
|
||||
size_t strCnt,
|
||||
size_t &selIdx,
|
||||
ImVec2 const&sz = {0, 0}) noexcept;
|
||||
ImVec2 const &sz = {0, 0}) noexcept;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -290,7 +290,7 @@ bool ListBox(
|
||||
* @param selIdx
|
||||
* @return true if new value selected, false otherwise
|
||||
*/
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const&list, size_t &selIdx) noexcept;
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const &list, size_t &selIdx) noexcept;
|
||||
|
||||
class FilePicker {
|
||||
private:
|
||||
@@ -306,7 +306,7 @@ class FilePicker {
|
||||
studio::Context &sctx,
|
||||
ox::StringParam title,
|
||||
ox::StringParam fileExt,
|
||||
ImVec2 const&size = {}) noexcept;
|
||||
ImVec2 const &size = {}) noexcept;
|
||||
|
||||
void draw() noexcept;
|
||||
|
||||
@@ -348,6 +348,8 @@ class QuestionPopup: public Popup {
|
||||
|
||||
QuestionPopup(ox::StringParam title, ox::StringParam question) noexcept;
|
||||
|
||||
void setQuestion(ox::StringParam msg) noexcept;
|
||||
|
||||
void draw(Context &ctx) noexcept override;
|
||||
|
||||
};
|
||||
|
@@ -109,7 +109,7 @@ class ItemMaker {
|
||||
return m_typeDisplayName;
|
||||
}
|
||||
|
||||
bool installTemplate(ox::UPtr<ItemTemplate> &tmpl) {
|
||||
bool installTemplate(ox::UPtr<ItemTemplate> &&tmpl) {
|
||||
if (typeName() == tmpl->typeName() &&
|
||||
typeVersion() <= tmpl->typeVersion()) {
|
||||
m_templates.emplace_back(std::move(tmpl));
|
||||
@@ -120,10 +120,6 @@ class ItemMaker {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool installTemplate(ox::UPtr<ItemTemplate> &&tmpl) {
|
||||
return installTemplate(tmpl);
|
||||
}
|
||||
|
||||
constexpr ox::Vector<ox::UPtr<ItemTemplate>> const&itemTemplates() const noexcept {
|
||||
return m_templates;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
add_library(
|
||||
Studio
|
||||
configio.cpp
|
||||
context.cpp
|
||||
editor.cpp
|
||||
filepickerpopup.cpp
|
||||
filetreemodel.cpp
|
||||
|
69
src/olympic/studio/modlib/src/context.cpp
Normal file
69
src/olympic/studio/modlib/src/context.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <studio/context.hpp>
|
||||
|
||||
namespace studio {
|
||||
|
||||
void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept {
|
||||
ox::String path = std::move(filePath);
|
||||
if (beginsWith(path, "uuid://")) {
|
||||
auto const [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path);
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
path = p;
|
||||
}
|
||||
ctx.navStack.resize(ctx.navIdx + 1);
|
||||
ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()});
|
||||
try {
|
||||
ctx.navCallback(std::move(path), std::move(navArgs));
|
||||
} catch (std::exception const &e) {
|
||||
oxErrf("Nav error: {}", e.what());
|
||||
oxAssert(false, "Nav error");
|
||||
}
|
||||
}
|
||||
|
||||
void navigateBack(Context &ctx) noexcept {
|
||||
if (!ctx.navIdx) {
|
||||
return;
|
||||
}
|
||||
--ctx.navIdx;
|
||||
while (ctx.navIdx < ctx.navStack.size() && ctx.navIdx) {
|
||||
auto const i = ctx.navIdx - 1;
|
||||
auto const &n = ctx.navStack[i];
|
||||
if (!ctx.project->exists(n.filePath)) {
|
||||
std::ignore = ctx.navStack.erase(i);
|
||||
--ctx.navIdx;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
ctx.navCallback(n.filePath, n.navArgs);
|
||||
} catch (std::exception const &e) {
|
||||
oxAssert(ctx.navCallback != nullptr, "navCallback is null");
|
||||
oxErrf("navigateForward failed: {}", e.what());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void navigateForward(Context &ctx) noexcept {
|
||||
while (ctx.navIdx < ctx.navStack.size()) {
|
||||
auto const &n = ctx.navStack[ctx.navIdx];
|
||||
try {
|
||||
ctx.navCallback(n.filePath, n.navArgs);
|
||||
} catch (std::exception const &e) {
|
||||
oxAssert(ctx.navCallback != nullptr, "navCallback is null");
|
||||
oxErrf("navigateForward failed: {}", e.what());
|
||||
}
|
||||
if (!ctx.project->exists(n.filePath)) {
|
||||
std::ignore = ctx.navStack.erase(ctx.navIdx);
|
||||
continue;
|
||||
}
|
||||
++ctx.navIdx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -72,8 +72,10 @@ bool BaseEditor::exportable() const noexcept {
|
||||
}
|
||||
|
||||
void BaseEditor::setCutEnabled(bool v) {
|
||||
m_cutEnabled = v;
|
||||
cutEnabledChanged.emit(v);
|
||||
if (m_cutEnabled != v) {
|
||||
m_cutEnabled = v;
|
||||
cutEnabledChanged.emit(v);
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseEditor::cutEnabled() const noexcept {
|
||||
@@ -81,8 +83,10 @@ bool BaseEditor::cutEnabled() const noexcept {
|
||||
}
|
||||
|
||||
void BaseEditor::setCopyEnabled(bool v) {
|
||||
m_copyEnabled = v;
|
||||
copyEnabledChanged.emit(v);
|
||||
if (m_copyEnabled != v) {
|
||||
m_copyEnabled = v;
|
||||
copyEnabledChanged.emit(v);
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseEditor::copyEnabled() const noexcept {
|
||||
@@ -90,8 +94,10 @@ bool BaseEditor::copyEnabled() const noexcept {
|
||||
}
|
||||
|
||||
void BaseEditor::setPasteEnabled(bool v) {
|
||||
m_pasteEnabled = v;
|
||||
pasteEnabledChanged.emit(v);
|
||||
if (m_pasteEnabled != v) {
|
||||
m_pasteEnabled = v;
|
||||
pasteEnabledChanged.emit(v);
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseEditor::pasteEnabled() const noexcept {
|
||||
|
@@ -8,6 +8,15 @@
|
||||
|
||||
namespace studio {
|
||||
|
||||
FilePickerPopup::Explorer::Explorer(keel::Context &kctx):
|
||||
FileExplorer{kctx} {
|
||||
}
|
||||
|
||||
void FilePickerPopup::Explorer::fileOpened(ox::StringViewCR) const noexcept {
|
||||
opened = true;
|
||||
}
|
||||
|
||||
|
||||
FilePickerPopup::FilePickerPopup(
|
||||
ox::StringParam name,
|
||||
keel::Context &kctx,
|
||||
@@ -41,6 +50,7 @@ void FilePickerPopup::refresh() noexcept {
|
||||
void FilePickerPopup::open() noexcept {
|
||||
refresh();
|
||||
m_open = true;
|
||||
m_explorer.opened = false;
|
||||
}
|
||||
|
||||
void FilePickerPopup::close() noexcept {
|
||||
@@ -60,16 +70,22 @@ ox::Optional<ox::String> FilePickerPopup::draw(Context &ctx) noexcept {
|
||||
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();
|
||||
if (ig::PopupControlsOkCancel(m_open) == ig::PopupResponse::OK || m_explorer.opened) {
|
||||
out = handlePick();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
ox::Optional<ox::String> FilePickerPopup::handlePick() noexcept {
|
||||
ox::Optional<ox::String> out;
|
||||
auto p = m_explorer.selectedPath();
|
||||
if (p) {
|
||||
out.emplace(*p);
|
||||
}
|
||||
close();
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace studio::ig {
|
||||
|
||||
ChildStackItem::ChildStackItem(ox::CStringViewCR id, ImVec2 const&sz) noexcept {
|
||||
ChildStackItem::ChildStackItem(ox::CStringViewCR id, ImVec2 const &sz) noexcept {
|
||||
ImGui::BeginChild(id.c_str(), sz);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void centerNextWindow(turbine::Context &ctx) noexcept {
|
||||
ImGui::SetNextWindowPos(ImVec2(screenW / mod, screenH / mod), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
bool PushButton(ox::CStringViewCR lbl, ImVec2 const&btnSz) noexcept {
|
||||
bool PushButton(ox::CStringViewCR lbl, ImVec2 const &btnSz) noexcept {
|
||||
return ImGui::Button(lbl.c_str(), btnSz);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ PopupResponse PopupControlsOk(
|
||||
return out;
|
||||
}
|
||||
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringViewCR popupName, bool &show, ImVec2 const&sz) {
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringViewCR popupName, bool &show, ImVec2 const &sz) {
|
||||
constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
centerNextWindow(ctx);
|
||||
ImGui::OpenPopup(popupName.c_str());
|
||||
@@ -149,7 +149,7 @@ bool ComboBox(
|
||||
|
||||
bool ComboBox(
|
||||
ox::CStringViewCR lbl,
|
||||
std::function<ox::CStringView(size_t)> const&f,
|
||||
std::function<ox::CStringView(size_t)> const &f,
|
||||
size_t strCnt,
|
||||
size_t &selectedIdx) noexcept {
|
||||
bool out{};
|
||||
@@ -172,16 +172,16 @@ bool FileComboBox(
|
||||
Context &sctx,
|
||||
ox::StringViewCR fileExt,
|
||||
size_t &selectedIdx) noexcept {
|
||||
auto const&list = sctx.project->fileList(fileExt);
|
||||
auto const &list = sctx.project->fileList(fileExt);
|
||||
return ComboBox(lbl, list, selectedIdx);
|
||||
}
|
||||
|
||||
bool ListBox(
|
||||
ox::CStringViewCR name,
|
||||
std::function<ox::CStringView(size_t)> const&f,
|
||||
std::function<ox::CStringView(size_t)> const &f,
|
||||
size_t const strCnt,
|
||||
size_t &selIdx,
|
||||
ImVec2 const&sz) noexcept {
|
||||
ImVec2 const &sz) noexcept {
|
||||
auto out = false;
|
||||
if (ImGui::BeginListBox(name.c_str(), sz)) {
|
||||
for (size_t i = 0; i < strCnt; ++i) {
|
||||
@@ -199,13 +199,13 @@ bool ListBox(
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const&list, size_t &selIdx) noexcept {
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const &list, size_t &selIdx) noexcept {
|
||||
return ListBox(name, [list](size_t i) -> ox::CStringView {
|
||||
return list[i];
|
||||
}, list.size(), selIdx);
|
||||
}
|
||||
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::CStringView> const&list, size_t &selIdx) noexcept {
|
||||
bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::CStringView> const &list, size_t &selIdx) noexcept {
|
||||
return ListBox(name, [list](size_t i) -> ox::CStringView {
|
||||
return list[i];
|
||||
}, list.size(), selIdx);
|
||||
@@ -216,7 +216,7 @@ FilePicker::FilePicker(
|
||||
Context &sctx,
|
||||
ox::StringParam title,
|
||||
ox::StringParam fileExt,
|
||||
ImVec2 const&size) noexcept:
|
||||
ImVec2 const &size) noexcept:
|
||||
m_sctx(sctx),
|
||||
m_title(std::move(title)),
|
||||
m_fileExt(std::move(fileExt)),
|
||||
@@ -230,7 +230,7 @@ void FilePicker::draw() noexcept {
|
||||
auto constexpr popupSz = ImVec2{450.f, 0};
|
||||
IDStackItem const idStackItem(m_title);
|
||||
if (BeginPopup(m_sctx.tctx, m_title, m_show, popupSz)) {
|
||||
auto const&list = m_sctx.project->fileList(m_fileExt);
|
||||
auto const &list = m_sctx.project->fileList(m_fileExt);
|
||||
size_t selIdx{};
|
||||
ComboBox(m_title, list, selIdx);
|
||||
if (PopupControlsOkCancel(popupSz.x, m_show) == ig::PopupResponse::OK) {
|
||||
@@ -267,6 +267,10 @@ QuestionPopup::QuestionPopup(ox::StringParam title, ox::StringParam question) no
|
||||
m_question{std::move(question)} {
|
||||
}
|
||||
|
||||
void QuestionPopup::setQuestion(ox::StringParam msg) noexcept {
|
||||
m_question = std::move(msg);
|
||||
}
|
||||
|
||||
void QuestionPopup::draw(Context &ctx) noexcept {
|
||||
switch (m_stage) {
|
||||
case Stage::Closed:
|
||||
|
@@ -101,8 +101,8 @@ ox::Result<ox::FileStat> Project::stat(ox::StringViewCR path) const noexcept {
|
||||
ox::Error Project::copyItem(ox::StringViewCR src, ox::StringViewCR dest) noexcept {
|
||||
OX_REQUIRE_M(buff, loadBuff(src));
|
||||
OX_REQUIRE(id, keel::regenerateUuidHeader(buff));
|
||||
OX_RETURN_ERROR(writeBuff(dest, buff));
|
||||
createUuidMapping(m_kctx, dest, id);
|
||||
OX_RETURN_ERROR(writeBuff(dest, ox::BufferView{buff} + keel::K1HdrSz));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user