[nostalgia/core/studio] Cleanup TileSheet selection, fix copy/paste bug
This commit is contained in:
		@@ -118,18 +118,18 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
 | 
				
			|||||||
	if (!popupOpen) {
 | 
						if (!popupOpen) {
 | 
				
			||||||
		auto const colorCnt = pal.pages[m_model.palettePage()].size();
 | 
							auto const colorCnt = pal.pages[m_model.palettePage()].size();
 | 
				
			||||||
		if (key == turbine::Key::Alpha_D) {
 | 
							if (key == turbine::Key::Alpha_D) {
 | 
				
			||||||
			m_tool = Tool::Draw;
 | 
								m_tool = TileSheetTool::Draw;
 | 
				
			||||||
			setCopyEnabled(false);
 | 
								setCopyEnabled(false);
 | 
				
			||||||
			setCutEnabled(false);
 | 
								setCutEnabled(false);
 | 
				
			||||||
			setPasteEnabled(false);
 | 
								setPasteEnabled(false);
 | 
				
			||||||
			m_model.clearSelection();
 | 
								m_model.clearSelection();
 | 
				
			||||||
		} else if (key == turbine::Key::Alpha_S) {
 | 
							} else if (key == turbine::Key::Alpha_S) {
 | 
				
			||||||
			m_tool = Tool::Select;
 | 
								m_tool = TileSheetTool::Select;
 | 
				
			||||||
			setCopyEnabled(true);
 | 
								setCopyEnabled(true);
 | 
				
			||||||
			setCutEnabled(true);
 | 
								setCutEnabled(true);
 | 
				
			||||||
			setPasteEnabled(true);
 | 
								setPasteEnabled(true);
 | 
				
			||||||
		} else if (key == turbine::Key::Alpha_F) {
 | 
							} else if (key == turbine::Key::Alpha_F) {
 | 
				
			||||||
			m_tool = Tool::Fill;
 | 
								m_tool = TileSheetTool::Fill;
 | 
				
			||||||
			setCopyEnabled(false);
 | 
								setCopyEnabled(false);
 | 
				
			||||||
			setCutEnabled(false);
 | 
								setCutEnabled(false);
 | 
				
			||||||
			setPasteEnabled(false);
 | 
								setPasteEnabled(false);
 | 
				
			||||||
@@ -173,17 +173,17 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
 | 
				
			|||||||
		ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
 | 
							ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto const btnSz = ImVec2(45, 14);
 | 
								auto const btnSz = ImVec2(45, 14);
 | 
				
			||||||
			if (ImGui::Selectable("Select", m_tool == Tool::Select, 0, btnSz)) {
 | 
								if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) {
 | 
				
			||||||
				m_tool = Tool::Select;
 | 
									m_tool = TileSheetTool::Select;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ImGui::SameLine();
 | 
								ImGui::SameLine();
 | 
				
			||||||
			if (ImGui::Selectable("Draw", m_tool == Tool::Draw, 0, btnSz)) {
 | 
								if (ImGui::Selectable("Draw", m_tool == TileSheetTool::Draw, 0, btnSz)) {
 | 
				
			||||||
				m_tool = Tool::Draw;
 | 
									m_tool = TileSheetTool::Draw;
 | 
				
			||||||
				m_model.clearSelection();
 | 
									m_model.clearSelection();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ImGui::SameLine();
 | 
								ImGui::SameLine();
 | 
				
			||||||
			if (ImGui::Selectable("Fill", m_tool == Tool::Fill, 0, btnSz)) {
 | 
								if (ImGui::Selectable("Fill", m_tool == TileSheetTool::Fill, 0, btnSz)) {
 | 
				
			||||||
				m_tool = Tool::Fill;
 | 
									m_tool = TileSheetTool::Fill;
 | 
				
			||||||
				m_model.clearSelection();
 | 
									m_model.clearSelection();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -370,16 +370,16 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
 | 
				
			|||||||
		if (io.MouseDown[0] && m_prevMouseDownPos != mousePos) {
 | 
							if (io.MouseDown[0] && m_prevMouseDownPos != mousePos) {
 | 
				
			||||||
			m_prevMouseDownPos = mousePos;
 | 
								m_prevMouseDownPos = mousePos;
 | 
				
			||||||
			switch (m_tool) {
 | 
								switch (m_tool) {
 | 
				
			||||||
				case Tool::Draw:
 | 
									case TileSheetTool::Draw:
 | 
				
			||||||
					m_view.clickDraw(fbSize, clickPos(winPos, mousePos));
 | 
										m_view.clickDraw(fbSize, clickPos(winPos, mousePos));
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case Tool::Fill:
 | 
									case TileSheetTool::Fill:
 | 
				
			||||||
					m_view.clickFill(fbSize, clickPos(winPos, mousePos));
 | 
										m_view.clickFill(fbSize, clickPos(winPos, mousePos));
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case Tool::Select:
 | 
									case TileSheetTool::Select:
 | 
				
			||||||
					m_view.clickSelect(fbSize, clickPos(winPos, mousePos));
 | 
										m_view.clickSelect(fbSize, clickPos(winPos, mousePos));
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case Tool::None:
 | 
									case TileSheetTool::None:
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -396,7 +396,7 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if (io.MouseReleased[0]) {
 | 
						if (io.MouseReleased[0]) {
 | 
				
			||||||
		m_prevMouseDownPos = {-1, -1};
 | 
							m_prevMouseDownPos = {-1, -1};
 | 
				
			||||||
		m_view.releaseMouseButton();
 | 
							m_view.releaseMouseButton(m_tool);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,13 +16,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace nostalgia::core {
 | 
					namespace nostalgia::core {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class Tool {
 | 
					 | 
				
			||||||
	None,
 | 
					 | 
				
			||||||
	Draw,
 | 
					 | 
				
			||||||
	Fill,
 | 
					 | 
				
			||||||
	Select,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TileSheetEditorImGui: public studio::Editor {
 | 
					class TileSheetEditorImGui: public studio::Editor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
@@ -71,7 +64,7 @@ class TileSheetEditorImGui: public studio::Editor {
 | 
				
			|||||||
		TileSheetEditorModel &m_model;
 | 
							TileSheetEditorModel &m_model;
 | 
				
			||||||
		float m_palViewWidth = 300;
 | 
							float m_palViewWidth = 300;
 | 
				
			||||||
		ox::Vec2 m_prevMouseDownPos;
 | 
							ox::Vec2 m_prevMouseDownPos;
 | 
				
			||||||
		Tool m_tool = Tool::Draw;
 | 
							TileSheetTool m_tool = TileSheetTool::Draw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		TileSheetEditorImGui(studio::StudioContext &sctx, ox::CRStringView path);
 | 
							TileSheetEditorImGui(studio::StudioContext &sctx, ox::CRStringView path);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,52 +55,55 @@ TileSheetEditorModel::TileSheetEditorModel(studio::StudioContext &sctx, ox::Stri
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::cut() {
 | 
					void TileSheetEditorModel::cut() {
 | 
				
			||||||
 | 
						if (!m_selection) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	TileSheetClipboard blankCb;
 | 
						TileSheetClipboard blankCb;
 | 
				
			||||||
	auto cb = ox::make_unique<TileSheetClipboard>();
 | 
						auto cb = ox::make_unique<TileSheetClipboard>();
 | 
				
			||||||
	const auto &s = activeSubSheet();
 | 
						auto const&s = activeSubSheet();
 | 
				
			||||||
	for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
 | 
						iterateSelectionRows(*m_selection, [&](int x, int y) {
 | 
				
			||||||
		for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
 | 
							auto pt = ox::Point{x, y};
 | 
				
			||||||
			auto pt = ox::Point(x, y);
 | 
							auto const idx = core::idx(s, pt);
 | 
				
			||||||
			const auto idx = core::idx(s, pt);
 | 
							auto const c = getPixel(s, m_img.bpp, idx);
 | 
				
			||||||
			const auto c = getPixel(s, m_img.bpp, idx);
 | 
							pt -= m_selection->a;
 | 
				
			||||||
			pt.x -= m_selectionBounds.x;
 | 
					 | 
				
			||||||
			pt.y -= m_selectionBounds.y;
 | 
					 | 
				
			||||||
		cb->addPixel(pt, c);
 | 
							cb->addPixel(pt, c);
 | 
				
			||||||
		blankCb.addPixel(pt, 0);
 | 
							blankCb.addPixel(pt, 0);
 | 
				
			||||||
		}
 | 
						});
 | 
				
			||||||
	}
 | 
						auto const pt1 = m_selection->a;
 | 
				
			||||||
	const auto pt1 = m_selectionOrigin == ox::Point(-1, -1) ? ox::Point(0, 0) : m_selectionOrigin;
 | 
						auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
 | 
				
			||||||
	const auto pt2 = ox::Point(s.columns * TileWidth, s.rows * TileHeight);
 | 
					 | 
				
			||||||
	turbine::setClipboardObject(m_tctx, std::move(cb));
 | 
						turbine::setClipboardObject(m_tctx, std::move(cb));
 | 
				
			||||||
	pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
 | 
						pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::copy() {
 | 
					void TileSheetEditorModel::copy() {
 | 
				
			||||||
 | 
						if (!m_selection) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	auto cb = ox::make_unique<TileSheetClipboard>();
 | 
						auto cb = ox::make_unique<TileSheetClipboard>();
 | 
				
			||||||
	for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
 | 
						iterateSelectionRows(*m_selection, [&](int x, int y) {
 | 
				
			||||||
		for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
 | 
							auto pt = ox::Point{x, y};
 | 
				
			||||||
			auto pt = ox::Point(x, y);
 | 
							const auto&s = activeSubSheet();
 | 
				
			||||||
			const auto &s = activeSubSheet();
 | 
					 | 
				
			||||||
		const auto idx = core::idx(s, pt);
 | 
							const auto idx = core::idx(s, pt);
 | 
				
			||||||
		const auto c = getPixel(s, m_img.bpp, idx);
 | 
							const auto c = getPixel(s, m_img.bpp, idx);
 | 
				
			||||||
			pt.x -= m_selectionBounds.x;
 | 
							pt -= m_selection->a;
 | 
				
			||||||
			pt.y -= m_selectionBounds.y;
 | 
					 | 
				
			||||||
		cb->addPixel(pt, c);
 | 
							cb->addPixel(pt, c);
 | 
				
			||||||
		}
 | 
						});
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	turbine::setClipboardObject(m_tctx, std::move(cb));
 | 
						turbine::setClipboardObject(m_tctx, std::move(cb));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::paste() {
 | 
					void TileSheetEditorModel::paste() {
 | 
				
			||||||
 | 
						if (!m_selection) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	auto [cb, err] = turbine::getClipboardObject<TileSheetClipboard>(m_tctx);
 | 
						auto [cb, err] = turbine::getClipboardObject<TileSheetClipboard>(m_tctx);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		oxLogError(err);
 | 
							oxLogError(err);
 | 
				
			||||||
		oxErrf("Could not read clipboard: {}", toStr(err));
 | 
							oxErrf("Could not read clipboard: {}", toStr(err));
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	const auto &s = activeSubSheet();
 | 
						auto const&s = activeSubSheet();
 | 
				
			||||||
	const auto pt1 = m_selectionOrigin == ox::Point(-1, -1) ? ox::Point(0, 0) : m_selectionOrigin;
 | 
						auto const pt1 = m_selection->a;
 | 
				
			||||||
	const auto pt2 = ox::Point(s.columns * TileWidth, s.rows * TileHeight);
 | 
						auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
 | 
				
			||||||
	pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
 | 
						pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,30 +209,24 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int palIdx) noexcept {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::select(ox::Point const&pt) noexcept {
 | 
					void TileSheetEditorModel::select(ox::Point const&pt) noexcept {
 | 
				
			||||||
	if (!m_selectionOngoing) {
 | 
						if (m_selTracker.updateCursorPoint(pt)) {
 | 
				
			||||||
		m_selectionOrigin = pt;
 | 
							m_selection.emplace(m_selTracker.selection());
 | 
				
			||||||
		m_selectionOngoing = true;
 | 
					 | 
				
			||||||
		m_selectionBounds = {pt, pt};
 | 
					 | 
				
			||||||
		m_updated = true;
 | 
					 | 
				
			||||||
	} else if (m_selectionBounds.pt2() != pt) {
 | 
					 | 
				
			||||||
		m_selectionBounds = {m_selectionOrigin, pt};
 | 
					 | 
				
			||||||
		m_updated = true;
 | 
							m_updated = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::completeSelection() noexcept {
 | 
					void TileSheetEditorModel::completeSelection() noexcept {
 | 
				
			||||||
	m_selectionOngoing = false;
 | 
					 | 
				
			||||||
	auto &s = activeSubSheet();
 | 
						auto &s = activeSubSheet();
 | 
				
			||||||
	auto pt = m_selectionBounds.pt2();
 | 
						m_selTracker.finishSelection();
 | 
				
			||||||
	pt.x = ox::min(s.columns * TileWidth, pt.x);
 | 
						m_selection.emplace(m_selTracker.selection());
 | 
				
			||||||
	pt.y = ox::min(s.rows * TileHeight, pt.y);
 | 
						auto &pt = m_selection->b;
 | 
				
			||||||
	m_selectionBounds.setPt2(pt);
 | 
						pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
 | 
				
			||||||
 | 
						pt.y = ox::min(s.rows * TileHeight - 1, pt.y);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::clearSelection() noexcept {
 | 
					void TileSheetEditorModel::clearSelection() noexcept {
 | 
				
			||||||
	m_updated = true;
 | 
						m_updated = true;
 | 
				
			||||||
	m_selectionOrigin = {-1, -1};
 | 
						m_selection.reset();
 | 
				
			||||||
	m_selectionBounds = {{-1, -1}, {-1, -1}};
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TileSheetEditorModel::updated() const noexcept {
 | 
					bool TileSheetEditorModel::updated() const noexcept {
 | 
				
			||||||
@@ -266,9 +263,9 @@ ox::Error TileSheetEditorModel::saveFile() noexcept {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
 | 
					bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
 | 
				
			||||||
	const auto &s = activeSubSheet();
 | 
						auto const&s = activeSubSheet();
 | 
				
			||||||
	const auto pt = idxToPt(static_cast<int>(idx), s.columns);
 | 
						auto const pt = idxToPt(static_cast<int>(idx), s.columns);
 | 
				
			||||||
	return m_selectionBounds.contains(pt);
 | 
						return m_selection && m_selection->contains(pt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept {
 | 
					void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,10 +33,9 @@ class TileSheetEditorModel: public ox::SignalHandler {
 | 
				
			|||||||
		size_t m_palettePage{};
 | 
							size_t m_palettePage{};
 | 
				
			||||||
		studio::UndoStack &m_undoStack;
 | 
							studio::UndoStack &m_undoStack;
 | 
				
			||||||
		class DrawCommand *m_ongoingDrawCommand = nullptr;
 | 
							class DrawCommand *m_ongoingDrawCommand = nullptr;
 | 
				
			||||||
 | 
							studio::SelectionTracker m_selTracker;
 | 
				
			||||||
 | 
							ox::Optional<studio::Selection> m_selection;
 | 
				
			||||||
		bool m_updated = false;
 | 
							bool m_updated = false;
 | 
				
			||||||
		bool m_selectionOngoing = false;
 | 
					 | 
				
			||||||
		ox::Point m_selectionOrigin = {-1, -1};
 | 
					 | 
				
			||||||
		ox::Bounds m_selectionBounds = {{-1, -1}, {-1, -1}};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
 | 
							TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,9 +84,18 @@ void TileSheetEditorView::clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clic
 | 
				
			|||||||
	m_model.fill(pt, static_cast<int>(m_palIdx));
 | 
						m_model.fill(pt, static_cast<int>(m_palIdx));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorView::releaseMouseButton() noexcept {
 | 
					void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept {
 | 
				
			||||||
 | 
						switch (tool) {
 | 
				
			||||||
 | 
							case TileSheetTool::Draw:
 | 
				
			||||||
			m_model.endDrawCommand();
 | 
								m_model.endDrawCommand();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case TileSheetTool::Select:
 | 
				
			||||||
			m_model.completeSelection();
 | 
								m_model.completeSelection();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case TileSheetTool::Fill:
 | 
				
			||||||
 | 
							case TileSheetTool::None:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TileSheetEditorView::resizeView(ox::Vec2 const&sz) noexcept {
 | 
					void TileSheetEditorView::resizeView(ox::Vec2 const&sz) noexcept {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace nostalgia::core {
 | 
					namespace nostalgia::core {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class TileSheetTool: int {
 | 
					enum class TileSheetTool {
 | 
				
			||||||
 | 
						None,
 | 
				
			||||||
	Select,
 | 
						Select,
 | 
				
			||||||
	Draw,
 | 
						Draw,
 | 
				
			||||||
	Fill,
 | 
						Fill,
 | 
				
			||||||
@@ -33,6 +34,8 @@ constexpr auto toString(TileSheetTool t) noexcept {
 | 
				
			|||||||
			return "Draw";
 | 
								return "Draw";
 | 
				
			||||||
		case TileSheetTool::Fill:
 | 
							case TileSheetTool::Fill:
 | 
				
			||||||
			return "Fill";
 | 
								return "Fill";
 | 
				
			||||||
 | 
							case TileSheetTool::None:
 | 
				
			||||||
 | 
								return "None";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return "";
 | 
						return "";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -66,7 +69,7 @@ class TileSheetEditorView: public ox::SignalHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept;
 | 
							void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void releaseMouseButton() noexcept;
 | 
							void releaseMouseButton(TileSheetTool tool) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept;
 | 
							void scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,11 @@ struct Selection {
 | 
				
			|||||||
	constexpr ox::Size size() const noexcept {
 | 
						constexpr ox::Size size() const noexcept {
 | 
				
			||||||
		return {b.x - a.x, b.y - a.y};
 | 
							return {b.x - a.x, b.y - a.y};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						[[nodiscard]]
 | 
				
			||||||
 | 
						constexpr bool contains(ox::Point const&pt) const noexcept {
 | 
				
			||||||
 | 
							return a.x <= pt.x && a.y <= pt.y
 | 
				
			||||||
 | 
							    && b.x >= pt.x && b.y >= pt.y;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
 | 
					constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
 | 
				
			||||||
@@ -36,6 +41,22 @@ constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto iterateSelectionRows(studio::Selection const&sel, auto const&cb) {
 | 
				
			||||||
 | 
						constexpr auto retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
 | 
				
			||||||
 | 
						for (auto y = sel.a.y; y <= sel.b.y; ++y) {
 | 
				
			||||||
 | 
							for (auto x = sel.a.x; x <= sel.b.x; ++x) {
 | 
				
			||||||
 | 
								if constexpr(retErr) {
 | 
				
			||||||
 | 
									oxReturnError(cb(x, y));
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									cb(x, y);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if constexpr(retErr) {
 | 
				
			||||||
 | 
							return ox::Error{};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SelectionTracker {
 | 
					class SelectionTracker {
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		bool m_selectionOngoing{};
 | 
							bool m_selectionOngoing{};
 | 
				
			||||||
@@ -53,14 +74,23 @@ class SelectionTracker {
 | 
				
			|||||||
			m_selectionOngoing = true;
 | 
								m_selectionOngoing = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr void updateCursorPoint(ox::Point cursor, bool allowStart = true) noexcept {
 | 
							/**
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * @param cursor
 | 
				
			||||||
 | 
							 * @param allowStart
 | 
				
			||||||
 | 
							 * @return true if changed, false otherwise
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							constexpr bool updateCursorPoint(ox::Point cursor, bool allowStart = true) noexcept {
 | 
				
			||||||
 | 
								auto changed = false;
 | 
				
			||||||
			if (!m_selectionOngoing && allowStart) {
 | 
								if (!m_selectionOngoing && allowStart) {
 | 
				
			||||||
				m_pointA = cursor;
 | 
									m_pointA = cursor;
 | 
				
			||||||
				m_selectionOngoing = true;
 | 
									m_selectionOngoing = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (m_selectionOngoing) {
 | 
								if (m_selectionOngoing) {
 | 
				
			||||||
				m_pointB = cursor;
 | 
									m_pointB = cursor;
 | 
				
			||||||
 | 
									changed = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								return changed;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr void updateCursorPoint(ox::Vec2 cursor, bool allowStart = true) noexcept {
 | 
							constexpr void updateCursorPoint(ox::Vec2 cursor, bool allowStart = true) noexcept {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user