diff --git a/kdecoration/oxygendecoration.cpp b/kdecoration/oxygendecoration.cpp index c64946d4..5dd87aab 100644 --- a/kdecoration/oxygendecoration.cpp +++ b/kdecoration/oxygendecoration.cpp @@ -1,750 +1,750 @@ /* * Copyright (c) 2014 Martin Gräßlin * Copyright (c) 2014 Hugo Pereira Da Costa * Copyright (c) 2015 David Edmundson * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "oxygendecoration.h" #include "oxygen.h" #include "oxygensettingsprovider.h" #include "oxygenshadowcache.h" #include "config-oxygen.h" #include "config/oxygenconfigwidget.h" #include "oxygenbutton.h" #include "oxygensizegrip.h" #include #include #include #include #include #include #include #include #include #include #include #if OXYGEN_HAVE_X11 #include #endif K_PLUGIN_FACTORY_WITH_JSON( OxygenDecoFactory, "oxygen.json", registerPlugin(); registerPlugin(QStringLiteral("button")); registerPlugin(QStringLiteral("kcmodule")); ) namespace Oxygen { using KDecoration2::ColorRole; using KDecoration2::ColorGroup; //________________________________________________________________ using DecorationShadowPointer = QSharedPointer; using ShadowMap = QHash; static int g_sDecoCount = 0; static ShadowMap g_sShadows; Decoration::Decoration(QObject *parent, const QVariantList &args) : KDecoration2::Decoration(parent, args) , m_animation( new QPropertyAnimation( this ) ) { g_sDecoCount++; } //________________________________________________________________ Decoration::~Decoration() { g_sDecoCount--; if (g_sDecoCount == 0) g_sShadows.clear(); deleteSizeGrip(); } //________________________________________________________________ void Decoration::setOpacity( qreal value ) { if( m_opacity == value ) return; m_opacity = value; updateShadow(); update(); if( m_sizeGrip ) m_sizeGrip->update(); } //_________________________________________________________ QColor Decoration::titleBarColor(const QPalette &palette) const { if( m_animation->state() == QPropertyAnimation::Running ) { return KColorUtils::mix( titleBarColor( palette, false ), titleBarColor( palette, true ), m_opacity ); } else { return titleBarColor( palette, client().data()->isActive() ); } } //_________________________________________________________ QColor Decoration::titleBarColor(const QPalette &palette, bool active) const { if( m_internalSettings->useWindowColors() ) { return palette.color( active ? QPalette::Active : QPalette::Inactive, QPalette::Window ); } else { auto c = client().data(); return c->color( active ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar ); } } //_________________________________________________________ QColor Decoration::fontColor(const QPalette &palette) const { if( hideTitleBar() ) return fontColor( palette, false ); if( m_animation->state() == QPropertyAnimation::Running ) { return KColorUtils::mix( fontColor( palette, false ), fontColor( palette, true ), m_opacity ); } else { return fontColor( palette, client().data()->isActive() ); } } //_________________________________________________________ QColor Decoration::fontColor(const QPalette &palette, bool active ) const { if( m_internalSettings->useWindowColors() ) { return palette.color( active ? QPalette::Active : QPalette::Disabled, QPalette::WindowText ); } else { auto c = client().data(); return c->color( active ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::Foreground ); } } //_________________________________________________________ QColor Decoration::contrastColor(const QPalette& palette) const { if( m_internalSettings->useWindowColors() ) return contrastColor( palette.color(QPalette::Window) ); else { auto c = client().data(); return contrastColor( c->color( c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar ) ); } } //_________________________________________________________ QColor Decoration::contrastColor(const QColor& color) const { return SettingsProvider::self()->helper()->calcLightColor( color ); } //________________________________________________________________ void Decoration::init() { // active state change animation m_animation->setStartValue( 0 ); m_animation->setEndValue( 1.0 ); m_animation->setTargetObject( this ); m_animation->setPropertyName( "opacity" ); m_animation->setEasingCurve( QEasingCurve::InOutQuad ); reconfigure(); updateTitleBar(); auto s = settings(); connect(s.data(), &KDecoration2::DecorationSettings::borderSizeChanged, this, &Decoration::recalculateBorders); // a change in font might cause the borders to change connect(s.data(), &KDecoration2::DecorationSettings::fontChanged, this, &Decoration::recalculateBorders); connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::recalculateBorders); // buttons connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::updateButtonsGeometryDelayed); connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsLeftChanged, this, &Decoration::updateButtonsGeometryDelayed); connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsRightChanged, this, &Decoration::updateButtonsGeometryDelayed); // full reconfiguration connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::reconfigure); connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, SettingsProvider::self(), &SettingsProvider::reconfigure, Qt::UniqueConnection ); connect(client().data(), &KDecoration2::DecoratedClient::adjacentScreenEdgesChanged, this, &Decoration::recalculateBorders); connect(client().data(), &KDecoration2::DecoratedClient::maximizedHorizontallyChanged, this, &Decoration::recalculateBorders); connect(client().data(), &KDecoration2::DecoratedClient::maximizedVerticallyChanged, this, &Decoration::recalculateBorders); connect(client().data(), &KDecoration2::DecoratedClient::captionChanged, this, [this]() { // update the caption area update(titleBar()); } ); connect(client().data(), &KDecoration2::DecoratedClient::activeChanged, this, &Decoration::updateAnimationState); connect(client().data(), &KDecoration2::DecoratedClient::activeChanged, this, &Decoration::updateShadow); //decoration has an overloaded update function, force the compiler to choose the right one connect(client().data(), &KDecoration2::DecoratedClient::paletteChanged, this, static_cast(&Decoration::update)); connect(client().data(), &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateTitleBar); connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateTitleBar); connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::setOpaque); connect(client().data(), &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateButtonsGeometry); connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateButtonsGeometry); connect(client().data(), &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::recalculateBorders); connect(client().data(), &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateButtonsGeometry); createButtons(); updateShadow(); } //________________________________________________________________ void Decoration::updateTitleBar() { auto s = settings(); const bool maximized = isMaximized(); const int width = maximized ? client().data()->width() : client().data()->width() - 2*s->largeSpacing()*Metrics::TitleBar_SideMargin; const int height = maximized ? borderTop() : borderTop() - s->smallSpacing()*Metrics::TitleBar_TopMargin; const int x = maximized ? 0 : s->largeSpacing()*Metrics::TitleBar_SideMargin; const int y = maximized ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin; setTitleBar(QRect(x, y, width, height)); } //________________________________________________________________ void Decoration::updateAnimationState() { if( m_internalSettings->animationsEnabled() ) { m_animation->setDirection( client().data()->isActive() ? QPropertyAnimation::Forward : QPropertyAnimation::Backward ); if( m_animation->state() != QPropertyAnimation::Running ) m_animation->start(); } else { update(); } } //________________________________________________________________ void Decoration::updateSizeGripVisibility() { auto c = client().data(); if( m_sizeGrip ) { m_sizeGrip->setVisible( c->isResizeable() && !isMaximized() && !c->isShaded() ); } } //________________________________________________________________ int Decoration::borderSize(bool bottom) const { const int baseSize = settings()->smallSpacing(); if( m_internalSettings && (m_internalSettings->mask() & BorderSize ) ) { switch (m_internalSettings->borderSize()) { case InternalSettings::BorderNone: return 0; case InternalSettings::BorderNoSides: return bottom ? qMax(4, baseSize) : 0; default: case InternalSettings::BorderTiny: return bottom ? qMax(4, baseSize) : baseSize; case InternalSettings::BorderNormal: return baseSize*2; case InternalSettings::BorderLarge: return baseSize*3; case InternalSettings::BorderVeryLarge: return baseSize*4; case InternalSettings::BorderHuge: return baseSize*5; case InternalSettings::BorderVeryHuge: return baseSize*6; case InternalSettings::BorderOversized: return baseSize*10; } } else { switch (settings()->borderSize()) { case KDecoration2::BorderSize::None: return 0; case KDecoration2::BorderSize::NoSides: return bottom ? qMax(4, baseSize) : 0; default: case KDecoration2::BorderSize::Tiny: return bottom ? qMax(4, baseSize) : baseSize; case KDecoration2::BorderSize::Normal: return baseSize*2; case KDecoration2::BorderSize::Large: return baseSize*3; case KDecoration2::BorderSize::VeryLarge: return baseSize*4; case KDecoration2::BorderSize::Huge: return baseSize*5; case KDecoration2::BorderSize::VeryHuge: return baseSize*6; case KDecoration2::BorderSize::Oversized: return baseSize*10; } } } //________________________________________________________________ void Decoration::reconfigure() { m_internalSettings = SettingsProvider::self()->internalSettings( this ); // animation m_animation->setDuration( m_internalSettings->shadowAnimationsDuration() ); // borders recalculateBorders(); // clear shadows g_sShadows.clear(); // size grip if( hasNoBorders() && m_internalSettings->drawSizeGrip() ) createSizeGrip(); else deleteSizeGrip(); } //________________________________________________________________ void Decoration::recalculateBorders() { auto s = settings(); const auto c = client().data(); const auto edges = c->adjacentScreenEdges(); // left, right and bottom borders auto testFlag = [&]( Qt::Edge edge ) { return edges.testFlag(edge) && !m_internalSettings->drawBorderOnMaximizedWindows(); }; const int left = isMaximizedHorizontally() || testFlag(Qt::LeftEdge) ? 0 : borderSize(); const int right = isMaximizedHorizontally() || testFlag(Qt::RightEdge) ? 0 : borderSize(); const int bottom = isMaximizedVertically() || c->isShaded() || testFlag(Qt::BottomEdge) ? 0 : borderSize(true); int top = 0; if( hideTitleBar() ) top = bottom; else { QFontMetrics fm(s->font()); top += qMax(fm.height(), buttonHeight() ); // padding below const int baseSize = s->smallSpacing(); top += baseSize*Metrics::TitleBar_BottomMargin; // padding above top += baseSize*TitleBar_TopMargin; } setBorders(QMargins(left, top, right, bottom)); // extended sizes const int extSize = s->largeSpacing(); int extSides = 0; int extBottom = 0; if( hasNoBorders() ) { if( !isMaximizedHorizontally() ) extSides = extSize; if( !isMaximizedVertically() ) extBottom = extSize; } else if( hasNoSideBorders() && !isMaximizedHorizontally() ) { extSides = extSize; } setResizeOnlyBorders(QMargins(extSides, 0, extSides, extBottom)); } //________________________________________________________________ void Decoration::createButtons() { m_leftButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Left, this, &Button::create); m_rightButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Right, this, &Button::create); updateButtonsGeometry(); } //________________________________________________________________ void Decoration::updateButtonsGeometryDelayed() { QTimer::singleShot( 0, this, &Decoration::updateButtonsGeometry ); } //________________________________________________________________ void Decoration::updateButtonsGeometry() { auto s = settings(); // adjust button position const int bHeight = captionHeight() + (isMaximized() ? s->smallSpacing()*Metrics::TitleBar_TopMargin:0); const int bWidth = buttonHeight(); const int verticalOffset = (isMaximized() ? s->smallSpacing()*Metrics::TitleBar_TopMargin:0) + (captionHeight()-buttonHeight())/2; foreach( const QPointer& button, m_leftButtons->buttons() + m_rightButtons->buttons() ) { button.data()->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth, bHeight ) ) ); static_cast( button.data() )->setOffset( QPointF( 0, verticalOffset ) ); static_cast( button.data() )->setIconSize( QSize( bWidth, bWidth ) ); } // left buttons if( !m_leftButtons->buttons().isEmpty() ) { // spacing m_leftButtons->setSpacing(s->smallSpacing()*Metrics::TitleBar_ButtonSpacing); // padding const int vPadding = isMaximized() ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin; const int hPadding = s->smallSpacing()*Metrics::TitleBar_SideMargin; if( isMaximizedHorizontally() ) { // add offsets on the side buttons, to preserve padding, but satisfy Fitts law auto button = static_cast( m_leftButtons->buttons().front().data() ); button->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth + hPadding, bHeight ) ) ); button->setFlag( Button::FlagFirstInList ); button->setHorizontalOffset( hPadding ); m_leftButtons->setPos(QPointF(0, vPadding)); } else m_leftButtons->setPos(QPointF(hPadding + borderLeft(), vPadding)); } // right buttons if( !m_rightButtons->buttons().isEmpty() ) { // spacing m_rightButtons->setSpacing(s->smallSpacing()*Metrics::TitleBar_ButtonSpacing); // padding const int vPadding = isMaximized() ? 0 : s->smallSpacing()*Metrics::TitleBar_TopMargin; const int hPadding = s->smallSpacing()*Metrics::TitleBar_SideMargin; if( isMaximizedHorizontally() ) { auto button = static_cast( m_rightButtons->buttons().back().data() ); button->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth + hPadding, bHeight ) ) ); button->setFlag( Button::FlagLastInList ); m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width(), vPadding)); } else m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width() - hPadding - borderRight(), vPadding)); } update(); } //________________________________________________________________ void Decoration::paint(QPainter *painter, const QRect &repaintRegion) { const auto c = client().data(); const auto palette = c->palette(); const auto rect = c->isShaded() ? QRect( QPoint(0, 0), QSize(size().width(), borderTop()) ) : this->rect(); renderWindowBorder(painter, rect, palette); if( !isMaximized() ) renderCorners( painter, rect, palette); if( !hideTitleBar() ) { m_leftButtons->paint(painter, repaintRegion); m_rightButtons->paint(painter, repaintRegion); renderTitleText( painter, palette ); } } //________________________________________________________________ int Decoration::buttonHeight() const { const int baseSize = settings()->gridUnit() + 2; //oxygen icons were always slightly larger switch( m_internalSettings->buttonSize() ) { case InternalSettings::ButtonSmall: return baseSize*1.5; default: case InternalSettings::ButtonDefault: return baseSize*2; case InternalSettings::ButtonLarge: return baseSize*2.5; case InternalSettings::ButtonVeryLarge: return baseSize*3.5; } } //________________________________________________________________ int Decoration::captionHeight() const { return hideTitleBar() ? borderTop() : borderTop() - settings()->smallSpacing()*(Metrics::TitleBar_BottomMargin + Metrics::TitleBar_TopMargin ); } //________________________________________________________________ QPair Decoration::captionRect() const { if( hideTitleBar() ) return qMakePair( QRect(), Qt::AlignCenter ); else { const int leftOffset = m_leftButtons->buttons().isEmpty() ? Metrics::TitleBar_SideMargin*settings()->smallSpacing(): m_leftButtons->geometry().x() + m_leftButtons->geometry().width() + Metrics::TitleBar_SideMargin*settings()->smallSpacing(); const int rightOffset = m_rightButtons->buttons().isEmpty() ? Metrics::TitleBar_SideMargin*settings()->smallSpacing() : size().width() - m_rightButtons->geometry().x() + Metrics::TitleBar_SideMargin*settings()->smallSpacing(); const int yOffset = settings()->smallSpacing()*Metrics::TitleBar_TopMargin; const QRect maxRect( leftOffset, yOffset, size().width() - leftOffset - rightOffset, captionHeight() ); switch( m_internalSettings->titleAlignment() ) { case InternalSettings::AlignLeft: return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignLeft ); case InternalSettings::AlignRight: return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignRight ); case InternalSettings::AlignCenter: return qMakePair( maxRect, Qt::AlignCenter ); default: case InternalSettings::AlignCenterFullWidth: { // full caption rect const QRect fullRect = QRect( 0, yOffset, size().width(), captionHeight() ); QRect boundingRect( settings()->fontMetrics().boundingRect( client().data()->caption()).toRect() ); // text bounding rect boundingRect.setTop( yOffset ); boundingRect.setHeight( captionHeight() ); boundingRect.moveLeft( ( size().width() - boundingRect.width() )/2 ); if( boundingRect.left() < leftOffset ) return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignLeft ); else if( boundingRect.right() > size().width() - rightOffset ) return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignRight ); else return qMakePair(fullRect, Qt::AlignCenter); } } } } //________________________________________________________________ void Decoration::updateShadow() { // do nothing if palettes are disabled if( !( SettingsProvider::self()->shadowCache()->isEnabled( QPalette::Active ) || SettingsProvider::self()->shadowCache()->isEnabled( QPalette::Inactive ) ) ) { return; } // see if shadow should be animated const bool animated( m_animation->state() == QPropertyAnimation::Running && SettingsProvider::self()->shadowCache()->isEnabled( QPalette::Active ) && SettingsProvider::self()->shadowCache()->isEnabled( QPalette::Inactive ) ); // generate key ShadowCache::Key key; key.active = SettingsProvider::self()->shadowCache()->isEnabled( QPalette::Active ) && client().data()->isActive(); key.isShade = client().data()->isShaded(); key.hasBorder = !hasNoBorders(); if( animated ) { static const int maxIndex = 255; key.index = m_opacity * maxIndex; } const int hash( key.hash() ); // find key in map auto iter = g_sShadows.find( hash ); if( iter == g_sShadows.end() ) { auto decorationShadow = DecorationShadowPointer::create(); QPixmap shadowPixmap = animated ? SettingsProvider::self()->shadowCache()->animatedPixmap( key, m_opacity ): SettingsProvider::self()->shadowCache()->pixmap( key ); const int shadowSize( shadowPixmap.width()/2 ); const int overlap = 4; decorationShadow->setPadding( QMargins( shadowSize-overlap, shadowSize-overlap, shadowSize-overlap, shadowSize-overlap ) ); decorationShadow->setInnerShadowRect( QRect( shadowSize, shadowSize, 1, 1 ) ); decorationShadow->setShadow( shadowPixmap.toImage() ); iter = g_sShadows.insert( hash, decorationShadow ); } setShadow( iter.value() ); } //_________________________________________________________ void Decoration::renderCorners( QPainter* painter, const QRect& frame, const QPalette& palette ) const { const QColor color( titleBarColor( palette ) ); QLinearGradient lg = QLinearGradient(0, -0.5, 0, qreal( frame.height() )+0.5); lg.setColorAt(0.0, SettingsProvider::self()->helper()->calcLightColor( SettingsProvider::self()->helper()->backgroundTopColor(color) )); lg.setColorAt(0.51, SettingsProvider::self()->helper()->backgroundBottomColor(color) ); lg.setColorAt(1.0, SettingsProvider::self()->helper()->backgroundBottomColor(color) ); painter->setPen( QPen( lg, 1 ) ); painter->setBrush( Qt::NoBrush ); painter->drawRoundedRect( QRectF( frame ).adjusted( 0.5, 0.5, -0.5, -0.5 ), 3.5, 3.5 ); } //_________________________________________________________ void Decoration::renderWindowBackground( QPainter* painter, const QRect& clipRect, const QPalette& palette ) const { const auto c = client().data(); auto innerClientRect = c->isShaded() ? QRect(QPoint(0, 0), QSize(size().width(), borderTop())): rect(); // size of window minus the outlines for the rounded corners if( settings()->isAlphaChannelSupported() && !isMaximized() ) { innerClientRect.adjust(1,1,-1,-1); } if( SettingsProvider::self()->helper()->hasBackgroundGradient( c->windowId() ) ) { SettingsProvider::self()->helper()->renderWindowBackground(painter, clipRect, innerClientRect, titleBarColor( palette ), borderTop()-24 ); } else { painter->fillRect( innerClientRect, titleBarColor( palette ) ); } } //_________________________________________________________ void Decoration::renderWindowBorder( QPainter* painter, const QRect& clipRect, const QPalette& palette ) const { // save painter if( clipRect.isValid() ) { painter->save(); painter->setClipRegion(clipRect,Qt::IntersectClip); } // title height renderWindowBackground(painter, clipRect, palette ); // restore painter if( clipRect.isValid() ) { painter->restore(); } } //_________________________________________________________ void Decoration::renderTitleText( QPainter* painter, const QPalette& palette ) const { // setup font painter->setFont( settings()->font() ); // caption rect const auto cR = captionRect(); // copy caption const auto c = client().data(); const QString caption = painter->fontMetrics().elidedText(c->caption(), Qt::ElideMiddle, cR.first.width()); const auto contrast( contrastColor( palette ) ); if( contrast.isValid() ) { painter->setPen( contrast ); painter->translate( 0, 1 ); painter->drawText( cR.first, cR.second | Qt::TextSingleLine, caption ); painter->translate( 0, -1 ); } const auto color( fontColor( palette ) ); painter->setPen( color ); painter->drawText( cR.first, cR.second | Qt::TextSingleLine, caption ); } //_________________________________________________________________ void Decoration::createSizeGrip( void ) { // do nothing if size grip already exist if( m_sizeGrip ) return; #if OXYGEN_HAVE_X11 if( !QX11Info::isPlatformX11() ) return; // access client KDecoration2::DecoratedClient *c( client().data() ); if( !c ) return; if( c->windowId() != 0 ) { m_sizeGrip = new SizeGrip( this ); - connect( client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateSizeGripVisibility ); - connect( client().data(), &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateSizeGripVisibility ); - connect( client().data(), &KDecoration2::DecoratedClient::resizeableChanged, this, &Decoration::updateSizeGripVisibility ); + connect( client().toStrongRef().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateSizeGripVisibility ); + connect( client().toStrongRef().data(), &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateSizeGripVisibility ); + connect( client().toStrongRef().data(), &KDecoration2::DecoratedClient::resizeableChanged, this, &Decoration::updateSizeGripVisibility ); } #endif } //_________________________________________________________________ void Decoration::deleteSizeGrip( void ) { if( m_sizeGrip ) { m_sizeGrip->deleteLater(); m_sizeGrip = nullptr; } } } // namespace #include "oxygendecoration.moc" diff --git a/kstyle/demo/oxygenmdidemowidget.cpp b/kstyle/demo/oxygenmdidemowidget.cpp index 8e761570..014a0c3d 100644 --- a/kstyle/demo/oxygenmdidemowidget.cpp +++ b/kstyle/demo/oxygenmdidemowidget.cpp @@ -1,114 +1,118 @@ ////////////////////////////////////////////////////////////////////////////// // oxygenmdidemowidget.cpp // oxygen mdi windows demo widget // ------------------- // // Copyright (c) 2010 Hugo Pereira Da Costa // // 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 "oxygenmdidemowidget.h" #include #include #include #include namespace Oxygen { //______________________________________________________________ MdiDemoWidget::MdiDemoWidget( QWidget* parent ): DemoWidget( parent ) { setLayout( new QVBoxLayout() ); +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) layout()->setMargin(0); +#else + layout()->setContentsMargins(0, 0, 0, 0); +#endif QMenuBar* menuBar = new QMenuBar( this ); layout()->addWidget( menuBar ); QWidget* widget = new QWidget( this ); layout()->addWidget( widget ); ui.setupUi( widget ); QMenu* menu = menuBar->addMenu( i18n( "Layout" ) ); connect( menu->addAction( i18n( "Tile" ) ), SIGNAL(triggered()), this, SLOT(setLayoutTiled()) ); connect( menu->addAction( i18n( "Cascade" ) ), SIGNAL(triggered()), this, SLOT(setLayoutCascade()) ); connect( menu->addAction( i18n( "Tabs" ) ), SIGNAL(triggered()), this, SLOT(setLayoutTabbed()) ); menu = menuBar->addMenu( i18n( "Tools" ) ); QAction* action; connect( action = menu->addAction( QIcon::fromTheme( QStringLiteral( "arrow-right" ) ), i18n( "Select Next Window" ) ), SIGNAL(triggered()), ui.mdiArea, SLOT(activateNextSubWindow()) ); action->setShortcut( Qt::CTRL + Qt::Key_Tab ); addAction( action ); connect( action = menu->addAction( QIcon::fromTheme( QStringLiteral( "arrow-left" ) ), i18n( "Select Previous Window" ) ), SIGNAL(triggered()), ui.mdiArea, SLOT(activatePreviousSubWindow()) ); action->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_Tab ); addAction( action ); } //______________________________________________________________ void MdiDemoWidget::setLayoutTiled( void ) { ui.mdiArea->setViewMode( QMdiArea::SubWindowView ); ui.mdiArea->tileSubWindows(); } //______________________________________________________________ void MdiDemoWidget::setLayoutCascade( void ) { ui.mdiArea->setViewMode( QMdiArea::SubWindowView ); ui.mdiArea->cascadeSubWindows(); } //______________________________________________________________ void MdiDemoWidget::setLayoutTabbed( void ) { ui.mdiArea->setViewMode( QMdiArea::TabbedView ); } //______________________________________________________________ void MdiDemoWidget::benchmark( void ) { if( !isVisible() ) return; if( true ) { // slide windows foreach( QMdiSubWindow* window, ui.mdiArea->findChildren() ) { simulator().click( window ); simulator().slide( window, QPoint( 20, 20 ) ); simulator().slide( window, QPoint( -20, -20 ) ); } } if( true ) { foreach( QAbstractButton* button, ui.toolBox->findChildren() ) { simulator().click( button ); } foreach( QAbstractButton* button, ui.toolBox->findChildren() ) { simulator().click( button ); } } simulator().run(); } } diff --git a/kstyle/oxygenstyle.h b/kstyle/oxygenstyle.h index dbef412f..62170f65 100644 --- a/kstyle/oxygenstyle.h +++ b/kstyle/oxygenstyle.h @@ -1,778 +1,778 @@ #ifndef oxygenstyle_h #define oxygenstyle_h ////////////////////////////////////////////////////////////////////////////// // oxygenstyle.h // Oxygen widget style for KDE 4 // ------------------- // // Copyright (C) 2009-2010 Hugo Pereira Da Costa // Copyright (C) 2008 Long Huynh Huu // Copyright (C) 2007-2008 Casper Boemann // Copyright (C) 2007 Matthew Woehlke // Copyright (C) 2003-2005 Sandro Giessl // // based on the KDE style "dotNET": // Copyright (C) 2001-2002, Chris Lee // Carsten Pfeiffer // Karol Szwed // Drawing routines completely reimplemented from KDE3 HighColor, which was // originally based on some stuff from the KDE2 HighColor. // // based on drawing routines of the style "Keramik": // Copyright (c) 2002 Malte Starostik // (c) 2002,2003 Maksim Orlovich // based on the KDE3 HighColor Style // Copyright (C) 2001-2002 Karol Szwed // (C) 2001-2002 Fredrik H�glund // Drawing routines adapted from the KDE2 HCStyle, // Copyright (C) 2000 Daniel M. Duley // (C) 2000 Dirk Mueller // (C) 2001 Martijn Klingens // Progressbar code based on KStyle, // Copyright (C) 2001-2002 Karol Szwed // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License version 2 as published by the Free Software Foundation. // // 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 // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with this library; see the file COPYING.LIB. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. ////////////////////////////////////////////////////////////////////////////// #include "oxygen.h" #include "oxygentileset.h" #include "config-liboxygen.h" #if OXYGEN_USE_KDE4 #include "kstylekde4compat.h" #else #include #endif #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #include #endif namespace OxygenPrivate { class TabBarData; } namespace Oxygen { class Animations; class FrameShadowFactory; class MdiWindowShadowFactory; class Mnemonics; class ShadowHelper; class SplitterFactory; class StyleHelper; class Transitions; class TopLevelManager; class WindowManager; class WidgetExplorer; class BlurHelper; //* convenience typedef for base class #if OXYGEN_USE_KDE4 using ParentStyleClass = KStyleKDE4Compat; #else using ParentStyleClass = KStyle; #endif //* base class for oxygen style /** it is responsible to draw all the primitives to be displayed on screen, on request from Qt paint engine */ class Style: public ParentStyleClass { Q_OBJECT /* this tells kde applications that custom style elements are supported, using the kstyle mechanism */ Q_CLASSINFO ("X-KDE-CustomElements", "true") public: //* constructor explicit Style( void ); //* destructor ~Style( void ) override; //* needed to avoid warnings at compilation time using ParentStyleClass::polish; using ParentStyleClass::unpolish; //* widget polishing void polish( QWidget* ) override; //* widget unpolishing void unpolish( QWidget* ) override; //* pixel metrics int pixelMetric(PixelMetric, const QStyleOption* = nullptr, const QWidget* = nullptr) const override; //* style hints int styleHint(StyleHint, const QStyleOption* = nullptr, const QWidget* = nullptr, QStyleHintReturn* = nullptr) const override; //* returns rect corresponding to one widget's subelement QRect subElementRect( SubElement, const QStyleOption*, const QWidget* ) const override; //* returns rect corresponding to one widget's subcontrol QRect subControlRect( ComplexControl, const QStyleOptionComplex*, SubControl, const QWidget* ) const override; //* returns size matching contents QSize sizeFromContents( ContentsType, const QStyleOption*, const QSize&, const QWidget* ) const override; //* returns which subcontrol given QPoint corresponds to SubControl hitTestComplexControl( ComplexControl, const QStyleOptionComplex*, const QPoint&, const QWidget* ) const override; //* primitives void drawPrimitive( PrimitiveElement, const QStyleOption*, QPainter*, const QWidget* ) const override; //* controls void drawControl( ControlElement, const QStyleOption*, QPainter*, const QWidget* ) const override; //* complex controls void drawComplexControl( ComplexControl, const QStyleOptionComplex*, QPainter*, const QWidget* ) const override; //* generic text rendering void drawItemText( QPainter*, const QRect&, int alignment, const QPalette&, bool enabled, const QString&, QPalette::ColorRole = QPalette::NoRole) const override; //*@name event filters //@{ bool eventFilter(QObject *, QEvent *) override; bool eventFilterComboBoxContainer( QWidget*, QEvent* ); bool eventFilterDockWidget( QDockWidget*, QEvent* ); bool eventFilterMdiSubWindow( QMdiSubWindow*, QEvent* ); #if QT_VERSION >= 0x050000 bool eventFilterCommandLinkButton( QCommandLinkButton*, QEvent* ); #endif bool eventFilterScrollBar( QWidget*, QEvent* ); bool eventFilterTabBar( QWidget*, QEvent* ); bool eventFilterToolBar( QToolBar*, QEvent* ); bool eventFilterToolBox( QToolBox*, QEvent* ); //* install event filter to object, in a unique way void addEventFilter( QObject* object ) { object->removeEventFilter( this ); object->installEventFilter( this ); } //@} protected Q_SLOTS: //* standard icons virtual QIcon standardIconImplementation( StandardPixmap, const QStyleOption*, const QWidget* ) const; protected: #if OXYGEN_USE_KDE4 //* standard icons QIcon standardIcon( StandardPixmap pixmap, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const #else //* standard icons QIcon standardIcon( StandardPixmap pixmap, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override #endif { return standardIconImplementation( pixmap, option, widget ); } private Q_SLOTS: //* update configuration void configurationChanged( void ); private: //* load configuration void loadConfiguration(); //*@name enumerations and convenience classes //@{ //* used to store slab characteristics class SlabRect { public: //* constructor explicit SlabRect(void); //* constructor SlabRect( const QRect& rect, int tiles ); //* validity bool isValid( void ) const; /** adjust rectangle depending on tiles and tileSize so that it is rendered properly **/ void adjust( int ); /** adjust rectangle depending on tiles and tileSize so that it is rendered properly **/ SlabRect adjusted( int ) const; QRect rect; TileSet::Tiles tiles; //* list of slabs using List = QList; }; //@} //*@name subelementRect specialized functions //@{ //* default implementation. Does not change anything QRect defaultSubElementRect( const QStyleOption* option, const QWidget* ) const { return option->rect; } QRect pushButtonContentsRect( const QStyleOption* option, const QWidget* ) const; QRect checkBoxContentsRect( const QStyleOption* option, const QWidget* ) const; QRect lineEditContentsRect( const QStyleOption*, const QWidget* ) const; QRect progressBarGrooveRect( const QStyleOption* option, const QWidget* ) const; QRect progressBarContentsRect( const QStyleOption* option, const QWidget* ) const; QRect headerArrowRect( const QStyleOption* option, const QWidget* ) const; QRect headerLabelRect( const QStyleOption* option, const QWidget* ) const; QRect tabBarTabLeftButtonRect( const QStyleOption*, const QWidget* ) const; QRect tabBarTabRightButtonRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetTabBarRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetTabContentsRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetTabPaneRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetCornerRect( SubElement, const QStyleOption* option, const QWidget* widget ) const; QRect toolBoxTabContentsRect( const QStyleOption* option, const QWidget* ) const; //@} //*@name subcontrol Rect specialized functions //@{ QRect groupBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect toolButtonSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect comboBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect spinBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect scrollBarInternalSubControlRect( const QStyleOptionComplex*, SubControl ) const; QRect scrollBarSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect sliderSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; //@} //*@name sizeFromContents //@{ QSize defaultSizeFromContents( const QStyleOption*, const QSize& size, const QWidget* ) const { return size; } QSize checkBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize lineEditSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize comboBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize spinBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize sliderSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize pushButtonSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize toolButtonSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize menuBarItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize menuItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize tabWidgetSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize tabBarTabSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize headerSectionSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize itemViewItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; //@} //*@name primitives specialized functions //@{ bool emptyPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const { return true; } bool drawFramePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameLineEditPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameFocusRectPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameMenuPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameGroupBoxPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameTabWidgetPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameTabBarBasePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameWindowPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorArrowUpPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowUp, option, painter, widget ); } bool drawIndicatorArrowDownPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowDown, option, painter, widget ); } bool drawIndicatorArrowLeftPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowLeft, option, painter, widget ); } bool drawIndicatorArrowRightPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowRight, option, painter, widget ); } //* dock widget separators /** it uses the same painting as QSplitter, but due to Qt, the horizontal/vertical convention is inverted */ bool drawIndicatorDockWidgetResizeHandlePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget) const { renderSplitter( option, painter, widget, !(option->state & State_Horizontal ) ); return true; } bool drawIndicatorArrowPrimitive( ArrowOrientation, const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorHeaderArrowPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelButtonCommandPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelButtonToolPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarPanelButtonToolPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelScrollAreaCornerPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelMenuPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelTipLabelPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelItemViewItemPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorMenuCheckMarkPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorCheckBoxPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorRadioButtonPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorButtonDropDownPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorTabClosePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const; bool drawIndicatorTabTearPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorToolBarHandlePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorToolBarSeparatorPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorBranchPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawWidgetPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; //@} //*@name controls specialized functions //@{ bool emptyControl( const QStyleOption*, QPainter*, const QWidget* ) const { return true; } bool drawPushButtonLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolButtonLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawMenuBarItemControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawMenuItemControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarContentsControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarGrooveControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawScrollBarSliderControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawScrollBarAddLineControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawScrollBarSubLineControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawShapedFrameControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawRubberBandControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawHeaderSectionControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawHeaderEmptyAreaControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarTabShapeControl_selected( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarTabShapeControl_unselected( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolBoxTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolBoxTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawDockWidgetTitleControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolBarControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawSplitterControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { renderSplitter( option, painter, widget, option->state & State_Horizontal ); return true; } //*@} //*@name complex ontrols specialized functions //@{ bool drawToolButtonComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawComboBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawSpinBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawSliderComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawDialComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawScrollBarComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawTitleBarComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; //@} //*@name internal rendering methods /** here mostly to avoid code duplication */ //@{ //* qdial slab - void renderDialSlab( QPainter* p, const QRect& r, const QColor& c, const QStyleOption* option, StyleOptions opts = 0 ) const + void renderDialSlab( QPainter* p, const QRect& r, const QColor& c, const QStyleOption* option, StyleOptions opts = {} ) const { renderDialSlab( p, r, c, option, opts, -1, AnimationNone ); } //* qdial slab void renderDialSlab( QPainter*, const QRect&, const QColor&, const QStyleOption*, StyleOptions, qreal, AnimationMode ) const; //* generic button slab - void renderButtonSlab( QPainter* p, QRect r, const QColor& c, StyleOptions opts = 0, TileSet::Tiles tiles = TileSet::Ring) const + void renderButtonSlab( QPainter* p, QRect r, const QColor& c, StyleOptions opts = {}, TileSet::Tiles tiles = TileSet::Ring) const { renderButtonSlab( p, r, c, opts, -1, AnimationNone, tiles ); } //* generic button slab void renderButtonSlab( QPainter*, QRect, const QColor&, StyleOptions, qreal, AnimationMode, TileSet::Tiles ) const; //* generic slab - void renderSlab( QPainter* painter, const SlabRect& slab, const QColor& color, StyleOptions options = 0 ) const + void renderSlab( QPainter* painter, const SlabRect& slab, const QColor& color, StyleOptions options = {} ) const { renderSlab( painter, slab.rect, color, options, slab.tiles ); } //* generic slab - void renderSlab( QPainter* painter, QRect rect, const QColor& color, StyleOptions options = 0, TileSet::Tiles tiles = TileSet::Ring) const + void renderSlab( QPainter* painter, QRect rect, const QColor& color, StyleOptions options = {}, TileSet::Tiles tiles = TileSet::Ring) const { renderSlab( painter, rect, color, options, -1, AnimationNone, tiles ); } //* generic slab void renderSlab( QPainter* painter, const SlabRect& slab, const QColor& color, StyleOptions options, qreal opacity, AnimationMode mode ) const { renderSlab( painter, slab.rect, color, options, opacity, mode, slab.tiles ); } //* generic slab void renderSlab( QPainter*, QRect, const QColor&, StyleOptions, qreal, AnimationMode, TileSet::Tiles ) const; //* tab background /** this paints window background behind tab when tab is being dragged */ void fillTabBackground( QPainter*, const QRect&, const QColor&, const QWidget* ) const; //* tab filling void fillTab( QPainter*, const QRect&, const QColor&, const QTabBar::Shape ) const; //* spinbox arrows void renderSpinBoxArrow( QPainter*, const QStyleOptionSpinBox*, const QWidget*, const SubControl& ) const; //* splitter void renderSplitter( const QStyleOption*, QPainter*, const QWidget*, bool ) const; //* mdi subwindow titlebar button void renderTitleBarButton( QPainter*, const QStyleOptionTitleBar*, const QWidget*, const SubControl& ) const; void renderTitleBarButton( QPainter*, const QRect& r, const QColor&, const QColor&, const SubControl& ) const; void renderTitleBarIcon( QPainter*, const QRect&, const SubControl& ) const; //* header background void renderHeaderBackground( const QRect&, const QPalette&, QPainter*, const QWidget*, bool horizontal, bool reverse ) const; void renderHeaderLines( const QRect&, const QPalette&, QPainter*, TileSet::Tiles ) const; //* menu item background void renderMenuItemBackground( const QStyleOption*, QPainter*, const QWidget* ) const; void renderMenuItemRect( const QStyleOption* opt, const QRect& rect, const QPalette& pal, QPainter* p, qreal opacity = -1 ) const { renderMenuItemRect( opt, rect, pal.color(QPalette::Window), p, opacity ); } void renderMenuItemRect( const QStyleOption*, const QRect&, const QColor&, const QPalette&, QPainter* p, qreal opacity = -1 ) const; //* checkbox state (used for checkboxes _and_ radio buttons) enum CheckBoxState { CheckOn, CheckOff, CheckTriState, CheckSunken }; //* checkbox void renderCheckBox( QPainter*, const QRect&, const QPalette&, StyleOptions, CheckBoxState, qreal opacity = -1, AnimationMode mode = AnimationNone ) const; //* radio button void renderRadioButton( QPainter*, const QRect&, const QPalette&, StyleOptions, CheckBoxState, qreal opacity = -1, AnimationMode mode = AnimationNone ) const; //* scrollbar hole void renderScrollBarHole( QPainter*, const QRect&, const QColor&, const Qt::Orientation&, const TileSet::Tiles& = TileSet::Full ) const; //* scrollbar handle (non animated) void renderScrollBarHandle( QPainter* painter, const QRect& r, const QPalette& palette, const Qt::Orientation& orientation, const bool& hover) const { renderScrollBarHandle( painter, r, palette, orientation, hover, -1 ); } //* scrollbar handle (animated) void renderScrollBarHandle( QPainter*, const QRect&, const QPalette&, const Qt::Orientation&, const bool&, const qreal& ) const; //* scrollbar arrow void renderScrollBarArrow( QPainter*, const QRect&, const QColor&, const QColor&, ArrowOrientation ) const; //* returns true if given scrollbar arrow is animated QColor scrollBarArrowColor( const QStyleOptionSlider*, const SubControl&, const QWidget* ) const; //@} //**@name various utilty functions //@{ //* return dial angle based on option and value qreal dialAngle( const QStyleOptionSlider*, int ) const; //* polish scrollarea void polishScrollArea( QAbstractScrollArea* ) const; //* toolbar mask /** this masks out toolbar expander buttons, when visible, from painting */ QRegion tabBarClipRegion( const QTabBar* ) const; //* returns point position for generic arrows QPolygonF genericArrow( ArrowOrientation, ArrowSize = ArrowNormal ) const; //* scrollbar buttons enum ScrollBarButtonType { NoButton, SingleButton, DoubleButton }; //* returns height for scrollbar buttons depending of button types int scrollBarButtonHeight( const ScrollBarButtonType& type ) const { switch( type ) { case NoButton: return _noButtonHeight; case SingleButton: return _singleButtonHeight; case DoubleButton: return _doubleButtonHeight; default: return 0; } } /** separator can have a title and an icon in that case they are rendered as sunken flat toolbuttons return toolbutton option that matches named separator menu items */ QStyleOptionToolButton separatorMenuItemOption( const QStyleOptionMenuItem*, const QWidget* ) const; //* return true if option corresponds to QtQuick control bool isQtQuickControl( const QStyleOption*, const QWidget* ) const; //@} //* adjust rect based on provided margins QRect insideMargin( const QRect& r, int margin ) const { return insideMargin( r, margin, margin ); } //* adjust rect based on provided margins QRect insideMargin( const QRect& r, int marginWidth, int marginHeight ) const { return r.adjusted( marginWidth, marginHeight, -marginWidth, -marginHeight ); } //* expand size based on margins QSize expandSize( const QSize& size, int margin ) const { return expandSize( size, margin, margin ); } //* expand size based on margins QSize expandSize( const QSize& size, int marginWidth, int marginHeight ) const { return size + 2*QSize( marginWidth, marginHeight ); } //* returns true for vertical tabs bool isVerticalTab( const QStyleOptionTab* option ) const { return isVerticalTab( option->shape ); } bool isVerticalTab( const QTabBar::Shape& shape ) const { return shape == QTabBar::RoundedEast || shape == QTabBar::RoundedWest || shape == QTabBar::TriangularEast || shape == QTabBar::TriangularWest; } //* right to left alignment handling using ParentStyleClass::visualRect; QRect visualRect(const QStyleOption* opt, const QRect& subRect) const { return ParentStyleClass::visualRect(opt->direction, opt->rect, subRect); } //* centering QRect centerRect(const QRect &rect, const QSize& size ) const { return centerRect( rect, size.width(), size.height() ); } QRect centerRect(const QRect &rect, int width, int height) const { return QRect(rect.left() + (rect.width() - width)/2, rect.top() + (rect.height() - height)/2, width, height); } /* Checks whether the point is before the bound rect for bound of given orientation. This is needed to implement custom number of buttons in scrollbars, as well as proper mouse-hover */ inline bool preceeds( const QPoint&, const QRect&, const QStyleOption* ) const; //* return which arrow button is hit by point for scrollbar double buttons inline QStyle::SubControl scrollBarHitTest( const QRect&, const QPoint&, const QStyleOption* ) const; //* adjusted slabRect inline void adjustSlabRect( SlabRect& slab, const QRect&, bool documentMode, bool vertical ) const; //* return true if one of the widget's parent inherits requested type inline bool hasParent( const QWidget*, const char* ) const; //* return true if one of the widget's parent inherits requested type template bool hasParent( const QWidget* ) const; //*@name scrollbar button types (for addLine and subLine ) //@{ ScrollBarButtonType _addLineButtons = DoubleButton; ScrollBarButtonType _subLineButtons = SingleButton; //@} //*@name metrics for scrollbar buttons //@{ int _noButtonHeight = 0; int _singleButtonHeight = 14; int _doubleButtonHeight = 28; //@} //* helper StyleHelper* _helper; //* shadow helper ShadowHelper* _shadowHelper; //* animations Animations* _animations; //* transitions Transitions* _transitions; //* window manager WindowManager* _windowManager; //* toplevel manager TopLevelManager* _topLevelManager; //* frame shadows FrameShadowFactory* _frameShadowFactory; //* mdi window shadows MdiWindowShadowFactory* _mdiWindowShadowFactory; //* keyboard accelerators Mnemonics* _mnemonics; //* blur helper BlurHelper* _blurHelper; //* widget explorer WidgetExplorer* _widgetExplorer; //* tabBar data OxygenPrivate::TabBarData* _tabBarData; //* splitter Factory, to extend splitters hit area SplitterFactory* _splitterFactory; //* pointer to primitive specialized function using StylePrimitive = bool(Style::*)(const QStyleOption*, QPainter*, const QWidget* ) const; StylePrimitive _frameFocusPrimitive = nullptr; //* pointer to control specialized function using StyleControl = bool (Style::*)( const QStyleOption*, QPainter*, const QWidget* ) const; //* pointer to control specialized function using StyleComplexControl = bool (Style::*)( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; //*@name custom elements //@{ //* use Argb Drag and Drop Window QStyle::StyleHint SH_ArgbDndWindow; //* styled painting for KCapacityBar QStyle::ControlElement CE_CapacityBar; //@} //* tab close button icon (cached) mutable QIcon _tabCloseIcon; friend class OxygenPrivate::TabBarData; }; //_________________________________________________________________________ bool Style::preceeds( const QPoint& point, const QRect& bound, const QStyleOption* option ) const { if( option->state&QStyle::State_Horizontal) { if( option->direction == Qt::LeftToRight) return point.x() < bound.right(); else return point.x() > bound.x(); } else return point.y() < bound.y(); } //_________________________________________________________________________ QStyle::SubControl Style::scrollBarHitTest( const QRect& rect, const QPoint& point, const QStyleOption* option ) const { if( option->state & QStyle::State_Horizontal) { if( option->direction == Qt::LeftToRight ) return point.x() < rect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; else return point.x() > rect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; } else return point.y() < rect.center().y() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; } //___________________________________________________________________________________ void Style::adjustSlabRect( SlabRect& slab, const QRect& tabWidgetRect, bool documentMode, bool vertical ) const { // no tabWidget found, do nothing if( documentMode || !tabWidgetRect.isValid() ) return; else if( vertical ) { slab.rect.setTop( qMax( slab.rect.top(), tabWidgetRect.top() ) ); slab.rect.setBottom( qMin( slab.rect.bottom(), tabWidgetRect.bottom() ) ); } else { slab.rect.setLeft( qMax( slab.rect.left(), tabWidgetRect.left() ) ); slab.rect.setRight( qMin( slab.rect.right(), tabWidgetRect.right() ) ); } return; } //_________________________________________________________________________ bool Style::hasParent( const QWidget* widget, const char* className ) const { if( !widget ) return false; while( (widget = widget->parentWidget()) ) { if( widget->inherits( className ) ) return true; } return false; } //_________________________________________________________________________ template< typename T > bool Style::hasParent( const QWidget* widget ) const { if( !widget ) return false; while( (widget = widget->parentWidget()) ) { if( qobject_cast( widget ) ) return true; } return false; } } #endif diff --git a/kstyle/oxygenstylehelper.h b/kstyle/oxygenstylehelper.h index 27031f6e..677e3707 100644 --- a/kstyle/oxygenstylehelper.h +++ b/kstyle/oxygenstylehelper.h @@ -1,305 +1,305 @@ #ifndef oxygen_style_helper_h #define oxygen_style_helper_h /* * Copyright 2010 Hugo Pereira Da Costa * Copyright 2008 Long Huynh Huu * Copyright 2007 Matthew Woehlke * Copyright 2007 Casper Boemann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "oxygenhelper.h" #include "oxygen.h" #include #if OXYGEN_HAVE_X11 #include #endif //* helper class /** contains utility functions used at multiple places in oxygen style */ namespace Oxygen { class StyleHelper : public Helper { public: //* constructor explicit StyleHelper( KSharedConfigPtr config ); #if OXYGEN_USE_KDE4 //* constructor explicit StyleHelper( const QByteArray& ); #endif //* destructor //* clear cache void invalidateCaches() override; //* update maximum cache size void setMaxCacheSize( int ) override; //* background gradient void setUseBackgroundGradient( bool value ) { _useBackgroundGradient = value; } //* render window background using a given color as a reference /** For the widget style, both the gradient and the background pixmap are rendered in the same method. All the actual rendering is performed by the base class */ using Helper::renderWindowBackground; void renderWindowBackground( QPainter*, const QRect&, const QWidget*, const QColor&, int y_shift=-23 ) override; //* set background gradient hint to widget void setHasBackgroundGradient( WId, bool ) const override; // render menu background void renderMenuBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QPalette& pal ) { renderMenuBackground( p, clipRect, widget, pal.color( widget->window()->backgroundRole() ) ); } // render menu background void renderMenuBackground( QPainter*, const QRect&, const QWidget*, const QColor& ); //*@name color utilities //@{ //* glow color for buttons (mouse-over takes precedence over focus) QColor buttonGlowColor( const QPalette& palette, StyleOptions options, qreal opacity, AnimationMode mode ) const { return buttonGlowColor( palette.currentColorGroup(), options, opacity, mode ); } //* glow color for frames (focus takes precedence over mouse-over) QColor frameGlowColor( const QPalette& palette, StyleOptions options, qreal opacity, AnimationMode mode ) const { return frameGlowColor( palette.currentColorGroup(), options, opacity, mode ); } //* glow color for arrows (mouse-over takes precedence over focus) QColor arrowColor( const QPalette& palette, StyleOptions options, qreal opacity, AnimationMode mode ) const; //* glow color for buttons (mouse-over takes precedence over focus) QColor buttonGlowColor( QPalette::ColorGroup, StyleOptions, qreal, AnimationMode ) const; //* glow color for frames (focus takes precedence over mouse-over) QColor frameGlowColor( QPalette::ColorGroup, StyleOptions, qreal, AnimationMode ) const; //* returns menu background color matching position in a given menu widget QColor menuBackgroundColor( const QColor& color, const QWidget* w, const QPoint& point ) { if( !( w && w->window() ) || checkAutoFillBackground( w ) ) return color; else return menuBackgroundColor( color, w->window()->height(), w->mapTo( w->window(), point ).y() ); } //* returns menu background color matching position in a menu widget of given height QColor menuBackgroundColor( const QColor& color, int height, int y ) { return backgroundColor( color, qMin( qreal( 1.0 ), qreal( y )/qMin( 200, 3*height/4 ) ) ); } //* color inline QColor calcMidColor( const QColor& color ); //* merge active and inactive palettes based on ratio, for smooth enable state change transition QPalette disabledPalette( const QPalette&, qreal ratio ) const; //@} //* overloaded window decoration buttons for MDI windows QPixmap dockWidgetButton( const QColor& color, bool pressed, int size = 21 ); //* round corners( used for Menus, combobox drop-down, detached toolbars and dockwidgets TileSet roundCorner( const QColor&, int size = 5 ); //* groupbox background TileSet slope( const QColor&, qreal shade, int size = TileSet::DefaultSize ); //*@name slabs //@{ //* inverse (inner-hole) shadow /** this method must be public because it is used directly by OxygenStyle to draw dials */ void drawInverseShadow( QPainter&, const QColor&, int pad, int size, qreal fuzz ) const; //* fill a slab of given size with brush set on painter void fillSlab( QPainter&, const QRect&, int size = TileSet::DefaultSize ) const; //* linear gradient used to fill buttons void fillButtonSlab( QPainter&, const QRect&, const QColor&, bool sunken ); //* default slab TileSet slab( const QColor& color, qreal shade, int size = TileSet::DefaultSize ) { return slab( color, QColor(), shade, size ); } //* default slab (with glow) TileSet slab( const QColor&, const QColor& glow, qreal shade, int size = TileSet::DefaultSize ); //* sunken slab TileSet slabSunken( const QColor&, int size = TileSet::DefaultSize ); //* progressbar TileSet progressBarIndicator( const QPalette&, int ); //* dial QPixmap dialSlab( const QColor& color, qreal shade, int size = TileSet::DefaultSize ) { return dialSlab( color, QColor(), shade, size ); } //* dial QPixmap dialSlab( const QColor&, const QColor&, qreal shade, int size = TileSet::DefaultSize ); // round slabs QPixmap roundSlab( const QColor& color, qreal shade, int size = TileSet::DefaultSize ) { return roundSlab( color, QColor(), shade, size ); } // round slab QPixmap roundSlab( const QColor&, const QColor& glow, qreal shade, int size = TileSet::DefaultSize ); //* slider slab QPixmap sliderSlab( const QColor&, const QColor& glow, bool sunken, qreal shade, int size = TileSet::DefaultSize ); //@} //* debug frame void renderDebugFrame( QPainter*, const QRect& ) const; //*@name holes //@{ void fillHole( QPainter&, const QRect&, int offset = 2 ) const; //* generic hole - void renderHole( QPainter *painter, const QColor& color, const QRect &rect, StyleOptions options = 0, TileSet::Tiles tiles = TileSet::Ring ) + void renderHole( QPainter *painter, const QColor& color, const QRect &rect, StyleOptions options = {}, TileSet::Tiles tiles = TileSet::Ring ) { renderHole( painter, color, rect, options, -1, Oxygen::AnimationNone, tiles ); } //* generic hole (with animated glow) void renderHole( QPainter*, const QColor&, const QRect&, StyleOptions, qreal, Oxygen::AnimationMode, TileSet::Tiles = TileSet::Ring ); TileSet holeFlat( const QColor&, qreal shade, bool fill = true, int size = TileSet::DefaultSize ); //* scrollbar hole TileSet scrollHole( const QColor&, Qt::Orientation orientation, bool smallShadow = false ); //* scrollbar handle TileSet scrollHandle( const QColor&, const QColor&, int size = TileSet::DefaultSize ); //@} //* focus rect for flat toolbuttons TileSet slitFocused( const QColor& ); //* dock frame TileSet dockFrame( const QColor&, const QColor& ); //* selection TileSet selection( const QColor&, int height, bool custom ); //* inverse glow /** this method must be public because it is used directly by OxygenStyle to draw dials */ void drawInverseGlow( QPainter&, const QColor&, int pad, int size, int rsize ) const; //*@name utility functions //* returns true if compositing is active bool compositingActive( void ) const; //* returns true if a given widget supports alpha channel inline bool hasAlphaChannel( const QWidget* ) const; //* returns true if given widget will get a decoration bool hasDecoration( const QWidget* ) const; //@} private: //*@name holes //@{ //* holes - TileSet hole( const QColor& color, int size = TileSet::DefaultSize, StyleOptions options = 0 ) + TileSet hole( const QColor& color, int size = TileSet::DefaultSize, StyleOptions options = {} ) { return hole( color, QColor(), size, options ); } //* holes - TileSet hole( const QColor&, const QColor& glow, int size = TileSet::DefaultSize, StyleOptions = 0 ); + TileSet hole( const QColor&, const QColor& glow, int size = TileSet::DefaultSize, StyleOptions = {} ); //@} //* generic slab painting (to be stored in tilesets) void drawSlab( QPainter&, const QColor&, qreal shade ); // round slabs void drawRoundSlab( QPainter&, const QColor&, qreal ); // slider slabs void drawSliderSlab( QPainter&, const QColor&, bool sunken, qreal ); //* initialize void init( void ); //* background grandient bool _useBackgroundGradient; Cache _dialSlabCache; Cache _roundSlabCache; Cache _sliderSlabCache; Cache _holeCache; Cache _scrollHandleCache; Cache _slabCache; //* mid color cache ColorCache _midColorCache; //* dock button cache PixmapCache _dockWidgetButtonCache; using TileSetCache = BaseCache; TileSetCache _slabSunkenCache; TileSetCache _cornerCache; TileSetCache _holeFlatCache; TileSetCache _slopeCache; TileSetCache _slitCache; TileSetCache _dockFrameCache; TileSetCache _scrollHoleCache; TileSetCache _selectionCache; TileSetCache _progressBarCache; #if OXYGEN_HAVE_X11 //* atom used for compositing manager xcb_atom_t _compositingManagerAtom; #endif }; //____________________________________________________________________ QColor StyleHelper::calcMidColor( const QColor& color ) { const quint64 key( color.rgba() ); if( QColor* cachedColor = _midColorCache.object( key ) ) { return *cachedColor; } QColor out = KColorScheme::shade( color, KColorScheme::MidShade, _contrast - 1.0 ); _midColorCache.insert( key, new QColor( out ) ); return out; } //____________________________________________________________________ bool StyleHelper::hasAlphaChannel( const QWidget* widget ) const { return compositingActive() && widget && widget->testAttribute( Qt::WA_TranslucentBackground ); } } #endif