File indexing completed on 2024-05-12 04:19:36

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2007 Aurélien Gâteau <agateau@kde.org>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0019 
0020 */
0021 // Self
0022 
0023 // Qt
0024 #include <QApplication>
0025 #include <QCheckBox>
0026 #include <QComboBox>
0027 // #include <QDesktopWidget>
0028 #include <QDialogButtonBox>
0029 #include <QFontDatabase>
0030 #include <QHBoxLayout>
0031 #include <QLabel>
0032 #include <QLineEdit>
0033 #include <QPushButton>
0034 #include <QScreen>
0035 #include <QSpinBox>
0036 #include <QtMath>
0037 
0038 // KF
0039 #include <KLocalizedString>
0040 
0041 // Local
0042 #include "croptool.h"
0043 #include "cropwidget.h"
0044 #include "flowlayout.h"
0045 #include <lib/documentview/rasterimageview.h>
0046 
0047 namespace Gwenview
0048 {
0049 // Euclidean algorithm to compute the greatest common divisor of two integers.
0050 // Found at:
0051 // https://en.wikipedia.org/wiki/Euclidean_algorithm
0052 static int gcd(int a, int b)
0053 {
0054     return b == 0 ? a : gcd(b, a % b);
0055 }
0056 
0057 static QSize ratio(const QSize &size)
0058 {
0059     const int divisor = gcd(size.width(), size.height());
0060     return size / divisor;
0061 }
0062 
0063 struct CropWidgetPrivate : public QWidget {
0064     CropWidget *q;
0065     QList<QWidget *> mAdvancedWidgets;
0066     QWidget *mPreserveAspectRatioWidget = nullptr;
0067     QCheckBox *advancedCheckBox = nullptr;
0068     QComboBox *ratioComboBox = nullptr;
0069     QSpinBox *widthSpinBox = nullptr;
0070     QSpinBox *heightSpinBox = nullptr;
0071     QSpinBox *leftSpinBox = nullptr;
0072     QSpinBox *topSpinBox = nullptr;
0073     QCheckBox *preserveAspectRatioCheckBox = nullptr;
0074     QDialogButtonBox *dialogButtonBox = nullptr;
0075 
0076     Document::Ptr mDocument;
0077     CropTool *mCropTool = nullptr;
0078     bool mUpdatingFromCropTool;
0079     bool mUpdatingFromWidthSpinBox = false;
0080     bool mUpdatingFromHeightSpinBox = false;
0081     int mCurrentImageComboBoxIndex;
0082     int mCropRatioComboBoxCurrentIndex;
0083 
0084     bool ratioIsConstrained() const
0085     {
0086         return cropRatio() > 0;
0087     }
0088 
0089     QSizeF chosenRatio() const
0090     {
0091         // A size of 0 represents no ratio, i.e. the combobox is empty
0092         if (ratioComboBox->currentText().isEmpty()) {
0093             return QSizeF(0, 0);
0094         }
0095 
0096         // A preset ratio is selected
0097         const int index = ratioComboBox->currentIndex();
0098         if (index != -1 && ratioComboBox->currentText() == ratioComboBox->itemText(index)) {
0099             return ratioComboBox->currentData().toSizeF();
0100         }
0101 
0102         // A custom ratio has been entered, extract ratio from the text
0103         // If invalid, return zero size instead
0104         const QStringList lst = ratioComboBox->currentText().split(QLatin1Char(':'));
0105         if (lst.size() != 2) {
0106             return QSizeF(0, 0);
0107         }
0108         bool ok;
0109         const double width = lst[0].toDouble(&ok);
0110         if (!ok) {
0111             return QSizeF(0, 0);
0112         }
0113         const double height = lst[1].toDouble(&ok);
0114         if (!ok) {
0115             return QSizeF(0, 0);
0116         }
0117 
0118         // Valid custom value
0119         return QSizeF(width, height);
0120     }
0121 
0122     void setChosenRatio(QSizeF size) const
0123     {
0124         // Size matches preset ratio, let's set the combobox to that
0125         const int index = ratioComboBox->findData(size);
0126         if (index >= 0) {
0127             ratioComboBox->setCurrentIndex(index);
0128             return;
0129         }
0130 
0131         // Deselect whatever was selected if anything
0132         ratioComboBox->setCurrentIndex(-1);
0133 
0134         // If size is 0 (represents blank combobox, i.e., unrestricted)
0135         if (size.isEmpty()) {
0136             ratioComboBox->clearEditText();
0137             return;
0138         }
0139 
0140         // Size must be custom ratio, convert to text and add to combobox
0141         QString ratioString = QStringLiteral("%1:%2").arg(size.width()).arg(size.height());
0142         ratioComboBox->setCurrentText(ratioString);
0143     }
0144 
0145     double cropRatio() const
0146     {
0147         if (q->advancedSettingsEnabled()) {
0148             const QSizeF size = chosenRatio();
0149             if (size.isEmpty()) {
0150                 return 0;
0151             }
0152             return size.height() / size.width();
0153         }
0154 
0155         if (q->preserveAspectRatio()) {
0156             const QSizeF size = ratio(mDocument->size());
0157             return size.height() / size.width();
0158         }
0159 
0160         return 0;
0161     }
0162 
0163     void addRatioToComboBox(const QSizeF &size, const QString &label = QString())
0164     {
0165         const QString text = label.isEmpty() ? QStringLiteral("%1:%2").arg(size.width()).arg(size.height()) : label;
0166         ratioComboBox->addItem(text, QVariant(size));
0167     }
0168 
0169     void addSectionHeaderToComboBox(const QString &title)
0170     {
0171         // Insert a line
0172         ratioComboBox->insertSeparator(ratioComboBox->count());
0173 
0174         // Insert our section header
0175         // This header is made of a separator with a text. We reset
0176         // Qt::AccessibleDescriptionRole to the header text otherwise QComboBox
0177         // delegate will draw a separator line instead of our text.
0178         int index = ratioComboBox->count();
0179         ratioComboBox->insertSeparator(index);
0180         ratioComboBox->setItemText(index, title);
0181         ratioComboBox->setItemData(index, title, Qt::AccessibleDescriptionRole);
0182         ratioComboBox->setItemData(index, Qt::AlignHCenter, Qt::TextAlignmentRole);
0183     }
0184 
0185     void initRatioComboBox()
0186     {
0187         QList<QSizeF> ratioList;
0188         const qreal sqrt2 = qSqrt(2.);
0189         ratioList << QSizeF(16, 9) << QSizeF(7, 5) << QSizeF(3, 2) << QSizeF(4, 3) << QSizeF(5, 4);
0190 
0191         addRatioToComboBox(ratio(mDocument->size()), i18n("Current Image"));
0192         mCurrentImageComboBoxIndex = ratioComboBox->count() - 1; // We need to refer to this ratio later
0193 
0194         addRatioToComboBox(QSizeF(1, 1), i18n("Square"));
0195         const QScreen *screen = QGuiApplication::screenAt(QCursor::pos());
0196         if (screen) {
0197             addRatioToComboBox(ratio(screen->geometry().size()), i18n("This Screen"));
0198         }
0199         addSectionHeaderToComboBox(i18n("Landscape"));
0200 
0201         for (const QSizeF &size : qAsConst(ratioList)) {
0202             addRatioToComboBox(size);
0203         }
0204         addRatioToComboBox(QSizeF(sqrt2, 1), i18n("ISO (A4, A3...)"));
0205         addRatioToComboBox(QSizeF(11, 8.5), i18n("US Letter"));
0206         addSectionHeaderToComboBox(i18n("Portrait"));
0207         for (QSizeF size : qAsConst(ratioList)) {
0208             size.transpose();
0209             addRatioToComboBox(size);
0210         }
0211         addRatioToComboBox(QSizeF(1, sqrt2), i18n("ISO (A4, A3...)"));
0212         addRatioToComboBox(QSizeF(8.5, 11), i18n("US Letter"));
0213 
0214         ratioComboBox->setMaxVisibleItems(ratioComboBox->count());
0215         ratioComboBox->clearEditText();
0216 
0217         auto edit = qobject_cast<QLineEdit *>(ratioComboBox->lineEdit());
0218         Q_ASSERT(edit);
0219         // Do not use i18n("%1:%2") because ':' should not be translated, it is
0220         // used to parse the ratio string.
0221         edit->setPlaceholderText(QStringLiteral("%1:%2").arg(i18n("Width"), i18n("Height")));
0222 
0223         // Enable clear button
0224         edit->setClearButtonEnabled(true);
0225         // Must manually adjust minimum width because the auto size adjustment doesn't take the
0226         // clear button into account
0227         const int width = ratioComboBox->minimumSizeHint().width();
0228         ratioComboBox->setMinimumWidth(width + 24);
0229 
0230         mCropRatioComboBoxCurrentIndex = -1;
0231         ratioComboBox->setCurrentIndex(mCropRatioComboBoxCurrentIndex);
0232     }
0233 
0234     QRect cropRect() const
0235     {
0236         const QRect rect(leftSpinBox->value(), topSpinBox->value(), widthSpinBox->value(), heightSpinBox->value());
0237         return rect;
0238     }
0239 
0240     void initSpinBoxes()
0241     {
0242         const QSize size = mDocument->size();
0243         leftSpinBox->setMaximum(size.width());
0244         widthSpinBox->setMaximum(size.width());
0245         topSpinBox->setMaximum(size.height());
0246         heightSpinBox->setMaximum(size.height());
0247 
0248         // When users change the crop rectangle, QSpinBox::setMaximum will be called
0249         // again, which then adapts the sizeHint due to a different maximum number
0250         // of digits, leading to horizontal movement in the layout. This can be
0251         // avoided by setting the minimum width so it fits the largest value possible.
0252         leftSpinBox->setMinimumWidth(leftSpinBox->sizeHint().width());
0253         widthSpinBox->setMinimumWidth(widthSpinBox->sizeHint().width());
0254         topSpinBox->setMinimumWidth(topSpinBox->sizeHint().width());
0255         heightSpinBox->setMinimumWidth(heightSpinBox->sizeHint().width());
0256     }
0257 
0258     void initDialogButtonBox()
0259     {
0260         QPushButton *cropButton = dialogButtonBox->button(QDialogButtonBox::Ok);
0261         cropButton->setIcon(QIcon::fromTheme(QStringLiteral("transform-crop-and-resize")));
0262         cropButton->setText(i18n("Crop"));
0263 
0264         QObject::connect(dialogButtonBox, &QDialogButtonBox::accepted, q, &CropWidget::cropRequested);
0265         QObject::connect(dialogButtonBox, &QDialogButtonBox::rejected, q, &CropWidget::done);
0266         QPushButton *resetButton = dialogButtonBox->button(QDialogButtonBox::Reset);
0267         connect(resetButton, &QPushButton::clicked, q, &CropWidget::reset);
0268     }
0269 
0270     QWidget *boxWidget(QWidget *parent = nullptr)
0271     {
0272         auto widget = new QWidget(parent);
0273         auto layout = new QHBoxLayout(widget);
0274         layout->setContentsMargins(0, 0, 0, 0);
0275         layout->setSpacing(2);
0276         return widget;
0277     }
0278 
0279     void setupUi(QWidget *cropWidget)
0280     {
0281         cropWidget->setObjectName(QStringLiteral("CropWidget"));
0282 
0283         auto flowLayout = new FlowLayout(cropWidget, 6, 0);
0284         flowLayout->setObjectName(QStringLiteral("CropWidgetFlowLayout"));
0285         flowLayout->setAlignment(Qt::AlignCenter);
0286         flowLayout->setVerticalSpacing(6);
0287 
0288         // (1) Checkbox
0289         QWidget *box = boxWidget(cropWidget);
0290         advancedCheckBox = new QCheckBox(i18nc("@option:check", "Advanced settings"), box);
0291         advancedCheckBox->setFocusPolicy(Qt::NoFocus);
0292         box->layout()->addWidget(advancedCheckBox);
0293         flowLayout->addWidget(box);
0294         flowLayout->addSpacing(14);
0295 
0296         // (2) Ratio combobox (Advanced settings)
0297         box = boxWidget(cropWidget);
0298         mAdvancedWidgets << box;
0299         auto label = new QLabel(i18nc("@label:listbox", "Aspect ratio:"), box);
0300         label->setContentsMargins(4, 4, 4, 4);
0301         box->layout()->addWidget(label);
0302         ratioComboBox = new QComboBox(box);
0303         ratioComboBox->setEditable(true);
0304         ratioComboBox->setInsertPolicy(QComboBox::NoInsert);
0305         box->layout()->addWidget(ratioComboBox);
0306         flowLayout->addWidget(box);
0307         flowLayout->addSpacing(8);
0308 
0309         // (3) Size spinboxes (Advanced settings)
0310         box = boxWidget(cropWidget);
0311         mAdvancedWidgets << box;
0312         label = new QLabel(i18nc("@label:spinbox", "Size:"), box);
0313         label->setContentsMargins(4, 4, 4, 4);
0314         box->layout()->addWidget(label);
0315 
0316         auto innerLayout = new QHBoxLayout();
0317         innerLayout->setSpacing(3);
0318 
0319         widthSpinBox = new QSpinBox(box);
0320         widthSpinBox->setAlignment(Qt::AlignCenter);
0321         innerLayout->addWidget(widthSpinBox);
0322 
0323         heightSpinBox = new QSpinBox(box);
0324         heightSpinBox->setAlignment(Qt::AlignCenter);
0325         innerLayout->addWidget(heightSpinBox);
0326 
0327         box->layout()->addItem(innerLayout);
0328         flowLayout->addWidget(box);
0329         flowLayout->addSpacing(8);
0330 
0331         // (4) Position spinboxes (Advanced settings)
0332         box = boxWidget(cropWidget);
0333         mAdvancedWidgets << box;
0334         label = new QLabel(i18nc("@label:spinbox", "Position:"), box);
0335         label->setContentsMargins(4, 4, 4, 4);
0336         box->layout()->addWidget(label);
0337 
0338         innerLayout = new QHBoxLayout();
0339         innerLayout->setSpacing(3);
0340 
0341         leftSpinBox = new QSpinBox(box);
0342         leftSpinBox->setAlignment(Qt::AlignCenter);
0343         innerLayout->addWidget(leftSpinBox);
0344 
0345         topSpinBox = new QSpinBox(box);
0346         topSpinBox->setAlignment(Qt::AlignCenter);
0347         innerLayout->addWidget(topSpinBox);
0348 
0349         box->layout()->addItem(innerLayout);
0350         flowLayout->addWidget(box);
0351         flowLayout->addSpacing(18);
0352 
0353         // (5) Preserve ratio checkbox
0354         mPreserveAspectRatioWidget = boxWidget(cropWidget);
0355         preserveAspectRatioCheckBox = new QCheckBox(i18nc("@option:check", "Preserve aspect ratio"), mPreserveAspectRatioWidget);
0356         mPreserveAspectRatioWidget->layout()->addWidget(preserveAspectRatioCheckBox);
0357         flowLayout->addWidget(mPreserveAspectRatioWidget);
0358         flowLayout->addSpacing(18);
0359 
0360         // (6) Dialog buttons
0361         box = boxWidget(cropWidget);
0362         dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Reset | QDialogButtonBox::Ok, box);
0363         box->layout()->addWidget(dialogButtonBox);
0364         flowLayout->addWidget(box);
0365     }
0366 };
0367 
0368 CropWidget::CropWidget(QWidget *parent, RasterImageView *imageView, CropTool *cropTool)
0369     : QWidget(parent)
0370     , d(new CropWidgetPrivate)
0371 {
0372     setWindowFlags(Qt::Tool);
0373     d->q = this;
0374     d->mDocument = imageView->document();
0375     d->mUpdatingFromCropTool = false;
0376     d->mCropTool = cropTool;
0377     d->setupUi(this);
0378     setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0379 
0380     connect(d->advancedCheckBox, &QCheckBox::toggled, this, &CropWidget::slotAdvancedCheckBoxToggled);
0381     for (auto w : qAsConst(d->mAdvancedWidgets)) {
0382         w->setVisible(false);
0383     }
0384 
0385     connect(d->preserveAspectRatioCheckBox, &QCheckBox::toggled, this, &CropWidget::applyRatioConstraint);
0386 
0387     d->initRatioComboBox();
0388 
0389     connect(d->mCropTool, &CropTool::rectUpdated, this, &CropWidget::setCropRect);
0390 
0391     connect(d->leftSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &CropWidget::slotPositionChanged);
0392     connect(d->topSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &CropWidget::slotPositionChanged);
0393     connect(d->widthSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &CropWidget::slotWidthChanged);
0394     connect(d->heightSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &CropWidget::slotHeightChanged);
0395 
0396     d->initDialogButtonBox();
0397 
0398     // We need to listen for both signals because the combobox is multi-function:
0399     // Text Changed: required so that manual ratio entry is detected (index doesn't change)
0400     // Index Changed: required so that choosing an item with the same text is detected (e.g. going from US Letter portrait
0401     // to US Letter landscape)
0402     connect(d->ratioComboBox, &QComboBox::editTextChanged, this, &CropWidget::slotRatioComboBoxChanged);
0403     connect(d->ratioComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &CropWidget::slotRatioComboBoxChanged);
0404 
0405     // Don't do this before signals are connected, otherwise the tool won't get
0406     // initialized
0407     d->initSpinBoxes();
0408 
0409     setCropRect(d->mCropTool->rect());
0410 }
0411 
0412 CropWidget::~CropWidget()
0413 {
0414     delete d;
0415 }
0416 
0417 void CropWidget::setAdvancedSettingsEnabled(bool enable)
0418 {
0419     d->advancedCheckBox->setChecked(enable);
0420 }
0421 
0422 bool CropWidget::advancedSettingsEnabled() const
0423 {
0424     return d->advancedCheckBox->isChecked();
0425 }
0426 
0427 void CropWidget::setPreserveAspectRatio(bool preserve)
0428 {
0429     d->preserveAspectRatioCheckBox->setChecked(preserve);
0430 }
0431 
0432 bool CropWidget::preserveAspectRatio() const
0433 {
0434     return d->preserveAspectRatioCheckBox->isChecked();
0435 }
0436 
0437 void CropWidget::setCropRatio(QSizeF size)
0438 {
0439     d->setChosenRatio(size);
0440 }
0441 
0442 QSizeF CropWidget::cropRatio() const
0443 {
0444     return d->chosenRatio();
0445 }
0446 
0447 void CropWidget::reset()
0448 {
0449     d->ratioComboBox->clearEditText();
0450     d->ratioComboBox->setCurrentIndex(-1);
0451 
0452     QSize size = d->mDocument->size();
0453     d->leftSpinBox->setValue(0);
0454     d->widthSpinBox->setValue(size.width());
0455     d->topSpinBox->setValue(0);
0456     d->heightSpinBox->setValue(size.height());
0457     Q_EMIT rectReset();
0458 }
0459 
0460 void CropWidget::setCropRatioIndex(int index)
0461 {
0462     d->ratioComboBox->setCurrentIndex(index);
0463 }
0464 
0465 int CropWidget::cropRatioIndex() const
0466 {
0467     return d->mCropRatioComboBoxCurrentIndex;
0468 }
0469 
0470 void CropWidget::setCropRect(const QRect &rect)
0471 {
0472     d->mUpdatingFromCropTool = true;
0473     d->leftSpinBox->setValue(rect.left());
0474     d->topSpinBox->setValue(rect.top());
0475     d->widthSpinBox->setValue(rect.width());
0476     d->heightSpinBox->setValue(rect.height());
0477     d->mUpdatingFromCropTool = false;
0478 }
0479 
0480 void CropWidget::slotPositionChanged()
0481 {
0482     const QSize size = d->mDocument->size();
0483     d->widthSpinBox->setMaximum(size.width() - d->leftSpinBox->value());
0484     d->heightSpinBox->setMaximum(size.height() - d->topSpinBox->value());
0485 
0486     if (d->mUpdatingFromCropTool) {
0487         return;
0488     }
0489     d->mCropTool->setRect(d->cropRect());
0490 }
0491 
0492 void CropWidget::slotWidthChanged()
0493 {
0494     d->leftSpinBox->setMaximum(d->mDocument->width() - d->widthSpinBox->value());
0495 
0496     if (d->mUpdatingFromCropTool || d->mUpdatingFromHeightSpinBox) {
0497         return;
0498     }
0499 
0500     if (d->ratioIsConstrained()) {
0501         d->mUpdatingFromWidthSpinBox = true;
0502         int height = int(d->widthSpinBox->value() * d->cropRatio());
0503         d->heightSpinBox->setValue(height);
0504         d->mUpdatingFromWidthSpinBox = false;
0505     }
0506     d->mCropTool->setRect(d->cropRect());
0507 }
0508 
0509 void CropWidget::slotHeightChanged()
0510 {
0511     d->topSpinBox->setMaximum(d->mDocument->height() - d->heightSpinBox->value());
0512 
0513     if (d->mUpdatingFromCropTool || d->mUpdatingFromWidthSpinBox) {
0514         return;
0515     }
0516 
0517     if (d->ratioIsConstrained()) {
0518         d->mUpdatingFromHeightSpinBox = true;
0519         int width = int(d->heightSpinBox->value() / d->cropRatio());
0520         d->widthSpinBox->setValue(width);
0521         d->mUpdatingFromHeightSpinBox = false;
0522     }
0523     d->mCropTool->setRect(d->cropRect());
0524 }
0525 
0526 void CropWidget::applyRatioConstraint()
0527 {
0528     double ratio = d->cropRatio();
0529     d->mCropTool->setCropRatio(ratio);
0530 
0531     if (!d->ratioIsConstrained()) {
0532         return;
0533     }
0534     QRect rect = d->cropRect();
0535     rect.setHeight(int(rect.width() * ratio));
0536     d->mCropTool->setRect(rect);
0537 }
0538 
0539 void CropWidget::slotAdvancedCheckBoxToggled(bool checked)
0540 {
0541     for (auto w : qAsConst(d->mAdvancedWidgets)) {
0542         w->setVisible(checked);
0543     }
0544     d->mPreserveAspectRatioWidget->setVisible(!checked);
0545     applyRatioConstraint();
0546 }
0547 
0548 void CropWidget::slotRatioComboBoxChanged()
0549 {
0550     const QString text = d->ratioComboBox->currentText();
0551 
0552     // If text cleared, clear the current item as well
0553     if (text.isEmpty()) {
0554         d->ratioComboBox->setCurrentIndex(-1);
0555     }
0556 
0557     // We want to keep track of the selected ratio, including when the user has entered a custom ratio
0558     // or cleared the text. We can't simply use currentIndex() because this stays >= 0 when the user manually
0559     // enters text. We also can't set the current index to -1 when there is no match like above because that
0560     // interferes when manually entering text.
0561     // Furthermore, since there can be duplicate text items, we can't rely on findText() as it will stop on
0562     // the first match it finds. Therefore we must check if there's a match, and if so, get the index directly.
0563     if (d->ratioComboBox->findText(text) >= 0) {
0564         d->mCropRatioComboBoxCurrentIndex = d->ratioComboBox->currentIndex();
0565     } else {
0566         d->mCropRatioComboBoxCurrentIndex = -1;
0567     }
0568 
0569     applyRatioConstraint();
0570 }
0571 
0572 void CropWidget::updateCropRatio()
0573 {
0574     // First we need to re-calculate the "Current Image" ratio in case the user rotated the image
0575     d->ratioComboBox->setItemData(d->mCurrentImageComboBoxIndex, QVariant(ratio(d->mDocument->size())));
0576 
0577     // Always re-apply the constraint, even though we only need to when the user has "Current Image"
0578     // selected or the "Preserve aspect ratio" checked, since there's no harm
0579     applyRatioConstraint();
0580     // If the ratio is unrestricted, calling applyRatioConstraint doesn't update the rect, so we call
0581     // this manually to make sure the rect is adjusted to fit within the image
0582     d->mCropTool->setRect(d->mCropTool->rect());
0583 }
0584 
0585 } // namespace
0586 
0587 #include "moc_cropwidget.cpp"