From f1ec6f885e3d6c07483ae0981b6d4d8669489f11 Mon Sep 17 00:00:00 2001 From: lupoDharkael Date: Sun, 15 Apr 2018 21:29:16 +0200 Subject: [PATCH] Selection refactor New improved selection code: - Selection decopuled into a new class - When you drag the selection against the limits it won't become permanently smaller, it will "bounce" trying to recover its size. If you drop it again it will adapt its size to the borders of the screen. - Fixed bugs in the button position algorithm. - Implemented selection animations for future implementations. --- flameshot.pro | 6 +- src/widgets/capture/buttonhandler.cpp | 40 ++-- src/widgets/capture/buttonhandler.h | 2 + src/widgets/capture/capturewidget.cpp | 261 +++++++++++------------- src/widgets/capture/capturewidget.h | 19 +- src/widgets/capture/selectionwidget.cpp | 128 ++++++++++++ src/widgets/capture/selectionwidget.h | 79 +++++++ src/widgets/capture/utilitypanel.cpp | 1 - 8 files changed, 353 insertions(+), 183 deletions(-) create mode 100644 src/widgets/capture/selectionwidget.cpp create mode 100644 src/widgets/capture/selectionwidget.h diff --git a/flameshot.pro b/flameshot.pro index 7dba5f83..36c2907f 100644 --- a/flameshot.pro +++ b/flameshot.pro @@ -127,7 +127,8 @@ SOURCES += src/main.cpp \ src/tools/abstractactiontool.cpp \ src/utils/globalvalues.cpp \ src/widgets/capture/utilitypanel.cpp \ - src/widgets/capture/hovereventfilter.cpp + src/widgets/capture/hovereventfilter.cpp \ + src/widgets/capture/selectionwidget.cpp HEADERS += src/widgets/capture/buttonhandler.h \ src/widgets/infowindow.h \ @@ -191,7 +192,8 @@ HEADERS += src/widgets/capture/buttonhandler.h \ src/tools/abstracttwopointtool.h \ src/tools/abstractactiontool.h \ src/widgets/capture/utilitypanel.h \ - src/widgets/capture/hovereventfilter.h + src/widgets/capture/hovereventfilter.h \ + src/widgets/capture/selectionwidget.h unix:!macx { SOURCES += src/core/flameshotdbusadapter.cpp \ diff --git a/src/widgets/capture/buttonhandler.cpp b/src/widgets/capture/buttonhandler.cpp index 9f30ffd4..7b14ff19 100644 --- a/src/widgets/capture/buttonhandler.cpp +++ b/src/widgets/capture/buttonhandler.cpp @@ -81,7 +81,7 @@ void ButtonHandler::updatePosition(const QRect &selection) { return; } // Copy of the selection area for internal modifications - m_selection = selection; + m_selection = intersectWithAreas(selection); updateBlockedSides(); ensureSelectionMinimunSize(); // Indicates the actual button to be moved @@ -219,6 +219,17 @@ QVector ButtonHandler::verticalPoints( return res; } +QRect ButtonHandler::intersectWithAreas(const QRect &rect) { + QRect res; + for(const QRect &r : m_screenRegions) { + QRect temp = rect.intersected(r); + if (temp.height() * temp.width() > res.height() * res.width()) { + res = temp; + } + } + return res; +} + void ButtonHandler::init() { m_separator = GlobalValues::buttonBaseSize() / 4; } @@ -261,31 +272,20 @@ void ButtonHandler::updateBlockedSides() { } void ButtonHandler::expandSelection() { - if (m_blockedRight && !m_blockedLeft) { - m_selection.setX(m_selection.x() - m_buttonExtendedSize); - } else if (!m_blockedRight && !m_blockedLeft) { - m_selection.setX(m_selection.x() - m_buttonExtendedSize); - m_selection.setWidth(m_selection.width() + m_buttonExtendedSize); - } else { - m_selection.setWidth(m_selection.width() + m_buttonExtendedSize); - } - - if (m_blockedBotton && !m_blockedTop) { - m_selection.setY(m_selection.y() - m_buttonExtendedSize); - } else if (!m_blockedTop && !m_blockedBotton) { - m_selection.setY(m_selection.y() - m_buttonExtendedSize); - m_selection.setHeight(m_selection.height() + m_buttonExtendedSize); - } else { - m_selection.setHeight(m_selection.height() + m_buttonExtendedSize); - } + int &s = m_buttonExtendedSize; + m_selection = m_selection + QMargins(s, s, s, s); + m_selection = intersectWithAreas(m_selection); } void ButtonHandler::positionButtonsInside(int index) { // Position the buttons in the botton-center of the main but inside of the // selection. - QRect mainArea = QGuiApplication::primaryScreen()->geometry() - .intersected(m_selection); + QRect mainArea = m_selection; + mainArea = intersectWithAreas(mainArea); const int buttonsPerRow = (mainArea.width()) / (m_buttonExtendedSize); + if (buttonsPerRow == 0) { + return; + } QPoint center = QPoint(mainArea.center().x(), mainArea.bottom() - m_buttonExtendedSize); diff --git a/src/widgets/capture/buttonhandler.h b/src/widgets/capture/buttonhandler.h index 6d4daf0c..48d8fe59 100644 --- a/src/widgets/capture/buttonhandler.h +++ b/src/widgets/capture/buttonhandler.h @@ -54,6 +54,8 @@ private: QVector verticalPoints(const QPoint ¢er, const int elements, const bool upToDown) const; + QRect intersectWithAreas(const QRect &rect); + QVector m_vectorButtons; QRegion m_screenRegions; diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index f5336093..9e3ce540 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -49,33 +49,29 @@ // enableSaveWIndow CaptureWidget::CaptureWidget(const uint id, const QString &savePath, bool fullscreen, QWidget *parent) : - QWidget(parent), m_mouseOverHandle(nullptr), - m_mouseIsClicked(false), m_rightClick(false), m_newSelection(false), - m_grabbing(false), m_captureDone(false), m_previewEnabled(true), - m_activeButton(nullptr), m_activeTool(nullptr), m_id(id) + QWidget(parent), m_mouseIsClicked(false), m_rightClick(false), + m_newSelection(false), m_grabbing(false), m_captureDone(false), + m_previewEnabled(true), m_activeButton(nullptr), m_activeTool(nullptr), + m_mouseOverHandle(SelectionWidget::NO_SIDE), m_id(id) { + // Base config of the widget m_eventFilter = new HoverEventFilter(this); connect(m_eventFilter, &HoverEventFilter::hoverIn, this, &CaptureWidget::childEnter); connect(m_eventFilter, &HoverEventFilter::hoverOut, this, &CaptureWidget::childLeave); - - initContext(savePath, fullscreen); - initSelection(); - - // Base config of the widget setAttribute(Qt::WA_DeleteOnClose); m_showInitialMsg = m_config.showHelpValue(); m_opacity = m_config.contrastOpacityValue(); setMouseTracking(true); - updateCursor(); + initContext(savePath, fullscreen); initShortcuts(); #ifdef Q_OS_WIN // Top left of the whole set of screens QPoint topLeft(0,0); #endif - if (m_context.fullscreen) { + if (fullscreen) { // Grab Screenshot bool ok = true; m_context.screenshot = ScreenGrabber().grabEntireDesktop(ok); @@ -124,6 +120,8 @@ CaptureWidget::CaptureWidget(const uint id, const QString &savePath, m_buttonHandler->updateScreenRegions(areas); m_buttonHandler->hide(); + initSelection(); + updateCursor(); // Init color picker m_colorPicker = new ColorPicker(this); @@ -199,7 +197,10 @@ void CaptureWidget::paintEvent(QPaintEvent *) { QColor overlayColor(0, 0, 0, m_opacity); painter.setBrush(overlayColor); - QRect r = m_context.selection.normalized().adjusted(0, 0, -1, -1); + QRect r; + if (m_selection->isVisible()) { + r = m_selection->geometry().normalized().adjusted(0, 0, -1, -1); + } QRegion grey(rect()); grey = grey.subtracted(r); @@ -239,17 +240,13 @@ void CaptureWidget::paintEvent(QPaintEvent *) { painter.drawText(helpRect, Qt::AlignCenter, helpTxt); } - if (!m_context.selection.isNull()) { - // paint selection rect - painter.setPen(m_uiColor); - painter.setBrush(Qt::NoBrush); - painter.drawRect(r); - + if (m_selection->isVisible()) { // paint handlers + painter.setPen(m_uiColor); painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(m_uiColor); - for(auto r: m_handles) { - painter.drawRoundRect(*r, 100, 100); + for(auto r: m_selection->handlerAreas()) { + painter.drawRoundRect(r, 100, 100); } } } @@ -263,6 +260,7 @@ void CaptureWidget::mousePressEvent(QMouseEvent *e) { } else if (e->button() == Qt::LeftButton) { m_showInitialMsg = false; m_mouseIsClicked = true; + // Click using a tool if (m_activeButton) { if (m_activeTool) { m_activeTool->deleteLater(); @@ -275,10 +273,14 @@ void CaptureWidget::mousePressEvent(QMouseEvent *e) { } m_dragStartPoint = e->pos(); - m_selectionBeforeDrag = m_context.selection; - if (!m_context.selection.contains(e->pos()) && !m_mouseOverHandle) { + m_selection->saveGeometry(); + // New selection + if (!m_selection->geometry().contains(e->pos()) && + m_mouseOverHandle == SelectionWidget::NO_SIDE) + { + m_selection->setGeometry(QRect(e->pos(), e->pos())); + m_selection->setVisible(false); m_newSelection = true; - m_context.selection = QRect(); m_buttonHandler->hide(); update(); } else { @@ -296,70 +298,72 @@ void CaptureWidget::mouseMoveEvent(QMouseEvent *e) { m_buttonHandler->hide(); } if (m_newSelection) { - m_context.selection = - QRect(m_dragStartPoint, m_context.mousePos).normalized(); - updateHandles(); + m_selection->setVisible(true); + m_selection->setGeometry( + QRect(m_dragStartPoint, m_context.mousePos).normalized()); update(); - } else if (!m_mouseOverHandle) { + } else if (m_mouseOverHandle == SelectionWidget::NO_SIDE) { // Moving the whole selection - QRect r = rect().normalized(); - QRect initialRect = m_context.selection.normalized(); - // new top left - QPoint p = initialRect.topLeft() + (e->pos() - m_dragStartPoint); - m_dragStartPoint += e->pos() - m_dragStartPoint; - m_context.selection.moveTo(p); - if (!r.contains(QPoint(r.center().x(), m_context.selection.top()))) { - m_context.selection.setTop(r.top()); - } if (!r.contains(QPoint(m_context.selection.left(), r.center().y()))) { - m_context.selection.setLeft(r.left()); + QRect initialRect = m_selection->savedGeometry().normalized(); + QPoint newTopLeft = initialRect.topLeft() + (e->pos() - m_dragStartPoint); + QRect finalRect(newTopLeft, initialRect.size()); + + if (finalRect.left() < rect().left()) { + finalRect.setLeft(rect().left()); + } else if (finalRect.right() > rect().right()) { + finalRect.setRight(rect().right()); } - if (!r.contains(QPoint(m_context.selection.right(), r.center().y()))) { - m_context.selection.setRight(r.right()); - } if (!r.contains(QPoint(r.center().x(), m_context.selection.bottom()))) { - m_context.selection.setBottom(r.bottom()); + if (finalRect.top() < rect().top()) { + finalRect.setTop(rect().top()); + } else if (finalRect.bottom() > rect().bottom()) { + finalRect.setBottom(rect().bottom()); } - updateHandles(); + m_selection->setGeometry(finalRect.normalized().intersected(rect())); update(); } else { // Dragging a handle - QRect r = m_selectionBeforeDrag; + QRect r = m_selection->savedGeometry(); QPoint offset = e->pos() - m_dragStartPoint; bool symmetryMod = qApp->keyboardModifiers() & Qt::ShiftModifier; - if (m_mouseOverHandle == &m_TLHandle || m_mouseOverHandle == &m_TSide - || m_mouseOverHandle == &m_TRHandle) + using sw = SelectionWidget; + if (m_mouseOverHandle == sw::TOPLEFT_SIDE + || m_mouseOverHandle == sw::TOP_SIDE + || m_mouseOverHandle == sw::TOPRIGHT_SIDE) { // dragging one of the top handles r.setTop(r.top() + offset.y()); if (symmetryMod) { r.setBottom(r.bottom() - offset.y()); } } - if (m_mouseOverHandle == &m_TLHandle || m_mouseOverHandle == &m_LSide - || m_mouseOverHandle == &m_BLHandle) + if (m_mouseOverHandle == sw::TOPLEFT_SIDE + || m_mouseOverHandle == sw::LEFT_SIDE + || m_mouseOverHandle == sw::BOTTONLEFT_SIDE) { // dragging one of the left handles r.setLeft(r.left() + offset.x()); if (symmetryMod) { r.setRight(r.right() - offset.x()); } } - if (m_mouseOverHandle == &m_BLHandle || m_mouseOverHandle == &m_BSide - || m_mouseOverHandle == &m_BRHandle) + if (m_mouseOverHandle == sw::BOTTONLEFT_SIDE + || m_mouseOverHandle == sw::BOTTON_SIDE + || m_mouseOverHandle == sw::BOTTONRIGHT_SIDE) { // dragging one of the bottom handles r.setBottom(r.bottom() + offset.y()); if (symmetryMod) { r.setTop(r.top() - offset.y()); } } - if (m_mouseOverHandle == &m_TRHandle || m_mouseOverHandle == &m_RSide - || m_mouseOverHandle == &m_BRHandle) + if (m_mouseOverHandle == sw::TOPRIGHT_SIDE + || m_mouseOverHandle == sw::RIGHT_SIDE + || m_mouseOverHandle == sw::BOTTONRIGHT_SIDE) { // dragging one of the right handles r.setRight(r.right() + offset.x()); if (symmetryMod) { r.setLeft(r.left() - offset.x()); } } - m_context.selection = r.normalized(); - updateHandles(); + m_selection->setGeometry(r.intersected(rect()).normalized()); update(); } } else if (m_mouseIsClicked && m_activeTool) { @@ -378,20 +382,10 @@ void CaptureWidget::mouseMoveEvent(QMouseEvent *e) { } else if (m_activeButton && m_activeButton->tool()->showMousePreview()) { update(); } else { - if (m_context.selection.isNull()) { + if (!m_selection->isVisible()) { return; } - bool found = false; - for (QRect *const r: m_sides) { - if (r->contains(e->pos())) { - m_mouseOverHandle = r; - found = true; - break; - } - } - if (!found) { - m_mouseOverHandle = nullptr; - } + m_mouseOverHandle = m_selection->getMouseSide(m_context.mousePos); updateCursor(); } } @@ -414,11 +408,12 @@ void CaptureWidget::mouseReleaseEvent(QMouseEvent *e) { // Show the buttons after the resize of the selection or the creation // of a new one. - if (!m_buttonHandler->isVisible() && !m_context.selection.isNull()) { + if (!m_buttonHandler->isVisible() && m_selection->isVisible()) { // Don't go outside - m_context.selection = m_context.selection.intersected(rect()); + m_selection->setGeometry(m_selection->geometry().intersected(rect())); + m_context.selection = m_selection->geometry(); // TODO remove? updateSizeIndicator(); - m_buttonHandler->updatePosition(m_context.selection); + m_buttonHandler->updatePosition(m_selection->geometry()); m_buttonHandler->show(); } m_mouseIsClicked = false; @@ -429,31 +424,27 @@ void CaptureWidget::mouseReleaseEvent(QMouseEvent *e) { } void CaptureWidget::keyPressEvent(QKeyEvent *e) { - if (m_context.selection.isNull()) { + if (!m_selection->isVisible()) { return; } else if (e->key() == Qt::Key_Up - && m_context.selection.top() > rect().top()) { - m_context.selection.moveTop(m_context.selection.top()-1); - m_buttonHandler->updatePosition(m_context.selection); - updateHandles(); + && m_selection->geometry().top() > rect().top()) { + m_selection->move(QPoint(m_selection->x(), m_selection->y() -1)); + m_buttonHandler->updatePosition(m_selection->geometry()); update(); } else if (e->key() == Qt::Key_Down - && m_context.selection.bottom() < rect().bottom()) { - m_context.selection.moveBottom(m_context.selection.bottom()+1); - m_buttonHandler->updatePosition(m_context.selection); - updateHandles(); + && m_selection->geometry().bottom() < rect().bottom()) { + m_selection->move(QPoint(m_selection->x(), m_selection->y() +1)); + m_buttonHandler->updatePosition(m_selection->geometry()); update(); } else if (e->key() == Qt::Key_Left - && m_context.selection.left() > rect().left()) { - m_context.selection.moveLeft(m_context.selection.left()-1); - m_buttonHandler->updatePosition(m_context.selection); - updateHandles(); + && m_selection->geometry().left() > rect().left()) { + m_selection->move(QPoint(m_selection->x() -1, m_selection->y())); + m_buttonHandler->updatePosition(m_selection->geometry()); update(); } else if (e->key() == Qt::Key_Right - && m_context.selection.right() < rect().right()) { - m_context.selection.moveRight(m_context.selection.right()+1); - m_buttonHandler->updatePosition(m_context.selection); - updateHandles(); + && m_selection->geometry().right() < rect().right()) { + m_selection->move(QPoint(m_selection->x() +1, m_selection->y())); + m_buttonHandler->updatePosition(m_selection->geometry()); update(); } } @@ -475,6 +466,7 @@ void CaptureWidget::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); m_context.widgetDimensions = rect(); m_context.widgetOffset = mapToGlobal(QPoint(0,0)); + m_panel->setFixedHeight(height()); if (!m_context.fullscreen) { m_buttonHandler->updateScreenRegions(rect()); } @@ -498,7 +490,10 @@ void CaptureWidget::initContext(const QString &savePath, bool fullscreen) { void CaptureWidget::initPanel() { m_panel = new UtilityPanel(this); makeChild(m_panel); - QRect panelRect = QGuiApplication::primaryScreen()->geometry(); + QRect panelRect = rect(); + if (m_context.fullscreen) { + panelRect = QGuiApplication::primaryScreen()->geometry(); + } panelRect.moveTo(mapFromGlobal(panelRect.topLeft())); panelRect.setWidth(m_colorPicker->width() * 3); m_panel->setGeometry(panelRect); @@ -507,17 +502,11 @@ void CaptureWidget::initPanel() { } void CaptureWidget::initSelection() { - QRect baseRect(0, 0, handleSize(), handleSize()); - m_TLHandle = baseRect; m_TRHandle = baseRect; - m_BLHandle = baseRect; m_BRHandle = baseRect; - m_LHandle = baseRect; m_THandle = baseRect; - m_RHandle = baseRect; m_BHandle = baseRect; - - m_handles << &m_TLHandle << &m_TRHandle << &m_BLHandle << &m_BRHandle - << &m_LHandle << &m_THandle << &m_RHandle << &m_BHandle; - - m_sides << &m_TLHandle << &m_TRHandle << &m_BLHandle << &m_BRHandle - << &m_LSide << &m_TSide << &m_RSide << &m_BSide; + m_selection = new SelectionWidget(m_uiColor, this); + m_selection->setVisible(false); + connect(m_selection, &SelectionWidget::animationEnded, this, [this](){ + this->m_buttonHandler->updatePosition(this->m_selection->geometry()); + }); } void CaptureWidget::initWidget() { @@ -564,7 +553,7 @@ void CaptureWidget::processTool(CaptureTool *t) { void CaptureWidget::handleButtonSignal(CaptureTool::Request r) { switch (r) { case CaptureTool::REQ_CLEAR_MODIFICATIONS: - m_undoStack.clear(); // TODO + m_undoStack.setIndex(0); update(); break; case CaptureTool::REQ_CLOSE_GUI: @@ -575,11 +564,11 @@ void CaptureWidget::handleButtonSignal(CaptureTool::Request r) { break; case CaptureTool::REQ_HIDE_SELECTION: m_newSelection = true; - m_context.selection = QRect(); + m_selection->setVisible(false); updateCursor(); break; case CaptureTool::REQ_SELECT_ALL: - m_context.selection = rect(); + m_selection->setGeometryAnimated(rect()); break; case CaptureTool::REQ_UNDO_MODIFICATION: m_undoStack.undo(); @@ -635,41 +624,37 @@ void CaptureWidget::setDrawColor(const QColor &c) { } void CaptureWidget::leftResize() { - if (!m_context.selection.isNull() && m_context.selection.right() > m_context.selection.left()) { - m_context.selection.setRight(m_context.selection.right()-1); - m_buttonHandler->updatePosition(m_context.selection); + if (m_selection->isVisible() && m_selection->geometry().right() > m_selection->geometry().left()) { + m_selection->setGeometry(m_selection->geometry() + QMargins(0, 0, -1, 0)); + m_buttonHandler->updatePosition(m_selection->geometry()); updateSizeIndicator(); - updateHandles(); update(); } } void CaptureWidget::rightResize() { - if (!m_context.selection.isNull() && m_context.selection.right() < rect().right()) { - m_context.selection.setRight(m_context.selection.right()+1); - m_buttonHandler->updatePosition(m_context.selection); + if (m_selection->isVisible() && m_selection->geometry().right() < rect().right()) { + m_selection->setGeometry(m_selection->geometry() + QMargins(0, 0, 1, 0)); + m_buttonHandler->updatePosition(m_selection->geometry()); updateSizeIndicator(); - updateHandles(); update(); } } void CaptureWidget::upResize() { - if (!m_context.selection.isNull() && m_context.selection.bottom() > m_context.selection.top()) { - m_context.selection.setBottom(m_context.selection.bottom()-1); - m_buttonHandler->updatePosition(m_context.selection); + if (m_selection->isVisible() && m_selection->geometry().bottom() > m_selection->geometry().top()) { + m_selection->setGeometry(m_selection->geometry() + QMargins(0, 0, 0, -1)); + m_buttonHandler->updatePosition(m_selection->geometry()); updateSizeIndicator(); - updateHandles(); update(); } } void CaptureWidget::downResize() { - if (!m_context.selection.isNull() && m_context.selection.bottom() < rect().bottom()) { - m_context.selection.setBottom(m_context.selection.bottom()+1); - m_buttonHandler->updatePosition(m_context.selection); + if (m_selection->isVisible() && m_selection->geometry().bottom() < rect().bottom()) { + m_selection->setGeometry(m_selection->geometry() + QMargins(0, 0, 0, 1)); + m_buttonHandler->updatePosition(m_selection->geometry()); updateSizeIndicator(); - updateHandles(); update(); } } @@ -689,26 +674,6 @@ void CaptureWidget::initShortcuts() { new QShortcut(Qt::Key_Return, this, SLOT(copyScreenshot())); } -void CaptureWidget::updateHandles() { - QRect r = m_context.selection.normalized().adjusted(0, 0, -1, -1); - int s2 = handleSize() / 2; - - m_TLHandle.moveTopLeft(QPoint(r.x() - s2, r.y() - s2)); - m_TRHandle.moveTopRight(QPoint(r.right() + s2, r.y() - s2)); - m_BRHandle.moveBottomRight(QPoint(r.x() + r.width() + s2, r.bottom() + s2)); - m_BLHandle.moveBottomLeft(QPoint(QPoint(r.x() - s2, r.bottom() + s2))); - - m_LHandle.moveTopLeft(QPoint(r.x() - s2, r.y() + r.height() / 2 - s2)); - m_THandle.moveTopLeft(QPoint(r.x() + r.width() / 2 - s2, r.y() - s2)); - m_RHandle.moveTopRight(QPoint(r.right() + s2, r.y() + r.height() / 2 - s2)); - m_BHandle.moveBottomLeft(QPoint(r.x() + r.width() / 2 - s2, r.bottom() + s2)); - - m_LSide = QRect(m_TLHandle.bottomLeft(), m_BLHandle.topRight()); - m_RSide = QRect(m_TRHandle.bottomLeft(), m_BRHandle.topRight()); - m_BSide = QRect(m_BLHandle.topRight(), m_BRHandle.bottomLeft()); - m_TSide = QRect(m_TLHandle.topRight(), m_TRHandle.bottomLeft()); -} - void CaptureWidget::updateSizeIndicator() { if (m_sizeIndButton){ const QRect &selection = extendedSelection(); @@ -724,18 +689,26 @@ void CaptureWidget::updateCursor() { } else if (m_grabbing) { setCursor(Qt::ClosedHandCursor); } else if (!m_activeButton) { - if (m_mouseOverHandle){ + using sw = SelectionWidget; + if (m_mouseOverHandle != sw::NO_SIDE){ // cursor on the handlers - if (m_mouseOverHandle == &m_TLHandle || m_mouseOverHandle == &m_BRHandle) { + switch (m_mouseOverHandle) { + case sw::TOPLEFT_SIDE: case sw::BOTTONRIGHT_SIDE: setCursor(Qt::SizeFDiagCursor); - } else if (m_mouseOverHandle == &m_TRHandle || m_mouseOverHandle == &m_BLHandle) { + break; + case sw::TOPRIGHT_SIDE: case sw::BOTTONLEFT_SIDE: setCursor(Qt::SizeBDiagCursor); - } else if (m_mouseOverHandle == &m_LSide || m_mouseOverHandle == &m_RSide) { + break; + case sw::LEFT_SIDE: case sw::RIGHT_SIDE: setCursor(Qt::SizeHorCursor); - } else if (m_mouseOverHandle == &m_TSide || m_mouseOverHandle == &m_BSide) { + break; + case sw::TOP_SIDE: case sw::BOTTON_SIDE: setCursor(Qt::SizeVerCursor); + break; + default: + break; } - } else if (m_context.selection.contains(m_context.mousePos)) { + } else if (m_selection->geometry().contains(m_context.mousePos)) { setCursor(Qt::OpenHandCursor); } else { setCursor(Qt::CrossCursor); @@ -794,11 +767,11 @@ void CaptureWidget::redo() { } QRect CaptureWidget::extendedSelection() const { - if (m_context.selection.isNull()) + if (!m_selection->isVisible()) return QRect(); auto devicePixelRatio = m_context.screenshot.devicePixelRatio(); - QRect const &r = m_context.selection; + QRect const &r = m_selection->geometry(); return QRect(r.left() * devicePixelRatio, r.top() * devicePixelRatio, r.width() * devicePixelRatio, diff --git a/src/widgets/capture/capturewidget.h b/src/widgets/capture/capturewidget.h index d793a329..54f6d9e2 100644 --- a/src/widgets/capture/capturewidget.h +++ b/src/widgets/capture/capturewidget.h @@ -27,6 +27,7 @@ #include "src/tools/capturecontext.h" #include "src/tools/capturetool.h" #include "src/utils/confighandler.h" +#include "src/widgets/capture/selectionwidget.h" #include "src/widgets/capture/utilitypanel.h" #include "buttonhandler.h" #include @@ -102,9 +103,6 @@ protected: // Secondary ui color QColor m_contrastUiColor; - // pointer to the handlers under the mouse - QRect m_selectionBeforeDrag; - QRect *m_mouseOverHandle; // Outside selection opacity int m_opacity; // utility flags @@ -122,7 +120,6 @@ private: void initSelection(); void initWidget(); void initShortcuts(); - void updateHandles(); void updateSizeIndicator(); void updateCursor(); void makeChild(QWidget *w); @@ -144,19 +141,9 @@ private: ConfigHandler m_config; NotifierBox *m_notifierBox; HoverEventFilter *m_eventFilter; + SelectionWidget *m_selection; QPoint m_dragStartPoint; + SelectionWidget::SideType m_mouseOverHandle; uint m_id; - - // naming convention for handles - // T top, B bottom, R Right, L left - // 2 letters: a corner - // 1 letter: the handle on the middle of the corresponding side - QRect m_TLHandle, m_TRHandle, m_BLHandle, m_BRHandle; - QRect m_LHandle, m_THandle, m_RHandle, m_BHandle; - // Side Rects - QRect m_LSide, m_TSide, m_RSide, m_BSide; - // list containing the active habdlers - QVector m_handles; - QVector m_sides; }; diff --git a/src/widgets/capture/selectionwidget.cpp b/src/widgets/capture/selectionwidget.cpp new file mode 100644 index 00000000..f82e53b1 --- /dev/null +++ b/src/widgets/capture/selectionwidget.cpp @@ -0,0 +1,128 @@ +// Copyright(c) 2017-2018 Alejandro Sirgo Rica & Contributors +// +// This file is part of Flameshot. +// +// Flameshot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Flameshot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Flameshot. If not, see . + +#include "selectionwidget.h" +#include "src/utils/globalvalues.h" +#include +#include + +SelectionWidget::SelectionWidget(const QColor &c, QWidget *parent) : + QWidget(parent), m_color(c) +{ + m_animation = new QPropertyAnimation(this, "geometry", this); + m_animation->setEasingCurve(QEasingCurve::InOutQuad); + m_animation->setDuration(200); + connect(m_animation, &QPropertyAnimation::finished, + this, &SelectionWidget::animationEnded); + + setAttribute(Qt::WA_TransparentForMouseEvents); + int sideVal = GlobalValues::buttonBaseSize() * 0.6; + int handleSide = sideVal / 2; + const QRect areaRect(0, 0, sideVal, sideVal); + const QRect handleRect(0, 0, handleSide, handleSide); + m_TLHandle = m_TRHandle = m_BLHandle = m_BRHandle = + m_LHandle = m_THandle = m_RHandle = m_BHandle= handleRect; + m_TLArea = m_TRArea = m_BLArea = m_BRArea = areaRect; + + m_areaOffset = QPoint(-sideVal/2, -sideVal/2); + m_handleOffset = QPoint(-handleSide/2, -handleSide/2); +} + +SelectionWidget::SideType SelectionWidget::getMouseSide(const QPoint &point) const { + if (m_TLArea.contains(point)) { + return TOPLEFT_SIDE; + } else if (m_TRArea.contains(point)) { + return TOPRIGHT_SIDE; + } else if (m_BLArea.contains(point)) { + return BOTTONLEFT_SIDE; + } else if (m_BRArea.contains(point)) { + return BOTTONRIGHT_SIDE; + } else if (m_LArea.contains(point)) { + return LEFT_SIDE; + } else if (m_TArea.contains(point)) { + return TOP_SIDE; + } else if (m_RArea.contains(point)) { + return RIGHT_SIDE; + } else if (m_BArea.contains(point)) { + return BOTTON_SIDE; + } else { + return NO_SIDE; + } +} + +QVector SelectionWidget::handlerAreas() { + QVector areas; + areas << m_TLHandle << m_TRHandle << m_BLHandle << m_BRHandle + <setStartValue(geometry()); + m_animation->setEndValue(r); + m_animation->start(); + } +} + +void SelectionWidget::saveGeometry() { + m_geometryBackup = geometry(); +} + +QRect SelectionWidget::savedGeometry() { + return m_geometryBackup; +} + +void SelectionWidget::paintEvent(QPaintEvent *) { + QPainter p(this); + p.setPen(m_color); + p.drawRect(rect() + QMargins(0, 0, -1, -1)); +} + +void SelectionWidget::resizeEvent(QResizeEvent *) { + updateAreas(); +} + +void SelectionWidget::moveEvent(QMoveEvent *) { + updateAreas(); +} + +void SelectionWidget::updateColor(const QColor &c) { + m_color = c; +} + +void SelectionWidget::updateAreas() { + QRect r = rect(); + m_TLArea.moveTo(m_areaOffset + pos()); + m_TRArea.moveTo(r.topRight() + m_areaOffset + pos()); + m_BLArea.moveTo(r.bottomLeft() + m_areaOffset + pos()); + m_BRArea.moveTo(r.bottomRight() + m_areaOffset + pos()); + + m_LArea = QRect(m_TLArea.bottomLeft(), m_BLArea.topRight()); + m_TArea = QRect(m_TLArea.topRight(), m_TRArea.bottomLeft()); + m_RArea = QRect(m_TRArea.bottomLeft(), m_BRArea.topRight()); + m_BArea = QRect(m_BLArea.topRight(), m_BRArea.bottomLeft()); + + m_TLHandle.moveTo(m_TLArea.center() + m_handleOffset); + m_BLHandle.moveTo(m_BLArea.center() + m_handleOffset); + m_TRHandle.moveTo(m_TRArea.center() + m_handleOffset); + m_BRHandle.moveTo(m_BRArea.center() + m_handleOffset); + m_LHandle.moveTo(m_LArea.center() + m_handleOffset); + m_THandle.moveTo(m_TArea.center() + m_handleOffset); + m_RHandle.moveTo(m_RArea.center() + m_handleOffset); + m_BHandle.moveTo(m_BArea.center() + m_handleOffset); +} diff --git a/src/widgets/capture/selectionwidget.h b/src/widgets/capture/selectionwidget.h new file mode 100644 index 00000000..0139a32c --- /dev/null +++ b/src/widgets/capture/selectionwidget.h @@ -0,0 +1,79 @@ +// Copyright(c) 2017-2018 Alejandro Sirgo Rica & Contributors +// +// This file is part of Flameshot. +// +// Flameshot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Flameshot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Flameshot. If not, see . + +#pragma once + +#include + +class QPropertyAnimation; + +class SelectionWidget : public QWidget +{ + Q_OBJECT +public: + enum SideType { + TOPLEFT_SIDE, + BOTTONLEFT_SIDE, + TOPRIGHT_SIDE, + BOTTONRIGHT_SIDE, + TOP_SIDE, + BOTTON_SIDE, + RIGHT_SIDE, + LEFT_SIDE, + NO_SIDE, + }; + + explicit SelectionWidget(const QColor &c, QWidget *parent = nullptr); + + SideType getMouseSide(const QPoint &p) const; + QVector handlerAreas(); + + void setGeometryAnimated(const QRect &r); + void saveGeometry(); + QRect savedGeometry(); + +protected: + void paintEvent(QPaintEvent *); + void resizeEvent(QResizeEvent *); + void moveEvent(QMoveEvent *); + +signals: + void animationEnded(); + +public slots: + void updateColor(const QColor &c); + +private: + void updateAreas(); + + QPropertyAnimation *m_animation; + + QColor m_color; + QPoint m_areaOffset; + QPoint m_handleOffset; + QRect m_geometryBackup; + + // naming convention for handles + // T top, B bottom, R Right, L left + // 2 letters: a corner + // 1 letter: the handle on the middle of the corresponding side + QRect m_TLHandle, m_TRHandle, m_BLHandle, m_BRHandle; + QRect m_LHandle, m_THandle, m_RHandle, m_BHandle; + + QRect m_TLArea, m_TRArea, m_BLArea, m_BRArea; + QRect m_LArea, m_TArea, m_RArea, m_BArea; +}; diff --git a/src/widgets/capture/utilitypanel.cpp b/src/widgets/capture/utilitypanel.cpp index 2ce901dc..b059c26c 100644 --- a/src/widgets/capture/utilitypanel.cpp +++ b/src/widgets/capture/utilitypanel.cpp @@ -69,7 +69,6 @@ void UtilityPanel::toggle() { m_hideAnimation->setEndValue(QRect(-width(), 0, 0, height())); m_hideAnimation->start(); } - } void UtilityPanel::initInternalPanel() {