wip: customize scroll bar

This commit is contained in:
Hane 2024-05-30 22:36:35 +02:00
commit 313a26c8e3
3 changed files with 448 additions and 48 deletions

View file

@ -250,6 +250,8 @@ void MainWindow::compose() {
log_debugcpp("Window Width: " + std::to_string(windowWidth));
this->createLayout(new QGridLayout());
//scrollArea->verticalScrollBar()->setMinimumWidth(windowWidth * (widthRatio));
//scrollArea->verticalScrollBar()->setMaximumWidth(windowWidth * (widthRatio));
/*
* this->setAttribute(Qt::WA_DontShowOnScreen, true);
* this->show();
@ -257,10 +259,11 @@ void MainWindow::compose() {
* this->hide();
* this->setAttribute(Qt::WA_DontShowOnScreen, false);
*/
const qreal dpr = screen->devicePixelRatio();
log_to_file("dpr: %f \n", dpr);
for (auto *epw : ews) {
if (!epw) continue;
epw->calculateSize(windowWidth, screenHeight);
epw->calculateSize(windowWidth * dpr,screenHeight * screen->devicePixelRatio());
log_debugcpp("epw loop");
log_debugcpp("epw roles: " + print_as_binary((epw->getEndpointHandler()->getRoles())));
//std::bitset<sizeof(uint8_t)> content =
@ -277,8 +280,8 @@ void MainWindow::compose() {
if (!ews[i]) continue;
ews[i]->layout()->getContentsMargins(&left, &top, &right, &bottom);
windowHeight += ews[i]->sizeHint().height();
windowHeight += top;
windowHeight += bottom;
windowHeight += top * 3;
//windowHeight += bottom;
log_debugcpp("windowHeight loop: " + std::to_string(windowHeight));
}
windowHeight += mainMenuBar->sizeHint().height();
@ -941,13 +944,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
scrollArea = new QScrollArea(this);
scrollArea->setWidget(widget);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setContentsMargins(QMargins(0, 0, 0, 0));
//scrollArea->verticalScrollBar()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
//scrollArea->verticalScrollBar()->setSingleStep(1);
//custom style = no qss
//scrollArea->setStyleSheet("QScrollBar:vertical { width: 4px; }");
//scrollArea->setMinimumWidth(500);
setCentralWidget(scrollArea);
/*

View file

@ -41,7 +41,7 @@
#include <QPixmapCache>
#include <QLatin1Char>
#include <QLatin1String>
//#include <QScrollbarStyleAnimation>
//#include <QScrollBar>
/*
* #else
@ -65,7 +65,7 @@ namespace StylingHelper {
return QLatin1String(ch);
}
static inline qreal dpi(const QStyleOption *option) {
static inline qreal calculateDpi(const QStyleOption *option) {
#ifndef Q_OS_DARWIN
// Prioritize the application override, except for on macOS where
// we have historically not supported the AA_Use96Dpi flag.
@ -77,7 +77,7 @@ namespace StylingHelper {
if (option)
return option->fontMetrics.fontDpi();
// Fall back to historical Qt behavior: hardocded 72 DPI on mac,
// Fall back to historical Qt behavior: hardcoded 72 DPI on mac,
// primary screen DPI on other platforms.
#ifdef Q_OS_DARWIN
return qstyleBaseDpi;
@ -86,6 +86,10 @@ namespace StylingHelper {
#endif
}
static inline qreal calculateDpi(const QScreen screen) {
return QFontMetrics(QApplication::font()).fontDpi();
}
/*
* #ifdef Q_OS_DARWIN
* static const qreal qstyleBaseDpi = 72;
@ -107,7 +111,7 @@ namespace StylingHelper {
}
static inline qreal dpiScaled(qreal value, const QStyleOption *option) {
return dpiScaled(value, dpi(option));
return dpiScaled(value, calculateDpi(option));
}
static inline bool isMacSystemPalette(const QPalette &pal) {
@ -161,5 +165,18 @@ namespace StylingHelper {
cachePixmap.fill(Qt::transparent);
return cachePixmap;
}
static inline QColor backgroundColor(const QPalette &pal, const QWidget* widget)
{
#if QT_CONFIG(scrollarea)
if (qobject_cast<const QScrollBar *>(widget) && widget->parent() &&
qobject_cast<const QAbstractScrollArea *>(widget->parent()->parent()))
return widget->parentWidget()->parentWidget()->palette().color(QPalette::Base);
#else
Q_UNUSED(widget);
#endif
return pal.color(QPalette::Base);
}
}

View file

@ -16,7 +16,7 @@ public:
QStyleHintReturn* returnData = 0) const {
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
return (Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
return QProxyStyle::styleHint(hint, option, widget, returnData);
return baseStyle()->styleHint(hint, option, widget, returnData);
}
QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option,
@ -24,7 +24,7 @@ public:
QRect rect = QCommonStyle::subControlRect(CC_Slider, option, subControl, widget);
switch (control) {
#if QT_CONFIG(slider)
#if QT_CONFIG(slider)
case CC_MeterSlider:
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
@ -88,6 +88,94 @@ public:
return rect;
break;
#endif // QT_CONFIG(slider)
#if QT_CONFIG(scrollbar)
case CC_ScrollBar:
if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
QRect scrollBarRect = scrollbar->rect;
const uint64_t offset = 7;
scrollBarRect.setWidth(scrollBarRect.width() / 2);
scrollBarRect.setHeight(scrollBarRect.height() - 15);
int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
scrollBarRect.width() : scrollBarRect.height());
int sliderlen;
// calculate slider length
if (scrollbar->maximum != scrollbar->minimum) {
uint range = scrollbar->maximum - scrollbar->minimum;
sliderlen = (qint64(scrollbar->pageStep) * maxlen) / (range + scrollbar->pageStep);
int slidermin = baseStyle()->pixelMetric(PM_ScrollBarSliderMin, scrollbar, widget);
if (sliderlen < slidermin || range > INT_MAX / 2)
sliderlen = slidermin;
if (sliderlen > maxlen)
sliderlen = maxlen;
} else {
sliderlen = maxlen;
}
int sliderstart = sliderPositionFromValue(scrollbar->minimum,
scrollbar->maximum,
scrollbar->sliderPosition,
maxlen - sliderlen,
scrollbar->upsideDown);
switch (subControl) {
/*
* case SC_ScrollBarSubLine: // top/left button
* if (scrollbar->orientation == Qt::Horizontal) {
* int buttonWidth = qMin(scrollBarRect.width() / 2, sbextent);
* rect.setRect(0, 0, buttonWidth, scrollBarRect.height());
* } else {
* int buttonHeight = qMin(scrollBarRect.height() / 2, sbextent);
* rect.setRect(0, 0, scrollBarRect.width(), buttonHeight);
* }
* break;
* case SC_ScrollBarAddLine: // bottom/right button
* if (scrollbar->orientation == Qt::Horizontal) {
* int buttonWidth = qMin(scrollBarRect.width()/2, sbextent);
* rect.setRect(scrollBarRect.width() - buttonWidth, 0, buttonWidth, scrollBarRect.height());
* } else {
* int buttonHeight = qMin(scrollBarRect.height()/2, sbextent);
* rect.setRect(0, scrollBarRect.height() - buttonHeight, scrollBarRect.width(), buttonHeight);
* }
* break;
*/
case SC_ScrollBarSubPage: // between top/left button and slider
if (scrollbar->orientation == Qt::Horizontal)
rect.setRect(0, 0, sliderstart, scrollBarRect.height());
else
rect.setRect(0, 0, scrollBarRect.width(), sliderstart);
break;
case SC_ScrollBarAddPage: // between bottom/right button and slider
if (scrollbar->orientation == Qt::Horizontal)
rect.setRect(sliderstart + sliderlen, 0,
maxlen - sliderstart - sliderlen, scrollBarRect.height());
else
rect.setRect(0, sliderstart + sliderlen, scrollBarRect.width(),
maxlen - sliderstart - sliderlen);
break;
case SC_ScrollBarGroove:
if (scrollbar->orientation == Qt::Horizontal)
rect.setRect(offset, 0, scrollBarRect.width(),
scrollBarRect.height());
else
rect.setRect(0, offset, scrollBarRect.width(),
scrollBarRect.height() );
break;
case SC_ScrollBarSlider:
if (scrollbar->orientation == Qt::Horizontal)
rect.setRect(sliderstart + offset, 0, sliderlen, scrollBarRect.height());
else
rect.setRect(0, sliderstart + offset, scrollBarRect.width(), sliderlen);
break;
default:
break;
}
rect = visualRect(scrollbar->direction, scrollBarRect, rect);
return rect;
}
break;
#endif // QT_CONFIG(scrollbar)
default:
return baseStyle()->subControlRect(control, option, subControl, widget);
break;
@ -97,6 +185,7 @@ public:
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
QPainter *painter, const QWidget *widget) const {
QColor outline;
switch (cc) {
#if QT_CONFIG(slider)
case CC_MeterSlider:
@ -115,7 +204,7 @@ public:
QPen oldPen = painter->pen();
QColor shadowAlpha(Qt::black);
shadowAlpha.setAlpha(10);
QColor outline;
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
outline = highlightedOutline(option->palette);
@ -327,6 +416,213 @@ public:
painter->setPen(oldPen);
}
break;
case CC_ScrollBar:
painter->save();
if (const QStyleOptionSlider *scrollBar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
bool wasActive = false;
qreal expandScale = 1.0;
qreal expandOffset = -1.0;
QObject *styleObject = option->styleObject;
QColor buttonColor = calculateButtonColor(option->palette);
QColor gradientStartColor = buttonColor.lighter(104);
QColor gradientStopColor = buttonColor.darker(102);
bool transient = styleHint(SH_ScrollBar_Transient, option, widget);
bool horizontal = scrollBar->orientation == Qt::Horizontal;
bool sunken = scrollBar->state & State_Sunken;
QRect scrollBarSubLine = subControlRect(cc, scrollBar, SC_ScrollBarSubLine, widget);
QRect scrollBarAddLine = subControlRect(cc, scrollBar, SC_ScrollBarAddLine, widget);
QRect scrollBarSlider = subControlRect(cc, scrollBar, SC_ScrollBarSlider, widget);
QRect scrollBarGroove = subControlRect(cc, scrollBar, SC_ScrollBarGroove, widget);
QRect rect = option->rect;
outline = highlightedOutline(option->palette);
QColor alphaOutline = outline;
alphaOutline.setAlpha(180);
QColor arrowColor = option->palette.windowText().color();
//QColor arrowColor = QColor(188,143,143,100);
arrowColor.setAlpha(160);
const QColor bgColor = backgroundColor(option->palette, widget);
const bool isDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
if (transient) {
if (horizontal) {
rect.setY(rect.y() + 4.5 - expandOffset);
scrollBarSlider.setY(scrollBarSlider.y() + 4.5 - expandOffset);
scrollBarGroove.setY(scrollBarGroove.y() + 4.5 - expandOffset);
rect.setHeight(rect.height() * expandScale);
scrollBarGroove.setHeight(scrollBarGroove.height() * expandScale);
} else {
rect.setX(rect.x() + 4.5 - expandOffset);
scrollBarSlider.setX(scrollBarSlider.x() + 4.5 - expandOffset);
scrollBarGroove.setX(scrollBarGroove.x() + 4.5 - expandOffset);
rect.setWidth(rect.width() * expandScale);
scrollBarGroove.setWidth(scrollBarGroove.width() * expandScale);
}
}
// Paint groove
if ((!transient || scrollBar->activeSubControls || wasActive) && scrollBar->subControls & SC_ScrollBarGroove) {
QLinearGradient gradient(rect.center().x(), rect.top(),
rect.center().x(), rect.bottom());
if (!horizontal)
gradient = QLinearGradient(rect.left(), rect.center().y(),
rect.right(), rect.center().y());
if (!transient || !isDarkBg) {
gradient.setColorAt(0, buttonColor.darker(107));
gradient.setColorAt(0.1, buttonColor.darker(105));
gradient.setColorAt(0.9, buttonColor.darker(105));
gradient.setColorAt(1, buttonColor.darker(107));
} else {
gradient.setColorAt(0, bgColor.lighter(157));
gradient.setColorAt(0.1, bgColor.lighter(155));
gradient.setColorAt(0.9, bgColor.lighter(155));
gradient.setColorAt(1, bgColor.lighter(157));
}
painter->save();
//painter->fillRect(rect, gradient);
painter->setPen(Qt::NoPen);
painter->setPen(alphaOutline);
QColor subtleEdge = alphaOutline;
subtleEdge.setAlpha(40);
painter->setPen(subtleEdge);
//painter->setBrush(Qt::NoBrush);
painter->setOpacity(0.3);
painter->setBrush(Qt::gray);
painter->drawRoundedRect(scrollBarGroove, 5, 5);
//painter->drawRoundedRect(scrollBarGroove, 5, 5);
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 = mergedColors(gradientStartColor, gradientStopColor, 40);
gradient.setColorAt(0, calculateButtonColor(option->palette).lighter(108));
gradient.setColorAt(1, calculateButtonColor(option->palette));
highlightedGradient.setColorAt(0, gradientStartColor.darker(102));
highlightedGradient.setColorAt(1, gradientStopColor.lighter(102));
// Paint slider
if (scrollBar->subControls & SC_ScrollBarSlider) {
if (transient) {
QRect rect = scrollBarSlider.adjusted(horizontal ? 1 : 2, horizontal ? 2 : 1, -1, -1);
painter->setPen(Qt::NoPen);
painter->setBrush(isDarkBg ? lightShade() : darkShade());
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 if (!isDarkBg)
painter->setBrush(gradient);
else
painter->setBrush(midColor2);
painter->drawRoundedRect(pixmapRect.adjusted(horizontal ? -1 : 0, horizontal ? 0 : -1, horizontal ? 0 : -1, horizontal ? -1 : 0), 5, 5);
painter->setPen(innerContrastLine());
painter->drawRoundedRect(scrollBarSlider.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, -1, -1), 5, 5);
// Outer shadow
// painter->setPen(subtleEdge);
// if (horizontal) {
//// painter->drawLine(scrollBarSlider.topLeft() + QPoint(-2, 0), scrollBarSlider.bottomLeft() + QPoint(2, 0));
//// painter->drawLine(scrollBarSlider.topRight() + QPoint(-2, 0), scrollBarSlider.bottomRight() + QPoint(2, 0));
// } else {
//// painter->drawLine(pixmapRect.topLeft() + QPoint(0, -2), pixmapRect.bottomLeft() + QPoint(0, -2));
//// painter->drawLine(pixmapRect.topRight() + QPoint(0, 2), pixmapRect.bottomRight() + QPoint(0, 2));
// }
}
}
/*
* // The SubLine (up/left) buttons
* if (!transient && 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->drawRoundedRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0), 1, 1);
* painter->setPen(QPen(alphaOutline));
* if (option->state & State_Horizontal) {
* painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, 0, horizontal ? 1 : 0, horizontal ? -1 : 0));
* } else {
* painter->drawRoundedRect(scrollBarSubLine.adjusted(0, 0, horizontal ? 0 : -1, 0), 1, 1);
* }
*
* 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
* Qt::ArrowType arrowType = Qt::UpArrow;
* if (option->state & State_Horizontal)
* arrowType = option->direction == Qt::LeftToRight ? Qt::LeftArrow : Qt::RightArrow;
* qt_fusion_draw_arrow(arrowType, painter, option, upRect, arrowColor);
* }
*
* // The AddLine (down/right) button
* if (!transient && 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) {
* painter->drawRect(scrollBarAddLine.adjusted(horizontal ? -1 : 0, 0, horizontal ? -1 : 0, horizontal ? -1 : 0));
* } else {
* painter->drawRect(scrollBarAddLine.adjusted(0, horizontal ? 0 : -1, horizontal ? 0 : -1, horizontal ? 0 : -1));
* }
*
* QRect downRect = scrollBarAddLine.adjusted(1, 1, -1, -1);
* painter->setPen(innerContrastLine());
* painter->setBrush(Qt::NoBrush);
* painter->drawRect(downRect);
*
* Qt::ArrowType arrowType = Qt::DownArrow;
* if (option->state & State_Horizontal)
* arrowType = option->direction == Qt::LeftToRight ? Qt::RightArrow : Qt::LeftArrow;
* qt_fusion_draw_arrow(arrowType, painter, option, downRect, arrowColor);
* }
*/
}
painter->restore();
break;
default:
baseStyle()->drawComplexControl(cc, option, painter, widget);
#endif // QT_CONFIG(slider)
@ -341,10 +637,8 @@ private:
FromRight
};
static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseColor, Direction direction = TopDown)
{
{
int x = rect.center().x();
int y = rect.center().y();
QLinearGradient gradient;
@ -377,6 +671,93 @@ private:
// gradient.setColorAt(0.501, midColor2);
}
return gradient;
}
QColor calculateButtonColor(const QPalette &pal) const {
QColor buttonColor = pal.button().color();
int val = qGray(buttonColor.rgb());
buttonColor = buttonColor.lighter(100 + qMax(1, (180 - val)/6));
buttonColor.setHsv(buttonColor.hue(), buttonColor.saturation() * 0.75, buttonColor.value());
return buttonColor;
}
// Used for grip handles
QColor lightShade() const {
return QColor(255, 255, 255, 90);
}
QColor darkShade() const {
return QColor(0, 0, 0, 60);
}
QColor innerContrastLine() const {
return QColor(255, 255, 255, 30);
}
static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50) {
const int maxFactor = 100;
QColor tmp = colorA;
tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
return tmp;
}
static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QStyleOption *option, const QRect &rect, const QColor &color)
{
if (rect.isEmpty())
return;
const qreal dpi = calculateDpi(option);
const qreal dpr = painter->device()->devicePixelRatio();
const int arrowWidth = int(dpiScaled(14, dpi));
const int arrowHeight = int(dpiScaled(8, dpi));
const int arrowMax = qMin(arrowHeight, arrowWidth);
const int rectMax = qMin(rect.height(), rect.width());
const int size = qMin(arrowMax, rectMax);
QPixmap cachePixmap;
const QString cacheKey = "fusion-arrow"_L1 + QString::number(rect.size().width()) + QString::number(rect.size().height()) + QString::number(type);
if (!QPixmapCache::find(cacheKey, &cachePixmap)) {
cachePixmap = styleCachePixmap(rect.size(), dpr);
QPainter cachePainter(&cachePixmap);
QRectF arrowRect;
arrowRect.setWidth(size);
arrowRect.setHeight(arrowHeight * size / arrowWidth);
if (type == Qt::LeftArrow || type == Qt::RightArrow)
arrowRect = arrowRect.transposed();
arrowRect.moveTo((rect.width() - arrowRect.width()) / 2.0,
(rect.height() - arrowRect.height()) / 2.0);
std::array<QPointF, 3> triangle;
switch (type) {
case Qt::DownArrow:
triangle = {arrowRect.topLeft(), arrowRect.topRight(), QPointF(arrowRect.center().x(), arrowRect.bottom())};
break;
case Qt::RightArrow:
triangle = {arrowRect.topLeft(), arrowRect.bottomLeft(), QPointF(arrowRect.right(), arrowRect.center().y())};
break;
case Qt::LeftArrow:
triangle = {arrowRect.topRight(), arrowRect.bottomRight(), QPointF(arrowRect.left(), arrowRect.center().y())};
break;
default:
triangle = {arrowRect.bottomLeft(), arrowRect.bottomRight(), QPointF(arrowRect.center().x(), arrowRect.top())};
break;
}
cachePainter.setPen(Qt::NoPen);
cachePainter.setBrush(color);
cachePainter.setRenderHint(QPainter::Antialiasing);
cachePainter.drawPolygon(triangle.data(), int(triangle.size()));
QPixmapCache::insert(cacheKey, cachePixmap);
}
painter->drawPixmap(rect, cachePixmap);
}
};