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() {