Commit 79609c4d authored by Alexander Stippich's avatar Alexander Stippich
Browse files

implement a page size ksaneoption

parent df26f294
......@@ -41,6 +41,7 @@ set(ksane_SRCS
options/ksanedoubleoption.cpp
options/ksanelistoption.cpp
options/ksaneinvertoption.cpp
options/ksanepagesizeoption.cpp
)
ecm_qt_declare_logging_category(ksane_SRCS
......
......@@ -10,6 +10,13 @@
*
* ============================================================ */
// Sane includes
extern "C"
{
#include <sane/saneopts.h>
#include <sane/sane.h>
}
#include "ksanewidget.h"
#include "ksanewidget_p.h"
......@@ -40,6 +47,7 @@
#include "ksanedevicedialog.h"
#include "labeledgamma.h"
#include "ksaneinvertoption.h"
#include "ksanepagesizeoption.h"
#include <ksane_debug.h>
......@@ -428,40 +436,57 @@ bool KSaneWidget::openDevice(const QString &deviceName)
numSaneOptions = *reinterpret_cast<SANE_Word *>(data.data());
// read the rest of the options
KSaneOption *option;
KSaneOption *m_optionTopLeftX;
KSaneOption *m_optionTopLeftY;
KSaneOption *m_optionBottomRightX;
KSaneOption *m_optionBottomRightY;
KSaneOption *m_optionResolution;
for (i = 1; i < numSaneOptions; ++i) {
switch (KSaneOption::optionType(sane_get_option_descriptor(d->m_saneHandle, i))) {
case KSaneOption::TypeDetectFail:
d->m_optList.append(new KSaneOption(d->m_saneHandle, i));
option = new KSaneOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeBool:
d->m_optList.append(new KSaneBoolOption(d->m_saneHandle, i));
option = new KSaneBoolOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeInteger:
d->m_optList.append(new KSaneIntegerOption(d->m_saneHandle, i));
option = new KSaneIntegerOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeDouble:
d->m_optList.append(new KSaneDoubleOption(d->m_saneHandle, i));
option = new KSaneDoubleOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeValueList:
d->m_optList.append(new KSaneListOption(d->m_saneHandle, i));
option = new KSaneListOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeString:
d->m_optList.append(new KSaneStringOption(d->m_saneHandle, i));
option = new KSaneStringOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeGamma:
d->m_optList.append(new KSaneGammaOption(d->m_saneHandle, i));
option = new KSaneGammaOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeAction:
d->m_optList.append(new KSaneActionOption(d->m_saneHandle, i));
option = new KSaneActionOption(d->m_saneHandle, i);
break;
}
}
// add extra option for inverting image colors
d->m_optList.append(new KSaneInvertOption());
// do the connections of the option parameters
for (const auto &option : qAsConst(d->m_optList)) {
d->m_optList.append(option);
if (option->name() == QStringLiteral(SANE_NAME_SCAN_TL_X)) {
m_optionTopLeftX = option;
}
if (option->name() == QStringLiteral(SANE_NAME_SCAN_TL_Y)) {
m_optionTopLeftY = option;
}
if (option->name() == QStringLiteral(SANE_NAME_SCAN_BR_X)) {
m_optionBottomRightX = option;
}
if (option->name() == QStringLiteral(SANE_NAME_SCAN_BR_Y)) {
m_optionBottomRightY = option;
}
if (option->name() == QStringLiteral(SANE_NAME_SCAN_RESOLUTION)) {
m_optionResolution = option;
}
connect(option, &KSaneOption::optionsNeedReload, d, &KSaneWidgetPrivate::reloadOptions);
connect(option, &KSaneOption::valuesNeedReload, d, &KSaneWidgetPrivate::scheduleValuesReload);
......@@ -469,11 +494,18 @@ bool KSaneWidget::openDevice(const QString &deviceName)
d->m_pollList.append(option);
if (option->type() == KSaneOption::TypeBool) {
connect( option, &KSaneOption::valueChanged,
[=]( const QVariant &newValue ) { Q_EMIT buttonPressed(option->name(), option->title(), newValue.toBool()); } );
[=]( const QVariant &newValue ) { Q_EMIT buttonPressed(option->name(), option->title(), newValue.toBool()); } );
}
}
}
// add extra option for inverting image colors
d->m_optList.append(new KSaneInvertOption());
// add extra option for selecting specific page sizes
d->m_optList.append(new KSanePageSizeOption(m_optionTopLeftX, m_optionTopLeftY,
m_optionBottomRightX, m_optionBottomRightY, m_optionResolution));
// start polling the poll options
if (d->m_pollList.size() > 0) {
d->m_optionPollTmr.start();
......
......@@ -22,6 +22,9 @@
#include <ksane_debug.h>
#include "ksaneinvertoption.h"
#include "ksanepagesizeoption.h"
#define SCALED_PREVIEW_MAX_SIDE 400
static constexpr int ActiveSelection = 100000;
......@@ -128,7 +131,7 @@ void KSaneWidgetPrivate::clearDeviceOptions()
delete m_optList.takeFirst();
}
m_pollList.clear();
m_optWithWidget.clear();
m_handledOptions.clear();
m_optionPollTmr.stop();
// remove the remaining layouts/widgets and read thread
......@@ -392,7 +395,7 @@ KSaneOptionWidget *KSaneWidgetPrivate::createOptionWidget(QWidget *parent, KSane
widget = new KSaneOptionWidget(parent, option);
break;
}
m_optWithWidget.insert(option->name());
m_handledOptions.insert(option->name());
return widget;
}
......@@ -477,18 +480,25 @@ void KSaneWidgetPrivate::createOptInterface()
if ((option = getOption(QStringLiteral(SANE_NAME_SCAN_TL_X))) != nullptr) {
m_optTlX = option;
connect(option, &KSaneOption::valueChanged, this, &KSaneWidgetPrivate::setTLX);
m_handledOptions.insert(option->name());
}
if ((option = getOption(QStringLiteral(SANE_NAME_SCAN_TL_Y))) != nullptr) {
m_optTlY = option;
connect(option, &KSaneOption::valueChanged, this, &KSaneWidgetPrivate::setTLY);
m_handledOptions.insert(option->name());
}
if ((option = getOption(QStringLiteral(SANE_NAME_SCAN_BR_X))) != nullptr) {
m_optBrX = option;
connect(option, &KSaneOption::valueChanged, this, &KSaneWidgetPrivate::setBRX);
m_handledOptions.insert(option->name());
}
if ((option = getOption(QStringLiteral(SANE_NAME_SCAN_BR_Y))) != nullptr) {
m_optBrY = option;
connect(option, &KSaneOption::valueChanged, this, &KSaneWidgetPrivate::setBRY);
m_handledOptions.insert(option->name());
}
if ((option = getOption(PageSizeOptionName)) != nullptr) {
m_handledOptions.insert(option->name());
}
// Color Options Frame
......@@ -519,19 +529,19 @@ void KSaneWidgetPrivate::createOptInterface()
m_optGamR = option;
gammaR = new LabeledGamma(gamma_frm, option);
gam_frm_l->addWidget(gammaR);
m_optWithWidget.insert(option->name());
m_handledOptions.insert(option->name());
}
if ((option = getOption(QStringLiteral(SANE_NAME_GAMMA_VECTOR_G))) != nullptr) {
m_optGamG = option;
gammaG = new LabeledGamma(gamma_frm, option);
gam_frm_l->addWidget(gammaG);
m_optWithWidget.insert(option->name());
m_handledOptions.insert(option->name());
}
if ((option = getOption(QStringLiteral(SANE_NAME_GAMMA_VECTOR_B))) != nullptr) {
m_optGamB = option;
gammaB = new LabeledGamma(gamma_frm, option);
gam_frm_l->addWidget(gammaB);
m_optWithWidget.insert(option->name());
m_handledOptions.insert(option->name());
}
if ((m_optGamR != nullptr) && (m_optGamG != nullptr) && (m_optGamB != nullptr)
......@@ -612,15 +622,10 @@ void KSaneWidgetPrivate::createOptInterface()
// add the remaining parameters
for (int i = 0; i < m_optList.size(); ++i) {
KSaneOption *option = m_optList.at(i);
if (m_optWithWidget.find(option->name()) != m_optWithWidget.end()) {
if (m_handledOptions.find(option->name()) != m_handledOptions.end()) {
continue;
}
if ((option->name() != QStringLiteral(SANE_NAME_SCAN_TL_X)) &&
(option->name() != QStringLiteral(SANE_NAME_SCAN_TL_Y)) &&
(option->name() != QStringLiteral(SANE_NAME_SCAN_BR_X)) &&
(option->name() != QStringLiteral(SANE_NAME_SCAN_BR_Y)) &&
(option->name() != QStringLiteral(SANE_NAME_PREVIEW)) &&
(option->type() != KSaneOption::TypeDetectFail)) {
if (option->type() != KSaneOption::TypeDetectFail) {
KSaneOptionWidget *widget = createOptionWidget(m_otherOptsTab, option);
if (widget != nullptr) {
other_layout->addWidget(widget);
......
......@@ -31,7 +31,6 @@ extern "C"
#include "ksanewidget.h"
#include "ksaneoption.h"
#include "ksaneinvertoption.h"
#include "ksaneoptionwidget.h"
#include "ksaneviewer.h"
#include "labeledcombo.h"
......@@ -155,7 +154,7 @@ public:
// Option variables
QList<KSaneOption *> m_optList;
QList<KSaneOption *> m_pollList;
QSet<QString> m_optWithWidget;
QSet<QString> m_handledOptions;
KSaneOption *m_optSource;
KSaneOption *m_optNegative;
KSaneOption *m_optFilmType;
......
/* ============================================================
*
* SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi>
* SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
* SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
#include "ksanepagesizeoption.h"
#include <QPageSize>
#include <QSizeF>
#include <ksane_debug.h>
static constexpr int PageSizeWiggleRoom = 2; // in mm
namespace KSaneIface
{
KSanePageSizeOption::KSanePageSizeOption(KSaneOption *optionTopLeftX, KSaneOption *optionTopLeftY,
KSaneOption *optionBottomRightX, KSaneOption *optionBottomRightY,
KSaneOption *optionResolution) : KSaneOption()
{
if (optionTopLeftX == nullptr || optionTopLeftY == nullptr ||
optionBottomRightX == nullptr || optionBottomRightY == nullptr) {
m_optionType = KSaneOption::TypeDetectFail;
return;
}
connect(optionTopLeftX, &KSaneOption::valueChanged, this, &KSanePageSizeOption::optionTopLeftXUpdated);
connect(optionTopLeftY, &KSaneOption::valueChanged, this, &KSanePageSizeOption::optionTopLeftYUpdated);
connect(optionBottomRightX, &KSaneOption::valueChanged, this, &KSanePageSizeOption::optionBottomRightXUpdated);
connect(optionBottomRightY, &KSaneOption::valueChanged, this, &KSanePageSizeOption::optionBottomRightYUpdated);
m_optionTopLeftX = optionTopLeftX;
m_optionTopLeftY = optionTopLeftY;
m_optionBottomRightX = optionBottomRightX;
m_optionBottomRightY = optionBottomRightY;
m_optionResolution = optionResolution;
const QList<QPageSize::PageSizeId> possibleSizesList = {
QPageSize::A3,
QPageSize::A4,
QPageSize::A5,
QPageSize::A6,
QPageSize::Letter,
QPageSize::Legal,
QPageSize::Tabloid,
QPageSize::B3,
QPageSize::B4,
QPageSize::B5,
QPageSize::B6,
QPageSize::C5E,
QPageSize::Comm10E,
QPageSize::DLE,
QPageSize::Executive,
QPageSize::Folio,
QPageSize::Ledger,
QPageSize::JisB3,
QPageSize::JisB4,
QPageSize::JisB5,
QPageSize::JisB6,
};
m_availableSizesList << QPageSize::size(QPageSize::Custom, QPageSize::Millimeter);
m_availableSizesListNames << QPageSize::name(QPageSize::Custom);
double maxScannerWidth = ensureMilliMeter(m_optionBottomRightX, m_optionBottomRightX->maximumValue().toDouble());
double maxScannerHeight = ensureMilliMeter(m_optionBottomRightY, m_optionBottomRightY->maximumValue().toDouble());
// Add portrait page sizes
for (const auto sizeCode : possibleSizesList) {
QSizeF size = QPageSize::size(sizeCode, QPageSize::Millimeter);
if (size.width() - PageSizeWiggleRoom > maxScannerWidth) {
continue;
}
if (size.height() - PageSizeWiggleRoom > maxScannerHeight) {
continue;
}
m_availableSizesList << size;
m_availableSizesListNames << QPageSize::name(sizeCode);
}
// Add landscape page sizes
for (const auto sizeCode : possibleSizesList) {
QSizeF size = QPageSize::size(sizeCode, QPageSize::Millimeter);
size.transpose();
if (size.width() - PageSizeWiggleRoom > maxScannerWidth) {
continue;
}
if (size.height() - PageSizeWiggleRoom > maxScannerHeight) {
continue;
}
m_availableSizesList << size;
m_availableSizesListNames << i18nc("Page size landscape", "Landscape %1", QPageSize::name(sizeCode));
}
// Set custom as current
m_currentIndex = 0;
if (m_availableSizesList.count() > 1) {
m_state = KSaneOptionState::StateActive;
} else {
m_state = KSaneOptionState::StateHidden;
}
m_optionType = KSaneOption::TypeValueList;
}
bool KSanePageSizeOption::setValue(const QVariant &value)
{
if (static_cast<QMetaType::Type>(value.type()) == QMetaType::QString) {
QString newValue = value.toString();
if (newValue == m_availableSizesListNames.at(m_currentIndex)) {
return true;
}
for (int i = 0; i < m_availableSizesListNames.size(); i++) {
QString sizeEntry = m_availableSizesListNames.at(i).toString();
if (sizeEntry == newValue) {
m_currentIndex = i;
if (i != 0) {
const auto size = m_availableSizesList.at(i);
m_optionTopLeftX->setValue(0);
m_optionTopLeftY->setValue(0);
m_optionBottomRightX->setValue(size.width());
m_optionBottomRightY->setValue(size.height());
}
Q_EMIT valueChanged(sizeEntry);
return true;
}
}
}
return false;
}
QVariant KSanePageSizeOption::value() const
{
if (m_currentIndex >= 0 && m_currentIndex < m_availableSizesListNames.size()) {
return m_availableSizesListNames.at(m_currentIndex);
} else {
return QVariant();
}
}
QString KSanePageSizeOption::valueAsString() const
{
if (m_currentIndex >= 0 && m_currentIndex < m_availableSizesListNames.size()) {
return m_availableSizesListNames.at(m_currentIndex).toString();
} else {
return QString();
}
}
QVariantList KSanePageSizeOption::valueList() const
{
return m_availableSizesListNames;
}
KSaneOption::KSaneOptionState KSanePageSizeOption::state() const
{
return m_state;
}
QString KSanePageSizeOption::name() const
{
return PageSizeOptionName;
}
QString KSanePageSizeOption::title() const
{
return i18n("Scan area size");
}
QString KSanePageSizeOption::description() const
{
return i18n("Select a predefined page size for the scanning area.");
}
void KSanePageSizeOption::optionTopLeftXUpdated()
{
if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size()
&& m_optionTopLeftY->value().toDouble() != 0 ) {
m_currentIndex = 0;
Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
}
}
void KSanePageSizeOption::optionTopLeftYUpdated()
{
if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size()
&& m_optionTopLeftY->value().toDouble() != 0 ) {
m_currentIndex = 0;
Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
}
}
void KSanePageSizeOption::optionBottomRightXUpdated()
{
if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size()
&& ensureMilliMeter(m_optionBottomRightX, m_optionBottomRightX->value().toDouble())!= m_availableSizesList.at(m_currentIndex).width() ) {
m_currentIndex = 0;
Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
}
}
void KSanePageSizeOption::optionBottomRightYUpdated()
{
if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size()
&& ensureMilliMeter(m_optionBottomRightY, m_optionBottomRightY->value().toDouble()) != m_availableSizesList.at(m_currentIndex).height() ) {
m_currentIndex = 0;
Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
}
}
double KSanePageSizeOption::ensureMilliMeter(KSaneOption *option, double value)
{
// convert if necessary with current DPI if available
if (option->valueUnit() == KSaneOption::UnitPixel && m_optionResolution != nullptr) {
double dpi = m_optionResolution->value().toDouble();
if (dpi > 1) {
return value / (dpi / 25.4);
}
}
return value;
}
} // NameSpace KSaneIface
/* ============================================================
*
* SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
#ifndef KSANE_PAGESIZE_OPTION_H
#define KSANE_PAGESIZE_OPTION_H
#include <QList>
#include "ksaneoption.h"
namespace KSaneIface
{
static const QString PageSizeOptionName = QStringLiteral("KSane::PageSize");
class KSanePageSizeOption : public KSaneOption
{
Q_OBJECT
public:
KSanePageSizeOption(KSaneOption *m_optionTopLeftX, KSaneOption *m_optionTopLeftY,
KSaneOption *m_optionBottomRightX, KSaneOption *m_optionBottomRightY,
KSaneOption *m_optionResolution);
QVariant value() const override;
QString valueAsString() const override;
KSaneOptionState state() const override;
QString name() const override;
QString title() const override;
QString description() const override;
QVariantList valueList() const override;
public Q_SLOTS:
bool setValue(const QVariant &value) override;
private Q_SLOTS:
void optionTopLeftXUpdated();
void optionTopLeftYUpdated();
void optionBottomRightXUpdated();
void optionBottomRightYUpdated();
private:
double ensureMilliMeter(KSaneOption *option, double value);
KSaneOption *m_optionTopLeftX;
KSaneOption *m_optionTopLeftY;
KSaneOption *m_optionBottomRightX;
KSaneOption *m_optionBottomRightY;
KSaneOption *m_optionResolution;
int m_currentIndex = -1;
KSaneOption::KSaneOptionState m_state = StateDisabled;
QVariantList m_availableSizesListNames;
QList<QSizeF> m_availableSizesList;
};
} // NameSpace KSaneIface
#endif // KSANE_PAGESIZE_OPTION_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment