File indexing completed on 2024-06-02 04:23:50

0001 /*
0002    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0003    All rights reserved.
0004 
0005    Redistribution and use in source and binary forms, with or without
0006    modification, are permitted provided that the following conditions
0007    are met:
0008 
0009    1. Redistributions of source code must retain the above copyright
0010       notice, this list of conditions and the following disclaimer.
0011    2. Redistributions in binary form must reproduce the above copyright
0012       notice, this list of conditions and the following disclaimer in the
0013       documentation and/or other materials provided with the distribution.
0014 
0015    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0016    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0017    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0018    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0019    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0020    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0021    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0022    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0023    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0024    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0025 */
0026 
0027 #define DEBUG_KP_TOOL_ROTATE 0
0028 
0029 
0030 #include "kpTransformRotateDialog.h"
0031 
0032 #include "kpDefs.h"
0033 #include "document/kpDocument.h"
0034 #include "pixmapfx/kpPixmapFX.h"
0035 #include "tools/kpTool.h"
0036 #include "environments/dialogs/imagelib/transforms/kpTransformDialogEnvironment.h"
0037 #include "views/manager/kpViewManager.h"
0038 
0039 #include "kpLogCategories.h"
0040 #include <KLocalizedString>
0041 
0042 #include <QGroupBox>
0043 #include <QIcon>
0044 #include <QLabel>
0045 #include <QSpinBox>
0046 #include <QPushButton>
0047 #include <QRadioButton>
0048 #include <QTransform>
0049 #include <QGridLayout>
0050 
0051 // private static
0052 int kpTransformRotateDialog::s_lastWidth = -1,
0053     kpTransformRotateDialog::s_lastHeight = -1;
0054 
0055 // private static
0056 bool kpTransformRotateDialog::s_lastIsClockwise = true;
0057 int kpTransformRotateDialog::s_lastAngleCustom = 0;
0058 
0059 
0060 kpTransformRotateDialog::kpTransformRotateDialog (bool actOnSelection,
0061         kpTransformDialogEnvironment *_env, QWidget *parent)
0062     : kpTransformPreviewDialog (kpTransformPreviewDialog::AllFeatures,
0063         false/*don't reserve top row*/,
0064         actOnSelection ? i18nc ("@title:window", "Rotate Selection") : i18nc ("@title:window", "Rotate Image"),
0065         i18n ("After rotate:"),
0066         actOnSelection,
0067         _env, parent)
0068 {
0069     s_lastAngleCustom = 0;
0070 
0071 
0072     createDirectionGroupBox ();
0073     createAngleGroupBox ();
0074 
0075 
0076     if (s_lastWidth > 0 && s_lastHeight > 0) {
0077         resize (s_lastWidth, s_lastHeight);
0078     }
0079 
0080 
0081     slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ());
0082     slotUpdate ();
0083 }
0084 
0085 kpTransformRotateDialog::~kpTransformRotateDialog ()
0086 {
0087     s_lastWidth = width ();
0088     s_lastHeight = height ();
0089 }
0090 
0091 
0092 // private
0093 void kpTransformRotateDialog::createDirectionGroupBox ()
0094 {
0095     auto *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ());
0096     addCustomWidget (directionGroupBox);
0097 
0098     QPixmap antiClockwisePixmap;
0099     const QIcon rotateLeftIcon = QIcon::fromTheme(QStringLiteral("object-rotate-left"));
0100     // Don't fall back to a generic "object-rotate" or "object"
0101     if (rotateLeftIcon.isNull() || rotateLeftIcon.name() != QLatin1String("object-rotate-left")) {
0102         antiClockwisePixmap = QPixmap(QStringLiteral(":/icons/image_rotate_anticlockwise"));
0103     } else {
0104         antiClockwisePixmap = rotateLeftIcon.pixmap(48);
0105     }
0106 
0107     auto *antiClockwisePixmapLabel = new QLabel (directionGroupBox);
0108     antiClockwisePixmapLabel->setPixmap (antiClockwisePixmap);
0109 
0110     QPixmap clockwisePixmap;
0111     const QIcon rotateRightIcon = QIcon::fromTheme(QStringLiteral("object-rotate-right"));
0112     if (rotateRightIcon.isNull() || rotateRightIcon.name() != QLatin1String("object-rotate-right")) {
0113         clockwisePixmap = QPixmap(QStringLiteral(":/icons/image_rotate_clockwise"));
0114     } else {
0115         clockwisePixmap = rotateRightIcon.pixmap(48);
0116     }
0117 
0118     auto *clockwisePixmapLabel = new QLabel (directionGroupBox);
0119     clockwisePixmapLabel->setPixmap (clockwisePixmap);
0120 
0121     m_antiClockwiseRadioButton = new QRadioButton (i18n ("Cou&nterclockwise"), directionGroupBox);
0122     m_clockwiseRadioButton = new QRadioButton (i18n ("C&lockwise"), directionGroupBox);
0123 
0124 
0125     m_antiClockwiseRadioButton->setChecked (!s_lastIsClockwise);
0126     m_clockwiseRadioButton->setChecked (s_lastIsClockwise);
0127 
0128 
0129     auto *directionLayout = new QGridLayout (directionGroupBox );
0130     directionLayout->addWidget (antiClockwisePixmapLabel, 0, 0, Qt::AlignCenter);
0131     directionLayout->addWidget (clockwisePixmapLabel, 0, 1, Qt::AlignCenter);
0132     directionLayout->addWidget (m_antiClockwiseRadioButton, 1, 0, Qt::AlignCenter);
0133     directionLayout->addWidget (m_clockwiseRadioButton, 1, 1, Qt::AlignCenter);
0134 
0135 
0136     connect (m_antiClockwiseRadioButton, &QRadioButton::toggled,
0137              this, &kpTransformRotateDialog::slotUpdate);
0138 
0139     connect (m_clockwiseRadioButton, &QRadioButton::toggled,
0140              this, &kpTransformRotateDialog::slotUpdate);
0141 }
0142 
0143 // private
0144 void kpTransformRotateDialog::createAngleGroupBox ()
0145 {
0146     auto *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ());
0147     addCustomWidget (angleGroupBox);
0148 
0149 
0150     m_angle90RadioButton = new QRadioButton (i18n ("90 &degrees"), angleGroupBox);
0151     m_angle180RadioButton = new QRadioButton (i18n ("180 d&egrees"), angleGroupBox);
0152     m_angle270RadioButton = new QRadioButton (i18n ("270 de&grees"), angleGroupBox);
0153 
0154     m_angleCustomRadioButton = new QRadioButton (i18n ("C&ustom:"), angleGroupBox);
0155     m_angleCustomInput = new QSpinBox;
0156     m_angleCustomInput->setMinimum(-359);
0157     m_angleCustomInput->setMaximum(+359);
0158     m_angleCustomInput->setValue(s_lastAngleCustom);
0159     auto *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
0160 
0161 
0162     m_angleCustomRadioButton->setChecked (true);
0163 
0164 
0165     auto *angleLayout = new QGridLayout (angleGroupBox );
0166 
0167     angleLayout->addWidget (m_angle90RadioButton, 0, 0, 1, 3);
0168     angleLayout->addWidget (m_angle180RadioButton, 1, 0, 1, 3);
0169     angleLayout->addWidget (m_angle270RadioButton, 2, 0, 1, 3);
0170 
0171     angleLayout->addWidget (m_angleCustomRadioButton, 3, 0);
0172     angleLayout->addWidget (m_angleCustomInput, 3, 1);
0173     angleLayout->addWidget (degreesLabel, 3, 2);
0174 
0175     angleLayout->setColumnStretch (1, 2);  // Stretch Custom Angle Input
0176 
0177 
0178 
0179     connect (m_angle90RadioButton, &QRadioButton::toggled,
0180              this, &kpTransformRotateDialog::slotUpdate);
0181     connect (m_angle180RadioButton, &QRadioButton::toggled,
0182              this, &kpTransformRotateDialog::slotUpdate);
0183     connect (m_angle270RadioButton, &QRadioButton::toggled,
0184              this, &kpTransformRotateDialog::slotUpdate);
0185 
0186     connect (m_angleCustomRadioButton, &QRadioButton::toggled,
0187              this, &kpTransformRotateDialog::slotAngleCustomRadioButtonToggled);
0188     connect (m_angleCustomRadioButton, &QRadioButton::toggled,
0189              this, &kpTransformRotateDialog::slotUpdate);
0190 
0191     connect (m_angleCustomInput,
0192              static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
0193              this, &kpTransformRotateDialog::slotUpdate);
0194 }
0195 
0196 
0197 // public virtual [base kpTransformPreviewDialog]
0198 bool kpTransformRotateDialog::isNoOp () const
0199 {
0200     return (angle () == 0);
0201 }
0202 
0203 // public
0204 int kpTransformRotateDialog::angle () const
0205 {
0206     int retAngle;
0207 
0208 
0209     if (m_angle90RadioButton->isChecked ()) {
0210         retAngle = 90;
0211     }
0212     else if (m_angle180RadioButton->isChecked ()) {
0213         retAngle = 180;
0214     }
0215     else if (m_angle270RadioButton->isChecked ()) {
0216         retAngle = 270;
0217     }
0218     else { // if (m_angleCustomRadioButton->isChecked ())
0219         retAngle = m_angleCustomInput->value ();
0220     }
0221 
0222 
0223     if (m_antiClockwiseRadioButton->isChecked ()) {
0224         retAngle *= -1;
0225     }
0226 
0227 
0228     if (retAngle < 0) {
0229         retAngle += ((0 - retAngle) / 360 + 1) * 360;
0230     }
0231 
0232     if (retAngle >= 360) {
0233         retAngle -= ((retAngle - 360) / 360 + 1) * 360;
0234     }
0235 
0236 
0237     return retAngle;
0238 }
0239 
0240 
0241 // private virtual [base kpTransformPreviewDialog]
0242 QSize kpTransformRotateDialog::newDimensions () const
0243 {
0244     QTransform matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ());
0245     QRect rect = matrix.mapRect (QRect (0, 0, m_oldWidth, m_oldHeight));
0246     return rect.size ();
0247 }
0248 
0249 // private virtual [base kpTransformPreviewDialog]
0250 QImage kpTransformRotateDialog::transformPixmap (const QImage &image,
0251                                                  int targetWidth, int targetHeight) const
0252 {
0253     return kpPixmapFX::rotate (image, angle (),
0254                                m_environ->backgroundColor (m_actOnSelection),
0255                                targetWidth, targetHeight);
0256 }
0257 
0258 
0259 // private slot
0260 void kpTransformRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked)
0261 {
0262     m_angleCustomInput->setEnabled (isChecked);
0263 
0264     if (isChecked) {
0265         m_angleCustomInput->setFocus();
0266     }
0267 }
0268 
0269 // private slot virtual [base kpTransformPreviewDialog]
0270 void kpTransformRotateDialog::slotUpdate ()
0271 {
0272     s_lastIsClockwise = m_clockwiseRadioButton->isChecked ();
0273     s_lastAngleCustom = m_angleCustomInput->value ();
0274 
0275     kpTransformPreviewDialog::slotUpdate ();
0276 }
0277 
0278 
0279 // private slot virtual [base QDialog]
0280 void kpTransformRotateDialog::accept ()
0281 {
0282     KLocalizedString message;
0283     QString caption, continueButtonText;
0284 
0285     if (document ()->selection ())
0286     {
0287         if (!document ()->textSelection ())
0288         {
0289             message =
0290                 ki18n ("<qt><p>Rotating the selection to %1x%2"
0291                       " may take a substantial amount of memory."
0292                       " This can reduce system"
0293                       " responsiveness and cause other application resource"
0294                       " problems.</p>"
0295 
0296                       "<p>Are you sure you want to rotate the selection?</p></qt>");
0297 
0298             caption = i18nc ("@title:window", "Rotate Selection?");
0299             continueButtonText = i18n ("Rotat&e Selection");
0300         }
0301     }
0302     else
0303     {
0304         message =
0305             ki18n ("<qt><p>Rotating the image to %1x%2"
0306                   " may take a substantial amount of memory."
0307                   " This can reduce system"
0308                   " responsiveness and cause other application resource"
0309                   " problems.</p>"
0310 
0311                   "<p>Are you sure you want to rotate the image?</p></qt>");
0312 
0313         caption = i18nc ("@title:window", "Rotate Image?");
0314         continueButtonText = i18n ("Rotat&e Image");
0315     }
0316 
0317 
0318     const int newWidth = newDimensions ().width ();
0319     const int newHeight = newDimensions ().height ();
0320 
0321     if (kpTool::warnIfBigImageSize (m_oldWidth,
0322             m_oldHeight,
0323             newWidth, newHeight,
0324             message.subs (newWidth).subs (newHeight).toString (),
0325             caption,
0326             continueButtonText,
0327             this))
0328     {
0329         QDialog::accept ();
0330     }
0331 }
0332 
0333 #include "moc_kpTransformRotateDialog.cpp"