diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index f042907d681..115e3fd35ed 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -89,6 +89,11 @@ bool panelWidget(const QWidget *widget) return false; } +inline bool isDSSlider(const QWidget *widget) +{ + return (widget && widget->property("DSSlider").toBool()); +} + // Consider making this a QStyle state static bool isQmlEditorMenu(const QWidget *widget) { @@ -489,7 +494,30 @@ QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionC return QRect(); // breaks the scrollbar, but avoids the crash } #endif - return QProxyStyle::subControlRect(control, option, subControl, widget); + + QRect retval = QProxyStyle::subControlRect(control, option, subControl, widget);; + if (isDSSlider(widget)) { + if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { + switch (subControl) { + case SubControl::SC_SliderGroove: + return option->rect; + case SubControl::SC_SliderHandle: + { + int thickness = 2; + QPoint center = retval.center(); + const QRect &rect = slider->rect; + if (slider->orientation == Qt::Horizontal) + return QRect(center.x() - thickness, rect.top(), (thickness * 2) + 1, rect.height()); + else + return QRect(rect.left(), center.y() - thickness, rect.width(), (thickness * 2) + 1); + } + break; + default: + break; + } + } + } + return retval; } QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, @@ -1758,7 +1786,156 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti painter->restore(); } break; + case CC_Slider: + if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { + if (!isDSSlider(widget)) { + QProxyStyle::drawComplexControl(control, option, painter, widget); + break; + } + QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget); + QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); + + bool horizontal = slider->orientation == Qt::Horizontal; + bool ticksAbove = slider->tickPosition & QSlider::TicksAbove; + bool ticksBelow = slider->tickPosition & QSlider::TicksBelow; + bool enabled = option->state & QStyle::State_Enabled; + bool activeFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange; + + int sliderPaintingOffset = horizontal + ? handle.center().x() + : handle.center().y(); + + painter->save(); + painter->setRenderHint(QPainter::RenderHint::Antialiasing); + + int lineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth, option, widget); + Theme::Color themeframeColor = enabled + ? activeFocus + ? Theme::DSstateBackgroundColor_hover + : Theme::DSBackgroundColorAlternate + : Theme::DScontrolBackgroundDisabled; + QColor frameColor = creatorTheme()->color(themeframeColor); + + if ((option->subControls & SC_SliderGroove) && groove.isValid()) { + Theme::Color bgPlusColor = enabled ? Theme::DSBackgroundColorAlternate : Theme::DScontrolOutlineDisabled; + Theme::Color bgMinusColor = enabled ? Theme::DScontrolBackground : Theme::DScontrolOutlineDisabled; + + QRect minusRect(groove); + QRect plusRect(groove); + + if (horizontal) { + if (slider->upsideDown) { + minusRect.setLeft(sliderPaintingOffset); + plusRect.setRight(sliderPaintingOffset); + } else { + minusRect.setRight(sliderPaintingOffset); + plusRect.setLeft(sliderPaintingOffset); + } + } else { + if (slider->upsideDown) { + minusRect.setBottom(sliderPaintingOffset); + plusRect.setTop(sliderPaintingOffset); + } else { + minusRect.setTop(sliderPaintingOffset); + plusRect.setBottom(sliderPaintingOffset); + } + } + + painter->setPen(Qt::NoPen); + painter->fillRect(plusRect, creatorTheme()->color(bgPlusColor)); + painter->fillRect(minusRect, creatorTheme()->color(bgMinusColor)); + } + + if (option->subControls & SC_SliderTickmarks) { + Theme::Color tickPen = enabled + ? activeFocus + ? Theme::DSstateBackgroundColor_hover + : Theme::DSBackgroundColorAlternate + : Theme::DScontrolBackgroundDisabled; + + painter->setPen(tickPen); + int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); + int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget); + int interval = slider->tickInterval; + if (interval <= 0) { + interval = slider->singleStep; + if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval, + available) + - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, + 0, available) < 3) + interval = slider->pageStep; + } + if (interval <= 0) + interval = 1; + + int v = slider->minimum; + int len = proxy()->pixelMetric(PM_SliderLength, slider, widget); + while (v <= slider->maximum + 1) { + if (v == slider->maximum + 1 && interval == 1) + break; + const int v_ = qMin(v, slider->maximum); + int pos = sliderPositionFromValue(slider->minimum, slider->maximum, + v_, (horizontal + ? slider->rect.width() + : slider->rect.height()) - len, + slider->upsideDown) + len / 2; + int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0); + + if (horizontal) { + if (ticksAbove) { + painter->drawLine(pos, slider->rect.top() + extra, + pos, slider->rect.top() + tickSize); + } + if (ticksBelow) { + painter->drawLine(pos, slider->rect.bottom() - extra, + pos, slider->rect.bottom() - tickSize); + } + } else { + if (ticksAbove) { + painter->drawLine(slider->rect.left() + extra, pos, + slider->rect.left() + tickSize, pos); + } + if (ticksBelow) { + painter->drawLine(slider->rect.right() - extra, pos, + slider->rect.right() - tickSize, pos); + } + } + // in the case where maximum is max int + int nextInterval = v + interval; + if (nextInterval < v) + break; + v = nextInterval; + } + } + + // draw handle + if ((option->subControls & SC_SliderHandle) ) { + Theme::Color handleColor = enabled + ? slider->state & QStyle::State_Editing + ? Theme::DSsliderHandleInteraction + : slider->activeSubControls & SC_SliderHandle + ? Theme::DSsliderHandleHover + : Theme::DSsliderHandle + : Theme::DSiconColorDisabled; + + int halfSliderThickness = horizontal + ? handle.width() / 2 + : handle.height() / 2; + painter->setBrush(creatorTheme()->color(handleColor)); + painter->drawRoundedRect(handle, + halfSliderThickness, + halfSliderThickness); + } + + if (groove.isValid()) { + painter->setBrush(Qt::NoBrush); + painter->setPen(QPen(frameColor, lineWidth)); + painter->drawRect(groove); + } + painter->restore(); + } + break; default: QProxyStyle::drawComplexControl(control, option, painter, widget); break; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 7abfab5fe09..05b73278c74 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -167,8 +167,8 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) view->setSeeker(seeker); seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); - QObject::connect(seeker, &SeekerSlider::positionChanged, [seeker, view]() { - view->emitView3DAction(View3DActionType::ParticlesSeek, seeker->position()); + QObject::connect(seeker, &SeekerSlider::valueChanged, [view](int value) { + view->emitView3DAction(View3DActionType::ParticlesSeek, value); }); // Onboarding label contains instructions for new users how to get 3D content into the project diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp index 577c9a198bd..e9f8788a8d5 100644 --- a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp @@ -5,112 +5,66 @@ #include +#include #include #include -#include #include namespace QmlDesigner { -SeekerSlider::SeekerSlider(QWidget *parentWidget) - : QWidget(parentWidget), - m_bgIcon(QLatin1String(":/icon/layout/scrubbg.png")) +SeekerSlider::SeekerSlider(QWidget *parent) + : QSlider(parent) { - m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-24.png"), QSize(24, 24)); - m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-48.png"), QSize(48, 48)); - m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-24.png"), QSize(24, 24), QIcon::Disabled); - m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-48.png"), QSize(48, 48), QIcon::Disabled); - const Utils::Icon bg({{":/icon/layout/scrubbg.png", Utils::Theme::IconsBaseColor}}); - m_bgWidth = bg.pixmap().width(); - m_bgHeight = bg.pixmap().height(); - m_handleWidth = m_bgHeight; - m_handleHeight = m_bgHeight; - int width = m_bgWidth + m_handleWidth * 2; - m_sliderHalfWidth = m_bgWidth / 2; - setMinimumWidth(width); - setMaximumWidth(width); setProperty("panelwidget", true); setProperty("panelwidget_singlerow", true); + setProperty("DSSlider", true); + setOrientation(Qt::Horizontal); + setFixedWidth(120); + setMaxValue(30); } -void SeekerSlider::paintEvent([[maybe_unused]] QPaintEvent *event) +int SeekerSlider::maxValue() const { - QPainter painter(this); - { - QStyleOptionToolBar option; - option.rect = rect(); - option.state = QStyle::State_Horizontal; - style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this); - } + return maximum(); +} - int x = rect().width() / 2; - int y = rect().height() / 2; - - const QPixmap bg = m_bgIcon.pixmap(QSize(m_bgWidth, m_bgHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On); - painter.drawPixmap(x - m_bgWidth / 2, y - m_bgHeight / 2, bg); - - if (m_moving) { - const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), QIcon::Active, QIcon::On); - painter.drawPixmap(x - m_handleWidth / 2 + m_sliderPos, y - m_handleHeight / 2, handle); - } else { - const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On); - painter.drawPixmap(x - m_handleWidth / 2, y - m_handleHeight / 2, handle); - } +void SeekerSlider::setMaxValue(int maxValue) +{ + maxValue = std::abs(maxValue); + setRange(-maxValue, +maxValue); } void SeekerSlider::mousePressEvent(QMouseEvent *event) { - if (event->button() != Qt::LeftButton) { - QWidget::mousePressEvent(event); + if (event->button() != Qt::LeftButton) return; - } - int x = rect().width() / 2; - int y = rect().height() / 2; - auto pos = event->localPos(); - if (pos.x() >= x - m_handleWidth / 2 && pos.x() <= x + m_handleWidth / 2 - && pos.y() >= y - m_handleHeight / 2 && pos.y() <= y + m_handleHeight / 2) { - m_moving = true; - m_startPos = pos.x(); - } + QStyleOptionSlider os; + initStyleOption(&os); + QRect handleRect = style()->subControlRect(QStyle::CC_Slider, &os, QStyle::SC_SliderHandle, this); + m_moving = handleRect.contains(event->localPos().toPoint()); + if (m_moving) + QSlider::mousePressEvent(event); + else + event->setAccepted(false); } void SeekerSlider::mouseMoveEvent(QMouseEvent *event) { - if (!m_moving) { - QWidget::mouseMoveEvent(event); + if (!m_moving) return; - } - auto pos = event->localPos(); - int delta = pos.x() - m_startPos; - m_sliderPos = qBound(-m_sliderHalfWidth, delta, m_sliderHalfWidth); - delta = m_maxPosition * m_sliderPos / m_sliderHalfWidth; - if (delta != m_position) { - m_position = delta; - Q_EMIT positionChanged(); - update(); - } + QSlider::mouseMoveEvent(event); } void SeekerSlider::mouseReleaseEvent(QMouseEvent *event) { - if (!m_moving) { - QWidget::mouseReleaseEvent(event); + if (!m_moving) return; - } + setValue(0); m_moving = false; - m_position = 0; - m_startPos = 0; - m_sliderPos = 0; - Q_EMIT positionChanged(); - update(); -} - -int SeekerSlider::position() const -{ - return m_position; + QSlider::mouseReleaseEvent(event); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.h b/src/plugins/qmldesigner/components/formeditor/seekerslider.h index f54ff783f10..3f55ceeeae5 100644 --- a/src/plugins/qmldesigner/components/formeditor/seekerslider.h +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.h @@ -2,50 +2,30 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #pragma once -#include -#include -#include +#include namespace QmlDesigner { - -class SeekerSlider : public QWidget +class SeekerSlider : public QSlider { Q_OBJECT + public: - SeekerSlider(QWidget *parentWidget); - int position() const; - int maxPosition() const - { - return m_maxPosition; - } + explicit SeekerSlider(QWidget *parent = nullptr); - void setMaxPosition(int pos) - { - m_maxPosition = qMax(0, pos); - } - -Q_SIGNALS: - void positionChanged(); + int maxValue() const; + void setMaxValue(int maxValue); protected: - void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; private: - int m_position = 0; - int m_startPos = 0; - int m_sliderPos = 0; - int m_sliderHalfWidth = 0; - int m_maxPosition = 30; + using QSlider::setMinimum; + using QSlider::setMaximum; + using QSlider::setRange; + bool m_moving = false; - int m_bgWidth; - int m_bgHeight; - int m_handleWidth; - int m_handleHeight; - QIcon m_bgIcon; - QIcon m_handleIcon; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp index 3e3236c7f2e..4f905c91d96 100644 --- a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp @@ -48,7 +48,7 @@ ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget) m_rightToolBar->setOrientation(Qt::Horizontal); horizontalLayout->addWidget(m_leftToolBar); horizontalLayout->addWidget(stretchToolbar); - if (seeker) + if (m_seeker) horizontalLayout->addWidget(m_seeker); horizontalLayout->addWidget(m_rightToolBar); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp index 54553919ab4..6b44a3c74fe 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp @@ -429,6 +429,9 @@ void TimelineToolBar::createRightControls() m_scale = new QSlider(this); m_scale->setOrientation(Qt::Horizontal); + m_scale->setProperty("DSSlider", true); + m_scale->setProperty("panelwidget", true); + m_scale->setProperty("panelwidget_singlerow", true); m_scale->setMaximumWidth(200); m_scale->setMinimumWidth(100); m_scale->setMinimum(0);