kpTransformRotateDialog.cpp 10 KB
Newer Older
1
/*
2
   Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
3
   All rights reserved.
Clarence Dang's avatar
   
Clarence Dang committed
4

5
6
7
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
Clarence Dang's avatar
   
Clarence Dang committed
8

9
10
11
12
13
   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
Clarence Dang's avatar
   
Clarence Dang committed
14

15
16
17
18
19
20
   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
22
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
24
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
*/

27
#define DEBUG_KP_TOOL_ROTATE 0
28

Clarence Dang's avatar
Clarence Dang committed
29

30
31
32
33
34
35
36
37
38
#include "kpTransformRotateDialog.h"

#include "kpDefs.h"
#include "document/kpDocument.h"
#include "pixmapfx/kpPixmapFX.h"
#include "tools/kpTool.h"
#include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h"
#include "views/manager/kpViewManager.h"

39
#include "kpLogCategories.h"
40
#include <KLocalizedString>
Clarence Dang's avatar
Clarence Dang committed
41

42
43
44
45
#include <QButtonGroup>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
46
#include <QImage>
47
#include <QSpinBox>
48
49
50
#include <QPolygon>
#include <QPushButton>
#include <QRadioButton>
Laurent Montel's avatar
Laurent Montel committed
51
#include <QTransform>
52
53


54
// private static
55
56
int kpTransformRotateDialog::s_lastWidth = -1,
    kpTransformRotateDialog::s_lastHeight = -1;
57

Clarence Dang's avatar
   
Clarence Dang committed
58
// private static
59
60
bool kpTransformRotateDialog::s_lastIsClockwise = true;
int kpTransformRotateDialog::s_lastAngleCustom = 0;
61
62


63
kpTransformRotateDialog::kpTransformRotateDialog (bool actOnSelection,
64
        kpTransformDialogEnvironment *_env, QWidget *parent)
65
    : kpTransformPreviewDialog (kpTransformPreviewDialog::AllFeatures,
66
        false/*don't reserve top row*/,
67
        actOnSelection ? i18nc ("@title:window", "Rotate Selection") : i18nc ("@title:window", "Rotate Image"),
68
        i18n ("After rotate:"),
69
        actOnSelection,
70
        _env, parent)
Clarence Dang's avatar
   
Clarence Dang committed
71
72
{
    s_lastAngleCustom = 0;
73
74


Clarence Dang's avatar
   
Clarence Dang committed
75
76
    createDirectionGroupBox ();
    createAngleGroupBox ();
77
78


79
    if (s_lastWidth > 0 && s_lastHeight > 0) {
80
        resize (s_lastWidth, s_lastHeight);
81
    }
82
83


Clarence Dang's avatar
   
Clarence Dang committed
84
85
    slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ());
    slotUpdate ();
86
87
}

88
kpTransformRotateDialog::~kpTransformRotateDialog ()
89
{
90
91
    s_lastWidth = width ();
    s_lastHeight = height ();
92
93
94
}


Clarence Dang's avatar
   
Clarence Dang committed
95
// private
96
void kpTransformRotateDialog::createDirectionGroupBox ()
97
{
98
    auto *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ());
Clarence Dang's avatar
   
Clarence Dang committed
99
    addCustomWidget (directionGroupBox);
100
101


102
    auto *antiClockwisePixmapLabel = new QLabel (directionGroupBox);
103
    antiClockwisePixmapLabel->setPixmap (QStringLiteral(":/icons/image_rotate_anticlockwise"));
104

105
    auto *clockwisePixmapLabel = new QLabel (directionGroupBox);
106
    clockwisePixmapLabel->setPixmap (QStringLiteral(":/icons/image_rotate_clockwise"));
Clarence Dang's avatar
   
Clarence Dang committed
107
108


Clarence Dang's avatar
Clarence Dang committed
109
    m_antiClockwiseRadioButton = new QRadioButton (i18n ("Cou&nterclockwise"), directionGroupBox);
Clarence Dang's avatar
   
Clarence Dang committed
110
111
112
113
114
115
116
    m_clockwiseRadioButton = new QRadioButton (i18n ("C&lockwise"), directionGroupBox);


    m_antiClockwiseRadioButton->setChecked (!s_lastIsClockwise);
    m_clockwiseRadioButton->setChecked (s_lastIsClockwise);


117
    auto *directionLayout = new QGridLayout (directionGroupBox );
Clarence Dang's avatar
   
Clarence Dang committed
118
119
120
121
122
123
    directionLayout->addWidget (antiClockwisePixmapLabel, 0, 0, Qt::AlignCenter);
    directionLayout->addWidget (clockwisePixmapLabel, 0, 1, Qt::AlignCenter);
    directionLayout->addWidget (m_antiClockwiseRadioButton, 1, 0, Qt::AlignCenter);
    directionLayout->addWidget (m_clockwiseRadioButton, 1, 1, Qt::AlignCenter);


124
125
126
127
128
    connect (m_antiClockwiseRadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotUpdate);

    connect (m_clockwiseRadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotUpdate);
129
130
}

Clarence Dang's avatar
   
Clarence Dang committed
131
// private
132
void kpTransformRotateDialog::createAngleGroupBox ()
133
{
134
    auto *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ());
Clarence Dang's avatar
   
Clarence Dang committed
135
    addCustomWidget (angleGroupBox);
136
137


138
139
140
    m_angle90RadioButton = new QRadioButton (i18n ("90 &degrees"), angleGroupBox);
    m_angle180RadioButton = new QRadioButton (i18n ("180 d&egrees"), angleGroupBox);
    m_angle270RadioButton = new QRadioButton (i18n ("270 de&grees"), angleGroupBox);
141

Clarence Dang's avatar
   
Clarence Dang committed
142
    m_angleCustomRadioButton = new QRadioButton (i18n ("C&ustom:"), angleGroupBox);
143
144
145
146
    m_angleCustomInput = new QSpinBox;
    m_angleCustomInput->setMinimum(-359);
    m_angleCustomInput->setMaximum(+359);
    m_angleCustomInput->setValue(s_lastAngleCustom);
147
    auto *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
148

Clarence Dang's avatar
   
Clarence Dang committed
149

Clarence Dang's avatar
Clarence Dang committed
150
    m_angleCustomRadioButton->setChecked (true);
Clarence Dang's avatar
   
Clarence Dang committed
151
152


153
    auto *angleLayout = new QGridLayout (angleGroupBox );
Clarence Dang's avatar
   
Clarence Dang committed
154

Clarence Dang's avatar
Clarence Dang committed
155
156
157
    angleLayout->addWidget (m_angle90RadioButton, 0, 0, 1, 3);
    angleLayout->addWidget (m_angle180RadioButton, 1, 0, 1, 3);
    angleLayout->addWidget (m_angle270RadioButton, 2, 0, 1, 3);
Clarence Dang's avatar
   
Clarence Dang committed
158
159
160
161
162

    angleLayout->addWidget (m_angleCustomRadioButton, 3, 0);
    angleLayout->addWidget (m_angleCustomInput, 3, 1);
    angleLayout->addWidget (degreesLabel, 3, 2);

Clarence Dang's avatar
Clarence Dang committed
163
    angleLayout->setColumnStretch (1, 2);  // Stretch Custom Angle Input
Clarence Dang's avatar
   
Clarence Dang committed
164
165
166



167
168
169
170
171
172
173
174
175
176
177
    connect (m_angle90RadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotUpdate);
    connect (m_angle180RadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotUpdate);
    connect (m_angle270RadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotUpdate);

    connect (m_angleCustomRadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotAngleCustomRadioButtonToggled);
    connect (m_angleCustomRadioButton, &QRadioButton::toggled,
             this, &kpTransformRotateDialog::slotUpdate);
Clarence Dang's avatar
   
Clarence Dang committed
178

179
180
181
    connect (m_angleCustomInput,
             static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
             this, &kpTransformRotateDialog::slotUpdate);
182
183
}

Clarence Dang's avatar
   
Clarence Dang committed
184

185
// public virtual [base kpTransformPreviewDialog]
186
bool kpTransformRotateDialog::isNoOp () const
187
{
Clarence Dang's avatar
   
Clarence Dang committed
188
    return (angle () == 0);
189
190
}

Clarence Dang's avatar
   
Clarence Dang committed
191
// public
192
int kpTransformRotateDialog::angle () const
193
{
Clarence Dang's avatar
   
Clarence Dang committed
194
195
196
    int retAngle;


197
    if (m_angle90RadioButton->isChecked ()) {
Clarence Dang's avatar
   
Clarence Dang committed
198
        retAngle = 90;
199
200
    }
    else if (m_angle180RadioButton->isChecked ()) {
Clarence Dang's avatar
   
Clarence Dang committed
201
        retAngle = 180;
202
203
    }
    else if (m_angle270RadioButton->isChecked ()) {
Clarence Dang's avatar
   
Clarence Dang committed
204
        retAngle = 270;
205
206
    }
    else { // if (m_angleCustomRadioButton->isChecked ())
Clarence Dang's avatar
   
Clarence Dang committed
207
        retAngle = m_angleCustomInput->value ();
208
    }
Clarence Dang's avatar
   
Clarence Dang committed
209
210


211
    if (m_antiClockwiseRadioButton->isChecked ()) {
Clarence Dang's avatar
   
Clarence Dang committed
212
        retAngle *= -1;
213
    }
Clarence Dang's avatar
   
Clarence Dang committed
214
215


216
    if (retAngle < 0) {
Clarence Dang's avatar
   
Clarence Dang committed
217
        retAngle += ((0 - retAngle) / 360 + 1) * 360;
218
    }
Clarence Dang's avatar
   
Clarence Dang committed
219

220
    if (retAngle >= 360) {
Clarence Dang's avatar
   
Clarence Dang committed
221
        retAngle -= ((retAngle - 360) / 360 + 1) * 360;
222
    }
Clarence Dang's avatar
   
Clarence Dang committed
223
224
225


    return retAngle;
226
227
}

Clarence Dang's avatar
   
Clarence Dang committed
228

229
// private virtual [base kpTransformPreviewDialog]
230
QSize kpTransformRotateDialog::newDimensions () const
231
{
Laurent Montel's avatar
Laurent Montel committed
232
    QTransform matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ());
Clarence Dang's avatar
Clarence Dang committed
233
    QRect rect = matrix.mapRect (QRect (0, 0, m_oldWidth, m_oldHeight));
Clarence Dang's avatar
   
Clarence Dang committed
234
    return rect.size ();
235
236
}

237
// private virtual [base kpTransformPreviewDialog]
238
239
QImage kpTransformRotateDialog::transformPixmap (const QImage &image,
                                                 int targetWidth, int targetHeight) const
240
{
241
    return kpPixmapFX::rotate (image, angle (),
242
                               m_environ->backgroundColor (m_actOnSelection),
Clarence Dang's avatar
   
Clarence Dang committed
243
                               targetWidth, targetHeight);
244
245
}

Clarence Dang's avatar
   
Clarence Dang committed
246
247

// private slot
248
void kpTransformRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked)
249
{
Clarence Dang's avatar
   
Clarence Dang committed
250
    m_angleCustomInput->setEnabled (isChecked);
251

252
    if (isChecked) {
253
        m_angleCustomInput->setFocus();
254
    }
255
256
}

257
// private slot virtual [base kpTransformPreviewDialog]
258
void kpTransformRotateDialog::slotUpdate ()
259
{
Clarence Dang's avatar
   
Clarence Dang committed
260
261
    s_lastIsClockwise = m_clockwiseRadioButton->isChecked ();
    s_lastAngleCustom = m_angleCustomInput->value ();
262

263
    kpTransformPreviewDialog::slotUpdate ();
264
265
266
}


267
// private slot virtual [base QDialog]
268
void kpTransformRotateDialog::accept ()
269
{
270
271
    KLocalizedString message;
    QString caption, continueButtonText;
272
273
274

    if (document ()->selection ())
    {
275
        if (!document ()->textSelection ())
276
        {
277
            message =
278
                ki18n ("<qt><p>Rotating the selection to %1x%2"
279
280
281
282
283
                      " may take a substantial amount of memory."
                      " This can reduce system"
                      " responsiveness and cause other application resource"
                      " problems.</p>"

284
                      "<p>Are you sure you want to rotate the selection?</p></qt>");
285

286
            caption = i18nc ("@title:window", "Rotate Selection?");
287
            continueButtonText = i18n ("Rotat&e Selection");
288
289
290
291
        }
    }
    else
    {
292
        message =
293
            ki18n ("<qt><p>Rotating the image to %1x%2"
294
295
296
297
298
                  " may take a substantial amount of memory."
                  " This can reduce system"
                  " responsiveness and cause other application resource"
                  " problems.</p>"

299
                  "<p>Are you sure you want to rotate the image?</p></qt>");
300

301
        caption = i18nc ("@title:window", "Rotate Image?");
302
        continueButtonText = i18n ("Rotat&e Image");
303
304
305
306
307
308
309
310
311
    }


    const int newWidth = newDimensions ().width ();
    const int newHeight = newDimensions ().height ();

    if (kpTool::warnIfBigImageSize (m_oldWidth,
            m_oldHeight,
            newWidth, newHeight,
312
            message.subs (newWidth).subs (newHeight).toString (),
313
314
            caption,
            continueButtonText,
315
316
            this))
    {
Christoph Feck's avatar
Christoph Feck committed
317
        QDialog::accept ();
318
319
320
    }
}

321