diff --git a/README.md b/README.md index 7e0ec144..6055b43e 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,7 @@ These shortcuts are available in GUI mode: | B | Set Pixalate as the paint tool | | , , , | Move selection 1px | | Shift + , , , | Resize selection 1px | +| Ctrl + Shift + , , , | Symmetrically resize selection 2px | | Esc | Quit capture | | Ctrl + M | Move the selection area | | Ctrl + C | Copy to clipboard | diff --git a/flameshot.example.ini b/flameshot.example.ini index efe4cff1..a77e9ac4 100644 --- a/flameshot.example.ini +++ b/flameshot.example.ini @@ -113,6 +113,10 @@ ;TYPE_RESIZE_LEFT=Shift+Left ;TYPE_RESIZE_RIGHT=Shift+Right ;TYPE_RESIZE_UP=Shift+Up +;TYPE_SYM_RESIZE_DOWN=Ctrl+Shift+Down +;TYPE_SYM_RESIZE_LEFT=Ctrl+Shift+Left +;TYPE_SYM_RESIZE_RIGHT=Ctrl+Shift+Right +;TYPE_SYM_RESIZE_UP=Ctrl+Shift+Up ;TYPE_SAVE=Ctrl+S ;TYPE_SELECTION=S ;TYPE_SELECTIONINDICATOR= diff --git a/src/config/shortcutswidget.cpp b/src/config/shortcutswidget.cpp index 74a0fba0..12938ae4 100644 --- a/src/config/shortcutswidget.cpp +++ b/src/config/shortcutswidget.cpp @@ -176,6 +176,14 @@ void ShortcutsWidget::loadShortcuts() appendShortcut("TYPE_RESIZE_RIGHT", tr("Resize selection right 1px")); appendShortcut("TYPE_RESIZE_UP", tr("Resize selection up 1px")); appendShortcut("TYPE_RESIZE_DOWN", tr("Resize selection down 1px")); + appendShortcut("TYPE_SYM_RESIZE_LEFT", + tr("Symmetrically decrease width by 2px")); + appendShortcut("TYPE_SYM_RESIZE_RIGHT", + tr("Symmetrically increase width by 2px")); + appendShortcut("TYPE_SYM_RESIZE_UP", + tr("Symmetrically increase height by 2px")); + appendShortcut("TYPE_SYM_RESIZE_DOWN", + tr("Symmetrically decrease height by 2px")); appendShortcut("TYPE_SELECT_ALL", tr("Select entire screen")); appendShortcut("TYPE_MOVE_LEFT", tr("Move selection left 1px")); appendShortcut("TYPE_MOVE_RIGHT", tr("Move selection right 1px")); diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp index 23f31d1f..b77b964e 100644 --- a/src/utils/confighandler.cpp +++ b/src/utils/confighandler.cpp @@ -155,6 +155,10 @@ static QMap> recognizedShortcuts = { SHORTCUT("TYPE_RESIZE_RIGHT" , "Shift+Right" ), SHORTCUT("TYPE_RESIZE_UP" , "Shift+Up" ), SHORTCUT("TYPE_RESIZE_DOWN" , "Shift+Down" ), + SHORTCUT("TYPE_SYM_RESIZE_LEFT" , "Ctrl+Shift+Left" ), + SHORTCUT("TYPE_SYM_RESIZE_RIGHT" , "Ctrl+Shift+Right" ), + SHORTCUT("TYPE_SYM_RESIZE_UP" , "Ctrl+Shift+Up" ), + SHORTCUT("TYPE_SYM_RESIZE_DOWN" , "Ctrl+Shift+Down" ), SHORTCUT("TYPE_SELECT_ALL" , "Ctrl+A" ), SHORTCUT("TYPE_MOVE_LEFT" , "Left" ), SHORTCUT("TYPE_MOVE_RIGHT" , "Right" ), diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp index b4a9da24..796bdc55 100644 --- a/src/widgets/capture/capturewidget.cpp +++ b/src/widgets/capture/capturewidget.cpp @@ -1505,6 +1505,18 @@ void CaptureWidget::initShortcuts() newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_RESIZE_DOWN")), m_selection, SLOT(resizeDown())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_SYM_RESIZE_LEFT")), + m_selection, + SLOT(symResizeLeft())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_SYM_RESIZE_RIGHT")), + m_selection, + SLOT(symResizeRight())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_SYM_RESIZE_UP")), + m_selection, + SLOT(symResizeUp())); + newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_SYM_RESIZE_DOWN")), + m_selection, + SLOT(symResizeDown())); newShortcut(QKeySequence(ConfigHandler().shortcut("TYPE_MOVE_LEFT")), m_selection, diff --git a/src/widgets/capture/selectionwidget.cpp b/src/widgets/capture/selectionwidget.cpp index 13919d6f..68c208e2 100644 --- a/src/widgets/capture/selectionwidget.cpp +++ b/src/widgets/capture/selectionwidget.cpp @@ -215,58 +215,149 @@ void SelectionWidget::parentMouseMoveEvent(QMouseEvent* e) } auto geom = geometry(); + float aspectRatio = (float)geom.width() / (float)geom.height(); bool symmetryMod = qApp->keyboardModifiers() & Qt::ShiftModifier; + bool preserveAspect = qApp->keyboardModifiers() & Qt::ControlModifier; QPoint newTopLeft = geom.topLeft(), newBottomRight = geom.bottomRight(); + int oldLeft = newTopLeft.rx(), oldRight = newBottomRight.rx(), + oldTop = newTopLeft.ry(), oldBottom = newBottomRight.ry(); int &newLeft = newTopLeft.rx(), &newRight = newBottomRight.rx(), &newTop = newTopLeft.ry(), &newBottom = newBottomRight.ry(); switch (mouseSide) { case TOPLEFT_SIDE: if (m_activeSide) { - newTopLeft = pos; + if (preserveAspect) { + if ((float)(oldRight - pos.x()) / + (float)(oldBottom - pos.y()) > + aspectRatio) { + /* width longer than expected width, hence increase + * height to compensate for the aspect ratio */ + newLeft = pos.x(); + newTop = + oldBottom - + (int)(((float)(oldRight - pos.x())) / aspectRatio); + } else { + /* height longer than expected height, hence increase + * width to compensate for the aspect ratio */ + newTop = pos.y(); + newLeft = + oldRight - + (int)(((float)(oldBottom - pos.y())) * aspectRatio); + } + } else { + newTopLeft = pos; + } } break; case BOTTOMRIGHT_SIDE: if (m_activeSide) { - newBottomRight = pos; + if (preserveAspect) { + if ((float)(pos.x() - oldLeft) / (float)(pos.y() - oldTop) > + aspectRatio) { + newRight = pos.x(); + newBottom = + oldTop + + (int)(((float)(pos.x() - oldLeft)) / aspectRatio); + } else { + newBottom = pos.y(); + newRight = oldLeft + (int)(((float)(pos.y() - oldTop)) * + aspectRatio); + } + } else { + newBottomRight = pos; + } } break; case TOPRIGHT_SIDE: if (m_activeSide) { - newTop = pos.y(); - newRight = pos.x(); + if (preserveAspect) { + if ((float)(pos.x() - oldLeft) / + (float)(oldBottom - pos.y()) > + aspectRatio) { + newRight = pos.x(); + newTop = + oldBottom - + (int)(((float)(pos.x() - oldLeft)) / aspectRatio); + } else { + newTop = pos.y(); + newRight = + oldLeft + + (int)(((float)(oldBottom - pos.y())) * aspectRatio); + } + } else { + newTop = pos.y(); + newRight = pos.x(); + } } break; case BOTTOMLEFT_SIDE: if (m_activeSide) { - newBottom = pos.y(); - newLeft = pos.x(); + if (preserveAspect) { + if ((float)(oldRight - pos.x()) / + (float)(pos.y() - oldTop) > + aspectRatio) { + newLeft = pos.x(); + newBottom = + oldTop + + (int)(((float)(oldRight - pos.x())) / aspectRatio); + } else { + newBottom = pos.y(); + newLeft = oldRight - (int)(((float)(pos.y() - oldTop)) * + aspectRatio); + } + } else { + newBottom = pos.y(); + newLeft = pos.x(); + } } break; case LEFT_SIDE: if (m_activeSide) { newLeft = pos.x(); + if (preserveAspect) { + /* By default bottom edge moves when dragging sides, this + * behavior feels natural */ + newBottom = oldTop + (int)(((float)(oldRight - pos.x())) / + aspectRatio); + } } break; case RIGHT_SIDE: if (m_activeSide) { newRight = pos.x(); + if (preserveAspect) { + newBottom = oldTop + (int)(((float)(pos.x() - oldLeft)) / + aspectRatio); + } } break; case TOP_SIDE: if (m_activeSide) { newTop = pos.y(); + if (preserveAspect) { + /* By default right edge moves when dragging sides, this + * behavior feels natural */ + newRight = + oldLeft + + (int)(((float)(oldBottom - pos.y()) * aspectRatio)); + } } break; case BOTTOM_SIDE: if (m_activeSide) { newBottom = pos.y(); + if (preserveAspect) { + newRight = oldLeft + + (int)(((float)(pos.y() - oldTop) * aspectRatio)); + } } break; default: if (m_activeSide) { move(this->pos() + pos - m_dragStartPos); m_dragStartPos = pos; + /* do nothing special in case of preserveAspect */ } return; } @@ -369,6 +460,26 @@ void SelectionWidget::resizeDown() setGeometryByKeyboard(geometry().adjusted(0, 0, 0, 1)); } +void SelectionWidget::symResizeLeft() +{ + setGeometryByKeyboard(geometry().adjusted(1, 0, -1, 0)); +} + +void SelectionWidget::symResizeRight() +{ + setGeometryByKeyboard(geometry().adjusted(-1, 0, 1, 0)); +} + +void SelectionWidget::symResizeUp() +{ + setGeometryByKeyboard(geometry().adjusted(0, -1, 0, 1)); +} + +void SelectionWidget::symResizeDown() +{ + setGeometryByKeyboard(geometry().adjusted(0, 1, 0, -1)); +} + void SelectionWidget::updateAreas() { QRect r = rect(); diff --git a/src/widgets/capture/selectionwidget.h b/src/widgets/capture/selectionwidget.h index fcc8dae4..fa7238a4 100644 --- a/src/widgets/capture/selectionwidget.h +++ b/src/widgets/capture/selectionwidget.h @@ -72,6 +72,11 @@ public slots: void resizeUp(); void resizeDown(); + void symResizeLeft(); + void symResizeRight(); + void symResizeUp(); + void symResizeDown(); + private: void updateAreas(); void updateCursor();