diff --git a/GUI/Views/SampleDesigner/WidgetMoverButton.cpp b/GUI/Views/SampleDesigner/WidgetMoverButton.cpp index 0ddbaf22d8e913d4a49ca1890217e445d744bd77..a3c70f7fd5ba11d9126150c5726992c0788c5a27 100644 --- a/GUI/Views/SampleDesigner/WidgetMoverButton.cpp +++ b/GUI/Views/SampleDesigner/WidgetMoverButton.cpp @@ -13,23 +13,42 @@ // ************************************************************************************************ #include "GUI/Views/SampleDesigner/WidgetMoverButton.h" +#include "Base/Utils/Assert.h" #include <QLayout> #include <QMouseEvent> #include <QPropertyAnimation> +#include <QScrollArea> +#include <QScrollBar> WidgetMoverButton::WidgetMoverButton(QWidget* parent, QWidget* widgetToMove, int ignoreOnTop) - : QToolButton(parent), m_widgetToMove(widgetToMove), m_ignoreOnTop(ignoreOnTop) + : QToolButton(parent) + , m_widgetToMove(widgetToMove) + , m_ignoreOnTop(ignoreOnTop) + , m_scrollArea(nullptr) { setIcon(QIcon(":/images/toolbar24dark_hambar.svg")); + m_dragScrollTimer.setSingleShot(false); } void WidgetMoverButton::mousePressEvent(QMouseEvent* event) { - m_mouseDownY = event->globalY(); + if (m_scrollArea == nullptr) { + QWidget* p = parentWidget(); + do { + m_scrollArea = dynamic_cast<QScrollArea*>(p); + p = p->parentWidget(); + } while (p != nullptr && m_scrollArea == nullptr); + } + + ASSERT(m_scrollArea); + m_globalMouseDownY = event->globalY(); + m_hotSpot = event->globalPos() + - m_widgetToMove->parentWidget()->mapToGlobal(m_widgetToMove->geometry().topLeft()); } void WidgetMoverButton::mouseReleaseEvent(QMouseEvent*) { + m_dragScrollTimer.stop(); m_started = false; if (m_layoutToDeactivate != nullptr) { m_layoutToDeactivate->setEnabled(true); @@ -40,7 +59,7 @@ void WidgetMoverButton::mouseReleaseEvent(QMouseEvent*) void WidgetMoverButton::mouseMoveEvent(QMouseEvent* event) { - int dy = event->globalY() - m_mouseDownY; + int dy = event->globalY() - m_globalMouseDownY; if (abs(dy) > 5 && !m_started) { m_started = true; @@ -58,7 +77,9 @@ void WidgetMoverButton::mouseMoveEvent(QMouseEvent* event) if (m_started) { // -- move the dragged widget to the new position - m_widgetToMove->move(m_widgetToMove->x(), m_originalWidgetY + dy); + QPoint newPos = + m_widgetToMove->parentWidget()->mapFromGlobal(event->globalPos()) - m_hotSpot; + m_widgetToMove->move(m_widgetToMove->x(), newPos.y()); // -- move other widgets to make room m_dropAboveThisWidget = nullptr; @@ -99,5 +120,35 @@ void WidgetMoverButton::mouseMoveEvent(QMouseEvent* event) yTopOfLayoutItem += r.height() + m_layoutToDeactivate->spacing(); } + + // -- check whether scrolling is necessary + QPoint parPos = m_scrollArea->mapFromGlobal(mapToGlobal(event->pos())); + if (parPos.y() < 20) { + m_dragScrollTimer.setInterval(10); + m_dragScrollTimer.disconnect(); + connect(&m_dragScrollTimer, &QTimer::timeout, [=]() { scrollParent(true); }); + m_dragScrollTimer.start(); + } else if (parPos.y() > m_scrollArea->height() - 20) { + m_dragScrollTimer.setInterval(10); + m_dragScrollTimer.disconnect(); + connect(&m_dragScrollTimer, &QTimer::timeout, [=]() { scrollParent(false); }); + m_dragScrollTimer.start(); + } else + m_dragScrollTimer.stop(); } } + +void WidgetMoverButton::scrollParent(bool up) +{ + auto* scrollbar = m_scrollArea->verticalScrollBar(); + if (!scrollbar->isVisible()) + return; + + const int oldScrollValue = scrollbar->value(); + scrollbar->setValue(oldScrollValue + (up ? -5 : 5)); + + // move the dragged widget to the new position to avoid jitter effects + // use the real change of value, not +/-5: scrolling may have been unsuccessful + m_widgetToMove->move(m_widgetToMove->x(), + m_widgetToMove->y() + scrollbar->value() - oldScrollValue); +} diff --git a/GUI/Views/SampleDesigner/WidgetMoverButton.h b/GUI/Views/SampleDesigner/WidgetMoverButton.h index 1f0e29002c1e943b97f4ffe8f4898b936dffd37f..95ecfc29c25c25e0a7f9ed67aaa6415334af40cf 100644 --- a/GUI/Views/SampleDesigner/WidgetMoverButton.h +++ b/GUI/Views/SampleDesigner/WidgetMoverButton.h @@ -15,8 +15,11 @@ #ifndef BORNAGAIN_GUI_VIEWS_SAMPLEDESIGNER_WIDGETMOVERBUTTON_H #define BORNAGAIN_GUI_VIEWS_SAMPLEDESIGNER_WIDGETMOVERBUTTON_H +#include <QTimer> #include <QToolButton> +class QScrollArea; + //! Button to move a widget vertically in a layout. //! //! With this button, the "move layer" feature in the layer oriented sample editor is realized @@ -47,15 +50,21 @@ signals: void startingToMove(); void finishedMoving(QWidget* widgetToMove, QWidget* moveAboveThisWidget); +private: + void scrollParent(bool up); + private: bool m_started = false; - int m_mouseDownY; + int m_globalMouseDownY; QLayout* m_layoutToDeactivate = nullptr; QWidget* m_widgetToMove; QWidget* m_dropAboveThisWidget; int m_originalWidgetY; int m_yOfFirstRelevantWidget; int m_ignoreOnTop; + QTimer m_dragScrollTimer; + QScrollArea* m_scrollArea; + QPoint m_hotSpot; //!< The mouse-down coordinates in the widget to move };