[nostalgia] Add NewMenu for creating new files
This commit is contained in:
parent
b14e41d057
commit
275e9dbff1
@ -92,8 +92,11 @@ class AssetRef: public ox::SignalHandler {
|
||||
}
|
||||
|
||||
constexpr const T *get() const noexcept {
|
||||
if (m_ctr) {
|
||||
return m_ctr->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr const T &operator*() const & noexcept {
|
||||
return *m_ctr->get();
|
||||
|
@ -61,10 +61,10 @@ struct TileSheet {
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
ox::String name;
|
||||
int columns = 1;
|
||||
int rows = 1;
|
||||
int columns = 0;
|
||||
int rows = 0;
|
||||
ox::Vector<SubSheet> subsheets;
|
||||
ox::Vector<uint8_t> pixels = {};
|
||||
ox::Vector<uint8_t> pixels;
|
||||
|
||||
constexpr SubSheet() noexcept = default;
|
||||
constexpr SubSheet(const SubSheet &other) noexcept {
|
||||
@ -84,8 +84,8 @@ struct TileSheet {
|
||||
other.columns = 0;
|
||||
other.rows = 0;
|
||||
}
|
||||
constexpr SubSheet(const char *pName, int pColumns, int pRows) noexcept:
|
||||
name(pName), columns(pColumns), rows(pRows), pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile)) {
|
||||
constexpr SubSheet(const char *pName, int pColumns, int pRows, int bpp) noexcept:
|
||||
name(pName), columns(pColumns), rows(pRows), pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
|
||||
}
|
||||
constexpr SubSheet(const char *pName, int pColumns, int pRows, ox::Vector<uint8_t> pPixels) noexcept:
|
||||
name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) {
|
||||
@ -267,27 +267,27 @@ struct TileSheet {
|
||||
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet";
|
||||
static constexpr auto TypeVersion = 2;
|
||||
int8_t bpp = 0;
|
||||
int8_t bpp = 4;
|
||||
ox::FileAddress defaultPalette;
|
||||
SubSheet subsheet;
|
||||
SubSheet subsheet{"Root", 1, 1, bpp};
|
||||
|
||||
constexpr TileSheet() noexcept = default;
|
||||
inline TileSheet(const TileSheet &other) noexcept {
|
||||
bpp = other.bpp;
|
||||
defaultPalette = other.defaultPalette;
|
||||
subsheet = other.subsheet;
|
||||
inline TileSheet(const TileSheet &other) noexcept:
|
||||
bpp(other.bpp),
|
||||
defaultPalette(other.defaultPalette),
|
||||
subsheet(other.subsheet) {
|
||||
}
|
||||
inline TileSheet(TileSheet &&other) noexcept {
|
||||
bpp = other.bpp;
|
||||
defaultPalette = std::move(other.defaultPalette);
|
||||
subsheet = std::move(other.subsheet);
|
||||
inline TileSheet(TileSheet &&other) noexcept:
|
||||
bpp(std::move(other.bpp)),
|
||||
defaultPalette(std::move(other.defaultPalette)),
|
||||
subsheet(std::move(other.subsheet)) {
|
||||
}
|
||||
|
||||
inline auto &operator=(const TileSheet &other) noexcept {
|
||||
if (this != &other) {
|
||||
bpp = other.bpp;
|
||||
defaultPalette = other.defaultPalette;
|
||||
subsheet = other.subsheet;
|
||||
return *this;
|
||||
subsheet = other.subsheet; } return *this;
|
||||
}
|
||||
inline auto &operator=(TileSheet &&other) noexcept {
|
||||
bpp = other.bpp;
|
||||
@ -359,10 +359,10 @@ struct TileSheet {
|
||||
constexpr ox::Error addSubSheet(const SubSheetIdx &idx) noexcept {
|
||||
auto &parent = getSubSheet(idx);
|
||||
if (parent.subsheets.size() < 2) {
|
||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()).c_str(), 1, 1);
|
||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()).c_str(), 1, 1, bpp);
|
||||
} else {
|
||||
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows);
|
||||
parent.subsheets.emplace_back("Subsheet 1", 1, 1);
|
||||
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, bpp);
|
||||
parent.subsheets.emplace_back("Subsheet 1", 1, 1, bpp);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file, bool
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error writeObj(Context *ctx, const ox::FileAddress &file, T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
|
||||
ox::Error writeObj(Context *ctx, const ox::FileAddress &file, const T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
|
||||
oxRequire(objBuff, ox::writeClaw(&obj, fmt));
|
||||
return ctx->rom-write(file, objBuff);
|
||||
return ctx->rom->write(file, objBuff.data(), objBuff.size());
|
||||
}
|
||||
|
||||
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ox/std/memory.hpp"
|
||||
#include "paletteeditor-imgui.hpp"
|
||||
#include "tilesheeteditor-imgui.hpp"
|
||||
|
||||
@ -30,4 +31,11 @@ ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept {
|
||||
};
|
||||
}
|
||||
|
||||
ox::Vector<ox::UniquePtr<studio::ItemMaker>> Module::itemMakers(core::Context*) noexcept {
|
||||
ox::Vector<ox::UniquePtr<studio::ItemMaker>> out;
|
||||
out.emplace_back(new studio::ItemMakerT<core::TileSheet>("Tile Sheet", "TileSheets", "ng"));
|
||||
out.emplace_back(new studio::ItemMakerT<core::Palette>("Palette", "Palettes", "npal"));
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ namespace nostalgia::core {
|
||||
class Module: public studio::Module {
|
||||
public:
|
||||
ox::Vector<studio::EditorMaker> editors(core::Context *ctx) noexcept override;
|
||||
ox::Vector<ox::UniquePtr<studio::ItemMaker>> itemMakers(core::Context*) noexcept override;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -87,7 +87,9 @@ void TileSheetEditorImGui::keyStateChanged(core::Key key, bool down) {
|
||||
if (!down) {
|
||||
return;
|
||||
}
|
||||
const auto colorCnt = model()->pal().colors.size();
|
||||
auto pal = model()->pal();
|
||||
if (pal) {
|
||||
const auto colorCnt = pal->colors.size();
|
||||
if (key >= core::Key::Num_1 && key <= core::Key::Num_0 + colorCnt) {
|
||||
auto idx = ox::min<std::size_t>(static_cast<uint32_t>(key - core::Key::Num_1), colorCnt - 1);
|
||||
m_tileSheetEditor.setPalIdx(idx);
|
||||
@ -95,6 +97,7 @@ void TileSheetEditorImGui::keyStateChanged(core::Key key, bool down) {
|
||||
auto idx = ox::min<std::size_t>(static_cast<uint32_t>(key - core::Key::Num_1 + 9), colorCnt - 1);
|
||||
m_tileSheetEditor.setPalIdx(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileSheetEditorImGui::draw(core::Context*) noexcept {
|
||||
@ -255,7 +258,7 @@ void TileSheetEditorImGui::exportSubhseetToPng() noexcept {
|
||||
const auto &img = model()->img();
|
||||
const auto &s = *model()->activeSubSheet();
|
||||
const auto &pal = model()->pal();
|
||||
err = toPngFile(path, s, pal, img.bpp);
|
||||
err = toPngFile(path, s, *pal, img.bpp);
|
||||
if (err) {
|
||||
oxErrorf("Tilesheet export failed: {}", toStr(err));
|
||||
}
|
||||
@ -353,7 +356,8 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
|
||||
ImGui::TableSetupColumn("", 0, 0.22);
|
||||
ImGui::TableSetupColumn("Color16", 0, 3);
|
||||
ImGui::TableHeadersRow();
|
||||
for (auto i = 0u; auto c: m_tileSheetEditor.pal().colors) {
|
||||
if (auto pal = m_tileSheetEditor.pal()) {
|
||||
for (auto i = 0u; auto c: pal->colors) {
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
// Column: color idx
|
||||
ImGui::TableNextColumn();
|
||||
@ -372,6 +376,7 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
|
||||
ImGui::PopID();
|
||||
++i;
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,10 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
const Palette TileSheetEditorModel::s_defaultPalette = {
|
||||
.colors = ox::Vector<Color16>(128),
|
||||
};
|
||||
|
||||
class TileSheetClipboard: public ClipboardObject<TileSheetClipboard> {
|
||||
public:
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
|
||||
@ -252,12 +256,12 @@ class AddSubSheetCommand: public TileSheetCommand {
|
||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||
if (m_addedSheets.size() < 2) {
|
||||
auto i = parent.subsheets.size();
|
||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i).c_str(), 1, 1);
|
||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i).c_str(), 1, 1, m_img->bpp);
|
||||
} else {
|
||||
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
|
||||
parent.rows = 0;
|
||||
parent.columns = 0;
|
||||
parent.subsheets.emplace_back("Subsheet 1", 1, 1);
|
||||
parent.subsheets.emplace_back("Subsheet 1", 1, 1, m_img->bpp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,12 +535,14 @@ class PaletteChangeCommand: public TileSheetCommand {
|
||||
};
|
||||
|
||||
|
||||
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) {
|
||||
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, ox::String path) {
|
||||
m_ctx = ctx;
|
||||
m_path = path;
|
||||
oxRequireT(img, readObj<TileSheet>(ctx, path.c_str()));
|
||||
m_path = std::move(path);
|
||||
oxRequireT(img, readObj<TileSheet>(ctx, m_path.c_str()));
|
||||
m_img = *img;
|
||||
if (m_img.defaultPalette) {
|
||||
oxThrowError(readObj<Palette>(ctx, m_img.defaultPalette).moveTo(&m_pal));
|
||||
}
|
||||
m_pal.updated.connect(this, &TileSheetEditorModel::markUpdated);
|
||||
m_undoStack.changeTriggered.connect(this, &TileSheetEditorModel::markUpdatedCmdId);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
||||
ox::Signal<ox::Error(const TileSheet::SubSheetIdx&)> activeSubsheetChanged;
|
||||
|
||||
private:
|
||||
static const Palette s_defaultPalette;
|
||||
TileSheet m_img;
|
||||
TileSheet::SubSheetIdx m_activeSubsSheetIdx;
|
||||
AssetRef<Palette> m_pal;
|
||||
@ -33,7 +34,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
||||
geo::Bounds m_selectionBounds = {{-1, -1}, {-1, -1}};
|
||||
|
||||
public:
|
||||
TileSheetEditorModel(Context *ctx, const ox::String &path);
|
||||
TileSheetEditorModel(Context *ctx, ox::String path);
|
||||
|
||||
~TileSheetEditorModel() override = default;
|
||||
|
||||
@ -50,7 +51,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
||||
constexpr TileSheet &img() noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr const Palette &pal() const noexcept;
|
||||
constexpr const Palette *pal() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
const ox::FileAddress &palPath() const noexcept;
|
||||
@ -142,8 +143,11 @@ constexpr TileSheet &TileSheetEditorModel::img() noexcept {
|
||||
return m_img;
|
||||
}
|
||||
|
||||
constexpr const Palette &TileSheetEditorModel::pal() const noexcept {
|
||||
return *m_pal;
|
||||
constexpr const Palette *TileSheetEditorModel::pal() const noexcept {
|
||||
if (m_pal) {
|
||||
return m_pal.get();
|
||||
}
|
||||
return &s_defaultPalette;
|
||||
}
|
||||
|
||||
constexpr studio::UndoStack *TileSheetEditorModel::undoStack() noexcept {
|
||||
|
@ -80,7 +80,7 @@ class TileSheetEditorView: public ox::SignalHandler {
|
||||
constexpr TileSheet &img() noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr const Palette &pal() const noexcept;
|
||||
constexpr const Palette *pal() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr auto *model() noexcept {
|
||||
@ -125,7 +125,7 @@ constexpr TileSheet &TileSheetEditorView::img() noexcept {
|
||||
return m_model.img();
|
||||
}
|
||||
|
||||
constexpr const Palette &TileSheetEditorView::pal() const noexcept {
|
||||
constexpr const Palette *TileSheetEditorView::pal() const noexcept {
|
||||
return m_model.pal();
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned v
|
||||
void TileSheetPixels::setBufferObjects(const geo::Vec2 &paneSize) noexcept {
|
||||
// set buffer lengths
|
||||
const auto subSheet = m_model->activeSubSheet();
|
||||
const auto &pal = m_model->pal();
|
||||
const auto pal = m_model->pal();
|
||||
const auto width = subSheet->columns * TileWidth;
|
||||
const auto height = subSheet->rows * TileHeight;
|
||||
const auto pixels = static_cast<unsigned>(width * height);
|
||||
@ -93,12 +93,18 @@ void TileSheetPixels::setBufferObjects(const geo::Vec2 &paneSize) noexcept {
|
||||
m_bufferSet.elements.resize(pixels * VertexEboLength);
|
||||
// set pixels
|
||||
subSheet->walkPixels(m_model->img().bpp, [&](std::size_t i, uint8_t p) {
|
||||
auto color = pal.colors[p];
|
||||
auto color = pal->colors[p];
|
||||
const auto pt = idxToPt(static_cast<int>(i), subSheet->columns);
|
||||
const auto fx = static_cast<float>(pt.x);
|
||||
const auto fy = static_cast<float>(pt.y);
|
||||
const auto vbo = &m_bufferSet.vertices[i * VertexVboLength];
|
||||
const auto ebo = &m_bufferSet.elements[i * VertexEboLength];
|
||||
if (i * VertexVboLength + VertexVboLength > m_bufferSet.vertices.size()) {
|
||||
return;
|
||||
}
|
||||
if (i * VertexEboLength + VertexEboLength > m_bufferSet.elements.size()) {
|
||||
return;
|
||||
}
|
||||
if (m_model->pixelSelected(i)) {
|
||||
const auto r = red16(color) / 2;
|
||||
const auto g = (green16(color) + 20) / 2;
|
||||
|
@ -5,10 +5,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <ox/claw/claw.hpp>
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/model/typestore.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
class TypeStore: public ox::TypeStore {
|
||||
|
@ -2,8 +2,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_executable(
|
||||
nostalgia-studio MACOSX_BUNDLE
|
||||
aboutpopup.cpp
|
||||
filedialogmanager.cpp
|
||||
main.cpp
|
||||
newmenu.cpp
|
||||
projectexplorer.cpp
|
||||
projecttreemodel.cpp
|
||||
studioapp.cpp
|
||||
|
57
src/nostalgia/studio/aboutpopup.cpp
Normal file
57
src/nostalgia/studio/aboutpopup.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "lib/imguiuitl.hpp"
|
||||
#include "aboutpopup.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
|
||||
void AboutPopup::open() noexcept {
|
||||
m_stage = Stage::Opening;
|
||||
}
|
||||
|
||||
void AboutPopup::close() noexcept {
|
||||
m_stage = Stage::Closed;
|
||||
}
|
||||
|
||||
bool AboutPopup::isOpen() const noexcept {
|
||||
return m_stage == Stage::Open;
|
||||
}
|
||||
|
||||
void AboutPopup::draw(core::Context *ctx) noexcept {
|
||||
switch (m_stage) {
|
||||
case Stage::Closed:
|
||||
break;
|
||||
case Stage::Opening:
|
||||
ImGui::OpenPopup("About");
|
||||
m_stage = Stage::Open;
|
||||
[[fallthrough]];
|
||||
case Stage::Open: {
|
||||
constexpr auto modalFlags =
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
ImGui::SetNextWindowSize(ImVec2(215, 90));
|
||||
studio::ig::centerNextWindow(ctx);
|
||||
auto open = true;
|
||||
if (ImGui::BeginPopupModal("About", &open, modalFlags)) {
|
||||
ImGui::Text("Nostalgia Studio - dev build");
|
||||
ImGui::NewLine();
|
||||
ImGui::Dummy(ImVec2(148.0f, 0.0f));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Close")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
open = false;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
if (!open) {
|
||||
m_stage = Stage::Closed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
39
src/nostalgia/studio/aboutpopup.hpp
Normal file
39
src/nostalgia/studio/aboutpopup.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/event/signal.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
#include "lib/popup.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
|
||||
class AboutPopup: public studio::Popup {
|
||||
public:
|
||||
enum class Stage {
|
||||
Closed,
|
||||
Opening,
|
||||
Open,
|
||||
};
|
||||
|
||||
private:
|
||||
Stage m_stage = Stage::Closed;
|
||||
|
||||
public:
|
||||
void open() noexcept override;
|
||||
|
||||
void close() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
bool isOpen() const noexcept override;
|
||||
|
||||
void draw(core::Context *ctx) noexcept override;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -2,7 +2,9 @@ add_library(
|
||||
NostalgiaStudio
|
||||
configio.cpp
|
||||
editor.cpp
|
||||
imguiutil.cpp
|
||||
module.cpp
|
||||
popup.cpp
|
||||
project.cpp
|
||||
task.cpp
|
||||
undostack.cpp
|
||||
@ -43,7 +45,9 @@ install(
|
||||
context.hpp
|
||||
editor.hpp
|
||||
filedialog.hpp
|
||||
itemmaker.hpp
|
||||
module.hpp
|
||||
popup.hpp
|
||||
project.hpp
|
||||
task.hpp
|
||||
undostack.hpp
|
||||
|
@ -35,9 +35,13 @@ void BaseEditor::save() noexcept {
|
||||
const auto err = saveItem();
|
||||
if (!err) {
|
||||
setUnsavedChanges(false);
|
||||
} else {
|
||||
if constexpr(ox::defines::Debug) {
|
||||
oxErrorf("Could not save file {}: {} ({}:{})", itemName(), toStr(err), err.file, err.line);
|
||||
} else {
|
||||
oxErrorf("Could not save file {}: {}", itemName(), toStr(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaseEditor::setUnsavedChanges(bool uc) {
|
||||
|
13
src/nostalgia/studio/lib/imguiuitl.hpp
Normal file
13
src/nostalgia/studio/lib/imguiuitl.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nostalgia/core/core.hpp>
|
||||
|
||||
namespace nostalgia::studio::ig {
|
||||
|
||||
void centerNextWindow(core::Context *ctx) noexcept;
|
||||
|
||||
}
|
19
src/nostalgia/studio/lib/imguiutil.cpp
Normal file
19
src/nostalgia/studio/lib/imguiutil.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nostalgia/core/core.hpp>
|
||||
|
||||
namespace nostalgia::studio::ig {
|
||||
|
||||
void centerNextWindow(core::Context *ctx) noexcept {
|
||||
const auto sz = core::getScreenSize(ctx);
|
||||
const auto screenW = static_cast<float>(sz.width);
|
||||
const auto screenH = static_cast<float>(sz.height);
|
||||
const auto mod = ImGui::GetWindowDpiScale() * 2;
|
||||
ImGui::SetNextWindowPos(ImVec2(screenW / mod, screenH / mod), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
}
|
54
src/nostalgia/studio/lib/itemmaker.hpp
Normal file
54
src/nostalgia/studio/lib/itemmaker.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/claw/claw.hpp>
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
class ItemMaker {
|
||||
public:
|
||||
const ox::String name;
|
||||
const ox::String parentDir;
|
||||
const ox::String fileExt;
|
||||
constexpr explicit ItemMaker(ox::String pName, ox::String pParentDir, ox::String pFileExt) noexcept:
|
||||
name(std::move(pName)),
|
||||
parentDir(std::move(pParentDir)),
|
||||
fileExt(std::move(pFileExt)) {
|
||||
}
|
||||
virtual ~ItemMaker() noexcept = default;
|
||||
virtual ox::Error write(core::Context *ctx, const char *pName) const noexcept = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ItemMakerT: public ItemMaker {
|
||||
private:
|
||||
const T item;
|
||||
const ox::ClawFormat fmt;
|
||||
public:
|
||||
constexpr explicit ItemMakerT(ox::String pDisplayName, ox::String pParentDir, ox::String fileExt, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept:
|
||||
ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
|
||||
fmt(pFmt) {
|
||||
}
|
||||
constexpr ItemMakerT(ox::String pDisplayName, ox::String pParentDir, ox::String fileExt, const T &pItem, ox::ClawFormat pFmt) noexcept:
|
||||
ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
|
||||
item(pItem),
|
||||
fmt(pFmt) {
|
||||
}
|
||||
constexpr ItemMakerT(ox::String pDisplayName, ox::String pParentDir, T &&pItem, ox::ClawFormat pFmt) noexcept:
|
||||
ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
|
||||
item(std::forward(pItem)),
|
||||
fmt(pFmt) {
|
||||
}
|
||||
ox::Error write(core::Context *ctx, const char *pName) const noexcept override {
|
||||
const auto path = ox::sfmt("{}/{}.{}", parentDir, pName, fileExt);
|
||||
auto sctx = core::applicationData<studio::StudioContext>(ctx);
|
||||
return sctx->project->writeObj(path, &item, fmt);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -10,4 +10,8 @@ ox::Vector<EditorMaker> Module::editors(core::Context*) {
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Vector<ox::UniquePtr<ItemMaker>> Module::itemMakers(core::Context*) {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,10 +9,13 @@
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include <nostalgia/studio/studio.hpp>
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
class ItemMaker;
|
||||
|
||||
struct EditorMaker {
|
||||
using Func = std::function<ox::Result<class BaseEditor*>(const ox::String&)>;
|
||||
ox::Vector<ox::String> fileTypes;
|
||||
@ -25,6 +28,8 @@ class Module {
|
||||
|
||||
virtual ox::Vector<EditorMaker> editors(core::Context *ctx);
|
||||
|
||||
virtual ox::Vector<ox::UniquePtr<ItemMaker>> itemMakers(core::Context*);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
9
src/nostalgia/studio/lib/popup.cpp
Normal file
9
src/nostalgia/studio/lib/popup.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include "popup.hpp"
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
}
|
62
src/nostalgia/studio/lib/popup.hpp
Normal file
62
src/nostalgia/studio/lib/popup.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/event/signal.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
|
||||
#include <nostalgia/geo/vec.hpp>
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
#include "imguiuitl.hpp"
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
|
||||
class Popup {
|
||||
private:
|
||||
geo::Vec2 m_size;
|
||||
ox::String m_title;
|
||||
public:
|
||||
// emits path parameter
|
||||
ox::Signal<ox::Error(const ox::String&)> finished;
|
||||
|
||||
virtual ~Popup() noexcept = default;
|
||||
|
||||
virtual void open() noexcept = 0;
|
||||
|
||||
virtual void close() noexcept = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool isOpen() const noexcept = 0;
|
||||
|
||||
virtual void draw(core::Context *ctx) noexcept = 0;
|
||||
|
||||
protected:
|
||||
constexpr void setSize(geo::Size sz) noexcept {
|
||||
m_size = {static_cast<float>(sz.width), static_cast<float>(sz.height)};
|
||||
}
|
||||
|
||||
constexpr void setTitle(ox::String title) noexcept {
|
||||
m_title = std::move(title);
|
||||
}
|
||||
|
||||
constexpr const ox::String &title() const noexcept {
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void drawWindow(core::Context *ctx, bool *open, auto drawContents) {
|
||||
studio::ig::centerNextWindow(ctx);
|
||||
ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
|
||||
constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
if (ImGui::BeginPopupModal(m_title.c_str(), open, modalFlags)) {
|
||||
drawContents();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -11,16 +11,8 @@
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
ox::String filePathToName(const ox::String &path, const ox::String &prefix, const ox::String &suffix) noexcept {
|
||||
const auto begin = prefix.len();
|
||||
const auto end = path.len() - (suffix.len() + prefix.len());
|
||||
return path.substr(begin, end);
|
||||
}
|
||||
|
||||
|
||||
Project::Project(ox::FileSystem *fs, const ox::String &path) noexcept: m_typeStore(fs), m_fs(fs) {
|
||||
oxTracef("nostalgia::studio", "Project: {}", path);
|
||||
m_path = path;
|
||||
Project::Project(ox::FileSystem *fs, ox::String path) noexcept: m_path(std::move(path)), m_typeStore(fs), m_fs(fs) {
|
||||
oxTracef("nostalgia::studio", "Project: {}", m_path);
|
||||
buildFileIndex();
|
||||
}
|
||||
|
||||
@ -71,8 +63,13 @@ void Project::buildFileIndex() noexcept {
|
||||
}
|
||||
|
||||
ox::Error Project::writeBuff(const ox::String &path, const ox::Buffer &buff) const noexcept {
|
||||
const auto newFile = m_fs->stat(path.c_str()).error != 0;
|
||||
oxReturnError(m_fs->write(path.c_str(), buff.data(), buff.size()));
|
||||
if (newFile) {
|
||||
fileAdded.emit(path);
|
||||
} else {
|
||||
fileUpdated.emit(path);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,6 @@ constexpr ox::Result<ox::String> fileExt(const ox::String &path) noexcept {
|
||||
return path.substr(extStart + 1);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::String filePathToName(const ox::String &path, const ox::String &prefix, const ox::String &suffix) noexcept;
|
||||
|
||||
class NOSTALGIASTUDIO_EXPORT Project {
|
||||
private:
|
||||
ox::String m_path;
|
||||
@ -48,7 +45,7 @@ class NOSTALGIASTUDIO_EXPORT Project {
|
||||
ox::HashMap<ox::String, ox::Vector<ox::String>> m_fileExtFileMap;
|
||||
|
||||
public:
|
||||
explicit Project(ox::FileSystem *fs, const ox::String &path) noexcept;
|
||||
explicit Project(ox::FileSystem *fs, ox::String path) noexcept;
|
||||
|
||||
ox::Error create() noexcept;
|
||||
|
||||
@ -60,7 +57,7 @@ class NOSTALGIASTUDIO_EXPORT Project {
|
||||
/**
|
||||
* Writes a MetalClaw object to the project at the given path.
|
||||
*/
|
||||
ox::Error writeObj(const ox::String &path, auto *obj) const noexcept;
|
||||
ox::Error writeObj(const ox::String &path, auto *obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) const noexcept;
|
||||
|
||||
template<typename T>
|
||||
ox::Result<ox::UniquePtr<T>> loadObj(const ox::String &path) const noexcept;
|
||||
@ -100,9 +97,9 @@ class NOSTALGIASTUDIO_EXPORT Project {
|
||||
|
||||
};
|
||||
|
||||
ox::Error Project::writeObj(const ox::String &path, auto *obj) const noexcept {
|
||||
ox::Error Project::writeObj(const ox::String &path, auto *obj, ox::ClawFormat fmt) const noexcept {
|
||||
// write MetalClaw
|
||||
oxRequireM(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
||||
oxRequireM(buff, ox::writeClaw(obj, fmt));
|
||||
// write to FS
|
||||
oxReturnError(writeBuff(path, buff));
|
||||
// write type descriptor
|
||||
@ -110,15 +107,12 @@ ox::Error Project::writeObj(const ox::String &path, auto *obj) const noexcept {
|
||||
// write out type store
|
||||
static constexpr auto descPath = "/.nostalgia/type_descriptors";
|
||||
oxReturnError(mkdir(descPath));
|
||||
for (const auto t : m_typeStore.typeList()) {
|
||||
if (t->typeName.beginsWith("B:")) {
|
||||
continue;
|
||||
}
|
||||
for (const auto &t : m_typeStore.typeList()) {
|
||||
oxRequireM(typeOut, ox::writeClaw(t, ox::ClawFormat::Organic));
|
||||
// replace garbage last character with new line
|
||||
typeOut.back().value = '\n';
|
||||
// write to FS
|
||||
const auto typePath = ox::sfmt("{}/{}", descPath, t->typeName);
|
||||
const auto typePath = ox::sfmt("{}/{};{}", descPath, t->typeName, t->typeVersion);
|
||||
oxReturnError(writeBuff(typePath, typeOut));
|
||||
}
|
||||
fileUpdated.emit(path);
|
||||
|
121
src/nostalgia/studio/newmenu.cpp
Normal file
121
src/nostalgia/studio/newmenu.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "lib/context.hpp"
|
||||
#include "lib/imguiuitl.hpp"
|
||||
|
||||
#include "newmenu.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
|
||||
NewMenu::NewMenu() noexcept {
|
||||
setTitle("New Item");
|
||||
setSize({225, 110});
|
||||
}
|
||||
|
||||
void NewMenu::open() noexcept {
|
||||
m_stage = Stage::Opening;
|
||||
m_selectedType = 0;
|
||||
}
|
||||
|
||||
void NewMenu::close() noexcept {
|
||||
m_stage = Stage::Closed;
|
||||
m_open = false;
|
||||
}
|
||||
|
||||
bool NewMenu::isOpen() const noexcept {
|
||||
return m_open;
|
||||
}
|
||||
|
||||
void NewMenu::draw(core::Context *ctx) noexcept {
|
||||
switch (m_stage) {
|
||||
case Stage::Opening:
|
||||
ImGui::OpenPopup(title().c_str());
|
||||
m_stage = Stage::NewItemType;
|
||||
m_open = true;
|
||||
[[fallthrough]];
|
||||
case Stage::NewItemType:
|
||||
drawNewItemType(ctx);
|
||||
break;
|
||||
case Stage::NewItemName:
|
||||
drawNewItemName(ctx);
|
||||
break;
|
||||
case Stage::Closed:
|
||||
m_open = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NewMenu::addItemMaker(ox::UniquePtr<studio::ItemMaker> im) noexcept {
|
||||
m_types.emplace_back(std::move(im));
|
||||
}
|
||||
|
||||
void NewMenu::drawNewItemType(core::Context *ctx) noexcept {
|
||||
drawWindow(ctx, &m_open, [this] {
|
||||
auto items = ox_malloca(m_types.size() * sizeof(const char*), const char*, nullptr);
|
||||
for (auto i = 0u; const auto &im : m_types) {
|
||||
items[i] = im->name.c_str();
|
||||
++i;
|
||||
}
|
||||
ImGui::ListBox("Item Type", &m_selectedType, items.get(), m_types.size());
|
||||
drawFirstPageButtons();
|
||||
ImGui::EndPopup();
|
||||
});
|
||||
}
|
||||
|
||||
void NewMenu::drawNewItemName(core::Context *ctx) noexcept {
|
||||
drawWindow(ctx, &m_open, [this, ctx] {
|
||||
const auto typeIdx = static_cast<std::size_t>(m_selectedType);
|
||||
if (typeIdx < m_types.size()) {
|
||||
ImGui::InputText("Name", m_itemName.data(), m_itemName.cap());
|
||||
}
|
||||
drawLastPageButtons(ctx);
|
||||
ImGui::EndPopup();
|
||||
});
|
||||
}
|
||||
|
||||
void NewMenu::drawFirstPageButtons() noexcept {
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 80);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
|
||||
if (ImGui::Button("Next")) {
|
||||
m_stage = Stage::NewItemName;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Quit")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
m_stage = Stage::Closed;
|
||||
}
|
||||
}
|
||||
|
||||
void NewMenu::drawLastPageButtons(core::Context *ctx) noexcept {
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 138);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
|
||||
if (ImGui::Button("Back")) {
|
||||
m_stage = Stage::NewItemType;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Finish")) {
|
||||
finish(ctx);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Quit")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
m_stage = Stage::Closed;
|
||||
}
|
||||
}
|
||||
|
||||
void NewMenu::finish(core::Context *ctx) noexcept {
|
||||
const auto err = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName.c_str());
|
||||
if (err) {
|
||||
oxDebugf("NewMenu::finish() error: {}", toStr(err));
|
||||
oxLogError(err);
|
||||
return;
|
||||
}
|
||||
finished.emit("");
|
||||
m_stage = Stage::Closed;
|
||||
}
|
||||
|
||||
}
|
81
src/nostalgia/studio/newmenu.hpp
Normal file
81
src/nostalgia/studio/newmenu.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/claw/claw.hpp>
|
||||
#include <ox/event/signal.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
#include "lib/itemmaker.hpp"
|
||||
#include "lib/popup.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
|
||||
class NewMenu: public studio::Popup {
|
||||
public:
|
||||
enum class Stage {
|
||||
Closed,
|
||||
Opening,
|
||||
NewItemType,
|
||||
NewItemName,
|
||||
};
|
||||
|
||||
// emits path parameter
|
||||
ox::Signal<ox::Error(const ox::String&)> finished;
|
||||
|
||||
private:
|
||||
Stage m_stage = Stage::Closed;
|
||||
ox::String m_typeName;
|
||||
ox::BString<255> m_itemName;
|
||||
ox::Vector<ox::UniquePtr<studio::ItemMaker>> m_types;
|
||||
int m_selectedType = 0;
|
||||
bool m_open = false;
|
||||
|
||||
public:
|
||||
NewMenu() noexcept;
|
||||
|
||||
void open() noexcept override;
|
||||
|
||||
void close() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
bool isOpen() const noexcept override;
|
||||
|
||||
void draw(core::Context *ctx) noexcept override;
|
||||
|
||||
template<typename T>
|
||||
void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
|
||||
|
||||
template<typename T>
|
||||
void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
|
||||
|
||||
void addItemMaker(ox::UniquePtr<studio::ItemMaker> im) noexcept;
|
||||
|
||||
private:
|
||||
void drawNewItemType(core::Context *ctx) noexcept;
|
||||
|
||||
void drawNewItemName(core::Context *ctx) noexcept;
|
||||
|
||||
void drawFirstPageButtons() noexcept;
|
||||
|
||||
void drawLastPageButtons(core::Context *ctx) noexcept;
|
||||
|
||||
void finish(core::Context *ctx) noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt) noexcept {
|
||||
m_types.emplace_back(new studio::ItemMakerT<T>(std::move(displayName), std::move(parentDir), std::move(fileExt), std::move(itemTempl), pFmt));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt) noexcept {
|
||||
m_types.emplace_back(new studio::ItemMakerT<T>(std::move(displayName), std::move(parentDir), std::move(fileExt), pFmt));
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ class ProjectExplorer: public studio::Widget {
|
||||
|
||||
ox::Error refreshProjectTreeModel(const ox::String& = {}) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr ox::FileSystem *romFs() noexcept {
|
||||
return m_ctx->rom.get();
|
||||
}
|
||||
|
@ -7,7 +7,10 @@
|
||||
#include "lib/context.hpp"
|
||||
#include "lib/editor.hpp"
|
||||
#include "lib/filedialog.hpp"
|
||||
#include "lib/imguiuitl.hpp"
|
||||
#include "lib/module.hpp"
|
||||
#include "lib/itemmaker.hpp"
|
||||
#include "lib/popup.hpp"
|
||||
#include "lib/project.hpp"
|
||||
#include "lib/task.hpp"
|
||||
#include "lib/undostack.hpp"
|
||||
|
@ -46,10 +46,10 @@ StudioUI::StudioUI(core::Context *ctx) noexcept {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (toStr(err)) {
|
||||
oxErrf("Could not open studio config file: {}\n", toStr(err));
|
||||
if constexpr(!ox::defines::Debug) {
|
||||
oxErrf("Could not open studio config file: {}: {}\n", err.errCode, toStr(err));
|
||||
} else {
|
||||
oxErrf("Could not open studio config file: {} ({}:{})\n", err.errCode, err.file, err.line);
|
||||
oxErrf("Could not open studio config file: {}: {} ({}:{})\n", err.errCode, toStr(err), err.file, err.line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,6 +60,14 @@ void StudioUI::update() noexcept {
|
||||
|
||||
void StudioUI::handleKeyEvent(core::Key key, bool down) noexcept {
|
||||
const auto ctrlDown = core::buttonDown(m_ctx, core::Key::Mod_Ctrl);
|
||||
for (auto p : m_popups) {
|
||||
if (p->isOpen()) {
|
||||
if (key == core::Key::Escape) {
|
||||
p->close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (down && ctrlDown) {
|
||||
switch (key) {
|
||||
case core::Key::Num_1:
|
||||
@ -68,6 +76,9 @@ void StudioUI::handleKeyEvent(core::Key key, bool down) noexcept {
|
||||
case core::Key::Alpha_C:
|
||||
m_activeEditor->copy();
|
||||
break;
|
||||
case core::Key::Alpha_N:
|
||||
m_newMenu.open();
|
||||
break;
|
||||
case core::Key::Alpha_O:
|
||||
m_taskRunner.add(new FileDialogManager(this, &StudioUI::openProject));
|
||||
break;
|
||||
@ -109,16 +120,16 @@ void StudioUI::draw() noexcept {
|
||||
for (auto &w : m_widgets) {
|
||||
w->draw(m_ctx);
|
||||
}
|
||||
if (m_aboutEnabled) {
|
||||
ImGui::OpenPopup("About");
|
||||
for (auto p : m_popups) {
|
||||
p->draw(m_ctx);
|
||||
}
|
||||
drawAboutPopup();
|
||||
}
|
||||
|
||||
void StudioUI::drawMenu() noexcept {
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("New...", "Ctrl+N")) {
|
||||
m_newMenu.open();
|
||||
}
|
||||
if (ImGui::MenuItem("Open Project...", "Ctrl+O")) {
|
||||
m_taskRunner.add(new FileDialogManager(this, &StudioUI::openProject));
|
||||
@ -159,7 +170,7 @@ void StudioUI::drawMenu() noexcept {
|
||||
}
|
||||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("About")) {
|
||||
m_aboutEnabled = true;
|
||||
m_aboutPopup.open();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@ -221,19 +232,6 @@ void StudioUI::drawTabs() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void StudioUI::drawAboutPopup() noexcept {
|
||||
constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
if (ImGui::BeginPopupModal("About", &m_aboutEnabled, modalFlags)) {
|
||||
ImGui::Text("Nostalgia Studio - dev build");
|
||||
ImGui::SetNextWindowPos(ImVec2(0.5f, 0.5f), ImGuiCond_Always, ImVec2(0.5f,0.5f));
|
||||
if (ImGui::Button("Close")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
m_aboutEnabled = false;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void StudioUI::loadEditorMaker(const studio::EditorMaker &editorMaker) noexcept {
|
||||
for (const auto &ext : editorMaker.fileTypes) {
|
||||
m_editorMakers[ext] = editorMaker.make;
|
||||
@ -244,6 +242,9 @@ void StudioUI::loadModule(studio::Module *module) noexcept {
|
||||
for (auto &editorMaker : module->editors(m_ctx)) {
|
||||
loadEditorMaker(editorMaker);
|
||||
}
|
||||
for (auto &im : module->itemMakers(m_ctx)) {
|
||||
m_newMenu.addItemMaker(std::move(im));
|
||||
}
|
||||
}
|
||||
|
||||
void StudioUI::loadModules() noexcept {
|
||||
@ -320,7 +321,11 @@ ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab
|
||||
}
|
||||
auto [editor, err] = m_editorMakers[ext](path);
|
||||
if (err) {
|
||||
oxErrorf("Could not open Editor: {} ({}:{})", err.msg, err.file, err.line);
|
||||
if constexpr(!ox::defines::Debug) {
|
||||
oxErrf("Could not open Editor: {}\n", toStr(err));
|
||||
} else {
|
||||
oxErrf("Could not open Editor: {} ({}:{})\n", err.errCode, err.file, err.line);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
editor->closed.connect(this, &StudioUI::closeFile);
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "lib/module.hpp"
|
||||
#include "lib/project.hpp"
|
||||
#include "lib/task.hpp"
|
||||
#include "aboutpopup.hpp"
|
||||
#include "newmenu.hpp"
|
||||
#include "projectexplorer.hpp"
|
||||
#include "projecttreemodel.hpp"
|
||||
|
||||
@ -31,8 +33,12 @@ class StudioUI: public ox::SignalHandler {
|
||||
ox::Vector<ox::String> m_openFiles;
|
||||
studio::BaseEditor *m_activeEditor = nullptr;
|
||||
studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
|
||||
bool m_saveEnabled = false;
|
||||
bool m_aboutEnabled = false;
|
||||
NewMenu m_newMenu;
|
||||
AboutPopup m_aboutPopup;
|
||||
const ox::Array<studio::Popup*, 2> m_popups = {
|
||||
&m_newMenu,
|
||||
&m_aboutPopup
|
||||
};
|
||||
bool m_showProjectExplorer = true;
|
||||
|
||||
public:
|
||||
@ -57,8 +63,6 @@ class StudioUI: public ox::SignalHandler {
|
||||
|
||||
void drawTabs() noexcept;
|
||||
|
||||
void drawAboutPopup() noexcept;
|
||||
|
||||
void loadEditorMaker(const studio::EditorMaker &editorMaker) noexcept;
|
||||
|
||||
void loadModule(studio::Module *module) noexcept;
|
||||
|
Loading…
Reference in New Issue
Block a user