Commit 576cfa68 authored by Huon Imberger's avatar Huon Imberger

Add ability to constrain crop tool to current image ratio

Summary:
The crop tool was lacking the ability to choose the ratio of the current image.
This patch adds:
  - Checkbox in {nav Normal} to toggle between no restriction (default),
  and restrict to the current image ratio
  - "Current Image" item to the Ratio combobox in {nav Advanced}
  - "Unrestricted" item to the Ratio combobox in {nav Advanced}
  (default, functionally no change from before)
  - Clear button to the Ratio combobox in {nav Advanced}, to help make
  it clear the user can enter a custom ratio

BUG: 236970

Test Plan:
  # {nav Image} view > enable crop tool (e.g. by using {key shift}+{key
  c}
  # Ensure ratio restrictions work in both {nav Normal} and {nav Advanced}

The ratio settings in {nav Normal} and {nav Advanced} are independant of
one another, in prep for future patch which will have these remember the
chosen setting.

Reviewers: #gwenview, rkflx

Reviewed By: #gwenview, rkflx

Subscribers: muhlenpfordt

Differential Revision: https://phabricator.kde.org/D11202
parent beef8f3b
......@@ -201,6 +201,9 @@ struct CropToolPrivate
q, SLOT(slotCropRequested()));
QObject::connect(mCropWidget, SIGNAL(done()),
q, SIGNAL(done()));
// This is needed when crop ratio set to Current Image, and the image is rotated
QObject::connect(view, &RasterImageView::imageRectUpdated, mCropWidget, &CropWidget::updateCropRatio);
}
QRect computeVisibleImageRect() const
......
......@@ -50,13 +50,10 @@ static int gcd(int a, int b)
return b == 0 ? a : gcd(b, a % b);
}
static QSize screenRatio()
static QSize ratio(const QSize &size)
{
const QRect rect = QApplication::desktop()->screenGeometry();
const int width = rect.width();
const int height = rect.height();
const int divisor = gcd(width, height);
return QSize(width / divisor, height / divisor);
const int divisor = gcd(size.width(), size.height());
return size / divisor;
}
struct CropWidgetPrivate : public Ui_CropWidget
......@@ -66,6 +63,7 @@ struct CropWidgetPrivate : public Ui_CropWidget
Document::Ptr mDocument;
CropTool* mCropTool;
bool mUpdatingFromCropTool;
int mCurrentImageComboBoxIndex;
bool ratioIsConstrained() const
{
......@@ -74,32 +72,41 @@ struct CropWidgetPrivate : public Ui_CropWidget
double cropRatio() const
{
int index = ratioComboBox->currentIndex();
if (index != -1 && ratioComboBox->currentText() == ratioComboBox->itemText(index)) {
// Get ratio from predefined value
// Note: We check currentText is itemText(currentIndex) because
// currentIndex is not reset to -1 when text is edited by hand.
QSizeF size = ratioComboBox->itemData(index).toSizeF();
return size.height() / size.width();
}
// Not a predefined value, extract ratio from the combobox text
const QStringList lst = ratioComboBox->currentText().split(':');
if (lst.size() != 2) {
return 0;
if (q->advancedSettingsEnabled()) {
int index = ratioComboBox->currentIndex();
if (index != -1 && ratioComboBox->currentText() == ratioComboBox->itemText(index)) {
// Get ratio from predefined value
// Note: We check currentText is itemText(currentIndex) because
// currentIndex is not reset to -1 when text is edited by hand.
QSizeF size = ratioComboBox->itemData(index).toSizeF();
return size.height() / size.width();
}
// Not a predefined value, extract ratio from the combobox text
const QStringList lst = ratioComboBox->currentText().split(':');
if (lst.size() != 2) {
return 0;
}
bool ok;
const double width = lst[0].toDouble(&ok);
if (!ok) {
return 0;
}
const double height = lst[1].toDouble(&ok);
if (!ok) {
return 0;
}
return height / width;
}
bool ok;
const double width = lst[0].toDouble(&ok);
if (!ok) {
return 0;
}
const double height = lst[1].toDouble(&ok);
if (!ok) {
return 0;
if (restrictToImageRatioCheckBox->isChecked()) {
QSizeF size = ratio(mDocument->size());
return size.height() / size.width();
}
return height / width;
return 0;
}
void addRatioToComboBox(const QSizeF& size, const QString& label = QString())
......@@ -137,8 +144,11 @@ struct CropWidgetPrivate : public Ui_CropWidget
<< QSizeF(4, 3)
<< QSizeF(5, 4);
addRatioToComboBox(ratio(mDocument->size()), i18n("Current Image"));
mCurrentImageComboBoxIndex = ratioComboBox->count() - 1; // We need to refer to this ratio later
addRatioToComboBox(QSizeF(1, 1), i18n("Square"));
addRatioToComboBox(screenRatio(), i18n("This Screen"));
addRatioToComboBox(ratio(QApplication::desktop()->screenGeometry().size()), i18n("This Screen"));
addSectionHeaderToComboBox(i18n("Landscape"));
Q_FOREACH(const QSizeF& size, ratioList) {
......@@ -162,6 +172,15 @@ struct CropWidgetPrivate : public Ui_CropWidget
// Do not use i18n("%1:%2") because ':' should not be translated, it is
// used to parse the ratio string.
edit->setPlaceholderText(QString("%1:%2").arg(i18n("Width")).arg(i18n("Height")));
// Enable clear button
edit->setClearButtonEnabled(true);
// Must manually adjust minimum width because the auto size adjustment doesn't take the
// clear button into account
const int width = ratioComboBox->minimumSizeHint().width();
ratioComboBox->setMinimumWidth(width + 24);
ratioComboBox->setCurrentIndex(-1);
}
QRect cropRect() const
......@@ -208,11 +227,12 @@ CropWidget::CropWidget(QWidget* parent, RasterImageView* imageView, CropTool* cr
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
layout()->setSizeConstraint(QLayout::SetFixedSize);
connect(d->advancedCheckBox, SIGNAL(toggled(bool)),
d->advancedWidget, SLOT(setVisible(bool)));
connect(d->advancedCheckBox, &QCheckBox::toggled, this, &CropWidget::slotAdvancedCheckBoxToggled);
d->advancedWidget->setVisible(false);
d->advancedWidget->layout()->setMargin(0);
connect(d->restrictToImageRatioCheckBox, &QCheckBox::toggled, this, &CropWidget::applyRatioConstraint);
d->initRatioComboBox();
connect(d->mCropTool, &CropTool::rectUpdated, this, &CropWidget::setCropRect);
......@@ -224,7 +244,7 @@ CropWidget::CropWidget(QWidget* parent, RasterImageView* imageView, CropTool* cr
d->initDialogButtonBox();
connect(d->ratioComboBox, &QComboBox::editTextChanged, this, &CropWidget::slotRatioComboBoxEditTextChanged);
connect(d->ratioComboBox, &QComboBox::editTextChanged, this, &CropWidget::applyRatioConstraint);
// Don't do this before signals are connected, otherwise the tool won't get
// initialized
......@@ -311,9 +331,24 @@ void CropWidget::applyRatioConstraint()
d->mCropTool->setRect(rect);
}
void CropWidget::slotRatioComboBoxEditTextChanged()
void CropWidget::slotAdvancedCheckBoxToggled(bool checked)
{
d->advancedWidget->setVisible(checked);
d->restrictToImageRatioCheckBox->setVisible(!checked);
applyRatioConstraint();
}
void CropWidget::updateCropRatio()
{
// First we need to re-calculate the "Current Image" ratio in case the user rotated the image
d->ratioComboBox->setItemData(d->mCurrentImageComboBoxIndex, QVariant(ratio(d->mDocument->size())));
// Always re-apply the constraint, even though we only need to when the user has "Current Image"
// selected or the "Restrict to current image" checked, since there's no harm
applyRatioConstraint();
// If the ratio is unrestricted, calling applyRatioConstraint doesn't update the rect, so we call
// this manually to make sure the rect is adjusted to fit within the image
d->mCropTool->setRect(d->mCropTool->rect());
}
} // namespace
......@@ -52,13 +52,16 @@ Q_SIGNALS:
void cropRequested();
void done();
public Q_SLOTS:
void updateCropRatio();
private Q_SLOTS:
void slotPositionChanged();
void slotWidthChanged();
void slotHeightChanged();
void setCropRect(const QRect& rect);
void slotRatioComboBoxEditTextChanged();
void slotAdvancedCheckBoxToggled(bool checked);
void applyRatioConstraint();
private:
......
......@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>824</width>
<width>1006</width>
<height>66</height>
</rect>
</property>
......@@ -160,6 +160,13 @@
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="restrictToImageRatioCheckBox">
<property name="text">
<string>Restrict to image ratio</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="dialogButtonBox">
<property name="standardButtons">
......
......@@ -320,6 +320,7 @@ void RasterImageView::updateImageRect(const QRect& imageRect)
d->setScalerRegionToVisibleRect();
update();
emit imageRectUpdated();
}
void RasterImageView::slotDocumentIsAnimatedUpdated()
......
......@@ -60,6 +60,7 @@ public:
Q_SIGNALS:
void currentToolChanged(AbstractRasterImageViewTool*);
void imageRectUpdated();
protected:
void loadFromDocument() Q_DECL_OVERRIDE;
......
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