diff --git a/src/headers/macro-segment-list.hpp b/src/headers/macro-segment-list.hpp index 87c40be5..ef578341 100644 --- a/src/headers/macro-segment-list.hpp +++ b/src/headers/macro-segment-list.hpp @@ -5,12 +5,14 @@ #include #include #include +#include class MacroSegmentList : public QScrollArea { Q_OBJECT public: MacroSegmentList(QWidget *parent = nullptr); + virtual ~MacroSegmentList(); void SetHelpMsg(const QString &msg); void SetHelpMsgVisible(bool visible); void Insert(int idx, QWidget *widget); @@ -40,6 +42,8 @@ private: int GetDragIndex(const QPoint &); int GetDropIndex(const QPoint &); int GetWidgetIdx(const QPoint &); + void CheckScroll(); + void CheckDropLine(const QPoint &); bool IsInListArea(const QPoint &); QRect GetContentItemRectWithPadding(int idx); void HideLastDropLine(); @@ -47,6 +51,9 @@ private: int _dragPosition = -1; int _dropLineIdx = -1; + QPoint _dragCursorPos; + std::thread _autoScrollThread; + std::atomic_bool _autoScroll{false}; QVBoxLayout *_layout; QVBoxLayout *_contentLayout; diff --git a/src/macro-segment-list.cpp b/src/macro-segment-list.cpp index 9049eeb7..cfadf34d 100644 --- a/src/macro-segment-list.cpp +++ b/src/macro-segment-list.cpp @@ -33,6 +33,14 @@ MacroSegmentList::MacroSegmentList(QWidget *parent) setAcceptDrops(true); } +MacroSegmentList::~MacroSegmentList() +{ + if (_autoScrollThread.joinable()) { + _autoScroll = false; + _autoScrollThread.join(); + } +} + int MacroSegmentList::GetDragIndex(const QPoint &pos) { for (int idx = 0; idx < _contentLayout->count(); ++idx) { @@ -172,7 +180,12 @@ void MacroSegmentList::mouseMoveEvent(QMouseEvent *event) drag->setMimeData(mimedata); drag->setPixmap(img); drag->setHotSpot(event->pos()); + _autoScroll = true; + _autoScrollThread = + std::thread(&MacroSegmentList::CheckScroll, this); drag->exec(); + _autoScroll = false; + _autoScrollThread.join(); } } @@ -249,7 +262,73 @@ void MacroSegmentList::dragMoveEvent(QDragMoveEvent *event) if (!widgetIsInLayout(widget, _contentLayout)) { return; } - const QPoint pos(mapToGlobal(event->pos())); + + _dragCursorPos = (mapToGlobal(event->pos())); + CheckDropLine(_dragCursorPos); +} + +QRect MacroSegmentList::GetContentItemRectWithPadding(int idx) +{ + auto item = _contentLayout->itemAt(idx); + if (!item) { + return {}; + } + int scrollOffset = 0; + if (verticalScrollBar()) { + scrollOffset = verticalScrollBar()->value(); + } + const QRect itemRect = item->geometry().marginsAdded( + _contentLayout->contentsMargins()); + const QRect rect( + mapToGlobal(QPoint(itemRect.topLeft().x(), + itemRect.topLeft().y() - + _contentLayout->spacing() - + scrollOffset)), + QSize(itemRect.size().width(), + itemRect.size().height() + _contentLayout->spacing())); + return rect; +} + +int MacroSegmentList::GetWidgetIdx(const QPoint &pos) +{ + int idx = -1; + for (int i = 0; i < _contentLayout->count(); ++i) { + if (GetContentItemRectWithPadding(i).contains(pos)) { + idx = i; + break; + } + } + return idx; +} + +void MacroSegmentList::CheckScroll() +{ + while (_autoScroll) { + const int scrollTrigger = 15; + const int scrollAmount = 1; + const QRect rect(mapToGlobal(QPoint(0, 0)), size()); + const QRect upperScrollTrigger( + QPoint(rect.topLeft().x(), + rect.topLeft().y() - scrollTrigger), + QSize(rect.width(), scrollTrigger * 2)); + if (upperScrollTrigger.contains(_dragCursorPos)) { + verticalScrollBar()->setValue( + verticalScrollBar()->value() - scrollAmount); + } + const QRect lowerScrollTrigger( + QPoint(rect.bottomLeft().x(), + rect.bottomLeft().y() - scrollTrigger), + QSize(rect.width(), scrollTrigger * 2)); + if (lowerScrollTrigger.contains(_dragCursorPos)) { + verticalScrollBar()->setValue( + verticalScrollBar()->value() + scrollAmount); + } + std::this_thread::sleep_for(std::chrono::microseconds(50)); + } +} + +void MacroSegmentList::CheckDropLine(const QPoint &pos) +{ int idx = GetWidgetIdx(pos); if (idx == _dragPosition) { return; @@ -292,40 +371,6 @@ void MacroSegmentList::dragMoveEvent(QDragMoveEvent *event) } } -QRect MacroSegmentList::GetContentItemRectWithPadding(int idx) -{ - auto item = _contentLayout->itemAt(idx); - if (!item) { - return {}; - } - int scrollOffset = 0; - if (verticalScrollBar()) { - scrollOffset = verticalScrollBar()->value(); - } - const QRect itemRect = item->geometry().marginsAdded( - _contentLayout->contentsMargins()); - const QRect rect( - mapToGlobal(QPoint(itemRect.topLeft().x(), - itemRect.topLeft().y() - - _contentLayout->spacing() - - scrollOffset)), - QSize(itemRect.size().width(), - itemRect.size().height() + _contentLayout->spacing())); - return rect; -} - -int MacroSegmentList::GetWidgetIdx(const QPoint &pos) -{ - int idx = -1; - for (int i = 0; i < _contentLayout->count(); ++i) { - if (GetContentItemRectWithPadding(i).contains(pos)) { - idx = i; - break; - } - } - return idx; -} - bool MacroSegmentList::IsInListArea(const QPoint &pos) { const QRect layoutRect(mapToGlobal(_layout->contentsRect().topLeft()),