~ubuntu-branches/ubuntu/precise/gwenview/precise-proposed

« back to all changes in this revision

Viewing changes to lib/crop/cropwidget.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2011-12-15 14:17:54 UTC
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: package-import@ubuntu.com-20111215141754-z043hyx69dulbggf
Tags: upstream-4.7.90
ImportĀ upstreamĀ versionĀ 4.7.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
1
// vim: set tabstop=4 shiftwidth=4 expandtab:
2
2
/*
3
3
Gwenview: an image viewer
4
4
Copyright 2007 AurĆ©lien GĆ¢teau <agateau@kde.org>
34
34
#include <klocale.h>
35
35
 
36
36
// Local
 
37
#include <lib/documentview/rasterimageview.h>
37
38
#include "croptool.h"
38
 
#include "imageview.h"
39
39
#include "signalblocker.h"
40
40
#include "ui_cropwidget.h"
41
41
 
42
 
namespace Gwenview {
43
 
 
 
42
namespace Gwenview
 
43
{
44
44
 
45
45
// Euclidean algorithm to compute the greatest common divisor of two integers.
46
46
// Found at:
47
47
// http://en.wikipedia.org/wiki/Euclidean_algorithm
48
 
static int gcd(int a, int b) {
49
 
        return b == 0 ? a : gcd(b, a % b);
50
 
}
51
 
 
52
 
 
53
 
static QSize screenRatio() {
54
 
        const QRect rect = QApplication::desktop()->screenGeometry();
55
 
        const int width = rect.width();
56
 
        const int height = rect.height();
57
 
        const int divisor = gcd(width, height);
58
 
        return QSize(width / divisor, height / divisor);
59
 
}
60
 
 
 
48
static int gcd(int a, int b)
 
49
{
 
50
    return b == 0 ? a : gcd(b, a % b);
 
51
}
 
52
 
 
53
static QSize screenRatio()
 
54
{
 
55
    const QRect rect = QApplication::desktop()->screenGeometry();
 
56
    const int width = rect.width();
 
57
    const int height = rect.height();
 
58
    const int divisor = gcd(width, height);
 
59
    return QSize(width / divisor, height / divisor);
 
60
}
61
61
 
62
62
struct CropWidgetPrivate : public Ui_CropWidget {
63
 
        CropWidget* that;
64
 
 
65
 
        Document::Ptr mDocument;
66
 
        CropTool* mCropTool;
67
 
        bool mUpdatingFromCropTool;
68
 
 
69
 
 
70
 
        bool ratioIsConstrained() const {
71
 
                return cropRatio() > 0;
72
 
        }
73
 
 
74
 
 
75
 
        double cropRatio() const {
76
 
                const QStringList lst = ratioComboBox->currentText().split(':');
77
 
                if (lst.size() != 2) {
78
 
                        return 0;
79
 
                }
80
 
 
81
 
                bool ok;
82
 
                const double width = lst[0].toDouble(&ok);
83
 
                if (!ok) {
84
 
                        return 0;
85
 
                }
86
 
                const double height = lst[1].toDouble(&ok);
87
 
                if (!ok) {
88
 
                        return 0;
89
 
                }
90
 
 
91
 
                return height / width;
92
 
        }
93
 
 
94
 
 
95
 
        void addRatioToComboBox(const QSize& size, const QString& label = QString()) {
96
 
                QString text = QString("%1:%2").arg(size.width()).arg(size.height());
97
 
                if (!label.isEmpty()) {
98
 
                        text += QString(" (%1)").arg(label);
99
 
                }
100
 
                ratioComboBox->addItem(text, QVariant(size));
101
 
        }
102
 
 
103
 
 
104
 
        void addSeparatorToComboBox() {
105
 
                ratioComboBox->insertSeparator(ratioComboBox->count());
106
 
        }
107
 
 
108
 
 
109
 
        void initRatioComboBox() {
110
 
                QList<QSize> ratioList;
111
 
                ratioList
112
 
                        << QSize(3, 2)
113
 
                        << QSize(4, 3)
114
 
                        << QSize(5, 4)
115
 
                        << QSize(6, 4)
116
 
                        << QSize(7, 5)
117
 
                        << QSize(10, 8);
118
 
 
119
 
                addRatioToComboBox(QSize(1, 1), i18n("Square"));
120
 
                addRatioToComboBox(screenRatio(), i18n("This Screen"));
121
 
                addSeparatorToComboBox();
122
 
 
123
 
                Q_FOREACH(const QSize& size, ratioList) {
124
 
                        addRatioToComboBox(size);
125
 
                }
126
 
                addSeparatorToComboBox();
127
 
                Q_FOREACH(QSize size, ratioList) {
128
 
                        size.transpose();
129
 
                        addRatioToComboBox(size);
130
 
                }
131
 
 
132
 
                ratioComboBox->setMaxVisibleItems(ratioComboBox->count());
133
 
                ratioComboBox->setEditText(QString());
134
 
 
135
 
                KLineEdit* edit = qobject_cast<KLineEdit*>(ratioComboBox->lineEdit());
136
 
                Q_ASSERT(edit);
137
 
                // Do not use i18n("%1:%2") because ':' should not be translated, it is
138
 
                // used to parse the ratio string.
139
 
                edit->setClickMessage(QString("%1:%2").arg(i18n("Width")).arg(i18n("Height")));
140
 
        }
141
 
 
142
 
 
143
 
        QRect cropRect() const {
144
 
                QRect rect(
145
 
                        leftSpinBox->value(),
146
 
                        topSpinBox->value(),
147
 
                        widthSpinBox->value(),
148
 
                        heightSpinBox->value()
149
 
                        );
150
 
                return rect;
151
 
        }
152
 
 
153
 
 
154
 
        void initSpinBoxes() {
155
 
                QSize size = mDocument->size();
156
 
                leftSpinBox->setMaximum(size.width());
157
 
                widthSpinBox->setMaximum(size.width());
158
 
                topSpinBox->setMaximum(size.height());
159
 
                heightSpinBox->setMaximum(size.height());
160
 
        }
161
 
 
162
 
 
163
 
        void initCropButton() {
164
 
                cropButton->setIcon(KIcon("transform-crop-and-resize"));
165
 
 
166
 
                QObject::connect(cropButton, SIGNAL(clicked()),
167
 
                        that, SIGNAL(cropRequested()) );
168
 
        }
 
63
    CropWidget* q;
 
64
 
 
65
    Document::Ptr mDocument;
 
66
    CropTool* mCropTool;
 
67
    bool mUpdatingFromCropTool;
 
68
 
 
69
    bool ratioIsConstrained() const {
 
70
        return cropRatio() > 0;
 
71
    }
 
72
 
 
73
    double cropRatio() const {
 
74
        const QStringList lst = ratioComboBox->currentText().split(':');
 
75
        if (lst.size() != 2) {
 
76
            return 0;
 
77
        }
 
78
 
 
79
        bool ok;
 
80
        const double width = lst[0].toDouble(&ok);
 
81
        if (!ok) {
 
82
            return 0;
 
83
        }
 
84
        const double height = lst[1].toDouble(&ok);
 
85
        if (!ok) {
 
86
            return 0;
 
87
        }
 
88
 
 
89
        return height / width;
 
90
    }
 
91
 
 
92
    void addRatioToComboBox(const QSize& size, const QString& label = QString())
 
93
    {
 
94
        QString text = QString("%1:%2").arg(size.width()).arg(size.height());
 
95
        if (!label.isEmpty()) {
 
96
            text += QString(" (%1)").arg(label);
 
97
        }
 
98
        ratioComboBox->addItem(text, QVariant(size));
 
99
    }
 
100
 
 
101
    void addSeparatorToComboBox()
 
102
    {
 
103
        ratioComboBox->insertSeparator(ratioComboBox->count());
 
104
    }
 
105
 
 
106
    void initRatioComboBox()
 
107
    {
 
108
        QList<QSize> ratioList;
 
109
        ratioList
 
110
                << QSize(3, 2)
 
111
                << QSize(4, 3)
 
112
                << QSize(5, 4)
 
113
                << QSize(6, 4)
 
114
                << QSize(7, 5)
 
115
                << QSize(10, 8);
 
116
 
 
117
        addRatioToComboBox(QSize(1, 1), i18n("Square"));
 
118
        addRatioToComboBox(screenRatio(), i18n("This Screen"));
 
119
        addSeparatorToComboBox();
 
120
 
 
121
        Q_FOREACH(const QSize & size, ratioList) {
 
122
            addRatioToComboBox(size);
 
123
        }
 
124
        addSeparatorToComboBox();
 
125
        Q_FOREACH(QSize size, ratioList) {
 
126
            size.transpose();
 
127
            addRatioToComboBox(size);
 
128
        }
 
129
 
 
130
        ratioComboBox->setMaxVisibleItems(ratioComboBox->count());
 
131
        ratioComboBox->setEditText(QString());
 
132
 
 
133
        KLineEdit* edit = qobject_cast<KLineEdit*>(ratioComboBox->lineEdit());
 
134
        Q_ASSERT(edit);
 
135
        // Do not use i18n("%1:%2") because ':' should not be translated, it is
 
136
        // used to parse the ratio string.
 
137
        edit->setClickMessage(QString("%1:%2").arg(i18n("Width")).arg(i18n("Height")));
 
138
    }
 
139
 
 
140
    QRect cropRect() const {
 
141
        QRect rect(
 
142
            leftSpinBox->value(),
 
143
            topSpinBox->value(),
 
144
            widthSpinBox->value(),
 
145
            heightSpinBox->value()
 
146
        );
 
147
        return rect;
 
148
    }
 
149
 
 
150
    void initSpinBoxes()
 
151
    {
 
152
        QSize size = mDocument->size();
 
153
        leftSpinBox->setMaximum(size.width());
 
154
        widthSpinBox->setMaximum(size.width());
 
155
        topSpinBox->setMaximum(size.height());
 
156
        heightSpinBox->setMaximum(size.height());
 
157
    }
 
158
 
 
159
    void initDialogButtonBox()
 
160
    {
 
161
        QPushButton* cropButton = dialogButtonBox->button(QDialogButtonBox::Ok);
 
162
        cropButton->setIcon(KIcon("transform-crop-and-resize"));
 
163
        cropButton->setText(i18n("Crop"));
 
164
 
 
165
        QObject::connect(dialogButtonBox, SIGNAL(accepted()),
 
166
                         q, SIGNAL(cropRequested()));
 
167
        QObject::connect(dialogButtonBox, SIGNAL(rejected()),
 
168
                         q, SIGNAL(done()));
 
169
    }
169
170
};
170
171
 
171
 
 
172
 
CropWidget::CropWidget(QWidget* parent, ImageView* imageView, CropTool* cropTool)
 
172
CropWidget::CropWidget(QWidget* parent, RasterImageView* imageView, CropTool* cropTool)
173
173
: QWidget(parent)
174
 
, d(new CropWidgetPrivate) {
175
 
        setWindowFlags(Qt::Tool);
176
 
        d->that = this;
177
 
        d->mDocument = imageView->document();
178
 
        d->mUpdatingFromCropTool = false;
179
 
        d->mCropTool = cropTool;
180
 
        d->setupUi(this);
181
 
        setFont(KGlobalSettings::smallestReadableFont());
182
 
        layout()->setMargin(KDialog::marginHint());
183
 
        layout()->setSizeConstraint(QLayout::SetFixedSize);
184
 
 
185
 
        connect(d->advancedCheckBox, SIGNAL(toggled(bool)),
186
 
                d->advancedWidget, SLOT(setVisible(bool)));
187
 
        d->advancedWidget->setVisible(false);
188
 
        d->advancedWidget->layout()->setMargin(0);
189
 
 
190
 
        d->initRatioComboBox();
191
 
 
192
 
        connect(d->mCropTool, SIGNAL(rectUpdated(const QRect&)),
193
 
                SLOT(setCropRect(const QRect&)) );
194
 
 
195
 
        connect(d->leftSpinBox, SIGNAL(valueChanged(int)),
196
 
                SLOT(slotPositionChanged()) );
197
 
        connect(d->topSpinBox, SIGNAL(valueChanged(int)),
198
 
                SLOT(slotPositionChanged()) );
199
 
        connect(d->widthSpinBox, SIGNAL(valueChanged(int)),
200
 
                SLOT(slotWidthChanged()) );
201
 
        connect(d->heightSpinBox, SIGNAL(valueChanged(int)),
202
 
                SLOT(slotHeightChanged()) );
203
 
 
204
 
        d->initCropButton();
205
 
        
206
 
        connect(d->ratioComboBox, SIGNAL(editTextChanged(const QString&)),
207
 
                SLOT(slotRatioComboBoxEditTextChanged()) );
208
 
        connect(d->ratioComboBox, SIGNAL(activated(int)),
209
 
                SLOT(slotRatioComboBoxActivated()) );
210
 
 
211
 
        // Don't do this before signals are connected, otherwise the tool won't get
212
 
        // initialized
213
 
        d->initSpinBoxes();
214
 
 
215
 
        setCropRect(d->mCropTool->rect());
216
 
}
217
 
 
218
 
 
219
 
CropWidget::~CropWidget() {
220
 
        delete d;
221
 
}
222
 
 
223
 
 
224
 
void CropWidget::setCropRect(const QRect& rect) {
225
 
        d->mUpdatingFromCropTool = true;
226
 
        d->leftSpinBox->setValue(rect.left());
227
 
        d->topSpinBox->setValue(rect.top());
228
 
        d->widthSpinBox->setValue(rect.width());
229
 
        d->heightSpinBox->setValue(rect.height());
230
 
        d->mUpdatingFromCropTool = false;
231
 
}
232
 
 
233
 
 
234
 
void CropWidget::slotPositionChanged() {
235
 
        const QSize size = d->mDocument->size();
236
 
        d->widthSpinBox->setMaximum(size.width() - d->leftSpinBox->value());
237
 
        d->heightSpinBox->setMaximum(size.height() - d->topSpinBox->value());
238
 
 
239
 
        if (d->mUpdatingFromCropTool) {
240
 
                return;
241
 
        }
242
 
        d->mCropTool->setRect(d->cropRect());
243
 
}
244
 
 
245
 
 
246
 
void CropWidget::slotWidthChanged() {
247
 
        d->leftSpinBox->setMaximum(d->mDocument->width() - d->widthSpinBox->value());
248
 
 
249
 
        if (d->mUpdatingFromCropTool) {
250
 
                return;
251
 
        }
252
 
        if (d->ratioIsConstrained()) {
253
 
                int height = int(d->widthSpinBox->value() * d->cropRatio());
254
 
                d->heightSpinBox->setValue(height);
255
 
        }
256
 
        d->mCropTool->setRect(d->cropRect());
257
 
}
258
 
 
259
 
 
260
 
void CropWidget::slotHeightChanged() {
261
 
        d->topSpinBox->setMaximum(d->mDocument->height() - d->heightSpinBox->value());
262
 
 
263
 
        if (d->mUpdatingFromCropTool) {
264
 
                return;
265
 
        }
266
 
        if (d->ratioIsConstrained()) {
267
 
                int width = int(d->heightSpinBox->value() / d->cropRatio());
268
 
                d->widthSpinBox->setValue(width);
269
 
        }
270
 
        d->mCropTool->setRect(d->cropRect());
271
 
}
272
 
 
273
 
 
274
 
void CropWidget::applyRatioConstraint() {
275
 
        double ratio = d->cropRatio();
276
 
        d->mCropTool->setCropRatio(ratio);
277
 
 
278
 
        if (!d->ratioIsConstrained()) {
279
 
                return;
280
 
        }
281
 
        QRect rect = d->cropRect();
282
 
        rect.setHeight(int(rect.width() * ratio));
283
 
        d->mCropTool->setRect(rect);
284
 
}
285
 
 
286
 
 
287
 
void CropWidget::slotRatioComboBoxEditTextChanged() {
288
 
        applyRatioConstraint();
289
 
}
290
 
 
291
 
 
292
 
void CropWidget::slotRatioComboBoxActivated() {
293
 
        // If the ratioComboBox contains text like this: "w:h (foo bar)", change it
294
 
        // to "w:h" only, so that it's easier to edit for the user.
295
 
        QStringList lst = d->ratioComboBox->currentText().split(' ');
296
 
        if (lst.size() > 1) {
297
 
                SignalBlocker blocker(d->ratioComboBox);
298
 
                d->ratioComboBox->setEditText(lst[0]);
299
 
                applyRatioConstraint();
300
 
        }
301
 
}
302
 
 
 
174
, d(new CropWidgetPrivate)
 
175
{
 
176
    setWindowFlags(Qt::Tool);
 
177
    d->q = this;
 
178
    d->mDocument = imageView->document();
 
179
    d->mUpdatingFromCropTool = false;
 
180
    d->mCropTool = cropTool;
 
181
    d->setupUi(this);
 
182
    setFont(KGlobalSettings::smallestReadableFont());
 
183
    layout()->setMargin(KDialog::marginHint());
 
184
    layout()->setSizeConstraint(QLayout::SetFixedSize);
 
185
 
 
186
    connect(d->advancedCheckBox, SIGNAL(toggled(bool)),
 
187
            d->advancedWidget, SLOT(setVisible(bool)));
 
188
    d->advancedWidget->setVisible(false);
 
189
    d->advancedWidget->layout()->setMargin(0);
 
190
 
 
191
    d->initRatioComboBox();
 
192
 
 
193
    connect(d->mCropTool, SIGNAL(rectUpdated(QRect)),
 
194
            SLOT(setCropRect(QRect)));
 
195
 
 
196
    connect(d->leftSpinBox, SIGNAL(valueChanged(int)),
 
197
            SLOT(slotPositionChanged()));
 
198
    connect(d->topSpinBox, SIGNAL(valueChanged(int)),
 
199
            SLOT(slotPositionChanged()));
 
200
    connect(d->widthSpinBox, SIGNAL(valueChanged(int)),
 
201
            SLOT(slotWidthChanged()));
 
202
    connect(d->heightSpinBox, SIGNAL(valueChanged(int)),
 
203
            SLOT(slotHeightChanged()));
 
204
 
 
205
    d->initDialogButtonBox();
 
206
 
 
207
    connect(d->ratioComboBox, SIGNAL(editTextChanged(QString)),
 
208
            SLOT(slotRatioComboBoxEditTextChanged()));
 
209
    connect(d->ratioComboBox, SIGNAL(activated(int)),
 
210
            SLOT(slotRatioComboBoxActivated()));
 
211
 
 
212
    // Don't do this before signals are connected, otherwise the tool won't get
 
213
    // initialized
 
214
    d->initSpinBoxes();
 
215
 
 
216
    setCropRect(d->mCropTool->rect());
 
217
}
 
218
 
 
219
CropWidget::~CropWidget()
 
220
{
 
221
    delete d;
 
222
}
 
223
 
 
224
void CropWidget::setCropRect(const QRect& rect)
 
225
{
 
226
    d->mUpdatingFromCropTool = true;
 
227
    d->leftSpinBox->setValue(rect.left());
 
228
    d->topSpinBox->setValue(rect.top());
 
229
    d->widthSpinBox->setValue(rect.width());
 
230
    d->heightSpinBox->setValue(rect.height());
 
231
    d->mUpdatingFromCropTool = false;
 
232
}
 
233
 
 
234
void CropWidget::slotPositionChanged()
 
235
{
 
236
    const QSize size = d->mDocument->size();
 
237
    d->widthSpinBox->setMaximum(size.width() - d->leftSpinBox->value());
 
238
    d->heightSpinBox->setMaximum(size.height() - d->topSpinBox->value());
 
239
 
 
240
    if (d->mUpdatingFromCropTool) {
 
241
        return;
 
242
    }
 
243
    d->mCropTool->setRect(d->cropRect());
 
244
}
 
245
 
 
246
void CropWidget::slotWidthChanged()
 
247
{
 
248
    d->leftSpinBox->setMaximum(d->mDocument->width() - d->widthSpinBox->value());
 
249
 
 
250
    if (d->mUpdatingFromCropTool) {
 
251
        return;
 
252
    }
 
253
    if (d->ratioIsConstrained()) {
 
254
        int height = int(d->widthSpinBox->value() * d->cropRatio());
 
255
        d->heightSpinBox->setValue(height);
 
256
    }
 
257
    d->mCropTool->setRect(d->cropRect());
 
258
}
 
259
 
 
260
void CropWidget::slotHeightChanged()
 
261
{
 
262
    d->topSpinBox->setMaximum(d->mDocument->height() - d->heightSpinBox->value());
 
263
 
 
264
    if (d->mUpdatingFromCropTool) {
 
265
        return;
 
266
    }
 
267
    if (d->ratioIsConstrained()) {
 
268
        int width = int(d->heightSpinBox->value() / d->cropRatio());
 
269
        d->widthSpinBox->setValue(width);
 
270
    }
 
271
    d->mCropTool->setRect(d->cropRect());
 
272
}
 
273
 
 
274
void CropWidget::applyRatioConstraint()
 
275
{
 
276
    double ratio = d->cropRatio();
 
277
    d->mCropTool->setCropRatio(ratio);
 
278
 
 
279
    if (!d->ratioIsConstrained()) {
 
280
        return;
 
281
    }
 
282
    QRect rect = d->cropRect();
 
283
    rect.setHeight(int(rect.width() * ratio));
 
284
    d->mCropTool->setRect(rect);
 
285
}
 
286
 
 
287
void CropWidget::slotRatioComboBoxEditTextChanged()
 
288
{
 
289
    applyRatioConstraint();
 
290
}
 
291
 
 
292
void CropWidget::slotRatioComboBoxActivated()
 
293
{
 
294
    // If the ratioComboBox contains text like this: "w:h (foo bar)", change it
 
295
    // to "w:h" only, so that it's easier to edit for the user.
 
296
    QStringList lst = d->ratioComboBox->currentText().split(' ');
 
297
    if (lst.size() > 1) {
 
298
        SignalBlocker blocker(d->ratioComboBox);
 
299
        d->ratioComboBox->setEditText(lst[0]);
 
300
        applyRatioConstraint();
 
301
    }
 
302
}
303
303
 
304
304
} // namespace