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