Use one capture widget for all screens instead of one per screen

This commit is contained in:
Gres 2020-03-22 11:36:31 +03:00
parent 178c954124
commit 2874177bc4
4 changed files with 116 additions and 88 deletions

View File

@ -6,7 +6,6 @@
#include <QMouseEvent>
#include <QPainter>
#include <QScreen>
CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
const Settings &settings)
@ -19,27 +18,37 @@ CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
setMouseTracking(true);
}
void CaptureAreaSelector::setScreen(QScreen &screen)
void CaptureAreaSelector::activate()
{
const auto geometry = screen.availableGeometry();
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
const auto pixmap =
screen.grabWindow(0, 0, 0, geometry.width(), geometry.height());
#else
const auto pixmap = screen.grabWindow(0, geometry.x(), geometry.y(),
geometry.width(), geometry.height());
#endif
pixmap_ = pixmap;
show();
activateWindow();
}
void CaptureAreaSelector::setPixmap(const QPixmap &pixmap)
{
pixmap_ = pixmap;
auto palette = this->palette();
palette.setBrush(backgroundRole(), pixmap);
setPalette(palette);
setGeometry(geometry);
updateHelp();
setGeometry(pixmap_.rect());
}
void CaptureAreaSelector::updateHelp()
void CaptureAreaSelector::setScreenRects(const std::vector<QRect> &screens)
{
auto helpRect = fontMetrics().boundingRect({}, 0, help_);
helpRect.setSize(helpRect.size() * 1.4);
helpRects_.clear();
helpRects_.reserve(screens.size());
for (const auto &screen : screens) {
auto possible = std::vector<QRect>(2, helpRect);
possible[0].moveTopLeft(screen.topLeft());
possible[1].moveTopRight(screen.topRight());
helpRects_.push_back({possible[0], possible});
}
}
void CaptureAreaSelector::updateSettings()
{
LanguageCodes languages;
const auto source = languages.findById(settings_.sourceLanguage);
@ -52,14 +61,6 @@ void CaptureAreaSelector::updateHelp()
help_ = tr(R"(Recognition language: %1
Translation language: %2)")
.arg(sourceName, targetName);
const auto rect = this->rect();
auto helpRect = fontMetrics().boundingRect({}, 0, help_);
helpRect.setSize(helpRect.size() * 1.4);
helpRects_ = std::vector<QRect>(2, helpRect);
helpRects_[0].moveTopLeft(rect.topLeft());
helpRects_[1].moveTopRight(rect.topRight());
currentHelpRect_ = helpRects_[0];
}
void CaptureAreaSelector::showEvent(QShowEvent * /*event*/)
@ -77,22 +78,15 @@ void CaptureAreaSelector::paintEvent(QPaintEvent * /*event*/)
{
QPainter painter(this);
const auto cursor = mapFromGlobal(QCursor::pos());
if (currentHelpRect_.contains(cursor)) {
for (const auto &rect : helpRects_) {
if (!rect.contains(cursor)) {
currentHelpRect_ = rect;
break;
}
}
}
for (auto &screenHelp : helpRects_) {
painter.setBrush(QBrush(QColor(200, 200, 200, 200)));
painter.setPen(Qt::NoPen);
painter.drawRect(currentHelpRect_);
painter.drawRect(screenHelp.current);
painter.setBrush({});
painter.setPen(Qt::black);
painter.drawText(currentHelpRect_, Qt::AlignCenter, help_);
painter.drawText(screenHelp.current, Qt::AlignCenter, help_);
}
auto selection = QRect(startSelectPos_, currentSelectPos_).normalized();
if (!selection.isValid())
@ -103,6 +97,28 @@ void CaptureAreaSelector::paintEvent(QPaintEvent * /*event*/)
painter.drawRect(selection);
}
bool CaptureAreaSelector::updateCurrentHelpRects()
{
const auto cursor = mapFromGlobal(QCursor::pos());
auto changed = false;
for (auto &screenHelp : helpRects_) {
if (!screenHelp.current.contains(cursor))
continue;
for (const auto &screenPossible : screenHelp.possible) {
if (screenPossible.contains(cursor))
continue;
screenHelp.current = screenPossible;
changed = true;
break;
}
}
return changed;
}
void CaptureAreaSelector::mousePressEvent(QMouseEvent *event)
{
if (startSelectPos_.isNull())
@ -112,12 +128,13 @@ void CaptureAreaSelector::mousePressEvent(QMouseEvent *event)
void CaptureAreaSelector::mouseMoveEvent(QMouseEvent *event)
{
if (startSelectPos_.isNull()) {
if (currentHelpRect_.contains(event->pos()))
if (updateCurrentHelpRects())
update();
return;
}
currentSelectPos_ = event->pos();
updateCurrentHelpRects();
update();
}

View File

@ -4,8 +4,6 @@
#include <QWidget>
class QScreen;
class CaptureAreaSelector : public QWidget
{
Q_OBJECT
@ -13,7 +11,10 @@ class CaptureAreaSelector : public QWidget
public:
CaptureAreaSelector(Capturer &capturer, const Settings &settings);
void setScreen(QScreen &screen);
void activate();
void setPixmap(const QPixmap &pixmap);
void setScreenRects(const std::vector<QRect> &screens);
void updateSettings();
protected:
void showEvent(QShowEvent *event) override;
@ -24,7 +25,12 @@ protected:
void paintEvent(QPaintEvent *event) override;
private:
void updateHelp();
struct HelpRect {
QRect current;
std::vector<QRect> possible;
};
bool updateCurrentHelpRects();
Capturer &capturer_;
const Settings &settings_;
@ -32,6 +38,5 @@ private:
QPoint startSelectPos_;
QPoint currentSelectPos_;
QString help_;
QRect currentHelpRect_;
std::vector<QRect> helpRects_;
std::vector<HelpRect> helpRects_;
};

View File

@ -1,36 +1,75 @@
#include "capturer.h"
#include "captureareaselector.h"
#include "debug.h"
#include "manager.h"
#include "settings.h"
#include "task.h"
#include <QApplication>
#include <QPainter>
#include <QScreen>
Capturer::Capturer(Manager &manager, const Settings &settings)
: manager_(manager)
, settings_(settings)
, selector_(std::make_unique<CaptureAreaSelector>(*this, settings_))
{
}
Capturer::~Capturer() = default;
void Capturer::capture()
{
showOverlays(true);
updatePixmap();
SOFT_ASSERT(selector_, return );
selector_->activate();
}
void Capturer::updatePixmap()
{
const auto screens = QApplication::screens();
std::vector<QRect> screenRects;
screenRects.reserve(screens.size());
QRect rect;
for (const auto screen : screens) {
const auto geometry = screen->geometry();
screenRects.push_back(geometry);
rect |= geometry;
}
QPixmap combined(rect.size());
QPainter p(&combined);
for (const auto screen : screens) {
const auto geometry = screen->geometry();
const auto pixmap =
screen->grabWindow(0, 0, 0, geometry.width(), geometry.height());
p.drawPixmap(geometry, pixmap);
}
SOFT_ASSERT(selector_, return );
selector_->setPixmap(combined);
selector_->setScreenRects(screenRects);
}
void Capturer::repeatCapture()
{
showOverlays(false);
SOFT_ASSERT(selector_, return );
selector_->activate();
}
void Capturer::updateSettings()
{
SOFT_ASSERT(selector_, return );
selector_->updateSettings();
}
void Capturer::captured(const TaskPtr &task)
{
hideOverlays();
// TODO respect more overlay's options
// TODO process modifiers
SOFT_ASSERT(selector_, return );
selector_->hide();
task->translators = settings_.translators;
task->sourceLanguage = settings_.sourceLanguage;
if (settings_.doTranslation)
@ -40,40 +79,7 @@ void Capturer::captured(const TaskPtr &task)
void Capturer::canceled()
{
hideOverlays();
SOFT_ASSERT(selector_, return );
selector_->hide();
manager_.captureCanceled();
}
void Capturer::showOverlays(bool capturePixmap)
{
const auto screens = QApplication::screens();
const auto screensSize = screens.size();
int overlaysSize = selectors_.size();
if (screensSize > overlaysSize)
selectors_.reserve(screensSize);
for (auto i = 0, end = screensSize; i < end; ++i) {
if (i == overlaysSize) {
selectors_.push_back(new CaptureAreaSelector(*this, settings_));
++overlaysSize;
}
const auto screen = screens[i];
auto &overlay = selectors_[i];
overlay->hide();
if (capturePixmap)
overlay->setScreen(*screen);
overlay->show();
overlay->activateWindow();
}
if (screensSize < overlaysSize) {
for (auto i = overlaysSize - 1; i >= screensSize; --i)
selectors_[i]->deleteLater();
}
}
void Capturer::hideOverlays()
{
for (const auto &overlay : selectors_) overlay->hide();
}

View File

@ -8,6 +8,7 @@ class Capturer
{
public:
Capturer(Manager &manager, const Settings &settings);
~Capturer();
void capture();
void repeatCapture();
@ -17,10 +18,9 @@ public:
void canceled();
private:
void showOverlays(bool capturePixmap);
void hideOverlays();
void updatePixmap();
Manager &manager_;
const Settings &settings_;
std::vector<CaptureAreaSelector *> selectors_;
std::unique_ptr<CaptureAreaSelector> selector_;
};