mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
2430 lines
70 KiB
C++
2430 lines
70 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019-2025 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "RDStyle.h"
|
|
#include <QAbstractItemView>
|
|
#include <QApplication>
|
|
#include <QComboBox>
|
|
#include <QCommonStyle>
|
|
#include <QDebug>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QPen>
|
|
#include <QStyleOption>
|
|
#include <QtMath>
|
|
#include "Code/QRDUtils.h"
|
|
|
|
namespace Constants
|
|
{
|
|
static const int SliderHandleHalfWidth = 5;
|
|
static const int SliderGrooveHeight = 4;
|
|
static const qreal SliderHandleCornerRadius = 4.0f;
|
|
|
|
static const int ButtonMargin = 6;
|
|
static const int ButtonBorder = 1;
|
|
|
|
static const int HighlightBorder = 2;
|
|
|
|
static const int CheckWidth = 14;
|
|
static const int CheckHeight = 14;
|
|
static const float CheckCornerSize = 2.0f;
|
|
static const int CheckMargin = 3;
|
|
|
|
static const int GroupHMargin = 8;
|
|
static const int GroupVMargin = 4;
|
|
|
|
static const int ScrollButtonDim = 12;
|
|
static const int ScrollBarMargin = 2;
|
|
static const int ScrollBarMin = ScrollButtonDim;
|
|
static const qreal ScrollBarRadius = 4.0;
|
|
|
|
static const int SeparatorMargin = 2;
|
|
|
|
static const int ComboMargin = 2;
|
|
static const int ComboArrowDim = 12;
|
|
|
|
static const int SpinButtonDim = 12;
|
|
static const int SpinMargin = 1;
|
|
|
|
static const int ProgressMargin = 2;
|
|
static const qreal ProgressRadius = 4.0;
|
|
|
|
static const int MenuBarMargin = 6;
|
|
static const int MenuSubmenuWidth = 8;
|
|
static const int MenuBarIconSize = 16;
|
|
static const int MenuBarMinimumWidth = 80;
|
|
|
|
static const int TabWidgetBorder = 1;
|
|
static const int TabMargin = 4;
|
|
static const int TabMinWidth = 75;
|
|
static const int TabMaxWidth = 250;
|
|
|
|
static const int ItemHeaderMargin = 4;
|
|
static const int ItemHeaderIconSize = 16;
|
|
};
|
|
|
|
namespace Animation
|
|
{
|
|
QHash<QObject *, QAbstractAnimation *> animations;
|
|
|
|
bool has(QObject *target)
|
|
{
|
|
return animations.contains(target);
|
|
}
|
|
|
|
QAbstractAnimation *get(QObject *target)
|
|
{
|
|
return animations.value(target);
|
|
}
|
|
|
|
template <typename AnimationType>
|
|
AnimationType *get(QObject *target)
|
|
{
|
|
return (AnimationType *)get(target);
|
|
}
|
|
|
|
void stop(QObject *target)
|
|
{
|
|
if(has(target))
|
|
{
|
|
QAbstractAnimation *existing = get(target);
|
|
existing->stop();
|
|
delete existing;
|
|
animations.remove(target);
|
|
}
|
|
}
|
|
|
|
void removeOnDelete(QObject *target)
|
|
{
|
|
if(has(target))
|
|
animations.remove(target);
|
|
}
|
|
|
|
void start(QAbstractAnimation *anim)
|
|
{
|
|
QObject *target = anim->parent();
|
|
|
|
stop(target);
|
|
if(has(target))
|
|
{
|
|
QAbstractAnimation *existing = get(target);
|
|
existing->stop();
|
|
delete existing;
|
|
animations.remove(target);
|
|
}
|
|
|
|
animations.insert(target, anim);
|
|
QObject::connect(target, &QObject::destroyed, &removeOnDelete);
|
|
anim->start();
|
|
}
|
|
};
|
|
|
|
static QWindow *widgetWindow(const QWidget *widget)
|
|
{
|
|
return widget ? widget->window()->windowHandle() : NULL;
|
|
}
|
|
|
|
RDStyle::RDStyle(ColorScheme scheme) : RDTweakedNativeStyle(new QCommonStyle())
|
|
{
|
|
m_Scheme = scheme;
|
|
|
|
const uchar bits[] = {
|
|
0x19, // X..XX
|
|
0x1C, // ..XXX
|
|
0x0E, // .XXX.
|
|
0x07, // XXX..
|
|
0x13, // XX..X
|
|
};
|
|
|
|
m_PartialCheckPattern = QBitmap::fromData(QSize(5, 5), bits);
|
|
}
|
|
|
|
RDStyle::~RDStyle()
|
|
{
|
|
}
|
|
|
|
void RDStyle::polishPalette(QPalette &pal) const
|
|
{
|
|
int h = 0, s = 0, v = 0;
|
|
|
|
QColor windowText;
|
|
QColor window;
|
|
QColor base;
|
|
QColor highlight;
|
|
QColor tooltip;
|
|
|
|
if(m_Scheme == Light)
|
|
{
|
|
window = QColor(225, 225, 225);
|
|
windowText = QColor(Qt::black);
|
|
base = QColor(Qt::white);
|
|
highlight = QColor(80, 110, 160);
|
|
tooltip = QColor(250, 245, 200);
|
|
}
|
|
else
|
|
{
|
|
window = QColor(45, 55, 60);
|
|
windowText = QColor(225, 225, 225);
|
|
base = QColor(22, 27, 30);
|
|
highlight = QColor(100, 130, 200);
|
|
tooltip = QColor(70, 70, 65);
|
|
}
|
|
|
|
QColor light = window.lighter(150);
|
|
QColor mid = window.darker(150);
|
|
QColor dark = mid.darker(150);
|
|
|
|
QColor text = windowText;
|
|
|
|
pal = QPalette(windowText, window, light, dark, mid, text, base);
|
|
|
|
pal.setColor(QPalette::Shadow, Qt::black);
|
|
|
|
if(m_Scheme == Light)
|
|
pal.setColor(QPalette::AlternateBase, base.darker(110));
|
|
else
|
|
pal.setColor(QPalette::AlternateBase, base.lighter(110));
|
|
|
|
if(m_Scheme == Dark)
|
|
{
|
|
pal.setColor(QPalette::BrightText, text);
|
|
}
|
|
|
|
pal.setColor(QPalette::ToolTipBase, tooltip);
|
|
pal.setColor(QPalette::ToolTipText, text);
|
|
|
|
pal.setColor(QPalette::Highlight, highlight);
|
|
// inactive highlight is desaturated
|
|
highlight.getHsv(&h, &s, &v);
|
|
highlight.setHsv(h, int(s * 0.5), v);
|
|
pal.setColor(QPalette::Inactive, QPalette::Highlight, highlight);
|
|
|
|
pal.setColor(QPalette::HighlightedText, Qt::white);
|
|
|
|
// links are based on the highlight colour
|
|
QColor link = m_Scheme == Light ? highlight.darker(125) : highlight.lighter(105);
|
|
pal.setColor(QPalette::Link, link);
|
|
|
|
// visited links are desaturated
|
|
QColor linkVisited = link;
|
|
linkVisited.getHsv(&h, &s, &v);
|
|
linkVisited.setHsv(h, 0, v);
|
|
pal.setColor(QPalette::LinkVisited, linkVisited);
|
|
|
|
// for the 'text' type roles, make the disabled colour half as bright
|
|
for(QPalette::ColorRole role :
|
|
{QPalette::WindowText, QPalette::Text, QPalette::ButtonText, QPalette::Highlight,
|
|
QPalette::HighlightedText, QPalette::Link, QPalette::LinkVisited})
|
|
{
|
|
QColor col = pal.color(QPalette::Inactive, role);
|
|
|
|
col.getHsv(&h, &s, &v);
|
|
|
|
// with the exception of link text, the disabled version is desaturated
|
|
if(role != QPalette::Link)
|
|
s = 0;
|
|
|
|
// black is the only colour that gets brighter, any other colour gets darker
|
|
if(s == 0 && v == 0)
|
|
{
|
|
pal.setColor(QPalette::Disabled, role, QColor(160, 160, 160));
|
|
}
|
|
else
|
|
{
|
|
col.setHsv(h, s, v / 2);
|
|
pal.setColor(QPalette::Disabled, role, col);
|
|
}
|
|
}
|
|
|
|
// the 'base' roles get every so slightly darker, but not as much as text
|
|
for(QPalette::ColorRole role : {QPalette::Base, QPalette::Window, QPalette::Button})
|
|
{
|
|
QColor col = pal.color(QPalette::Inactive, role);
|
|
|
|
col.getHsv(&h, &s, &v);
|
|
col.setHsv(h, s, v * 0.9);
|
|
pal.setColor(QPalette::Disabled, role, col);
|
|
}
|
|
}
|
|
|
|
void RDStyle::polish(QWidget *widget)
|
|
{
|
|
if(qobject_cast<QAbstractSlider *>(widget) || qobject_cast<QTabBar *>(widget))
|
|
widget->setAttribute(Qt::WA_Hover);
|
|
|
|
QTabWidget *tabwidget = qobject_cast<QTabWidget *>(widget);
|
|
if(tabwidget && tabwidget->inherits("ToolWindowManagerArea"))
|
|
{
|
|
tabwidget->installEventFilter(this);
|
|
tabwidget->setDocumentMode(false);
|
|
tabwidget->tabBar()->setDrawBase(true);
|
|
}
|
|
}
|
|
|
|
void RDStyle::polish(QApplication *app)
|
|
{
|
|
app->setPalette(standardPalette());
|
|
}
|
|
|
|
void RDStyle::unpolish(QWidget *widget)
|
|
{
|
|
Animation::stop(widget);
|
|
|
|
QTabWidget *tabwidget = qobject_cast<QTabWidget *>(widget);
|
|
if(tabwidget && tabwidget->inherits("ToolWindowManagerArea"))
|
|
tabwidget->removeEventFilter(this);
|
|
}
|
|
|
|
QPalette RDStyle::standardPalette() const
|
|
{
|
|
QPalette ret = RDTweakedNativeStyle::standardPalette();
|
|
|
|
polishPalette(ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool RDStyle::eventFilter(QObject *watched, QEvent *event)
|
|
{
|
|
QTabWidget *tabwidget = qobject_cast<QTabWidget *>(watched);
|
|
if(tabwidget && tabwidget->inherits("ToolWindowManagerArea"))
|
|
{
|
|
if(tabwidget->documentMode())
|
|
tabwidget->setDocumentMode(false);
|
|
if(!tabwidget->tabBar()->drawBase())
|
|
tabwidget->tabBar()->setDrawBase(true);
|
|
}
|
|
|
|
return QObject::eventFilter(watched, event);
|
|
}
|
|
|
|
QRect RDStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
|
|
const QWidget *widget) const
|
|
{
|
|
if(cc == QStyle::CC_GroupBox)
|
|
{
|
|
QRect ret = opt->rect;
|
|
|
|
if(sc == SC_GroupBoxFrame)
|
|
return ret;
|
|
|
|
const QStyleOptionGroupBox *group = qstyleoption_cast<const QStyleOptionGroupBox *>(opt);
|
|
|
|
const int border = Constants::ButtonBorder;
|
|
const int lineHeight = group->fontMetrics.height();
|
|
|
|
ret.adjust(border, border, -2 * border, -2 * border);
|
|
|
|
const int labelHeight = lineHeight + border * 2;
|
|
|
|
const int checkWidth =
|
|
(group->subControls & QStyle::SC_GroupBoxCheckBox) ? Constants::CheckWidth : 0;
|
|
|
|
if(sc == SC_GroupBoxLabel)
|
|
{
|
|
if(checkWidth > 0)
|
|
{
|
|
ret.adjust(checkWidth + Constants::CheckMargin, 0, 0, 0);
|
|
ret.setHeight(qMax(labelHeight, Constants::CheckHeight));
|
|
}
|
|
else
|
|
{
|
|
ret.setHeight(labelHeight);
|
|
}
|
|
|
|
ret.setWidth(group->fontMetrics.boundingRect(group->text).width());
|
|
|
|
return ret;
|
|
}
|
|
|
|
if(sc == SC_GroupBoxCheckBox)
|
|
{
|
|
if(checkWidth > 0)
|
|
{
|
|
ret.setWidth(checkWidth);
|
|
ret.setHeight(Constants::CheckHeight);
|
|
ret.adjust(Constants::CheckMargin, Constants::CheckMargin, Constants::CheckMargin,
|
|
Constants::CheckMargin);
|
|
}
|
|
else
|
|
{
|
|
ret = QRect();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if(sc == QStyle::SC_GroupBoxContents)
|
|
{
|
|
ret.setTop(ret.top() + labelHeight + Constants::GroupHMargin);
|
|
|
|
return ret;
|
|
}
|
|
|
|
return opt->rect;
|
|
}
|
|
else if(cc == QStyle::CC_ScrollBar)
|
|
{
|
|
QRect ret = opt->rect;
|
|
|
|
// shrink by the border
|
|
ret.adjust(1, 1, -1, -1);
|
|
|
|
// don't have first/last buttons
|
|
if(sc == QStyle::SC_ScrollBarFirst || sc == QStyle::SC_ScrollBarLast)
|
|
return QRect();
|
|
|
|
const QStyleOptionSlider *scroll = qstyleoption_cast<const QStyleOptionSlider *>(opt);
|
|
const int range = scroll->maximum - scroll->minimum;
|
|
|
|
if(scroll->orientation == Qt::Horizontal)
|
|
{
|
|
if(sc == QStyle::SC_ScrollBarSubLine)
|
|
return ret.adjusted(0, 0, -ret.width() + Constants::ScrollButtonDim, 0);
|
|
if(sc == QStyle::SC_ScrollBarAddLine)
|
|
return ret.adjusted(ret.width() - Constants::ScrollButtonDim, 0, 0, 0);
|
|
|
|
const int buttonAdjust = Constants::ScrollButtonDim + Constants::ScrollBarMargin;
|
|
ret.adjust(buttonAdjust, 0, -buttonAdjust, 0);
|
|
|
|
if(sc == QStyle::SC_ScrollBarGroove)
|
|
return ret;
|
|
|
|
QRect slider = ret;
|
|
|
|
if(scroll->maximum > scroll->minimum)
|
|
{
|
|
int sliderSize = qMax(Constants::ScrollBarMin,
|
|
(scroll->pageStep * ret.width()) / (range + scroll->pageStep));
|
|
|
|
slider.setWidth(qMin(slider.width(), sliderSize));
|
|
slider.moveLeft(ret.left() + (qreal(scroll->sliderPosition) / qreal(range)) *
|
|
(ret.width() - slider.width()));
|
|
}
|
|
else
|
|
{
|
|
return QRect();
|
|
}
|
|
|
|
if(sc == QStyle::SC_ScrollBarSlider)
|
|
return slider;
|
|
|
|
if(sc == QStyle::SC_ScrollBarSubPage)
|
|
return ret.adjusted(0, 0, slider.left() - ret.right(), 0);
|
|
if(sc == QStyle::SC_ScrollBarAddPage)
|
|
return ret.adjusted(slider.right() - ret.left(), 0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
if(sc == QStyle::SC_ScrollBarSubLine)
|
|
return ret.adjusted(0, 0, 0, -ret.height() + Constants::ScrollButtonDim);
|
|
if(sc == QStyle::SC_ScrollBarAddLine)
|
|
return ret.adjusted(0, ret.height() - Constants::ScrollButtonDim, 0, 0);
|
|
|
|
const int buttonAdjust = Constants::ScrollButtonDim + Constants::ScrollBarMargin;
|
|
ret.adjust(0, buttonAdjust, 0, -buttonAdjust);
|
|
|
|
if(sc == QStyle::SC_ScrollBarGroove)
|
|
return ret;
|
|
|
|
QRect slider = ret;
|
|
|
|
if(scroll->maximum > scroll->minimum)
|
|
{
|
|
int sliderSize = qMax(Constants::ScrollBarMin,
|
|
(scroll->pageStep * ret.height()) / (range + scroll->pageStep));
|
|
|
|
slider.setHeight(qMin(slider.height(), sliderSize));
|
|
slider.moveTop(ret.top() + (qreal(scroll->sliderPosition) / qreal(range)) *
|
|
(ret.height() - slider.height()));
|
|
}
|
|
else
|
|
{
|
|
return QRect();
|
|
}
|
|
|
|
if(sc == QStyle::SC_ScrollBarSlider)
|
|
return slider;
|
|
|
|
if(sc == QStyle::SC_ScrollBarSubPage)
|
|
return ret.adjusted(0, 0, 0, slider.top() - ret.bottom());
|
|
if(sc == QStyle::SC_ScrollBarAddPage)
|
|
return ret.adjusted(0, slider.bottom() - ret.top(), 0, 0);
|
|
}
|
|
|
|
return opt->rect;
|
|
}
|
|
else if(cc == QStyle::CC_Slider)
|
|
{
|
|
QRect ret = opt->rect;
|
|
ret.adjust(1, 1, -1, -1);
|
|
if(sc == QStyle::SC_SliderGroove)
|
|
{
|
|
int toGrooveHeightHalfReduction = (ret.height() - Constants::SliderGrooveHeight) / 2;
|
|
// QSlider code handles only moving the handle up to where it abutts the groove in either
|
|
// direction, reducing it here breaks that calculation. We'll do it visually when actually
|
|
// painting
|
|
ret.adjust(0, toGrooveHeightHalfReduction, 0, -toGrooveHeightHalfReduction);
|
|
}
|
|
else if(sc == QStyle::SC_SliderHandle)
|
|
{
|
|
const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(widget);
|
|
int sliderMin = slider->minimum();
|
|
int sliderMax = slider->maximum();
|
|
int sliderPos = slider->sliderPosition();
|
|
qreal posUNorm = (qreal)(sliderPos - sliderMin) / (qreal)(sliderMax - sliderMin);
|
|
int grooveLeft = ret.left() + Constants::SliderHandleHalfWidth;
|
|
int grooveRight = ret.right() - Constants::SliderHandleHalfWidth;
|
|
int grooveWidth = grooveRight - grooveLeft;
|
|
int sliderX = (int)(posUNorm * (qreal)grooveWidth) + grooveLeft;
|
|
// since sizes are inclusive, x-w to x+w results in 2w+1 width (w pixels either side + the x
|
|
// pixel itself), so we make this favour the right side so it's w-1 pixels to the left, the x
|
|
// pixel and then w pixels to the right, for a total of 2w
|
|
ret.setLeft(sliderX - Constants::SliderHandleHalfWidth + 1);
|
|
ret.setRight(sliderX + Constants::SliderHandleHalfWidth);
|
|
}
|
|
return ret;
|
|
}
|
|
else if(cc == QStyle::CC_ComboBox)
|
|
{
|
|
QRect rect = opt->rect;
|
|
|
|
if(sc == QStyle::SC_ComboBoxFrame || sc == QStyle::SC_ComboBoxListBoxPopup)
|
|
return rect;
|
|
|
|
const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
|
|
|
|
if(combo->subControls & QStyle::SC_ComboBoxFrame)
|
|
{
|
|
rect.adjust(Constants::ComboMargin, Constants::ComboMargin, -Constants::ComboMargin,
|
|
-Constants::ComboMargin);
|
|
}
|
|
|
|
if(sc == QStyle::SC_ComboBoxEditField)
|
|
return rect.adjusted(0, 0, -Constants::ComboArrowDim, 0);
|
|
|
|
if(sc == QStyle::SC_ComboBoxArrow)
|
|
return rect.adjusted(rect.width() - Constants::ComboArrowDim, 0, 0, 0);
|
|
}
|
|
else if(cc == QStyle::CC_SpinBox)
|
|
{
|
|
QRect rect = opt->rect;
|
|
|
|
if(sc == QStyle::SC_SpinBoxFrame)
|
|
return rect;
|
|
|
|
rect.adjust(Constants::ButtonBorder, Constants::ButtonBorder, -Constants::ButtonBorder,
|
|
-Constants::ButtonBorder);
|
|
|
|
if(sc == QStyle::SC_SpinBoxEditField)
|
|
return rect.adjusted(Constants::SpinMargin, Constants::SpinMargin,
|
|
-Constants::SpinButtonDim - Constants::SpinMargin, -Constants::SpinMargin);
|
|
|
|
rect.adjust(rect.width() - Constants::SpinButtonDim, 0, 0, 0);
|
|
|
|
int buttonHeight = rect.height() / 2;
|
|
|
|
if(sc == QStyle::SC_SpinBoxUp)
|
|
return rect.adjusted(0, 0, 0, -(rect.height() - buttonHeight));
|
|
|
|
if(sc == QStyle::SC_SpinBoxDown)
|
|
return rect.adjusted(0, rect.height() - buttonHeight, 0, 0);
|
|
|
|
return opt->rect;
|
|
}
|
|
|
|
return RDTweakedNativeStyle::subControlRect(cc, opt, sc, widget);
|
|
}
|
|
|
|
QRect RDStyle::subElementRect(SubElement element, const QStyleOption *opt, const QWidget *widget) const
|
|
{
|
|
if(element == QStyle::SE_PushButtonContents || element == QStyle::SE_PushButtonFocusRect)
|
|
{
|
|
const int border = Constants::ButtonBorder;
|
|
return opt->rect.adjusted(border, border, -2 * border, -2 * border);
|
|
}
|
|
else if(element == QStyle::SE_RadioButtonFocusRect || element == QStyle::SE_CheckBoxFocusRect)
|
|
{
|
|
return opt->rect;
|
|
}
|
|
else if(element == QStyle::SE_RadioButtonIndicator || element == QStyle::SE_CheckBoxIndicator ||
|
|
element == QStyle::SE_ItemViewItemCheckIndicator)
|
|
{
|
|
QRect ret = opt->rect;
|
|
|
|
if(element == QStyle::SE_ItemViewItemCheckIndicator)
|
|
ret.setLeft(ret.left() + 4);
|
|
ret.setWidth(Constants::CheckWidth);
|
|
|
|
int extra = ret.height() - Constants::CheckHeight;
|
|
|
|
ret.setTop(ret.top() + extra / 2);
|
|
ret.setHeight(Constants::CheckHeight);
|
|
|
|
return ret;
|
|
}
|
|
else if(element == QStyle::SE_RadioButtonContents || element == QStyle::SE_CheckBoxContents)
|
|
{
|
|
QRect ret = opt->rect;
|
|
|
|
ret.setLeft(ret.left() + Constants::CheckWidth + Constants::CheckMargin);
|
|
|
|
return ret;
|
|
}
|
|
else if(element == QStyle::SE_TabWidgetTabPane || element == QStyle::SE_TabWidgetTabContents ||
|
|
element == QStyle::SE_TabWidgetTabBar)
|
|
{
|
|
const QStyleOptionTabWidgetFrame *tabwidget =
|
|
qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt);
|
|
|
|
QRect rect = tabwidget->rect;
|
|
|
|
QRect barRect = rect;
|
|
barRect.setSize(tabwidget->tabBarSize);
|
|
|
|
barRect.setWidth(qMin(barRect.width(), tabwidget->rect.width() -
|
|
tabwidget->leftCornerWidgetSize.width() -
|
|
tabwidget->rightCornerWidgetSize.width()));
|
|
|
|
if(element == QStyle::SE_TabWidgetTabBar)
|
|
return barRect;
|
|
|
|
rect.setTop(rect.top() + barRect.height());
|
|
|
|
if(element == QStyle::SE_TabWidgetTabPane)
|
|
return rect;
|
|
|
|
const int border = Constants::TabWidgetBorder;
|
|
rect.adjust(border, 0, -border, -border);
|
|
|
|
return rect;
|
|
}
|
|
else if(element == QStyle::SE_TabBarTabLeftButton || element == QStyle::SE_TabBarTabRightButton)
|
|
{
|
|
const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt);
|
|
|
|
QRect ret = tab->rect;
|
|
|
|
if(element == SE_TabBarTabLeftButton)
|
|
{
|
|
ret.setSize(tab->leftButtonSize);
|
|
ret.moveLeft(Constants::TabMargin);
|
|
}
|
|
else if(element == SE_TabBarTabRightButton)
|
|
{
|
|
ret.setSize(tab->rightButtonSize);
|
|
ret.moveRight(tab->rect.right() - Constants::TabMargin);
|
|
}
|
|
|
|
// centre it vertically
|
|
|
|
ret.moveTop((tab->rect.height() - ret.height()) / 2);
|
|
|
|
return ret;
|
|
}
|
|
else if(element == QStyle::SE_HeaderLabel)
|
|
{
|
|
return opt->rect;
|
|
}
|
|
|
|
return RDTweakedNativeStyle::subElementRect(element, opt, widget);
|
|
}
|
|
|
|
QSize RDStyle::sizeFromContents(ContentsType type, const QStyleOption *opt, const QSize &size,
|
|
const QWidget *widget) const
|
|
{
|
|
if(type == CT_PushButton || type == CT_ToolButton)
|
|
{
|
|
const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt);
|
|
const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
|
|
|
|
QSize ret = size;
|
|
|
|
// only for pushbuttons with text, ensure a minimum size
|
|
if(type == CT_PushButton && button && !button->text.isEmpty())
|
|
{
|
|
ret.setWidth(qMax(50, ret.width()));
|
|
ret.setHeight(qMax(15, ret.height()));
|
|
}
|
|
else if(type == CT_ToolButton && toolbutton)
|
|
{
|
|
ret = adjustToolButtonSize(toolbutton, size, widget);
|
|
}
|
|
|
|
// add margin and border
|
|
ret.setHeight(ret.height() + Constants::ButtonMargin + Constants::ButtonBorder * 2);
|
|
ret.setWidth(ret.width() + Constants::ButtonMargin + Constants::ButtonBorder * 2);
|
|
|
|
return ret;
|
|
}
|
|
else if(type == CT_TabBarTab)
|
|
{
|
|
// have a maximum size for tabs
|
|
return size.boundedTo(QSize(Constants::TabMaxWidth, INT_MAX))
|
|
.expandedTo(QSize(Constants::TabMinWidth, 0)) +
|
|
QSize(Constants::TabMargin * 2, 0);
|
|
}
|
|
else if(type == CT_CheckBox || type == CT_RadioButton)
|
|
{
|
|
const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt);
|
|
|
|
QSize ret = size;
|
|
|
|
// set minimum height for check/radio
|
|
ret.setHeight(qMax(ret.height(), Constants::CheckHeight) + Constants::HighlightBorder);
|
|
|
|
// add width for the check/radio and a gap before the text/icon
|
|
ret.setWidth(Constants::CheckWidth + Constants::CheckMargin + ret.width());
|
|
|
|
return ret;
|
|
}
|
|
else if(type == CT_LineEdit)
|
|
{
|
|
QSize ret = size;
|
|
|
|
const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt);
|
|
|
|
if(frame && frame->lineWidth > 0)
|
|
{
|
|
ret.setWidth(Constants::ButtonBorder * 2 + ret.width());
|
|
ret.setHeight(Constants::ButtonBorder * 2 + ret.height());
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
else if(type == CT_GroupBox || type == CT_ScrollBar || type == CT_ProgressBar || type == CT_Splitter)
|
|
{
|
|
return size;
|
|
}
|
|
else if(type == CT_ComboBox)
|
|
{
|
|
QSize ret = size;
|
|
|
|
// make room for both the down arrow button and a potential scrollbar
|
|
ret.setWidth(Constants::ButtonBorder * 2 + Constants::ComboMargin * 2 +
|
|
Constants::ComboArrowDim + Constants::ScrollButtonDim + ret.width());
|
|
ret.setHeight(Constants::ButtonBorder * 2 + Constants::ComboMargin * 2 + ret.height());
|
|
|
|
return ret;
|
|
}
|
|
else if(type == CT_SpinBox)
|
|
{
|
|
QSize ret = size;
|
|
|
|
const int margin = Constants::SpinMargin + Constants::ButtonBorder;
|
|
ret.setWidth(margin * 2 + Constants::SpinButtonDim + ret.width());
|
|
ret.setHeight(margin * 2 + ret.height());
|
|
|
|
return ret;
|
|
}
|
|
else if(type == CT_MenuItem)
|
|
{
|
|
QSize ret = size;
|
|
|
|
ret.setWidth(ret.width() + 2 * Constants::MenuBarMargin);
|
|
ret.setHeight(ret.height() + Constants::MenuBarMargin);
|
|
|
|
const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt);
|
|
|
|
// add more room for items with shortcuts
|
|
if(menuitem->text.contains(QLatin1Char('\t')))
|
|
ret.setWidth(ret.width() + 4 * Constants::MenuBarMargin);
|
|
|
|
// add room for an icon
|
|
if(menuitem->maxIconWidth || menuitem->menuHasCheckableItems)
|
|
ret.setWidth(ret.width() + Constants::MenuBarMargin +
|
|
std::max(menuitem->maxIconWidth, Constants::MenuBarIconSize));
|
|
|
|
if(menuitem->menuItemType == QStyleOptionMenuItem::SubMenu)
|
|
ret.setWidth(ret.width() + Constants::MenuSubmenuWidth);
|
|
|
|
ret = ret.expandedTo(QSize(Constants::MenuBarMinimumWidth, 0));
|
|
|
|
return ret;
|
|
}
|
|
else if(type == CT_MenuBarItem)
|
|
{
|
|
const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt);
|
|
int iconSize = pixelMetric(QStyle::PM_SmallIconSize, opt, widget);
|
|
QSize sz = menuitem->fontMetrics.size(Qt::TextShowMnemonic, menuitem->text);
|
|
|
|
if(!menuitem->icon.isNull() || menuitem->checkType != QStyleOptionMenuItem::NotCheckable)
|
|
{
|
|
sz.setWidth(sz.width() + Constants::MenuBarMargin + iconSize);
|
|
sz = sz.expandedTo(QSize(1, iconSize));
|
|
}
|
|
|
|
sz += QSize(Constants::MenuBarMargin * 2, Constants::MenuBarMargin);
|
|
|
|
return sz;
|
|
}
|
|
else if(type == CT_MenuBar || type == CT_Menu)
|
|
{
|
|
return size;
|
|
}
|
|
else if(type == CT_HeaderSection)
|
|
{
|
|
const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
|
|
int iconSize = pixelMetric(QStyle::PM_SmallIconSize, opt, widget);
|
|
QSize sz = header->fontMetrics.size(Qt::TextShowMnemonic, header->text);
|
|
|
|
if(!header->icon.isNull())
|
|
{
|
|
sz.setWidth(sz.width() + Constants::ItemHeaderMargin + iconSize);
|
|
sz = sz.expandedTo(QSize(1, iconSize));
|
|
}
|
|
|
|
if(header->sortIndicator != QStyleOptionHeader::None)
|
|
{
|
|
sz += QSize(Constants::ItemHeaderMargin + Constants::SpinButtonDim, 0);
|
|
}
|
|
|
|
sz += QSize(Constants::ItemHeaderMargin * 2, Constants::ItemHeaderMargin);
|
|
|
|
return sz;
|
|
}
|
|
|
|
return RDTweakedNativeStyle::sizeFromContents(type, opt, size, widget);
|
|
}
|
|
|
|
int RDStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
|
|
{
|
|
if(metric == QStyle::PM_ButtonShiftHorizontal || metric == QStyle::PM_ButtonShiftVertical)
|
|
{
|
|
if(opt && (opt->state & State_AutoRaise) == 0)
|
|
return 1;
|
|
}
|
|
|
|
if(metric == PM_ScrollBarExtent)
|
|
return Constants::ScrollButtonDim + 2;
|
|
// not used for rendering but just as an estimate of how small a progress bar can get
|
|
if(metric == PM_ProgressBarChunkWidth)
|
|
return 10;
|
|
|
|
if(metric == PM_SplitterWidth)
|
|
return 5;
|
|
|
|
if(metric == PM_MenuBarHMargin || metric == PM_MenuBarVMargin)
|
|
return 1;
|
|
|
|
if(metric == PM_MenuBarPanelWidth || metric == PM_MenuPanelWidth)
|
|
return 1;
|
|
|
|
if(metric == PM_MenuHMargin || metric == PM_MenuVMargin)
|
|
return 0;
|
|
|
|
if(metric == PM_MenuBarItemSpacing)
|
|
return 0;
|
|
|
|
if(metric == PM_MenuDesktopFrameWidth)
|
|
return 0;
|
|
|
|
if(metric == PM_SubMenuOverlap)
|
|
return 0;
|
|
|
|
if(metric == PM_MenuButtonIndicator)
|
|
return Constants::ComboArrowDim;
|
|
|
|
if(metric == PM_TabBarTabOverlap)
|
|
return 0;
|
|
|
|
if(metric == PM_TabBarTabHSpace)
|
|
return Constants::TabMargin;
|
|
|
|
if(metric == PM_IndicatorWidth)
|
|
return Constants::CheckWidth + Constants::CheckMargin;
|
|
|
|
if(metric == PM_IndicatorHeight)
|
|
return Constants::CheckHeight + Constants::CheckMargin;
|
|
|
|
return RDTweakedNativeStyle::pixelMetric(metric, opt, widget);
|
|
}
|
|
|
|
int RDStyle::styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget,
|
|
QStyleHintReturn *returnData) const
|
|
{
|
|
if(stylehint == QStyle::SH_EtchDisabledText || stylehint == QStyle::SH_DitherDisabledText)
|
|
return 0;
|
|
|
|
if(stylehint == QStyle::SH_ComboBox_PopupFrameStyle)
|
|
return QFrame::StyledPanel | QFrame::Plain;
|
|
|
|
if(stylehint == QStyle::SH_ComboBox_Popup)
|
|
return 0;
|
|
|
|
if(stylehint == SH_ToolTipLabel_Opacity)
|
|
return 255;
|
|
|
|
if(stylehint == SH_UnderlineShortcut)
|
|
return 0;
|
|
|
|
if(stylehint == SH_MessageBox_CenterButtons)
|
|
return 0;
|
|
if(stylehint == SH_ProgressDialog_CenterCancelButton)
|
|
return 1;
|
|
|
|
if(stylehint == SH_ProgressDialog_TextLabelAlignment)
|
|
return Qt::AlignCenter;
|
|
|
|
if(stylehint == SH_Splitter_OpaqueResize)
|
|
return 1;
|
|
|
|
if(stylehint == SH_MenuBar_MouseTracking || stylehint == SH_Menu_MouseTracking ||
|
|
stylehint == SH_MenuBar_AltKeyNavigation || stylehint == SH_MainWindow_SpaceBelowMenuBar)
|
|
return 1;
|
|
|
|
if(stylehint == SH_Menu_FlashTriggeredItem || stylehint == SH_Menu_KeyboardSearch ||
|
|
stylehint == SH_Menu_FadeOutOnHide || stylehint == SH_Menu_AllowActiveAndDisabled)
|
|
return 0;
|
|
|
|
if(stylehint == SH_Menu_SubMenuPopupDelay || stylehint == SH_Menu_SubMenuSloppyCloseTimeout)
|
|
return 500;
|
|
|
|
if(stylehint == SH_Menu_SubMenuResetWhenReenteringParent ||
|
|
stylehint == SH_Menu_SubMenuDontStartSloppyOnLeave)
|
|
return 0;
|
|
|
|
if(stylehint == SH_Menu_SubMenuUniDirection || stylehint == SH_Menu_SubMenuUniDirectionFailCount)
|
|
return 0;
|
|
|
|
if(stylehint == SH_Menu_SubMenuSloppySelectOtherActions)
|
|
return 1;
|
|
|
|
if(stylehint == QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren)
|
|
return 1;
|
|
|
|
if(stylehint == QStyle::SH_TabBar_ElideMode)
|
|
return Qt::ElideRight;
|
|
|
|
return RDTweakedNativeStyle::styleHint(stylehint, opt, widget, returnData);
|
|
}
|
|
|
|
QIcon RDStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *opt,
|
|
const QWidget *widget) const
|
|
{
|
|
return RDTweakedNativeStyle::standardIcon(standardIcon, opt, widget);
|
|
}
|
|
|
|
void RDStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *opt,
|
|
QPainter *p, const QWidget *widget) const
|
|
{
|
|
// let the tweaked native style render autoraise tool buttons
|
|
if(control == QStyle::CC_ToolButton && (opt->state & State_AutoRaise) == 0)
|
|
{
|
|
drawRoundedRectBorder(opt, p, widget, QPalette::Button, true);
|
|
|
|
const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
|
|
|
|
QStyleOptionToolButton labelTextIcon = *toolbutton;
|
|
labelTextIcon.rect = subControlRect(control, opt, SC_ToolButton, widget);
|
|
|
|
// draw the label text/icon
|
|
proxy()->drawControl(CE_ToolButtonLabel, &labelTextIcon, p, widget);
|
|
|
|
// draw the menu arrow, if there is one
|
|
if(shouldDrawToolButtonMenuArrow(toolbutton))
|
|
{
|
|
QStyleOptionToolButton menu = *toolbutton;
|
|
menu.rect = subControlRect(control, opt, SC_ToolButtonMenu, widget);
|
|
proxy()->drawPrimitive(PE_IndicatorArrowDown, &menu, p, widget);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(control == CC_GroupBox)
|
|
{
|
|
// when drawing the border don't apply any states intended for the checkbox
|
|
QStyleOptionComplex frame = *opt;
|
|
frame.state &=
|
|
~(QStyle::State_Sunken | QStyle::State_MouseOver | QStyle::State_On | QStyle::State_Off);
|
|
drawRoundedRectBorder(&frame, p, widget, QPalette::Window, false);
|
|
|
|
const QStyleOptionGroupBox *group = qstyleoption_cast<const QStyleOptionGroupBox *>(opt);
|
|
|
|
QRect labelRect = proxy()->subControlRect(CC_GroupBox, opt, QStyle::SC_GroupBoxLabel, widget);
|
|
|
|
labelRect.adjust(Constants::GroupHMargin, Constants::GroupVMargin, Constants::GroupHMargin,
|
|
Constants::GroupVMargin);
|
|
|
|
QColor textColor = group->textColor;
|
|
QPalette::ColorRole penRole = QPalette::WindowText;
|
|
|
|
if(textColor.isValid())
|
|
{
|
|
p->setPen(textColor);
|
|
penRole = QPalette::NoRole;
|
|
}
|
|
|
|
proxy()->drawItemText(p, labelRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextHideMnemonic,
|
|
group->palette, group->state & State_Enabled, group->text, penRole);
|
|
|
|
labelRect.setRight(subControlRect(CC_GroupBox, opt, QStyle::SC_GroupBoxFrame, widget).right());
|
|
labelRect.adjust(-Constants::GroupHMargin / 2, 0, -Constants::GroupHMargin, 0);
|
|
|
|
p->setPen(QPen(opt->palette.brush(m_Scheme == Light ? QPalette::Mid : QPalette::Midlight), 1.0));
|
|
p->drawLine(labelRect.bottomLeft(), labelRect.bottomRight());
|
|
|
|
if(opt->subControls & QStyle::SC_GroupBoxCheckBox)
|
|
{
|
|
QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox, widget);
|
|
|
|
QStyleOptionButton box;
|
|
(QStyleOption &)box = *(QStyleOption *)opt;
|
|
box.rect = checkBoxRect;
|
|
proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, p, widget);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CC_ScrollBar)
|
|
{
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
p->fillRect(opt->rect, opt->palette.brush(QPalette::Window));
|
|
|
|
QBrush hoverBrush;
|
|
QBrush sliderBrush;
|
|
|
|
if(m_Scheme == Light)
|
|
{
|
|
sliderBrush = opt->palette.brush(QPalette::Dark);
|
|
hoverBrush = opt->palette.brush(QPalette::Midlight);
|
|
}
|
|
else
|
|
{
|
|
sliderBrush = opt->palette.brush(QPalette::Text);
|
|
hoverBrush = opt->palette.brush(QPalette::Light);
|
|
}
|
|
|
|
const QStyleOptionSlider *scroll = qstyleoption_cast<const QStyleOptionSlider *>(opt);
|
|
|
|
if(scroll)
|
|
{
|
|
const int margin = Constants::ScrollBarMargin;
|
|
|
|
{
|
|
p->setPen(QPen(sliderBrush, 2.5));
|
|
|
|
QRectF rect = proxy()->subControlRect(CC_ScrollBar, opt, QStyle::SC_ScrollBarSubLine, widget);
|
|
|
|
rect = rect.adjusted(margin, margin, -margin, -margin);
|
|
|
|
if(scroll->orientation == Qt::Vertical)
|
|
rect.moveTop(rect.top() + rect.height() / 4);
|
|
else
|
|
rect.moveLeft(rect.left() + rect.width() / 4);
|
|
|
|
QPainterPath path;
|
|
QPolygonF poly;
|
|
|
|
if(scroll->orientation == Qt::Vertical)
|
|
{
|
|
QPointF pt = rect.center();
|
|
pt.setX(rect.left());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setY(rect.top());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setX(rect.right());
|
|
poly << pt;
|
|
}
|
|
else
|
|
{
|
|
QPointF pt = rect.center();
|
|
pt.setY(rect.top());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setX(rect.left());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setY(rect.bottom());
|
|
poly << pt;
|
|
}
|
|
|
|
path.addPolygon(poly);
|
|
|
|
p->drawPath(path);
|
|
}
|
|
|
|
{
|
|
p->setPen(QPen(sliderBrush, 2.5));
|
|
|
|
QRectF rect = proxy()->subControlRect(CC_ScrollBar, opt, QStyle::SC_ScrollBarAddLine, widget);
|
|
|
|
rect = rect.adjusted(margin, margin, -margin, -margin);
|
|
|
|
if(scroll->orientation == Qt::Vertical)
|
|
rect.moveBottom(rect.bottom() - rect.height() / 4);
|
|
else
|
|
rect.moveRight(rect.right() - rect.width() / 4);
|
|
|
|
QPainterPath path;
|
|
QPolygonF poly;
|
|
|
|
if(scroll->orientation == Qt::Vertical)
|
|
{
|
|
QPointF pt = rect.center();
|
|
pt.setX(rect.left());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setY(rect.bottom());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setX(rect.right());
|
|
poly << pt;
|
|
}
|
|
else
|
|
{
|
|
QPointF pt = rect.center();
|
|
pt.setY(rect.top());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setX(rect.right());
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setY(rect.bottom());
|
|
poly << pt;
|
|
}
|
|
|
|
path.addPolygon(poly);
|
|
|
|
p->drawPath(path);
|
|
}
|
|
}
|
|
|
|
QStyle::State activeHover = State_MouseOver | State_Active | State_Enabled;
|
|
if((opt->state & activeHover) == activeHover)
|
|
{
|
|
QRect hoverRect =
|
|
proxy()
|
|
->subControlRect(CC_ScrollBar, opt, QStyle::SC_ScrollBarAddPage, widget)
|
|
.united(subControlRect(CC_ScrollBar, opt, QStyle::SC_ScrollBarSubPage, widget));
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(hoverRect, Constants::ScrollBarRadius, Constants::ScrollBarRadius);
|
|
|
|
p->fillPath(path, hoverBrush);
|
|
}
|
|
|
|
QRect slider = proxy()->subControlRect(CC_ScrollBar, opt, QStyle::SC_ScrollBarSlider, widget);
|
|
|
|
if(slider.isValid() && (opt->state & State_Enabled))
|
|
{
|
|
QPainterPath path;
|
|
path.addRoundedRect(slider, Constants::ScrollBarRadius, Constants::ScrollBarRadius);
|
|
|
|
if(opt->state & State_Sunken)
|
|
p->fillPath(path, opt->palette.brush(QPalette::Highlight));
|
|
else
|
|
p->fillPath(path, sliderBrush);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CC_Slider)
|
|
{
|
|
QRect grooveRect = subControlRect(control, opt, QStyle::SC_SliderGroove, widget);
|
|
p->drawLine(QLine(grooveRect.x() + Constants::SliderHandleHalfWidth + 1,
|
|
grooveRect.y() + grooveRect.height() / 2,
|
|
grooveRect.right() - Constants::SliderHandleHalfWidth,
|
|
grooveRect.y() + grooveRect.height() / 2));
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
QRect handleRect = subControlRect(control, opt, QStyle::SC_SliderHandle, widget);
|
|
QBrush handleBrush = (m_Scheme == Light) ? opt->palette.brush(QPalette::Dark)
|
|
: opt->palette.brush(QPalette::Text);
|
|
QPainterPath path;
|
|
path.addRoundedRect(handleRect, Constants::SliderHandleCornerRadius,
|
|
Constants::SliderHandleCornerRadius);
|
|
p->fillPath(path, handleBrush);
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CC_ComboBox)
|
|
{
|
|
const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
|
|
|
|
if(combo->subControls & QStyle::SC_ComboBoxFrame)
|
|
{
|
|
drawRoundedRectBorder(opt, p, widget, QPalette::Base, false);
|
|
}
|
|
|
|
QRectF rect = proxy()->subControlRect(control, opt, QStyle::SC_ComboBoxArrow, widget);
|
|
|
|
if(!(combo->subControls & QStyle::SC_ComboBoxFrame))
|
|
p->fillRect(rect, opt->palette.brush(QPalette::Base));
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
rect.setTop(rect.top() + rect.height() / 2.0 - rect.width() / 2.0);
|
|
rect.setHeight(rect.width());
|
|
|
|
{
|
|
qreal penWidth = 1.5;
|
|
p->setPen(QPen(outlineBrush(opt->palette), penWidth));
|
|
|
|
QPainterPath path;
|
|
QPolygonF poly;
|
|
|
|
QPointF pt = rect.center();
|
|
pt.setX(rect.left() + penWidth);
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setY(rect.bottom() - penWidth);
|
|
poly << pt;
|
|
|
|
pt = rect.center();
|
|
pt.setX(rect.right() - penWidth);
|
|
poly << pt;
|
|
|
|
path.addPolygon(poly);
|
|
|
|
p->drawPath(path);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CC_SpinBox)
|
|
{
|
|
{
|
|
QStyleOption o = *opt;
|
|
o.state &= ~State_Sunken;
|
|
drawRoundedRectBorder(&o, p, widget, QPalette::Base, false);
|
|
}
|
|
|
|
QRect rect = opt->rect;
|
|
rect.adjust(Constants::ButtonBorder, Constants::ButtonBorder, -Constants::ButtonBorder,
|
|
-Constants::ButtonBorder);
|
|
|
|
rect.adjust(0, 0, -Constants::SpinButtonDim, 0);
|
|
|
|
p->save();
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
|
|
p->drawLine(rect.topRight(), rect.bottomRight());
|
|
|
|
rect = proxy()->subControlRect(control, opt, QStyle::SC_SpinBoxUp, widget);
|
|
|
|
p->setClipRect(rect);
|
|
|
|
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt);
|
|
|
|
{
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
if((opt->state & State_Sunken) && (spinbox->activeSubControls & QStyle::SC_SpinBoxUp))
|
|
p->fillPath(path, opt->palette.brush(QPalette::Midlight));
|
|
else
|
|
p->fillPath(path, opt->palette.brush(QPalette::Button));
|
|
}
|
|
|
|
p->drawLine(rect.bottomLeft(), rect.bottomRight());
|
|
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
QPalette::ColorGroup group = QPalette::Disabled;
|
|
if(spinbox->stepEnabled & QAbstractSpinBox::StepUpEnabled)
|
|
group = QPalette::Normal;
|
|
|
|
qreal penWidth = 1.5;
|
|
p->setPen(QPen(opt->palette.brush(group, QPalette::WindowText), penWidth));
|
|
|
|
{
|
|
QRectF arrowRect = QRectF(rect);
|
|
arrowRect.adjust(0.5, 0.5, -0.5, 0.5);
|
|
|
|
QPainterPath path;
|
|
QPolygonF poly;
|
|
|
|
QPointF pt = arrowRect.center();
|
|
pt.setX(arrowRect.left() + penWidth);
|
|
poly << pt;
|
|
|
|
pt = arrowRect.center();
|
|
pt.setY(arrowRect.top() + penWidth);
|
|
poly << pt;
|
|
|
|
pt = arrowRect.center();
|
|
pt.setX(arrowRect.right() - penWidth);
|
|
poly << pt;
|
|
|
|
path.addPolygon(poly);
|
|
|
|
p->drawPath(path);
|
|
}
|
|
|
|
rect = proxy()->subControlRect(control, opt, QStyle::SC_SpinBoxDown, widget);
|
|
|
|
p->setClipRect(rect);
|
|
|
|
{
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
if((opt->state & State_Sunken) && (spinbox->activeSubControls & QStyle::SC_SpinBoxDown))
|
|
p->fillPath(path, opt->palette.brush(QPalette::Midlight));
|
|
else
|
|
p->fillPath(path, opt->palette.brush(QPalette::Button));
|
|
}
|
|
|
|
group = QPalette::Disabled;
|
|
if(spinbox->stepEnabled & QAbstractSpinBox::StepDownEnabled)
|
|
group = QPalette::Normal;
|
|
|
|
p->setPen(QPen(opt->palette.brush(group, QPalette::WindowText), penWidth));
|
|
|
|
{
|
|
QRectF arrowRect = QRectF(rect);
|
|
arrowRect.adjust(0.5, -0.5, -0.5, -0.5);
|
|
|
|
QPainterPath path;
|
|
QPolygonF poly;
|
|
|
|
QPointF pt = arrowRect.center();
|
|
pt.setX(arrowRect.left() + penWidth);
|
|
poly << pt;
|
|
|
|
pt = arrowRect.center();
|
|
pt.setY(arrowRect.bottom() - penWidth);
|
|
poly << pt;
|
|
|
|
pt = arrowRect.center();
|
|
pt.setX(arrowRect.right() - penWidth);
|
|
poly << pt;
|
|
|
|
path.addPolygon(poly);
|
|
|
|
p->drawPath(path);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
|
|
return RDTweakedNativeStyle::drawComplexControl(control, opt, p, widget);
|
|
}
|
|
|
|
static void drawX(const QStyleOption *opt, QPainter *p, const QRectF &rect)
|
|
{
|
|
QPainterPath checkpath;
|
|
QPolygonF poly;
|
|
|
|
// Left side:
|
|
//
|
|
// X
|
|
// | CheckCornerSize
|
|
// X
|
|
// \\ innerSizeX, innerSizeY
|
|
// \\ (width and height)
|
|
// CheckHeight X
|
|
// /
|
|
// /
|
|
// X
|
|
// | CheckCornerSize
|
|
// X
|
|
|
|
// Top side:
|
|
//
|
|
// X---X X----X
|
|
// \\ /
|
|
// \\ /
|
|
// X
|
|
|
|
Q_ASSERT(rect.height() == rect.width());
|
|
|
|
const float innerSize = float(rect.height() - Constants::CheckCornerSize * 2) / 2.0f;
|
|
|
|
const float totalSize = innerSize * 2 + Constants::CheckCornerSize * 2;
|
|
Q_ASSERT(totalSize == rect.height());
|
|
|
|
// left edge
|
|
QPointF pt = rect.topLeft();
|
|
poly << pt;
|
|
pt.setY(pt.y() + Constants::CheckCornerSize);
|
|
poly << pt;
|
|
pt.setY(pt.y() + innerSize);
|
|
pt.setX(pt.x() + innerSize);
|
|
poly << pt;
|
|
pt.setY(pt.y() + innerSize);
|
|
pt.setX(pt.x() - innerSize);
|
|
poly << pt;
|
|
pt.setY(pt.y() + Constants::CheckCornerSize);
|
|
poly << pt;
|
|
|
|
// bottom edge
|
|
pt.setX(pt.x() + Constants::CheckCornerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() + innerSize);
|
|
pt.setY(pt.y() - innerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() + innerSize);
|
|
pt.setY(pt.y() + innerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() + Constants::CheckCornerSize);
|
|
poly << pt;
|
|
|
|
// right edge
|
|
pt.setY(pt.y() - Constants::CheckCornerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() - innerSize);
|
|
pt.setY(pt.y() - innerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() + innerSize);
|
|
pt.setY(pt.y() - innerSize);
|
|
poly << pt;
|
|
pt.setY(pt.y() - Constants::CheckCornerSize);
|
|
poly << pt;
|
|
|
|
// top edge
|
|
pt.setX(pt.x() - Constants::CheckCornerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() - innerSize);
|
|
pt.setY(pt.y() + innerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() - innerSize);
|
|
pt.setY(pt.y() - innerSize);
|
|
poly << pt;
|
|
pt.setX(pt.x() - Constants::CheckCornerSize);
|
|
poly << pt;
|
|
|
|
checkpath.addPolygon(poly);
|
|
p->fillPath(checkpath, opt->palette.brush(QPalette::ButtonText));
|
|
}
|
|
|
|
void RDStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *opt, QPainter *p,
|
|
const QWidget *widget) const
|
|
{
|
|
if(element == QStyle::PE_PanelLineEdit)
|
|
{
|
|
const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt);
|
|
|
|
if(frame && frame->lineWidth > 0)
|
|
{
|
|
QStyleOption o = *opt;
|
|
o.state &= ~State_Sunken;
|
|
drawRoundedRectBorder(&o, p, widget, QPalette::Base, false);
|
|
}
|
|
else
|
|
{
|
|
p->fillRect(opt->rect.adjusted(0, 0, -1, -1), opt->palette.brush(QPalette::Base));
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_Frame)
|
|
{
|
|
const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt);
|
|
|
|
QStyleOptionFrame frameOpt = *frame;
|
|
frameOpt.frameShape = QFrame::Panel;
|
|
proxy()->drawControl(CE_ShapedFrame, &frameOpt, p, widget);
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_FrameFocusRect)
|
|
{
|
|
// don't draw focus rects
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_FrameStatusBarItem)
|
|
{
|
|
// don't draw any panel around status bar items
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_PanelTipLabel)
|
|
{
|
|
QPen oldPen = p->pen();
|
|
|
|
p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 0));
|
|
p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
|
|
|
|
p->setPen(oldPen);
|
|
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_FrameMenu)
|
|
{
|
|
drawRoundedRectBorder(opt, p, widget, QPalette::NoRole, false);
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_PanelMenu)
|
|
{
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_PanelMenuBar)
|
|
{
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_FrameTabBarBase)
|
|
{
|
|
QPen oldPen = p->pen();
|
|
p->setPen(QPen(outlineBrush(opt->palette), 0));
|
|
p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
|
|
p->setPen(oldPen);
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_FrameTabWidget)
|
|
{
|
|
const QStyleOptionTabWidgetFrame *tabwidget =
|
|
qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt);
|
|
|
|
QRegion region;
|
|
|
|
// include the whole rect, *except* the part just under the tabs. The border under them is drawn
|
|
// as part of the tab itself so the selected tab can avoid it
|
|
region += opt->rect;
|
|
|
|
QRect topRect = opt->rect;
|
|
topRect.adjust(1, 0, -1, 0);
|
|
topRect.setHeight(2);
|
|
|
|
region -= topRect;
|
|
|
|
p->save();
|
|
|
|
p->setClipRegion(region);
|
|
|
|
QStyleOptionTabWidgetFrame border = *tabwidget;
|
|
border.state &= ~State_HasFocus;
|
|
drawRoundedRectBorder(&border, p, widget, QPalette::NoRole, false);
|
|
|
|
p->restore();
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
|
|
// draw vertical lines down from top left/right corners to straighten it.
|
|
p->drawLine(opt->rect.topLeft(), opt->rect.topLeft() + QPoint(0, 1));
|
|
p->drawLine(opt->rect.topRight(), opt->rect.topRight() + QPoint(0, 1));
|
|
|
|
// draw a vertical line to complete the tab bottoms
|
|
QRect tabBottomLine = opt->rect.adjusted(0, -1, 0, -opt->rect.height());
|
|
p->drawLine(tabBottomLine.topLeft(), tabBottomLine.topRight());
|
|
|
|
return;
|
|
}
|
|
else if(element == QStyle::PE_IndicatorViewItemCheck || element == QStyle::PE_IndicatorCheckBox)
|
|
{
|
|
QRect rect = opt->rect;
|
|
int w = rect.width();
|
|
int h = rect.height();
|
|
if(w < h)
|
|
{
|
|
int padding = (h - w) / 2;
|
|
rect.setHeight(w);
|
|
rect.adjust(0, padding, 0, padding);
|
|
}
|
|
else if(h < w)
|
|
{
|
|
int padding = (w - h) / 2;
|
|
rect.setWidth(h);
|
|
rect.adjust(padding, 0, padding, 0);
|
|
}
|
|
|
|
QPen outlinePen(outlineBrush(opt->palette), 1.0);
|
|
|
|
p->save();
|
|
p->setClipRect(rect);
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
rect.adjust(0, 0, -1, -1);
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
p->setPen(outlinePen);
|
|
p->drawPath(path.translated(QPointF(0.5, 0.5)));
|
|
|
|
rect = rect.adjusted(2, 2, -1, -1);
|
|
|
|
if(opt->state & State_On)
|
|
{
|
|
drawX(opt, p, rect);
|
|
}
|
|
else if(opt->state & State_NoChange)
|
|
{
|
|
QBrush brush = opt->palette.brush(QPalette::ButtonText);
|
|
brush.setTexture(m_PartialCheckPattern);
|
|
p->fillRect(rect, brush);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(element == PE_PanelItemViewItem)
|
|
{
|
|
const QStyleOptionViewItem *viewitem = qstyleoption_cast<const QStyleOptionViewItem *>(opt);
|
|
|
|
QPalette::ColorGroup group = QPalette::Normal;
|
|
|
|
if((widget && !widget->isEnabled()) || !(viewitem->state & QStyle::State_Enabled))
|
|
group = QPalette::Disabled;
|
|
else if(!(viewitem->state & QStyle::State_Active))
|
|
group = QPalette::Inactive;
|
|
|
|
if(viewitem->state & QStyle::State_Selected)
|
|
{
|
|
if(viewitem->backgroundBrush.style() != Qt::NoBrush)
|
|
{
|
|
p->fillRect(viewitem->rect, viewitem->backgroundBrush);
|
|
// If we have a custom color, use the selection color at half opacity over the custom color
|
|
QColor col = viewitem->palette.color(group, QPalette::Highlight);
|
|
col.setAlphaF(0.5f);
|
|
p->fillRect(viewitem->rect, QBrush(col));
|
|
}
|
|
else
|
|
{
|
|
p->fillRect(viewitem->rect, viewitem->palette.brush(group, QPalette::Highlight));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(viewitem->backgroundBrush.style() != Qt::NoBrush)
|
|
p->fillRect(viewitem->rect, viewitem->backgroundBrush);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
RDTweakedNativeStyle::drawPrimitive(element, opt, p, widget);
|
|
}
|
|
|
|
const QBrush &RDStyle::outlineBrush(const QPalette &pal, QPalette::ColorRole role) const
|
|
{
|
|
if(role == QPalette::Text || role == QPalette::WindowText)
|
|
return m_Scheme == Light ? pal.brush(QPalette::WindowText) : pal.brush(QPalette::Light);
|
|
|
|
return pal.brush(role);
|
|
}
|
|
|
|
void RDStyle::drawControl(ControlElement control, const QStyleOption *opt, QPainter *p,
|
|
const QWidget *widget) const
|
|
{
|
|
if(control == CE_PushButton)
|
|
{
|
|
drawRoundedRectBorder(opt, p, widget, QPalette::Button, true);
|
|
|
|
QCommonStyle::drawControl(CE_PushButtonLabel, opt, p, widget);
|
|
return;
|
|
}
|
|
else if(control == CE_PushButtonBevel)
|
|
{
|
|
drawRoundedRectBorder(opt, p, widget, QPalette::Button, true);
|
|
return;
|
|
}
|
|
else if(control == CE_RadioButton)
|
|
{
|
|
const QStyleOptionButton *radiobutton = qstyleoption_cast<const QStyleOptionButton *>(opt);
|
|
if(radiobutton)
|
|
{
|
|
QRectF rect = proxy()->subElementRect(SE_CheckBoxIndicator, opt, widget);
|
|
|
|
rect = rect.adjusted(1.5, 1.5, -1, -1);
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
if(opt->state & State_HasFocus)
|
|
{
|
|
QPainterPath highlight;
|
|
highlight.addEllipse(rect.center(), rect.width() / 2.0 + 1.25, rect.height() / 2.0 + 1.25);
|
|
|
|
p->fillPath(highlight, opt->palette.brush(QPalette::Highlight));
|
|
}
|
|
|
|
QPainterPath path;
|
|
path.addEllipse(rect.center(), rect.width() / 2.0, rect.height() / 2.0);
|
|
|
|
p->fillPath(path, outlineBrush(opt->palette));
|
|
|
|
rect = rect.adjusted(1, 1, -1, -1);
|
|
|
|
path = QPainterPath();
|
|
path.addEllipse(rect.center(), rect.width() / 2.0, rect.height() / 2.0);
|
|
|
|
if(opt->state & State_Sunken)
|
|
p->fillPath(path, opt->palette.brush(QPalette::Midlight));
|
|
else
|
|
p->fillPath(path, opt->palette.brush(QPalette::Button));
|
|
|
|
if(opt->state & State_On)
|
|
{
|
|
rect = rect.adjusted(1.5, 1.5, -1.5, -1.5);
|
|
|
|
path = QPainterPath();
|
|
path.addEllipse(rect.center(), rect.width() / 2.0, rect.height() / 2.0);
|
|
|
|
p->fillPath(path, opt->palette.brush(QPalette::ButtonText));
|
|
}
|
|
|
|
p->restore();
|
|
|
|
QStyleOptionButton labelText = *radiobutton;
|
|
labelText.rect = proxy()->subElementRect(SE_RadioButtonContents, &labelText, widget);
|
|
drawControl(CE_RadioButtonLabel, &labelText, p, widget);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(control == CE_CheckBox)
|
|
{
|
|
const QStyleOptionButton *checkbox = qstyleoption_cast<const QStyleOptionButton *>(opt);
|
|
if(checkbox)
|
|
{
|
|
QRectF rect = proxy()->subElementRect(SE_CheckBoxIndicator, opt, widget).adjusted(1, 1, -1, -1);
|
|
float w = rect.width();
|
|
float h = rect.height();
|
|
if(w < h)
|
|
{
|
|
int padding = (h - w) * 0.5;
|
|
rect.setHeight(w);
|
|
rect.adjust(0, padding, 0, padding);
|
|
}
|
|
else if(h < w)
|
|
{
|
|
int padding = (w - h) * 0.5;
|
|
rect.setWidth(h);
|
|
rect.adjust(padding, 0, padding, 0);
|
|
}
|
|
|
|
QPen outlinePen(outlineBrush(opt->palette), 1.0);
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
if(opt->state & State_HasFocus)
|
|
{
|
|
QPainterPath highlight;
|
|
highlight.addRoundedRect(rect.adjusted(-0.5, -0.5, 0.5, 0.5), 1.0, 1.0);
|
|
|
|
p->strokePath(highlight.translated(QPointF(0.5, 0.5)),
|
|
QPen(opt->palette.brush(QPalette::Highlight), 1.5));
|
|
}
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
p->setPen(outlinePen);
|
|
p->drawPath(path.translated(QPointF(0.5, 0.5)));
|
|
|
|
rect = rect.adjusted(2, 2, -1, -1);
|
|
|
|
if(opt->state & State_On)
|
|
{
|
|
drawX(opt, p, rect);
|
|
}
|
|
else if(opt->state & State_NoChange)
|
|
{
|
|
QBrush brush = opt->palette.brush(QPalette::ButtonText);
|
|
brush.setTexture(m_PartialCheckPattern);
|
|
p->fillRect(rect, brush);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
QStyleOptionButton labelText = *checkbox;
|
|
labelText.rect = proxy()->subElementRect(SE_CheckBoxContents, &labelText, widget);
|
|
proxy()->drawControl(CE_CheckBoxLabel, &labelText, p, widget);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(control == CE_CheckBoxLabel || control == QStyle::CE_RadioButtonLabel)
|
|
{
|
|
const QStyleOptionButton *checkbox = qstyleoption_cast<const QStyleOptionButton *>(opt);
|
|
if(checkbox)
|
|
{
|
|
QRect rect = checkbox->rect;
|
|
|
|
if(!checkbox->icon.isNull())
|
|
{
|
|
proxy()->drawItemPixmap(
|
|
p, rect, Qt::AlignLeft | Qt::AlignVCenter,
|
|
checkbox->icon.pixmap(widgetWindow(widget), checkbox->iconSize,
|
|
checkbox->state & State_Enabled ? QIcon::Normal : QIcon::Disabled));
|
|
|
|
rect.setLeft(rect.left() + checkbox->iconSize.width() + Constants::CheckMargin);
|
|
}
|
|
|
|
if(!checkbox->text.isEmpty())
|
|
{
|
|
proxy()->drawItemText(p, rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic,
|
|
checkbox->palette, checkbox->state & State_Enabled, checkbox->text,
|
|
QPalette::WindowText);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(control == CE_SizeGrip)
|
|
{
|
|
// don't draw size grips
|
|
return;
|
|
}
|
|
else if(control == CE_ShapedFrame)
|
|
{
|
|
const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt);
|
|
|
|
qreal lineWidth = qMax(1, frame->lineWidth);
|
|
|
|
p->save();
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette, widget->foregroundRole()), lineWidth));
|
|
|
|
qreal adjust = 0.5 * lineWidth;
|
|
|
|
QRectF rect = QRectF(opt->rect).adjusted(adjust, adjust, -adjust, -adjust);
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
if(frame->frameShape == QFrame::NoFrame)
|
|
{
|
|
// draw nothing
|
|
}
|
|
else if(frame->frameShape == QFrame::Box)
|
|
{
|
|
p->drawRect(rect);
|
|
}
|
|
else if(frame->frameShape == QFrame::Panel || frame->frameShape == QFrame::WinPanel ||
|
|
frame->frameShape == QFrame::StyledPanel)
|
|
{
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
p->drawPath(path);
|
|
}
|
|
else if(frame->frameShape == QFrame::HLine)
|
|
{
|
|
rect.adjust(Constants::SeparatorMargin, 0, -Constants::SeparatorMargin, 0);
|
|
QPoint offs(0, opt->rect.height() / 2);
|
|
p->drawLine(opt->rect.topLeft() + offs, opt->rect.topRight() + offs);
|
|
}
|
|
else if(frame->frameShape == QFrame::VLine)
|
|
{
|
|
rect.adjust(0, Constants::SeparatorMargin, 0, -Constants::SeparatorMargin);
|
|
QPoint offs(opt->rect.width() / 2, 0);
|
|
p->drawLine(opt->rect.topLeft() + offs, opt->rect.bottomLeft() + offs);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_ProgressBar)
|
|
{
|
|
QRect rect = opt->rect;
|
|
|
|
rect.adjust(Constants::ProgressMargin, Constants::ProgressMargin, -Constants::ProgressMargin,
|
|
-Constants::ProgressMargin);
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, Constants::ProgressRadius, Constants::ProgressRadius);
|
|
|
|
const QStyleOptionProgressBar *progress = qstyleoption_cast<const QStyleOptionProgressBar *>(opt);
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
p->drawPath(path);
|
|
|
|
if(progress->minimum >= progress->maximum && opt->styleObject)
|
|
{
|
|
// animate an 'infinite' progress bar by adding animated clip regions
|
|
if(!Animation::has(opt->styleObject))
|
|
Animation::start(new RDProgressAnimation(2, 30, opt->styleObject));
|
|
|
|
RDProgressAnimation *anim = Animation::get<RDProgressAnimation>(opt->styleObject);
|
|
|
|
QRegion region;
|
|
|
|
rect.setWidth(anim->chunkSize());
|
|
|
|
rect.moveLeft(rect.left() + anim->offset());
|
|
|
|
while(rect.intersects(opt->rect))
|
|
{
|
|
region += rect;
|
|
|
|
// step two chunks, to skip over the chunk we're excluding from the region
|
|
rect.moveLeft(rect.left() + anim->chunkSize() * 2);
|
|
}
|
|
|
|
p->setClipRegion(region);
|
|
}
|
|
|
|
// if we're rendering a normal progress bar, set the clip rect
|
|
if(progress->minimum < progress->maximum)
|
|
{
|
|
qreal delta = qreal(progress->progress) / qreal(progress->maximum - progress->minimum);
|
|
rect.setRight(rect.left() + rect.width() * delta);
|
|
|
|
p->setClipRect(rect);
|
|
}
|
|
|
|
p->fillPath(path, opt->palette.brush(QPalette::Highlight));
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_ProgressBarGroove)
|
|
{
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_Splitter)
|
|
{
|
|
p->eraseRect(opt->rect);
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_MenuBarEmptyArea)
|
|
{
|
|
QRect rect = opt->rect;
|
|
p->eraseRect(opt->rect);
|
|
rect.adjust(0, -2, 0, -2);
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
p->drawLine(rect.bottomLeft(), rect.bottomRight());
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_MenuBarItem)
|
|
{
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
QRectF rect = QRectF(opt->rect).adjusted(0.5, 0.5, 0.5, 0.5);
|
|
|
|
const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt);
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
|
|
QPalette::ColorRole textrole = QPalette::WindowText;
|
|
|
|
QStyle::State mask = State_Enabled | State_Selected;
|
|
if((opt->state & mask) == mask)
|
|
{
|
|
qreal radius = 2.0;
|
|
|
|
if(opt->state & State_Sunken)
|
|
radius = 1.0;
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect.adjusted(1, 1, -1, -1), radius, radius);
|
|
p->fillPath(path, opt->palette.brush(QPalette::Highlight));
|
|
|
|
textrole = QPalette::HighlightedText;
|
|
|
|
if(opt->state & State_Sunken)
|
|
p->drawPath(path);
|
|
}
|
|
|
|
rect.adjust(Constants::MenuBarMargin, 0, -Constants::MenuBarMargin, 0);
|
|
|
|
if(!menuitem->icon.isNull())
|
|
{
|
|
int iconSize = proxy()->pixelMetric(QStyle::PM_SmallIconSize, opt, widget);
|
|
|
|
QPixmap pix =
|
|
menuitem->icon.pixmap(widgetWindow(widget), QSize(iconSize, iconSize),
|
|
(menuitem->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
|
|
|
|
if(!pix.isNull())
|
|
{
|
|
QRectF iconRect = rect;
|
|
iconRect.setWidth(iconSize);
|
|
proxy()->drawItemPixmap(p, iconRect.toRect(),
|
|
Qt::AlignCenter | Qt::AlignTop | Qt::TextShowMnemonic, pix);
|
|
rect.adjust(iconSize + Constants::MenuBarMargin, 0, 0, 0);
|
|
}
|
|
}
|
|
else if(menuitem->checkType != QStyleOptionMenuItem::NotCheckable)
|
|
{
|
|
int checkSize = proxy()->pixelMetric(QStyle::PM_SmallIconSize, opt, widget);
|
|
|
|
QRectF checkRect = rect.adjusted(1, 1, -1, -1);
|
|
checkRect.setWidth(checkSize);
|
|
|
|
// vertically align the check
|
|
int excess = checkRect.height() - checkRect.width();
|
|
if(excess > 0)
|
|
{
|
|
checkRect.setHeight(checkRect.height() - excess / 2);
|
|
excess -= excess / 2;
|
|
checkRect.setTop(checkRect.top() + excess);
|
|
}
|
|
|
|
QStyleOptionButton box;
|
|
(QStyleOption &)box = *(QStyleOption *)opt;
|
|
box.rect = checkRect.toRect().adjusted(1, 1, -1, -1);
|
|
if(menuitem->checked)
|
|
box.state |= State_On;
|
|
else
|
|
box.state &= ~State_On;
|
|
proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, p, widget);
|
|
|
|
rect.adjust(checkSize + Constants::MenuBarMargin, 0, 0, 0);
|
|
}
|
|
|
|
if(menuitem->menuItemType == QStyleOptionMenuItem::Normal)
|
|
{
|
|
p->setFont(menuitem->font);
|
|
proxy()->drawItemText(p, rect.toRect(), Qt::AlignCenter | Qt::AlignTop | Qt::TextShowMnemonic,
|
|
menuitem->palette, menuitem->state & State_Enabled, menuitem->text,
|
|
textrole);
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_MenuEmptyArea)
|
|
{
|
|
p->eraseRect(opt->rect);
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_MenuItem)
|
|
{
|
|
const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt);
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
QRectF rect = QRectF(opt->rect).adjusted(0.5, 0.5, 0.5, 0.5);
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
|
|
QPalette::ColorRole textrole = QPalette::WindowText;
|
|
|
|
QStyle::State mask = State_Enabled | State_Selected;
|
|
if((opt->state & mask) == mask)
|
|
{
|
|
qreal radius = 2.0;
|
|
|
|
if(opt->state & State_Sunken)
|
|
radius = 1.0;
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect.adjusted(1, 1, -1, -1), radius, radius);
|
|
p->fillPath(path, opt->palette.brush(QPalette::Highlight));
|
|
|
|
textrole = QPalette::HighlightedText;
|
|
|
|
if(opt->state & State_Sunken)
|
|
p->drawPath(path);
|
|
}
|
|
|
|
rect.adjust(Constants::MenuBarMargin, 0, -Constants::MenuBarMargin, 0);
|
|
|
|
if(menuitem->menuItemType == QStyleOptionMenuItem::Separator)
|
|
{
|
|
QPointF left = rect.center();
|
|
QPointF right = rect.center();
|
|
|
|
left.setX(rect.left());
|
|
right.setX(rect.right());
|
|
|
|
p->drawLine(left, right);
|
|
}
|
|
|
|
// draw the icon, if it exists
|
|
if(!menuitem->icon.isNull())
|
|
{
|
|
proxy()->drawItemPixmap(
|
|
p, rect.toRect(), Qt::AlignLeft | Qt::AlignVCenter,
|
|
menuitem->icon.pixmap(widgetWindow(widget),
|
|
QSize(Constants::MenuBarIconSize, Constants::MenuBarIconSize),
|
|
menuitem->state & State_Enabled ? QIcon::Normal : QIcon::Disabled));
|
|
}
|
|
else if(menuitem->checkType != QStyleOptionMenuItem::NotCheckable)
|
|
{
|
|
QRectF checkRect = rect.adjusted(1, 1, -1, -1);
|
|
checkRect.setWidth(Constants::MenuBarIconSize);
|
|
|
|
// vertically align the check
|
|
int excess = checkRect.height() - checkRect.width();
|
|
if(excess > 0)
|
|
{
|
|
checkRect.setHeight(checkRect.height() - excess / 2);
|
|
excess -= excess / 2;
|
|
checkRect.setTop(checkRect.top() + excess);
|
|
}
|
|
|
|
QStyleOptionButton box;
|
|
(QStyleOption &)box = *(QStyleOption *)opt;
|
|
box.rect = checkRect.toRect().adjusted(1, 1, -1, -1);
|
|
if(menuitem->checked)
|
|
box.state |= State_On;
|
|
else
|
|
box.state &= ~State_On;
|
|
proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, p, widget);
|
|
}
|
|
|
|
if(menuitem->menuHasCheckableItems)
|
|
rect.adjust(
|
|
Constants::MenuBarMargin + std::max(Constants::MenuBarIconSize, menuitem->maxIconWidth),
|
|
0, 0, 0);
|
|
else if(menuitem->maxIconWidth)
|
|
rect.adjust(Constants::MenuBarMargin + menuitem->maxIconWidth, 0, 0, 0);
|
|
|
|
if(menuitem->menuItemType == QStyleOptionMenuItem::Normal ||
|
|
menuitem->menuItemType == QStyleOptionMenuItem::SubMenu)
|
|
{
|
|
p->setFont(menuitem->font);
|
|
|
|
QString text = menuitem->text;
|
|
|
|
int tabIndex = text.indexOf(QLatin1Char('\t'));
|
|
|
|
if(tabIndex < 0)
|
|
{
|
|
proxy()->drawItemText(
|
|
p, rect.toRect(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
|
|
menuitem->palette, menuitem->state & State_Enabled, menuitem->text, textrole);
|
|
}
|
|
else
|
|
{
|
|
QString title = text.left(tabIndex);
|
|
QString shortcut = text.mid(tabIndex + 1, -1);
|
|
|
|
proxy()->drawItemText(p, rect.toRect(),
|
|
Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
|
|
menuitem->palette, menuitem->state & State_Enabled, title, textrole);
|
|
proxy()->drawItemText(
|
|
p, rect.toRect(), Qt::AlignRight | Qt::AlignVCenter | Qt::TextShowMnemonic,
|
|
menuitem->palette, menuitem->state & State_Enabled, shortcut, textrole);
|
|
}
|
|
|
|
if(menuitem->menuItemType == QStyleOptionMenuItem::SubMenu)
|
|
{
|
|
QStyleOptionMenuItem submenu = *menuitem;
|
|
submenu.rect.setLeft(submenu.rect.right() - Constants::MenuSubmenuWidth);
|
|
proxy()->drawPrimitive(PE_IndicatorArrowRight, &submenu, p, widget);
|
|
}
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_TabBarTabLabel)
|
|
{
|
|
const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt);
|
|
|
|
QRect rect = tab->rect;
|
|
|
|
rect.adjust(Constants::TabMargin, 0, 0, 0);
|
|
|
|
if(!tab->icon.isNull())
|
|
{
|
|
proxy()->drawItemPixmap(
|
|
p, rect, Qt::AlignLeft | Qt::AlignVCenter,
|
|
tab->icon.pixmap(widgetWindow(widget), tab->iconSize,
|
|
tab->state & State_Enabled ? QIcon::Normal : QIcon::Disabled));
|
|
|
|
rect.setLeft(rect.left() + tab->iconSize.width() + Constants::TabMargin);
|
|
}
|
|
|
|
proxy()->drawItemText(p, rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic,
|
|
tab->palette, tab->state & State_Enabled, tab->text, QPalette::WindowText);
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_TabBarTabShape)
|
|
{
|
|
const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt);
|
|
|
|
QRect rect = opt->rect;
|
|
|
|
rect.adjust(0, 0, 0, 100);
|
|
|
|
if(tab->position == QStyleOptionTab::OnlyOneTab || tab->position == QStyleOptionTab::End ||
|
|
(opt->state & State_Selected))
|
|
rect.setRight(rect.right() - 1);
|
|
|
|
if(tab->selectedPosition == QStyleOptionTab::PreviousIsSelected)
|
|
rect.setLeft(rect.left() - 1);
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 0.0));
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 3.0, 3.0);
|
|
|
|
if(opt->state & State_Selected)
|
|
p->fillPath(path, opt->palette.brush(QPalette::Window));
|
|
else if(opt->state & State_MouseOver)
|
|
p->fillPath(path, opt->palette.brush(QPalette::Midlight));
|
|
else
|
|
p->fillPath(path, opt->palette.brush(QPalette::Disabled, QPalette::Window));
|
|
|
|
p->drawPath(path.translated(QPointF(0.5, 0.5)));
|
|
|
|
if(!(opt->state & State_Selected))
|
|
{
|
|
QRectF bottomLine = QRectF(opt->rect).adjusted(0, -0.5, 0, 0);
|
|
p->drawLine(bottomLine.bottomLeft(), bottomLine.bottomRight());
|
|
}
|
|
|
|
p->restore();
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_TabBarTab)
|
|
{
|
|
proxy()->drawControl(CE_TabBarTabShape, opt, p, widget);
|
|
proxy()->drawControl(CE_TabBarTabLabel, opt, p, widget);
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_DockWidgetTitle)
|
|
{
|
|
QColor mid = opt->palette.color(QPalette::Mid);
|
|
QColor window = opt->palette.color(QPalette::Window);
|
|
|
|
QColor backGround = QColor::fromRgbF(0.5f * mid.redF() + 0.5f * window.redF(),
|
|
0.5f * mid.greenF() + 0.5f * window.greenF(),
|
|
0.5f * mid.blueF() + 0.5f * window.blueF());
|
|
|
|
QRectF rect = QRectF(opt->rect).adjusted(0.5, 0.5, 0.0, 0.0);
|
|
|
|
p->fillRect(rect, backGround);
|
|
|
|
p->save();
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
p->drawPath(path);
|
|
|
|
p->restore();
|
|
|
|
const QStyleOptionDockWidget *dockwidget = qstyleoption_cast<const QStyleOptionDockWidget *>(opt);
|
|
|
|
proxy()->drawItemText(p, rect.toRect().adjusted(Constants::TabMargin, 0, 0, 0),
|
|
Qt::AlignLeft | Qt::AlignTop | Qt::TextHideMnemonic, dockwidget->palette,
|
|
dockwidget->state & State_Enabled, dockwidget->title, QPalette::WindowText);
|
|
|
|
return;
|
|
}
|
|
else if(control == QStyle::CE_Header)
|
|
{
|
|
const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
|
|
|
|
QRectF rect = QRectF(opt->rect).adjusted(0.0, 0.0, -0.5, -0.5);
|
|
|
|
p->save();
|
|
|
|
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
|
|
|
p->fillRect(rect, opt->palette.brush(QPalette::Midlight));
|
|
p->drawLine(rect.bottomLeft(), rect.bottomRight());
|
|
p->drawLine(rect.topRight(), rect.bottomRight());
|
|
|
|
rect.adjust(Constants::ItemHeaderMargin, 0, -Constants::ItemHeaderMargin, 0);
|
|
|
|
// draw the icon, if it exists
|
|
if(!header->icon.isNull())
|
|
{
|
|
proxy()->drawItemPixmap(
|
|
p, rect.toRect(), Qt::AlignLeft | Qt::AlignVCenter,
|
|
header->icon.pixmap(widgetWindow(widget),
|
|
QSize(Constants::ItemHeaderIconSize, Constants::ItemHeaderIconSize),
|
|
header->state & State_Enabled ? QIcon::Normal : QIcon::Disabled));
|
|
}
|
|
|
|
proxy()->drawItemText(p, rect.toRect(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic,
|
|
header->palette, header->state & State_Enabled, header->text,
|
|
QPalette::WindowText);
|
|
|
|
if(header->sortIndicator != QStyleOptionHeader::None)
|
|
{
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
qreal penWidth = 1.5;
|
|
p->setPen(QPen(opt->palette.brush(QPalette::WindowText), penWidth));
|
|
|
|
{
|
|
QRectF arrowRect = rect;
|
|
arrowRect.setLeft(arrowRect.right() - Constants::SpinButtonDim);
|
|
|
|
qreal yoffset = 2.5f;
|
|
if(header->sortIndicator == QStyleOptionHeader::SortUp)
|
|
yoffset = -yoffset;
|
|
|
|
qreal ycentre = arrowRect.center().y();
|
|
|
|
QPainterPath path;
|
|
QPolygonF poly;
|
|
|
|
QPointF pt;
|
|
pt.setX(arrowRect.left() + penWidth);
|
|
pt.setY(ycentre + yoffset);
|
|
poly << pt;
|
|
|
|
pt.setX(arrowRect.center().x());
|
|
pt.setY(ycentre - yoffset);
|
|
poly << pt;
|
|
|
|
pt.setX(arrowRect.right() - penWidth);
|
|
pt.setY(ycentre + yoffset);
|
|
poly << pt;
|
|
|
|
path.addPolygon(poly);
|
|
|
|
p->drawPath(path);
|
|
}
|
|
}
|
|
|
|
p->restore();
|
|
|
|
return;
|
|
}
|
|
|
|
RDTweakedNativeStyle::drawControl(control, opt, p, widget);
|
|
}
|
|
|
|
void RDStyle::drawRoundedRectBorder(const QStyleOption *opt, QPainter *p, const QWidget *widget,
|
|
QPalette::ColorRole fillRole, bool shadow) const
|
|
{
|
|
QPen outlinePen(outlineBrush(opt->palette), 1.0);
|
|
|
|
if(opt->state & State_HasFocus)
|
|
outlinePen = QPen(opt->palette.brush(QPalette::Highlight), 1.5);
|
|
|
|
p->save();
|
|
|
|
p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
int xshift = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
|
|
int yshift = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
|
|
|
|
QRect rect = opt->rect.adjusted(0, 0, -1, -1);
|
|
|
|
if(opt->state & State_Sunken)
|
|
{
|
|
rect.setLeft(rect.left() + xshift);
|
|
rect.setTop(rect.top() + yshift);
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
p->fillPath(path, opt->palette.brush(QPalette::Midlight));
|
|
|
|
p->setPen(outlinePen);
|
|
p->drawPath(path.translated(QPointF(0.5, 0.5)));
|
|
}
|
|
else
|
|
{
|
|
if(shadow)
|
|
{
|
|
rect.setRight(rect.right() - xshift);
|
|
rect.setBottom(rect.bottom() - yshift);
|
|
}
|
|
|
|
QPainterPath path;
|
|
path.addRoundedRect(rect, 1.0, 1.0);
|
|
|
|
if(shadow)
|
|
{
|
|
p->setPen(QPen(opt->palette.brush(QPalette::Shadow), 1.0));
|
|
p->drawPath(path.translated(QPointF(1.0, 1.0)));
|
|
}
|
|
|
|
p->fillPath(path, opt->palette.brush(fillRole));
|
|
|
|
p->setPen(outlinePen);
|
|
p->drawPath(path.translated(QPointF(0.5, 0.5)));
|
|
}
|
|
|
|
p->restore();
|
|
}
|
|
|
|
RDProgressAnimation::RDProgressAnimation(int stepSize, int chunkSize, QObject *parent)
|
|
: QAbstractAnimation(parent)
|
|
{
|
|
m_stepSize = stepSize;
|
|
m_offset = 0;
|
|
m_chunkSize = chunkSize;
|
|
m_prevTime = 0;
|
|
}
|
|
|
|
void RDProgressAnimation::updateCurrentTime(int currentTime)
|
|
{
|
|
// update every 33ms, for a 30Hz animation
|
|
const int rate = 33;
|
|
|
|
// how many steps to take
|
|
int steps = 0;
|
|
|
|
int delta = currentTime - m_prevTime;
|
|
|
|
// depending on how fast we're updated, we might have to process multiple frames together.
|
|
while(delta > rate)
|
|
{
|
|
m_prevTime += rate;
|
|
delta = currentTime - m_prevTime;
|
|
|
|
steps++;
|
|
}
|
|
|
|
if(steps > 0)
|
|
{
|
|
m_offset += steps * m_stepSize;
|
|
|
|
// the animation loops after two chunks, but to visualise a smooth animation with a new chunk
|
|
// coming in from the left, we wrap to negative.
|
|
// Consider the graph y = (x+1) % 2 - 1
|
|
|
|
if(m_offset > m_chunkSize)
|
|
m_offset -= m_chunkSize * 2;
|
|
|
|
QEvent event(QEvent::StyleAnimationUpdate);
|
|
event.setAccepted(false);
|
|
QCoreApplication::sendEvent(parent(), &event);
|
|
}
|
|
}
|