QmlDesigner: Implement transient scrollbar for widgets in studiostyle

Task-number: QDS-9556
Task-number: QDS-10368
Task-number: QDS-10385
Change-Id: Idcbc70db3075f7741a754376580f48d7df40e67a
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Thomas Hartmann
2023-05-03 19:42:51 +02:00
committed by Ali Kianian
parent 98a28d30bc
commit c78e0965c0
24 changed files with 1631 additions and 364 deletions

View File

@@ -50,6 +50,7 @@ public:
DockAreaWidget *m_dockArea = nullptr;
QAction *m_toggleViewAction = nullptr;
bool m_closed = false;
bool m_focused = false;
QScrollArea *m_scrollArea = nullptr;
QToolBar *m_toolBar = nullptr;
Qt::ToolButtonStyle m_toolBarStyleDocked = Qt::ToolButtonIconOnly;
@@ -219,6 +220,7 @@ void DockWidgetPrivate::setupScrollArea()
m_scrollArea = new QScrollArea(q);
m_scrollArea->setObjectName("dockWidgetScrollArea");
m_scrollArea->setWidgetResizable(true);
m_scrollArea->setProperty("focused", q->isFocused());
m_layout->addWidget(m_scrollArea);
}
@@ -439,6 +441,21 @@ bool DockWidget::isClosed() const
return d->m_closed;
}
void DockWidget::setFocused(bool focused)
{
if (d->m_focused == focused)
return;
d->m_focused = focused;
if (d->m_scrollArea)
d->m_scrollArea->setProperty("focused", focused);
}
bool DockWidget::isFocused() const
{
return d->m_focused;
}
QAction *DockWidget::toggleViewAction() const
{
return d->m_toggleViewAction;

View File

@@ -32,6 +32,8 @@ class AutoHideSideBar;
class ADS_EXPORT DockWidget : public QFrame
{
Q_OBJECT
Q_PROPERTY(bool focused READ isFocused WRITE setFocused)
private:
DockWidgetPrivate *d; ///< private data (pimpl)
friend class DockWidgetPrivate;
@@ -367,6 +369,16 @@ public:
*/
bool isClosed() const;
/**
* Sets the focus property for widget
*/
void setFocused(bool focused);
/**
* Returns true if this dock widget is focused.
*/
bool isFocused() const;
/**
* Returns a checkable action that can be used to show or close this dock widget.
* The action's text is set to the dock widget's window title.

View File

@@ -5,12 +5,17 @@
#include "algorithm.h"
#include <QApplication>
#include <QEvent>
#include <QPainter>
#include <QStyleOption>
#include <QWidget>
using namespace Utils;
static const qreal ScrollBarFadeOutDuration = 200.0;
static const qreal ScrollBarFadeOutDelay = 450.0;
Animation * StyleAnimator::widgetAnimation(const QWidget *widget) const
{
if (!widget)
@@ -125,3 +130,187 @@ void StyleAnimator::startAnimation(Animation *t)
if (animations.size() > 0 && !animationTimer.isActive())
animationTimer.start(35, this);
}
QStyleAnimation::QStyleAnimation(QObject *target)
: QAbstractAnimation(target)
, m_delay(0)
, m_duration(-1)
, m_startTime(QTime::currentTime())
, m_fps(ThirtyFps)
, m_skip(0)
{}
QStyleAnimation::~QStyleAnimation() {}
QObject *QStyleAnimation::target() const
{
return parent();
}
int QStyleAnimation::duration() const
{
return m_duration;
}
void QStyleAnimation::setDuration(int duration)
{
m_duration = duration;
}
int QStyleAnimation::delay() const
{
return m_delay;
}
void QStyleAnimation::setDelay(int delay)
{
m_delay = delay;
}
QTime QStyleAnimation::startTime() const
{
return m_startTime;
}
void QStyleAnimation::setStartTime(const QTime &time)
{
m_startTime = time;
}
QStyleAnimation::FrameRate QStyleAnimation::frameRate() const
{
return m_fps;
}
void QStyleAnimation::setFrameRate(FrameRate fps)
{
m_fps = fps;
}
void QStyleAnimation::updateTarget()
{
QEvent event(QEvent::StyleAnimationUpdate);
event.setAccepted(false);
QCoreApplication::sendEvent(target(), &event);
if (!event.isAccepted())
stop();
}
void QStyleAnimation::start()
{
m_skip = 0;
QAbstractAnimation::start(DeleteWhenStopped);
}
bool QStyleAnimation::isUpdateNeeded() const
{
return currentTime() > m_delay;
}
void QStyleAnimation::updateCurrentTime(int)
{
if (++m_skip >= m_fps) {
m_skip = 0;
if (target() && isUpdateNeeded())
updateTarget();
}
}
QNumberStyleAnimation::QNumberStyleAnimation(QObject *target)
: QStyleAnimation(target)
, m_start(0.0)
, m_end(1.0)
, m_prev(0.0)
{
setDuration(250);
}
qreal QNumberStyleAnimation::startValue() const
{
return m_start;
}
void QNumberStyleAnimation::setStartValue(qreal value)
{
m_start = value;
}
qreal QNumberStyleAnimation::endValue() const
{
return m_end;
}
void QNumberStyleAnimation::setEndValue(qreal value)
{
m_end = value;
}
qreal QNumberStyleAnimation::currentValue() const
{
qreal step = qreal(currentTime() - delay()) / (duration() - delay());
return m_start + qMax(qreal(0), step) * (m_end - m_start);
}
bool QNumberStyleAnimation::isUpdateNeeded() const
{
if (QStyleAnimation::isUpdateNeeded()) {
qreal current = currentValue();
if (!qFuzzyCompare(m_prev, current)) {
m_prev = current;
return true;
}
}
return false;
}
QScrollbarStyleAnimation::QScrollbarStyleAnimation(Mode mode, QObject *target)
: QNumberStyleAnimation(target)
, m_mode(mode)
, m_active(false)
{
switch (mode) {
case Activating:
setDuration(ScrollBarFadeOutDuration);
setStartValue(0.0);
setEndValue(1.0);
break;
case Deactivating:
setDuration(ScrollBarFadeOutDelay + ScrollBarFadeOutDuration);
setDelay(ScrollBarFadeOutDelay);
setStartValue(1.0);
setEndValue(0.0);
break;
}
}
QScrollbarStyleAnimation::Mode QScrollbarStyleAnimation::mode() const
{
return m_mode;
}
bool QScrollbarStyleAnimation::wasActive() const
{
return m_active;
}
bool QScrollbarStyleAnimation::wasAdjacent() const
{
return m_adjacent;
}
void QScrollbarStyleAnimation::setActive(bool active)
{
m_active = active;
}
void QScrollbarStyleAnimation::setAdjacent(bool adjacent)
{
m_adjacent = adjacent;
}
void QScrollbarStyleAnimation::updateCurrentTime(int time)
{
QNumberStyleAnimation::updateCurrentTime(time);
if (m_mode == Deactivating && qFuzzyIsNull(currentValue()))
target()->setProperty("visible", false);
}

View File

@@ -5,6 +5,7 @@
#include "utils_global.h"
#include <QAbstractAnimation>
#include <QBasicTimer>
#include <QPointer>
#include <QTime>
@@ -13,6 +14,7 @@
QT_BEGIN_NAMESPACE
class QPainter;
class QStyleOption;
class QTimerEvent;
QT_END_NAMESPACE
namespace Utils {
@@ -76,4 +78,78 @@ private:
QBasicTimer animationTimer;
QList <Animation*> animations;
};
}
class QTCREATOR_UTILS_EXPORT QStyleAnimation : public QAbstractAnimation
{
Q_OBJECT
public:
QStyleAnimation(QObject *target);
virtual ~QStyleAnimation();
QObject *target() const;
int duration() const override;
void setDuration(int duration);
int delay() const;
void setDelay(int delay);
QTime startTime() const;
void setStartTime(const QTime &time);
enum FrameRate { DefaultFps, SixtyFps, ThirtyFps, TwentyFps, FifteenFps };
FrameRate frameRate() const;
void setFrameRate(FrameRate fps);
void updateTarget();
public Q_SLOTS:
void start();
protected:
virtual bool isUpdateNeeded() const;
virtual void updateCurrentTime(int time) override;
private:
int m_delay;
int m_duration;
QTime m_startTime;
FrameRate m_fps;
int m_skip;
};
class QTCREATOR_UTILS_EXPORT QNumberStyleAnimation : public QStyleAnimation
{
Q_OBJECT
public:
QNumberStyleAnimation(QObject *target);
qreal startValue() const;
void setStartValue(qreal value);
qreal endValue() const;
void setEndValue(qreal value);
qreal currentValue() const;
protected:
bool isUpdateNeeded() const override;
private:
qreal m_start;
qreal m_end;
mutable qreal m_prev;
};
class QTCREATOR_UTILS_EXPORT QScrollbarStyleAnimation : public QNumberStyleAnimation
{
Q_OBJECT
public:
enum Mode { Activating, Deactivating };
QScrollbarStyleAnimation(Mode mode, QObject *target);
Mode mode() const;
bool wasActive() const;
bool wasAdjacent() const;
void setActive(bool active);
void setAdjacent(bool adjacent);
private slots:
void updateCurrentTime(int time) override;
private:
Mode m_mode;
bool m_active;
bool m_adjacent;
};
} // namespace Utils

View File

@@ -12,6 +12,8 @@
using namespace Utils;
static constexpr char transientScrollAreaSupportName[] = "transientScrollAreSupport";
static constexpr char focusedPropertyName[] = "focused";
static constexpr char skipChildPropertyName[] = "qds_transient_skipChildArea";
class Utils::ScrollAreaPrivate
{
@@ -19,14 +21,23 @@ public:
ScrollAreaPrivate(QAbstractScrollArea *area)
: area(area)
{
verticalScrollBar = new ScrollBar(area);
area->setVerticalScrollBar(verticalScrollBar);
verticalScrollBar = dynamic_cast<ScrollBar *>(area->verticalScrollBar());
if (!verticalScrollBar) {
verticalScrollBar = new ScrollBar(area);
area->setVerticalScrollBar(verticalScrollBar);
}
horizontalScrollBar = new ScrollBar(area);
area->setHorizontalScrollBar(horizontalScrollBar);
horizontalScrollBar = dynamic_cast<ScrollBar *>(area->horizontalScrollBar());
if (!horizontalScrollBar) {
horizontalScrollBar = new ScrollBar(area);
area->setHorizontalScrollBar(horizontalScrollBar);
}
area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
if (area->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff)
area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
if (area->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff)
area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}
inline QRect scrollBarRect(ScrollBar *scrollBar)
@@ -40,15 +51,30 @@ public:
return rect.adjusted(0, mDiff, 0, mDiff);
}
}
inline QPointer<ScrollBar> adjacentScrollBar(QPointer<ScrollBar> scrollBar)
{
if (scrollBar == verticalScrollBar)
return horizontalScrollBar;
if (scrollBar == horizontalScrollBar)
return verticalScrollBar;
return {};
}
inline bool checkToFlashScroll(QPointer<ScrollBar> scrollBar, const QPoint &pos)
{
if (scrollBar.isNull())
return false;
if (!scrollBar->style()->styleHint(
QStyle::SH_ScrollBar_Transient,
nullptr, scrollBar))
if (!scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, scrollBar))
return false;
Qt::ScrollBarPolicy policy = (scrollBar->orientation() == Qt::Horizontal)
? area->horizontalScrollBarPolicy()
: area->verticalScrollBarPolicy();
if (policy == Qt::ScrollBarAlwaysOff)
return false;
if (scrollBarRect(scrollBar).contains(pos)) {
@@ -59,16 +85,120 @@ public:
return false;
}
inline bool setAdjacentHovered(QObject *w, bool setHovered)
{
if (!w)
return false;
QPointer<ScrollBar> scrollBar;
if (w == verticalScrollBar)
scrollBar = verticalScrollBar;
else if (w == horizontalScrollBar)
scrollBar = horizontalScrollBar;
if (!scrollBar)
return false;
QPointer<ScrollBar> adjacent = adjacentScrollBar(scrollBar);
if (!adjacent)
return false;
return adjacent->setAdjacentHovered(setHovered);
}
inline bool setAdjacentVisible(QObject *changedObject, bool setVisible)
{
if (!changedObject)
return false;
QPointer<ScrollBar> scrollBar;
if (changedObject == verticalScrollBar) {
scrollBar = verticalScrollBar;
} else if (changedObject == horizontalScrollBar) {
scrollBar = horizontalScrollBar;
} else if (changedObject == area) {
if (setVisible && verticalScrollBar && horizontalScrollBar) {
bool anyChange = false;
anyChange |= verticalScrollBar->setAdjacentVisible(horizontalScrollBar->isVisible());
anyChange |= horizontalScrollBar->setAdjacentVisible(verticalScrollBar->isVisible());
return anyChange;
}
}
if (!scrollBar)
return false;
QPointer<ScrollBar> adjacent = adjacentScrollBar(scrollBar);
if (!adjacent)
return false;
return adjacent->setAdjacentVisible(setVisible);
}
inline bool checkToFlashScroll(const QPoint &pos)
{
bool coversScroll = checkToFlashScroll(verticalScrollBar, pos);
if (!coversScroll)
coversScroll |= checkToFlashScroll(horizontalScrollBar, pos);
return coversScroll;
}
inline void installViewPort(QObject *eventHandler) {
inline bool canSetTransientProperty(QPointer<ScrollBar> scrollBar) const
{
if (scrollBar.isNull())
return false;
if (!scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, scrollBar))
return false;
Qt::ScrollBarPolicy policy = (scrollBar->orientation() == Qt::Horizontal)
? area->horizontalScrollBarPolicy()
: area->verticalScrollBarPolicy();
if (policy == Qt::ScrollBarAlwaysOff)
return false;
return true;
}
inline bool setFocus(QPointer<ScrollBar> scrollBar, const bool &focus)
{
if (!canSetTransientProperty(scrollBar))
return false;
return scrollBar->setFocused(focus);
}
inline bool setFocus(const bool &focus)
{
bool flashChanged = false;
flashChanged |= setFocus(verticalScrollBar, focus);
flashChanged |= setFocus(horizontalScrollBar, focus);
return flashChanged;
}
inline bool setViewPortIntraction(QPointer<ScrollBar> scrollBar, const bool &hovered)
{
if (!canSetTransientProperty(scrollBar))
return false;
return scrollBar->setViewPortInteraction(hovered);
}
inline bool setViewPortIntraction(const bool &hovered)
{
bool interactionChanged = false;
interactionChanged |= setViewPortIntraction(verticalScrollBar, hovered);
interactionChanged |= setViewPortIntraction(horizontalScrollBar, hovered);
return interactionChanged;
}
inline void installViewPort(QObject *eventHandler)
{
QWidget *viewPort = area->viewport();
if (viewPort
&& viewPort != this->viewPort
@@ -76,14 +206,30 @@ public:
&& (area->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff
|| area->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff)) {
viewPort->installEventFilter(eventHandler);
if (verticalScrollBar)
verticalScrollBar->installEventFilter(eventHandler);
if (horizontalScrollBar)
horizontalScrollBar->installEventFilter(eventHandler);
this->viewPort = viewPort;
setViewPortIntraction(true);
}
}
inline void uninstallViewPort(QObject *eventHandler) {
if (viewPort) {
viewPort->removeEventFilter(eventHandler);
if (verticalScrollBar)
verticalScrollBar->removeEventFilter(eventHandler);
if (horizontalScrollBar)
horizontalScrollBar->removeEventFilter(eventHandler);
this->viewPort = nullptr;
setViewPortIntraction(false);
}
}
@@ -111,6 +257,13 @@ void TransientScrollAreaSupport::support(QAbstractScrollArea *scrollArea)
);
}
void TransientScrollAreaSupport::supportWidget(QWidget *widget)
{
for (QAbstractScrollArea *area : widget->findChildren<QAbstractScrollArea *>()) {
support(area);
}
}
TransientScrollAreaSupport::~TransientScrollAreaSupport()
{
delete d;
@@ -122,23 +275,65 @@ bool TransientScrollAreaSupport::eventFilter(QObject *watched, QEvent *event)
case QEvent::Enter: {
if (watched == d->area)
d->installViewPort(this);
}
break;
} break;
case QEvent::Leave: {
if (watched == d->area)
d->uninstallViewPort(this);
}
break;
} break;
case QEvent::MouseMove: {
if (watched == d->viewPort){
if (watched == d->viewPort) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent) {
if (d->checkToFlashScroll(mouseEvent->pos()))
return true;
}
}
}
break;
} break;
case QEvent::HoverEnter:
case QEvent::HoverMove: {
QHoverEvent *hoverEvent = static_cast<QHoverEvent *>(event);
if (watched == d->horizontalScrollBar || watched == d->verticalScrollBar) {
if (hoverEvent)
d->setAdjacentHovered(watched, true);
}
} break;
case QEvent::HoverLeave: {
QHoverEvent *hoverEvent = static_cast<QHoverEvent *>(event);
if (watched == d->horizontalScrollBar || watched == d->verticalScrollBar) {
if (hoverEvent)
d->setAdjacentHovered(watched, false);
}
} break;
case QEvent::DynamicPropertyChange: {
if (watched == d->area) {
auto *pEvent = static_cast<QDynamicPropertyChangeEvent *>(event);
if (!pEvent || pEvent->propertyName() != focusedPropertyName)
break;
bool focused = d->area->property(focusedPropertyName).toBool();
d->setFocus(focused);
if (!d->area->property(skipChildPropertyName).toBool() && d->area->viewport()) {
const QList<QAbstractScrollArea *> scrollChildren
= d->area->viewport()->findChildren<QAbstractScrollArea *>();
for (QAbstractScrollArea *area : scrollChildren) {
area->setProperty(skipChildPropertyName, true);
area->setProperty(focusedPropertyName, focused);
area->setProperty(skipChildPropertyName, false);
}
}
}
} break;
case QEvent::Hide:
d->setAdjacentVisible(watched, false);
break;
case QEvent::Show:
d->setAdjacentVisible(watched, true);
break;
case QEvent::Resize: {
if (watched == d->area)
d->setAdjacentVisible(watched, true);
} break;
default:
break;
}
@@ -149,6 +344,12 @@ class Utils::ScrollBarPrivate {
public:
bool flashed = false;
int flashTimer = 0;
bool focused = false;
bool viewPortIntraction = false;
bool adjacentHovered = false;
bool adjacentVisible = false;
bool isHandleUnderCursor = false;
bool isGrooveUnderCursor = false;
};
ScrollBar::ScrollBar(QWidget *parent)
@@ -162,25 +363,6 @@ ScrollBar::~ScrollBar()
delete d;
}
QSize ScrollBar::sizeHint() const
{
QSize sh = QScrollBar::sizeHint();
if (style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
constexpr int thickness = 10;
if (orientation() == Qt::Horizontal)
sh.setHeight(thickness);
else
sh.setWidth(thickness);
} else {
constexpr int thickness = 12;
if (orientation() == Qt::Horizontal)
sh.setHeight(thickness);
else
sh.setWidth(thickness);
}
return sh;
}
void ScrollBar::flash()
{
if (!d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
@@ -197,14 +379,57 @@ void ScrollBar::flash()
void ScrollBar::initStyleOption(QStyleOptionSlider *option) const
{
QScrollBar::initStyleOption(option);
if (style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
if (d->flashed || d->focused || d->viewPortIntraction)
option->state |= QStyle::State_On;
if (d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this))
option->state |= QStyle::State_On;
if (d->isGrooveUnderCursor || d->isHandleUnderCursor || d->adjacentHovered)
option->subControls |= QStyle::SC_ScrollBarGroove;
option->styleObject->setProperty("adjacentScroll", d->adjacentHovered);
if (d->isHandleUnderCursor)
option->activeSubControls |= QStyle::SC_ScrollBarSlider;
if (d->adjacentVisible) {
int scrollExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, option, this);
if (option->orientation == Qt::Horizontal)
option->rect.adjust(0, 0, -scrollExtent, 0);
else
option->rect.adjust(0, 0, 0, -scrollExtent);
}
}
}
bool ScrollBar::event(QEvent *event)
{
switch (event->type()) {
case QEvent::HoverEnter:
case QEvent::HoverMove: {
QHoverEvent *hoverEvent = static_cast<QHoverEvent *>(event);
if (hoverEvent) {
QStyleOptionSlider option;
option.initFrom(this);
d->isHandleUnderCursor = style()
->subControlRect(QStyle::CC_ScrollBar,
&option,
QStyle::SC_ScrollBarSlider,
this)
.contains(hoverEvent->pos());
d->isGrooveUnderCursor = !d->isHandleUnderCursor
&& style()
->subControlRect(QStyle::CC_ScrollBar,
&option,
QStyle::SC_ScrollBarGroove,
this)
.contains(hoverEvent->pos());
}
} break;
case QEvent::HoverLeave:
d->isHandleUnderCursor = false;
d->isGrooveUnderCursor = false;
break;
case QEvent::Timer:
if (static_cast<QTimerEvent *>(event)->timerId() == d->flashTimer) {
if (d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
@@ -213,6 +438,7 @@ bool ScrollBar::event(QEvent *event)
}
killTimer(d->flashTimer);
d->flashTimer = 0;
return true;
}
break;
default:
@@ -220,3 +446,99 @@ bool ScrollBar::event(QEvent *event)
}
return QScrollBar::event(event);
}
bool ScrollBar::setFocused(const bool &focused)
{
if (d->focused == focused)
return false;
d->focused = focused;
if (d->focused)
flash();
else
update();
return true;
}
bool ScrollBar::setAdjacentVisible(const bool &visible)
{
if (d->adjacentVisible == visible)
return false;
d->adjacentVisible = visible;
update();
return true;
}
bool ScrollBar::setAdjacentHovered(const bool &hovered)
{
if (d->adjacentHovered == hovered)
return false;
d->adjacentHovered = hovered;
update();
return true;
}
bool ScrollBar::setViewPortInteraction(const bool &hovered)
{
if (d->viewPortIntraction == hovered)
return false;
d->viewPortIntraction = hovered;
if (d->viewPortIntraction)
flash();
else
update();
return true;
}
void GlobalTransientSupport::support(QWidget *widget)
{
if (!widget)
return;
widget->installEventFilter(instance());
QAbstractScrollArea *area = dynamic_cast<QAbstractScrollArea *>(widget);
if (area)
TransientScrollAreaSupport::support(area);
for (QWidget *childWidget : widget->findChildren<QWidget *>(Qt::FindChildOption::FindDirectChildrenOnly))
support(childWidget);
}
GlobalTransientSupport::GlobalTransientSupport()
: QObject(nullptr)
{}
GlobalTransientSupport *GlobalTransientSupport::instance()
{
static GlobalTransientSupport *gVal = nullptr;
if (!gVal)
gVal = new GlobalTransientSupport;
return gVal;
}
bool GlobalTransientSupport::eventFilter(QObject *watched, QEvent *event)
{
switch (event->type()) {
case QEvent::ChildAdded: {
QChildEvent *childEvent = static_cast<QChildEvent *>(event);
if (!childEvent || !childEvent->child() || !childEvent->child()->isWidgetType())
break;
QWidget *widget = dynamic_cast<QWidget *>(childEvent->child());
if (widget)
support(widget);
}
default:
break;
}
return QObject::eventFilter(watched, event);
}

View File

@@ -21,6 +21,7 @@ class QTCREATOR_UTILS_EXPORT TransientScrollAreaSupport : public QObject
Q_OBJECT
public:
static void support(QAbstractScrollArea *scrollArea);
static void supportWidget(QWidget *widget);
virtual ~TransientScrollAreaSupport();
protected:
@@ -35,20 +36,38 @@ private:
class QTCREATOR_UTILS_EXPORT ScrollBar : public QScrollBar
{
Q_OBJECT
friend class ScrollAreaPrivate;
public:
explicit ScrollBar(QWidget *parent = nullptr);
virtual ~ScrollBar();
QSize sizeHint() const override;
virtual void flash();
bool setFocused(const bool &focused);
protected:
virtual void initStyleOption(QStyleOptionSlider *option) const override;
void initStyleOption(QStyleOptionSlider *option) const override;
bool event(QEvent *event) override;
private:
bool setAdjacentVisible(const bool &visible);
bool setAdjacentHovered(const bool &hovered);
bool setViewPortInteraction(const bool &hovered);
ScrollBarPrivate *d = nullptr;
};
class QTCREATOR_UTILS_EXPORT GlobalTransientSupport : public QObject
{
Q_OBJECT
public:
static void support(QWidget *widget);
private:
GlobalTransientSupport();
static GlobalTransientSupport *instance();
virtual bool eventFilter(QObject *watched, QEvent *event) override;
};
}

View File

@@ -31,11 +31,10 @@ class HighlightScrollBarOverlay : public QWidget
public:
HighlightScrollBarOverlay(HighlightScrollBarController *scrollBarController)
: QWidget(scrollBarController->scrollArea())
, m_scrollBar(scrollBarController->scrollBar())
, m_highlightController(scrollBarController)
{
setAttribute(Qt::WA_TransparentForMouseEvents);
m_scrollBar->parentWidget()->installEventFilter(this);
scrollBar()->parentWidget()->installEventFilter(this);
doResize();
doMove();
show();
@@ -43,12 +42,12 @@ public:
void doResize()
{
resize(m_scrollBar->size());
resize(scrollBar()->size());
}
void doMove()
{
move(parentWidget()->mapFromGlobal(m_scrollBar->mapToGlobal(m_scrollBar->pos())));
move(parentWidget()->mapFromGlobal(scrollBar()->mapToGlobal(scrollBar()->pos())));
}
void scheduleUpdate();
@@ -71,7 +70,7 @@ private:
// line start to line end
QMap<Highlight::Priority, QMap<Utils::Theme::Color, QMap<int, int>>> m_highlightCache;
QScrollBar *m_scrollBar;
inline QScrollBar *scrollBar() const { return m_highlightController->scrollBar(); }
HighlightScrollBarController *m_highlightController;
bool m_isCacheUpdateScheduled = true;
};
@@ -115,8 +114,8 @@ void HighlightScrollBarOverlay::paintEvent(QPaintEvent *paintEvent)
gRect.width() + marginH,
gRect.height() - hRect.height() + gRect.y() - hRect.y());
const int aboveValue = m_scrollBar->value();
const int belowValue = m_scrollBar->maximum() - m_scrollBar->value();
const int aboveValue = scrollBar()->value();
const int belowValue = scrollBar()->maximum() - scrollBar()->value();
const int sizeDocAbove = int(aboveValue * m_highlightController->lineHeight());
const int sizeDocBelow = int(belowValue * m_highlightController->lineHeight());
const int sizeDocVisible = int(m_highlightController->visibleRange());
@@ -303,14 +302,14 @@ void HighlightScrollBarOverlay::updateCache()
QRect HighlightScrollBarOverlay::overlayRect() const
{
QStyleOptionSlider opt = qt_qscrollbarStyleOption(m_scrollBar);
return m_scrollBar->style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, m_scrollBar);
QStyleOptionSlider opt = qt_qscrollbarStyleOption(scrollBar());
return scrollBar()->style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar());
}
QRect HighlightScrollBarOverlay::handleRect() const
{
QStyleOptionSlider opt = qt_qscrollbarStyleOption(m_scrollBar);
return m_scrollBar->style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, m_scrollBar);
QStyleOptionSlider opt = qt_qscrollbarStyleOption(scrollBar());
return scrollBar()->style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar());
}

View File

@@ -80,7 +80,6 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
ui->tabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
QByteArray sheet = Utils::FileReader::fetchQrc(":/connectionview/stylesheet.css");
sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
connect(ui->tabBar, &QTabBar::currentChanged,

View File

@@ -87,11 +87,6 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
applyZoom(m_zoomX, m_zoomY);
update();
const QString css = Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
horizontalScrollBar()->setStyleSheet(css);
verticalScrollBar()->setStyleSheet(css);
}
GraphicsView::~GraphicsView()

View File

@@ -74,7 +74,6 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view)
setAcceptDrops(true);
QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
Core::Context context(Constants::C_QMLEDITOR3D);

View File

@@ -291,7 +291,6 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view)
fillLayout->addWidget(m_graphicsView.data());
QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
}

View File

@@ -10,6 +10,8 @@
#include "qproxystyle.h"
#include "previewtooltip.h"
#include <qmldesignerbase/studio/studiostyle.h>
#include <metainfo.h>
#include <theme.h>
@@ -35,7 +37,8 @@ namespace {
class TableViewStyle : public QProxyStyle
{
public:
TableViewStyle(QObject *parent) : QProxyStyle(QStyleFactory::create("fusion"))
TableViewStyle(QObject *parent)
: QProxyStyle(new StudioStyle("fusion"))
{
setParent(parent);
baseStyle()->setParent(parent);

View File

@@ -62,7 +62,6 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
setWindowTitle(tr("Navigator", "Title of navigator view"));
QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_NAVIGATORVIEW_TIME);

View File

@@ -70,11 +70,6 @@ void TextEditorWidget::setTextEditor(Utils::UniqueObjectLatePtr<TextEditor::Base
});
m_textEditor->editorWidget()->installEventFilter(this);
static QString styleSheet = Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
m_textEditor->editorWidget()->verticalScrollBar()->setStyleSheet(styleSheet);
m_textEditor->editorWidget()->horizontalScrollBar()->setStyleSheet(styleSheet);
}
}

View File

@@ -24,6 +24,7 @@
#include <theme.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/transientscroll.h>
#include <QApplication>
#include <QComboBox>
@@ -97,7 +98,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
, m_toolbar(new TimelineToolBar(this))
, m_rulerView(new QGraphicsView(this))
, m_graphicsView(new QGraphicsView(this))
, m_scrollbar(new QScrollBar(this))
, m_scrollbar(new Utils::ScrollBar(this))
, m_statusBar(new QLabel(this))
, m_timelineView(view)
, m_graphicsScene(new TimelineGraphicsScene(this, view->externalDependencies()))
@@ -112,11 +113,6 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_toolbar->setStyleSheet(Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
const QString css = Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
m_scrollbar->setStyleSheet(css);
m_scrollbar->setOrientation(Qt::Horizontal);
QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Preferred);
@@ -129,7 +125,6 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_rulerView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
m_rulerView->viewport()->installEventFilter(new Eventfilter(this));
m_rulerView->viewport()->setFocusPolicy(Qt::NoFocus);
m_rulerView->setStyleSheet(css);
m_rulerView->setFrameShape(QFrame::NoFrame);
m_rulerView->setFrameShadow(QFrame::Plain);
m_rulerView->setLineWidth(0);
@@ -137,12 +132,11 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_rulerView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_rulerView->setScene(graphicsScene());
m_graphicsView->setStyleSheet(css);
m_graphicsView->setObjectName("SceneView");
m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setFrameShadow(QFrame::Plain);
m_graphicsView->setLineWidth(0);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_graphicsView->setSizePolicy(sizePolicy1);
@@ -286,6 +280,8 @@ TimelineWidget::TimelineWidget(TimelineView *view)
auto onFinish = [this]() { graphicsScene()->setCurrentFrame(m_playbackAnimation->startValue().toInt()); };
connect(m_playbackAnimation, &QVariantAnimation::finished, onFinish);
TimeLineNS::TimelineScrollAreaSupport::support(m_graphicsView, m_scrollbar);
}
void TimelineWidget::connectToolbar()
@@ -541,11 +537,11 @@ void TimelineWidget::invalidateTimelinePosition(const QmlTimeline &timeline)
void TimelineWidget::setupScrollbar(int min, int max, int current)
{
bool b = m_scrollbar->blockSignals(true);
m_scrollbar->setMinimum(min);
m_scrollbar->setMaximum(max);
m_scrollbar->setRange(min, max);
m_scrollbar->setValue(current);
m_scrollbar->setSingleStep((max - min) / 10);
m_scrollbar->blockSignals(b);
m_scrollbar->flash();
}
void TimelineWidget::setTimelineId(const QString &id)
@@ -634,4 +630,145 @@ TimelineView *TimelineWidget::timelineView() const
return m_timelineView;
}
namespace TimeLineNS {
using ScrollBar = Utils::ScrollBar;
static constexpr char timelineScrollAreaSupportName[] = "timelinetransientScrollAreSupport";
static constexpr char focusedPropertyName[] = "focused";
class TimelineScrollAreaPrivate
{
public:
TimelineScrollAreaPrivate(QAbstractScrollArea *area, ScrollBar *scrollbar)
: area(area)
, scrollbar(scrollbar)
{}
inline QRect scrollBarRect(ScrollBar *scrollBar)
{
QRect rect = viewPort ? viewPort->rect() : area->rect();
if (scrollBar->orientation() == Qt::Vertical) {
int mDiff = rect.width() - scrollBar->sizeHint().width();
return rect.adjusted(mDiff, 0, mDiff, 0);
} else {
int mDiff = rect.height() - scrollBar->sizeHint().height();
return rect.adjusted(0, mDiff, 0, mDiff);
}
}
inline bool checkToFlashScroll(QPointer<ScrollBar> scrollBar, const QPoint &pos)
{
if (scrollBar.isNull())
return false;
if (!scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, scrollBar))
return false;
if (scrollBarRect(scrollBar).contains(pos)) {
scrollBar->flash();
return true;
}
return false;
}
inline bool checkToFlashScroll(const QPoint &pos)
{
bool coversScroll = checkToFlashScroll(scrollbar, pos);
return coversScroll;
}
inline bool setFocus(const bool &focus)
{
if (scrollbar.isNull())
return false;
if (!scrollbar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, scrollbar))
return false;
return scrollbar->setFocused(focus);
}
inline void installViewPort(QObject *eventHandler)
{
QWidget *viewPort = area->viewport();
if (viewPort && viewPort != this->viewPort
&& viewPort->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, viewPort)) {
viewPort->installEventFilter(eventHandler);
this->viewPort = viewPort;
}
}
inline void uninstallViewPort(QObject *eventHandler)
{
if (viewPort) {
viewPort->removeEventFilter(eventHandler);
this->viewPort = nullptr;
}
}
QAbstractScrollArea *area = nullptr;
QPointer<QWidget> viewPort = nullptr;
QPointer<ScrollBar> scrollbar;
};
TimelineScrollAreaSupport::TimelineScrollAreaSupport(QAbstractScrollArea *scrollArea,
Utils::ScrollBar *scrollbar)
: QObject(scrollArea)
, d(new TimelineScrollAreaPrivate(scrollArea, scrollbar))
{
scrollArea->installEventFilter(this);
}
void TimelineScrollAreaSupport::support(QAbstractScrollArea *scrollArea, Utils::ScrollBar *scrollbar)
{
QObject *prevSupport = scrollArea->property(timelineScrollAreaSupportName).value<QObject *>();
if (!prevSupport)
scrollArea->setProperty(timelineScrollAreaSupportName,
QVariant::fromValue(
new TimelineScrollAreaSupport(scrollArea, scrollbar)));
}
TimelineScrollAreaSupport::~TimelineScrollAreaSupport()
{
delete d;
}
bool TimelineScrollAreaSupport::eventFilter(QObject *watched, QEvent *event)
{
switch (event->type()) {
case QEvent::Enter: {
if (watched == d->area)
d->installViewPort(this);
} break;
case QEvent::Leave: {
if (watched == d->area)
d->uninstallViewPort(this);
} break;
case QEvent::MouseMove: {
if (watched == d->viewPort) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent) {
if (d->checkToFlashScroll(mouseEvent->pos()))
return true;
}
}
} break;
case QEvent::DynamicPropertyChange: {
if (watched == d->area) {
auto *pEvent = static_cast<QDynamicPropertyChangeEvent *>(event);
if (!pEvent || pEvent->propertyName() != focusedPropertyName)
break;
bool focused = d->area->property(focusedPropertyName).toBool();
d->setFocus(focused);
}
} break;
default:
break;
}
return QObject::eventFilter(watched, event);
}
} // namespace TimeLineNS
} // namespace QmlDesigner

View File

@@ -19,15 +19,44 @@ QT_FORWARD_DECLARE_CLASS(QString)
QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_FORWARD_DECLARE_CLASS(QVariantAnimation)
QT_FORWARD_DECLARE_CLASS(QScrollBar)
QT_FORWARD_DECLARE_CLASS(QAbstractScrollArea)
namespace Utils {
QT_FORWARD_DECLARE_CLASS(ScrollBar)
}
namespace QmlDesigner {
class TimelineToolBar;
class TimelineView;
class TimelineGraphicsScene;
class TimelineWidget;
class QmlTimeline;
class Navigation2dScrollBar;
namespace TimeLineNS {
class TimelineScrollAreaPrivate;
class ScrollBarPrivate;
class TimelineScrollAreaSupport : public QObject
{
Q_OBJECT
public:
static void support(QAbstractScrollArea *scrollArea, Utils::ScrollBar *scrollbar);
virtual ~TimelineScrollAreaSupport();
protected:
virtual bool eventFilter(QObject *watched, QEvent *event) override;
private:
explicit TimelineScrollAreaSupport(QAbstractScrollArea *scrollArea, Utils::ScrollBar *scrollbar);
TimelineScrollAreaPrivate *d = nullptr;
};
} // namespace TimeLineNS
class TimelineWidget : public QWidget
{
Q_OBJECT
@@ -76,7 +105,7 @@ private:
QGraphicsView *m_graphicsView = nullptr;
QScrollBar *m_scrollbar = nullptr;
Utils::ScrollBar *m_scrollbar = nullptr;
QLabel *m_statusBar = nullptr;

View File

@@ -82,7 +82,7 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
, m_toolbar(new TransitionEditorToolBar(this))
, m_rulerView(new QGraphicsView(this))
, m_graphicsView(new QGraphicsView(this))
, m_scrollbar(new QScrollBar(this))
, m_scrollbar(new Utils::ScrollBar(this))
, m_statusBar(new QLabel(this))
, m_transitionEditorView(view)
, m_graphicsScene(new TransitionEditorGraphicsScene(this))
@@ -94,11 +94,6 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_toolbar->setStyleSheet(Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
const QString css = Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
m_scrollbar->setStyleSheet(css);
m_scrollbar->setOrientation(Qt::Horizontal);
QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Preferred);
@@ -111,7 +106,6 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_rulerView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
m_rulerView->viewport()->installEventFilter(new Eventfilter(this));
m_rulerView->viewport()->setFocusPolicy(Qt::NoFocus);
m_rulerView->setStyleSheet(css);
m_rulerView->setFrameShape(QFrame::NoFrame);
m_rulerView->setFrameShadow(QFrame::Plain);
m_rulerView->setLineWidth(0);
@@ -119,7 +113,6 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_rulerView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_rulerView->setScene(graphicsScene());
m_graphicsView->setStyleSheet(css);
m_graphicsView->setObjectName("SceneView");
m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setFrameShadow(QFrame::Plain);

View File

@@ -7,6 +7,8 @@
#include <coreplugin/icontext.h>
#include <utils/transientscroll.h>
#include <QWidget>
#include <functional>
@@ -75,7 +77,7 @@ private:
QGraphicsView *m_graphicsView = nullptr;
QScrollBar *m_scrollbar = nullptr;
Utils::ScrollBar *m_scrollbar = nullptr;
QLabel *m_statusBar = nullptr;

View File

@@ -38,6 +38,7 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <utils/transientscroll.h>
#include <QActionGroup>
#include <QApplication>
@@ -125,7 +126,6 @@ QWidget *DesignModeWidget::createProjectExplorerWidget(QWidget *parent)
if (navigationView.widget) {
QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
sheet += "QLabel { background-color: #4f4f4f; }";
navigationView.widget->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
navigationView.widget->setParent(parent);
@@ -190,7 +190,6 @@ void DesignModeWidget::setup()
Core::ICore::resourcePath("qmldesigner/workspacePresets/").toString());
QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css"));
sheet += QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css"));
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
// Setup icons
@@ -300,7 +299,6 @@ void DesignModeWidget::setup()
// Apply stylesheet to QWidget
QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
sheet += "QLabel { background-color: creatorTheme.DSsectionHeadBackground; }";
navigationView.widget->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
@@ -428,6 +426,8 @@ void DesignModeWidget::setup()
setupNavigatorHistory(currentDesignDocument()->textEditor());
m_dockManager->initialize();
if (style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this))
Utils::GlobalTransientSupport::support(m_dockManager);
// Hide all floating widgets if the initial mode isn't design mode
if (Core::ModeManager::instance()->currentModeId() != Core::Constants::MODE_DESIGN) {

View File

@@ -36,6 +36,7 @@ extend_qtc_plugin(QmlDesignerBase
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/studio
SOURCES
studiostyle.cpp studiostyle.h
studiostyle_p.cpp studiostyle_p.h
studioquickwidget.cpp studioquickwidget.h
studiosettingspage.cpp studiosettingspage.h
)

View File

@@ -1,7 +1,10 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "studiostyle.h"
#include "studiostyle_p.h"
#include <utils/hostosinfo.h>
#include <utils/styleanimator.h>
#include <utils/stylehelper.h>
#include <utils/theme/theme.h>
@@ -9,7 +12,9 @@
#include <QPainter>
#include <QStyleOption>
#define ANIMATE_SCROLLBARS QT_CONFIG(animation)
using namespace Utils;
using namespace QmlDesigner;
namespace {
@@ -65,6 +70,17 @@ inline QColor studioButtonOutlineColor(bool enabled,
return creatorTheme()->color(themePenColorId);
}
inline bool anyParentsFocused(const QWidget *widget)
{
const QWidget *p = widget;
while (p) {
if (p->property("focused").toBool())
return true;
p = p->parentWidget();
}
return false;
}
bool styleEnabled(const QWidget *widget)
{
const QWidget *p = widget;
@@ -93,221 +109,43 @@ bool isQmlEditorMenu(const QWidget *widget)
return false;
}
QPixmap getPixmapFromIcon(const QIcon &icon, const QSize &size, bool enabled, bool active, bool checked)
inline QPixmap getPixmapFromIcon(
const QIcon &icon, const QSize &size, bool enabled, bool active, bool checked)
{
QIcon::Mode mode = enabled ? ((active) ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
QIcon::State state = (checked) ? QIcon::On : QIcon::Off;
return icon.pixmap(size, mode, state);
}
struct StudioShortcut {
StudioShortcut(const QStyleOptionMenuItem *option,
const QString &shortcutText)
: shortcutText(shortcutText)
, enabled(option->state & QStyle::State_Enabled)
, active(option->state & QStyle::State_Selected)
, font(option->font)
, fm(font)
, defaultHeight(fm.height())
, spaceConst(fm.boundingRect(".").width())
{
reset();
if (backspaceMatch(shortcutText).hasMatch())
backspaceIcon = option->styleObject->property("backspaceIcon").value<QIcon>();
}
QSize getSize()
{
if (isFirstParticle)
calcResult();
return _size;
}
QPixmap getPixmap()
{
if (!isFirstParticle && !_pixmap.isNull())
return _pixmap;
_pixmap = QPixmap(getSize());
_pixmap.fill(Qt::transparent);
QPainter painter(&_pixmap);
painter.setFont(font);
QPen pPen = painter.pen();
pPen.setColor(studioTextColor(enabled, active, false));
painter.setPen(pPen);
calcResult(&painter);
painter.end();
return _pixmap;
}
private:
void applySize(const QSize &itemSize) {
width += itemSize.width();
height = std::max(height, itemSize.height());
if (isFirstParticle)
isFirstParticle = false;
else
width += spaceConst;
};
void addText(const QString &txt, QPainter *painter = nullptr)
{
if (txt.size()) {
int textWidth = fm.horizontalAdvance(txt);
QSize itemSize = {textWidth, defaultHeight};
if (painter) {
static const QTextOption textOption(Qt::AlignLeft | Qt::AlignVCenter);
QRect placeRect({width, 0}, itemSize);
painter->drawText(placeRect, txt, textOption);
}
applySize(itemSize);
}
};
void addPixmap(const QPixmap &pixmap, QPainter *painter = nullptr)
{
if (painter)
painter->drawPixmap(QRect({width, 0}, pixmap.size()), pixmap);
applySize(pixmap.size());
};
void calcResult(QPainter *painter = nullptr)
{
reset();
#ifndef QT_NO_SHORTCUT
if (!shortcutText.isEmpty()) {
int fwdIndex = 0;
QRegularExpressionMatch mMatch = backspaceMatch(shortcutText);
int matchCount = mMatch.lastCapturedIndex();
for (int i = 0; i <= matchCount; ++i) {
QString mStr = mMatch.captured(i);
QSize iconSize(defaultHeight * 3, defaultHeight);
const QList<QSize> iconSizes = backspaceIcon.availableSizes();
if (iconSizes.size())
iconSize = iconSizes.last();
double aspectRatio = (defaultHeight + .0) / iconSize.height();
int newWidth = iconSize.width() * aspectRatio;
QPixmap pixmap = getPixmapFromIcon(backspaceIcon,
{newWidth, defaultHeight},
enabled, active, false);
int lIndex = shortcutText.indexOf(mStr, fwdIndex);
int diffChars = lIndex - fwdIndex;
addText(shortcutText.mid(fwdIndex, diffChars), painter);
addPixmap(pixmap, painter);
fwdIndex = lIndex + mStr.size();
}
addText(shortcutText.mid(fwdIndex), painter);
}
#endif
_size = {width, height};
}
void reset()
{
isFirstParticle = true;
width = 0;
height = 0;
}
inline QRegularExpressionMatch backspaceMatch(const QString &str) const
{
static const QRegularExpression backspaceDetect(
"\\+*backspace\\+*",
QRegularExpression::CaseInsensitiveOption);
return backspaceDetect.match(str);
}
const QString shortcutText;
const bool enabled;
const bool active;
const QFont font;
const QFontMetrics fm;
const int defaultHeight;
const int spaceConst;
QIcon backspaceIcon;
bool isFirstParticle = true;
int width = 0;
int height = 0;
QSize _size;
QPixmap _pixmap;
};
} // blank namespace
class StudioStylePrivate
inline QRect expandScrollRect(const QRect &ref,
const qreal &factor,
const Qt::Orientation &orientation)
{
public:
explicit StudioStylePrivate();
if (qFuzzyCompare(factor, 1))
return ref;
public:
QPalette stdPalette;
};
StudioStylePrivate::StudioStylePrivate()
{
auto color = [] (Theme::Color c) {
return creatorTheme()->color(c);
};
{
stdPalette.setColorGroup(
QPalette::Disabled, // group
color(Theme::DStextColorDisabled), // windowText
color(Theme::DScontrolBackgroundDisabled), // button
color(Theme::DScontrolOutlineDisabled), // light
color(Theme::DStextSelectedTextColor), // dark
color(Theme::DSstatusbarBackground), // mid
color(Theme::DStextColorDisabled), // text
color(Theme::DStextColorDisabled), // brightText
color(Theme::DStoolbarIcon_blocked), // base
color(Theme::DStoolbarIcon_blocked) // window
);
stdPalette.setColorGroup(
QPalette::Inactive, // group
color(Theme::DStextColor), // windowText
color(Theme::DScontrolBackground), // button
color(Theme::DStoolbarBackground), // light
color(Theme::DSstatusbarBackground), // dark
color(Theme::DScontrolBackground), // mid
color(Theme::DStextColor), // text
color(Theme::DStextColor), // brightText
color(Theme::DStoolbarBackground), // base
color(Theme::DStoolbarBackground) // window
);
stdPalette.setColorGroup(
QPalette::Active, // group
color(Theme::DStextSelectedTextColor), // windowText
color(Theme::DSnavigatorItemBackgroundHover), // button
color(Theme::DSstateBackgroundColor_hover), // light
color(Theme::DSpanelBackground), // dark
color(Theme::DSnavigatorItemBackgroundHover), // mid
color(Theme::DStextSelectedTextColor), // text
color(Theme::DStextSelectedTextColor), // brightText
color(Theme::DStoolbarBackground), // base
color(Theme::DStoolbarBackground) // window
);
if (orientation == Qt::Horizontal) {
qreal newExp = ref.height() * factor;
qreal newDiff = ref.height() - newExp;
return ref.adjusted(0, newDiff, 0, 0);
} else {
qreal newExp = ref.width() * factor;
qreal newDiff = ref.width() - newExp;
return ref.adjusted(newDiff, 0, 0, 0);
}
}
} // namespace
StudioStyle::StudioStyle(QStyle *style)
: QProxyStyle(style)
, d(new StudioStylePrivate)
, d(new StudioStylePrivate(this))
{
}
StudioStyle::StudioStyle(const QString &key)
: QProxyStyle(key)
, d(new StudioStylePrivate)
, d(new StudioStylePrivate(this))
{
}
@@ -358,8 +196,7 @@ void StudioStyle::drawPrimitive(
if (!isQmlEditorMenu(widget))
Super::drawPrimitive(element, option, painter, widget);
break;
case PE_FrameDefaultButton:
{
case PE_FrameDefaultButton: {
if (const auto button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
bool enabled = button->state & QStyle::State_Enabled;
bool hovered = enabled && button->state & QStyle::State_MouseOver;
@@ -385,30 +222,29 @@ void StudioStyle::drawPrimitive(
painter->restore();
}
}
break;
} break;
case PE_IndicatorToolBarSeparator:
{
case PE_IndicatorToolBarSeparator: {
bool horizontal = option->state & State_Horizontal;
int thickness = pixelMetric(PM_ToolBarSeparatorExtent, option, widget);
QRect colorRect;
if (horizontal) {
colorRect = {option->rect.center().x() - thickness / 2 , option->rect.top() + 2,
thickness , option->rect.height() - 4};
colorRect = {option->rect.center().x() - thickness / 2,
option->rect.top() + 2,
thickness,
option->rect.height() - 4};
} else {
colorRect = {option->rect.left() + 2, option->rect.center().y() - thickness / 2,
option->rect.width() - 4, thickness};
colorRect = {option->rect.left() + 2,
option->rect.center().y() - thickness / 2,
option->rect.width() - 4,
thickness};
}
// The separator color is currently the same as toolbar bg
painter->fillRect(colorRect,
creatorTheme()->color(Theme::DStoolbarBackground));
}
break;
painter->fillRect(colorRect, creatorTheme()->color(Theme::DStoolbarBackground));
} break;
default:
{
default: {
Super::drawPrimitive(element, option, painter, widget);
break;
}
@@ -452,7 +288,7 @@ void StudioStyle::drawControl(
if (item.menuItemType == QStyleOptionMenuItem::Separator) {
int commonHeight = item.rect.center().y();
int additionalMargin = forwardX /*hmargin*/;
int additionalMargin = forwardX;
QLineF separatorLine (item.rect.left() + additionalMargin,
commonHeight,
item.rect.right() - additionalMargin,
@@ -764,6 +600,295 @@ void StudioStyle::drawComplexControl(
}
Super::drawComplexControl(control, option, painter, widget);
} break;
#if QT_CONFIG(slider)
case CC_ScrollBar: {
painter->save();
if (const QStyleOptionSlider *scrollBar = qstyleoption_cast<const QStyleOptionSlider *>(
option)) {
bool wasActive = false;
bool wasAdjacent = false;
bool isFocused = anyParentsFocused(widget);
bool isAdjacent = false;
qreal scaleCoFactor = 1.0;
QObject *styleObject = option->styleObject;
bool hasTransientStyle = proxy()->styleHint(SH_ScrollBar_Transient, option, widget);
if (styleObject && hasTransientStyle) {
#if ANIMATE_SCROLLBARS
qreal opacity = 0.0;
bool shouldExpand = false;
const qreal minExpandScale = 0.7;
const qreal maxExpandScale = 1.0;
#endif
isAdjacent = styleObject->property("adjacentScroll").toBool();
int oldPos = styleObject->property("_qdss_stylepos").toInt();
int oldMin = styleObject->property("_qdss_stylemin").toInt();
int oldMax = styleObject->property("_qdss_stylemax").toInt();
QRect oldRect = styleObject->property("_qdss_stylerect").toRect();
QStyle::State oldState = static_cast<QStyle::State>(
qvariant_cast<QStyle::State::Int>(styleObject->property("_qdss_stylestate")));
uint oldActiveControls = styleObject->property("_qdss_stylecontrols").toUInt();
bool oldFocus = styleObject->property("_qdss_focused").toBool();
bool oldAdjacent = styleObject->property("_qdss_adjacentScroll").toBool();
// a scrollbar is transient when the scrollbar itself and
// its sibling are both inactive (ie. not pressed/hovered/moved)
bool transient = !option->activeSubControls && !(option->state & State_On);
if (!transient || oldPos != scrollBar->sliderPosition
|| oldMin != scrollBar->minimum || oldMax != scrollBar->maximum
|| oldRect != scrollBar->rect || oldState != scrollBar->state
|| oldActiveControls != scrollBar->activeSubControls || oldFocus != isFocused
|| oldAdjacent != isAdjacent) {
styleObject->setProperty("_qdss_stylepos", scrollBar->sliderPosition);
styleObject->setProperty("_qdss_stylemin", scrollBar->minimum);
styleObject->setProperty("_qdss_stylemax", scrollBar->maximum);
styleObject->setProperty("_qdss_stylerect", scrollBar->rect);
styleObject->setProperty("_qdss_stylestate",
static_cast<QStyle::State::Int>(scrollBar->state));
styleObject->setProperty("_qdss_stylecontrols",
static_cast<uint>(scrollBar->activeSubControls));
styleObject->setProperty("_qdss_focused", isFocused);
styleObject->setProperty("_qdss_adjacentScroll", isAdjacent);
#if ANIMATE_SCROLLBARS
// if the scrollbar is transient or its attributes, geometry or
// state has changed, the opacity is reset back to 100% opaque
opacity = 1.0;
QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(
d->animation(styleObject));
if (transient) {
if (anim && anim->mode() != QScrollbarStyleAnimation::Deactivating) {
d->stopAnimation(styleObject);
anim = nullptr;
}
if (!anim) {
anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating,
styleObject);
d->startAnimation(anim);
} else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
// the scrollbar was already fading out while the
// state changed -> restart the fade out animation
anim->setCurrentTime(0);
}
} else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
d->stopAnimation(styleObject);
}
#endif // animation
}
#if ANIMATE_SCROLLBARS
QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(
d->animation(styleObject));
if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
// once a scrollbar was active (hovered/pressed), it retains
// the active look even if it's no longer active while fading out
if (oldActiveControls)
anim->setActive(true);
if (oldAdjacent)
anim->setAdjacent(true);
wasActive = anim->wasActive();
wasAdjacent = anim->wasAdjacent();
opacity = anim->currentValue();
}
shouldExpand = (option->activeSubControls || wasActive);
if (shouldExpand) {
if (!anim && !oldActiveControls) {
// Start expand animation only once and when entering
anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating,
styleObject);
d->startAnimation(anim);
}
if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
scaleCoFactor = (1.0 - anim->currentValue()) * minExpandScale
+ anim->currentValue() * maxExpandScale;
} else {
// Keep expanded state after the animation ends, and when fading out
scaleCoFactor = maxExpandScale;
}
}
painter->setOpacity(opacity);
#endif // animation
}
bool horizontal = scrollBar->orientation == Qt::Horizontal;
bool sunken = scrollBar->state & State_Sunken;
QRect scrollBarSubLine = proxy()->subControlRect(control,
scrollBar,
SC_ScrollBarSubLine,
widget);
QRect scrollBarAddLine = proxy()->subControlRect(control,
scrollBar,
SC_ScrollBarAddLine,
widget);
QRect scrollBarSlider = proxy()->subControlRect(control,
scrollBar,
SC_ScrollBarSlider,
widget);
QRect scrollBarGroove = proxy()->subControlRect(control,
scrollBar,
SC_ScrollBarGroove,
widget);
QRect rect = option->rect;
QColor alphaOutline = StyleHelper::borderColor();
alphaOutline.setAlpha(180);
QColor arrowColor = option->palette.windowText().color();
arrowColor.setAlpha(160);
bool enabled = scrollBar->state & QStyle::State_Enabled;
bool hovered = enabled && scrollBar->state & QStyle::State_MouseOver;
QColor buttonColor = hovered ? "#D9D9D9" : "#9B9B9B";
QColor gradientStartColor = buttonColor.lighter(118);
QColor gradientStopColor = buttonColor;
if (hasTransientStyle) {
rect = expandScrollRect(rect, scaleCoFactor, scrollBar->orientation);
scrollBarSlider = expandScrollRect(scrollBarSlider,
scaleCoFactor,
scrollBar->orientation);
scrollBarGroove = expandScrollRect(scrollBarGroove,
scaleCoFactor,
scrollBar->orientation);
}
// Paint groove
if ((!hasTransientStyle || scrollBar->activeSubControls || wasActive || isAdjacent
|| wasAdjacent)
&& scrollBar->subControls & SC_ScrollBarGroove) {
painter->save();
painter->setPen(Qt::NoPen);
if (hasTransientStyle) {
QColor brushColor("#D9D9D9");
brushColor.setAlpha(0.3 * 255);
painter->setBrush(QBrush(brushColor));
painter->drawRoundedRect(scrollBarGroove, 4, 4);
} else {
painter->setBrush(QBrush("#773E3E"));
painter->drawRect(rect);
}
painter->restore();
}
QRect pixmapRect = scrollBarSlider;
QLinearGradient gradient(pixmapRect.center().x(),
pixmapRect.top(),
pixmapRect.center().x(),
pixmapRect.bottom());
if (!horizontal)
gradient = QLinearGradient(pixmapRect.left(),
pixmapRect.center().y(),
pixmapRect.right(),
pixmapRect.center().y());
QLinearGradient highlightedGradient = gradient;
QColor midColor2 = StyleHelper::mergedColors(gradientStartColor, gradientStopColor, 40);
gradient.setColorAt(0, buttonColor.lighter(108));
gradient.setColorAt(1, buttonColor);
QColor innerContrastLine = StyleHelper::highlightColor();
highlightedGradient.setColorAt(0, gradientStartColor.darker(102));
highlightedGradient.setColorAt(1, gradientStopColor.lighter(102));
// Paint slider
if (scrollBar->subControls & SC_ScrollBarSlider) {
if (hasTransientStyle) {
QRect rect = scrollBarSlider;
painter->setPen(Qt::NoPen);
painter->setBrush(highlightedGradient);
int r = qMin(rect.width(), rect.height()) / 2;
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
painter->drawRoundedRect(rect, r, r);
painter->restore();
} else {
QRect pixmapRect = scrollBarSlider;
painter->setPen(QPen(alphaOutline));
if (option->state & State_Sunken
&& scrollBar->activeSubControls & SC_ScrollBarSlider)
painter->setBrush(midColor2);
else if (option->state & State_MouseOver
&& scrollBar->activeSubControls & SC_ScrollBarSlider)
painter->setBrush(highlightedGradient);
else
painter->setBrush(gradient);
painter->drawRect(pixmapRect.adjusted(horizontal ? -1 : 0,
horizontal ? 0 : -1,
horizontal ? 0 : 1,
horizontal ? 1 : 0));
painter->setPen(innerContrastLine);
painter->drawRect(
scrollBarSlider.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, -1, -1));
}
}
// The SubLine (up/left) buttons
if (!hasTransientStyle && scrollBar->subControls & SC_ScrollBarSubLine) {
if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken)
painter->setBrush(gradientStopColor);
else if ((scrollBar->activeSubControls & SC_ScrollBarSubLine))
painter->setBrush(highlightedGradient);
else
painter->setBrush(gradient);
painter->setPen(Qt::NoPen);
painter->drawRect(
scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0));
painter->setPen(QPen(alphaOutline));
if (option->state & State_Horizontal) {
if (option->direction == Qt::RightToLeft) {
pixmapRect.setLeft(scrollBarSubLine.left());
painter->drawLine(pixmapRect.topLeft(), pixmapRect.bottomLeft());
} else {
pixmapRect.setRight(scrollBarSubLine.right());
painter->drawLine(pixmapRect.topRight(), pixmapRect.bottomRight());
}
} else {
pixmapRect.setBottom(scrollBarSubLine.bottom());
painter->drawLine(pixmapRect.bottomLeft(), pixmapRect.bottomRight());
}
QRect upRect = scrollBarSubLine.adjusted(horizontal ? 0 : 1,
horizontal ? 1 : 0,
horizontal ? -2 : -1,
horizontal ? -1 : -2);
painter->setBrush(Qt::NoBrush);
painter->setPen(innerContrastLine);
painter->drawRect(upRect);
// Arrows
PrimitiveElement arrowType = PE_IndicatorArrowUp;
if (option->state & State_Horizontal)
arrowType = option->direction == Qt::LeftToRight ? PE_IndicatorArrowLeft
: PE_IndicatorArrowRight;
StyleHelper::drawArrow(arrowType, painter, option);
}
// The AddLine (down/right) button
if (!hasTransientStyle && scrollBar->subControls & SC_ScrollBarAddLine) {
if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken)
painter->setBrush(gradientStopColor);
else if ((scrollBar->activeSubControls & SC_ScrollBarAddLine))
painter->setBrush(midColor2);
else
painter->setBrush(gradient);
painter->setPen(Qt::NoPen);
painter->drawRect(
scrollBarAddLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0));
painter->setPen(QPen(alphaOutline, 1));
if (option->state & State_Horizontal) {
if (option->direction == Qt::LeftToRight) {
pixmapRect.setLeft(scrollBarAddLine.left());
painter->drawLine(pixmapRect.topLeft(), pixmapRect.bottomLeft());
} else {
pixmapRect.setRight(scrollBarAddLine.right());
painter->drawLine(pixmapRect.topRight(), pixmapRect.bottomRight());
}
} else {
pixmapRect.setTop(scrollBarAddLine.top());
painter->drawLine(pixmapRect.topLeft(), pixmapRect.topRight());
}
QRect downRect = scrollBarAddLine.adjusted(1, 1, -1, -1);
painter->setPen(innerContrastLine);
painter->setBrush(Qt::NoBrush);
painter->drawRect(downRect);
PrimitiveElement arrowType = PE_IndicatorArrowDown;
if (option->state & State_Horizontal)
arrowType = option->direction == Qt::LeftToRight ? PE_IndicatorArrowRight
: PE_IndicatorArrowLeft;
StyleHelper::drawArrow(arrowType, painter, option);
}
}
painter->restore();
} break;
#endif // QT_CONFIG(slider)
default:
Super::drawComplexControl(control, option, painter, widget);
break;
@@ -779,7 +904,7 @@ QSize StudioStyle::sizeFromContents(
QSize newSize;
switch (type) {
case CT_MenuItem:
case CT_MenuItem: {
if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
if (!isQmlEditorMenu(widget)) {
newSize = Super::sizeFromContents(type, option, size, widget);
@@ -835,8 +960,7 @@ QSize StudioStyle::sizeFromContents(
break;
}
}
break;
} break;
default:
newSize = Super::sizeFromContents(type, option, size, widget);
break;
@@ -860,26 +984,56 @@ QRect StudioStyle::subControlRect(
}
#endif
switch (control)
{
case CC_Slider:
switch (control) {
case CC_Slider: {
if (const auto slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
switch (subControl) {
case SubControl::SC_SliderGroove:
return slider->rect;
case SubControl::SC_SliderHandle:
{
case SubControl::SC_SliderHandle: {
QRect retval = Super::subControlRect(control, option, subControl, widget);
return (slider->orientation == Qt::Horizontal)
? retval.adjusted(0, 1, 0, 0)
: retval.adjusted(1, 0, 0, 0);
}
break;
return (slider->orientation == Qt::Horizontal) ? retval.adjusted(0, 1, 0, 0)
: retval.adjusted(1, 0, 0, 0);
} break;
default:
break;
}
}
break;
} break;
case CC_ScrollBar: {
if (!styleHint(SH_ScrollBar_Transient, option, widget))
break;
if (const auto scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
QRect newRect = Super::subControlRect(control, option, subControl, widget);
if (Utils::HostOsInfo::isMacHost()) {
if (scrollbar->orientation == Qt::Horizontal) {
const int halfThickness = newRect.height() / 2;
newRect.adjust(0, halfThickness, 0, 0);
} else {
const int halfThickness = newRect.width() / 2;
newRect.adjust(halfThickness, 0, 0, 0);
}
}
if (subControl == SC_ScrollBarSlider) {
bool hasGroove
= (scrollbar->activeSubControls.testFlag(SC_SliderGroove)
|| (scrollbar->styleObject
&& scrollbar->styleObject->property("adjacentScrollBar").toBool()))
&& scrollbar->subControls.testFlag(SC_ScrollBarGroove);
bool interacted = scrollbar->activeSubControls.testFlag(SC_ScrollBarSlider);
if (hasGroove || interacted)
return newRect;
if (scrollbar->orientation == Qt::Horizontal)
newRect.adjust(0, 1, 0, -1);
else
newRect.adjust(1, 0, -1, 0);
}
return newRect;
}
} break;
default:
break;
}
@@ -893,6 +1047,12 @@ int StudioStyle::styleHint(
const QWidget *widget,
QStyleHintReturn *returnData) const
{
switch (hint) {
case SH_ScrollBar_Transient:
return true;
default:
break;
}
return Super::styleHint(hint, option, widget, returnData);
}
@@ -946,19 +1106,22 @@ int StudioStyle::pixelMetric(
return 4;
case PM_ToolBarExtensionExtent:
return 29;
case PM_ScrollBarExtent:
return 20;
case PM_ScrollBarExtent: {
if (styleHint(SH_ScrollBar_Transient, option, widget))
return 10;
return 14;
} break;
case PM_ScrollBarSliderMin:
return 30;
case PM_SliderLength:
return 5;
case PM_SliderThickness:
case PM_SliderThickness: {
if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
return (slider->orientation == Qt::Horizontal
? slider->rect.height()
: slider->rect.width()) - 1;
}
break;
} break;
case PM_SliderControlThickness:
return 2;
default:

View File

@@ -7,6 +7,7 @@
#include <QProxyStyle>
namespace QmlDesigner {
class StudioStylePrivate;
class QMLDESIGNERBASE_EXPORT StudioStyle : public QProxyStyle
@@ -20,57 +21,51 @@ public:
virtual ~StudioStyle() override;
// Drawing Methods
void drawPrimitive(
PrimitiveElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
void drawPrimitive(PrimitiveElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
void drawControl(
ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
void drawControl(ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
void drawComplexControl(
ComplexControl control,
const QStyleOptionComplex *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
void drawComplexControl(ComplexControl control,
const QStyleOptionComplex *option,
QPainter *painter,
const QWidget *widget = nullptr) const override;
// Topology
QSize sizeFromContents(
ContentsType type,
const QStyleOption *option,
const QSize &size,
const QWidget *widget) const override;
QSize sizeFromContents(ContentsType type,
const QStyleOption *option,
const QSize &size,
const QWidget *widget) const override;
QRect subControlRect(
ComplexControl control,
const QStyleOptionComplex *option,
SubControl subControl,
const QWidget *widget) const override;
QRect subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
SubControl subControl,
const QWidget *widget) const override;
int styleHint(
StyleHint hint,
const QStyleOption *option,
const QWidget *widget,
QStyleHintReturn *returnData) const override;
int styleHint(StyleHint hint,
const QStyleOption *option = nullptr,
const QWidget *widget = nullptr,
QStyleHintReturn *returnData = nullptr) const override;
int pixelMetric(
PixelMetric metric,
const QStyleOption *option = nullptr,
const QWidget *widget = nullptr) const override;
int pixelMetric(PixelMetric metric,
const QStyleOption *option = nullptr,
const QWidget *widget = nullptr) const override;
QPalette standardPalette() const override;
private:
void drawQmlEditorIcon(
PrimitiveElement element,
const QStyleOption *option,
const char *propertyName,
QPainter *painter,
const QWidget *widget = nullptr) const;
void drawQmlEditorIcon(PrimitiveElement element,
const QStyleOption *option,
const char *propertyName,
QPainter *painter,
const QWidget *widget = nullptr) const;
StudioStylePrivate *d = nullptr;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,240 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "studiostyle_p.h"
#include "studiostyle.h"
#include <utils/styleanimator.h>
#include <utils/theme/theme.h>
#include <QPainter>
#include <QStyleOption>
using namespace Utils;
using namespace QmlDesigner;
namespace {
inline QPixmap getPixmapFromIcon(
const QIcon &icon, const QSize &size, bool enabled, bool active, bool checked)
{
QIcon::Mode mode = enabled ? ((active) ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
QIcon::State state = (checked) ? QIcon::On : QIcon::Off;
return icon.pixmap(size, mode, state);
}
inline QColor studioTextColor(bool enabled, bool active, bool checked)
{
Theme::Color themePenColorId = enabled ? (active ? (checked ? Theme::DSsubPanelBackground
: Theme::DSpanelBackground)
: Theme::DStextColor)
: Theme::DStextColorDisabled;
return creatorTheme()->color(themePenColorId);
}
}; // namespace
StudioStylePrivate::StudioStylePrivate(StudioStyle *q)
: QObject(q)
, q(q)
{
auto color = [](Theme::Color c) { return creatorTheme()->color(c); };
{
stdPalette.setColorGroup(QPalette::Disabled, // group
color(Theme::DStextColorDisabled), // windowText
color(Theme::DScontrolBackgroundDisabled), // button
color(Theme::DScontrolOutlineDisabled), // light
color(Theme::DStextSelectedTextColor), // dark
color(Theme::DSstatusbarBackground), // mid
color(Theme::DStextColorDisabled), // text
color(Theme::DStextColorDisabled), // brightText
color(Theme::DStoolbarIcon_blocked), // base
color(Theme::DStoolbarIcon_blocked) // window
);
stdPalette.setColorGroup(QPalette::Inactive, // group
color(Theme::DStextColor), // windowText
color(Theme::DScontrolBackground), // button
color(Theme::DStoolbarBackground), // light
color(Theme::DSstatusbarBackground), // dark
color(Theme::DScontrolBackground), // mid
color(Theme::DStextColor), // text
color(Theme::DStextColor), // brightText
color(Theme::DStoolbarBackground), // base
color(Theme::DStoolbarBackground) // window
);
stdPalette.setColorGroup(QPalette::Active, // group
color(Theme::DStextSelectedTextColor), // windowText
color(Theme::DSnavigatorItemBackgroundHover), // button
color(Theme::DSstateBackgroundColor_hover), // light
color(Theme::DSpanelBackground), // dark
color(Theme::DSnavigatorItemBackgroundHover), // mid
color(Theme::DStextSelectedTextColor), // text
color(Theme::DStextSelectedTextColor), // brightText
color(Theme::DStoolbarBackground), // base
color(Theme::DStoolbarBackground) // window
);
}
}
QList<const QObject *> StudioStylePrivate::animationTargets() const
{
return m_animations.keys();
}
QStyleAnimation *StudioStylePrivate::animation(const QObject *target) const
{
return m_animations.value(target, nullptr);
}
void StudioStylePrivate::startAnimation(QStyleAnimation *animation) const
{
stopAnimation(animation->target());
QObject::connect(animation,
&QObject::destroyed,
this,
&StudioStylePrivate::removeAnimation,
Qt::UniqueConnection);
m_animations.insert(animation->target(), animation);
animation->start();
}
void StudioStylePrivate::stopAnimation(const QObject *target) const
{
QStyleAnimation *animation = m_animations.take(target);
if (animation) {
animation->stop();
delete animation;
}
}
void StudioStylePrivate::removeAnimation(const QObject *animationObject)
{
if (animationObject)
m_animations.remove(animationObject->parent());
}
StudioShortcut::StudioShortcut(const QStyleOptionMenuItem *option, const QString &shortcutText)
: m_shortcutText(shortcutText)
, m_enabled(option->state & QStyle::State_Enabled)
, m_active(option->state & QStyle::State_Selected)
, m_font(option->font)
, m_fontMetrics(m_font)
, m_defaultHeight(m_fontMetrics.height())
, m_spaceConst(m_fontMetrics.boundingRect(".").width())
{
reset();
if (backspaceMatch(shortcutText).hasMatch() && option->styleObject)
m_backspaceIcon = option->styleObject->property("backspaceIcon").value<QIcon>();
}
QSize StudioShortcut::getSize()
{
if (m_isFirstParticle)
calcResult();
return m_size;
}
QPixmap StudioShortcut::getPixmap()
{
if (!m_isFirstParticle && !m_pixmap.isNull())
return m_pixmap;
m_pixmap = QPixmap(getSize());
m_pixmap.fill(Qt::transparent);
QPainter painter(&m_pixmap);
painter.setFont(m_font);
QPen pPen = painter.pen();
pPen.setColor(studioTextColor(m_enabled, m_active, false));
painter.setPen(pPen);
calcResult(&painter);
painter.end();
return m_pixmap;
}
void StudioShortcut::applySize(const QSize &itemSize)
{
m_width += itemSize.width();
m_height = std::max(m_height, itemSize.height());
if (m_isFirstParticle)
m_isFirstParticle = false;
else
m_width += m_spaceConst;
}
void StudioShortcut::addText(const QString &txt, QPainter *painter)
{
if (txt.size()) {
int textWidth = m_fontMetrics.horizontalAdvance(txt);
QSize itemSize = {textWidth, m_defaultHeight};
if (painter) {
static const QTextOption textOption(Qt::AlignLeft | Qt::AlignVCenter);
QRect placeRect({m_width, 0}, itemSize);
painter->drawText(placeRect, txt, textOption);
}
applySize(itemSize);
}
}
void StudioShortcut::addPixmap(const QPixmap &pixmap, QPainter *painter)
{
if (painter)
painter->drawPixmap(QRect({m_width, 0}, pixmap.size()), pixmap);
applySize(pixmap.size());
}
void StudioShortcut::calcResult(QPainter *painter)
{
reset();
#ifndef QT_NO_SHORTCUT
if (!m_shortcutText.isEmpty()) {
int fwdIndex = 0;
QRegularExpressionMatch mMatch = backspaceMatch(m_shortcutText);
int matchCount = mMatch.lastCapturedIndex();
for (int i = 0; i <= matchCount; ++i) {
QString mStr = mMatch.captured(i);
QSize iconSize(m_defaultHeight * 3, m_defaultHeight);
const QList<QSize> iconSizes = m_backspaceIcon.availableSizes();
if (iconSizes.size())
iconSize = iconSizes.last();
double aspectRatio = (m_defaultHeight + .0) / iconSize.height();
int newWidth = iconSize.width() * aspectRatio;
QPixmap pixmap = getPixmapFromIcon(m_backspaceIcon,
{newWidth, m_defaultHeight},
m_enabled,
m_active,
false);
int lIndex = m_shortcutText.indexOf(mStr, fwdIndex);
int diffChars = lIndex - fwdIndex;
addText(m_shortcutText.mid(fwdIndex, diffChars), painter);
addPixmap(pixmap, painter);
fwdIndex = lIndex + mStr.size();
}
addText(m_shortcutText.mid(fwdIndex), painter);
}
#endif
m_size = {m_width, m_height};
}
void StudioShortcut::reset()
{
m_isFirstParticle = true;
m_width = 0;
m_height = 0;
}
QRegularExpressionMatch StudioShortcut::backspaceMatch(const QString &str) const
{
static const QRegularExpression backspaceDetect("\\+*backspace\\+*",
QRegularExpression::CaseInsensitiveOption);
return backspaceDetect.match(str);
}

View File

@@ -0,0 +1,84 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include <QFont>
#include <QFontMetrics>
#include <QHash>
#include <QIcon>
#include <QList>
#include <QObject>
#include <QPalette>
#include <QPixmap>
#include <QProxyStyle>
#include <QRegularExpressionMatch>
#include <QSize>
class QStyleOptionMenuItem;
class QPainter;
namespace Utils {
class StyleAnimation;
class QStyleAnimation;
} // namespace Utils
namespace QmlDesigner {
class StudioStyle;
class StudioStylePrivate : public QObject
{
Q_OBJECT
using StyleAnimation = Utils::StyleAnimation;
using QStyleAnimation = Utils::QStyleAnimation;
public:
explicit StudioStylePrivate(StudioStyle *q);
QList<const QObject *> animationTargets() const;
QStyleAnimation *animation(const QObject *target) const;
void startAnimation(QStyleAnimation *animation) const;
void stopAnimation(const QObject *target) const;
QPalette stdPalette;
private:
StudioStyle *q = nullptr;
mutable QHash<const QObject *, QStyleAnimation *> m_animations;
private slots:
void removeAnimation(const QObject *animationObject);
};
struct StudioShortcut
{
StudioShortcut(const QStyleOptionMenuItem *option, const QString &shortcutText);
QSize getSize();
QPixmap getPixmap();
private:
void applySize(const QSize &itemSize);
void addText(const QString &txt, QPainter *painter = nullptr);
void addPixmap(const QPixmap &pixmap, QPainter *painter = nullptr);
void calcResult(QPainter *painter = nullptr);
void reset();
QRegularExpressionMatch backspaceMatch(const QString &str) const;
const QString m_shortcutText;
const bool m_enabled;
const bool m_active;
const QFont m_font;
const QFontMetrics m_fontMetrics;
const int m_defaultHeight;
const int m_spaceConst;
QIcon m_backspaceIcon;
bool m_isFirstParticle = true;
int m_width = 0;
int m_height = 0;
QSize m_size;
QPixmap m_pixmap;
};
} // namespace QmlDesigner