#include "scanpopup.h"
#include "tapp.h"
#include "menubarcommandids.h"
#include "texception.h"
#include "mainwindow.h"
#include "tsystem.h"
#include "timagecache.h"
#include "tgl.h"
#include "tcurveutil.h"
#include "tpixelutils.h"
#include "trop.h"
#include "tiio.h"
#include "toonz/tscenehandle.h"
#include "toonz/tframehandle.h"
#include "toonz/txshlevelhandle.h"
#include "toonz/toonzscene.h"
#include "toonz/observer.h"
#include "toonz/sceneproperties.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/stage2.h"
#include "toonz/glrasterpainter.h"
#include "tools/toolutils.h"
#include "toonz/preferences.h"
#include "toonz/cleanupparameters.h"
#include "toonz/tcleanupper.h"
#include "tools/toolhandle.h"
#include "tools/cursors.h"
#include "toonzqt/menubarcommand.h"
#include "toonzqt/doublefield.h"
#include "toonzqt/checkbox.h"
#include "toonzqt/gutil.h"
#include <QPushButton>
#include <QComboBox>
#include <QLabel>
#include <QSettings>
#include <QApplication>
using namespace DVGui;
using namespace CleanupTypes;
//-----------------------------------------------------------------------------
namespace {
const double previewDPI = 64;
//-----------------------------------------------------------------------------
const QString BlackAndWhite = "Black & White", Graytones = "Graytones",
Rgbcolors = "RGB Color";
bool ScannerHasBeenDefined = false;
void checkPaperFormat(TScannerParameters *parameters) {
if (parameters->getPaperOverflow()) {
TScanner *scanner = TScanner::instance();
QString scannerName = scanner ? scanner->getName() : "no scanner";
DVGui::warning(
QObject::tr("The selected paper format is not available for %1.")
.arg(scannerName));
}
}
//-----------------------------------------------------------------------------
bool defineScanner(const QString &scannerType) {
bool ret = false;
QApplication::setOverrideCursor(Qt::WaitCursor);
TScanner::m_isTwain = (scannerType == "TWAIN");
try {
if (!TScanner::instance()->isDeviceAvailable()) {
DVGui::warning(TScanner::m_isTwain
? QObject::tr("No TWAIN scanner is available")
: QObject::tr("No scanner is available"));
/* FIXME: try/catch からの goto
って合法じゃないだろ……。とりあえず応急処置したところ"例外ってナニ?"って感じになったのが
indent も腐っておりつらいので後で直す */
// goto end;
QApplication::restoreOverrideCursor();
return false;
}
TScanner::instance()->selectDevice();
} catch (TException &e) {
DVGui::warning(QString::fromStdWString(e.getMessage()));
QApplication::restoreOverrideCursor();
return false;
// goto end;
}
TScannerParameters *scanParameters = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
try {
scanParameters->adaptToCurrentScanner();
} catch (TException &e) {
DVGui::warning(QString::fromStdWString(e.getMessage()));
// goto end;
QApplication::restoreOverrideCursor();
return false;
}
scanParameters->updatePaperFormat();
checkPaperFormat(scanParameters);
// ScanSettingsPopup::instance()->updateUI();
ret = true;
// end:
QApplication::restoreOverrideCursor();
return ret;
}
//-----------------------------------------------------------------------------
bool checkScannerDefinition() {
if (!ScannerHasBeenDefined) {
QString scannerType = QSettings().value("CurrentScannerType").toString();
if (scannerType == "") {
QSettings().setValue("CurrentScannerType", "Internal");
scannerType = "Internal";
}
ScannerHasBeenDefined = defineScanner(scannerType);
}
return ScannerHasBeenDefined;
}
//-----------------------------------------------------------------------------
void fillOutputType(QComboBox *t, TScannerParameters *params) {
while (t->count()) t->removeItem(0);
if (params->isSupported(TScannerParameters::BW)) t->addItem(BlackAndWhite);
if (params->isSupported(TScannerParameters::GR8)) t->addItem(Graytones);
if (params->isSupported(TScannerParameters::RGB24)) t->addItem(Rgbcolors);
}
//-----------------------------------------------------------------------------
TPixelGR8 fromRGB(int r, int g, int b) {
return TPixelGR8(
(((UINT)(r)*19594 + (UINT)(g)*38472 + (UINT)(b)*7470 + (UINT)(1 << 15)) >>
16));
}
//-----------------------------------------------------------------------------
void makeTransparent(const TRaster32P &ras) {
if (!ras) return;
TRop::addBackground(ras, TPixel32::White);
int x, y;
for (x = 0; x < ras->getLx(); x++) {
for (y = 0; y < ras->getLy(); y++) {
TPixel32 *pix = &ras->pixels(y)[x];
TPixelGR8 pixGR8 = fromRGB(pix->r, pix->g, pix->b);
int value = pixGR8.value;
pix->m = (UCHAR)tcrop<SHORT>(255 - value, 0, 255);
premult(*pix);
}
}
}
//=============================================================================
} // namespace
//=============================================================================
/*! \class DefineScannerPopup
\brief The DefineScannerPopup class provides a modal dialog to
choose and define a scan for application.
Inherits \b Dialog.
*/
//-----------------------------------------------------------------------------
DefineScannerPopup::DefineScannerPopup()
: Dialog(TApp::instance()->getMainWindow(), true,
Preferences::instance()->getCurrentLanguage() == "English",
"DefineScanner") {
#ifdef MACOSX
setModal(false);
#endif
setWindowTitle(tr("Define Scanner"));
m_scanDriverOm = new QComboBox();
m_scanDriverOm->setFixedSize(150, WidgetHeight);
m_scanDriverOm->addItem(tr("TWAIN"), "TWAIN");
m_scanDriverOm->addItem(tr("Internal"), "Internal");
addWidget(tr("Scanner Driver:"), m_scanDriverOm);
if (QSettings().value("CurrentScannerType").toString() == "Internal")
m_scanDriverOm->setCurrentIndex(m_scanDriverOm->findData("Internal"));
QPushButton *okBtn = new QPushButton(tr("OK"), this);
okBtn->setDefault(true);
QPushButton *cancelBtn = new QPushButton(tr("Cancel"), this);
connect(okBtn, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
addButtonBarWidget(okBtn, cancelBtn);
}
//-----------------------------------------------------------------------------
void DefineScannerPopup::accept() {
QString scannerType = m_scanDriverOm->currentData().toString();
if (QSettings().value("CurrentScannerType").toString() != scannerType ||
!ScannerHasBeenDefined) {
QSettings().setValue("CurrentScannerType", scannerType);
ScannerHasBeenDefined = defineScanner(scannerType);
QAction *setCropAction =
CommandManager::instance()->getAction("MI_SetScanCropbox");
QAction *resetCropAction =
CommandManager::instance()->getAction("MI_ResetScanCropbox");
if (scannerType == "TWAIN")
setCropAction->setDisabled(true);
else
setCropAction->setDisabled(false);
resetCropAction->setDisabled(true);
}
QDialog::accept();
}
//-----------------------------------------------------------------------------
//=============================================================================
/*! \class ScanSettingsPopup
\brief The ScanSettingsPopup class provides a dialog to change
scan settings.
Inherits \b Dialog.
*/
//-----------------------------------------------------------------------------
ScanSettingsPopup::ScanSettingsPopup()
: Dialog(TApp::instance()->getMainWindow(), false, true, "ScanSettings") {
setWindowTitle(tr("Scan Settings"));
m_scannerNameLbl = new QLabel(tr("[no scanner]"));
addWidget(m_scannerNameLbl);
beginVLayout();
m_paperFormatOm = new QComboBox();
m_paperFormatOm->setFixedSize(150, WidgetHeight);
std::vector<std::string> formats;
TPaperFormatManager::instance()->getFormats(formats);
int i;
for (i = 0; i < (int)formats.size(); i++)
m_paperFormatOm->addItem(QString(formats[i].c_str()));
addWidgets(m_formatLbl = new QLabel(tr("Paper Format:")), m_paperFormatOm);
m_reverseOrderCB = new CheckBox(tr("Reverse Order"));
m_reverseOrderCB->setFixedSize(150, WidgetHeight);
addWidget(m_reverseOrderCB);
m_paperFeederCB = new CheckBox(tr("Paper Feeder"));
m_paperFeederCB->setFixedSize(150, WidgetHeight);
addWidget(m_paperFeederCB);
m_dpi = new DVGui::DoubleField();
addWidgets(m_dpiLbl = new QLabel(tr("Dpi: ")), m_dpi);
m_dpi->hide();
m_dpiLbl->hide();
m_modeOm = new QComboBox();
m_modeOm->setMaximumHeight(WidgetHeight);
addWidgets(m_modeLbl = new QLabel(tr("Mode:")), m_modeOm);
m_threshold = new DVGui::IntField();
addWidgets(m_thresholdLbl = new QLabel(tr("Threshold: ")), m_threshold);
m_threshold->hide(), m_thresholdLbl->hide();
m_brightness = new DVGui::IntField();
addWidgets(m_brightnessLbl = new QLabel(tr("Brightness: ")), m_brightness);
m_brightness->hide(), m_brightnessLbl->hide();
endVLayout();
connectAll();
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::showEvent(QShowEvent *event) {
connectAll();
updateUI();
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::hideEvent(QHideEvent *event) {
disconnectAll();
Dialog::hideEvent(event);
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::connectAll() {
bool ret = true;
ret = ret &&
connect(m_paperFormatOm, SIGNAL(currentIndexChanged(const QString &)),
SLOT(onPaperChanged(const QString &)));
ret = ret && connect(m_reverseOrderCB, SIGNAL(stateChanged(int)),
SLOT(onToggle(int)));
ret = ret && connect(m_paperFeederCB, SIGNAL(stateChanged(int)),
SLOT(onToggle(int)));
ret = ret &&
connect(m_dpi, SIGNAL(valueChanged(bool)), SLOT(onValueChanged(bool)));
ret = ret && connect(m_brightness, SIGNAL(valueChanged(bool)),
SLOT(onValueChanged(bool)));
ret = ret && connect(m_threshold, SIGNAL(valueChanged(bool)),
SLOT(onValueChanged(bool)));
ret = ret && connect(m_modeOm, SIGNAL(currentIndexChanged(const QString &)),
SLOT(onModeChanged(const QString &)));
ret = ret && connect(TApp::instance()->getCurrentScene(),
SIGNAL(sceneSwitched()), SLOT(updateUI()));
assert(ret);
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::disconnectAll() {
bool ret = true;
ret = ret && m_paperFormatOm->disconnect();
ret = ret && m_reverseOrderCB->disconnect();
ret = ret && m_paperFeederCB->disconnect();
ret = ret && m_dpi->disconnect();
ret = ret && m_threshold->disconnect();
ret = ret && m_brightness->disconnect();
ret = ret && m_modeOm->disconnect();
ret = ret && disconnect(TApp::instance()->getCurrentScene(),
SIGNAL(sceneSwitched()), this, SLOT(updateUI()));
assert(ret);
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::onValueChanged(bool) {
TScannerParameters *params = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
params->m_dpi.m_value = m_dpi->getValue();
params->m_threshold.m_value = m_threshold->getValue();
params->m_brightness.m_value = m_brightness->getValue();
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::onToggle(int) {
TScannerParameters *sp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
sp->setReverseOrder(m_reverseOrderCB->isChecked());
sp->enablePaperFeeder(m_paperFeederCB->isChecked());
}
//-----------------------------------------------------------------------------
void ScanSettingsPopup::onPaperChanged(const QString &format) {
if (!ScannerHasBeenDefined) return;
TScannerParameters *sp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
sp->setPaperFormat(format.toStdString());
sp->setCropBox(sp->getScanArea());
checkPaperFormat(sp);
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::onModeChanged(const QString &mode) {
if (!ScannerHasBeenDefined) return;
TScannerParameters *sp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
m_threshold->setVisible(false);
m_thresholdLbl->setVisible(false);
if (mode == BlackAndWhite) {
sp->setScanType(TScannerParameters::BW);
m_threshold->setVisible(true);
m_thresholdLbl->setVisible(true);
} else if (mode == Graytones)
sp->setScanType(TScannerParameters::GR8);
else if (mode == Rgbcolors)
sp->setScanType(TScannerParameters::RGB24);
else {
// assert(0);
sp->setScanType(TScannerParameters::None);
}
}
//------------------------------------------------------------------------------
void ScanSettingsPopup::updateUI() {
disconnectAll();
checkScannerDefinition();
TScannerParameters *params = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
QApplication::setOverrideCursor(Qt::WaitCursor);
params->adaptToCurrentScanner();
QApplication::restoreOverrideCursor();
TScanner *scanner = TScanner::instance();
m_scannerNameLbl->setText(scanner && scanner->getName() != ""
? scanner->getName()
: tr("[no scanner]"));
m_reverseOrderCB->setChecked(params->isReverseOrder());
m_paperFeederCB->setChecked(params->m_paperFeeder.m_value == 1.0);
if (params->m_dpi.m_supported) {
if (params->m_dpi.m_max > params->m_dpi.m_min) {
m_dpi->setRange(params->m_dpi.m_min, params->m_dpi.m_max);
m_dpi->setValue(params->m_dpi.m_value);
}
m_dpi->show(), m_dpiLbl->show();
} else
m_dpi->hide(), m_dpiLbl->hide();
if (TScanner::m_isTwain) {
m_paperFeederCB->hide();
m_modeOm->hide(), m_modeLbl->hide();
m_paperFormatOm->hide(), m_formatLbl->hide();
m_threshold->hide(), m_thresholdLbl->hide();
m_brightness->hide(), m_brightnessLbl->hide();
connectAll();
return;
}
m_paperFeederCB->show();
m_modeOm->show(), m_modeLbl->show();
m_paperFormatOm->show(), m_formatLbl->show();
disconnect(m_modeOm);
fillOutputType(m_modeOm, params);
connect(m_modeOm, SIGNAL(currentIndexChanged(const QString &)),
SLOT(onModeChanged(const QString &)));
m_modeOm->setEnabled(true);
switch (params->getScanType()) {
case TScannerParameters::BW:
m_modeOm->setCurrentIndex(m_modeOm->findText(BlackAndWhite));
break;
case TScannerParameters::GR8:
m_modeOm->setCurrentIndex(m_modeOm->findText(Graytones));
break;
case TScannerParameters::RGB24:
m_modeOm->setCurrentIndex(m_modeOm->findText(Rgbcolors));
break;
default:
m_modeOm->setEnabled(false);
break;
}
m_paperFormatOm->setCurrentIndex(m_paperFormatOm->findText(
QString::fromStdString(params->getPaperFormat())));
if (params->m_threshold.m_supported) {
m_threshold->setRange(params->m_threshold.m_min, params->m_threshold.m_max);
m_threshold->setValue(params->m_threshold.m_value);
if (params->getScanType() == TScannerParameters::BW) {
m_threshold->show();
m_thresholdLbl->show();
} else {
m_threshold->hide();
m_thresholdLbl->hide();
}
}
if (params->m_brightness.m_supported) {
if (params->m_brightness.m_max > params->m_brightness.m_min) {
m_brightness->setRange(params->m_brightness.m_min,
params->m_brightness.m_max);
m_brightness->setValue(params->m_brightness.m_value);
}
m_brightness->show(), m_brightnessLbl->show();
} else
m_brightness->hide(), m_brightnessLbl->hide();
connectAll();
}
#ifdef LINETEST
//-----------------------------------------------------------------------------
AutocenterPopup::AutocenterPopup() : DVGui::Dialog(0, false, true) {
setWindowTitle(tr("Autocenter"));
QGridLayout *settingsLayout = new QGridLayout(this);
settingsLayout->setSizeConstraint(QLayout::SetFixedSize);
settingsLayout->setSpacing(5);
settingsLayout->setMargin(12);
int row = 0;
// AutoCenter
QWidget *w = new QWidget();
w->setFixedWidth(70);
settingsLayout->addWidget(w, row, 0);
m_autocenter = new CheckBox(tr("Autocenter"), this);
m_autocenter->setFixedSize(150, WidgetHeight);
settingsLayout->addWidget(m_autocenter, row, 1, Qt::AlignLeft);
++row;
// Pegbar Holse
settingsLayout->addWidget(new QLabel(tr("Pegbar Holes:")), row, 0,
Qt::AlignRight);
m_pegbarHoles = new QComboBox(this);
m_pegbarHoles->setFixedHeight(WidgetHeight);
m_pegbarHoles->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);
QStringList pegbarHoles;
pegbarHoles << "Bottom"
<< "Top"
<< "Left"
<< "Right";
m_pegbarHoles->addItems(pegbarHoles);
settingsLayout->addWidget(m_pegbarHoles, row, 1, Qt::AlignLeft);
++row;
// Field Guide
settingsLayout->addWidget(new QLabel(tr("Field Guide:")), row, 0,
Qt::AlignRight);
m_fieldGuide = new QComboBox(this);
m_fieldGuide->setFixedHeight(WidgetHeight);
m_fieldGuide->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);
std::vector<std::string> fdgNames;
CleanupParameters::getFdgNames(fdgNames);
int i;
for (i = 0; i < (int)fdgNames.size(); i++)
m_fieldGuide->addItem(QString(fdgNames[i].c_str()));
settingsLayout->addWidget(m_fieldGuide, row, 1, Qt::AlignLeft);
++row;
beginHLayout();
addLayout(settingsLayout, false);
endHLayout();
bool ret = true;
ret = ret && connect(m_autocenter, SIGNAL(toggled(bool)), this,
SLOT(onAutocenterToggled(bool)));
ret = ret &&
connect(m_pegbarHoles, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(onPegbarHolesChanged(const QString &)));
ret =
ret && connect(m_fieldGuide, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(onFieldGuideChanged(const QString &)));
assert(ret);
}
//-----------------------------------------------------------------------------
void AutocenterPopup::showEvent(QShowEvent *e) {
CleanupParameters *cp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCleanupParameters();
m_autocenter->setChecked(cp->m_autocenterType == AUTOCENTER_FDG);
CleanupTypes::PEGS_SIDE type = cp->m_pegSide;
switch (cp->m_pegSide) {
case PEGS_BOTTOM:
m_pegbarHoles->setCurrentIndex(0);
break;
case PEGS_TOP:
m_pegbarHoles->setCurrentIndex(1);
break;
case PEGS_LEFT:
m_pegbarHoles->setCurrentIndex(2);
break;
case PEGS_RIGHT:
m_pegbarHoles->setCurrentIndex(3);
break;
default:
assert(false);
}
QString fieldName = QString::fromStdString(cp->getFdgName());
int index = (fieldName == "") ? 0 : m_fieldGuide->findText(fieldName);
assert(index != -1);
m_fieldGuide->setCurrentIndex(index);
}
//-----------------------------------------------------------------------------
void AutocenterPopup::onAutocenterToggled(bool toggled) {
CleanupParameters *cp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCleanupParameters();
cp->m_autocenterType = toggled ? AUTOCENTER_FDG : AUTOCENTER_NONE;
}
//-----------------------------------------------------------------------------
void AutocenterPopup::onPegbarHolesChanged(const QString &pg) {
CleanupParameters *cp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCleanupParameters();
CleanupTypes::PEGS_SIDE type;
if (pg == "Bottom") type = PEGS_BOTTOM;
if (pg == "Top") type = PEGS_TOP;
if (pg == "Left") type = PEGS_LEFT;
if (pg == "Right") type = PEGS_RIGHT;
if (cp->m_pegSide == type) return;
cp->m_pegSide = type;
}
//-----------------------------------------------------------------------------
void AutocenterPopup::onFieldGuideChanged(const QString &fg) {
CleanupParameters *cp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCleanupParameters();
if (cp->getFdgName() == fg.toStdString()) return;
cp->setFdgByName(fg.toStdString());
}
//-----------------------------------------------------------------------------
#endif
MyScannerListener::MyScannerListener(const ScanList &scanList)
: m_scanList(scanList)
, m_current(0)
, m_inc(+1)
, m_isCanceled(false)
, m_progressDialog(0) {
TScannerParameters *parameters = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
m_isPreview = parameters->isPreview();
if (m_isPreview) return;
if (parameters->isPaperFeederEnabled()) {
int frameCount = m_scanList.getFrameCount();
ScanListFrame frame = m_scanList.getFrame(m_current);
TXshSimpleLevel *newXl = frame.getLevel();
TFilePath levelName(newXl->getName());
QString imageName =
toQString(levelName.withFrame(frame.getFrameId())) + QString(".tif");
QString text = tr("Scanning in progress: ") + imageName + " 1/" +
QString::number(frameCount);
m_progressDialog =
new DVGui::ProgressDialog(text, QObject::tr("Cancel"), 0, frameCount);
connect(m_progressDialog, SIGNAL(canceled()), this,
SLOT(cancelButtonPressed()));
m_progressDialog->setWindowModality(Qt::WindowModal);
m_progressDialog->show();
}
if (parameters->isReverseOrder()) {
m_current = m_scanList.getFrameCount() - 1;
m_inc = -1;
}
}
//-----------------------------------------------------------------------------
void MyScannerListener::onImage(const TRasterImageP &rasImg) {
if (!rasImg || !rasImg->getRaster()) {
DVGui::warning(tr("The pixel type is not supported."));
m_current += m_inc;
return;
}
if (!m_isPreview &&
(m_current < 0 || m_current >= m_scanList.getFrameCount())) {
DVGui::warning(tr("The scanning process is completed."));
return;
}
if (m_isPreview) {
TImageCache::instance()->add((std::string) "setScanCropboxId",
rasImg.getPointer());
} else {
#ifdef LINETEST
// Autocenter
CleanupParameters *cp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getCleanupParameters();
if (cp->m_autocenterType != AUTOCENTER_NONE) {
bool autocentered;
TCleanupper *cl = TCleanupper::instance();
cl->setParameters(cp);
TRasterImageP outImg = cl->autocenterOnly(rasImg, false, autocentered);
if (!autocentered)
DVGui::warning(
QObject::tr("The autocentering failed on the current drawing."));
else
rasImg->setRaster(outImg->getRaster());
}
makeTransparent(rasImg->getRaster());
#endif
TScannerParameters *params = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
ScanListFrame frame = m_scanList.getFrame(m_current);
bool isBW = false;
if (params->getScanType() == TScannerParameters::BW) {
isBW = true;
rasImg->setScanBWFlag(true);
Tiio::Writer::setBlackAndWhiteThreshold(params->m_threshold.m_value);
}
frame.setRasterImage(rasImg, isBW);
TApp::instance()->getCurrentFrame()->setFid(frame.getFrameId());
TApp::instance()->getCurrentScene()->notifyCastChange();
TApp::instance()->getCurrentLevel()->notifyLevelChange();
m_current += m_inc;
}
}
//-----------------------------------------------------------------------------
void MyScannerListener::onError() {
if (m_progressDialog) m_progressDialog->hide();
DVGui::warning(tr("There was an error during the scanning process."));
}
//-----------------------------------------------------------------------------
void MyScannerListener::onNextPaper() {
assert(!m_isPreview);
if (TScanner::instance()->m_isTwain)
DVGui::info(
tr("Please, place the next paper drawing on the scanner flatbed, then "
"select the relevant command in the TWAIN interface."));
else {
QString question(
tr("Please, place the next paper drawing on the scanner flatbed, then "
"click the Scan button."));
int ret =
DVGui::MsgBox(question, QObject::tr("Scan"), QObject::tr("Cancel"), 0);
if (ret == 2 || ret == 0) m_isCanceled = true;
}
}
//-----------------------------------------------------------------------------
void MyScannerListener::onAutomaticallyNextPaper() {
assert(!m_isPreview);
assert(!!m_progressDialog);
int frameCount = m_scanList.getFrameCount();
int step = m_inc == -1 ? frameCount - m_current - 1 : m_current;
if (step < frameCount) {
ScanListFrame frame = m_scanList.getFrame(m_current);
TXshSimpleLevel *newXl = frame.getLevel();
TFilePath levelName(newXl->getName());
QString imageName =
toQString(levelName.withFrame(frame.getFrameId())) + QString(".tif");
m_progressDialog->setLabelText(tr("Scanning in progress: ") + imageName +
QString::number(m_current + 1) + " /" +
QString::number(frameCount));
}
m_progressDialog->setValue(step);
if (m_progressDialog && (step == frameCount)) m_progressDialog->hide();
}
//-----------------------------------------------------------------------------
bool MyScannerListener::isCanceled() { return m_isCanceled; }
//-----------------------------------------------------------------------------
void MyScannerListener::cancelButtonPressed() {
assert(!!m_progressDialog);
m_isCanceled = true;
}
//=============================================================================
//
static void doScan() {
if (!checkScannerDefinition()) return;
ScanList scanList;
if (scanList.areScannedFramesSelected()) {
int ret = DVGui::MsgBox(
QObject::tr("Some of the selected drawings were already scanned. Do "
"you want to scan them again?"),
QObject::tr("Scan"), QObject::tr("Don't Scan"), QObject::tr("Cancel"));
if (ret == 3) return;
scanList.update(ret == 1);
} else
scanList.update(true);
if (scanList.getFrameCount() == 0) {
DVGui::warning(QObject::tr("There are no frames to scan."));
return;
}
try {
TScanner *scanner = TScanner::instance();
int rc = scanner->isDeviceAvailable();
if (!rc) {
DVGui::warning(QObject::tr("TWAIN is not available."));
return;
}
MyScannerListener lst(scanList);
scanner->addListener(&lst);
TScannerParameters *sp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
sp->adaptToCurrentScannerIfNeeded();
scanner->acquire(*sp, scanList.getFrameCount());
scanner->removeListener(&lst);
SetScanCropboxCheck *cropboxCheck = SetScanCropboxCheck::instance();
if (cropboxCheck->isEnabled()) cropboxCheck->uncheck();
} catch (TException &e) {
DVGui::warning(QString::fromStdWString(e.getMessage()));
}
// If some levels were scanned successfully, their renumber table must be
// updated.
// A level's renumber table is usually updated when it is either loaded or
// before saving -
// this is a similar case, where a level is filled with frames.
// An empty renumber table means that a renumbering operation was carried out
// with all frames
// being eradicated - which may lead to the level being saved with missing
// frames.
int i, frameCount = scanList.getFrameCount();
TXshSimpleLevel *oldLevel = 0, *level;
for (i = 0; i < frameCount; ++i) {
level = scanList.getFrame(i).getLevel();
if (level != oldLevel) level->setRenumberTable();
oldLevel = level;
}
}
//-----------------------------------------------------------------------------
OpenPopupCommandHandler<DefineScannerPopup> openDefineScannerPopup(
MI_DefineScanner);
OpenPopupCommandHandler<ScanSettingsPopup> openScanSettingsPopup(
MI_ScanSettings);
#ifdef LINETEST
OpenPopupCommandHandler<AutocenterPopup> openAutocenterPopup(MI_Autocenter);
#endif
class ScanCommand final : public MenuItemHandler {
public:
ScanCommand() : MenuItemHandler("MI_Scan") {}
void execute() override { doScan(); }
} ScanCommand;
//=========================================================================================
//
// SetCropboxCommand
//
//=========================================================================================
class SetCropboxCommand final : public MenuItemHandler {
TTool *m_currentTool;
public:
SetCropboxCommand()
: MenuItemHandler("MI_SetScanCropbox"), m_currentTool(0) {}
void execute() override {
TApp *app = TApp::instance();
SetScanCropboxCheck *cropboxCheck = SetScanCropboxCheck::instance();
cropboxCheck->setIsEnabled(!cropboxCheck->isEnabled());
TScannerParameters *sp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
QAction *resetCropAction =
CommandManager::instance()->getAction("MI_ResetScanCropbox");
if (!cropboxCheck->isEnabled()) {
if (m_currentTool)
app->getCurrentTool()->setTool(
QString::fromStdString(m_currentTool->getName()));
return;
}
if (!checkScannerDefinition()) return;
ScanList scanList;
scanList.update(true);
try {
TScanner *scanner = TScanner::instance();
int rc = scanner->isDeviceAvailable();
if (!rc) {
DVGui::warning(QObject::tr("TWAIN is not available."));
return;
}
double currentDPI = sp->m_dpi.m_value;
sp->m_dpi.m_value = previewDPI;
double reverse = sp->isReverseOrder();
sp->setReverseOrder(false);
sp->setIsPreview(true);
MyScannerListener lst(scanList);
scanner->addListener(&lst);
sp->adaptToCurrentScannerIfNeeded();
scanner->acquire(*sp, 1);
scanner->removeListener(&lst);
sp->m_dpi.m_value = currentDPI;
sp->setReverseOrder(reverse);
m_currentTool = app->getCurrentTool()->getTool();
app->getCurrentTool()->setTool("T_SetScanCropbox");
sp->setIsPreview(false);
if (resetCropAction) resetCropAction->setDisabled(false);
} catch (TException &e) {
DVGui::warning(QString::fromStdWString(e.getMessage()));
}
}
} setCropboxCommand;
//=========================================================================================
//
// ResetCropboxCommand
//
//=========================================================================================
class ResetCropboxCommand final : public MenuItemHandler {
public:
ResetCropboxCommand() : MenuItemHandler("MI_ResetScanCropbox") {}
void execute() override {
TScannerParameters *sp = TApp::instance()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
sp->setCropBox(sp->getScanArea());
}
} resetCropboxCommand;
//=========================================================================================
//
// SetScanCropboxTool
//
//=========================================================================================
class SetScanCropboxTool final : public TTool {
const std::string m_imgId;
TScannerParameters *m_parameters;
int m_scaling;
TPointD m_lastPos;
enum { eNone, eMove, e00, e01, e10, e11, eM0, e1M, eM1, e0M };
public:
SetScanCropboxTool()
: TTool("T_SetScanCropbox")
, m_imgId("setScanCropboxId")
, m_scaling(eNone)
, m_lastPos() {
bind(TTool::AllTargets); // Deals with tool deactivation internally
}
//-----------------------------------------------------------------------------
ToolType getToolType() const override { return TTool::GenericTool; }
//-----------------------------------------------------------------------------
void draw() override {
TRasterImageP ri = TImageCache::instance()->get(m_imgId, false);
if (ri) {
TPointD center = ri->getRaster()->getCenterD();
GLRasterPainter::drawRaster(
TScale(Stage::inch / previewDPI, Stage::inch / previewDPI), ri, true);
}
TRectD cropBox = rect2pix(m_parameters->getCropBox());
double pixelSize = getPixelSize();
tglColor(TPixel::Red);
glLineStipple(1, 0xFFFF);
glEnable(GL_LINE_STIPPLE);
tglDrawRect(cropBox);
TPointD size(10, 10);
tglColor(TPixel::Red);
ToolUtils::drawSquare(cropBox.getP00(), pixelSize * 4, TPixel::Red);
ToolUtils::drawSquare(cropBox.getP01(), pixelSize * 4, TPixel::Red);
ToolUtils::drawSquare(cropBox.getP10(), pixelSize * 4, TPixel::Red);
ToolUtils::drawSquare(cropBox.getP11(), pixelSize * 4, TPixel::Red);
TPointD center = (cropBox.getP00() + cropBox.getP11()) * 0.5;
ToolUtils::drawSquare(TPointD(center.x, cropBox.y0), pixelSize * 4,
TPixel::Red); // draw M0 handle
ToolUtils::drawSquare(TPointD(cropBox.x1, center.y), pixelSize * 4,
TPixel::Red); // draw 1M handle
ToolUtils::drawSquare(TPointD(center.x, cropBox.y1), pixelSize * 4,
TPixel::Red); // draw M1 handle
ToolUtils::drawSquare(TPointD(cropBox.x0, center.y), pixelSize * 4,
TPixel::Red); // draw 0M handle
glDisable(GL_LINE_STIPPLE);
}
//-----------------------------------------------------------------------------
void mouseMove(const TPointD &p, const TMouseEvent &e) override {
double pixelSize = getPixelSize();
TPointD size(10 * pixelSize, 10 * pixelSize);
TRectD cropBox = rect2pix(m_parameters->getCropBox());
double maxDist = 5 * pixelSize;
if (TRectD(cropBox.getP00() - size, cropBox.getP00() + size).contains(p))
m_scaling = e00;
else if (TRectD(cropBox.getP01() - size, cropBox.getP01() + size)
.contains(p))
m_scaling = e01;
else if (TRectD(cropBox.getP11() - size, cropBox.getP11() + size)
.contains(p))
m_scaling = e11;
else if (TRectD(cropBox.getP10() - size, cropBox.getP10() + size)
.contains(p))
m_scaling = e10;
else if (isCloseToSegment(p, TSegment(cropBox.getP00(), cropBox.getP10()),
maxDist))
m_scaling = eM0;
else if (isCloseToSegment(p, TSegment(cropBox.getP10(), cropBox.getP11()),
maxDist))
m_scaling = e1M;
else if (isCloseToSegment(p, TSegment(cropBox.getP11(), cropBox.getP01()),
maxDist))
m_scaling = eM1;
else if (isCloseToSegment(p, TSegment(cropBox.getP01(), cropBox.getP00()),
maxDist))
m_scaling = e0M;
else if (cropBox.contains(p))
m_scaling = eMove;
else
m_scaling = eNone;
}
//-----------------------------------------------------------------------------
void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override {
m_lastPos = pos;
}
//-----------------------------------------------------------------------------
void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override {
TPointD dp = pos - m_lastPos;
double scaleFactor = Stage::inch / previewDPI;
dp.x = ((dp.x / scaleFactor) * 25.4) / previewDPI;
dp.y = ((dp.y / scaleFactor) * 25.4) / previewDPI;
TRectD scanArea = m_parameters->getScanArea();
TRectD cropBox = m_parameters->getCropBox();
if (m_scaling != eNone && m_scaling != eMove) {
if ((m_scaling == eM1 ||
((m_scaling == e11 || m_scaling == e01) && !e.isShiftPressed())) &&
cropBox.x0 - dp.y < cropBox.x1)
cropBox.x0 -= dp.y;
if ((m_scaling == eM0 ||
((m_scaling == e10 || m_scaling == e00) && !e.isShiftPressed())) &&
cropBox.x1 - dp.y > cropBox.x0)
cropBox.x1 -= dp.y;
if ((m_scaling == e0M ||
((m_scaling == e00 || m_scaling == e01) && !e.isShiftPressed())) &&
cropBox.y1 - dp.x > cropBox.y0)
cropBox.y1 -= dp.x;
if ((m_scaling == e1M ||
((m_scaling == e11 || m_scaling == e10) && !e.isShiftPressed())) &&
cropBox.y0 - dp.x < cropBox.y1)
cropBox.y0 -= dp.x;
if (e.isShiftPressed()) {
TPointD delta;
delta.x = (fabs(dp.x) > fabs(dp.y)) ? dp.x : dp.y;
delta.y = delta.x * scanArea.getLx() / scanArea.getLy();
if (m_scaling == e11) {
if (cropBox.y0 - delta.x < cropBox.y1) cropBox.y0 -= delta.x;
if (cropBox.x0 - delta.y < cropBox.x1) cropBox.x0 -= delta.y;
} else if (m_scaling == e00) {
if (cropBox.y1 - delta.x > cropBox.y0) cropBox.y1 -= delta.x;
if (cropBox.x1 - delta.y > cropBox.x0) cropBox.x1 -= delta.y;
} else if (m_scaling == e01) {
if (cropBox.y1 - delta.x > cropBox.y0) cropBox.y1 -= delta.x;
if (cropBox.x0 - delta.y < cropBox.x1) cropBox.x0 -= delta.y;
}
if (m_scaling == e10) {
if (cropBox.y0 - delta.x < cropBox.y1) cropBox.y0 -= delta.x;
if (cropBox.x1 - delta.y > cropBox.x0) cropBox.x1 -= delta.y;
}
}
cropBox *= scanArea;
if (cropBox != m_parameters->getCropBox()) {
m_parameters->setCropBox(cropBox);
m_lastPos = pos;
}
} else if (m_scaling == eMove) {
cropBox += TPointD(-dp.y, 0);
if (scanArea.contains(cropBox)) m_parameters->setCropBox(cropBox);
cropBox += TPointD(0, -dp.x);
if (scanArea.contains(cropBox)) m_parameters->setCropBox(cropBox);
m_lastPos = pos;
}
invalidate();
}
//-----------------------------------------------------------------------------
int getCursorId() const override {
switch (m_scaling) {
case eNone:
return ToolCursor::StrokeSelectCursor;
case eMove:
return ToolCursor::MoveCursor;
case e11:
case e00:
return ToolCursor::ScaleCursor;
case e10:
case e01:
return ToolCursor::ScaleInvCursor;
case e1M:
case e0M:
return ToolCursor::ScaleHCursor;
case eM1:
case eM0:
return ToolCursor::ScaleVCursor;
default:
assert(false);
}
return 0;
}
//-----------------------------------------------------------------------------
void onActivate() override {
m_parameters = TTool::getApplication()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
}
void onEnter() override {
m_parameters = TTool::getApplication()
->getCurrentScene()
->getScene()
->getProperties()
->getScanParameters();
}
//-----------------------------------------------------------------------------
private:
TRectD rect2pix(const TRectD &rect) {
const double f = 25.4;
TRectD scanArea = m_parameters->getScanArea();
TPointD scanAreaCenter = (scanArea.getP00() + scanArea.getP11()) * 0.5;
double scaleFactor = Stage::inch / previewDPI;
double cbOffsetx =
(((rect.x0 - scanAreaCenter.x) * previewDPI) / f) * scaleFactor;
double cbOffsety =
(((rect.y0 - scanAreaCenter.y) * previewDPI) / f) * scaleFactor;
double cbSizelx = (((rect.x1 - rect.x0) * previewDPI) / f) * scaleFactor;
double cbSizely = (((rect.y1 - rect.y0) * previewDPI) / f) * scaleFactor;
TRectD rectPix(TPointD(cbOffsetx, cbOffsety),
TDimensionD(cbSizelx, cbSizely));
return TRectD(-rectPix.y1, -rectPix.x1, -rectPix.y0, -rectPix.x0);
}
} setScanCropboxTool;