Compare commits
	
		
			3 Commits
		
	
	
		
			a3d6a58cc8
			...
			92e9d9cbfc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 92e9d9cbfc | |||
| b29b9a9b3a | |||
| 721f844214 | 
							
								
								
									
										85
									
								
								deps/ox/src/ox/std/anyptr.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										85
									
								
								deps/ox/src/ox/std/anyptr.hpp
									
									
									
									
										vendored
									
									
								
							@@ -15,16 +15,20 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ox {
 | 
					namespace ox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AnyPtr {
 | 
					namespace detail {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<bool unique>
 | 
				
			||||||
 | 
					class AnyPtrT {
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		struct WrapBase {
 | 
							struct WrapBase {
 | 
				
			||||||
			virtual constexpr ~WrapBase() = default;
 | 
								virtual constexpr ~WrapBase() = default;
 | 
				
			||||||
			virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
 | 
								virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
 | 
				
			||||||
			virtual constexpr operator bool() const noexcept = 0;
 | 
								virtual constexpr operator bool() const noexcept = 0;
 | 
				
			||||||
 | 
								virtual void free() noexcept = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		struct Wrap: public WrapBase {
 | 
							struct Wrap final: WrapBase {
 | 
				
			||||||
			T *data{};
 | 
								T *data{};
 | 
				
			||||||
			constexpr Wrap(T *pData) noexcept: data(pData) {
 | 
								constexpr Wrap(T *pData) noexcept: data(pData) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -39,16 +43,20 @@ class AnyPtr {
 | 
				
			|||||||
			constexpr operator bool() const noexcept override {
 | 
								constexpr operator bool() const noexcept override {
 | 
				
			||||||
				return data != nullptr;
 | 
									return data != nullptr;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								constexpr void free() noexcept override {
 | 
				
			||||||
 | 
									ox::safeDelete(data);
 | 
				
			||||||
 | 
									data = {};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		WrapBase *m_wrapPtr{};
 | 
							WrapBase *m_wrapPtr{};
 | 
				
			||||||
		ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
 | 
							ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		constexpr AnyPtr() noexcept = default;
 | 
							constexpr AnyPtrT() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		constexpr AnyPtr(T *ptr) noexcept {
 | 
							constexpr AnyPtrT(T *ptr) noexcept {
 | 
				
			||||||
			if (std::is_constant_evaluated()) {
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
				m_wrapPtr = new Wrap(ptr);
 | 
									m_wrapPtr = new Wrap(ptr);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
@@ -56,22 +64,39 @@ class AnyPtr {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr AnyPtr(AnyPtr const&other) noexcept {
 | 
							constexpr AnyPtrT(AnyPtrT const&other) noexcept {
 | 
				
			||||||
			if (other) {
 | 
								if (other) {
 | 
				
			||||||
				m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
 | 
									m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr ~AnyPtr() noexcept {
 | 
							constexpr AnyPtrT(AnyPtrT &&other) noexcept {
 | 
				
			||||||
 | 
								if (other) {
 | 
				
			||||||
 | 
									m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
 | 
									if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
										ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									other.m_wrapPtr = {};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr ~AnyPtrT() noexcept {
 | 
				
			||||||
 | 
								if constexpr(unique) {
 | 
				
			||||||
 | 
									free();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (std::is_constant_evaluated()) {
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
				ox::safeDelete(m_wrapPtr);
 | 
									ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		constexpr AnyPtr &operator=(T *ptr) noexcept {
 | 
							constexpr AnyPtrT &operator=(T *ptr) noexcept {
 | 
				
			||||||
			if (std::is_constant_evaluated()) {
 | 
								if constexpr(unique) {
 | 
				
			||||||
 | 
									free();
 | 
				
			||||||
 | 
								} else if (std::is_constant_evaluated()) {
 | 
				
			||||||
				ox::safeDelete(m_wrapPtr);
 | 
									ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
				m_wrapPtr = new Wrap(ptr);
 | 
									m_wrapPtr = new Wrap(ptr);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
 | 
									m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
 | 
				
			||||||
@@ -79,10 +104,14 @@ class AnyPtr {
 | 
				
			|||||||
			return *this;
 | 
								return *this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr AnyPtr &operator=(AnyPtr const&ptr) noexcept {
 | 
							constexpr AnyPtrT &operator=(AnyPtrT const&ptr) noexcept {
 | 
				
			||||||
			if (this != &ptr) {
 | 
								if (this != &ptr) {
 | 
				
			||||||
				if (ptr) {
 | 
									if constexpr(unique) {
 | 
				
			||||||
 | 
										free();
 | 
				
			||||||
 | 
									} else if (std::is_constant_evaluated()) {
 | 
				
			||||||
					ox::safeDelete(m_wrapPtr);
 | 
										ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (ptr) {
 | 
				
			||||||
					m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
 | 
										m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					m_wrapPtr = nullptr;
 | 
										m_wrapPtr = nullptr;
 | 
				
			||||||
@@ -91,10 +120,40 @@ class AnyPtr {
 | 
				
			|||||||
			return *this;
 | 
								return *this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr AnyPtrT &operator=(AnyPtrT &&ptr) noexcept {
 | 
				
			||||||
 | 
								if (this != &ptr) {
 | 
				
			||||||
 | 
									if constexpr(unique) {
 | 
				
			||||||
 | 
										free();
 | 
				
			||||||
 | 
									} else if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
										ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (ptr) {
 | 
				
			||||||
 | 
										m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
 | 
										if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
											ox::safeDelete(ptr.m_wrapPtr);
 | 
				
			||||||
 | 
											ptr.m_wrapPtr = nullptr;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										m_wrapPtr = nullptr;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return *this;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr operator bool() const noexcept {
 | 
							constexpr operator bool() const noexcept {
 | 
				
			||||||
			return m_wrapPtr && *m_wrapPtr;
 | 
								return m_wrapPtr && *m_wrapPtr;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr void free() noexcept {
 | 
				
			||||||
 | 
								if (m_wrapPtr) {
 | 
				
			||||||
 | 
									m_wrapPtr->free();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
									ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								m_wrapPtr = nullptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr T *get() const noexcept {
 | 
							constexpr T *get() const noexcept {
 | 
				
			||||||
@@ -104,6 +163,12 @@ class AnyPtr {
 | 
				
			|||||||
			return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
 | 
								return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using AnyPtr = detail::AnyPtrT<false>;
 | 
				
			||||||
 | 
					using UAnyPtr = detail::AnyPtrT<true>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -234,7 +234,7 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
 | 
				
			|||||||
		ImGui::BeginChild("SubSheets", {s_palViewWidth - 24, ySize / 2.f}, true);
 | 
							ImGui::BeginChild("SubSheets", {s_palViewWidth - 24, ySize / 2.f}, true);
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			static constexpr auto btnHeight = ig::BtnSz.y;
 | 
								static constexpr auto btnHeight = ig::BtnSz.y;
 | 
				
			||||||
			auto const btnSize = ImVec2{btnHeight, btnHeight};
 | 
								auto constexpr btnSize = ImVec2{btnHeight, btnHeight};
 | 
				
			||||||
			if (ig::PushButton("+", btnSize)) {
 | 
								if (ig::PushButton("+", btnSize)) {
 | 
				
			||||||
				auto insertOnIdx = m_model.activeSubSheetIdx();
 | 
									auto insertOnIdx = m_model.activeSubSheetIdx();
 | 
				
			||||||
				auto const&parent = m_model.activeSubSheet();
 | 
									auto const&parent = m_model.activeSubSheet();
 | 
				
			||||||
@@ -258,16 +258,19 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
 | 
				
			|||||||
				m_exportMenu.show();
 | 
									m_exportMenu.show();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			TileSheet::SubSheetIdx path;
 | 
								TileSheet::SubSheetIdx path;
 | 
				
			||||||
			static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
 | 
								static constexpr auto flags =
 | 
				
			||||||
			if (ImGui::BeginTable("Subsheets", 4, flags)) {
 | 
									ImGuiTableFlags_RowBg |
 | 
				
			||||||
				ImGui::TableSetupColumn("Subsheet", ImGuiTableColumnFlags_NoHide);
 | 
					                ImGuiTableFlags_NoBordersInBody |
 | 
				
			||||||
				ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 25);
 | 
					                ImGuiTableFlags_ScrollY;
 | 
				
			||||||
				ImGui::TableSetupColumn("Columns", ImGuiTableColumnFlags_WidthFixed, 50);
 | 
					            if (ImGui::BeginTable("Subsheets", 4, flags)) {
 | 
				
			||||||
				ImGui::TableSetupColumn("Rows", ImGuiTableColumnFlags_WidthFixed, 50);
 | 
					                ImGui::TableSetupColumn("Subsheet", ImGuiTableColumnFlags_NoHide);
 | 
				
			||||||
				ImGui::TableHeadersRow();
 | 
					                ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 25);
 | 
				
			||||||
				drawSubsheetSelector(m_view.img().subsheet, path);
 | 
					                ImGui::TableSetupColumn("Columns", ImGuiTableColumnFlags_WidthFixed, 50);
 | 
				
			||||||
				ImGui::EndTable();
 | 
					                ImGui::TableSetupColumn("Rows", ImGuiTableColumnFlags_WidthFixed, 50);
 | 
				
			||||||
			}
 | 
					                ImGui::TableHeadersRow();
 | 
				
			||||||
 | 
					                drawSubsheetSelector(m_view.img().subsheet, path);
 | 
				
			||||||
 | 
					                ImGui::EndTable();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ImGui::EndChild();
 | 
							ImGui::EndChild();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -462,8 +465,12 @@ void TileSheetEditorImGui::drawPaletteMenu() noexcept {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// header
 | 
						// header
 | 
				
			||||||
 | 
						auto constexpr palTblFlags =
 | 
				
			||||||
 | 
							ImGuiTableFlags_RowBg |
 | 
				
			||||||
 | 
					        ImGuiTableFlags_SizingStretchProp |
 | 
				
			||||||
 | 
					        ImGuiTableFlags_ScrollY;
 | 
				
			||||||
	if (ImGui::BeginTable(
 | 
						if (ImGui::BeginTable(
 | 
				
			||||||
			"PaletteTable", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) {
 | 
								"PaletteTable", 4, palTblFlags)) {
 | 
				
			||||||
		ImGui::TableSetupColumn("Idx", 0, 0.6f);
 | 
							ImGui::TableSetupColumn("Idx", 0, 0.6f);
 | 
				
			||||||
		ImGui::TableSetupColumn("", 0, 0.22f);
 | 
							ImGui::TableSetupColumn("", 0, 0.22f);
 | 
				
			||||||
		ImGui::TableSetupColumn("Name", 0, 3);
 | 
							ImGui::TableSetupColumn("Name", 0, 3);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,8 @@ class Wrap {
 | 
				
			|||||||
		virtual ox::CStringView typeName() const noexcept = 0;
 | 
							virtual ox::CStringView typeName() const noexcept = 0;
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		virtual int typeVersion() const noexcept = 0;
 | 
							virtual int typeVersion() const noexcept = 0;
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::UAnyPtr moveToCopy() noexcept = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
@@ -27,6 +29,11 @@ class WrapT: public Wrap {
 | 
				
			|||||||
	public:
 | 
						public:
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		virtual constexpr T &obj() noexcept = 0;
 | 
							virtual constexpr T &obj() noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::UAnyPtr moveToCopy() noexcept final {
 | 
				
			||||||
 | 
								return new T{std::move(obj())};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
@@ -184,7 +191,18 @@ ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			|||||||
		auto &src,
 | 
							auto &src,
 | 
				
			||||||
		ox::StringViewCR dstTypeName,
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
		int const dstTypeVersion) noexcept {
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
	return convert(ctx, WrapRef{src}, dstTypeName, dstTypeVersion);
 | 
						WrapRef ref{src};
 | 
				
			||||||
 | 
						return convert(ctx, static_cast<Wrap&>(ref), dstTypeName, dstTypeVersion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
 | 
							keel::Context &ctx,
 | 
				
			||||||
 | 
							auto const&src,
 | 
				
			||||||
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
 | 
						auto srcCpy = src;
 | 
				
			||||||
 | 
						WrapRef ref{srcCpy};
 | 
				
			||||||
 | 
						return convert(ctx, ref, dstTypeName, dstTypeVersion);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename DstType>
 | 
					template<typename DstType>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ namespace studio {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
NewMenu::NewMenu() noexcept {
 | 
					NewMenu::NewMenu() noexcept {
 | 
				
			||||||
	setTitle("New Item");
 | 
						setTitle("New Item");
 | 
				
			||||||
	setSize({230, 140});
 | 
						setSize({280, 180});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::open() noexcept {
 | 
					void NewMenu::open() noexcept {
 | 
				
			||||||
@@ -33,7 +33,7 @@ bool NewMenu::isOpen() const noexcept {
 | 
				
			|||||||
	return m_open;
 | 
						return m_open;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::draw(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::draw(StudioContext &sctx) noexcept {
 | 
				
			||||||
	switch (m_stage) {
 | 
						switch (m_stage) {
 | 
				
			||||||
		case Stage::Opening:
 | 
							case Stage::Opening:
 | 
				
			||||||
			ImGui::OpenPopup(title().c_str());
 | 
								ImGui::OpenPopup(title().c_str());
 | 
				
			||||||
@@ -46,51 +46,73 @@ void NewMenu::draw(studio::StudioContext &sctx) noexcept {
 | 
				
			|||||||
		case Stage::NewItemName:
 | 
							case Stage::NewItemName:
 | 
				
			||||||
			drawNewItemName(sctx);
 | 
								drawNewItemName(sctx);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case Stage::NewItemTemplate:
 | 
				
			||||||
 | 
								drawNewItemTemplate(sctx);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case Stage::Closed:
 | 
							case Stage::Closed:
 | 
				
			||||||
			m_open = false;
 | 
								m_open = false;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::addItemMaker(ox::UniquePtr<studio::ItemMaker> &&im) noexcept {
 | 
					void NewMenu::addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept {
 | 
				
			||||||
	m_types.emplace_back(std::move(im));
 | 
						m_types.emplace_back(std::move(im));
 | 
				
			||||||
	std::sort(
 | 
						std::sort(
 | 
				
			||||||
			m_types.begin(), m_types.end(),
 | 
								m_types.begin(), m_types.end(),
 | 
				
			||||||
			[](ox::UPtr<ItemMaker> const&im1, ox::UPtr<ItemMaker> const&im2) {
 | 
								[](ox::UPtr<ItemMaker> const&im1, ox::UPtr<ItemMaker> const&im2) {
 | 
				
			||||||
				 return im1->typeName < im2->typeName;
 | 
									 return im1->typeDisplayName() < im2->typeDisplayName();
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawNewItemType(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept {
 | 
				
			||||||
	drawWindow(sctx.tctx, &m_open, [this] {
 | 
						for (auto const&im : m_types) {
 | 
				
			||||||
		auto const allocSz = m_types.size() * sizeof(char const*);
 | 
							if (im->installTemplate(tmplt)) {
 | 
				
			||||||
		auto mem = ox_malloca(allocSz, char const*, nullptr);
 | 
								break;
 | 
				
			||||||
		auto items = ox::Span{mem.get(), allocSz};
 | 
					 | 
				
			||||||
		for (auto i = 0u; auto const&im : m_types) {
 | 
					 | 
				
			||||||
			items[i] = im->typeName.c_str();
 | 
					 | 
				
			||||||
			++i;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ImGui::ListBox("Item Type", &m_selectedType, items.data(), static_cast<int>(m_types.size()));
 | 
						}
 | 
				
			||||||
		drawFirstPageButtons();
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NewMenu::drawNewItemType(StudioContext const&sctx) noexcept {
 | 
				
			||||||
 | 
						drawWindow(sctx.tctx, m_open, [this] {
 | 
				
			||||||
 | 
							ig::ListBox("Item Type", [&](size_t const i) -> ox::CStringView {
 | 
				
			||||||
 | 
								return m_types[i]->typeDisplayName();
 | 
				
			||||||
 | 
							}, m_types.size(), m_selectedType, {200, 100});
 | 
				
			||||||
 | 
							auto const&im = *m_types[m_selectedType];
 | 
				
			||||||
 | 
							drawFirstPageButtons(im.itemTemplates().size() == 1 ?
 | 
				
			||||||
 | 
								Stage::NewItemName : Stage::NewItemTemplate);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawNewItemName(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::drawNewItemTemplate(StudioContext &sctx) noexcept {
 | 
				
			||||||
	drawWindow(sctx.tctx, &m_open, [this, &sctx] {
 | 
						drawWindow(sctx.tctx, m_open, [this] {
 | 
				
			||||||
		auto const typeIdx = static_cast<std::size_t>(m_selectedType);
 | 
							auto const&templates =
 | 
				
			||||||
		if (typeIdx < m_types.size()) {
 | 
								m_types[m_selectedType]->itemTemplates();
 | 
				
			||||||
 | 
							ig::ListBox("Template", [&](size_t const i) -> ox::CStringView {
 | 
				
			||||||
 | 
								return templates[i]->name();
 | 
				
			||||||
 | 
							}, templates.size(), m_selectedTemplate, {200, 100});
 | 
				
			||||||
 | 
							drawButtons(Stage::NewItemType, Stage::NewItemName);
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NewMenu::drawNewItemName(StudioContext &sctx) noexcept {
 | 
				
			||||||
 | 
						drawWindow(sctx.tctx, m_open, [this, &sctx] {
 | 
				
			||||||
 | 
							if (m_selectedType < m_types.size()) {
 | 
				
			||||||
			ig::InputText("Name", m_itemName);
 | 
								ig::InputText("Name", m_itemName);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		drawLastPageButtons(sctx);
 | 
							drawLastPageButtons(sctx);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawFirstPageButtons() noexcept {
 | 
					void NewMenu::drawButtons(Stage const prev, Stage const next) noexcept {
 | 
				
			||||||
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130);
 | 
						ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198);
 | 
				
			||||||
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
						ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
				
			||||||
	auto const btnSz = ImVec2(60, 20);
 | 
						constexpr ImVec2 btnSz{60, 20};
 | 
				
			||||||
 | 
						if (ImGui::Button("Back", btnSz)) {
 | 
				
			||||||
 | 
							m_stage = prev;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ImGui::SameLine();
 | 
				
			||||||
	if (ImGui::Button("Next", btnSz)) {
 | 
						if (ImGui::Button("Next", btnSz)) {
 | 
				
			||||||
		m_stage = Stage::NewItemName;
 | 
							m_stage = next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ImGui::SameLine();
 | 
						ImGui::SameLine();
 | 
				
			||||||
	if (ImGui::Button("Cancel", btnSz)) {
 | 
						if (ImGui::Button("Cancel", btnSz)) {
 | 
				
			||||||
@@ -99,34 +121,50 @@ void NewMenu::drawFirstPageButtons() noexcept {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawLastPageButtons(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::drawFirstPageButtons(Stage const next) noexcept {
 | 
				
			||||||
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 138);
 | 
						ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130);
 | 
				
			||||||
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
						ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
				
			||||||
	if (ImGui::Button("Back")) {
 | 
						constexpr ImVec2 btnSz{60, 20};
 | 
				
			||||||
		m_stage = Stage::NewItemType;
 | 
						if (ImGui::Button("Next", btnSz)) {
 | 
				
			||||||
 | 
							m_stage = next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ImGui::SameLine();
 | 
						ImGui::SameLine();
 | 
				
			||||||
	if (ImGui::Button("Finish")) {
 | 
						if (ImGui::Button("Cancel", btnSz)) {
 | 
				
			||||||
		finish(sctx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ImGui::SameLine();
 | 
					 | 
				
			||||||
	if (ImGui::Button("Quit")) {
 | 
					 | 
				
			||||||
		ImGui::CloseCurrentPopup();
 | 
							ImGui::CloseCurrentPopup();
 | 
				
			||||||
		m_stage = Stage::Closed;
 | 
							m_stage = Stage::Closed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::finish(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::drawLastPageButtons(StudioContext &sctx) noexcept {
 | 
				
			||||||
 | 
						ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198);
 | 
				
			||||||
 | 
						ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
				
			||||||
 | 
						constexpr ImVec2 btnSz{60, 20};
 | 
				
			||||||
 | 
						if (ImGui::Button("Back", btnSz)) {
 | 
				
			||||||
 | 
							m_stage = Stage::NewItemType;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ImGui::SameLine();
 | 
				
			||||||
 | 
						if (ImGui::Button("Finish", btnSz)) {
 | 
				
			||||||
 | 
							finish(sctx);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ImGui::SameLine();
 | 
				
			||||||
 | 
						if (ImGui::Button("Quit", btnSz)) {
 | 
				
			||||||
 | 
							ImGui::CloseCurrentPopup();
 | 
				
			||||||
 | 
							m_stage = Stage::Closed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NewMenu::finish(StudioContext &sctx) noexcept {
 | 
				
			||||||
	if (m_itemName.len() == 0) {
 | 
						if (m_itemName.len() == 0) {
 | 
				
			||||||
		oxLogError(ox::Error(1, "New file error: no file name"));
 | 
							oxLogError(ox::Error{1, "New file error: no file name"});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	auto const&typeMaker = *m_types[static_cast<std::size_t>(m_selectedType)];
 | 
						auto const&im = *m_types[static_cast<std::size_t>(m_selectedType)];
 | 
				
			||||||
	if (sctx.project->exists(typeMaker.itemPath(m_itemName))) {
 | 
						if (sctx.project->exists(im.itemPath(m_itemName))) {
 | 
				
			||||||
		oxLogError(ox::Error(1, "New file error: file already exists"));
 | 
							oxLogError(ox::Error{1, "New file error: file already exists"});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	auto const [path, err] = typeMaker.write(sctx, m_itemName);
 | 
						auto const [path, err] =
 | 
				
			||||||
 | 
							im.write(sctx, m_itemName, m_selectedTemplate);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		oxLogError(err);
 | 
							oxLogError(err);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,13 +13,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NewMenu: public studio::Popup {
 | 
					class NewMenu final: public Popup {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		enum class Stage {
 | 
							enum class Stage {
 | 
				
			||||||
			Closed,
 | 
								Closed,
 | 
				
			||||||
			Opening,
 | 
								Opening,
 | 
				
			||||||
			NewItemType,
 | 
								NewItemType,
 | 
				
			||||||
			NewItemName,
 | 
								NewItemName,
 | 
				
			||||||
 | 
								NewItemTemplate,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// emits path parameter
 | 
							// emits path parameter
 | 
				
			||||||
@@ -29,8 +30,9 @@ class NewMenu: public studio::Popup {
 | 
				
			|||||||
		Stage m_stage = Stage::Closed;
 | 
							Stage m_stage = Stage::Closed;
 | 
				
			||||||
		ox::String m_typeName;
 | 
							ox::String m_typeName;
 | 
				
			||||||
		ox::IString<255> m_itemName;
 | 
							ox::IString<255> m_itemName;
 | 
				
			||||||
		ox::Vector<ox::UniquePtr<studio::ItemMaker>> m_types;
 | 
							ox::Vector<ox::UPtr<studio::ItemMaker>> m_types;
 | 
				
			||||||
		int m_selectedType = 0;
 | 
							size_t m_selectedType = 0;
 | 
				
			||||||
 | 
							size_t m_selectedTemplate = 0;
 | 
				
			||||||
		bool m_open = false;
 | 
							bool m_open = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
@@ -43,37 +45,70 @@ class NewMenu: public studio::Popup {
 | 
				
			|||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		bool isOpen() const noexcept override;
 | 
							bool isOpen() const noexcept override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void draw(studio::StudioContext &sctx) noexcept override;
 | 
							void draw(StudioContext &sctx) noexcept override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
							void addItemType(
 | 
				
			||||||
 | 
								ox::StringParam displayName,
 | 
				
			||||||
 | 
								ox::StringParam parentDir,
 | 
				
			||||||
 | 
								ox::StringParam fileExt,
 | 
				
			||||||
 | 
								T itemTempl,
 | 
				
			||||||
 | 
								ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
							void addItemType(
 | 
				
			||||||
 | 
								ox::StringParam displayName,
 | 
				
			||||||
 | 
								ox::StringParam parentDir,
 | 
				
			||||||
 | 
								ox::StringParam fileExt,
 | 
				
			||||||
 | 
								ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void addItemMaker(ox::UniquePtr<studio::ItemMaker> &&im) noexcept;
 | 
							void addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		void drawNewItemType(studio::StudioContext &sctx) noexcept;
 | 
							void drawNewItemType(StudioContext const&sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawNewItemName(studio::StudioContext &sctx) noexcept;
 | 
							void drawNewItemName(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawFirstPageButtons() noexcept;
 | 
							void drawNewItemTemplate(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawLastPageButtons(studio::StudioContext &sctx) noexcept;
 | 
							void drawButtons(Stage prev, Stage next) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void finish(studio::StudioContext &sctx) noexcept;
 | 
							void drawFirstPageButtons(Stage next) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void drawLastPageButtons(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void finish(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt) noexcept {
 | 
					void NewMenu::addItemType(
 | 
				
			||||||
	m_types.emplace_back(ox::make<studio::ItemMakerT<T>>(std::move(displayName), std::move(parentDir), std::move(fileExt), std::move(itemTempl), pFmt));
 | 
						ox::StringParam displayName,
 | 
				
			||||||
 | 
						ox::StringParam parentDir,
 | 
				
			||||||
 | 
						ox::StringParam fileExt,
 | 
				
			||||||
 | 
						T itemTempl,
 | 
				
			||||||
 | 
						ox::ClawFormat const pFmt) noexcept {
 | 
				
			||||||
 | 
						m_types.emplace_back(ox::make<ItemMakerT<T>>(
 | 
				
			||||||
 | 
							std::move(displayName),
 | 
				
			||||||
 | 
							std::move(parentDir),
 | 
				
			||||||
 | 
							std::move(fileExt),
 | 
				
			||||||
 | 
							std::move(itemTempl),
 | 
				
			||||||
 | 
							pFmt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt) noexcept {
 | 
					void NewMenu::addItemType(
 | 
				
			||||||
	m_types.emplace_back(ox::make<studio::ItemMakerT<T>>(std::move(displayName), std::move(parentDir), std::move(fileExt), pFmt));
 | 
						ox::StringParam displayName,
 | 
				
			||||||
 | 
						ox::StringParam parentDir,
 | 
				
			||||||
 | 
						ox::StringParam fileExt,
 | 
				
			||||||
 | 
						ox::ClawFormat const pFmt) noexcept {
 | 
				
			||||||
 | 
						m_types.emplace_back(ox::make<ItemMakerT<T>>(
 | 
				
			||||||
 | 
							std::move(displayName),
 | 
				
			||||||
 | 
							std::move(parentDir),
 | 
				
			||||||
 | 
							std::move(fileExt),
 | 
				
			||||||
 | 
							pFmt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@ void NewProject::draw(studio::StudioContext &ctx) noexcept {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewProject::drawNewProjectName(studio::StudioContext &sctx) noexcept {
 | 
					void NewProject::drawNewProjectName(studio::StudioContext &sctx) noexcept {
 | 
				
			||||||
	drawWindow(sctx.tctx, &m_open, [this, &sctx] {
 | 
						drawWindow(sctx.tctx, m_open, [this, &sctx] {
 | 
				
			||||||
		ig::InputText("Name", m_projectName);
 | 
							ig::InputText("Name", m_projectName);
 | 
				
			||||||
		ImGui::Text("Path: %s", m_projectPath.c_str());
 | 
							ImGui::Text("Path: %s", m_projectPath.c_str());
 | 
				
			||||||
		if (ImGui::Button("Browse")) {
 | 
							if (ImGui::Button("Browse")) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -251,6 +251,10 @@ void StudioUI::loadModule(Module const&mod) noexcept {
 | 
				
			|||||||
	for (auto &im : mod.itemMakers(m_sctx)) {
 | 
						for (auto &im : mod.itemMakers(m_sctx)) {
 | 
				
			||||||
		m_newMenu.addItemMaker(std::move(im));
 | 
							m_newMenu.addItemMaker(std::move(im));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						auto tmplts = mod.itemTemplates(m_sctx);
 | 
				
			||||||
 | 
						for (auto &t : tmplts) {
 | 
				
			||||||
 | 
							m_newMenu.installItemTemplate(t);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::loadModules() noexcept {
 | 
					void StudioUI::loadModules() noexcept {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -214,7 +214,8 @@ bool ListBox(
 | 
				
			|||||||
		ox::CStringViewCR name,
 | 
							ox::CStringViewCR name,
 | 
				
			||||||
		std::function<ox::CStringView(size_t)> const&f,
 | 
							std::function<ox::CStringView(size_t)> const&f,
 | 
				
			||||||
		size_t strCnt,
 | 
							size_t strCnt,
 | 
				
			||||||
		size_t &selIdx) noexcept;
 | 
							size_t &selIdx,
 | 
				
			||||||
 | 
							ImVec2 const&sz = {0, 0}) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ox/claw/claw.hpp>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ox/model/typenamecatcher.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <keel/media.hpp>
 | 
					#include <keel/media.hpp>
 | 
				
			||||||
#include <turbine/context.hpp>
 | 
					#include <turbine/context.hpp>
 | 
				
			||||||
@@ -13,75 +15,212 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ItemMaker {
 | 
					class ItemTemplate {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							ox::String const m_name{"Default"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		ox::String const typeName;
 | 
							explicit ItemTemplate() noexcept = default;
 | 
				
			||||||
		ox::String const parentDir;
 | 
					
 | 
				
			||||||
		ox::String const fileExt;
 | 
							explicit ItemTemplate(ox::StringParam name) noexcept: m_name{std::move(name)} {}
 | 
				
			||||||
		constexpr explicit ItemMaker(
 | 
					
 | 
				
			||||||
 | 
							virtual ~ItemTemplate() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							constexpr ox::String const&name() const noexcept {
 | 
				
			||||||
 | 
								return m_name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr bool operator<=>(ItemTemplate const&other) const noexcept {
 | 
				
			||||||
 | 
								return m_name != other.name() ? (m_name < other.name() ? -1 : 1) : 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							ox::CStringView displayName() const noexcept {
 | 
				
			||||||
 | 
								return m_name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::CStringView typeName() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual int typeVersion() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual ox::Result<ox::UAnyPtr> getItem(
 | 
				
			||||||
 | 
								keel::Context &ctx, ox::StringViewCR name, int version) noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					class ItemTemplateT: public ItemTemplate {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							T const m_item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							constexpr ItemTemplateT() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							explicit ItemTemplateT(ox::StringParam name, T item) noexcept:
 | 
				
			||||||
 | 
								ItemTemplate{std::move(name)}, m_item{std::move(item)} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							ox::CStringView typeName() const noexcept final {
 | 
				
			||||||
 | 
								return ox::ModelTypeName_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							int typeVersion() const noexcept final {
 | 
				
			||||||
 | 
								return ox::ModelTypeVersion_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::Result<ox::UAnyPtr> getItem(
 | 
				
			||||||
 | 
									keel::Context &kctx, ox::StringViewCR name, int const version) noexcept final {
 | 
				
			||||||
 | 
								if (ox::ModelTypeVersion_v<T> != version || ox::ModelTypeName_v<T> != name) {
 | 
				
			||||||
 | 
									OX_REQUIRE_M(item, keel::convert(kctx, m_item, name, version));
 | 
				
			||||||
 | 
									auto out = ox::Result<ox::UAnyPtr>{item->moveToCopy()};
 | 
				
			||||||
 | 
									ox::safeDelete(item.release());
 | 
				
			||||||
 | 
									return out;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ox::UAnyPtr{new T{m_item}};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ItemMaker {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							ox::Vector<ox::UPtr<ItemTemplate>> m_templates;
 | 
				
			||||||
 | 
							ox::String const m_parentDir;
 | 
				
			||||||
 | 
							ox::String const m_fileExt;
 | 
				
			||||||
 | 
							ox::String const m_typeDisplayName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							constexpr ItemMaker(
 | 
				
			||||||
				ox::StringParam pName,
 | 
									ox::StringParam pName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam pFileExt) noexcept:
 | 
									ox::StringParam pFileExt) noexcept:
 | 
				
			||||||
			typeName{std::move(pName)},
 | 
								m_parentDir{std::move(pParentDir)},
 | 
				
			||||||
			parentDir{std::move(pParentDir)},
 | 
								m_fileExt{std::move(pFileExt)},
 | 
				
			||||||
			fileExt{std::move(pFileExt)} {
 | 
								m_typeDisplayName{std::move(pName)} {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual ~ItemMaker() noexcept = default;
 | 
							virtual ~ItemMaker() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		virtual ox::String itemPath(ox::StringView pName) const noexcept {
 | 
							ox::String const&typeDisplayName() const noexcept {
 | 
				
			||||||
			return ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
 | 
								return m_typeDisplayName;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool installTemplate(ox::UPtr<ItemTemplate> &tmpl) {
 | 
				
			||||||
 | 
								if (typeName() == tmpl->typeName() &&
 | 
				
			||||||
 | 
								    typeVersion() <= tmpl->typeVersion()) {
 | 
				
			||||||
 | 
					                m_templates.emplace_back(std::move(tmpl));
 | 
				
			||||||
 | 
									// begin() + 1 because 'Default' should always be first
 | 
				
			||||||
 | 
					                std::sort(m_templates.begin() + 1, m_templates.end());
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool installTemplate(ox::UPtr<ItemTemplate> &&tmpl) {
 | 
				
			||||||
 | 
								return installTemplate(tmpl);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr ox::Vector<ox::UPtr<ItemTemplate>> const&itemTemplates() const noexcept {
 | 
				
			||||||
 | 
								return m_templates;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							ox::String itemPath(ox::StringViewCR pName) const noexcept {
 | 
				
			||||||
 | 
								return ox::sfmt("/{}/{}.{}", m_parentDir, pName, m_fileExt);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::StringView typeName() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual int typeVersion() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * Returns path of the file created.
 | 
							 * Returns path of the file created.
 | 
				
			||||||
		 * @param ctx
 | 
							 * @param ctx
 | 
				
			||||||
		 * @param pName
 | 
							 * @param pName
 | 
				
			||||||
 | 
							 * @param pTemplateIdx
 | 
				
			||||||
		 * @return path of file or error in Result
 | 
							 * @return path of file or error in Result
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		virtual ox::Result<ox::String> write(StudioContext &ctx, ox::StringView pName) const noexcept = 0;
 | 
							virtual ox::Result<ox::String> write(
 | 
				
			||||||
 | 
								StudioContext &ctx, ox::StringViewCR pName, size_t pTemplateIdx) const noexcept = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
class ItemMakerT: public ItemMaker {
 | 
					class ItemMakerT final: public ItemMaker {
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		T const m_item;
 | 
					 | 
				
			||||||
		ox::ClawFormat const m_fmt;
 | 
							ox::ClawFormat const m_fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		constexpr ItemMakerT(
 | 
							constexpr ItemMakerT(
 | 
				
			||||||
				ox::StringParam pDisplayName,
 | 
									ox::StringParam pDisplayName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam fileExt,
 | 
									ox::StringParam fileExt,
 | 
				
			||||||
				ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept:
 | 
									ox::ClawFormat const pFmt = ox::ClawFormat::Metal) noexcept:
 | 
				
			||||||
			ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
 | 
									ItemMaker(
 | 
				
			||||||
			m_fmt(pFmt) {
 | 
										std::move(pDisplayName),
 | 
				
			||||||
 | 
										std::move(pParentDir),
 | 
				
			||||||
 | 
										std::move(fileExt)),
 | 
				
			||||||
 | 
									m_fmt{pFmt} {
 | 
				
			||||||
 | 
								installTemplate(ox::make_unique<ItemTemplateT<T>>());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr ItemMakerT(
 | 
							constexpr ItemMakerT(
 | 
				
			||||||
				ox::StringParam pDisplayName,
 | 
									ox::StringParam pDisplayName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam fileExt,
 | 
									ox::StringParam fileExt,
 | 
				
			||||||
				T pItem,
 | 
									T const&pItem,
 | 
				
			||||||
				ox::ClawFormat pFmt) noexcept:
 | 
									ox::ClawFormat const pFmt) noexcept:
 | 
				
			||||||
			ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
 | 
									ItemMaker(
 | 
				
			||||||
			m_item(std::move(pItem)),
 | 
										std::move(pDisplayName),
 | 
				
			||||||
			m_fmt(pFmt) {
 | 
										std::move(pParentDir),
 | 
				
			||||||
 | 
										std::move(fileExt)),
 | 
				
			||||||
 | 
									m_fmt{pFmt} {
 | 
				
			||||||
 | 
								installTemplate(ox::make_unique<ItemTemplateT<T>>(std::move(pItem)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr ItemMakerT(
 | 
							constexpr ItemMakerT(
 | 
				
			||||||
				ox::StringParam pDisplayName,
 | 
									ox::StringParam pDisplayName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam fileExt,
 | 
									ox::StringParam fileExt,
 | 
				
			||||||
				T &&pItem,
 | 
									T &&pItem,
 | 
				
			||||||
				ox::ClawFormat pFmt) noexcept:
 | 
									ox::ClawFormat const pFmt) noexcept:
 | 
				
			||||||
			ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
 | 
									ItemMaker(
 | 
				
			||||||
			m_item(std::move(pItem)),
 | 
										std::move(pDisplayName),
 | 
				
			||||||
			m_fmt(pFmt) {
 | 
										std::move(pParentDir),
 | 
				
			||||||
 | 
										std::move(fileExt)),
 | 
				
			||||||
 | 
									m_fmt{pFmt} {
 | 
				
			||||||
 | 
								installTemplate(ox::make_unique<ItemTemplateT<T>>(std::move(pItem)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ox::Result<ox::String> write(studio::StudioContext &sctx, ox::StringView const pName) const noexcept override {
 | 
					
 | 
				
			||||||
 | 
							ox::StringView typeName() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeName_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int typeVersion() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeVersion_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::Result<ox::String> write(
 | 
				
			||||||
 | 
								StudioContext &sctx,
 | 
				
			||||||
 | 
								ox::StringViewCR pName,
 | 
				
			||||||
 | 
								size_t const pTemplateIdx) const noexcept override {
 | 
				
			||||||
			auto const path = itemPath(pName);
 | 
								auto const path = itemPath(pName);
 | 
				
			||||||
			createUuidMapping(keelCtx(sctx.tctx), path, ox::UUID::generate().unwrap());
 | 
								createUuidMapping(keelCtx(sctx.tctx), path, ox::UUID::generate().unwrap());
 | 
				
			||||||
			OX_RETURN_ERROR(sctx.project->writeObj(path, m_item, m_fmt));
 | 
								auto const&templates = itemTemplates();
 | 
				
			||||||
 | 
								auto const tmplIdx = pTemplateIdx < templates.size() ? pTemplateIdx : 0;
 | 
				
			||||||
 | 
								OX_REQUIRE_M(tmpl, templates[tmplIdx]->getItem(
 | 
				
			||||||
 | 
									keelCtx(sctx), typeName(), typeVersion()));
 | 
				
			||||||
 | 
								auto item = tmpl.template get<T>();
 | 
				
			||||||
 | 
								OX_RETURN_ERROR(sctx.project->writeObj(path, *item, m_fmt));
 | 
				
			||||||
 | 
								tmpl.free();
 | 
				
			||||||
			return path;
 | 
								return path;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ class Module {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(studio::StudioContext&) const;
 | 
							virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(studio::StudioContext&) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual ox::Vector<ox::UPtr<ItemTemplate>> itemTemplates(studio::StudioContext&) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Editor>
 | 
					template<typename Editor>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ class Popup {
 | 
				
			|||||||
			return m_title;
 | 
								return m_title;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents);
 | 
							void drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const&drawContents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,11 +136,12 @@ bool FileComboBox(
 | 
				
			|||||||
bool ListBox(
 | 
					bool ListBox(
 | 
				
			||||||
		ox::CStringViewCR name,
 | 
							ox::CStringViewCR name,
 | 
				
			||||||
		std::function<ox::CStringView(size_t)> const&f,
 | 
							std::function<ox::CStringView(size_t)> const&f,
 | 
				
			||||||
		size_t strCnt,
 | 
							size_t const strCnt,
 | 
				
			||||||
		size_t &selIdx) noexcept {
 | 
							size_t &selIdx,
 | 
				
			||||||
 | 
							ImVec2 const&sz) noexcept {
 | 
				
			||||||
	auto out = false;
 | 
						auto out = false;
 | 
				
			||||||
	if (ImGui::BeginListBox(name.c_str())) {
 | 
						if (ImGui::BeginListBox(name.c_str(), sz)) {
 | 
				
			||||||
		for (auto i = 0u; i < strCnt; ++i) {
 | 
							for (size_t i = 0; i < strCnt; ++i) {
 | 
				
			||||||
			auto str = f(i);
 | 
								auto str = f(i);
 | 
				
			||||||
			ig::IDStackItem const idStackItem2(static_cast<int>(i));
 | 
								ig::IDStackItem const idStackItem2(static_cast<int>(i));
 | 
				
			||||||
			if (ImGui::Selectable(str.c_str(), selIdx == i)) {
 | 
								if (ImGui::Selectable(str.c_str(), selIdx == i)) {
 | 
				
			||||||
@@ -161,6 +162,12 @@ bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const&list, size_t
 | 
				
			|||||||
	}, list.size(), selIdx);
 | 
						}, list.size(), selIdx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FilePicker::FilePicker(
 | 
					FilePicker::FilePicker(
 | 
				
			||||||
		StudioContext &sctx,
 | 
							StudioContext &sctx,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Vector<EditorMaker> Module::editors(studio::StudioContext&) const {
 | 
					ox::Vector<EditorMaker> Module::editors(StudioContext&) const {
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Vector<ox::UPtr<ItemMaker>> Module::itemMakers(studio::StudioContext&) const {
 | 
					ox::Vector<ox::UPtr<ItemMaker>> Module::itemMakers(StudioContext&) const {
 | 
				
			||||||
 | 
						return {};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Vector<ox::UPtr<ItemTemplate>> Module::itemTemplates(StudioContext&) const {
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,11 +7,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Popup::drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents) {
 | 
					void Popup::drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const&drawContents) {
 | 
				
			||||||
	studio::ig::centerNextWindow(ctx);
 | 
						studio::ig::centerNextWindow(ctx);
 | 
				
			||||||
	ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
 | 
						ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
 | 
				
			||||||
	constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
 | 
						constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
 | 
				
			||||||
	if (ImGui::BeginPopupModal(m_title.c_str(), open, modalFlags)) {
 | 
						if (ImGui::BeginPopupModal(m_title.c_str(), &open, modalFlags)) {
 | 
				
			||||||
		drawContents();
 | 
							drawContents();
 | 
				
			||||||
		ImGui::EndPopup();
 | 
							ImGui::EndPopup();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user