Files
baldurk 856c838def Update copyright years to 2026 and fix copyright ranges
* In a previous update in 2021 many copyright ranges were truncated
  accidentally, and some files have been copy-pasted with wrong years. These
  dates have been fixed based on git history and original copyright messages.
2026-01-05 14:17:28 +00:00

2430 lines
70 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017-2026 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);
}
}