diff --git a/kdecoration/oxygenbutton.cpp b/kdecoration/oxygenbutton.cpp index f5d65d45..52544584 100644 --- a/kdecoration/oxygenbutton.cpp +++ b/kdecoration/oxygenbutton.cpp @@ -1,430 +1,433 @@ /* * Copyright (c) 2009 Hugo Pereira Da Costa * Copyright (c) 2006, 2007 Riccardo Iaconelli * Copyright (c) 2006, 2007 Casper Boemann * 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 "oxygenbutton.h" #include "oxygensettingsprovider.h" #include #include #include #include namespace Oxygen { //____________________________________________________________________________________ Button* Button::create(KDecoration2::DecorationButtonType type, KDecoration2::Decoration* decoration, QObject* parent) { if (auto d = qobject_cast(decoration)) { Button *b = new Button(type, d, parent); switch( type ) { case KDecoration2::DecorationButtonType::Close: b->setVisible( d->client().data()->isCloseable() ); QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::closeableChanged, b, &Oxygen::Button::setVisible ); break; case KDecoration2::DecorationButtonType::Maximize: b->setVisible( d->client().data()->isMaximizeable() ); QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::maximizeableChanged, b, &Oxygen::Button::setVisible ); break; case KDecoration2::DecorationButtonType::Minimize: b->setVisible( d->client().data()->isMinimizeable() ); QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::minimizeableChanged, b, &Oxygen::Button::setVisible ); break; case KDecoration2::DecorationButtonType::ContextHelp: b->setVisible( d->client().data()->providesContextHelp() ); QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::providesContextHelpChanged, b, &Oxygen::Button::setVisible ); break; case KDecoration2::DecorationButtonType::Shade: b->setVisible( d->client().data()->isShadeable() ); QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::shadeableChanged, b, &Oxygen::Button::setVisible ); break; case KDecoration2::DecorationButtonType::Menu: QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::iconChanged, b, [b]() { b->update(); }); break; default: break; } return b; } else return nullptr; } //____________________________________________________________________________________ Button::Button(KDecoration2::DecorationButtonType type, Decoration* decoration, QObject* parent): KDecoration2::DecorationButton(type, decoration, parent) , m_animation( new QPropertyAnimation( this ) ) , m_opacity(0) { // setup animation m_animation->setStartValue( 0 ); m_animation->setEndValue( 1.0 ); m_animation->setTargetObject( this ); m_animation->setPropertyName( "opacity" ); m_animation->setEasingCurve( QEasingCurve::InOutQuad ); // setup default geometry const int height = decoration->buttonHeight(); setGeometry(QRect(0, 0, height, height)); setIconSize(QSize( height, height )); reconfigure(); // setup connections if( isMenuButton() ) { connect(decoration->client().data(), SIGNAL(iconChanged(QIcon)), this, SLOT(update())); } connect(decoration->settings().data(), &KDecoration2::DecorationSettings::reconfigured, this, &Button::reconfigure); connect( this, &KDecoration2::DecorationButton::hoveredChanged, this, &Button::updateAnimationState ); } //_______________________________________________ Button::Button(QObject *parent, const QVariantList &args) - : KDecoration2::DecorationButton(args.at(0).value(), args.at(1).value(), parent) - , m_flag(FlagStandalone) - , m_animation( new QPropertyAnimation( this ) ) - {} + : Button(args.at(0).value(), args.at(1).value(), parent) + { + m_flag = FlagStandalone; + //! icon size must return to !valid because it was altered from the default constructor, + //! in Standalone mode the button is not using the decoration metrics but its geometry + m_iconSize = QSize(-1, -1); + } //_______________________________________________ QColor Button::foregroundColor(const QPalette &palette) const { auto d( qobject_cast( decoration().data() ) ); if( d->isAnimated() ) { return KColorUtils::mix( foregroundColor( palette, false ), foregroundColor( palette, true ), d->opacity() ); } else { return foregroundColor( palette, isActive()); } } //___________________________________________________ QColor Button::foregroundColor( const QPalette& palette, bool active ) const { auto d( qobject_cast( decoration().data() ) ); if( d->internalSettings()->useWindowColors() ) { return palette.color( active ? QPalette::Active : QPalette::Disabled, QPalette::ButtonText ); } else { return d->fontColor( palette, active ); } } //_______________________________________________ QColor Button::backgroundColor(const QPalette &palette) const { auto d( qobject_cast( decoration().data() ) ); if( d->isAnimated() ) { return KColorUtils::mix( backgroundColor( palette, false ), backgroundColor( palette, true ), d->opacity() ); } else { return backgroundColor( palette, isActive()); } } //___________________________________________________ QColor Button::backgroundColor( const QPalette& palette, bool active ) const { auto d( qobject_cast( decoration().data() ) ); if( d->internalSettings()->useWindowColors() ) { return palette.color( active ? QPalette::Active : QPalette::Inactive, QPalette::Button ); } else { return d->titleBarColor( palette, active ); } } //___________________________________________________ bool Button::isActive( void ) const { return decoration().data()->client().data()->isActive(); } //___________________________________________________ void Button::reconfigure( void ) { // animation auto d = qobject_cast(decoration()); if( d ) m_animation->setDuration( d->internalSettings()->buttonAnimationsDuration() ); } //___________________________________________________ void Button::paint( QPainter* painter, const QRect& repaintRegion) { Q_UNUSED(repaintRegion) if (!decoration()) return; painter->save(); // translate from offset if( m_flag == FlagFirstInList ) painter->translate( m_offset ); else painter->translate( 0, m_offset.y() ); if( !m_iconSize.isValid() ) m_iconSize = geometry().size().toSize(); // menu buttons if( isMenuButton() ) { const QRectF iconRect( geometry().topLeft(), m_iconSize ); const QPixmap pixmap = decoration()->client().data()->icon().pixmap( m_iconSize.width() ); painter->drawPixmap(iconRect.center() - QPoint(pixmap.width()/2, pixmap.height()/2), pixmap); painter->restore(); return; } // palette QPalette palette( decoration().data()->client().data()->palette() ); palette.setCurrentColorGroup( isActive() ? QPalette::Active : QPalette::Inactive); // base button color QColor base = backgroundColor( palette ); // text color QColor color = foregroundColor( palette ); // decide decoration color QColor glow; if( isAnimated() || isHovered() ) { glow = isCloseButton() ? SettingsProvider::self()->helper()->negativeTextColor(palette): SettingsProvider::self()->helper()->hoverColor(palette); if( isAnimated() ) { color = KColorUtils::mix( color, glow, m_opacity ); glow = SettingsProvider::self()->helper()->alphaColor( glow, m_opacity ); } else if( isHovered() ) color = glow; } // draw button shape const bool sunken = isPressed() || ( isToggleButton() && isChecked() ); const QRectF iconRect( geometry().topLeft(), m_iconSize ); painter->drawPixmap(iconRect.topLeft(), SettingsProvider::self()->helper()->windecoButton( base, glow, sunken, m_iconSize.width() ) ); // Icon painter->setRenderHints(QPainter::Antialiasing); painter->translate( geometry().topLeft() ); qreal width( 1.2 ); // contrast painter->setBrush(Qt::NoBrush); painter->translate(0, 1.5); painter->setPen(QPen( SettingsProvider::self()->helper()->calcLightColor( base ), width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); drawIcon(painter); // main painter->translate(0,-1.5); painter->setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); drawIcon(painter); painter->restore(); } //___________________________________________________ void Button::drawIcon( QPainter* painter ) { painter->save(); //keep all co-ordinates between 0 and 21 const qreal width( m_iconSize.width() ); painter->scale( width/21, width/21 ); // make sure pen width is always larger than 1.1 in "real" coordinates QPen pen( painter->pen() ); pen.setWidthF( qMax( 1.1*21/width, pen.widthF() ) ); painter->setPen( pen ); switch(type()) { case KDecoration2::DecorationButtonType::OnAllDesktops: painter->drawPoint(QPointF(10.5,10.5)); break; case KDecoration2::DecorationButtonType::ContextHelp: painter->translate(1.5, 1.5); painter->drawArc(7,5,4,4,135*16, -180*16); painter->drawArc(9,8,4,4,135*16,45*16); painter->drawPoint(9,12); painter->translate(-1.5, -1.5); break; case KDecoration2::DecorationButtonType::ApplicationMenu: painter->drawLine(QPointF(7.5, 7.5), QPointF(13.5, 7.5)); painter->drawLine(QPointF(7.5, 10.5), QPointF(13.5, 10.5)); painter->drawLine(QPointF(7.5, 13.5), QPointF(13.5, 13.5)); break; case KDecoration2::DecorationButtonType::Minimize: { painter->drawPolyline( QPolygonF() << QPointF(7.5, 9.5) << QPointF(10.5, 12.5) << QPointF(13.5, 9.5) ); break; } case KDecoration2::DecorationButtonType::Maximize: if(decoration()->client().data()->isMaximized()) { painter->drawPolygon( QPolygonF() << QPointF(7.5, 10.5) << QPointF(10.5, 7.5) << QPointF(13.5, 10.5) << QPointF(10.5, 13.5) ); } else { painter->drawPolyline( QPolygonF() << QPointF(7.5, 11.5) << QPointF(10.5, 8.5) << QPointF(13.5, 11.5) ); } break; case KDecoration2::DecorationButtonType::Close: painter->drawLine(QPointF( 7.5,7.5), QPointF(13.5,13.5)); painter->drawLine(QPointF(13.5,7.5), QPointF( 7.5,13.5)); break; case KDecoration2::DecorationButtonType::KeepAbove: { painter->drawPolyline( QPolygonF() << QPointF( 7.5, 14) << QPointF(10.5, 11) << QPointF(13.5, 14) ); painter->drawPolyline( QPolygonF() << QPointF(7.5, 10) << QPointF(10.5, 7) << QPointF(13.5, 10) ); break; } case KDecoration2::DecorationButtonType::KeepBelow: { painter->drawPolyline( QPolygonF() << QPointF( 7.5, 11) << QPointF(10.5, 14) << QPointF(13.5, 11) ); painter->drawPolyline( QPolygonF() << QPointF(7.5, 7) << QPointF(10.5, 10) << QPointF(13.5, 7) ); break; } case KDecoration2::DecorationButtonType::Shade: if (!isChecked()) { // shade button painter->drawPolyline( QPolygonF() << QPointF(7.5, 7.5) << QPointF(10.5, 10.5) << QPointF(13.5, 7.5) ); painter->drawLine(QPointF( 7.5,13.0), QPointF(13.5,13.0)); } else { painter->drawPolyline( QPolygonF() << QPointF(7.5, 10.5) << QPointF(10.5, 7.5) << QPointF(13.5, 10.5) ); painter->drawLine(QPointF( 7.5,13.0), QPointF(13.5,13.0)); } break; default: break; } painter->restore(); return; } //__________________________________________________________________ void Button::updateAnimationState( bool hovered ) { auto d = qobject_cast(decoration()); if( !(d && d->internalSettings()->animationsEnabled() ) ) return; m_animation->setDirection( hovered ? QPropertyAnimation::Forward : QPropertyAnimation::Backward ); if( m_animation->state() != QPropertyAnimation::Running ) m_animation->start(); } }