Add ability to capture multiple areas
This commit is contained in:
		
							parent
							
								
									5f4ef955e1
								
							
						
					
					
						commit
						8d2e726715
					
				@ -17,6 +17,7 @@ TaskPtr CaptureArea::task(const QPixmap &pixmap) const
 | 
				
			|||||||
    return {};
 | 
					    return {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto task = std::make_shared<Task>();
 | 
					  auto task = std::make_shared<Task>();
 | 
				
			||||||
 | 
					  task->generation = generation_;
 | 
				
			||||||
  task->captured = pixmap.copy(rect_);
 | 
					  task->captured = pixmap.copy(rect_);
 | 
				
			||||||
  task->capturePoint = rect_.topLeft();
 | 
					  task->capturePoint = rect_.topLeft();
 | 
				
			||||||
  task->sourceLanguage = sourceLanguage_;
 | 
					  task->sourceLanguage = sourceLanguage_;
 | 
				
			||||||
@ -28,6 +29,11 @@ TaskPtr CaptureArea::task(const QPixmap &pixmap) const
 | 
				
			|||||||
  return task;
 | 
					  return task;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CaptureArea::setGeneration(uint generation)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  generation_ = generation;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool CaptureArea::isValid() const
 | 
					bool CaptureArea::isValid() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return !(rect_.width() < 3 || rect_.height() < 3);
 | 
					  return !(rect_.width() < 3 || rect_.height() < 3);
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ public:
 | 
				
			|||||||
  CaptureArea(const QRect& rect, const Settings& settings);
 | 
					  CaptureArea(const QRect& rect, const Settings& settings);
 | 
				
			||||||
  TaskPtr task(const QPixmap& pixmap) const;
 | 
					  TaskPtr task(const QPixmap& pixmap) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setGeneration(uint generation);
 | 
				
			||||||
  bool isValid() const;
 | 
					  bool isValid() const;
 | 
				
			||||||
  bool isLocked() const;
 | 
					  bool isLocked() const;
 | 
				
			||||||
  const QRect& rect() const;
 | 
					  const QRect& rect() const;
 | 
				
			||||||
@ -23,6 +24,7 @@ public:
 | 
				
			|||||||
private:
 | 
					private:
 | 
				
			||||||
  friend class CaptureAreaEditor;
 | 
					  friend class CaptureAreaEditor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Generation generation_{};
 | 
				
			||||||
  QRect rect_;
 | 
					  QRect rect_;
 | 
				
			||||||
  bool doTranslation_;
 | 
					  bool doTranslation_;
 | 
				
			||||||
  bool isLocked_{false};
 | 
					  bool isLocked_{false};
 | 
				
			||||||
 | 
				
			|||||||
@ -4,12 +4,21 @@
 | 
				
			|||||||
#include "capturer.h"
 | 
					#include "capturer.h"
 | 
				
			||||||
#include "debug.h"
 | 
					#include "debug.h"
 | 
				
			||||||
#include "geometryutils.h"
 | 
					#include "geometryutils.h"
 | 
				
			||||||
#include "languagecodes.h"
 | 
					 | 
				
			||||||
#include "settings.h"
 | 
					#include "settings.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QMenu>
 | 
				
			||||||
#include <QMouseEvent>
 | 
					#include <QMouseEvent>
 | 
				
			||||||
#include <QPainter>
 | 
					#include <QPainter>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool locked(const std::shared_ptr<CaptureArea> &area)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return area->isLocked();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static bool notLocked(const std::shared_ptr<CaptureArea> &area)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return !area->isLocked();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
 | 
					CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
 | 
				
			||||||
                                         const Settings &settings,
 | 
					                                         const Settings &settings,
 | 
				
			||||||
                                         const CommonModels &models,
 | 
					                                         const CommonModels &models,
 | 
				
			||||||
@ -18,6 +27,7 @@ CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
 | 
				
			|||||||
  , settings_(settings)
 | 
					  , settings_(settings)
 | 
				
			||||||
  , pixmap_(pixmap)
 | 
					  , pixmap_(pixmap)
 | 
				
			||||||
  , editor_(std::make_unique<CaptureAreaEditor>(models, this))
 | 
					  , editor_(std::make_unique<CaptureAreaEditor>(models, this))
 | 
				
			||||||
 | 
					  , contextMenu_(new QMenu(this))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
 | 
					  setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
 | 
				
			||||||
                 Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
 | 
					                 Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
 | 
				
			||||||
@ -27,7 +37,20 @@ CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  help_ = tr(R"(Right click on selection - customize
 | 
					  help_ = tr(R"(Right click on selection - customize
 | 
				
			||||||
Left click on selection - process
 | 
					Left click on selection - process
 | 
				
			||||||
Esc - cancel)");
 | 
					Enter - process all selections
 | 
				
			||||||
 | 
					Esc - cancel
 | 
				
			||||||
 | 
					Ctrl - keep selecting)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    auto action = contextMenu_->addAction(tr("Capture all"));
 | 
				
			||||||
 | 
					    connect(action, &QAction::triggered,  //
 | 
				
			||||||
 | 
					            this, &CaptureAreaSelector::captureAll);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    auto action = contextMenu_->addAction(tr("Cancel"));
 | 
				
			||||||
 | 
					    connect(action, &QAction::triggered,  //
 | 
				
			||||||
 | 
					            this, &CaptureAreaSelector::cancel);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CaptureAreaSelector::~CaptureAreaSelector() = default;
 | 
					CaptureAreaSelector::~CaptureAreaSelector() = default;
 | 
				
			||||||
@ -41,13 +64,36 @@ void CaptureAreaSelector::activate()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool CaptureAreaSelector::hasLocked() const
 | 
					bool CaptureAreaSelector::hasLocked() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return area_ && area_->isLocked();
 | 
					  const auto it = std::find_if(areas_.cbegin(), areas_.cend(), locked);
 | 
				
			||||||
 | 
					  return it != areas_.cend();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::captureLocked()
 | 
					void CaptureAreaSelector::captureLocked()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SOFT_ASSERT(hasLocked(), return );
 | 
					  SOFT_ASSERT(hasLocked(), return );
 | 
				
			||||||
  capturer_.selected(*area_);
 | 
					  ++generation_;
 | 
				
			||||||
 | 
					  for (auto &area : areas_) {
 | 
				
			||||||
 | 
					    if (area->isLocked())
 | 
				
			||||||
 | 
					      capture(*area, generation_);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CaptureAreaSelector::capture(CaptureArea &area, uint generation)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  area.setGeneration(generation);
 | 
				
			||||||
 | 
					  capturer_.selected(area);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CaptureAreaSelector::captureAll()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  SOFT_ASSERT(!areas_.empty(), return );
 | 
				
			||||||
 | 
					  ++generation_;
 | 
				
			||||||
 | 
					  for (auto &area : areas_) capture(*area, generation_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CaptureAreaSelector::cancel()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  capturer_.canceled();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::setScreenRects(const std::vector<QRect> &screens)
 | 
					void CaptureAreaSelector::setScreenRects(const std::vector<QRect> &screens)
 | 
				
			||||||
@ -67,7 +113,7 @@ void CaptureAreaSelector::setScreenRects(const std::vector<QRect> &screens)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::updateSettings()
 | 
					void CaptureAreaSelector::updateSettings()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  area_.reset();
 | 
					  areas_.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::paintEvent(QPaintEvent * /*event*/)
 | 
					void CaptureAreaSelector::paintEvent(QPaintEvent * /*event*/)
 | 
				
			||||||
@ -77,8 +123,9 @@ void CaptureAreaSelector::paintEvent(QPaintEvent * /*event*/)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  for (const auto &rect : helpRects_) drawHelpRects(painter, rect);
 | 
					  for (const auto &rect : helpRects_) drawHelpRects(painter, rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (area_)
 | 
					  if (!areas_.empty()) {
 | 
				
			||||||
    drawCaptureArea(painter, *area_);
 | 
					    for (const auto &area : areas_) drawCaptureArea(painter, *area);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (editor_->isVisible()) {
 | 
					  if (editor_->isVisible()) {
 | 
				
			||||||
    painter.setBrush(QBrush(QColor(200, 200, 200, 200)));
 | 
					    painter.setBrush(QBrush(QColor(200, 200, 200, 200)));
 | 
				
			||||||
@ -86,11 +133,10 @@ void CaptureAreaSelector::paintEvent(QPaintEvent * /*event*/)
 | 
				
			|||||||
    painter.drawRect(editor_->geometry());
 | 
					    painter.drawRect(editor_->geometry());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto selection = QRect(startSelectPos_, currentSelectPos_).normalized();
 | 
					  const auto area = CaptureArea(
 | 
				
			||||||
  if (!selection.isValid())
 | 
					      QRect(startSelectPos_, currentSelectPos_).normalized(), settings_);
 | 
				
			||||||
 | 
					  if (!area.isValid())
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  const auto area = CaptureArea(selection, settings_);
 | 
					 | 
				
			||||||
  drawCaptureArea(painter, area);
 | 
					  drawCaptureArea(painter, area);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -154,9 +200,9 @@ void CaptureAreaSelector::drawCaptureArea(QPainter &painter,
 | 
				
			|||||||
void CaptureAreaSelector::showEvent(QShowEvent * /*event*/)
 | 
					void CaptureAreaSelector::showEvent(QShowEvent * /*event*/)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  editor_->hide();
 | 
					  editor_->hide();
 | 
				
			||||||
  if (area_ && !area_->isLocked())
 | 
					 | 
				
			||||||
    area_.reset();
 | 
					 | 
				
			||||||
  startSelectPos_ = currentSelectPos_ = QPoint();
 | 
					  startSelectPos_ = currentSelectPos_ = QPoint();
 | 
				
			||||||
 | 
					  areas_.erase(std::remove_if(areas_.begin(), areas_.end(), notLocked),
 | 
				
			||||||
 | 
					               areas_.end());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::hideEvent(QHideEvent * /*event*/)
 | 
					void CaptureAreaSelector::hideEvent(QHideEvent * /*event*/)
 | 
				
			||||||
@ -166,8 +212,19 @@ void CaptureAreaSelector::hideEvent(QHideEvent * /*event*/)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::keyPressEvent(QKeyEvent *event)
 | 
					void CaptureAreaSelector::keyPressEvent(QKeyEvent *event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (event->key() == Qt::Key_Escape)
 | 
					  if (event->key() == Qt::Key_Escape) {
 | 
				
			||||||
    capturer_.canceled();
 | 
					    cancel();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (event->key() == Qt::Key_Return) {
 | 
				
			||||||
 | 
					    if (!areas_.empty()) {
 | 
				
			||||||
 | 
					      captureAll();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      cancel();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::mousePressEvent(QMouseEvent *event)
 | 
					void CaptureAreaSelector::mousePressEvent(QMouseEvent *event)
 | 
				
			||||||
@ -179,17 +236,22 @@ void CaptureAreaSelector::mousePressEvent(QMouseEvent *event)
 | 
				
			|||||||
    applyEditor();
 | 
					    applyEditor();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (area_ && area_->rect().contains(event->pos())) {
 | 
					  if (!areas_.empty()) {
 | 
				
			||||||
    if (event->button() == Qt::LeftButton) {
 | 
					    for (auto &area : areas_) {
 | 
				
			||||||
      capturer_.selected(*area_);
 | 
					      if (!area->rect().contains(event->pos()))
 | 
				
			||||||
    } else if (event->button() == Qt::RightButton) {
 | 
					        continue;
 | 
				
			||||||
      customize(*area_);
 | 
					
 | 
				
			||||||
 | 
					      if (event->button() == Qt::LeftButton) {
 | 
				
			||||||
 | 
					        capture(*area, ++generation_);
 | 
				
			||||||
 | 
					      } else if (event->button() == Qt::RightButton) {
 | 
				
			||||||
 | 
					        customize(area);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (startSelectPos_.isNull())
 | 
					  if (startSelectPos_.isNull())
 | 
				
			||||||
    startSelectPos_ = event->pos();
 | 
					    startSelectPos_ = currentSelectPos_ = event->pos();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::mouseMoveEvent(QMouseEvent *event)
 | 
					void CaptureAreaSelector::mouseMoveEvent(QMouseEvent *event)
 | 
				
			||||||
@ -215,27 +277,37 @@ void CaptureAreaSelector::mouseReleaseEvent(QMouseEvent *event)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  startSelectPos_ = currentSelectPos_ = {};
 | 
					  startSelectPos_ = currentSelectPos_ = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auto area = CaptureArea(selection, settings_);
 | 
					  auto area = CaptureArea(selection, settings_);
 | 
				
			||||||
  if (!area.isValid()) {
 | 
					  if (!area.isValid()) {  // just a click
 | 
				
			||||||
    capturer_.canceled();
 | 
					    if (areas_.empty()) {
 | 
				
			||||||
 | 
					      cancel();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (event->button() == Qt::RightButton) {
 | 
				
			||||||
 | 
					      contextMenu_->popup(QCursor::pos());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (event->button() != Qt::RightButton) {
 | 
					  areas_.emplace_back(std::make_unique<CaptureArea>(area));
 | 
				
			||||||
    capturer_.selected(area);
 | 
					  if (event->button() == Qt::RightButton) {
 | 
				
			||||||
  } else {
 | 
					    customize(areas_.back());
 | 
				
			||||||
    area_ = std::make_unique<CaptureArea>(area);
 | 
					    return;
 | 
				
			||||||
    customize(*area_);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!(event->modifiers() & Qt::ControlModifier))
 | 
				
			||||||
 | 
					    captureAll();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CaptureAreaSelector::customize(const CaptureArea &area)
 | 
					void CaptureAreaSelector::customize(const std::shared_ptr<CaptureArea> &area)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SOFT_ASSERT(editor_, return );
 | 
					  SOFT_ASSERT(editor_, return );
 | 
				
			||||||
  editor_->set(area);
 | 
					  SOFT_ASSERT(area, return );
 | 
				
			||||||
 | 
					  editor_->set(*area);
 | 
				
			||||||
 | 
					  edited_ = area;
 | 
				
			||||||
  editor_->show();
 | 
					  editor_->show();
 | 
				
			||||||
  const auto topLeft = service::geometry::cornerAtPoint(
 | 
					  const auto topLeft = service::geometry::cornerAtPoint(
 | 
				
			||||||
      area.rect().center(), editor_->size(), geometry());
 | 
					      area->rect().center(), editor_->size(), geometry());
 | 
				
			||||||
  editor_->move(topLeft);
 | 
					  editor_->move(topLeft);
 | 
				
			||||||
  update();
 | 
					  update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -243,8 +315,9 @@ void CaptureAreaSelector::customize(const CaptureArea &area)
 | 
				
			|||||||
void CaptureAreaSelector::applyEditor()
 | 
					void CaptureAreaSelector::applyEditor()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SOFT_ASSERT(editor_, return );
 | 
					  SOFT_ASSERT(editor_, return );
 | 
				
			||||||
  if (!editor_->isVisible() || !area_)
 | 
					  if (!editor_->isVisible() || edited_.expired())
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  editor_->apply(*area_);
 | 
					  editor_->apply(*edited_.lock());
 | 
				
			||||||
  editor_->hide();
 | 
					  editor_->hide();
 | 
				
			||||||
 | 
					  update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <QWidget>
 | 
					#include <QWidget>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QMenu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CaptureAreaSelector : public QWidget
 | 
					class CaptureAreaSelector : public QWidget
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Q_OBJECT
 | 
					  Q_OBJECT
 | 
				
			||||||
@ -33,21 +35,27 @@ private:
 | 
				
			|||||||
    QRect current;
 | 
					    QRect current;
 | 
				
			||||||
    std::vector<QRect> possible;
 | 
					    std::vector<QRect> possible;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  void capture(CaptureArea &area, uint generation);
 | 
				
			||||||
 | 
					  void captureAll();
 | 
				
			||||||
 | 
					  void cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool updateCurrentHelpRects();
 | 
					  bool updateCurrentHelpRects();
 | 
				
			||||||
  void drawHelpRects(QPainter &painter, const HelpRect &rect) const;
 | 
					  void drawHelpRects(QPainter &painter, const HelpRect &rect) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void customize(const CaptureArea &area);
 | 
					  void customize(const std::shared_ptr<CaptureArea> &area);
 | 
				
			||||||
  void applyEditor();
 | 
					  void applyEditor();
 | 
				
			||||||
  void drawCaptureArea(QPainter &painter, const CaptureArea &area) const;
 | 
					  void drawCaptureArea(QPainter &painter, const CaptureArea &area) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Capturer &capturer_;
 | 
					  Capturer &capturer_;
 | 
				
			||||||
  const Settings &settings_;
 | 
					  const Settings &settings_;
 | 
				
			||||||
  const QPixmap &pixmap_;
 | 
					  const QPixmap &pixmap_;
 | 
				
			||||||
 | 
					  Generation generation_{};
 | 
				
			||||||
  QPoint startSelectPos_;
 | 
					  QPoint startSelectPos_;
 | 
				
			||||||
  QPoint currentSelectPos_;
 | 
					  QPoint currentSelectPos_;
 | 
				
			||||||
  QString help_;
 | 
					  QString help_;
 | 
				
			||||||
  std::vector<HelpRect> helpRects_;
 | 
					  std::vector<HelpRect> helpRects_;
 | 
				
			||||||
  std::unique_ptr<CaptureArea> area_;
 | 
					  std::vector<std::shared_ptr<CaptureArea>> areas_;
 | 
				
			||||||
 | 
					  std::weak_ptr<CaptureArea> edited_;
 | 
				
			||||||
  std::unique_ptr<CaptureAreaEditor> editor_;
 | 
					  std::unique_ptr<CaptureAreaEditor> editor_;
 | 
				
			||||||
 | 
					  QMenu *contextMenu_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <QApplication>
 | 
					#include <QApplication>
 | 
				
			||||||
#include <QClipboard>
 | 
					#include <QClipboard>
 | 
				
			||||||
 | 
					#include <QMouseEvent>
 | 
				
			||||||
#include <QScreen>
 | 
					#include <QScreen>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Representer::Representer(Manager &manager, TrayIcon &tray,
 | 
					Representer::Representer(Manager &manager, TrayIcon &tray,
 | 
				
			||||||
@ -25,15 +26,21 @@ Representer::~Representer() = default;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Representer::showLast()
 | 
					void Representer::showLast()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SOFT_ASSERT(widget_, return );
 | 
					  SOFT_ASSERT(!widgets_.empty(), return );
 | 
				
			||||||
  widget_->show();
 | 
					  for (auto &widget : widgets_) {
 | 
				
			||||||
 | 
					    SOFT_ASSERT(widget->task(), continue);
 | 
				
			||||||
 | 
					    if (widget->task()->generation != generation_)
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					    widget->show();
 | 
				
			||||||
 | 
					    widget->activateWindow();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Representer::clipboardLast()
 | 
					void Representer::clipboardLast()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SOFT_ASSERT(widget_, return );
 | 
					  SOFT_ASSERT(!widgets_.empty(), return );
 | 
				
			||||||
  SOFT_ASSERT(widget_->task(), return );
 | 
					  SOFT_ASSERT(widgets_.front()->task(), return );
 | 
				
			||||||
  clipboardText(widget_->task());
 | 
					  clipboardText(widgets_.front()->task());
 | 
				
			||||||
  tray_.showInformation(
 | 
					  tray_.showInformation(
 | 
				
			||||||
      QObject::tr("The last result was copied to the clipboard."));
 | 
					      QObject::tr("The last result was copied to the clipboard."));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -48,19 +55,24 @@ void Representer::represent(const TaskPtr &task)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool Representer::isVisible() const
 | 
					bool Representer::isVisible() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  return widget_ && widget_->isVisible();
 | 
					  if (widgets_.empty())
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  return std::any_of(widgets_.cbegin(), widgets_.cend(),
 | 
				
			||||||
 | 
					                     [](const auto &w) { return w->isVisible(); });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Representer::hide()
 | 
					void Representer::hide()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (widget_)
 | 
					  if (widgets_.empty())
 | 
				
			||||||
    widget_->hide();
 | 
					    return;
 | 
				
			||||||
 | 
					  for (auto &w : widgets_) w->hide();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Representer::updateSettings()
 | 
					void Representer::updateSettings()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (widget_)
 | 
					  if (widgets_.empty())
 | 
				
			||||||
    widget_->updateSettings();
 | 
					    return;
 | 
				
			||||||
 | 
					  for (auto &w : widgets_) w->updateSettings();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Representer::clipboardText(const TaskPtr &task)
 | 
					void Representer::clipboardText(const TaskPtr &task)
 | 
				
			||||||
@ -98,6 +110,22 @@ void Representer::edit(const TaskPtr &task)
 | 
				
			|||||||
                                                 screen->geometry()));
 | 
					                                                 screen->geometry()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Representer::eventFilter(QObject * /*watched*/, QEvent *event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (event->type() == QEvent::WindowDeactivate) {
 | 
				
			||||||
 | 
					    for (const auto &w : widgets_) {
 | 
				
			||||||
 | 
					      if (w->isActiveWindow())
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    hide();
 | 
				
			||||||
 | 
					  } else if (event->type() == QEvent::MouseButtonPress) {
 | 
				
			||||||
 | 
					    const auto casted = static_cast<QMouseEvent *>(event);
 | 
				
			||||||
 | 
					    if (casted->button() == Qt::LeftButton)
 | 
				
			||||||
 | 
					      hide();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Representer::showTooltip(const TaskPtr &task)
 | 
					void Representer::showTooltip(const TaskPtr &task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  auto message = task->recognized + " - " + task->translated;
 | 
					  auto message = task->recognized + " - " + task->translated;
 | 
				
			||||||
@ -106,8 +134,22 @@ void Representer::showTooltip(const TaskPtr &task)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Representer::showWidget(const TaskPtr &task)
 | 
					void Representer::showWidget(const TaskPtr &task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!widget_)
 | 
					  generation_ = task->generation;
 | 
				
			||||||
    widget_ = std::make_unique<ResultWidget>(*this, settings_);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  widget_->show(task);
 | 
					  auto index = 0u;
 | 
				
			||||||
 | 
					  const auto count = widgets_.size();
 | 
				
			||||||
 | 
					  for (; index < count; ++index) {
 | 
				
			||||||
 | 
					    auto &widget = widgets_[index];
 | 
				
			||||||
 | 
					    SOFT_ASSERT(widget->task(), continue);
 | 
				
			||||||
 | 
					    if (widget->task()->generation != generation_)
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (index == count) {
 | 
				
			||||||
 | 
					    widgets_.emplace_back(std::make_unique<ResultWidget>(*this, settings_));
 | 
				
			||||||
 | 
					    widgets_.back()->installEventFilter(this);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto &widget = widgets_[index];
 | 
				
			||||||
 | 
					  widget->show(task);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,12 +2,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "stfwd.h"
 | 
					#include "stfwd.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <QObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class ResultMode;
 | 
					enum class ResultMode;
 | 
				
			||||||
class ResultWidget;
 | 
					class ResultWidget;
 | 
				
			||||||
class ResultEditor;
 | 
					class ResultEditor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Representer
 | 
					class Representer : public QObject
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  Q_OBJECT
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  Representer(Manager &manager, TrayIcon &tray, const Settings &settings,
 | 
					  Representer(Manager &manager, TrayIcon &tray, const Settings &settings,
 | 
				
			||||||
              const CommonModels &models);
 | 
					              const CommonModels &models);
 | 
				
			||||||
@ -24,6 +27,8 @@ public:
 | 
				
			|||||||
  void clipboardImage(const TaskPtr &task);
 | 
					  void clipboardImage(const TaskPtr &task);
 | 
				
			||||||
  void edit(const TaskPtr &task);
 | 
					  void edit(const TaskPtr &task);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool eventFilter(QObject *watched, QEvent *event) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  void showTooltip(const TaskPtr &task);
 | 
					  void showTooltip(const TaskPtr &task);
 | 
				
			||||||
  void showWidget(const TaskPtr &task);
 | 
					  void showWidget(const TaskPtr &task);
 | 
				
			||||||
@ -32,6 +37,7 @@ private:
 | 
				
			|||||||
  TrayIcon &tray_;
 | 
					  TrayIcon &tray_;
 | 
				
			||||||
  const Settings &settings_;
 | 
					  const Settings &settings_;
 | 
				
			||||||
  const CommonModels &models_;
 | 
					  const CommonModels &models_;
 | 
				
			||||||
  std::unique_ptr<ResultWidget> widget_;
 | 
					  Generation generation_{};
 | 
				
			||||||
 | 
					  std::vector<std::unique_ptr<ResultWidget>> widgets_;
 | 
				
			||||||
  std::unique_ptr<ResultEditor> editor_;
 | 
					  std::unique_ptr<ResultEditor> editor_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -148,13 +148,6 @@ void ResultWidget::updateSettings()
 | 
				
			|||||||
  image_->setVisible(settings_.showCaptured);
 | 
					  image_->setVisible(settings_.showCaptured);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ResultWidget::eventFilter(QObject *watched, QEvent *event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  if (event->type() == QEvent::WindowDeactivate)
 | 
					 | 
				
			||||||
    hide();
 | 
					 | 
				
			||||||
  return QWidget::eventFilter(watched, event);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ResultWidget::mousePressEvent(QMouseEvent *event)
 | 
					void ResultWidget::mousePressEvent(QMouseEvent *event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  const auto button = event->button();
 | 
					  const auto button = event->button();
 | 
				
			||||||
@ -167,8 +160,6 @@ void ResultWidget::mousePressEvent(QMouseEvent *event)
 | 
				
			|||||||
    lastPos_ = event->pos();
 | 
					    lastPos_ = event->pos();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  hide();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ResultWidget::mouseMoveEvent(QMouseEvent *event)
 | 
					void ResultWidget::mouseMoveEvent(QMouseEvent *event)
 | 
				
			||||||
 | 
				
			|||||||
@ -19,8 +19,6 @@ public:
 | 
				
			|||||||
  using QWidget::show;
 | 
					  using QWidget::show;
 | 
				
			||||||
  void updateSettings();
 | 
					  void updateSettings();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool eventFilter(QObject* watched, QEvent* event) override;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
  void mousePressEvent(QMouseEvent* event) override;
 | 
					  void mousePressEvent(QMouseEvent* event) override;
 | 
				
			||||||
  void mouseMoveEvent(QMouseEvent* event) override;
 | 
					  void mouseMoveEvent(QMouseEvent* event) override;
 | 
				
			||||||
 | 
				
			|||||||
@ -29,3 +29,4 @@ class AutoChecker;
 | 
				
			|||||||
using TaskPtr = std::shared_ptr<Task>;
 | 
					using TaskPtr = std::shared_ptr<Task>;
 | 
				
			||||||
using LanguageId = QString;
 | 
					using LanguageId = QString;
 | 
				
			||||||
using LanguageIds = QStringList;
 | 
					using LanguageIds = QStringList;
 | 
				
			||||||
 | 
					using Generation = unsigned int;
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,8 @@ public:
 | 
				
			|||||||
  bool isNull() const { return captured.isNull() && !sourceLanguage.isEmpty(); }
 | 
					  bool isNull() const { return captured.isNull() && !sourceLanguage.isEmpty(); }
 | 
				
			||||||
  bool isValid() const { return error.isEmpty(); }
 | 
					  bool isValid() const { return error.isEmpty(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Generation generation{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  QPoint capturePoint;
 | 
					  QPoint capturePoint;
 | 
				
			||||||
  QPixmap captured;
 | 
					  QPixmap captured;
 | 
				
			||||||
  QString recognized;
 | 
					  QString recognized;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user