scanned-image-extractor/scannerExtract/imagescene.cpp

1708 lines
59 KiB
C++

/***********************************************************************
* This file is part of Scanned Image Extract.
*
* Scanned Image Extract is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Scanned Image Extract is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Scanned Image Extract. If not, see <http://www.gnu.org/licenses/>
*
*
* Copyright (C) 2015, Dominik Rueß; info@dominik-ruess.de
**********************************************************************/
#include "imagescene.h"
#include <QGraphicsSceneMouseEvent>
#include <QApplication>
#include <QDebug>
#include <QGraphicsView>
#include <QTransform>
#include <QKeyEvent>
#include <QScrollBar>
#include <QtCore/qmath.h>
#include <QSettings>
#include <QFileDialog>
#include <QMessageBox>
#include <QShortcut>
#include <QStatusBar>
#include "settings.h"
// #define DEBUG_TEST
ImageScene::ImageScene(QObject *parent)
: QGraphicsScene(parent)
, _currentState(MouseStateNotLoaded)
, _currentMouseState(MouseStateNone)
, _sizeChange(":/images/sizeChange.png")
, _rotate(":/images/rotate.png")
, _currentIndex(-1)
, _currLine(0)
, _cropPercentage(0)
, _aspectRatio(-1)
, _backgroundLoader(0)
, _isWaiting(false)
, _enforceAspectForNew(false)
, _waitBar(0)
, _numNeighbours(2)
{
qRegisterMetaType<QFileInfoList>("QFileInfoList");
qRegisterMetaType<SourceFilePtr>("SourceFilePtr");
qRegisterMetaType<TargetImagePtr>("TargetImagePtr");
connect(this, SIGNAL(selectionChanged()),
this, SLOT(onSelectionChanged()), Qt::QueuedConnection);
connect(&_copyTargetThread, SIGNAL(copied(QString,QString)),
SLOT(doneCopy(QString,QString)), Qt::QueuedConnection);
connect(&_copyTargetThread, SIGNAL(copied(QString,QString)),
SIGNAL(doneCopying(QString,QString)), Qt::QueuedConnection);
connect(&_timer, SIGNAL(timeout()), this, SLOT(updateSelection()), Qt::QueuedConnection);
connect(this, SIGNAL(renewList(QFileInfoList,int)),
this, SLOT(newImageList(QFileInfoList,int)), Qt::QueuedConnection);
/*
connect(this, SIGNAL(extractTarget(int,int)), SLOT(_extractTarget(int,int)),
Qt::QueuedConnection);*/
connect(&_targetExtractor, SIGNAL(doneTarget(const TargetImagePtr&)),
this, SLOT(doneLoadingTarget(const TargetImagePtr&)), Qt::BlockingQueuedConnection);
connect(&_copyTargetThread, SIGNAL(copyError(SourceFilePtr,TargetImagePtr)),
this, SLOT(_onCopyError(SourceFilePtr,TargetImagePtr)));
_timer.setInterval(250);
_timer.start();
}
ImageScene::~ImageScene()
{
if (_backgroundLoader != 0)
{
delete _backgroundLoader;
}
disconnect(this);
saveCurrent();
_copyTargetThread.setExitSaving();
delete _currLine;
}
void ImageScene::updateSelection()
{
// for a selection animation
if (_currentIndex >= 0
&& _currentIndex < _currentFiles.size()
&& _currentFiles[_currentIndex]->targets.size() > 0)
{
for (int i=0; i<_currentFiles[_currentIndex]->targets.size(); i++)
{
_currentFiles[_currentIndex]->targets[i]->boundary->update();
}
}
update();
}
void ImageScene::init()
{
QListIterator<QGraphicsItem *> i(items());
while (i.hasNext())
{
QGraphicsItem* item = i.next();
item->setVisible(false);
removeItem(item); // does not perform "delete" (would destroy use of smartptr)
}
QList<QGraphicsView *> v = views();
_view = v.size() > 0 ? v[0] : NULL;
_view->setCursor(Qt::CrossCursor);
_view->viewport()->setMouseTracking(true);
update();
_view->resetMatrix();
_view->resetTransform();
_view->update();
}
void ImageScene::newImageList(const QFileInfoList& images,
const int selectedIndex)
{
if (!_extractMutex.tryLock())
{
emit (renewList(images, selectedIndex));
}
_copyTargetThread.clear();
if (_backgroundLoader != 0) {
disconnect(_backgroundLoader);
_backgroundLoader->setPriority(QThread::LowPriority);
_backgroundLoader->disconnect();
_backgroundLoader->stop();
_backgroundLoader->clear();
_backgroundLoader->deleteLater();
}
_backgroundLoader = new PreloadSource();
connect(_backgroundLoader, SIGNAL(doneLoading(SourceFilePtr,int)),
this, SLOT(_doneLoading(SourceFilePtr,int)), Qt::QueuedConnection);
_currentFiles.clear();
for (int i=0; i<images.size(); i++) {
SourceFilePtr tmp (new SourceFile);
tmp->source = images[i];
_currentFiles.push_back(tmp);
}
_currentIndex = qMax(0,selectedIndex);
_currentTarget = 0;
_extractMutex.unlock();
emit reloadSettings(); // update settings for thread
_isWaiting = false;
loadPosition(_currentIndex, false, true);
}
void ImageScene::saveCurrent(const bool noUpdate, const bool force)
{
if (_currentIndex>=0
&& _currentIndex < _currentFiles.size()
&& _currentFiles[_currentIndex]->targets.size() > 0) {
clearSelection();
if (!noUpdate)
{
emit updateTargetDisplay(QPixmap());
}
if (force)
{
for (int i=0; i<_currentFiles[_currentIndex]->targets.size(); i++)
{
_currentFiles[_currentIndex]->targets[i]->boundary->setCopied(false);
}
}
_copyTargetThread.addSaveFiles(_currentFiles[_currentIndex]);
}
}
void ImageScene::loadPosition(const int newPosition,
const bool increment,
const bool forceReload)
{
bool positionChanged = false;
if ( (newPosition >= 0 && !increment)
|| (newPosition == -2 && !increment)
|| (increment)) {
const int newPos = newPosition == -2 ? _currentFiles.size() -1 : (increment ? _currentIndex + newPosition : newPosition);
if (newPos>= 0 && newPos <_currentFiles.size()) {
positionChanged = _currentIndex != newPos;
if (positionChanged) {
_copyTargetThread.abortSaveFile(0);
saveCurrent();
}
_currentIndex = newPos;
}
}
if (_currentIndex <0 || _currentIndex >= _currentFiles.size())
{
return;
}
if (_currentIndex >=0 && _currentIndex < _currentFiles.size())
{
emit changed(_currentFiles[_currentIndex]->changed);
emit fileName(_currentFiles[_currentIndex]->source.fileName());
emit filePosition(QString(tr("%1 of %2")).arg(_currentIndex + 1).arg(_currentFiles.size()));
}
#ifdef DEBUG_TEST
// work on all images in selected directory
static bool done = false;
if (!done) {
qDebug() << "changed";
const int m = 3;
QVector<float> w(m);
w[0] = 0.0; w[1] = 1; w[2] = 5; //3.0; w[2] = 7.0; w[3] = 15;
/* for (int i=0; i<m; i++) {
for (int j=0; j<m; j++) {
for (int k=0; k<m; k++) {
for (int l=0; l<m; l++) {
cv::Vec4i values(w[i], w[j], w[k], w[l] );
if (w[i] == 0 && w[j] == 0 && w[k] == 0 && w[l] == 0) continue;
qDebug() << w[i] << w[j] << w[k] << w[l];*/
cv::Vec4f values(0.1,5,1,10);
for (int a=0; a<_currentFiles.size(); a++)
{
//SourceFilePtr file(new SourceFile);
//file->source = ->source.absoluteFilePath();
_backgroundLoader->addLoadFiles(
_currentFiles[a],
m,
values,
false,
false);
}
/*}
}
}
}*/
done = true;
qDebug() << "done";
return;
}
#endif
if ( (_isWaiting && !positionChanged)
|| _currentFiles[_currentIndex]->error)
{
if (_currentFiles[_currentIndex]->error)
{
emit fileName(_currentFiles[_currentIndex]->source.fileName()
+ " - <font style=\"color:red;\">ERROR LOADING SOURCE</font>");
_copyTargetThread.abortSaveFile(0);
if (_waitBar != 0)
{
_waitBar->setVisible(false);
delete _waitBar;
_waitBar = 0;
_isWaiting = false;
}
clear();
emit updateTargetDisplay(QPixmap());
return;
}
if (_currentFiles[_currentIndex]->imageOrig.isNull()) {
QTimer::singleShot(500, this, SLOT(loadPosition()));
return;
}
}
// do clear target display
emit setTargetWaiting(false);
emit updateTargetDisplay(QPixmap());
bool alreadyLoaded= false, isLoading = false;
if (positionChanged) {
if (!_currentFiles[_currentIndex]->imageOrig.isNull()) {
alreadyLoaded = true;
}
if (_backgroundLoader->isCurrentlyLoading() ==
_currentFiles[_currentIndex]->source.absoluteFilePath()) {
isLoading = true;
}
}
if (isLoading) {
if (_waitBar == 0 || !_waitBar->isVisible())
{
_waitBar = new QProgressBar(_view);
_waitBar->setWindowModality(Qt::ApplicationModal);
_waitBar->setMaximum(0);
_waitBar->setMinimum(0);
_waitBar->show();
}
init(); // clear display
return;
}
if ((!alreadyLoaded && positionChanged)
|| forceReload
|| _currentFiles[_currentIndex]->image.get() == NULL) {
emit fileName(_currentFiles[_currentIndex]->source.fileName());
init(); // clear display
bool isSaved = !_currentFiles[_currentIndex]->changed;
_backgroundLoader->addLoadFiles(_currentFiles[_currentIndex],
_currentIndex,
true,
isSaved);
if (_waitBar == 0 || !_waitBar->isVisible())
{
_waitBar = new QProgressBar(_view);
_waitBar->setWindowModality(Qt::ApplicationModal);
_waitBar->setMaximum(0);
_waitBar->setMinimum(0);
_waitBar->show();
}
_isWaiting = true;
return; // done setting up threads
}
// start preloading for neighbours, start and end
for (int i=_numNeighbours-1; i>=0; i--)
{
for (int j=0; j<2; j++)
{
const int ind = j==1 ?
qMax(0, _currentIndex - i -1)
: qMin(_currentFiles.size()-1, _currentIndex + i + 1);
if (_currentFiles[ind]->image.get() == NULL)
{
bool isSaved = !_currentFiles[ind]->changed;
_backgroundLoader->addLoadFiles(_currentFiles[ind],
ind,
false,
isSaved);
}
}
}
// update current display
clear();
_currentFiles[_currentIndex]->image->setVisible(true);
_currentFiles[_currentIndex]->image->setZValue(-100);
addItem(_currentFiles[_currentIndex]->image.get());
_view->resetMatrix();
_view->fitInView(_currentFiles[_currentIndex]->image.get(),
Qt::KeepAspectRatio);
for (int i=0; i<_currentFiles[_currentIndex]->targets.size(); i++) {
_currentFiles[_currentIndex]->targets[i]->boundary->setVisible(true);
_currentFiles[_currentIndex]->targets[i]->boundary->setZValue(10+i);
addItem(_currentFiles[_currentIndex]->targets[i]->boundary.get());
if (!_currentFiles[_currentIndex]->targets[i]->boundary->getUserHasSeenThis()
&& _enforceAspectForNew)
{
_correctAspectRatio(_currentFiles[_currentIndex]->targets[i]);
}
_currentFiles[_currentIndex]->targets[i]->boundary->setUserHasSeenThis();
qApp->processEvents();
}
if (_currentIndex >=0)
{
// select one item - but only if not all of them have been copied, already
if (_currentFiles[_currentIndex]->targets.size() > 0) {
int ind=-1;
for (int i=_currentFiles[_currentIndex]->targets.size()-1; i>=0; i--)
{
if (!_currentFiles[_currentIndex]->targets[i]->boundary->getCopied()) {
ind = i;
}
}
clearSelection();
if (ind >=0) {
_currentFiles[_currentIndex]->targets[ind]->boundary->setSelected(true);
emit targetPosition(QString(tr("%1 of %2")).arg(ind + 1).arg(_currentFiles[_currentIndex]->targets.size()));
}
}
emit changed(_currentFiles[_currentIndex]->changed);
emit fileName(_currentFiles[_currentIndex]->source.fileName());
emit filePosition(QString(tr("%1 of %2")).arg(_currentIndex + 1).arg(_currentFiles.size()));
}
if (_waitBar != 0) {
_waitBar->setVisible(false);
delete _waitBar;
_waitBar = 0;
}
_currentState = MouseStateNone;
_currentMouseState = MouseStateNone;
_isWaiting = false;
_view->update();
update();
_copyTargetThread.abortSaveFile(_currentFiles[_currentIndex]);
// free old data - but only, if it has been saved, already
// the target extraction may still work in one of the old images
// so lock
while (!ExtractTargets::fileListMutex.tryLock(50))
{
qApp->processEvents();
}
for (int i=0; i<_currentFiles.size(); i++) {
if (i == _currentIndex) continue;
bool inWaitingList = false;
QListIterator<QPair<TargetImagePtr, SourceFilePtr>> it(_targetExtractor.getList());
while (it.hasNext())
{
if (it.next().second->id == _currentFiles[i]->id)
{
inWaitingList = true;
break;
}
}
bool tooFar = qAbs(i-_currentIndex) > _numNeighbours
&& (!_currentFiles[i]->changed
|| _currentFiles[i]->error
|| (_currentFiles[i]->targets.size() > 0
&& !_currentFiles[i]->targets[0]->boundary->getUserHasSeenThis()));
if (tooFar && !inWaitingList) {
_currentFiles[i]->image = QGraphicsPixmapItemPtr();
_currentFiles[i]->imageOrig = QImage();
for (int j=0; j<_currentFiles[i]->targets.size(); j++) {
_currentFiles[i]->targets[j]->image = QImage();
_currentFiles[i]->targets[j]->backmap = BackMapPtr();
}
}
}
ExtractTargets::fileListMutex.unlock();
}
void ImageScene::_doneLoading(const SourceFilePtr &source, const int position)
{
#ifdef DEBUG_TEST
return;
#endif
if (position>=0 && position <_currentFiles.size())
{
if ( _currentFiles[position]->id == source->id)
{
_currentFiles[position]->image = QGraphicsPixmapItemPtr(new QGraphicsPixmapItem(
QPixmap::fromImage(_currentFiles[position]->imageOrig)
)
);
int currentId = -1;
for (int i=_currentFiles[position]->targets.size()-1; i>=0; i--)
{
_currentFiles[position]->targets[i]->boundary->setCrop(_cropPercentage);
if (_enforceAspectForNew)
{
_currentFiles[position]->targets[i]->aspect = _aspectRatio;
_correctAspectRatio(_currentFiles[position]->targets[i]);
}
if (position == _currentIndex && i == 0)
{
currentId = i;
}
else
{
_extractTarget(position, _currentFiles[position]->targets[i]);
}
}
if (currentId >= 0)
{
// insert current lastly, since we want to have it first
_currentTarget = _currentFiles[position]->targets[0];
_extractTarget(position, _currentFiles[position]->targets[currentId], true);
}
if (position == _currentIndex)
{
loadPosition();
}
}
}
}
TargetImagePtr ImageScene::addBoundary(ImageBoundaryPtr newB)
{
_currentFiles[_currentIndex]->targets.push_back(TargetImagePtr(new TargetImage(newB)));
addItem(newB.get());
return _currentFiles[_currentIndex]->targets.last();
}
void ImageScene::onSelectionChanged()
{
if (_currentState != MouseStateNewItem
&& _currentMouseState != MouseStateNewItem) {
QList<TargetImagePtr> items = _findSelectedTarget();
emit numSelected(items.size());
double rotation =-1.0, aspect = -1.0, crop = -1.0;
bool uniqueRotation = true, uniqueAspect = true, uniqueCrop = true;
if (items.size() > 0) {
_currentTarget = items.first();
}
else
{
_currentTarget = TargetImagePtr();
}
QListIterator<TargetImagePtr> i (items);
while (i.hasNext())
{
TargetImagePtr target = i.next();
if (rotation < 0) {
rotation = target->rotation;
aspect = target->aspect;
crop = target->boundary->getCrop();
}
if (rotation != target->rotation) {
uniqueRotation = false;
}
if (aspect != target->aspect) {
uniqueAspect = false;
}
if (crop != target->boundary->getCrop()) {
uniqueCrop = false;
}
if (!uniqueRotation && !uniqueAspect && !uniqueCrop) {
break;
}
}
if (items.size() > 0)
{
if (uniqueRotation) {
emit rotation90(items[0]->rotation);
} else {
emit noRotation();
}
//if (aspect >=1) {
if (uniqueAspect) {
emit selectedAspect(items[0]->aspect);
} else {
emit noAspect();
}
//}
if (crop > 0) {
if (uniqueCrop) {
emit newCrop(items[0]->boundary->getCrop());
} else {
emit noCrop();
}
}
}
_currentMouseState = MouseStateMoveItem;
_view->setCursor(Qt::OpenHandCursor);
_updateTarget(false);
}
update();
_view->update();
}
void ImageScene::_updateTarget(const bool targetChanged, bool dirty)
{
// search for targets
QListIterator<TargetImagePtr> it(_findSelectedTarget());
while (it.hasNext())
{
TargetImagePtr currTarget = it.next();
if (targetChanged
|| currTarget->image.width() == 0
|| currTarget->image.height() == 0
|| currTarget->image.isNull())
{
QListIterator<TargetImagePtr> i2(_currentFiles[_currentIndex]->targets);
while (i2.hasNext())
{
if (i2.next()->workOnId == currTarget->workOnId)
{
emit setTargetWaiting(true);
_extractTarget(_currentIndex, currTarget, true);
break;
}
}
}
else
{
QPixmap out;
QImage img = currTarget->image;
QListIterator<TargetImagePtr> i2(_currentFiles[_currentIndex]->targets);
while (i2.hasNext())
{
if (i2.next()->workOnId == currTarget->workOnId)
{
out = QPixmap::fromImage(img);
emit setTargetWaiting(false);
emit updateTargetDisplay(out);
break;
}
}
}
if (dirty)
{
currTarget->boundary->setCopied(false);
currTarget->boundary->dirty();
}
}
if (dirty) {
_currentFiles[_currentIndex]->changed=true;
emit changed(true);
}
}
void ImageScene::_extractTarget(const int fromImage,
const TargetImagePtr target,
const bool highPriority)
{
if (fromImage >=0 && fromImage < _currentFiles.size())
{
if (!target->boundary->getUserHasSeenThis()
|| target->boundary->getCrop()<0)
{
target->boundary->setCrop(_cropPercentage);
}
/* target->boundary->setFlags(
QGraphicsItem::ItemHasNoContents
| target->boundary->flags());*/
_targetExtractor.addTarget(target,
_currentFiles[fromImage],
highPriority);
}
}
void ImageScene::wheelEvent(QGraphicsSceneWheelEvent *event)
{
if (event->modifiers() & Qt::ControlModifier) {
const double numDegrees = event->delta()/8.0;
const double numSteps = numDegrees / 15.0;
double factor = qPow(1.12, numSteps);
QPointF scenePos = _view->mapToScene(
_view->mapFromGlobal(event->screenPos())
);
zoom(factor);
_view->centerOn(scenePos);
event->accept();
} else if (event->modifiers() & Qt::ShiftModifier) {
// scroll left-right
const int numPixRight = event->delta();
if (_view->horizontalScrollBar () != 0) {
//_view->horizontalScrollBar()->scroll(numPixRight, 0);
_view->horizontalScrollBar()->setValue(
_view->horizontalScrollBar()->value() - numPixRight);
}
event->accept();
} else {
event->ignore();
}
// otherwise the scrolling will be up-/down
}
void ImageScene::doneCopy(const QString &, const QString &)
{
bool changes = false;
if (_currentIndex >= 0 && _currentIndex <_currentFiles.size())
{
bool changes = _currentFiles[_currentIndex]->targets.size() > 0;
for (int k=0; k<(int)_currentFiles[_currentIndex]->targets.size(); k++)
{
changes &= _currentFiles[_currentIndex]->targets[k]->boundary->getCopied();
}
}
emit changed(!changes);
this->update();
}
void ImageScene::keyPressEvent ( QKeyEvent * keyEvent )
{
if (keyEvent->key() == Qt::Key_Plus) {
zoom(1.25);
} else if (keyEvent->key() == Qt::Key_Minus) {
zoom(0.8);
} else if (keyEvent->key() == Qt::Key_Delete
|| keyEvent->key() == Qt::Key_Backspace) {
deleteSelection();
} else if (keyEvent->key() == Qt::Key_Escape) {
if (_currentState == MouseStateNewItem) {
removeItem(_currLine);
delete _currLine;
_currLine = 0;
}
else if (_currentMouseState == MouseStateNewItem)
{
deleteSelection();
}
_currentState = MouseStateNone;
_currentMouseState = MouseStateNone;
_view->setCursor(Qt::CrossCursor);
} /*else if (keyEvent->key() == Qt::Key_Tab) {
bool changed=false;
TargetImagePtr target = _findSelectedTarget()[0];
if (target != 0) {
QPointF corners[4];
for (int i=0;i<4;i++) corners[i]= target->boundary->corners()[i];
const double l1 = _norm(corners[1]-corners[0]);
const double l2 = _norm(corners[2]-corners[1]);
corners[0] *= l1/l2;
corners[2] *= l1/l2;
corners[1] *= l2/l1;
corners[3] *= l2/l1;
target->boundary->setCorners(corners);
_updateTarget(true);
changed = true;
}
if (!changed) {
QGraphicsScene::keyPressEvent(keyEvent);
}
} */
else {
QGraphicsScene::keyPressEvent(keyEvent);
}
}
QList<TargetImagePtr> ImageScene::_findSelectedTarget()
{
QList<TargetImagePtr> out;
if (selectedItems().size() == 0
|| _currentFiles[_currentIndex]->targets.size() ==0)
return out;
QMap<ImageBoundary*, TargetImagePtr> map;
QListIterator<TargetImagePtr> iT(_currentFiles[_currentIndex]->targets);
int ind=0;
while (iT.hasNext())
{
TargetImagePtr t = iT.next();
map.insert(t->boundary.get(), t);
ind++;
}
QListIterator<QGraphicsItem*> i(selectedItems());
while (i.hasNext())
{
ImageBoundary* item = dynamic_cast<ImageBoundary*>(i.next());
if (item) {
out.append(map[item]);
}
}
return out;
}
void ImageScene::zoom(double factor)
{
if (_view == NULL) {
return;
}
_view->scale(factor, factor);
if (_currLine != NULL) {
const QPointF p1 = _view->mapToScene(
_view->mapFromGlobal(QPoint(0,0))
);
const QPointF p2 = _view->mapToScene(
_view->mapFromGlobal(QPoint(0,1))
);
const double width = 3.0 * _norm(p1-p2);
QPen pen = _currLine->pen();
pen.setWidth(width);
_currLine->setPen(pen);
}
}
inline double ImageScene::_norm(const QPointF& p)
{
return qSqrt(p.x()*p.x() + p.y()*p.y());
}
inline double ImageScene::_dot(const QPointF& p1, const QPointF& p2)
{
return p1.x() * p2.x() + p1.y() * p2.y();
}
inline double ImageScene::_norm2(const QPointF& p)
{
return p.x()*p.x() + p.y()*p.y();
}
inline double ImageScene::_lineDist(const QPointF& l1,
const QPointF& l2,
const QPointF& p)
{
return ( (l2.x() - l1.x())*(l1.y() - p.y())
- (l1.x() - p.x())*(l2.y() - l1.y()))
/ (qSqrt( (l2.x() - l1.x() ) * (l2.x() - l1.x() )
+ (l2.y() - l1.y())*(l2.y() - l1.y()) ));
}
void ImageScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (_currentState == MouseStateNotLoaded) {
return;
}
if (mouseEvent->button() != Qt::LeftButton) {
if (_currentState == MouseStateNewItem) {
_currentState = MouseStateNone;
_currentMouseState = MouseStateNone;
removeItem(_currLine);
delete _currLine;
_currLine = 0;
_view->setCursor(Qt::CrossCursor);
}
return;
}
if (_currentState == MouseStateNone
&& _currentMouseState == MouseStateReleaseItem)
{
// first corner
_view->setCursor(Qt::CrossCursor);
_currentMouseState = MouseStateNone;
clearSelection();
} else if (_currentState == MouseStateNone
&& _currentMouseState == MouseStateNone
&& selectedItems().size() == 0)
{
// draw line
const QPointF currMousePoint = _view->mapToScene(
_view->mapFromGlobal(mouseEvent->screenPos())
);
const QPointF p1 = _view->mapToScene(
_view->mapFromGlobal(QPoint(0,0))
);
const QPointF p2 = _view->mapToScene(
_view->mapFromGlobal(QPoint(0,1))
);
const double width = 3.0 * _norm(p1-p2);
delete _currLine;
_lastCornerPos[0] = currMousePoint;
_currLine = new QGraphicsLineItem(QLineF(currMousePoint, currMousePoint));
QPen pen;
pen.setWidth(width);
pen.setStyle(Qt::DashDotLine);
pen.setColor(NEW_BOX_LINE_COLOR);
_currLine->setPen(pen);
addItem(_currLine);
_currentState = MouseStateNewItem;
} else if (_currentState == MouseStateMoveCorner
&& _currentMouseState == MouseStateNewItem)
{
// switch to release mode, such that the next release of
// the mouse stops the process
_currentMouseState = MouseStateNewItemRelease;
} else if (_currentState == MouseStateNone
&& _currentMouseState == MouseStateMoveItem)
{
_view->setCursor(Qt::ClosedHandCursor);
_currentState = MouseStateMoveItem;
QGraphicsScene::mousePressEvent(mouseEvent);
} else if (_currentState == MouseStateNone
&& _currentMouseState == MouseStateRotateItem)
{
_currentState = MouseStateRotateItem;
_lastTransformation = _currentTarget->boundary->transform();
_rotationCenter = QPointF(0,0);
for (int i=0; i<4; i++) {
QPointF posCorner = _view->mapToGlobal(_view->mapFromScene(
_currentTarget->boundary->mapToScene(_currentTarget->boundary->corners()[i])));
_rotationCenter += posCorner;
}
_rotationCenter /= 4;
QPointF lastAngleDir = mouseEvent->screenPos() - _rotationCenter;
_lastAngle = qAtan2(lastAngleDir.x(), lastAngleDir.y());
QGraphicsScene::mousePressEvent(mouseEvent);
} else if (_currentState == MouseStateNone
&& _currentMouseState == MouseStateMoveCorner)
{
_currentState = MouseStateMoveCorner;
for (int i=0; i<4; i++) {
_lastCornerPos[i] = _currentTarget->boundary->corners()[i];
}
_lastTransformation = _currentTarget->boundary->transform();
} else if (_currentState == MouseStateNone
&& _currentMouseState == MouseStateMoveEdge)
{
_currentState = MouseStateMoveEdge;
for (int i=0; i<4; i++) {
_lastCornerPos[i] = _currentTarget->boundary->corners()[i];
}
_lastTransformation = _currentTarget->boundary->transform();
const double lCurr = _norm(_currentTarget->boundary->corners()[(_currentEdge+1)%4] - _currentTarget->boundary->corners()[_currentEdge]);
const double lOrth = _norm(_currentTarget->boundary->corners()[(_currentEdge+3)%4]
- _currentTarget->boundary->corners()[_currentEdge]);
_currAspectRatio = ( lCurr > lOrth ? _aspectRatio : 1.0/_aspectRatio);
} else {
QGraphicsScene::mousePressEvent(mouseEvent);
}
}
void ImageScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (_view == NULL) {
return;
}
if (_currentState == MouseStateNone) {
bool found = false;
for (int k=0; k<(int)_currentFiles[_currentIndex]->targets.size() && !found; k++) {
if (!_currentFiles[_currentIndex]->targets[k]->boundary->isSelected()) {
continue;
}
// check if mouse above one corner
for (int i=0; i<4; i++) { ;
QPointF posCorner = _view->mapToGlobal(_view->mapFromScene(
_currentFiles[_currentIndex]->targets[k]->boundary->mapToScene(
_currentFiles[_currentIndex]->targets[k]->boundary->corners()[i])));
if (QPointF(mouseEvent->screenPos() - posCorner).manhattanLength() < DISTANCE_GRAB_CORNER
&& ! (mouseEvent->modifiers() & Qt::ShiftModifier)) {
if (_currentMouseState != MouseStateMoveCorner) {
QPointF center = QPointF(0,0);
for (int j=0; j<4;j++) {
center += _currentFiles[_currentIndex]->targets[k]->boundary->corners()[j];
}
center /= 4.0;
center = _view->mapToGlobal(_view->mapFromScene(
_currentFiles[_currentIndex]->targets[k]->boundary->mapToScene(center)));
QPointF corner = _view->mapToGlobal(_view->mapFromScene(
_currentFiles[_currentIndex]->targets[k]->boundary->mapToScene(
_currentFiles[_currentIndex]->targets[k]->boundary->corners()[i]))) - center;
qreal angle = qAtan2(corner.y(), corner.x());
QCursor tmp = _sizeChange;
const QPixmap cursorPix = tmp.pixmap().transformed(QTransform().rotateRadians(angle ),Qt::SmoothTransformation);
tmp = QCursor(cursorPix);
_view->setCursor(tmp);
_currentMouseState = MouseStateMoveCorner;
}
_currentCorner = i;
_currentTarget = _currentFiles[_currentIndex]->targets[k];
found = true;
break;
}
}
// check if mouse above edge
if (!found && !(mouseEvent->modifiers() & Qt::ShiftModifier)) {
for (int i=0; i<4; i++) {
const QPointF p1 = _view->mapToGlobal(
_view->mapFromScene(
_currentFiles[_currentIndex]->targets[k]->boundary->mapToScene(
_currentFiles[_currentIndex]->targets[k]->boundary->corners()[i])));
const QPointF p2 = _view->mapToGlobal(
_view->mapFromScene(
_currentFiles[_currentIndex]->targets[k]->boundary->mapToScene(
_currentFiles[_currentIndex]->targets[k]->boundary->corners()[(i+1)%4])));
const QPointF diff = p1 -p2;
const double dist2 = _norm2(diff);
QPointF mP = mouseEvent->screenPos();
if (_norm2(mP - p1) < dist2
&& _norm2(mP - p2) < dist2)
{
// = is in between both points
// now compute distance to connecting line
if (qAbs(_lineDist(p1, p2, mP)) < DISTANCE_GRAB_EDGE) {
qreal angle = qAtan2(diff.y(), diff.x()) - M_PI/2.0;
QCursor tmp = _sizeChange;
const QPixmap cursorPix = tmp.pixmap().transformed(QTransform().rotateRadians(angle ),Qt::SmoothTransformation);
tmp = QCursor(cursorPix);
_view->setCursor(tmp);
_currentMouseState = MouseStateMoveEdge;
_currentEdge = i;
_currentTarget = _currentFiles[_currentIndex]->targets[k];
found = true;
break;
}
}
}
}
// check if mouse above selected item
if (!found
&& _currentFiles[_currentIndex]->targets[k]->boundary->isUnderMouse()
&& ! (mouseEvent->modifiers() & Qt::ShiftModifier)) {
if (_currentMouseState != MouseStateMoveItem) {
_view->setCursor(Qt::OpenHandCursor);
_currentMouseState = MouseStateMoveItem;
}
found = true;
break;
} else if ((mouseEvent->modifiers() & Qt::ShiftModifier)
&& _currentFiles[_currentIndex]->targets[k]->boundary->isUnderMouse()) {
if (_currentMouseState != MouseStateRotateItem) {
_view->setCursor(_rotate);
_currentMouseState = MouseStateRotateItem;
_currentTarget = _currentFiles[_currentIndex]->targets[k];
}
found = true;
break;
}
}
// if not, search for other item to be able to select
if (!found) {
for (int k=0; k<(int)_currentFiles[_currentIndex]->targets.size(); k++) {
if (!_currentFiles[_currentIndex]->targets[k]->boundary->isSelected()
&& _currentFiles[_currentIndex]->targets[k]->boundary->isUnderMouse()
&& ! (mouseEvent->modifiers() & Qt::ShiftModifier))
{
if (_currentMouseState != MouseStateSelectItem) {
_view->setCursor(Qt::PointingHandCursor);
_currentMouseState = MouseStateSelectItem;
}
found = true;
}
}
}
if (found == false
&& _currentMouseState != MouseStateNone) {
if (_findSelectedTarget().size() > 0 && _findSelectedTarget()[0] != 0) {
_view->setCursor(Qt::ArrowCursor);
_currentMouseState = MouseStateReleaseItem;
} else {
_view->setCursor(Qt::CrossCursor);
_currentMouseState = MouseStateNone;
}
}
} else if (_currentState == MouseStateRotateItem) {
QPointF currAngleDir = mouseEvent->screenPos() - _rotationCenter;
double currAngle = qAtan2(currAngleDir.x(), currAngleDir.y());
QTransform trans = _lastTransformation;
_currentTarget->boundary->setTransform(trans.rotateRadians(_lastAngle-currAngle));
} else if (_currentState == MouseStateMoveEdge) {
QPointF currCorners[4];
for (int i=0;i<4; i++) {
currCorners[i] = _currentTarget->boundary->corners()[i];
}
// make sure all computations are done on start basis
// this will not cause redraw as they are scheduled
// the next setTransform will cause the actual redraw
_currentTarget->boundary->setCorners(_lastCornerPos);
_currentTarget->boundary->setTransform(_lastTransformation);
const QPointF posCorner = _currentTarget->boundary->mapFromScene(
_view->mapToScene(
_view->mapFromGlobal(mouseEvent->screenPos())
)
);
const QPointF lastToCurr = _currentTarget->boundary->corners()[_currentEdge] -
_currentTarget->boundary->corners()[(_currentEdge+3)%4];
double diff = qAbs(-_lineDist(_lastCornerPos[_currentEdge],
_lastCornerPos[(_currentEdge+1)%4],
posCorner));
const double lengthSide = _norm(lastToCurr);
const double distOppositeMouse = qAbs(_lineDist(_lastCornerPos[(_currentEdge+3)%4],
_lastCornerPos[(_currentEdge+2)%4],
posCorner));
if (lengthSide > distOppositeMouse) {
diff *= -1;
}
QPointF movement = _currentTarget->boundary->corners()[(_currentEdge+1)%4] -
_currentTarget->boundary->corners()[_currentEdge];
movement /= _norm(movement);
const double tmp = movement.x();
movement.setX(movement.y());
movement.setY(tmp);
if (_dot(movement, lastToCurr) < 0) {
movement *= -1.0;
}
if (! (mouseEvent->modifiers() & Qt::ControlModifier)) {
diff /= 2.0;
}
QPointF newPos[4];
newPos[_currentEdge] = _lastCornerPos[_currentEdge] + diff * movement;
newPos[(_currentEdge+1)%4] = _lastCornerPos[(_currentEdge+1)%4] + diff * movement;
newPos[(_currentEdge+3)%4] = _lastCornerPos[(_currentEdge+3)%4] - diff * movement;
newPos[(_currentEdge+2)%4] = _lastCornerPos[(_currentEdge+2)%4] - diff * movement;
if (mouseEvent->modifiers() & Qt::ControlModifier) {
// this means scaling around the center
QTransform trans = _lastTransformation;
_currentTarget->boundary->setTransform(trans);
_currentTarget->boundary->update();
} else {
// really drag one corner towards somewhere
// meaning that we translate the object
QTransform trans = _lastTransformation;
_currentTarget->boundary->setTransform(trans.translate(diff*movement.x(),
diff*movement.y()));
_currentTarget->boundary->update();
}
_currentTarget->boundary->setCorners(newPos);
if (_aspectRatio > 0 ) {
QPointF c[4]; for (int i=0; i<4; i++) c[i] = _currentTarget->boundary->corners()[i];
QPointF c0[4]; for (int i=0; i<4; i++) c0[i] = c[i];
QPointF dir = c[(_currentEdge+1)%4] - c[_currentEdge];
const double lCurr = _norm(dir);
dir /= lCurr;
const double lOrth = _norm(c[(_currentEdge+3)%4] - c[_currentEdge]);
const double newLength = 0.5 * lOrth * _currAspectRatio;
QPointF center = c[(_currentEdge+1)%4] + c[_currentEdge];
center /= 2.0;
c[(_currentEdge+1)%4] = center + dir * newLength;
c[_currentEdge] = center - dir * newLength;
center = c[(_currentEdge+2)%4] + c[(_currentEdge+3)%4];
center /= 2.0;
c[(_currentEdge+2)%4] = center + dir * newLength;
c[(_currentEdge+3)%4] = center - dir * newLength;
_currentTarget->boundary->setCorners(c);
_currentTarget->aspect = _aspectRatio;
}
} else if (_currentState == MouseStateMoveCorner) {
// make sure all computations are done on start basis
// this will not cause redraw as they are scheduled
// the next setTransform will cause the actual redraw
_currentTarget->boundary->setCorners(_lastCornerPos);
_currentTarget->boundary->setTransform(_lastTransformation);
QPointF posCorner = _currentTarget->boundary->mapFromScene(
_view->mapToScene(
_view->mapFromGlobal(mouseEvent->screenPos())
)
);
QPointF diff = posCorner - _lastCornerPos[_currentCorner];
if (_aspectRatio > 0) {
//diff = _lastTransformation.inverted().map(diff);
QPointF p = posCorner - _lastCornerPos[(_currentCorner+2)%4];
double currAspect = p.x()/p.y();
if (currAspect < 0)
currAspect *= -1.0;
QPointF d[8];
if (currAspect > 1.0)
{
// landscape: what fits better?
d[0] = QPointF (p.x(), -p.x() / _aspectRatio);
d[1] = QPointF (-p.x(), -p.x() / _aspectRatio);
d[2] = QPointF (-p.x(), p.x() / _aspectRatio);
d[3] = QPointF (p.x(), p.x() / _aspectRatio);
d[4] = QPointF (p.y() * _aspectRatio , -p.y());
d[5] = QPointF (-p.y() * _aspectRatio , -p.y());
d[6] = QPointF (-p.y() * _aspectRatio , p.y());
d[7] = QPointF (p.y() * _aspectRatio , p.y());
}
else
{
// portrait
d[0] = QPointF (p.x(), -p.x() * _aspectRatio);
d[1] = QPointF (-p.x(), -p.x() * _aspectRatio);
d[2] = QPointF (-p.x(), p.x() * _aspectRatio);
d[3] = QPointF (p.x(), p.x() * _aspectRatio);
d[4] = QPointF (-p.y() / _aspectRatio, p.y() );
d[5] = QPointF (-p.y() / _aspectRatio, -p.y() );
d[6] = QPointF (p.y() / _aspectRatio, -p.y() );
d[7] = QPointF (p.y() / _aspectRatio, p.y() );
}
int minInd=-1;
double maxDist = 1e10;
for (int i=0; i<8; i++)
{
if (maxDist > _norm2(d[i]-p))
{
minInd = i;
maxDist = _norm2(d[i]-p);
}
}
diff = d[minInd] + _lastCornerPos[(_currentCorner+2)%4] - _lastCornerPos[_currentCorner];
_currentTarget->aspect = _aspectRatio;
}
if (! (mouseEvent->modifiers() & Qt::ControlModifier)) {
diff /= 2;
}
QPointF newPos[4];
newPos[_currentCorner] = _lastCornerPos[_currentCorner] + diff;
newPos[(_currentCorner+2)%4] = _lastCornerPos[(_currentCorner+2)%4] - diff;
newPos[(_currentCorner+3)%4].setX( newPos[(_currentCorner+2)%4].x());
newPos[(_currentCorner+3)%4].setY( newPos[(_currentCorner)].y());
newPos[(_currentCorner+1)%4].setX( newPos[(_currentCorner)].x());
newPos[(_currentCorner+1)%4].setY( newPos[(_currentCorner+2)%4].y());
if (mouseEvent->modifiers() & Qt::ControlModifier) {
// this means scaling around the center
QTransform trans = _lastTransformation;
_currentTarget->boundary->setTransform(trans);
_currentTarget->boundary->update();
_currentTarget->boundary->setCorners(newPos);
_correctAspectRatio(_currentTarget);
} else {
// really drag one corner towards somewhere
// meaning that we translate the object
QTransform trans = _lastTransformation;
_currentTarget->boundary->setTransform(trans.translate(diff.x(), diff.y()));
_currentTarget->boundary->update();
_currentTarget->boundary->setCorners(newPos);
}
} else if (_currentState == MouseStateNewItem) {
const QPointF posCorner = _view->mapToScene(
_view->mapFromGlobal(mouseEvent->screenPos())
);
_currLine->setLine(QLineF(_lastCornerPos[0], posCorner));
} else if (_currentState == MouseStateMoveItem) {
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
}
void ImageScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
bool update = false;
bool recompute = true;
bool bringCurrentTargetToFront = false;
if (_currentState == MouseStateMoveItem) {
_currentState = MouseStateNone;
_view->setCursor(Qt::OpenHandCursor);
update = true;
}
else if (_currentState == MouseStateNewItem) {
// fix line and start drawing rectangle for item
// compute line position & length
const QPointF firstPoint = _lastCornerPos[0];
const QPointF currPoint = _view->mapToScene(
_view->mapFromGlobal(mouseEvent->screenPos())
);
const double diff = _norm(_view->mapToGlobal(_view->mapFromScene(currPoint)) -
_view->mapToGlobal(_view->mapFromScene(firstPoint)));
if (diff > 5)
{
const QPointF diff = currPoint - firstPoint;
const double length = _norm(diff);
// create new rect
emit rotation90(TargetRotation0);
ImageBoundaryPtr newBoundary (new ImageBoundary());
_currentTarget = addBoundary(newBoundary);
_currentTarget->aspect = _aspectRatio;
newBoundary->setCrop(_cropPercentage);
newBoundary->setUserHasSeenThis();
clearSelection();
newBoundary->setSelected(true);
// determine rotation and center, for transformation
// of new boundary
QPointF newPoints[4];
const double l2 = length/2.0;
newPoints[0] = QPointF(0, l2);
newPoints[1] = QPointF(0, l2);
newPoints[2] = QPointF(0, -l2);
newPoints[3] = QPointF(0, -l2);
qreal angle = qAtan2(diff.y(), diff.x()) - M_PI/2.0;
newBoundary->setCorners(newPoints);
const QPointF center = (currPoint + firstPoint)/2.0;
newBoundary->setTransform(QTransform().translate(center.x(), center.y()).rotateRadians(angle));
// now prepare new state such that it moves corner
QCursor tmpCurs = _sizeChange;
const QPixmap cursorPix = tmpCurs.pixmap().transformed(QTransform().rotateRadians(angle ),Qt::SmoothTransformation);
tmpCurs = QCursor(cursorPix);
_view->setCursor(tmpCurs);
_currentCorner = 0;
_currentState = MouseStateMoveCorner;
_currentMouseState = MouseStateNewItem;
for (int i=0; i<4; i++) {
_lastCornerPos[i] = _currentTarget->boundary->corners()[i];
}
_lastTransformation = _currentTarget->boundary->transform();
// remove line
removeItem(_currLine);
delete _currLine;
_currLine = 0;
}
} else if (_currentState == MouseStateRotateItem) {
_currentState = MouseStateNone;
if (!(mouseEvent->modifiers() & Qt::ShiftModifier)) {
_view->setCursor(Qt::OpenHandCursor);
_currentMouseState = MouseStateMoveItem;
}
update = true;
bringCurrentTargetToFront = true;
} else if ( (_currentState == MouseStateMoveCorner
|| _currentState == MouseStateMoveEdge)
&& _currentMouseState != MouseStateNewItem )
{
// if _currentMouseState == MouseStateNewItem
// this means we have to continue moving the rect
// until user clicks again
_currentState = MouseStateNone;
_currentMouseState = MouseStateMoveItem;
update = true;
recompute = true;
bringCurrentTargetToFront = true;
} else if (_currentState == MouseStateMoveEdge
&& _currentMouseState == MouseStateNewItemRelease )
{
_currentState = MouseStateNone;
_currentMouseState = MouseStateMoveItem;
update = true;
bringCurrentTargetToFront = true;
}
QGraphicsScene::mouseReleaseEvent(mouseEvent);
if (update) {
_updateTarget(recompute, true);
}
if (bringCurrentTargetToFront) {
// more than one selection and possibly manipulation
// an item which is not displayed -> send update image of this image
QPixmap out;
if (!_currentTarget->image.isNull()
&& _currentTarget.get() != 0)
{
out = QPixmap::fromImage(_currentTarget->image);
}
emit updateTargetDisplay(out);
}
}
void ImageScene::newRotation(const Rotation90 rot)
{
QListIterator<TargetImagePtr> i(_findSelectedTarget());
while (i.hasNext())
{
TargetImagePtr tmp = i.next();
tmp->rotation = rot;
tmp->boundary->setCopied(false);
}
_currGlobalRotation = rot;
_updateTarget(true);
}
void ImageScene::newIndividualCrop(const double percentage)
{
QListIterator<TargetImagePtr> i(_findSelectedTarget());
while (i.hasNext())
{
i.next()->boundary->setCrop(percentage/100.0);
}
_updateTarget(true);
update();
}
void ImageScene::deleteSelection()
{
if (_currentFiles.size() == 0) {
return;
}
QList<QGraphicsItem *> list = selectedItems();
_currentState = MouseStateNone;
_currentMouseState = MouseStateNone;
for (int i=0; i<list.size(); i++) {
removeItem(list.at(i));
}
for (int i=list.size()-1; i>=0 ; i--) {
for (int j=0; j<_currentFiles[_currentIndex]->targets.size(); j++) {
if (list.at(i) == _currentFiles[_currentIndex]->targets[j]->boundary.get()) {
_currentFiles[_currentIndex]->targets.erase(
_currentFiles[_currentIndex]->targets.begin()+j);
}
}
}
clearSelection();
_updateTarget();
nextTarget(0);
_view->setCursor(Qt::CrossCursor);
}
void ImageScene::nextTarget(const int increment)
{
if (_currentFiles.size() == 0) {
return;
}
const int numTargets = _currentFiles[_currentIndex]->targets.size();
int pos = -1;
if (numTargets>0) {
const int num = selectedItems().size();
if (num == 0) {
if (increment > 0) {
pos = 0;
} else {
pos = numTargets - 1;
}
_currentFiles[_currentIndex]->targets[numTargets-1]->boundary->setSelected(true);
} else {
int currPos = 0;
for (int i=0; i<numTargets; i++) {
if (_currentFiles[_currentIndex]->targets[i]->boundary.get()
== selectedItems()[0]) {
currPos = i;
clearSelection();
break;
}
}
pos = currPos+increment < 0 ? numTargets-1 : (currPos+increment) % numTargets;
_currentTarget = _currentFiles[_currentIndex]->targets[pos];
_currentTarget->boundary->setSelected(true);
_updateTarget();
}
}
emit targetPosition(QString(tr("%1 of %2")).arg(pos+1).arg(_currentFiles[_currentIndex]->targets.size()));
}
void ImageScene::newAspectRatio(const double ratio)
{
_aspectRatio = ratio;
QListIterator<TargetImagePtr> i(_findSelectedTarget());
while (i.hasNext())
{
_correctAspectRatio(i.next());
}
_updateTarget(true);
}
bool ImageScene::_correctAspectRatio(TargetImagePtr target)
{
target->aspect = _aspectRatio;
if (_aspectRatio <=0) {
return false;
}
QPointF c[4];
for (int i=0; i<4; i++) c[i] = target->boundary->corners()[i];
const double width = _norm(c[0] - c[3]);
const double height = _norm(c[1] - c[0]);
const double currAspect = width > height ? (double)width/double(height) : (double)height/double(width);
if (qAbs(_aspectRatio - currAspect) < 1e-5) {
return false;
}
// fit with short side
if (width >= height) {
const double newHeight = 0.5 * width / _aspectRatio;
QPointF dir, center;
center = (c[0]+ c[1])/2.0;
dir = c[0]-c[1];
dir /= _norm(dir);
c[0] = center + newHeight * dir;
c[1] = center - newHeight * dir;
center = (c[3] + c[2])/2.0;
c[3] = center + newHeight * dir;
c[2] = center - newHeight * dir;
target->boundary->setCorners(c);
} else {
const double newWidth = 0.5 * height/ _aspectRatio;
QPointF dir, center;
center = (c[0]+ c[3])/2.0;
dir = c[0]-c[3];
dir /= _norm(dir);
c[0] = center + newWidth * dir;
c[3] = center - newWidth * dir;
center = (c[1] + c[2])/2.0;
c[1] = center + newWidth * dir;
c[2] = center - newWidth * dir;
target->boundary->setCorners(c);
}
return true;
}
void ImageScene::zoomFit()
{
_view->fitInView(_currentFiles[_currentIndex]->image.get(), Qt::KeepAspectRatio);
}
void ImageScene::zoom1()
{
if (_view == 0) {
return;
}
QPoint center (_view->width()/2, _view->height()/2);
QPointF centerScene = _currentFiles[_currentIndex]->image->mapFromParent(center.x(), center.y());
_view->resetMatrix();
_view->centerOn(centerScene.x(), centerScene.y());
}
void ImageScene::updateMinMax(const int mi, const int ma)
{
if ( _backgroundLoader != 0)
_backgroundLoader->updateMinMax(mi, ma);
}
void ImageScene::_onCopyError(SourceFilePtr source, TargetImagePtr)
{
QMessageBox::critical(_view,
tr("copy error"),
tr("Could not copy a target from scanned image '%s'' - enough disc space left ? enough RAM available ? If the images are too large, the 32bit version of this software might also be in trouble").arg(source->source.fileName()));
}
void ImageScene::getIsFirstLast(bool& isFirst, bool& isLast)
{
isFirst = _currentIndex <= 0;
isLast = _currentFiles.size() -1 == _currentIndex || _currentFiles.size() == 0;
}
void ImageScene::setEnforceAspect(const bool enforce)
{
_enforceAspectForNew = enforce;
}
void ImageScene::setDestination(QString destination)
{
_copyTargetThread.setDestination(destination);
}
void ImageScene::reloadFromNewSettings()
{
// the target extraction may still work in one of the old images
// so lock
while (!ExtractTargets::imageMutex.tryLock(50))
{
qApp->processEvents();
}
for (int i=0; i<_currentFiles.size(); i++) {
if (_currentFiles[i]->changed
&& i != _currentIndex) {
qDebug() << "resetting" << _currentFiles[i]->source.absoluteFilePath();
_currentFiles[i]->image = QGraphicsPixmapItemPtr();
_currentFiles[i]->imageOrig = QImage();
for (int j=0; j<_currentFiles[i]->targets.size(); j++) {
_currentFiles[i]->targets[j]->image = QImage();
}
_currentFiles[i]->targets.clear();
}
}
ExtractTargets::imageMutex.unlock();
loadPosition();
}
void ImageScene::refreshView()
{
QMessageBox::StandardButton reply = QMessageBox::question(_view, tr("refresh"),
tr("This will overwrite currently (and possibly saved) extracted images - continue ?"),
QMessageBox::Yes | QMessageBox::Abort);
bool save = reply == QMessageBox::Yes;
if (save)
{
while(!ExtractTargets::imageMutex.tryLock(50))
{
qApp->processEvents();
}
clear();
if (_currentIndex >=0) {
_currentFiles[_currentIndex]->changed = true;
_currentFiles[_currentIndex]->image = QGraphicsPixmapItemPtr();
_currentFiles[_currentIndex]->imageOrig = QImage();
for (int j=0; j<_currentFiles[_currentIndex]->targets.size(); j++) {
_currentFiles[_currentIndex]->targets[j]->image = QImage();
}
_currentFiles[_currentIndex]->targets.clear();
}
_currentFiles[_currentIndex]->error = false;
ExtractTargets::imageMutex.unlock();
loadPosition();
}
}
void ImageScene::selectAll()
{
QListIterator<QGraphicsItem* > i(items());
while (i.hasNext())
{
QGraphicsItem* item = i.next();
item->setSelected(true);
}
}
void ImageScene::clear()
{
// overwrite clear such that it does not delete it
// otherwise memory leaks with smart pointers
init();
}
void ImageScene::doneLoadingTarget(const TargetImagePtr &target)
{
if (_currentIndex >=0 && _currentIndex < _currentFiles.size())
{
for (int i=0; i<_currentFiles[_currentIndex]->targets.size(); i++)
{
/*QGraphicsItem::GraphicsItemFlags flags =
_currentFiles[_currentIndex] ->targets[i]->boundary->flags() & (~QGraphicsItem::ItemHasNoContents);
_currentFiles[_currentIndex]->targets[i]->boundary->setFlags(flags);*/
if (_currentFiles[_currentIndex]->targets[i]->workOnId == target->workOnId
&& _currentTarget.get() != 0 && _currentTarget->workOnId == target->workOnId) {
// the threading model does destroy the rendering -> hotfix re-add
emit updateTargetDisplay(QPixmap::fromImage(target->image));
emit setTargetWaiting(false);
}
if (_currentFiles[_currentIndex]->targets[i]->workOnId == target->workOnId)
{
removeItem(target->boundary.get());
addItem(target->boundary.get());
}
}
}
update();
_view->update();
}
void ImageScene::initialCropChanged(const double val)
{
_cropPercentage = val;
}