File indexing completed on 2024-05-12 16:02:02

0001 /*
0002  * KDE. Krita Project.
0003  *
0004  * SPDX-FileCopyrightText: 2020 Deif Lou <ginoba@gmail.com>
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <cmath>
0010 #include <functional>
0011 
0012 #include <QHBoxLayout>
0013 #include <QToolButton>
0014 #include <QAction>
0015 #include <QEvent>
0016 #include <QMenu>
0017 #include <QLineEdit>
0018 #include <QStyleOptionSpinBox>
0019 #include <QStyle>
0020 #include <QContextMenuEvent>
0021 
0022 #include <kis_icon_utils.h>
0023 #include <kis_signals_blocker.h>
0024 
0025 #include <klocalizedstring.h>
0026 
0027 #include "KisAngleSelector.h"
0028 
0029 struct KisAngleSelectorSpinBox::Private
0030 {
0031     KisAngleSelectorSpinBox *q;
0032     bool isFlat;
0033     bool hasFocus;
0034     bool isHovered;
0035     QSize cachedSizeHint;
0036 
0037     void updateStyleSheet()
0038     {
0039         if (!isFlat || hasFocus || isHovered) {
0040             q->setStyleSheet("QDoubleSpinBox{}");
0041         } else {
0042             q->setStyleSheet(
0043                 "QDoubleSpinBox{background:transparent; border:transparent;}"
0044                 "QDoubleSpinBox::up-button{background:transparent; border:transparent;}"
0045                 "QDoubleSpinBox::down-button{background:transparent; border:transparent;}"
0046             );
0047         }
0048         q->lineEdit()->setStyleSheet("QLineEdit{background:transparent;}");
0049     }
0050 };
0051 
0052 KisAngleSelectorSpinBox::KisAngleSelectorSpinBox(QWidget *parent)
0053     : KisDoubleParseSpinBox(parent)
0054     , m_d(new Private)
0055 {
0056     m_d->q = this;
0057     m_d->isFlat = false;
0058     m_d->hasFocus = false;
0059     m_d->isHovered = false;
0060     m_d->updateStyleSheet();
0061 }
0062 
0063 KisAngleSelectorSpinBox::~KisAngleSelectorSpinBox()
0064 {}
0065 
0066 void KisAngleSelectorSpinBox::setRange(double min, double max)
0067 {
0068     m_d->cachedSizeHint = QSize();
0069     KisDoubleParseSpinBox::setRange(min, max);
0070 }
0071 
0072 double KisAngleSelectorSpinBox::valueFromText(const QString & text) const
0073 {
0074     const double v = KisDoubleParseSpinBox::valueFromText(text);
0075     return KisAngleSelector::closestCoterminalAngleInRange(v, minimum(), maximum());
0076 }
0077 
0078 bool KisAngleSelectorSpinBox::isFlat() const
0079 {
0080     return m_d->isFlat;
0081 }
0082 
0083 void KisAngleSelectorSpinBox::setFlat(bool newFlat)
0084 {
0085     m_d->isFlat = newFlat;
0086     m_d->updateStyleSheet();
0087 }
0088 
0089 void KisAngleSelectorSpinBox::enterEvent(QEvent *e)
0090 {
0091     m_d->isHovered = true;
0092     m_d->updateStyleSheet();
0093     KisDoubleParseSpinBox::enterEvent(e);
0094 }
0095 
0096 void KisAngleSelectorSpinBox::leaveEvent(QEvent *e)
0097 {
0098     m_d->isHovered = false;
0099     m_d->updateStyleSheet();
0100     KisDoubleParseSpinBox::leaveEvent(e);
0101 }
0102 
0103 void KisAngleSelectorSpinBox::focusInEvent(QFocusEvent *e)
0104 {
0105     m_d->hasFocus = true;
0106     m_d->updateStyleSheet();
0107     KisDoubleParseSpinBox::focusInEvent(e);
0108 }
0109 
0110 void KisAngleSelectorSpinBox::focusOutEvent(QFocusEvent *e)
0111 {
0112     m_d->hasFocus = false;
0113     m_d->updateStyleSheet();
0114     KisDoubleParseSpinBox::focusOutEvent(e);
0115 }
0116 
0117 QSize KisAngleSelectorSpinBox::minimumSizeHint() const
0118 {
0119     if (m_d->cachedSizeHint.isEmpty()) {
0120         ensurePolished();
0121 
0122         const QFontMetrics fm(fontMetrics());
0123         int h = lineEdit()->minimumSizeHint().height();
0124         int w = 0;
0125 
0126         QString s;
0127         QString fixedContent =  prefix() + suffix() + QLatin1Char(' ');
0128         s = textFromValue(minimum());
0129         s.truncate(18);
0130         s += fixedContent;
0131 #if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
0132         w = qMax(w, fm.horizontalAdvance(s));
0133 #else
0134         w = qMax(w, fm.width(s));
0135 #endif
0136         s = textFromValue(maximum());
0137         s.truncate(18);
0138         s += fixedContent;
0139 #if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
0140         w = qMax(w, fm.horizontalAdvance(s));
0141 #else
0142         w = qMax(w, fm.width(s));
0143 #endif
0144 
0145 
0146         w += 2; // cursor blinking space
0147 
0148         QStyleOptionSpinBox option;
0149         initStyleOption(&option);
0150 
0151         QSize hint(w, h);
0152 
0153         KisDoubleParseSpinBox tmp;
0154         m_d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &option, hint, &tmp);
0155     }
0156 
0157     return m_d->cachedSizeHint;
0158 }
0159 
0160 QSize KisAngleSelectorSpinBox::sizeHint() const
0161 {
0162     return minimumSizeHint();
0163 }
0164 
0165 void KisAngleSelectorSpinBox::refreshStyle()
0166 {
0167     m_d->cachedSizeHint = QSize();
0168     updateGeometry();
0169     m_d->updateStyleSheet();
0170 }
0171 
0172 struct KisAngleSelector::Private
0173 {
0174     KisAngleSelector *q;
0175     KisAngleGauge *angleGauge;
0176     KisAngleSelectorSpinBox *spinBox;
0177     QToolButton *toolButtonFlipOptions;
0178     QToolButton *toolButtonFlipHorizontally;
0179     QToolButton *toolButtonFlipVertically;
0180     QToolButton *toolButtonFlipHorizontallyAndVertically;
0181     QAction *actionFlipHorizontally;
0182     QAction *actionFlipVertically;
0183     QAction *actionFlipHorizontallyAndVertically;
0184     QAction *actionResetAngle;
0185     QMenu *menuFlip;
0186 
0187     KisAngleSelector::FlipOptionsMode flipOptionsMode;
0188     int angleGaugeSize;
0189 
0190     void on_angleGauge_angleChanged(qreal angle);
0191     void on_spinBox_valueChanged(double value);
0192     void on_actionFlipHorizontally_triggered();
0193     void on_actionFlipVertically_triggered();
0194     void on_actionFlipHorizontallyAndVertically_triggered();
0195     void on_actionResetAngle_triggered();
0196 
0197     void resizeAngleGauge();
0198 };
0199 
0200 KisAngleSelector::KisAngleSelector(QWidget* parent)
0201     : QWidget(parent)
0202     , m_d(new Private)
0203 {
0204     m_d->q = this;
0205 
0206     QHBoxLayout *mainLayout = new QHBoxLayout;
0207     mainLayout->setSpacing(5);
0208     mainLayout->setContentsMargins(0, 0, 0, 0);
0209 
0210     m_d->angleGauge = new KisAngleGauge(this);
0211     m_d->angleGauge->installEventFilter(this);
0212 
0213     m_d->spinBox = new KisAngleSelectorSpinBox(this);
0214     m_d->spinBox->setSuffix(i18nc("Degrees symbol", "˚"));
0215     m_d->spinBox->setRange(0, 360);
0216     m_d->spinBox->setWrapping(true);
0217 
0218     m_d->actionFlipHorizontally = new QAction(this);
0219     m_d->actionFlipHorizontally->setText(
0220         i18nc(
0221             "Flips the angle horizontally, around the vertical axis",
0222             "Flip the angle horizontally"
0223         )
0224     );
0225     m_d->actionFlipVertically = new QAction(this);
0226     m_d->actionFlipVertically->setText(
0227         i18nc(
0228             "Flips the angle vertically, around the horizontal axis",
0229             "Flip the angle vertically"
0230         )
0231     );
0232     m_d->actionFlipHorizontallyAndVertically = new QAction(this);
0233     m_d->actionFlipHorizontallyAndVertically->setText(
0234         i18nc(
0235             "Flips the angle horizontally and vertically",
0236             "Flip the angle horizontally and vertically"
0237         )
0238     );
0239     QAction *menuSeparator = new QAction(this);
0240     menuSeparator->setSeparator(true);
0241     m_d->actionResetAngle = new QAction(this);
0242     m_d->actionResetAngle->setText(
0243         i18nc(
0244             "Reset the angle to a predefined value",
0245             "Reset angle"
0246         )
0247     );
0248     m_d->menuFlip = new QMenu(this);
0249     m_d->menuFlip->addAction(m_d->actionFlipHorizontally);
0250     m_d->menuFlip->addAction(m_d->actionFlipVertically);
0251     m_d->menuFlip->addAction(m_d->actionFlipHorizontallyAndVertically);
0252     m_d->menuFlip->addAction(menuSeparator);
0253     m_d->menuFlip->addAction(m_d->actionResetAngle);
0254 
0255     QHBoxLayout *layoutFlipButtons = new QHBoxLayout;
0256     layoutFlipButtons->setSpacing(1);
0257     layoutFlipButtons->setContentsMargins(0, 0, 0, 0);
0258 
0259     m_d->toolButtonFlipOptions = new QToolButton(this);
0260     m_d->toolButtonFlipOptions->setPopupMode(QToolButton::InstantPopup);
0261     m_d->toolButtonFlipOptions->setAutoRaise(true);
0262     m_d->toolButtonFlipOptions->setIcon(KisIconUtils::loadIcon("view-choose"));
0263     m_d->toolButtonFlipOptions->setStyleSheet("QToolButton::menu-indicator { image: none; }");
0264     m_d->toolButtonFlipOptions->setMenu(m_d->menuFlip);
0265     m_d->toolButtonFlipOptions->setFocusPolicy(Qt::StrongFocus);
0266 
0267     m_d->toolButtonFlipHorizontally = new QToolButton(this);
0268     m_d->toolButtonFlipHorizontally->setAutoRaise(true);
0269     m_d->toolButtonFlipHorizontally->setIcon(KisIconUtils::loadIcon("flip_angle_h"));
0270     m_d->toolButtonFlipHorizontally->setIconSize(QSize(20, 20));
0271     m_d->toolButtonFlipHorizontally->setToolTip(m_d->actionFlipHorizontally->text());
0272     m_d->toolButtonFlipHorizontally->setFocusPolicy(Qt::StrongFocus);
0273 
0274     m_d->toolButtonFlipVertically = new QToolButton(this);
0275     m_d->toolButtonFlipVertically->setAutoRaise(true);
0276     m_d->toolButtonFlipVertically->setIcon(KisIconUtils::loadIcon("flip_angle_v"));
0277     m_d->toolButtonFlipVertically->setIconSize(QSize(20, 20));
0278     m_d->toolButtonFlipVertically->setToolTip(m_d->actionFlipVertically->text());
0279     m_d->toolButtonFlipVertically->setFocusPolicy(Qt::StrongFocus);
0280 
0281     m_d->toolButtonFlipHorizontallyAndVertically = new QToolButton(this);
0282     m_d->toolButtonFlipHorizontallyAndVertically->setAutoRaise(true);
0283     m_d->toolButtonFlipHorizontallyAndVertically->setIcon(KisIconUtils::loadIcon("flip_angle_hv"));
0284     m_d->toolButtonFlipHorizontallyAndVertically->setIconSize(QSize(20, 20));
0285     m_d->toolButtonFlipHorizontallyAndVertically->setToolTip(m_d->actionFlipHorizontallyAndVertically->text());
0286     m_d->toolButtonFlipHorizontallyAndVertically->setFocusPolicy(Qt::StrongFocus);
0287 
0288     layoutFlipButtons->addWidget(m_d->toolButtonFlipOptions);
0289     layoutFlipButtons->addWidget(m_d->toolButtonFlipHorizontally);
0290     layoutFlipButtons->addWidget(m_d->toolButtonFlipVertically);
0291     layoutFlipButtons->addWidget(m_d->toolButtonFlipHorizontallyAndVertically);
0292 
0293     mainLayout->addWidget(m_d->angleGauge);
0294     mainLayout->addWidget(m_d->spinBox);
0295     mainLayout->addLayout(layoutFlipButtons);
0296 
0297     setLayout(mainLayout);
0298 
0299     setTabOrder(m_d->angleGauge, m_d->spinBox);
0300     setTabOrder(m_d->spinBox, m_d->toolButtonFlipOptions);
0301     setTabOrder(m_d->toolButtonFlipOptions, m_d->toolButtonFlipHorizontally);
0302     setTabOrder(m_d->toolButtonFlipHorizontally, m_d->toolButtonFlipVertically);
0303     setTabOrder(m_d->toolButtonFlipVertically, m_d->toolButtonFlipHorizontallyAndVertically);
0304 
0305     setFlipOptionsMode(FlipOptionsMode_Buttons);
0306     setGaugeSize(0);
0307     
0308     using namespace std::placeholders;
0309     connect(
0310         m_d->angleGauge,
0311         &KisAngleGauge::angleChanged,
0312         std::bind(&Private::on_angleGauge_angleChanged, m_d.data(), _1)
0313     );
0314     connect(
0315         m_d->spinBox,
0316         QOverload<double>::of(&KisDoubleParseSpinBox::valueChanged),
0317         std::bind(&Private::on_spinBox_valueChanged, m_d.data(), _1)
0318     );
0319     connect(
0320         m_d->actionFlipHorizontally,
0321         &QAction::triggered,
0322         std::bind(&Private::on_actionFlipHorizontally_triggered, m_d.data())
0323     );
0324     connect(
0325         m_d->actionFlipVertically,
0326         &QAction::triggered,
0327         std::bind(&Private::on_actionFlipVertically_triggered, m_d.data())
0328     );
0329     connect(
0330         m_d->actionFlipHorizontallyAndVertically,
0331         &QAction::triggered,
0332         std::bind(&Private::on_actionFlipHorizontallyAndVertically_triggered, m_d.data())
0333     );
0334     connect(m_d->actionResetAngle, SIGNAL(triggered()), SLOT(reset()));
0335     connect(m_d->toolButtonFlipHorizontally, SIGNAL(clicked()), m_d->actionFlipHorizontally, SLOT(trigger()));
0336     connect(m_d->toolButtonFlipVertically, SIGNAL(clicked()), m_d->actionFlipVertically, SLOT(trigger()));
0337     connect(m_d->toolButtonFlipHorizontallyAndVertically, SIGNAL(clicked()), m_d->actionFlipHorizontallyAndVertically, SLOT(trigger()));
0338 }
0339 
0340 KisAngleSelector::~KisAngleSelector()
0341 {}
0342 
0343 qreal KisAngleSelector::angle() const
0344 {
0345     return m_d->spinBox->value();
0346 }
0347 
0348 qreal KisAngleSelector::snapAngle() const
0349 {
0350     return m_d->angleGauge->snapAngle();
0351 }
0352 
0353 qreal KisAngleSelector::resetAngle() const
0354 {
0355     return m_d->angleGauge->resetAngle();
0356 }
0357 
0358 int KisAngleSelector::decimals() const
0359 {
0360     return m_d->spinBox->decimals();
0361 }
0362 
0363 qreal KisAngleSelector::maximum() const
0364 {
0365     return m_d->spinBox->maximum();
0366 }
0367 
0368 qreal KisAngleSelector::minimum() const
0369 {
0370     return m_d->spinBox->minimum();
0371 }
0372 
0373 QString KisAngleSelector::prefix() const
0374 {
0375     return m_d->spinBox->prefix();
0376 }
0377 
0378 bool KisAngleSelector::wrapping() const
0379 {
0380     return m_d->spinBox->wrapping();
0381 }
0382 
0383 KisAngleSelector::FlipOptionsMode KisAngleSelector::flipOptionsMode() const
0384 {
0385     return m_d->flipOptionsMode;
0386 }
0387 
0388 int KisAngleSelector::gaugeSize() const
0389 {
0390     return m_d->angleGaugeSize;
0391 }
0392 
0393 KisAngleGauge::IncreasingDirection KisAngleSelector::increasingDirection() const
0394 {
0395     return m_d->angleGauge->increasingDirection();
0396 }
0397 
0398 bool KisAngleSelector::isUsingFlatSpinBox() const
0399 {
0400     return m_d->spinBox->isFlat();
0401 }
0402 
0403 void KisAngleSelector::setAngle(qreal newAngle)
0404 {
0405     KisSignalsBlocker angleGaugeSignalsBlocker(m_d->angleGauge);
0406     KisSignalsBlocker spinBoxSignalsBlocker(m_d->spinBox);
0407 
0408     const qreal oldAngle = m_d->spinBox->value();
0409     
0410     m_d->spinBox->setValue(newAngle);
0411     m_d->angleGauge->setAngle(m_d->spinBox->value());
0412 
0413     if (qFuzzyCompare(oldAngle, m_d->spinBox->value())) {
0414         return;
0415     }
0416 
0417     emit angleChanged(m_d->spinBox->value());
0418 }
0419 
0420 void KisAngleSelector::setSnapAngle(qreal newSnapAngle)
0421 {
0422     m_d->angleGauge->setSnapAngle(newSnapAngle);
0423 }
0424 
0425 void KisAngleSelector::setResetAngle(qreal newResetAngle)
0426 {
0427     m_d->angleGauge->setResetAngle(newResetAngle);
0428 }
0429 
0430 void KisAngleSelector::setDecimals(int newNumberOfDecimals)
0431 {
0432     m_d->spinBox->setDecimals(newNumberOfDecimals);
0433 }
0434 
0435 void KisAngleSelector::setMaximum(qreal newMaximum)
0436 {
0437     m_d->spinBox->setMaximum(newMaximum);
0438 }
0439 
0440 void KisAngleSelector::setMinimum(qreal newMinimum)
0441 {
0442     m_d->spinBox->setMinimum(newMinimum);
0443 }
0444 
0445 void KisAngleSelector::setRange(qreal newMinimum, qreal newMaximum)
0446 {
0447     m_d->spinBox->setRange(newMinimum, newMaximum);
0448 }
0449 
0450 void KisAngleSelector::setPrefix(const QString &newPrefix)
0451 {
0452     m_d->spinBox->setPrefix(newPrefix);
0453 }
0454 
0455 void KisAngleSelector::setWrapping(bool newWrapping)
0456 {
0457     m_d->spinBox->setWrapping(newWrapping);
0458 }
0459 
0460 void KisAngleSelector::setFlipOptionsMode(FlipOptionsMode newMode)
0461 {
0462     m_d->flipOptionsMode = newMode;
0463 
0464     m_d->toolButtonFlipOptions->setVisible(newMode == FlipOptionsMode_MenuButton);
0465 
0466     bool useButtons = newMode == FlipOptionsMode_Buttons;
0467     m_d->toolButtonFlipHorizontally->setVisible(useButtons);
0468     m_d->toolButtonFlipVertically->setVisible(useButtons);
0469     m_d->toolButtonFlipHorizontallyAndVertically->setVisible(useButtons);
0470 
0471     bool showMenus = newMode != FlipOptionsMode_NoFlipOptions;
0472     m_d->actionFlipHorizontally->setVisible(showMenus);
0473     m_d->actionFlipVertically->setVisible(showMenus);
0474     m_d->actionFlipHorizontallyAndVertically->setVisible(showMenus);
0475 }
0476 
0477 void KisAngleSelector::setGaugeSize(int newGaugeSize)
0478 {
0479     if (newGaugeSize < 0) {
0480         return;
0481     }
0482     m_d->angleGaugeSize = newGaugeSize;
0483     m_d->resizeAngleGauge();
0484 }
0485 
0486 void KisAngleSelector::setIncreasingDirection(KisAngleGauge::IncreasingDirection newIncreasingDirection)
0487 {
0488     m_d->angleGauge->setIncreasingDirection(newIncreasingDirection);
0489 }
0490 
0491 void KisAngleSelector::useFlatSpinBox(bool newUseFlatSpinBox)
0492 {
0493     m_d->spinBox->setFlat(newUseFlatSpinBox);
0494 }
0495 
0496 void KisAngleSelector::reset()
0497 {
0498     m_d->angleGauge->reset();
0499 }
0500 
0501 qreal KisAngleSelector::closestCoterminalAngleInRange(qreal angle, qreal minimum, qreal maximum, bool *ok)
0502 {
0503     bool hasCoterminalAngleInRange = true;
0504 
0505     if (angle < minimum) {
0506         const qreal d = minimum - angle;
0507         const qreal cycles = std::floor(d / 360.0) + 1;
0508         angle += cycles * 360.0;
0509         if (angle > maximum) {
0510             hasCoterminalAngleInRange = false;
0511             angle = minimum;
0512         }
0513     } else if (angle > maximum) {
0514         const qreal d = angle - maximum;
0515         const qreal cycles = std::floor(d / 360.0) + 1;
0516         angle -= cycles * 360.0;
0517         if (angle < minimum) {
0518             hasCoterminalAngleInRange = false;
0519             angle = maximum;
0520         }
0521     }
0522 
0523     if (ok) {
0524         *ok = hasCoterminalAngleInRange;
0525     }
0526     return angle;
0527 }
0528 
0529 qreal KisAngleSelector::closestCoterminalAngleInRange(qreal angle, bool *ok) const
0530 {
0531     return closestCoterminalAngleInRange(angle, m_d->spinBox->minimum(), m_d->spinBox->maximum(), ok);
0532 }
0533 
0534 qreal KisAngleSelector::flipAngle(qreal angle, Qt::Orientations orientations)
0535 {
0536     if ((orientations & Qt::Horizontal) && (orientations & Qt::Vertical)) {
0537         angle += 180.0;
0538     } else if (orientations & Qt::Horizontal) {
0539         qreal a = std::fmod(angle, 360.0);
0540         if (a < 0) {
0541             a += 360.0;
0542         }
0543         if (a > 270.0) {
0544             angle -= 2.0 * (a - 270.0);
0545         } else if (a > 180.0) {
0546             angle += 2.0 * (270.0 - a);
0547         } else if (a > 90.0) {
0548             angle -= 2.0 * (a - 90.0);
0549         } else {
0550             angle += 2.0 * (90.0 - a);
0551         }
0552     } else if (orientations & Qt::Vertical) {
0553         qreal a = std::fmod(angle, 360.0);
0554         if (a < 0) {
0555             a += 360.0;
0556         }
0557         if (a > 270.0) {
0558             angle += 2.0 * (360.0 - a);
0559         } else if (a > 180.0) {
0560             angle -= 2.0 * (a - 180.0);
0561         } else if (a > 90.0) {
0562             angle += 2.0 * (180.0 - a);
0563         } else {
0564             angle -= 2.0 * a;
0565         }
0566     }
0567 
0568     return angle;
0569 }
0570 
0571 qreal KisAngleSelector::flipAngle(qreal angle, qreal minimum, qreal maximum, Qt::Orientations orientations, bool *ok)
0572 {
0573     return closestCoterminalAngleInRange(flipAngle(angle, orientations), minimum, maximum, ok);
0574 }
0575 
0576 void KisAngleSelector::flip(Qt::Orientations orientations)
0577 {
0578     bool ok = false;
0579     qreal flippedAngle = flipAngle(angle(), minimum(), maximum(), orientations, &ok);
0580     if (ok) {
0581         setAngle(flippedAngle);
0582     }
0583 }
0584 
0585 bool KisAngleSelector::event(QEvent *e)
0586 {
0587     if (e->type() == QEvent::PaletteChange) {
0588         // For some reason the spinbox, that uses stylesheets, doesn't update
0589         // on palette changes, so we reset the stylesheet to force an update.
0590         // Calling m_d->spinBox->update() doesn't work
0591         m_d->spinBox->refreshStyle();
0592     } else if (e->type() == QEvent::StyleChange || e->type() == QEvent::FontChange) {
0593         // Temporarily reset the spin box style so that we can get its
0594         // height size hint
0595         m_d->spinBox->refreshStyle();
0596         m_d->resizeAngleGauge();
0597     }
0598     return QWidget::event(e);
0599 }
0600 
0601 bool KisAngleSelector::eventFilter(QObject *o, QEvent *e)
0602 {
0603     QWidget *w = qobject_cast<QWidget*>(o);
0604     if (w != m_d->angleGauge || !w->isEnabled() || !e || e->type() != QEvent::ContextMenu) {
0605         return false;
0606     }
0607     QContextMenuEvent *cme = static_cast<QContextMenuEvent*>(e);
0608 
0609     m_d->menuFlip->exec(cme->globalPos());
0610     return true;
0611 }
0612 
0613 void KisAngleSelector::Private::on_angleGauge_angleChanged(qreal angle)
0614 {
0615     q->setAngle(q->closestCoterminalAngleInRange(angle));
0616 }
0617 
0618 void KisAngleSelector::Private::on_spinBox_valueChanged(double value)
0619 {
0620     KisSignalsBlocker angleGaugeSignalsBlocker(angleGauge);
0621 
0622     angleGauge->setAngle(value);
0623 
0624     emit q->angleChanged(value);
0625 }
0626 
0627 void KisAngleSelector::Private::on_actionFlipHorizontally_triggered()
0628 {
0629     q->flip(Qt::Horizontal);
0630 }
0631 
0632 void KisAngleSelector::Private::on_actionFlipVertically_triggered()
0633 {
0634     q->flip(Qt::Vertical);
0635 }
0636 
0637 void KisAngleSelector::Private::on_actionFlipHorizontallyAndVertically_triggered()
0638 {
0639     q->flip(Qt::Horizontal | Qt::Vertical);
0640 }
0641 
0642 void KisAngleSelector::Private::resizeAngleGauge()
0643 {
0644     if (angleGaugeSize == 0) {
0645         angleGauge->setFixedSize(spinBox->sizeHint().height(), spinBox->sizeHint().height());
0646     } else {
0647         angleGauge->setFixedSize(angleGaugeSize, angleGaugeSize);
0648     }
0649 }