diff --git a/flowlayout.cpp b/flowlayout.cpp index c570647..87917e2 100644 --- a/flowlayout.cpp +++ b/flowlayout.cpp @@ -4,7 +4,8 @@ #include #include "flowlayout.h" -//! [1] +#include "utils.hpp" + FlowLayout::FlowLayout(QWidget* parent, int margin, int hSpacing, int vSpacing) : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) { @@ -34,24 +35,33 @@ void FlowLayout::addItem(QLayoutItem *item) int FlowLayout::horizontalSpacing() const { - if (m_hSpace >= 0) { + if (m_hSpace >= 0) + { return m_hSpace; - } else { + } + else + { return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); } } int FlowLayout::verticalSpacing() const { - if (m_vSpace >= 0) { + if (m_vSpace >= 0) + { return m_vSpace; - } else { + } + else + { return smartSpacing(QStyle::PM_LayoutVerticalSpacing); } } int FlowLayout::count() const { + qInfo() << "getting item list size"; + if (itemList.isEmpty()) + return 0; return itemList.size(); } @@ -98,12 +108,16 @@ QSize FlowLayout::minimumSize() const { QSize size; for (const QLayoutItem* item : std::as_const(itemList)) + { size = size.expandedTo(item->minimumSize()); - + } const QMargins margins = contentsMargins(); size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); - if (size.height() < minimumHeight()) - size.rheight() = minimumHeight(); + auto minh = minimumHeight(); + if (size.height() < minh) + { + size.rheight() = minh; + } return size; } @@ -115,27 +129,33 @@ int FlowLayout::doLayout(const QRect &rect, bool testOnly) const int x = effectiveRect.x(); int y = effectiveRect.y(); int lineHeight = 0; - for (QLayoutItem* item : std::as_const(itemList)) { + for (QLayoutItem* item : std::as_const(itemList)) + { const QWidget* wid = item->widget(); int spaceX = horizontalSpacing(); if (spaceX == -1) + { spaceX = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + } int spaceY = verticalSpacing(); if (spaceY == -1) + { spaceY = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + } int nextX = x + item->sizeHint().width() + spaceX; - if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) + { x = effectiveRect.x(); y = y + lineHeight + spaceY; nextX = x + item->sizeHint().width() + spaceX; lineHeight = 0; } - if (!testOnly) + { item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); - + } x = nextX; lineHeight = qMax(lineHeight, item->sizeHint().height()); } @@ -162,14 +182,23 @@ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const void FlowLayout::setIndex(QWidget* wid, int index) { - if (itemAt(index)->widget() == wid) + qInfo() << "set index" << index; + if (index < count() && itemAt(index)->widget() == wid) return; + qInfo() << "past first check"; + IndexOutOfRangeException::ThrowIf(index, 0, {}); + qInfo() << "past second check"; wid->setParent(nullptr); + qInfo() << "cleared parent"; addWidget(wid); - if (index < 0) - return; - for (int i = count()-1; i > index; i--) + qInfo() << "added widget"; + IndexOutOfRangeException::ThrowIf(index, {}, count()-1); + qInfo() << "past third check"; + for (int i = count()-1; i > +1; i--) { + qInfo() << "about to swap" << i-1 << "and" << i; + //TODO excessive, should remove later + IndexOutOfRangeException::ThrowIf(index, 0, count()-1); itemList.swapItemsAt(i-1, i); } } diff --git a/tiercard.cpp b/tiercard.cpp index 582f53f..293910f 100644 --- a/tiercard.cpp +++ b/tiercard.cpp @@ -133,8 +133,10 @@ void TierCard::mousePressEvent(QMouseEvent* event) render(&pix); QDrag drag(this); drag.setPixmap(pix); - drag.setHotSpot(QPoint(pix.size().width() / 2, - pix.size().height() / 2)); + // const auto scale = compareMultiplier(ComparePoint::MiddleCenter); + // drag.setHotSpot(QPoint(pix.size().width() * std::get<0>(scale), + // pix.size().height() * std::get<1>(scale))); + drag.setHotSpot(getPoint(this, ComparePoint::MiddleCenter)); QByteArray itemData; QDataStream dataStream(&itemData, QIODevice::WriteOnly); TierCard::IdType _id = getId(); diff --git a/tierplaceholder.hpp b/tierplaceholder.hpp index 104c955..38af1f7 100644 --- a/tierplaceholder.hpp +++ b/tierplaceholder.hpp @@ -8,7 +8,6 @@ class TierPlaceholder : public QWidget Q_OBJECT public: explicit TierPlaceholder(QWidget *parent = nullptr); - public slots: void cardResize(QSize newSize); diff --git a/tierrow.cpp b/tierrow.cpp index 959f36a..63b680e 100644 --- a/tierrow.cpp +++ b/tierrow.cpp @@ -1,5 +1,4 @@ #include "tierrow.hpp" -// #include "fullsizelayout.hpp" #include "qmimedata.h" #include "utils.hpp" #include "settings.hpp" @@ -130,7 +129,6 @@ void TierRow::dropEvent(QDropEvent* event) { if (event->proposedAction() == Qt::MoveAction) { - clearPlaceholder(); auto data = event->mimeData()->data(TierCard::MimeType); QDataStream stream(&data, QIODevice::ReadOnly); TierCard::IdType cardId; @@ -139,7 +137,12 @@ void TierRow::dropEvent(QDropEvent* event) if (!card) throw InvalidCardIdException(cardId); // addCard(card); - cardLayout->setIndex(card, calculateIndex(event->position())); + // auto index = calculateIndex(event->position()); + // if (index > placeholderIndex) + // index--; + const auto index = placeholderIndex; + clearPlaceholder(); + cardLayout->setIndex(card, index); event->acceptProposedAction(); } else @@ -156,22 +159,21 @@ void TierRow::dropEvent(QDropEvent* event) void TierRow::dragEnterEvent(QDragEnterEvent* event) { - qDebug() << "drag enter event"; - if (cardCount() == 0) - { - qDebug() << "enter empty"; - } + qInfo() << "DRAG ENTER EVENT"; if (event->mimeData()->hasFormat(TierCard::MimeType)) { if (event->proposedAction() == Qt::MoveAction) { - if (placeholder != nullptr) + if (placeholder) { - qDebug() << "placeholder not previously cleared"; - clearPlaceholder(); + qWarning() << "placeholder not previously cleared"; } - placeholder = new TierPlaceholder(); - cardLayout->setIndex(placeholder, calculateIndex(event->position())); + else + { + placeholder = new TierPlaceholder(); + } + placeholderIndex = calculateIndex(event->position()); + cardLayout->setIndex(placeholder, placeholderIndex); event->setDropAction(Qt::MoveAction); event->accept(cardContainer->rect()); } @@ -184,25 +186,33 @@ void TierRow::dragEnterEvent(QDragEnterEvent* event) else if (event->mimeData()->hasImage()) { event->setDropAction(Qt::CopyAction); - event->accept(); + //TODO event->accept(); + event->ignore(); } - else { + else + { event->ignore(); } } void TierRow::dragMoveEvent(QDragMoveEvent* event) { + qInfo() << "DRAG MOVE EVENT"; if (event->mimeData()->hasFormat(TierCard::MimeType)) { if (event->proposedAction() == Qt::MoveAction) { - if (cardCount() == 1) - { - qDebug() << "moving in empty"; - } if (placeholder) - cardLayout->setIndex(placeholder, calculateIndex(event->position())); + { + if (!placeholder->rect().contains(event->position().toPoint())) + { + auto newPlaceholderIndex = calculateIndex(event->position()); + if (newPlaceholderIndex >= placeholderIndex) + newPlaceholderIndex--; + placeholderIndex = newPlaceholderIndex; + cardLayout->setIndex(placeholder, placeholderIndex); + } + } event->acceptProposedAction(); } else @@ -230,6 +240,7 @@ void TierRow::dragLeaveEvent(QDragLeaveEvent* event) void TierRow::clearPlaceholder() { + placeholderIndex = 0; placeholder->setParent(nullptr); placeholder->deleteLater(); placeholder = nullptr; @@ -237,22 +248,38 @@ void TierRow::clearPlaceholder() int TierRow::calculateIndex(QPointF loc) { + qInfo() << "Starting calculate index"; + qInfo() << "location" << loc; auto settings = Settings::get(); auto cardSize = settings->cardSize(); - auto cardCenter = loc + QPointF(cardSize.width() / 2, - cardSize.height() / 2); - auto lastBefore = 0; - for (int i = 0; i < cardLayout->count(); i++) + qInfo() << "card size" << cardSize; + // auto cardCenter = loc + QPointF(cardSize.width() / 2, + // cardSize.height() / 2); + auto cardCenter = loc; + auto offset = QPoint(midpoint(cardSize).x(), 0); + qInfo() << "card center" << cardCenter; + auto lastBefore = -1; + qInfo() << "card layout ptr" << cardLayout; + const auto size = cardLayout->count(); + const auto useLoc = loc + QPoint(cardSize.width() / 2, + cardSize.height() / 2); + qInfo() << "size" << size; + for (int i = 0; i < size; i++) { + qInfo() << "getting item at index" << i; auto refCard = cardLayout->itemAt(i); - auto refPos = refCard->widget()->pos(); - if (cardCenter.y() > refPos.y() - && cardCenter.x() > refPos.x()) + qInfo() << "index" << i << "geometry" << refCard->geometry(); + // auto refPos = refCard->widget()->pos() + offset; + if (isAfter(refCard->widget(), useLoc, ComparePoint::TopCenter)) lastBefore = i; else break; } - return lastBefore; + // qInfo() << "last before" << cardLayout->itemAt(lastBefore)->widget()->pos() + // << "index" << lastBefore; + const auto retVal = lastBefore+1; + qInfo() << "calculated index" << retVal; + return retVal; } void TierRow::cardResize(QSize newSize) diff --git a/tierrow.hpp b/tierrow.hpp index ee499fb..6bc59dd 100644 --- a/tierrow.hpp +++ b/tierrow.hpp @@ -44,6 +44,7 @@ private: QColor _color; const IdType _id; TierPlaceholder* placeholder = nullptr; + int placeholderIndex; void recalcMaxHeight(); void clearPlaceholder(); int calculateIndex(QPointF loc); diff --git a/utils.hpp b/utils.hpp index 174023c..69d700f 100644 --- a/utils.hpp +++ b/utils.hpp @@ -3,8 +3,11 @@ // #include "tierrow.hpp" +#include + #include #include +#include //change this stupid name inline void callOnMeAndChildren(QObject* obj, void (*func)(QObject*)) @@ -64,4 +67,168 @@ inline QColor blend(QColor first, QColor second, float portionFirst) ); } +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