QmlDesigner: Style particle slider for new theme

The style for slider is overridden in ManhattanStyle.
SeekSlider is modified.

Task-number: QDS-9134
Change-Id: Ib96413f2bb7918d611adf4fc19c184efae1c4f4c
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Ali Kianian
2023-02-16 17:04:53 +02:00
parent 3f816fdc77
commit c4cae904ee
6 changed files with 222 additions and 108 deletions

View File

@@ -89,6 +89,11 @@ bool panelWidget(const QWidget *widget)
return false; return false;
} }
inline bool isDSSlider(const QWidget *widget)
{
return (widget && widget->property("DSSlider").toBool());
}
// Consider making this a QStyle state // Consider making this a QStyle state
static bool isQmlEditorMenu(const QWidget *widget) 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 return QRect(); // breaks the scrollbar, but avoids the crash
} }
#endif #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<const QStyleOptionSlider *>(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, QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
@@ -1758,7 +1786,156 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti
painter->restore(); painter->restore();
} }
break; break;
case CC_Slider:
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(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: default:
QProxyStyle::drawComplexControl(control, option, painter, widget); QProxyStyle::drawComplexControl(control, option, painter, widget);
break; break;

View File

@@ -167,8 +167,8 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view)
view->setSeeker(seeker); view->setSeeker(seeker);
seeker->setToolTip(QLatin1String("Seek particle system time when paused.")); seeker->setToolTip(QLatin1String("Seek particle system time when paused."));
QObject::connect(seeker, &SeekerSlider::positionChanged, [seeker, view]() { QObject::connect(seeker, &SeekerSlider::valueChanged, [view](int value) {
view->emitView3DAction(View3DActionType::ParticlesSeek, seeker->position()); view->emitView3DAction(View3DActionType::ParticlesSeek, value);
}); });
// Onboarding label contains instructions for new users how to get 3D content into the project // Onboarding label contains instructions for new users how to get 3D content into the project

View File

@@ -5,112 +5,66 @@
#include <utils/icon.h> #include <utils/icon.h>
#include <QMouseEvent>
#include <QStyleOption> #include <QStyleOption>
#include <QSlider> #include <QSlider>
#include <QDebug>
#include <QPainter> #include <QPainter>
namespace QmlDesigner { namespace QmlDesigner {
SeekerSlider::SeekerSlider(QWidget *parentWidget) SeekerSlider::SeekerSlider(QWidget *parent)
: QWidget(parentWidget), : QSlider(parent)
m_bgIcon(QLatin1String(":/icon/layout/scrubbg.png"))
{ {
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", true);
setProperty("panelwidget_singlerow", 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); return maximum();
}
void SeekerSlider::setMaxValue(int maxValue)
{ {
QStyleOptionToolBar option; maxValue = std::abs(maxValue);
option.rect = rect(); setRange(-maxValue, +maxValue);
option.state = QStyle::State_Horizontal;
style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this);
}
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::mousePressEvent(QMouseEvent *event) void SeekerSlider::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() != Qt::LeftButton) { if (event->button() != Qt::LeftButton)
QWidget::mousePressEvent(event);
return; return;
}
int x = rect().width() / 2; QStyleOptionSlider os;
int y = rect().height() / 2; initStyleOption(&os);
auto pos = event->localPos(); QRect handleRect = style()->subControlRect(QStyle::CC_Slider, &os, QStyle::SC_SliderHandle, this);
if (pos.x() >= x - m_handleWidth / 2 && pos.x() <= x + m_handleWidth / 2 m_moving = handleRect.contains(event->localPos().toPoint());
&& pos.y() >= y - m_handleHeight / 2 && pos.y() <= y + m_handleHeight / 2) { if (m_moving)
m_moving = true; QSlider::mousePressEvent(event);
m_startPos = pos.x(); else
} event->setAccepted(false);
} }
void SeekerSlider::mouseMoveEvent(QMouseEvent *event) void SeekerSlider::mouseMoveEvent(QMouseEvent *event)
{ {
if (!m_moving) { if (!m_moving)
QWidget::mouseMoveEvent(event);
return; return;
}
auto pos = event->localPos(); QSlider::mouseMoveEvent(event);
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();
}
} }
void SeekerSlider::mouseReleaseEvent(QMouseEvent *event) void SeekerSlider::mouseReleaseEvent(QMouseEvent *event)
{ {
if (!m_moving) { if (!m_moving)
QWidget::mouseReleaseEvent(event);
return; return;
}
setValue(0);
m_moving = false; m_moving = false;
m_position = 0; QSlider::mouseReleaseEvent(event);
m_startPos = 0;
m_sliderPos = 0;
Q_EMIT positionChanged();
update();
}
int SeekerSlider::position() const
{
return m_position;
} }
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -2,50 +2,30 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once #pragma once
#include <QWidget> #include <QSlider>
#include <QMouseEvent>
#include <QIcon>
namespace QmlDesigner { namespace QmlDesigner {
class SeekerSlider : public QSlider
class SeekerSlider : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
SeekerSlider(QWidget *parentWidget); explicit SeekerSlider(QWidget *parent = nullptr);
int position() const;
int maxPosition() const
{
return m_maxPosition;
}
void setMaxPosition(int pos) int maxValue() const;
{ void setMaxValue(int maxValue);
m_maxPosition = qMax(0, pos);
}
Q_SIGNALS:
void positionChanged();
protected: protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;
private: private:
int m_position = 0; using QSlider::setMinimum;
int m_startPos = 0; using QSlider::setMaximum;
int m_sliderPos = 0; using QSlider::setRange;
int m_sliderHalfWidth = 0;
int m_maxPosition = 30;
bool m_moving = false; bool m_moving = false;
int m_bgWidth;
int m_bgHeight;
int m_handleWidth;
int m_handleHeight;
QIcon m_bgIcon;
QIcon m_handleIcon;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -48,7 +48,7 @@ ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget)
m_rightToolBar->setOrientation(Qt::Horizontal); m_rightToolBar->setOrientation(Qt::Horizontal);
horizontalLayout->addWidget(m_leftToolBar); horizontalLayout->addWidget(m_leftToolBar);
horizontalLayout->addWidget(stretchToolbar); horizontalLayout->addWidget(stretchToolbar);
if (seeker) if (m_seeker)
horizontalLayout->addWidget(m_seeker); horizontalLayout->addWidget(m_seeker);
horizontalLayout->addWidget(m_rightToolBar); horizontalLayout->addWidget(m_rightToolBar);
} }

View File

@@ -429,6 +429,9 @@ void TimelineToolBar::createRightControls()
m_scale = new QSlider(this); m_scale = new QSlider(this);
m_scale->setOrientation(Qt::Horizontal); 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->setMaximumWidth(200);
m_scale->setMinimumWidth(100); m_scale->setMinimumWidth(100);
m_scale->setMinimum(0); m_scale->setMinimum(0);