| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -12,33 +12,64 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				namespace nostalgia::core {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				template<bool alpha = false>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ox::Error toPngFile(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ox::CStringView const&path, TileSheet::SubSheet const&s, Palette const&pal, int8_t bpp) noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ox::Vector<uint8_t> pixels;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					s.readPixelsTo(&pixels, bpp);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const unsigned rows = s.rows == -1 ?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							static_cast<unsigned>(pixels.size()) / PixelsPerTile : static_cast<unsigned>(s.rows);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const unsigned cols = s.columns == -1 ? 1 : static_cast<unsigned>(s.columns);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const auto width = cols * TileWidth;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const auto height = rows * TileHeight;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					constexpr auto bytesPerPixel = alpha ? 4 : 3;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ox::Vector<unsigned char> outData(pixels.size() * bytesPerPixel);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (auto idx = 0; const auto colorIdx : pixels) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const auto pt = idxToPt(idx, static_cast<int>(cols));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const auto i = static_cast<unsigned>(pt.y * static_cast<int>(width) + pt.x) * bytesPerPixel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const auto c = pal.colors[colorIdx];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						outData[i + 0] = red32(c);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						outData[i + 1] = green32(c);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						outData[i + 2] = blue32(c);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if constexpr(alpha) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							outData[i + 3] = colorIdx ? 255 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static ox::Vector<uint32_t> normalizePixelSizes(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ox::Vector<uint8_t> const&inPixels,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						int const bpp) noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					uint_t const bytesPerTile = bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ox::Vector<uint32_t> outPixels;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (bytesPerTile == 64) { // 8 BPP
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						outPixels.resize(inPixels.size());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for (std::size_t i = 0; i < inPixels.size(); ++i) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							outPixels[i] = inPixels[i];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						++idx;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					} else { // 4 BPP
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						outPixels.resize(inPixels.size() * 2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for (std::size_t i = 0; i < inPixels.size(); ++i) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							outPixels[i * 2 + 0] = inPixels[i] & 0xF;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							outPixels[i * 2 + 1] = inPixels[i] >> 4;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					constexpr auto fmt = alpha ? LCT_RGBA : LCT_RGB;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return outPixels;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static ox::Vector<uint32_t> normalizePixelArrangement(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ox::Vector<uint32_t> const&inPixels,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						int cols,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						int scale) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const scalePt = ox::Point{scale, scale};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const width = cols * TileWidth;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const height = static_cast<int>(inPixels.size()) / width;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const dstWidth = width * scale;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ox::Vector<uint32_t> outPixels(static_cast<size_t>((width * scale) * (height * scale)));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (std::size_t dstIdx = 0; dstIdx < outPixels.size(); ++dstIdx) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						auto const dstPt = ox::Point{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							static_cast<int>(dstIdx) % dstWidth,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							static_cast<int>(dstIdx) / dstWidth};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						auto const srcPt = dstPt / scalePt;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						auto const srcIdx = ptToIdx(srcPt, cols);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						outPixels[dstIdx] = inPixels[srcIdx];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return outPixels;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static ox::Error toPngFile(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ox::CStringView const&path,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ox::Vector<uint32_t> &&pixels,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Palette const&pal,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						unsigned width,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						unsigned height) noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (auto &c : pixels) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						c = color32(pal.color(c)) | static_cast<Color32>(0XFF << 24);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					constexpr auto fmt = LCT_RGBA;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return OxError(static_cast<ox::ErrorCode>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							lodepng_encode_file(path.c_str(), outData.data(), width, height, fmt, 8)));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							lodepng_encode_file(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									path.c_str(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									reinterpret_cast<uint8_t const*>(pixels.data()),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									width,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									height,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									fmt,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									8)));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				TileSheetEditorImGui::TileSheetEditorImGui(turbine::Context &ctx, ox::CRStringView path):
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -50,11 +81,12 @@ TileSheetEditorImGui::TileSheetEditorImGui(turbine::Context &ctx, ox::CRStringVi
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// connect signal/slots
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					undoStack()->changeTriggered.connect(this, &TileSheetEditorImGui::markUnsavedChanges);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_subsheetEditor.inputSubmitted.connect(this, &TileSheetEditorImGui::updateActiveSubsheet);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_exportMenu.inputSubmitted.connect(this, &TileSheetEditorImGui::exportSubhseetToPng);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_model.paletteChanged.connect(this, &TileSheetEditorImGui::setPaletteSelection);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::exportFile() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					exportSubhseetToPng();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_exportMenu.show();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::cut() {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -75,6 +107,7 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (key == turbine::Key::Escape) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						m_subsheetEditor.close();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						m_exportMenu.close();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto pal = m_model.pal();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (pal) {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -168,7 +201,7 @@ void TileSheetEditorImGui::draw(turbine::Context&) noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::SameLine();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (ImGui::Button("Export", ImVec2(51, btnHeight))) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								exportSubhseetToPng();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								m_exportMenu.show();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							TileSheet::SubSheetIdx path;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -185,6 +218,7 @@ void TileSheetEditorImGui::draw(turbine::Context&) noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ImGui::EndChild();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_subsheetEditor.draw();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_exportMenu.draw();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::drawSubsheetSelector(TileSheet::SubSheet *subsheet, TileSheet::SubSheetIdx *path) {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -244,26 +278,33 @@ ox::Error TileSheetEditorImGui::saveItem() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::showSubsheetEditor() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const auto sheet = m_model.activeSubSheet();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (sheet->subsheets.size()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (!sheet->subsheets.empty()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						m_subsheetEditor.show(sheet->name, -1, -1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					} else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						m_subsheetEditor.show(sheet->name, sheet->columns, sheet->rows);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::exportSubhseetToPng() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto [path, err] = studio::saveFile({{"PNG", "png"}});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (err) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				ox::Error TileSheetEditorImGui::exportSubhseetToPng(int scale) noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					oxRequire(path, studio::saveFile({{"PNG", "png"}}));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// subsheet to png
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const auto &img = m_model.img();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const auto &s = *m_model.activeSubSheet();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const auto &pal = m_model.pal();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					err = toPngFile(path, s, *pal, img.bpp);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const&img = m_model.img();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const&s = *m_model.activeSubSheet();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const&pal = m_model.pal();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const width = s.columns * TileWidth;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const height = s.rows * TileHeight;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto pixels = normalizePixelSizes(s.pixels, img.bpp);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					pixels = normalizePixelArrangement(pixels, s.columns, scale);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					auto const err = toPngFile(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							path,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							std::move(pixels),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							*pal,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							static_cast<unsigned>(width * scale),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							static_cast<unsigned>(height * scale));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (err) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						oxErrorf("Tilesheet export failed: {}", toStr(err));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return err;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -420,13 +461,13 @@ void TileSheetEditorImGui::SubSheetEditor::draw() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::InputInt("Columns", &m_cols);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::InputInt("Rows", &m_rows);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ImGui::Button("OK")) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ImGui::Button("OK", ImVec2{50, 20})) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::CloseCurrentPopup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							m_show = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							inputSubmitted.emit(m_name, m_cols, m_rows);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ImGui::SameLine();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ImGui::Button("Cancel")) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ImGui::Button("Cancel", ImVec2{50, 20})) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::CloseCurrentPopup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							m_show = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -438,4 +479,34 @@ void TileSheetEditorImGui::SubSheetEditor::close() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_show = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::ExportMenu::draw() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					constexpr auto popupName = "Export Tile Sheet";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (!m_show) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ImGui::OpenPopup(popupName);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					constexpr auto popupHeight = 80.f;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ImGui::SetNextWindowSize(ImVec2(235, popupHeight));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (ImGui::BeginPopupModal(popupName, &m_show, modalFlags)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ImGui::InputInt("Scale", &m_scale);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						m_scale = ox::clamp(m_scale, 1, 20);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ImGui::Button("OK", ImVec2{50, 20})) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::CloseCurrentPopup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							m_show = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							inputSubmitted.emit(m_scale);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ImGui::SameLine();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (ImGui::Button("Cancel", ImVec2{50, 20})) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							ImGui::CloseCurrentPopup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							m_show = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ImGui::EndPopup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void TileSheetEditorImGui::ExportMenu::close() noexcept {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					m_show = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |