diff --git a/deps/buildcore/base.cmake b/deps/buildcore/base.cmake index 0a988652..20822cc0 100644 --- a/deps/buildcore/base.cmake +++ b/deps/buildcore/base.cmake @@ -44,7 +44,7 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor") - #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-null-dereference") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") diff --git a/deps/ox/CMakeLists.txt b/deps/ox/CMakeLists.txt index a00e462a..2d0a2ae2 100644 --- a/deps/ox/CMakeLists.txt +++ b/deps/ox/CMakeLists.txt @@ -56,7 +56,7 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp index 3b55cb55..3819ca6c 100644 --- a/deps/ox/src/ox/model/modelvalue.hpp +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "def.hpp" @@ -279,6 +280,11 @@ class ModelValueVector { return m_vec.begin(); } + [[nodiscard]] + auto begin() const noexcept { + return m_vec.cbegin(); + } + [[nodiscard]] auto cbegin() const noexcept { return m_vec.cbegin(); @@ -299,6 +305,11 @@ class ModelValueVector { return m_vec.end(); } + [[nodiscard]] + auto end() const noexcept { + return m_vec.cend(); + } + [[nodiscard]] auto cend() const noexcept { return m_vec.cend(); @@ -321,18 +332,17 @@ consteval bool isVector(const ModelValueVector*) noexcept { } class ModelObject { - protected: + public: struct Field { String name; ModelValue value; }; + protected: oxModelFriend(ModelObject); friend ModelValue; Vector> m_fieldsOrder; HashMap m_fields; const DescriptorType *m_type = nullptr; - String m_typeName; - int m_typeVersion = 0; public: constexpr ModelObject() noexcept = default; @@ -343,16 +353,12 @@ class ModelObject { m_fields[field->name] = &field->value; } m_type = other.m_type; - m_typeName = other.m_typeName; - m_typeVersion = other.m_typeVersion; } constexpr ModelObject(ModelObject &&other) noexcept { m_fields = std::move(other.m_fields); m_type = other.m_type; m_fieldsOrder = std::move(other.m_fieldsOrder); - m_typeName = std::move(other.m_typeName); - m_typeVersion = other.m_typeVersion; } [[nodiscard]] @@ -424,8 +430,6 @@ class ModelObject { m_fields[field->name] = &field->value; } m_type = other.m_type; - m_typeName = other.m_typeName; - m_typeVersion = other.m_typeVersion; return *this; } @@ -436,17 +440,35 @@ class ModelObject { m_type = other.m_type; m_fields = std::move(other.m_fields); m_fieldsOrder = std::move(other.m_fieldsOrder); - m_typeName = std::move(other.m_typeName); - m_typeVersion = other.m_typeVersion; return *this; } - constexpr auto &operator[](const std::size_t &i) noexcept { - return *m_fieldsOrder[i]; + template + constexpr auto set(const std::size_t &i, T &&val) noexcept { + auto &f = *m_fieldsOrder[i]; + f = val; + } + + constexpr Result get(const String &k) const noexcept { + if (m_fields.contains(k)) { + return *m_fields.at(k).value; + } + return OxError(1); + } + + template + constexpr Error set(const String &k, T &&val) noexcept { + oxRequire(t, m_fields.at(k)); + *t = ox::forward(val); + return {}; } constexpr auto &operator[](const String &k) noexcept { - return *m_fields[k]; + auto [v, err] = m_fields.at(k); + if (err) [[unlikely]] { + oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str()); + } + return **v; } constexpr auto &operator[](const std::size_t i) noexcept { @@ -454,13 +476,13 @@ class ModelObject { } [[nodiscard]] - constexpr StringView typeName() const noexcept { - return m_typeName; + constexpr CRString typeName() const noexcept { + return m_type->typeName; } [[nodiscard]] constexpr int typeVersion() const noexcept { - return m_typeVersion; + return m_type->typeVersion; } [[nodiscard]] @@ -473,8 +495,6 @@ class ModelObject { return OxError(1, "Cannot load a non-struct type to ModelObject"); } m_type = type; - m_typeName = type->typeName; - m_typeVersion = type->typeVersion; for (const auto &f : type->fieldList) { auto field = make_unique(); field->name = f.fieldName; @@ -498,8 +518,7 @@ class ModelUnion { friend ModelValue; Vector> m_fieldsOrder; HashMap m_fields; - String m_typeName; - int m_typeVersion = 0; + const DescriptorType *m_type = nullptr; int m_unionIdx = -1; private: @@ -512,16 +531,12 @@ class ModelUnion { m_fields[field->name] = field.get(); ++i; } - m_typeName = other.m_typeName; - m_typeVersion = other.m_typeVersion; m_unionIdx = other.m_unionIdx; } constexpr ModelUnion(ModelUnion &&other) noexcept { m_fieldsOrder = std::move(other.m_fieldsOrder); m_fields = std::move(other.m_fields); - m_typeName = std::move(other.m_typeName); - m_typeVersion = other.m_typeVersion; m_unionIdx = other.m_unionIdx; } @@ -536,7 +551,11 @@ class ModelUnion { } constexpr auto &operator[](const String &k) noexcept { - return m_fields[k]->value; + const auto [v, err] = m_fields.at(k); + if (err) [[unlikely]] { + oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str()); + } + return (*v)->value; } constexpr auto &operator[](const std::size_t i) noexcept { @@ -558,13 +577,17 @@ class ModelUnion { } [[nodiscard]] - constexpr ModelValue &get(std::size_t i) noexcept { - return m_fieldsOrder[i]->value; + constexpr Result get(std::size_t i) const noexcept { + if (i < m_fieldsOrder.size()) { + return &m_fieldsOrder[i]->value; + } + return {}; } [[nodiscard]] - constexpr ModelValue &get(const String &k) noexcept { - return (*m_fields.at(k).value)->value; + constexpr Result get(const String &k) const noexcept { + oxRequire(t, m_fields.at(k)); + return &(*t)->value; } [[nodiscard]] @@ -580,12 +603,12 @@ class ModelUnion { [[nodiscard]] constexpr const String &typeName() const noexcept { - return m_typeName; + return m_type->typeName; } [[nodiscard]] constexpr int typeVersion() const noexcept { - return m_typeVersion; + return m_type->typeVersion; } constexpr Error setType(const DescriptorType *type) noexcept { @@ -594,8 +617,7 @@ class ModelUnion { } m_fields.clear(); m_fieldsOrder.clear(); - m_typeName = type->typeName; - m_typeVersion = type->typeVersion; + m_type = type; for (auto i = 0; const auto &f : type->fieldList) { auto field = make_unique(); field->name = f.fieldName; @@ -744,7 +766,7 @@ constexpr std::size_t alignOf(const ModelValue &t) noexcept { } constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept { - h->template setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast(obj->m_fieldsOrder.size())); + h->template setTypeInfo(obj->typeName().c_str(), obj->typeVersion(), {}, static_cast(obj->m_fieldsOrder.size())); for (auto &f : obj->m_fieldsOrder) { oxReturnError(h->field(f->name.c_str(), &f->value)); } @@ -752,7 +774,7 @@ constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept { } constexpr Error model(auto *h, CommonPtrWith auto *obj) noexcept { - h->template setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast(obj->m_fieldsOrder.size())); + h->template setTypeInfo(obj->typeName().c_str(), obj->typeVersion(), {}, static_cast(obj->m_fieldsOrder.size())); for (auto &f : obj->m_fieldsOrder) { oxReturnError(h->field(f->name.c_str(), &f->value)); } diff --git a/deps/ox/src/ox/model/typenamecatcher.hpp b/deps/ox/src/ox/model/typenamecatcher.hpp index 5c65dc8f..553ad1ec 100644 --- a/deps/ox/src/ox/model/typenamecatcher.hpp +++ b/deps/ox/src/ox/model/typenamecatcher.hpp @@ -25,7 +25,7 @@ struct TypeNameCatcher { constexpr TypeNameCatcher() noexcept = default; template - constexpr void setTypeInfo(const char *n = T::TypeName, const Vector& = {}, int v = 0) noexcept { + constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, const Vector& = {}, int = 0) noexcept { this->name = n; this->version = v; } diff --git a/deps/ox/src/ox/model/typestore.hpp b/deps/ox/src/ox/model/typestore.hpp index 899bea5b..6bb404eb 100644 --- a/deps/ox/src/ox/model/typestore.hpp +++ b/deps/ox/src/ox/model/typestore.hpp @@ -29,7 +29,7 @@ class TypeStore { constexpr virtual ~TypeStore() noexcept = default; constexpr Result get(const auto &name, int typeVersion, - const Vector &typeParams) const noexcept { + const TypeParamPack &typeParams) const noexcept { const auto typeId = buildTypeId(name, typeVersion, typeParams); oxRequire(out, m_cache.at(typeId)); return out->get(); @@ -71,7 +71,7 @@ class TypeStore { } constexpr Result getLoad(const auto &typeName, auto typeVersion, - const Vector &typeParams = {}) noexcept { + const TypeParamPack &typeParams = {}) noexcept { return getLoad(buildTypeId(typeName, typeVersion, typeParams)); } @@ -95,7 +95,7 @@ class TypeStore { const auto &keys = m_cache.keys(); ox::Vector descs; for (const auto &k : keys) { - descs.emplace_back(m_cache.at(k).value->get()); + descs.emplace_back(m_cache.at(k).unwrap()->get()); } return descs; } @@ -106,7 +106,7 @@ class TypeStore { } Result> loadDescriptor(ox::CRStringView name, int version, - const Vector &typeParams) noexcept { + const ox::TypeParamPack &typeParams) noexcept { const auto typeId = buildTypeId(name, version, typeParams); return loadDescriptor(typeId); } diff --git a/deps/ox/src/ox/oc/test/tests.cpp b/deps/ox/src/ox/oc/test/tests.cpp index 4bd28b52..e4914b47 100644 --- a/deps/ox/src/ox/oc/test/tests.cpp +++ b/deps/ox/src/ox/oc/test/tests.cpp @@ -14,6 +14,14 @@ #include #include +template +union U { + T t; + int i; +}; + +U u; + union TestUnion { static constexpr auto TypeName = "TestUnion"; static constexpr auto TypeVersion = 1; @@ -204,26 +212,26 @@ const std::map tests = { ox::ModelObject testOut; oxReturnError(testOut.setType(type.value)); oxAssert(ox::readOC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed"); - oxAssert(testOut["Int"].get() == testIn.Int, "testOut.Int failed"); - oxAssert(testOut["Bool"].get() == testIn.Bool, "testOut.Bool failed"); - oxAssert(testOut["String"].get() == testIn.String, "testOut.String failed"); - auto &testOutStruct = testOut["Struct"].get(); - auto &testOutUnion = testOut["Union"].get(); - auto &testOutList = testOut["List"].get(); - auto testOutStructCopy = testOut["Struct"].get(); - auto testOutUnionCopy = testOut["Union"].get(); - auto testOutListCopy = testOut["List"].get(); + oxAssert(testOut.get("Int").unwrap()->get() == testIn.Int, "testOut.Int failed"); + oxAssert(testOut.get("Bool").unwrap()->get() == testIn.Bool, "testOut.Bool failed"); + oxAssert(testOut.get("String").unwrap()->get() == testIn.String, "testOut.String failed"); + auto &testOutStruct = testOut.get("Struct").unwrap()->get(); + auto &testOutUnion = testOut.get("Union").unwrap()->get(); + auto &testOutList = testOut.get("List").unwrap()->get(); + auto testOutStructCopy = testOut.get("Struct").unwrap()->get(); + auto testOutUnionCopy = testOut.get("Union").unwrap()->get(); + auto testOutListCopy = testOut.get("List").unwrap()->get(); oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed"); oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed"); - oxAssert(testOutStruct["Bool"].get() == testIn.Struct.Bool, "testOut.Struct.Bool failed"); - oxAssert(testOutStruct["String"].get() == testIn.Struct.String.c_str(), "testOut.Struct.String failed"); - oxAssert(testOut["unionIdx"].get() == testIn.unionIdx, "testOut.unionIdx failed"); + oxAssert(testOutStruct.get("Bool").unwrap()->get() == testIn.Struct.Bool, "testOut.Struct.Bool failed"); + oxAssert(testOutStruct.get("String").unwrap()->get() == testIn.Struct.String.c_str(), "testOut.Struct.String failed"); + oxAssert(testOut.get("unionIdx").unwrap()->get() == testIn.unionIdx, "testOut.unionIdx failed"); oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong"); - oxAssert(testOutUnion["Int"].get() == testIn.Union.Int, "testOut.Union.Int failed"); + oxAssert(testOutUnion.get("Int").unwrap()->get() == testIn.Union.Int, "testOut.Union.Int failed"); oxAssert(testOutList[0].get() == testIn.List[0], "testOut.List[0] failed"); oxAssert(testOutList[1].get() == testIn.List[1], "testOut.Struct.List[1] failed"); - oxAssert(testOutStructCopy["Bool"].get() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed"); - oxAssert(testOutStructCopy["String"].get() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed"); + oxAssert(testOutStructCopy.get("Bool").unwrap()->get() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed"); + oxAssert(testOutStructCopy.get("String").unwrap()->get() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed"); oxAssert(testOutListCopy[0].get() == testIn.List[0], "testOut.Struct.List[0] (copy) failed"); oxAssert(testOutListCopy[1].get() == testIn.List[1], "testOut.Struct.List[1] (copy) failed"); return OxError(0); diff --git a/deps/ox/src/ox/std/memops.hpp b/deps/ox/src/ox/std/memops.hpp index 820f3288..77ea1e06 100644 --- a/deps/ox/src/ox/std/memops.hpp +++ b/deps/ox/src/ox/std/memops.hpp @@ -68,6 +68,10 @@ constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept { namespace ox { +constexpr void *memcpy(void *dest, const void *src, std::size_t size) noexcept { + return ox_memcpy(dest, src, size); +} + template void *memsetElements(T *ptr, T val, std::size_t elements) noexcept { return memset(ptr, val, elements * sizeof(T)); diff --git a/deps/ox/src/ox/std/memory.hpp b/deps/ox/src/ox/std/memory.hpp index 78440edc..58a06929 100644 --- a/deps/ox/src/ox/std/memory.hpp +++ b/deps/ox/src/ox/std/memory.hpp @@ -247,6 +247,9 @@ class UniquePtr { }; +template +using UPtr = UniquePtr; + template constexpr bool operator==(const UniquePtr &p1, const UniquePtr &p2) noexcept { return p1.get() == p2.get(); diff --git a/deps/ox/src/ox/std/stringview.hpp b/deps/ox/src/ox/std/stringview.hpp index 5b1e824f..72e2b5f1 100644 --- a/deps/ox/src/ox/std/stringview.hpp +++ b/deps/ox/src/ox/std/stringview.hpp @@ -8,8 +8,10 @@ #pragma once +#include "iterator.hpp" #include "strops.hpp" #include "types.hpp" +#include "bit.hpp" namespace ox { @@ -20,6 +22,111 @@ template class BasicString; class StringView { + public: + template + struct iterator: public Iterator { + private: + PtrType m_t = nullptr; + std::size_t m_offset = 0; + std::size_t m_max = 0; + + public: + constexpr iterator() noexcept = default; + + constexpr iterator(PtrType t, std::size_t offset, std::size_t max) noexcept { + m_t = t; + m_offset = offset; + m_max = max; + } + + constexpr auto offset() const noexcept { + return m_offset; + } + + constexpr iterator operator+(std::size_t s) const noexcept { + if constexpr(reverse) { + return iterator(m_t, max(m_offset - s, 0), m_max); + } else { + return iterator(m_t, min(m_offset + s, m_max), m_max); + } + } + + constexpr auto operator-(const iterator &other) const noexcept { + if constexpr(reverse) { + return m_offset + other.m_offset; + } else { + return m_offset - other.m_offset; + } + } + + constexpr iterator operator-(std::size_t s) const noexcept { + if constexpr(reverse) { + return iterator(m_t, min(m_offset + s, m_max), m_max); + } else { + return iterator(m_t, max(m_offset - s, 0), m_max); + } + } + + constexpr iterator &operator+=(std::size_t s) noexcept { + if constexpr(reverse) { + m_offset = max(m_offset - s, 0); + } else { + m_offset = min(m_offset + s, m_max); + } + return *this; + } + + constexpr iterator &operator-=(std::size_t s) noexcept { + if constexpr(reverse) { + m_offset = min(m_offset + s, m_max); + } else { + m_offset = max(m_offset - s, 0); + } + return *this; + } + + constexpr iterator &operator++() noexcept { + return operator+=(1); + } + + constexpr iterator &operator--() noexcept { + return operator-=(1); + } + + constexpr RefType operator*() const noexcept { + return m_t[m_offset]; + } + + constexpr RefType operator[](std::size_t s) const noexcept { + return m_t[s]; + } + + constexpr bool operator<(const iterator &other) const noexcept { + return m_offset < other.m_offset; + } + + constexpr bool operator>(const iterator &other) const noexcept { + return m_offset > other.m_offset; + } + + constexpr bool operator<=(const iterator &other) const noexcept { + return m_offset <= other.m_offset; + } + + constexpr bool operator>=(const iterator &other) const noexcept { + return m_offset >= other.m_offset; + } + + constexpr bool operator==(const iterator &other) const noexcept { + return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max; + } + + constexpr bool operator!=(const iterator &other) const noexcept { + return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max; + } + + }; + private: const char *m_str = nullptr; std::size_t m_len = 0; @@ -41,6 +148,46 @@ class StringView { constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {} + [[nodiscard]] + constexpr iterator begin() const noexcept { + return {m_str, 0, m_len}; + } + + [[nodiscard]] + constexpr iterator end() const noexcept { + return {m_str, m_len, m_len}; + } + + [[nodiscard]] + constexpr iterator cbegin() const noexcept { + return {m_str, 0, m_len}; + } + + [[nodiscard]] + constexpr iterator cend() const noexcept { + return {m_str, m_len, m_len}; + } + + [[nodiscard]] + constexpr iterator crbegin() const noexcept { + return {m_str, m_len - 1, m_len}; + } + + [[nodiscard]] + constexpr iterator crend() const noexcept { + return {m_str, MaxValue, m_len}; + } + + [[nodiscard]] + constexpr iterator rbegin() const noexcept { + return {m_str, m_len - 1, m_len}; + } + + [[nodiscard]] + constexpr iterator rend() const noexcept { + return {m_str, MaxValue, m_len}; + } + [[nodiscard]] constexpr auto bytes() const noexcept { return m_len; @@ -66,6 +213,10 @@ class StringView { return m_str[m_len - 1]; } + constexpr auto substr(std::size_t pos) const noexcept { + return StringView(m_str + pos, m_len - pos); + } + constexpr auto operator[](std::size_t i) const noexcept { return m_str[i]; } diff --git a/src/nostalgia/studio/CMakeLists.txt b/src/nostalgia/studio/CMakeLists.txt index 4174cb78..3a13371b 100644 --- a/src/nostalgia/studio/CMakeLists.txt +++ b/src/nostalgia/studio/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable( nostalgia-studio MACOSX_BUNDLE aboutpopup.cpp + clawviewer.cpp filedialogmanager.cpp main.cpp newmenu.cpp diff --git a/src/nostalgia/studio/clawviewer.cpp b/src/nostalgia/studio/clawviewer.cpp new file mode 100644 index 00000000..14cbf511 --- /dev/null +++ b/src/nostalgia/studio/clawviewer.cpp @@ -0,0 +1,186 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "clawviewer.hpp" + +namespace nostalgia { + +ClawEditor::ClawEditor(ox::CRStringView path, ox::ModelObject obj) noexcept: + m_itemName(path), + m_itemDisplayName(pathToItemName(path)), + m_obj(std::move(obj)) { +} + +ox::CRString ClawEditor::itemName() const noexcept { + return m_itemName; +} + +ox::CRString ClawEditor::itemDisplayName() const noexcept { + return m_itemDisplayName; +} + +void ClawEditor::draw(core::Context*) noexcept { + //const auto paneSize = ImGui::GetContentRegionAvail(); + ImGui::BeginChild("PaletteEditor"); + static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + if (ImGui::BeginTable("ObjTree", 3, flags)) { + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 250); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_NoHide); + ImGui::TableHeadersRow(); + ObjPath objPath; + drawTree(&objPath, m_obj); + ImGui::EndTable(); + } + ImGui::EndChild(); +} + +void ClawEditor::drawRow(const ox::ModelValue &value) noexcept { + using Str = ox::BasicString<100>; + Str val, type; + switch (value.type()) { + case ox::ModelValue::Type::Undefined: + val = "undefined"; + type = "undefined"; + break; + case ox::ModelValue::Type::Bool: + val = value.get() ? "true" : "false"; + type = "bool"; + break; + case ox::ModelValue::Type::UnsignedInteger8: + val = ox::sfmt("{}", value.get()); + type = "uint8"; + break; + case ox::ModelValue::Type::UnsignedInteger16: + val = ox::sfmt("{}", value.get()); + type = "uint16"; + break; + case ox::ModelValue::Type::UnsignedInteger32: + val = ox::sfmt("{}", value.get()); + type = "uint32"; + break; + case ox::ModelValue::Type::UnsignedInteger64: + val = ox::sfmt("{}", value.get()); + type = "uint64"; + break; + case ox::ModelValue::Type::SignedInteger8: + val = ox::sfmt("{}", value.get()); + type = "int8"; + break; + case ox::ModelValue::Type::SignedInteger16: + val = ox::sfmt("{}", value.get()); + type = "int16"; + break; + case ox::ModelValue::Type::SignedInteger32: + val = ox::sfmt("{}", value.get()); + type = "int32"; + break; + case ox::ModelValue::Type::SignedInteger64: + val = ox::sfmt("{}", value.get()); + type = "int64"; + break; + case ox::ModelValue::Type::String: + val = ox::sfmt("\"{}\"", value.get()); + type = "string"; + break; + case ox::ModelValue::Type::Object: + type = value.get().type()->typeName.c_str(); + break; + case ox::ModelValue::Type::Union: + type = "union"; + break; + case ox::ModelValue::Type::Vector: + type = "list"; + break; + } + ImGui::TableNextColumn(); + ImGui::Text("%s", type.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%s", val.c_str()); +} + +void ClawEditor::drawVar(ObjPath *path, ox::CRStringView name, const ox::ModelValue &value) noexcept { + using Str = ox::BasicString<100>; + path->push_back(name); + if (value.type() == ox::ModelValue::Type::Object) { + drawTree(path, value.get()); + } else if (value.type() == ox::ModelValue::Type::Vector) { + const auto &vec = value.get(); + const auto pathStr = ox::join("##", *path).unwrap(); + const auto lbl = ox::sfmt("{}##{}", name, pathStr); + const auto flags = ImGuiTreeNodeFlags_SpanFullWidth + | ImGuiTreeNodeFlags_OpenOnArrow + | (vec.size() ? 0 : ImGuiTreeNodeFlags_Leaf) + | (false ? ImGuiTreeNodeFlags_Selected : 0); + const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags); + ImGui::SameLine(); + drawRow(value); + if (open) { + for (auto i = 0lu; const auto &e: vec) { + const auto iStr = ox::sfmt("{}", i); + path->push_back(iStr); + ImGui::TableNextRow(0, 5); + ImGui::TableNextColumn(); + drawVar(path, ox::sfmt("[{}]", i), e); + path->pop_back(); + ++i; + } + ImGui::TreePop(); + } + } else { + const auto pathStr = ox::join("##", *path).unwrap(); + const auto lbl = ox::sfmt("{}##{}", name, pathStr); + const auto flags = ImGuiTreeNodeFlags_SpanFullWidth + | ImGuiTreeNodeFlags_OpenOnArrow + | ImGuiTreeNodeFlags_Leaf + | (false ? ImGuiTreeNodeFlags_Selected : 0); + const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags); + ImGui::SameLine(); + drawRow(value); + if (open) { + ImGui::TreePop(); + } + } + path->pop_back(); +} + +void ClawEditor::drawTree(ObjPath *path, const ox::ModelObject &obj) noexcept { + using Str = ox::BasicString<100>; + for (const auto &c : obj) { + ImGui::TableNextRow(0, 5); + auto pathStr = ox::join("##", *path).unwrap(); + auto lbl = ox::sfmt("{}##{}", c->name, pathStr); + const auto rowSelected = false; + const auto hasChildren = c->value.type() == ox::ModelValue::Type::Object + || c->value.type() == ox::ModelValue::Type::Vector; + const auto flags = ImGuiTreeNodeFlags_SpanFullWidth + | ImGuiTreeNodeFlags_OpenOnArrow + | (hasChildren ? 0 : ImGuiTreeNodeFlags_Leaf) + | (rowSelected ? ImGuiTreeNodeFlags_Selected : 0); + ImGui::TableNextColumn(); + if (ImGui::IsItemClicked()) { + //model()->setActiveSubsheet(*path); + } + if (ImGui::IsMouseDoubleClicked(0) && ImGui::IsItemHovered()) { + //showSubsheetEditor(); + } + path->push_back(c->name); + if (c->value.type() == ox::ModelValue::Type::Object) { + const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags); + ImGui::SameLine(); + drawRow(c->value); + if (open) { + drawTree(path, c->value.get()); + ImGui::TreePop(); + } + } else { + drawVar(path, c->name, c->value); + } + path->pop_back(); + } +} + +} \ No newline at end of file diff --git a/src/nostalgia/studio/clawviewer.hpp b/src/nostalgia/studio/clawviewer.hpp new file mode 100644 index 00000000..09267122 --- /dev/null +++ b/src/nostalgia/studio/clawviewer.hpp @@ -0,0 +1,40 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include + +#include "lib/editor.hpp" + +namespace nostalgia { + +class ClawEditor: public studio::Editor { + private: + using ObjPath = ox::Vector; + ox::String m_itemName; + ox::String m_itemDisplayName; + ox::ModelObject m_obj; + public: + ClawEditor(ox::CRStringView path, ox::ModelObject obj) noexcept; + + /** + * Returns the name of item being edited. + */ + ox::CRString itemName() const noexcept final; + + ox::CRString itemDisplayName() const noexcept final; + + void draw(core::Context*) noexcept final; + + private: + static void drawRow(const ox::ModelValue &value) noexcept; + + void drawVar(ObjPath *path, ox::CRStringView name, const ox::ModelValue &value) noexcept; + + void drawTree(ObjPath *path, const ox::ModelObject &obj) noexcept; +}; + +} diff --git a/src/nostalgia/studio/lib/editor.hpp b/src/nostalgia/studio/lib/editor.hpp index eeb95439..b8a9f024 100644 --- a/src/nostalgia/studio/lib/editor.hpp +++ b/src/nostalgia/studio/lib/editor.hpp @@ -100,6 +100,11 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget { return nullptr; } + static constexpr auto pathToItemName(ox::CRStringView path) noexcept { + const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset(); + return path.substr(lastSlash + 1); + } + // signals public: ox::Signal unsavedChangesChanged; diff --git a/src/nostalgia/studio/lib/project.hpp b/src/nostalgia/studio/lib/project.hpp index 7779aa64..4af1cc39 100644 --- a/src/nostalgia/studio/lib/project.hpp +++ b/src/nostalgia/studio/lib/project.hpp @@ -61,7 +61,7 @@ class NOSTALGIASTUDIO_EXPORT Project { ox::Error writeObj(const ox::String &path, const T *obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept; template - ox::Result> loadObj(const ox::String &path) const noexcept; + ox::Result loadObj(const ox::String &path) const noexcept; ox::Result stat(const ox::String &path) const noexcept; @@ -126,10 +126,13 @@ ox::Error Project::writeObj(const ox::String &path, const T *obj, ox::ClawFormat } template -ox::Result> Project::loadObj(const ox::String &path) const noexcept { - auto obj = ox::make_unique(); +ox::Result Project::loadObj(const ox::String &path) const noexcept { oxRequire(buff, loadBuff(path)); - return ox::readClaw(buff); + if constexpr (ox::is_same_v) { + return ox::readClaw(&m_typeStore, buff); + } else { + return ox::readClaw(buff); + } } template diff --git a/src/nostalgia/studio/studioapp.cpp b/src/nostalgia/studio/studioapp.cpp index 73a8b532..bfdc7dab 100644 --- a/src/nostalgia/studio/studioapp.cpp +++ b/src/nostalgia/studio/studioapp.cpp @@ -8,6 +8,7 @@ #include "lib/configio.hpp" #include "builtinmodules.hpp" +#include "clawviewer.hpp" #include "filedialogmanager.hpp" #include "studioapp.hpp" @@ -300,11 +301,11 @@ ox::Error StudioUI::openProject(const ox::String &path) noexcept { return m_projectExplorer->refreshProjectTreeModel(); } -ox::Error StudioUI::openFile(const ox::String &path) noexcept { +ox::Error StudioUI::openFile(ox::CRStringView path) noexcept { return openFileActiveTab(path, true); } -ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab) noexcept { +ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab) noexcept { if (m_openFiles.contains(path)) { for (auto &e : m_editors) { if (makeActiveTab && e->itemName() == path) { @@ -317,17 +318,23 @@ ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab } oxRequire(ext, studio::fileExt(path)); // create Editor + studio::BaseEditor *editor = nullptr; if (!m_editorMakers.contains(ext)) { - return OxError(1, "There is no editor for this file extension"); - } - auto [editor, err] = m_editorMakers[ext](path); - if (err) { - 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); + auto [obj, err] = m_project->loadObj(path); + if (err) { + return OxError(1, "There is no editor for this file extension"); + } + editor = new ClawEditor(path, std::move(obj)); + } else { + const auto err = m_editorMakers[ext](path).moveTo(&editor); + if (err) { + 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; } - return err; } editor->closed.connect(this, &StudioUI::closeFile); m_editors.emplace_back(editor); diff --git a/src/nostalgia/studio/studioapp.hpp b/src/nostalgia/studio/studioapp.hpp index 0321a1f8..a7529cb1 100644 --- a/src/nostalgia/studio/studioapp.hpp +++ b/src/nostalgia/studio/studioapp.hpp @@ -79,9 +79,9 @@ class StudioUI: public ox::SignalHandler { ox::Error openProject(const ox::String &path) noexcept; - ox::Error openFile(const ox::String &path) noexcept; + ox::Error openFile(ox::CRStringView path) noexcept; - ox::Error openFileActiveTab(const ox::String &path, bool makeActiveTab) noexcept; + ox::Error openFileActiveTab(ox::CRStringView path, bool makeActiveTab) noexcept; ox::Error closeFile(const ox::String &path) noexcept; };