18#include <QStyleOptionSpinBox>
20#include <QContextMenuEvent>
25#include <klocalizedstring.h>
40 q->setStyleSheet(
"QDoubleSpinBox{}");
43 "QDoubleSpinBox{background:transparent; border:transparent;}"
44 "QDoubleSpinBox::up-button{background:transparent; border:transparent;}"
45 "QDoubleSpinBox::down-button{background:transparent; border:transparent;}"
48 q->lineEdit()->setStyleSheet(
"QLineEdit{background:transparent;}");
58 m_d->hasFocus =
false;
59 m_d->isHovered =
false;
60 m_d->updateStyleSheet();
68 m_d->cachedSizeHint = QSize();
69 KisDoubleParseSpinBox::setRange(min, max);
85 m_d->isFlat = newFlat;
86 m_d->updateStyleSheet();
88#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
94 m_d->isHovered =
true;
95 m_d->updateStyleSheet();
96 KisDoubleParseSpinBox::enterEvent(e);
101 m_d->isHovered =
false;
102 m_d->updateStyleSheet();
103 KisDoubleParseSpinBox::leaveEvent(e);
108 m_d->hasFocus =
true;
109 m_d->updateStyleSheet();
110 KisDoubleParseSpinBox::focusInEvent(e);
115 m_d->hasFocus =
false;
116 m_d->updateStyleSheet();
117 KisDoubleParseSpinBox::focusOutEvent(e);
122 if (
m_d->cachedSizeHint.isEmpty()) {
125 const QFontMetrics fm(fontMetrics());
126 int h = lineEdit()->minimumSizeHint().height();
130 QString fixedContent = prefix() + suffix() + QLatin1Char(
' ');
134 w = qMax(w, fm.horizontalAdvance(s));
138 w = qMax(w, fm.horizontalAdvance(s));
142 QStyleOptionSpinBox option;
143 initStyleOption(&option);
148 m_d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &option, hint, &
tmp);
151 return m_d->cachedSizeHint;
161 m_d->cachedSizeHint = QSize();
163 m_d->updateStyleSheet();
200 QHBoxLayout *mainLayout =
new QHBoxLayout;
201 mainLayout->setSpacing(5);
202 mainLayout->setContentsMargins(0, 0, 0, 0);
205 m_d->angleGauge->installEventFilter(
this);
208 m_d->spinBox->setSuffix(i18nc(
"Degrees symbol",
"˚"));
209 m_d->spinBox->setRange(0, 360);
210 m_d->spinBox->setWrapping(
true);
212 m_d->actionFlipHorizontally =
new QAction(
this);
213 m_d->actionFlipHorizontally->setText(
215 "Flips the angle horizontally, around the vertical axis",
216 "Flip the angle horizontally"
219 m_d->actionFlipVertically =
new QAction(
this);
220 m_d->actionFlipVertically->setText(
222 "Flips the angle vertically, around the horizontal axis",
223 "Flip the angle vertically"
226 m_d->actionFlipHorizontallyAndVertically =
new QAction(
this);
227 m_d->actionFlipHorizontallyAndVertically->setText(
229 "Flips the angle horizontally and vertically",
230 "Flip the angle horizontally and vertically"
233 QAction *menuSeparator =
new QAction(
this);
234 menuSeparator->setSeparator(
true);
235 m_d->actionResetAngle =
new QAction(
this);
236 m_d->actionResetAngle->setText(
238 "Reset the angle to a predefined value",
242 m_d->menuFlip =
new QMenu(
this);
243 m_d->menuFlip->addAction(
m_d->actionFlipHorizontally);
244 m_d->menuFlip->addAction(
m_d->actionFlipVertically);
245 m_d->menuFlip->addAction(
m_d->actionFlipHorizontallyAndVertically);
246 m_d->menuFlip->addAction(menuSeparator);
247 m_d->menuFlip->addAction(
m_d->actionResetAngle);
249 QHBoxLayout *layoutFlipButtons =
new QHBoxLayout;
250 layoutFlipButtons->setSpacing(1);
251 layoutFlipButtons->setContentsMargins(0, 0, 0, 0);
253 m_d->toolButtonFlipOptions =
new QToolButton(
this);
254 m_d->toolButtonFlipOptions->setPopupMode(QToolButton::InstantPopup);
255 m_d->toolButtonFlipOptions->setAutoRaise(
true);
257 m_d->toolButtonFlipOptions->setStyleSheet(
"QToolButton::menu-indicator { image: none; }");
258 m_d->toolButtonFlipOptions->setMenu(
m_d->menuFlip);
259 m_d->toolButtonFlipOptions->setFocusPolicy(Qt::StrongFocus);
261 m_d->toolButtonFlipHorizontally =
new QToolButton(
this);
262 m_d->toolButtonFlipHorizontally->setAutoRaise(
true);
264 m_d->toolButtonFlipHorizontally->setIconSize(QSize(20, 20));
265 m_d->toolButtonFlipHorizontally->setToolTip(
m_d->actionFlipHorizontally->text());
266 m_d->toolButtonFlipHorizontally->setFocusPolicy(Qt::StrongFocus);
268 m_d->toolButtonFlipVertically =
new QToolButton(
this);
269 m_d->toolButtonFlipVertically->setAutoRaise(
true);
271 m_d->toolButtonFlipVertically->setIconSize(QSize(20, 20));
272 m_d->toolButtonFlipVertically->setToolTip(
m_d->actionFlipVertically->text());
273 m_d->toolButtonFlipVertically->setFocusPolicy(Qt::StrongFocus);
275 m_d->toolButtonFlipHorizontallyAndVertically =
new QToolButton(
this);
276 m_d->toolButtonFlipHorizontallyAndVertically->setAutoRaise(
true);
278 m_d->toolButtonFlipHorizontallyAndVertically->setIconSize(QSize(20, 20));
279 m_d->toolButtonFlipHorizontallyAndVertically->setToolTip(
m_d->actionFlipHorizontallyAndVertically->text());
280 m_d->toolButtonFlipHorizontallyAndVertically->setFocusPolicy(Qt::StrongFocus);
282 layoutFlipButtons->addWidget(
m_d->toolButtonFlipOptions);
283 layoutFlipButtons->addWidget(
m_d->toolButtonFlipHorizontally);
284 layoutFlipButtons->addWidget(
m_d->toolButtonFlipVertically);
285 layoutFlipButtons->addWidget(
m_d->toolButtonFlipHorizontallyAndVertically);
287 mainLayout->addWidget(
m_d->angleGauge);
288 mainLayout->addWidget(
m_d->spinBox);
289 mainLayout->addLayout(layoutFlipButtons);
291 setLayout(mainLayout);
293 setTabOrder(
m_d->angleGauge,
m_d->spinBox);
294 setTabOrder(
m_d->spinBox,
m_d->toolButtonFlipOptions);
295 setTabOrder(
m_d->toolButtonFlipOptions,
m_d->toolButtonFlipHorizontally);
296 setTabOrder(
m_d->toolButtonFlipHorizontally,
m_d->toolButtonFlipVertically);
297 setTabOrder(
m_d->toolButtonFlipVertically,
m_d->toolButtonFlipHorizontallyAndVertically);
302 using namespace std::placeholders;
310 QOverload<double>::of(&KisDoubleParseSpinBox::valueChanged),
314 m_d->actionFlipHorizontally,
319 m_d->actionFlipVertically,
324 m_d->actionFlipHorizontallyAndVertically,
329 connect(
m_d->toolButtonFlipHorizontally, SIGNAL(clicked()),
m_d->actionFlipHorizontally, SLOT(trigger()));
330 connect(
m_d->toolButtonFlipVertically, SIGNAL(clicked()),
m_d->actionFlipVertically, SLOT(trigger()));
331 connect(
m_d->toolButtonFlipHorizontallyAndVertically, SIGNAL(clicked()),
m_d->actionFlipHorizontallyAndVertically, SLOT(trigger()));
339 return m_d->spinBox->value();
344 return m_d->angleGauge->snapAngle();
349 return m_d->angleGauge->resetAngle();
354 return m_d->spinBox->decimals();
359 return m_d->spinBox->maximum();
364 return m_d->spinBox->minimum();
369 return m_d->spinBox->prefix();
374 return m_d->spinBox->wrapping();
379 return m_d->flipOptionsMode;
384 return m_d->commonWidgetsHeight;
389 return m_d->angleGauge->increasingDirection();
394 return m_d->spinBox->isFlat();
402 const qreal oldAngle =
m_d->spinBox->value();
404 m_d->spinBox->setValue(newAngle);
405 m_d->angleGauge->setAngle(
m_d->spinBox->value());
416 m_d->angleGauge->setSnapAngle(newSnapAngle);
421 m_d->angleGauge->setResetAngle(newResetAngle);
426 m_d->spinBox->setDecimals(newNumberOfDecimals);
431 m_d->spinBox->setMaximum(newMaximum);
436 m_d->spinBox->setMinimum(newMinimum);
441 m_d->spinBox->setRange(newMinimum, newMaximum);
446 m_d->spinBox->setPrefix(newPrefix);
451 m_d->spinBox->setWrapping(newWrapping);
456 m_d->flipOptionsMode = newMode;
461 m_d->toolButtonFlipHorizontally->setVisible(useButtons);
462 m_d->toolButtonFlipVertically->setVisible(useButtons);
463 m_d->toolButtonFlipHorizontallyAndVertically->setVisible(useButtons);
466 m_d->actionFlipHorizontally->setVisible(showMenus);
467 m_d->actionFlipVertically->setVisible(showMenus);
468 m_d->actionFlipHorizontallyAndVertically->setVisible(showMenus);
476 m_d->commonWidgetsHeight = newHeight;
477 m_d->resizeWidgets();
482 m_d->angleGauge->setIncreasingDirection(newIncreasingDirection);
487 m_d->spinBox->setFlat(newUseFlatSpinBox);
492 m_d->angleGauge->reset();
497 bool hasCoterminalAngleInRange =
true;
501 const qreal cycles = std::floor(d / 360.0) + 1;
502 angle += cycles * 360.0;
504 hasCoterminalAngleInRange =
false;
509 const qreal cycles = std::floor(d / 360.0) + 1;
510 angle -= cycles * 360.0;
512 hasCoterminalAngleInRange =
false;
518 *ok = hasCoterminalAngleInRange;
530 if ((orientations & Qt::Horizontal) && (orientations & Qt::Vertical)) {
532 }
else if (orientations & Qt::Horizontal) {
533 qreal a = std::fmod(
angle, 360.0);
538 angle -= 2.0 * (a - 270.0);
539 }
else if (a > 180.0) {
540 angle += 2.0 * (270.0 - a);
541 }
else if (a > 90.0) {
542 angle -= 2.0 * (a - 90.0);
544 angle += 2.0 * (90.0 - a);
546 }
else if (orientations & Qt::Vertical) {
547 qreal a = std::fmod(
angle, 360.0);
552 angle += 2.0 * (360.0 - a);
553 }
else if (a > 180.0) {
554 angle -= 2.0 * (a - 180.0);
555 }
else if (a > 90.0) {
556 angle += 2.0 * (180.0 - a);
581 if (e->type() == QEvent::PaletteChange) {
585 m_d->spinBox->refreshStyle();
586 }
else if (e->type() == QEvent::StyleChange || e->type() == QEvent::FontChange) {
589 m_d->spinBox->refreshStyle();
590 m_d->resizeWidgets();
592 return QWidget::event(e);
597 QWidget *w = qobject_cast<QWidget*>(o);
598 if (w !=
m_d->angleGauge || !w->isEnabled() || !e || e->type() != QEvent::ContextMenu) {
601 QContextMenuEvent *cme =
static_cast<QContextMenuEvent*
>(e);
603 m_d->menuFlip->exec(cme->globalPos());
616 angleGauge->setAngle(
value);
618 Q_EMIT q->angleChanged(
value);
623 q->flip(Qt::Horizontal);
628 q->flip(Qt::Vertical);
633 q->flip(Qt::Horizontal | Qt::Vertical);
638 const int h = (commonWidgetsHeight != 0) ? commonWidgetsHeight : spinBox->sizeHint().height();
640 angleGauge->setFixedSize(h, h);
641 spinBox->setFixedHeight(h);
642 toolButtonFlipOptions->setFixedHeight(h);
643 toolButtonFlipHorizontally->setFixedHeight(h);
644 toolButtonFlipVertically->setFixedHeight(h);
645 toolButtonFlipHorizontallyAndVertically->setFixedHeight(h);
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
A circular widget that allows to choose an angle.
void angleChanged(qreal angle)
Signal emitted when the angle has changed.
QSize sizeHint() const override
void setRange(double min, double max)
void leaveEvent(QEvent *e) override
const QScopedPointer< Private > m_d
void setFlat(bool newFlat)
KisAngleSelectorSpinBox(QWidget *parent=0)
void focusInEvent(QFocusEvent *e) override
QSize minimumSizeHint() const override
void focusOutEvent(QFocusEvent *e) override
double valueFromText(const QString &text) const override
void enterEvent(QEnterEvent *e) override
~KisAngleSelectorSpinBox() override
A widget with several options to select an angle.
void setResetAngle(qreal newResetAngle)
Sets the angle that is used to reset the current angle.
static qreal flipAngle(qreal angle, Qt::Orientations orientations)
Flips an angle horizontally, vertically, or both.
void flip(Qt::Orientations orientations)
Flips the angle horizontally, vertically, or both.
FlipOptionsMode
Options to select how the flip options should be presented.
@ FlipOptionsMode_NoFlipOptions
There is no flip options available.
@ FlipOptionsMode_MenuButton
The flip options are shown as a menu accessible via a options button.
@ FlipOptionsMode_Buttons
The flip options are shown as individual buttons.
void setPrefix(const QString &newPrefix)
Sets the prefix shown in the spin box.
bool eventFilter(QObject *o, QEvent *e) override
bool wrapping() const
Gets if the angle should wrap pass the minimum or maximum angles.
int widgetsHeight() const
Gets the common height of the widgets inside this angle selector.
void setWrapping(bool newWrapping)
Sets if the angle should wrap pass the minimum or maximum angles.
qreal angle() const
Gets the current angle.
void setFlipOptionsMode(FlipOptionsMode newMode)
Sets the mode in which the flip options should be shown.
FlipOptionsMode flipOptionsMode() const
Gets the mode in which the flip options should be shown.
void setSnapAngle(qreal newSnapAngle)
Sets the angle to which multiples the selected angle will snap.
void setIncreasingDirection(KisAngleGauge::IncreasingDirection newIncreasingDirection)
Sets the increasing direction in the angle gauge.
KisAngleSelector(QWidget *parent=0)
Construct a new KisAngleSelector widget.
bool event(QEvent *e) override
qreal resetAngle() const
Gets the angle that is used to reset the current angle.
QString prefix() const
Gets the prefix shown in the spin box.
void useFlatSpinBox(bool newUseFlatSpinBox)
Sets if the spin box should be flat.
qreal maximum() const
Gets the maximum value for the angle.
qreal minimum() const
Gets the minimum value for the angle.
void setAngle(qreal newAngle)
Sets the current angle.
void setRange(qreal newMinimum, qreal newMaximum)
Sets the minimum and maximum values for the angle.
void setMaximum(qreal newMaximum)
Sets the maximum value for the angle.
qreal snapAngle() const
Gets the angle to which multiples the selected angle will snap.
void setWidgetsHeight(int newHeight)
Sets the common height of the widgets inside this angle selector. Use 0 to reset widgets to default h...
static qreal closestCoterminalAngleInRange(qreal angle, qreal minimum, qreal maximum, bool *ok=nullptr)
Gets the closest coterminal angle to the provided angle that is in the range provided.
void setDecimals(int newNumberOfDecimals)
Sets the number of decimals (precision) used by the angle.
void reset()
Sets the current angle to the reset angle.
bool isUsingFlatSpinBox() const
Gets if the spin box is flat (no border or background)
const QScopedPointer< Private > m_d
KisAngleGauge::IncreasingDirection increasingDirection() const
Gets the direction in which the angle increases in the angle gauge.
void angleChanged(qreal angle)
void setMinimum(qreal newMinimum)
Sets the minimum value for the angle.
int decimals() const
Gets the number of decimals (precision) used by the angle.
The KisDoubleParseSpinBox class is a cleverer doubleSpinBox, able to parse arithmetic expressions.
QString textFromValue(double value) const override
double valueFromText(const QString &text) const override
static bool qFuzzyCompare(half p1, half p2)
QIcon loadIcon(const QString &name)
KisAngleSelectorSpinBox * q
void on_spinBox_valueChanged(double value)
QAction * actionFlipHorizontallyAndVertically
QAction * actionFlipHorizontally
void on_actionFlipVertically_triggered()
KisAngleSelectorSpinBox * spinBox
KisAngleSelector::FlipOptionsMode flipOptionsMode
QToolButton * toolButtonFlipOptions
QAction * actionFlipVertically
void on_actionResetAngle_triggered()
QToolButton * toolButtonFlipHorizontally
QAction * actionResetAngle
QToolButton * toolButtonFlipHorizontallyAndVertically
void on_actionFlipHorizontallyAndVertically_triggered()
QToolButton * toolButtonFlipVertically
void on_angleGauge_angleChanged(qreal angle)
void on_actionFlipHorizontally_triggered()
KisAngleGauge * angleGauge