137 lines
3.0 KiB
C++
137 lines
3.0 KiB
C++
|
|
#pragma once
|
|
|
|
#include <imgui.h>
|
|
|
|
#include <ox/std/math.hpp>
|
|
#include <ox/std/point.hpp>
|
|
#include <ox/std/size.hpp>
|
|
#include <ox/std/typetraits.hpp>
|
|
|
|
namespace studio {
|
|
|
|
struct Selection {
|
|
ox::Point a, b;
|
|
constexpr Selection() noexcept = default;
|
|
constexpr Selection(ox::Point const&pA, ox::Point const&pB) noexcept: a(pA), b(pB) {}
|
|
[[nodiscard]]
|
|
constexpr ox::Size size() const noexcept {
|
|
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 retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
|
|
for (auto x = sel.a.x; x <= sel.b.x; ++x) {
|
|
for (auto y = sel.a.y; y <= sel.b.y; ++y) {
|
|
if constexpr(retErr) {
|
|
oxReturnError(cb(x, y));
|
|
} else {
|
|
cb(x, y);
|
|
}
|
|
}
|
|
}
|
|
if constexpr(retErr) {
|
|
return ox::Error{};
|
|
}
|
|
};
|
|
|
|
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 {
|
|
private:
|
|
bool m_selectionOngoing{};
|
|
ox::Point m_pointA;
|
|
ox::Point m_pointB;
|
|
public:
|
|
[[nodiscard]]
|
|
constexpr bool selectionOngoing() const noexcept {
|
|
return m_selectionOngoing;
|
|
}
|
|
|
|
constexpr void startSelection(ox::Point cursor) noexcept {
|
|
m_pointA = cursor;
|
|
m_pointB = cursor;
|
|
m_selectionOngoing = true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @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) {
|
|
m_pointA = cursor;
|
|
m_selectionOngoing = true;
|
|
}
|
|
if (m_selectionOngoing) {
|
|
m_pointB = cursor;
|
|
changed = true;
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
constexpr void updateCursorPoint(ox::Vec2 cursor, bool allowStart = true) noexcept {
|
|
updateCursorPoint(
|
|
ox::Point{
|
|
static_cast<int32_t>(cursor.x),
|
|
static_cast<int32_t>(cursor.y),
|
|
},
|
|
allowStart);
|
|
}
|
|
|
|
constexpr void updateCursorPoint(ImVec2 cursor, bool allowStart = true) noexcept {
|
|
updateCursorPoint(
|
|
ox::Point{
|
|
static_cast<int32_t>(cursor.x),
|
|
static_cast<int32_t>(cursor.y),
|
|
},
|
|
allowStart);
|
|
}
|
|
|
|
constexpr void reset() noexcept {
|
|
m_selectionOngoing = {};
|
|
}
|
|
|
|
constexpr void finishSelection() noexcept {
|
|
m_selectionOngoing = {};
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr Selection selection() const noexcept {
|
|
return {
|
|
{
|
|
ox::min(m_pointA.x, m_pointB.x),
|
|
ox::min(m_pointA.y, m_pointB.y),
|
|
},
|
|
{
|
|
ox::max(m_pointA.x, m_pointB.x),
|
|
ox::max(m_pointA.y, m_pointB.y),
|
|
},
|
|
};
|
|
}
|
|
};
|
|
|
|
} |