diff --git a/data/translations/Internationalization_uk.ts b/data/translations/Internationalization_uk.ts
index 2b120fcb58..48bc98bc09 100644
--- a/data/translations/Internationalization_uk.ts
+++ b/data/translations/Internationalization_uk.ts
@@ -2594,7 +2594,7 @@ You can find me in the system tray.
Screenshot cancelled
-
+ Знімок екрана скасовано
diff --git a/src/config/generalconf.cpp b/src/config/generalconf.cpp
index c76f2fa076..723a166de1 100644
--- a/src/config/generalconf.cpp
+++ b/src/config/generalconf.cpp
@@ -924,11 +924,12 @@ void GeneralConf::setInsecurePixelate(bool checked)
void GeneralConf::initCaptureActiveMonitor()
{
m_captureActiveMonitor = new QCheckBox(
- tr("Capture active monitor in X11 (skip monitor selection)"), this);
+ tr("Capture active monitor in X11 and Windows (skip monitor selection)"),
+ this);
m_captureActiveMonitor->setToolTip(
tr("Automatically capture the monitor where the cursor is located "
"instead of showing the monitor selection dialog. "
- "This feature is not supported on Wayland."));
+ "This feature is not supported on macOS and Wayland."));
m_scrollAreaLayout->addWidget(m_captureActiveMonitor);
connect(m_captureActiveMonitor,
diff --git a/src/core/capturerequest.cpp b/src/core/capturerequest.cpp
index 85d1f71039..0141684b7e 100644
--- a/src/core/capturerequest.cpp
+++ b/src/core/capturerequest.cpp
@@ -2,12 +2,7 @@
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include "capturerequest.h"
-#include "config/cacheutils.h"
-#include "utils/confighandler.h"
-#include
-#include
-#include
#include
#include
@@ -21,14 +16,7 @@ CaptureRequest::CaptureRequest(CaptureRequest::CaptureMode mode,
, m_data(std::move(data))
, m_selectedMonitor(-1)
, m_hasSelectedMonitor(false)
-{
-
- ConfigHandler config;
- if (m_mode == CaptureRequest::CaptureMode::GRAPHICAL_MODE &&
- config.saveLastRegion()) {
- setInitialSelection(getLastRegion());
- }
-}
+{}
CaptureRequest::CaptureMode CaptureRequest::captureMode() const
{
diff --git a/src/core/flameshot.cpp b/src/core/flameshot.cpp
index 6f96bddb5a..c172f76e88 100644
--- a/src/core/flameshot.cpp
+++ b/src/core/flameshot.cpp
@@ -42,6 +42,7 @@ constexpr const char* visibleInDockProperty = "_visibleInDock";
#include
#endif
+#include "config/cacheutils.h"
#include "config/configresolver.h"
#include "config/configwindow.h"
#include "core/qguiappcurrentscreen.h"
@@ -125,6 +126,13 @@ CaptureWidget* Flameshot::gui(const CaptureRequest& req)
return nullptr;
}
+ CaptureRequest request = req;
+ if (request.captureMode() == CaptureRequest::GRAPHICAL_MODE &&
+ request.initialSelection().isNull() &&
+ ConfigHandler().saveLastRegion()) {
+ request.setInitialSelection(getLastRegion());
+ }
+
#if defined(Q_OS_MACOS)
// This is required on MacOS because of Mission Control. If you'll switch to
// another Desktop you cannot take a new screenshot from the tray, you have
@@ -157,7 +165,7 @@ CaptureWidget* Flameshot::gui(const CaptureRequest& req)
return nullptr;
}
- m_captureWindow = new CaptureWidget(req);
+ m_captureWindow = new CaptureWidget(request);
#ifdef Q_OS_WIN
m_captureWindow->show();
diff --git a/src/tools/capturetool.h b/src/tools/capturetool.h
index 34d4706e36..77e4b22b14 100644
--- a/src/tools/capturetool.h
+++ b/src/tools/capturetool.h
@@ -78,7 +78,9 @@ class CaptureTool : public QObject
// increase tool size for all tools
REQ_INCREASE_TOOL_SIZE,
// decrease tool size for all tools
- REQ_DECREASE_TOOL_SIZE
+ REQ_DECREASE_TOOL_SIZE,
+ // Commit the active tool.
+ REQ_COMMIT_CURRENT_TOOL
};
explicit CaptureTool(QObject* parent = nullptr)
diff --git a/src/tools/text/texttool.cpp b/src/tools/text/texttool.cpp
index 46710502d6..d028c1b18e 100644
--- a/src/tools/text/texttool.cpp
+++ b/src/tools/text/texttool.cpp
@@ -108,6 +108,12 @@ QWidget* TextTool::widget()
m_widget->setText(m_text);
m_widget->selectAll();
connect(m_widget, &TextWidget::textUpdated, this, &TextTool::updateText);
+ connect(
+ m_widget,
+ &TextWidget::editingFinished,
+ this,
+ [this]() { emit requestAction(REQ_COMMIT_CURRENT_TOOL); },
+ Qt::QueuedConnection);
return m_widget;
}
diff --git a/src/tools/text/textwidget.cpp b/src/tools/text/textwidget.cpp
index bbc6a115cb..9fdb73e22a 100644
--- a/src/tools/text/textwidget.cpp
+++ b/src/tools/text/textwidget.cpp
@@ -3,6 +3,9 @@
#include "textwidget.h"
+#include
+#include
+
TextWidget::TextWidget(QWidget* parent)
: QTextEdit(parent)
{
@@ -14,6 +17,30 @@ TextWidget::TextWidget(QWidget* parent)
setContextMenuPolicy(Qt::NoContextMenu);
}
+bool TextWidget::event(QEvent* e)
+{
+ if (e->type() == QEvent::ShortcutOverride) {
+ auto* keyEvent = static_cast(e);
+ if (keyEvent->key() == Qt::Key_Escape) {
+ keyEvent->accept();
+ return true;
+ }
+ }
+
+ return QTextEdit::event(e);
+}
+
+void TextWidget::keyPressEvent(QKeyEvent* e)
+{
+ if (e->key() == Qt::Key_Escape) {
+ emit editingFinished();
+ e->accept();
+ return;
+ }
+
+ QTextEdit::keyPressEvent(e);
+}
+
void TextWidget::showEvent(QShowEvent* e)
{
QFont font;
diff --git a/src/tools/text/textwidget.h b/src/tools/text/textwidget.h
index c6d4323a6b..7eac653e7d 100644
--- a/src/tools/text/textwidget.h
+++ b/src/tools/text/textwidget.h
@@ -5,6 +5,9 @@
#include
+class QEvent;
+class QKeyEvent;
+
class TextWidget : public QTextEdit
{
Q_OBJECT
@@ -15,11 +18,14 @@ class TextWidget : public QTextEdit
void setFont(const QFont& f);
protected:
- void showEvent(QShowEvent* e);
- void resizeEvent(QResizeEvent* e);
+ bool event(QEvent* e) override;
+ void keyPressEvent(QKeyEvent* e) override;
+ void showEvent(QShowEvent* e) override;
+ void resizeEvent(QResizeEvent* e) override;
signals:
void textUpdated(const QString& s);
+ void editingFinished();
public slots:
void setTextColor(const QColor& c);
diff --git a/src/utils/monitorpreview.cpp b/src/utils/monitorpreview.cpp
index 413df7a537..5ae85a60b6 100644
--- a/src/utils/monitorpreview.cpp
+++ b/src/utils/monitorpreview.cpp
@@ -16,38 +16,48 @@ MonitorPreview::MonitorPreview(int monitorIndex,
QWidget* parent)
: QWidget(parent)
, m_monitorIndex(monitorIndex)
+ , m_selected(false)
+ , m_mouseHovered(false)
+ , m_imageLabel(nullptr)
+ , m_keyLabel(nullptr)
+ , m_textLabel(nullptr)
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(10, 10, 10, 10);
layout->setSpacing(10);
- QLabel* imageLabel = new QLabel(this);
- imageLabel->setAlignment(Qt::AlignCenter);
- imageLabel->setPixmap(thumbnail);
- imageLabel->setStyleSheet(
- "QLabel { background-color: black; border-radius: 8px; }");
- imageLabel->setScaledContents(false);
-
- m_textLabel = new QLabel(tr("Monitor %1: %2\nClick to select")
- .arg(m_monitorIndex + 1)
- .arg(screen->name()),
- this);
+ m_imageLabel = new QLabel(this);
+ m_imageLabel->setAlignment(Qt::AlignCenter);
+ m_imageLabel->setPixmap(thumbnail);
+ m_imageLabel->setScaledContents(false);
+
+ if (m_monitorIndex < 9) {
+ m_keyLabel =
+ new QLabel(QString::number(m_monitorIndex + 1), m_imageLabel);
+ m_keyLabel->setAlignment(Qt::AlignCenter);
+ m_keyLabel->setFixedSize(28, 28);
+ m_keyLabel->move(8, 8);
+ m_keyLabel->raise();
+ m_keyLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
+ }
+
+ const QString labelText =
+ m_monitorIndex < 9 ? tr("Monitor %1: %2\nClick or press %1 to select")
+ .arg(m_monitorIndex + 1)
+ .arg(screen->name())
+ : tr("Monitor %1: %2\nClick to select")
+ .arg(m_monitorIndex + 1)
+ .arg(screen->name());
+ m_textLabel = new QLabel(labelText, this);
m_textLabel->setAlignment(Qt::AlignCenter);
- layout->addWidget(imageLabel);
+ layout->addWidget(m_imageLabel);
layout->addWidget(m_textLabel);
m_uiColor = ConfigHandler().uiColor();
m_contrastColor = ColorUtils::contrastColor(m_uiColor);
- // Apply initial themed background to text label only
- QString normalStyle =
- QString("QLabel { color: white; background-color: rgba(%1, %2, %3, 200); "
- "padding: 5px; font-size: 12pt; border-radius: 3px; }")
- .arg(m_uiColor.red())
- .arg(m_uiColor.green())
- .arg(m_uiColor.blue());
- m_textLabel->setStyleSheet(normalStyle);
+ updateStyle();
}
void MonitorPreview::mousePressEvent(QMouseEvent* event)
@@ -59,24 +69,59 @@ void MonitorPreview::mousePressEvent(QMouseEvent* event)
void MonitorPreview::enterEvent(QEnterEvent* event)
{
Q_UNUSED(event)
- QColor hoverBg = m_contrastColor;
- QString hoverStyle =
- QString("QLabel { color: white; background-color: rgba(%1, %2, %3, 220); "
- "padding: 5px; font-size: 12pt; border-radius: 3px; }")
- .arg(hoverBg.red())
- .arg(hoverBg.green())
- .arg(hoverBg.blue());
- m_textLabel->setStyleSheet(hoverStyle);
+ m_mouseHovered = true;
+ updateStyle();
}
void MonitorPreview::leaveEvent(QEvent* event)
{
Q_UNUSED(event)
- QString normalStyle =
- QString("QLabel { color: white; background-color: rgba(%1, %2, %3, 200); "
+ m_mouseHovered = false;
+ updateStyle();
+}
+
+void MonitorPreview::setSelected(bool selected)
+{
+ if (m_selected == selected) {
+ return;
+ }
+
+ m_selected = selected;
+ updateStyle();
+}
+
+void MonitorPreview::updateStyle()
+{
+ const bool highlighted = m_selected || m_mouseHovered;
+ const QColor backgroundColor = highlighted ? m_contrastColor : m_uiColor;
+ const int textAlpha = highlighted ? 220 : 200;
+ const int borderAlpha = highlighted ? 255 : 0;
+
+ QString textStyle =
+ QString("QLabel { color: white; background-color: rgba(%1, %2, %3, %4); "
"padding: 5px; font-size: 12pt; border-radius: 3px; }")
- .arg(m_uiColor.red())
- .arg(m_uiColor.green())
- .arg(m_uiColor.blue());
- m_textLabel->setStyleSheet(normalStyle);
+ .arg(backgroundColor.red())
+ .arg(backgroundColor.green())
+ .arg(backgroundColor.blue())
+ .arg(textAlpha);
+ m_textLabel->setStyleSheet(textStyle);
+
+ QString imageStyle =
+ QString("QLabel { background-color: black; border: 2px solid "
+ "rgba(%1, %2, %3, %4); border-radius: 8px; }")
+ .arg(backgroundColor.red())
+ .arg(backgroundColor.green())
+ .arg(backgroundColor.blue())
+ .arg(borderAlpha);
+ m_imageLabel->setStyleSheet(imageStyle);
+
+ if (m_keyLabel) {
+ QString keyStyle = QString("QLabel { color: white; font-weight: bold; "
+ "background-color: rgba(%1, %2, %3, 230); "
+ "border-radius: 14px; }")
+ .arg(backgroundColor.red())
+ .arg(backgroundColor.green())
+ .arg(backgroundColor.blue());
+ m_keyLabel->setStyleSheet(keyStyle);
+ }
}
diff --git a/src/utils/monitorpreview.h b/src/utils/monitorpreview.h
index 78e911d925..196e9df0d2 100644
--- a/src/utils/monitorpreview.h
+++ b/src/utils/monitorpreview.h
@@ -20,6 +20,7 @@ class MonitorPreview : public QWidget
QWidget* parent = nullptr);
int monitorIndex() const { return m_monitorIndex; }
+ void setSelected(bool selected);
signals:
void monitorSelected(int index);
@@ -30,8 +31,14 @@ class MonitorPreview : public QWidget
void leaveEvent(QEvent* event) override;
private:
+ void updateStyle();
+
int m_monitorIndex;
+ bool m_selected;
+ bool m_mouseHovered;
QColor m_uiColor;
QColor m_contrastColor;
+ QLabel* m_imageLabel;
+ QLabel* m_keyLabel;
QLabel* m_textLabel;
};
diff --git a/src/utils/screengrabber.cpp b/src/utils/screengrabber.cpp
index 3b87c49703..0cafea6d3b 100644
--- a/src/utils/screengrabber.cpp
+++ b/src/utils/screengrabber.cpp
@@ -40,6 +40,7 @@ bool ScreenGrabber::m_monitorSelectionActive = false;
ScreenGrabber::ScreenGrabber(QObject* parent)
: QObject(parent)
, m_selectedMonitor(-1)
+ , m_highlightedMonitorPreview(-1)
, m_monitorSelectionLoop(nullptr)
, m_userCancelled(false)
{
@@ -178,6 +179,7 @@ QPixmap ScreenGrabber::selectMonitorAndCrop(const QPixmap& fullScreenshot,
// Only screenshot the monitor where the tray activated the screenshot
return cropToMonitor(fullScreenshot, 0);
#else
+
// If there's only one monitor, skip selection
const QList screens = QGuiApplication::screens();
if (screens.size() == 1) {
@@ -224,6 +226,8 @@ QPixmap ScreenGrabber::selectMonitorAndCrop(const QPixmap& fullScreenshot,
m_monitorSelectionLoop = nullptr;
delete container;
+ m_monitorPreviews.clear();
+ m_highlightedMonitorPreview = -1;
m_monitorSelectionActive = false;
if (m_selectedMonitor >= 0) {
@@ -251,6 +255,12 @@ QPixmap ScreenGrabber::grabEntireDesktop(bool& ok, int preSelectedMonitor)
ok = false;
return QPixmap();
}
+ m_selectedMonitor = QGuiApplication::screens().indexOf(currentScreen);
+ if (m_selectedMonitor < 0) {
+ AbstractLogger::error() << tr("Unable to get current screen");
+ ok = false;
+ return QPixmap();
+ }
const QRect geom = currentScreen->geometry();
screenshot = currentScreen->grabWindow(
wid, geom.x(), geom.y(), geom.width(), geom.height());
@@ -393,6 +403,8 @@ QScreen* ScreenGrabber::getSelectedScreen() const
QWidget* ScreenGrabber::createMonitorPreviews(const QPixmap& fullScreenshot)
{
const QList screens = QGuiApplication::screens();
+ m_monitorPreviews.clear();
+ m_highlightedMonitorPreview = -1;
#ifdef FLAMESHOT_DEBUG_CAPTURE
qDebug() << tr("=== All Screen Information ===");
@@ -441,17 +453,24 @@ QWidget* ScreenGrabber::createMonitorPreviews(const QPixmap& fullScreenshot)
MonitorPreview* preview =
new MonitorPreview(i, screen, thumbnail, monitorPreviews);
- connect(
- preview, &MonitorPreview::monitorSelected, this, [this](int index) {
- m_selectedMonitor = index;
- if (m_monitorSelectionLoop) {
- m_monitorSelectionLoop->quit();
- }
- });
+ connect(preview,
+ &MonitorPreview::monitorSelected,
+ this,
+ [this](int index) { selectMonitor(index); });
+ m_monitorPreviews.append(preview);
containerLayout->addWidget(preview);
}
+ int initialPreviewIndex = 0;
+ QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
+ int currentMonitorIndex = screens.indexOf(currentScreen);
+ int currentPreviewIndex = previewIndexForMonitor(currentMonitorIndex);
+ if (currentPreviewIndex >= 0) {
+ initialPreviewIndex = currentPreviewIndex;
+ }
+ setHighlightedMonitorPreview(initialPreviewIndex);
+
monitorPreviews->setLayout(containerLayout);
monitorPreviews->adjustSize();
@@ -462,21 +481,118 @@ QWidget* ScreenGrabber::createMonitorPreviews(const QPixmap& fullScreenshot)
center.y() - monitorPreviews->height() / 2);
monitorPreviews->show();
+ monitorPreviews->raise();
+ monitorPreviews->activateWindow();
+ monitorPreviews->setFocus(Qt::ActiveWindowFocusReason);
return monitorPreviews;
}
+void ScreenGrabber::cancelMonitorSelection()
+{
+ m_selectedMonitor = -1;
+ m_userCancelled = true;
+ if (m_monitorSelectionLoop) {
+ m_monitorSelectionLoop->quit();
+ }
+}
+
+void ScreenGrabber::moveHighlightedMonitorPreview(int offset)
+{
+ if (m_monitorPreviews.isEmpty()) {
+ return;
+ }
+
+ int nextPreviewIndex = m_highlightedMonitorPreview;
+ if (nextPreviewIndex < 0) {
+ nextPreviewIndex = 0;
+ } else {
+ nextPreviewIndex += offset;
+ }
+
+ setHighlightedMonitorPreview(nextPreviewIndex);
+}
+
+int ScreenGrabber::previewIndexForMonitor(int monitorIndex) const
+{
+ for (int i = 0; i < m_monitorPreviews.size(); ++i) {
+ if (m_monitorPreviews[i]->monitorIndex() == monitorIndex) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void ScreenGrabber::selectHighlightedMonitorPreview()
+{
+ if (m_highlightedMonitorPreview < 0 ||
+ m_highlightedMonitorPreview >= m_monitorPreviews.size()) {
+ return;
+ }
+
+ selectMonitor(
+ m_monitorPreviews[m_highlightedMonitorPreview]->monitorIndex());
+}
+
+void ScreenGrabber::selectMonitor(int monitorIndex)
+{
+ m_selectedMonitor = monitorIndex;
+ if (m_monitorSelectionLoop) {
+ m_monitorSelectionLoop->quit();
+ }
+}
+
+void ScreenGrabber::setHighlightedMonitorPreview(int previewIndex)
+{
+ if (m_monitorPreviews.isEmpty()) {
+ m_highlightedMonitorPreview = -1;
+ return;
+ }
+
+ const int previewCount = m_monitorPreviews.size();
+ int normalizedIndex = previewIndex % previewCount;
+ if (normalizedIndex < 0) {
+ normalizedIndex += previewCount;
+ }
+
+ for (int i = 0; i < previewCount; ++i) {
+ m_monitorPreviews[i]->setSelected(i == normalizedIndex);
+ }
+ m_highlightedMonitorPreview = normalizedIndex;
+}
+
bool ScreenGrabber::eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast(event);
- if (keyEvent->key() == Qt::Key_Escape) {
- // User cancelled selection
- m_selectedMonitor = -1;
- m_userCancelled = true;
- if (m_monitorSelectionLoop) {
- m_monitorSelectionLoop->quit();
- }
- return true;
+ switch (keyEvent->key()) {
+ case Qt::Key_Escape:
+ cancelMonitorSelection();
+ return true;
+ case Qt::Key_Left:
+ case Qt::Key_Up:
+ case Qt::Key_Backtab:
+ moveHighlightedMonitorPreview(-1);
+ return true;
+ case Qt::Key_Right:
+ case Qt::Key_Down:
+ case Qt::Key_Tab:
+ moveHighlightedMonitorPreview(1);
+ return true;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Space:
+ selectHighlightedMonitorPreview();
+ return true;
+ default:
+ if (keyEvent->key() >= Qt::Key_1 &&
+ keyEvent->key() <= Qt::Key_9) {
+ int monitorIndex = keyEvent->key() - Qt::Key_1;
+ if (previewIndexForMonitor(monitorIndex) >= 0) {
+ selectMonitor(monitorIndex);
+ }
+ return true;
+ }
}
}
return QObject::eventFilter(obj, event);
diff --git a/src/utils/screengrabber.h b/src/utils/screengrabber.h
index 3b1e475186..7ca6997462 100644
--- a/src/utils/screengrabber.h
+++ b/src/utils/screengrabber.h
@@ -13,6 +13,7 @@
class QEventLoop;
class QWidget;
+class MonitorPreview;
class ScreenGrabber : public QObject
{
@@ -36,6 +37,12 @@ class ScreenGrabber : public QObject
private:
void adjustDevicePixelRatio(QPixmap& pixmap);
QWidget* createMonitorPreviews(const QPixmap& fullScreenshot);
+ void cancelMonitorSelection();
+ void moveHighlightedMonitorPreview(int offset);
+ int previewIndexForMonitor(int monitorIndex) const;
+ void selectHighlightedMonitorPreview();
+ void selectMonitor(int monitorIndex);
+ void setHighlightedMonitorPreview(int previewIndex);
QPixmap cropToMonitor(const QPixmap& fullScreenshot, int monitorIndex);
QPixmap windowsScreenshot(int wid);
QPixmap x11LegacyScreenshot();
@@ -43,6 +50,8 @@ class ScreenGrabber : public QObject
DesktopInfo m_info;
QPixmap Screenshot;
int m_selectedMonitor;
+ int m_highlightedMonitorPreview;
+ QList m_monitorPreviews;
QEventLoop* m_monitorSelectionLoop;
bool m_userCancelled;
static bool m_monitorSelectionActive;
diff --git a/src/widgets/capture/capturewidget.cpp b/src/widgets/capture/capturewidget.cpp
index 73222e3dfe..8c2107b1fd 100644
--- a/src/widgets/capture/capturewidget.cpp
+++ b/src/widgets/capture/capturewidget.cpp
@@ -1494,6 +1494,18 @@ void CaptureWidget::handleToolSignal(CaptureTool::Request r)
case CaptureTool::REQ_DECREASE_TOOL_SIZE:
setToolSize(m_context.toolSize - 1);
break;
+ case CaptureTool::REQ_COMMIT_CURRENT_TOOL: {
+ const bool editingExistingTool =
+ m_activeTool && m_activeTool->editMode();
+ if (commitCurrentTool()) {
+ if (editingExistingTool) {
+ m_panel->setToolWidget(nullptr);
+ }
+ drawToolsData();
+ updateLayersPanel();
+ }
+ break;
+ }
default:
break;
}