peony/libpeony-qt/complementary-style.cpp

244 lines
9.5 KiB
C++
Raw Normal View History

2022-06-06 11:37:01 +08:00
/*
* Peony-Qt's Library
*
* Copyright (C) 2020, KylinSoft Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library. If not, see <https://www.gnu.org/licenses/>.
*
* Authors: Yue Lan <lanyue@kylinos.cn>
*
*/
#include "complementary-style.h"
#include "tool-bar.h"
#include "location-bar.h"
#include <QMenu>
#include <QPushButton>
#include <QStyleOptionComplex>
#include <QDebug>
#include <qdrawutil.h>
using namespace Peony;
static ComplementaryStyle *global_instance = nullptr;
ComplementaryStyle::ComplementaryStyle(QStyle *parent) : QProxyStyle(parent)
{
m_styled_menu = new QMenu;
m_styled_button = new QPushButton;
}
ComplementaryStyle::~ComplementaryStyle()
{
m_styled_menu->deleteLater();
m_styled_button->deleteLater();
}
ComplementaryStyle *ComplementaryStyle::getStyle()
{
if (!global_instance)
global_instance = new ComplementaryStyle;
return global_instance;
}
void ComplementaryStyle::polish(QWidget *widget)
{
QProxyStyle::polish(widget);
if (auto button = qobject_cast<QAbstractButton *>(widget)) {
//fix push button use as icon caused color issues
if (! button->property("isIcon").toBool())
{
button->setProperty("useIconHighlightEffect", true);
button->setProperty("iconHighlightEffectMode", 1);
button->setProperty("fillIconSymbolicColor", true);
}
return;
}
if (auto menu = qobject_cast<QMenu *>(widget)) {
menu->setProperty("useIconHighlightEffect", true);
menu->setProperty("iconHighlightEffectMode", 1);
menu->setProperty("fillIconSymbolicColor", true);
return;
}
}
int ComplementaryStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
{
switch (hint) {
case QStyle::SH_Menu_Scrollable: {
return 1;
}
default:
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
}
void ComplementaryStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
if (widget && widget->inherits("QMenu")) {
return QProxyStyle::drawPrimitive(element, option, painter, widget);
}
switch (element) {
case QStyle::PE_FrameFocusRect:
case QStyle::PE_IndicatorToolBarSeparator: {
//do not draw toolbar separator and focus rect
return;
}
case PE_IndicatorArrowDown: {
ToolBar *toolBar = qobject_cast<ToolBar*>(widget->parentWidget());
LocationBar *locationBar = qobject_cast<LocationBar*>(widget->parentWidget());
if (toolBar) {
auto rect = option->rect;
rect.setY((rect.top()+rect.bottom())/2 - 8);
rect.setWidth(16);
rect.setHeight(16);
if (option->state & State_Sunken) {
rect.adjust(1, 1, 1, 1);
}
QIcon arrowDown = QIcon::fromTheme("ukui-down-symbolic", QIcon(":/icons/ukui-down-symbolic"));
arrowDown.paint(painter, rect.adjusted(-3, 0, -3, 0));
return;
} else if (locationBar) {
auto rect = option->rect;
rect.setY((rect.top()+rect.bottom())/2 - 8);
rect.setX((rect.left()+rect.right())/2 - 8);
rect.setWidth(16);
rect.setHeight(16);
if (option->state & State_Sunken) {
QIcon arrowDown = QIcon::fromTheme("ukui-down-symbolic", QIcon(":/icons/ukui-down-symbolic"));
arrowDown.paint(painter, rect.adjusted(1, 1, 1, 1));
} else {
QIcon arrowDown = QIcon::fromTheme("ukui-end-symbolic", QIcon(":/icons/ukui-end-symbolic"));
arrowDown.paint(painter, rect.adjusted(1, 1, 1, 1));
}
return;
}
break;
}
default:
break;
}
return QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ComplementaryStyle::drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *widget) const
{
switch (cc) {
case QStyle::CC_ToolButton: {
if (const QStyleOptionToolButton *toolbutton
= qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
//Peony::ToolBar has different style with other toolbar.
ToolBar *parentWidget = qobject_cast<ToolBar*>(widget->parentWidget());
QRect button, menuarea;
button = proxy()->subControlRect(cc, toolbutton, SC_ToolButton, widget);
menuarea = proxy()->subControlRect(cc, toolbutton, SC_ToolButtonMenu, widget);
State bflags = toolbutton->state & ~State_Sunken;
if (bflags & State_AutoRaise) {
if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
bflags &= ~State_Raised;
}
}
State mflags = bflags;
if (toolbutton->state & State_Sunken) {
if (toolbutton->activeSubControls & SC_ToolButton)
bflags |= State_Sunken;
mflags |= State_Sunken;
}
QStyleOption tool = *toolbutton;
if (toolbutton->subControls & SC_ToolButton) {
if (bflags & (State_Sunken | State_On | State_Raised)) {
tool.rect = button;
tool.state = bflags;
if (parentWidget) {
if (toolbutton->features.testFlag(QStyleOptionToolButton::Menu)) {
tool.rect = QRect(button.topLeft(), QSize(button.width() + menuarea.width(), button.height()));
}
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
} else {
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
}
} else {
if (parentWidget) {
tool.rect = button;
tool.state = bflags;
if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) {
tool.rect = QRect(button.topLeft(), QSize(button.width() + menuarea.width(), button.height()));
}
qDrawShadePanel(p,
tool.rect.adjusted(1, 1, -1, -1),
m_styled_menu->palette().button().color(),
false,
0,
&m_styled_menu->palette().brush(QPalette::Normal, QPalette::Button));
}
}
}
if (toolbutton->state & State_HasFocus) {
QStyleOptionFocusRect fr;
fr.QStyleOption::operator=(*toolbutton);
fr.rect.adjust(3, 3, -3, -3);
if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator,
toolbutton, widget), 0);
proxy()->drawPrimitive(PE_FrameFocusRect, &fr, p, widget);
}
QStyleOptionToolButton label = *toolbutton;
label.state = bflags;
int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
label.rect = button.adjusted(fw, fw, -fw, -fw);
label.palette.setColor(QPalette::Window, m_styled_menu->palette().window().color());
proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
if (toolbutton->subControls & SC_ToolButtonMenu) {
tool.rect = menuarea;//.adjusted(1, 1, -1, -1);
tool.state = mflags;
tool.palette.setColor(QPalette::Button, m_styled_button->palette().highlight().color());
//FIXME: paint indicator button background correctly.
if (mflags & (State_Sunken | State_On | State_Raised)) {
if (parentWidget) {
//do nothing
} else {
proxy()->drawPrimitive(PE_PanelButtonCommand, &tool, p, widget);
}
}
drawPrimitive(PE_IndicatorArrowDown, &tool, p, widget);
} else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
QRect ir = toolbutton->rect;
QStyleOptionToolButton newBtn = *toolbutton;
newBtn.rect = QRect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6, mbi - 6);
newBtn.rect = visualRect(toolbutton->direction, button, newBtn.rect);
drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
}
}
break;
}
default:
return QProxyStyle::drawComplexControl(cc, opt, p, widget);
}
}