#ifndef UTILS_HPP #define UTILS_HPP // #include "tierrow.hpp" #include #include #include #include //change this stupid name inline void callOnMeAndChildren(QObject* obj, void (*func)(QObject*)) { func(obj); for (auto w : obj->children()) { callOnMeAndChildren(w, func); } } template void callOnMeAndChildren(QObject* obj, void (*func)(T*)) { if (auto casted = dynamic_cast(obj)) { func(casted); } for (auto w : obj->children()) { callOnMeAndChildren(w, func); } } inline QString makeBgColorString(QColor color) { return QString("background-color: rgba(%1,%2,%3,%4)") .arg(QString::number(color.red()), QString::number(color.green()), QString::number(color.blue()), QString::number(color.alphaF())); } template T* findParentOfType(QObject* obj) { auto parent = obj->parent(); if (!parent) return nullptr; else if (auto asT = dynamic_cast(parent)) { return asT; } else { return findParentOfType(parent); } } inline QColor blend(QColor first, QColor second, float portionFirst) { const float& pf = portionFirst; const float ps = 1 - pf; return QColor( first.red()*pf + second.red()*ps, first.green()*pf + second.green()*ps, first.blue()*pf + second.blue()*ps ); } inline QPoint midpoint(QWidget* wid) { const auto& size = wid->size(); return QPoint(size.width() / 2, size.height() / 2); } inline QPoint midpoint(QSize size) { return QPoint(size.width() / 2, size.height() / 2); } class InvalidEnumException : public QException { public: InvalidEnumException(int value, QString type = "") : type(type), value(value) { _what = InvalidEnumException::_makeWhat(value, type).toLocal8Bit(); } template>> InvalidEnumException(T value, QString type) : InvalidEnumException(static_cast(value), type) { } const char* what() const noexcept override { return _what.data(); } private: const QString type; const int value; QByteArray _what; inline static QString _makeWhat(int value, QString type) { QString str; if (!type.isEmpty()) str = "Type: " + type + " "; str += "Value: " + QString::number(value); return str; } }; enum class ComparePoint { TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight, }; constexpr std::tuple compareMultiplier(ComparePoint point) { switch (point) { case ComparePoint::TopLeft: return {0, 0}; case ComparePoint::TopCenter: return {0.5, 0}; case ComparePoint::TopRight: return {1, 0}; case ComparePoint::MiddleLeft: return {0, 0.5}; case ComparePoint::MiddleCenter: return {0.5, 0.5}; case ComparePoint::MiddleRight: return {1, 0.5}; case ComparePoint::BottomLeft: return {0, 1}; case ComparePoint::BottomCenter: return {0.5, 1}; case ComparePoint::BottomRight: return {1, 1}; default: throw InvalidEnumException(point, "ComparePoint"); } } constexpr QPoint getPoint(QSize size, ComparePoint point) { const auto scale = compareMultiplier(point); return QPoint(size.width() * std::get<0>(scale), size.height() * std::get<1>(scale)); } constexpr QPoint getPoint(QRect rect, ComparePoint point) { return rect.topLeft() + getPoint(rect.size(), point); } constexpr QPoint getPoint(QWidget* wid, ComparePoint point) { return getPoint(wid->geometry(), point); } constexpr bool isAfter(QPointF reference, QPointF test, [[maybe_unused]] ComparePoint point) { if (test.y() > reference.y()) return true; return test.x() > reference.x(); } inline bool isAfter(QWidget* reference, QPointF test, ComparePoint point) { // const auto scale = compareMultiplier(point); // const auto ref = reference->pos() + QPoint(reference->size().width() * std::get<0>(scale), // reference->size().height() * std::get<1>(scale)); const auto ref = getPoint(reference, point); return isAfter(ref, test, point); } inline bool isAfter(QPointF reference, QWidget* test, ComparePoint point) { // const auto scale = compareMultiplier(point); // const auto tst = test->pos() + QPoint(test->size().width() * std::get<0>(scale), // test->size().height() * std::get<1>(scale)); const auto tst = getPoint(test, point); return isAfter(reference, tst, point); } inline bool isAfter(QWidget* reference, QWidget* test, ComparePoint point) { // const auto scale = compareMultiplier(point); // const auto tst = test->pos() + QPoint(test->size().width() * std::get<0>(scale), // test->size().height() * std::get<1>(scale)); const auto tst = getPoint(test, point); return isAfter(reference, tst, point); } class IndexOutOfRangeException : public QException { public: IndexOutOfRangeException(qsizetype index, std::optional min, std::optional max) : index(index), min(min), max(max) { QString str = ""; str += "Value: " + QString::number(index); if (min.has_value()) str += " Min: " + QString::number(min.value()); if (max.has_value()) str += " Max: " + QString::number(max.value()); _what = str.toLocal8Bit(); } const char* what() const noexcept override { return _what.data(); } //assumes inclusive static void ThrowIf(qsizetype index, std::optional min, std::optional max) { if ((min.has_value() && index < min.value()) || (max.has_value() && index > max.value())) { throw IndexOutOfRangeException(index, min, max); } } private: const qsizetype index; const std::optional min; const std::optional max; QByteArray _what; }; #endif // UTILS_HPP