diff --git a/kdecoration/breezesettingsprovider.cpp b/kdecoration/breezesettingsprovider.cpp index 96d65783..f1e07cf4 100644 --- a/kdecoration/breezesettingsprovider.cpp +++ b/kdecoration/breezesettingsprovider.cpp @@ -1,130 +1,130 @@ /* * Copyright 2014 Hugo Pereira Da Costa * * 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 "breezesettingsprovider.h" #include "breezeexceptionlist.h" #include #include namespace Breeze { SettingsProvider *SettingsProvider::s_self = nullptr; //__________________________________________________________________ SettingsProvider::SettingsProvider(): m_config( KSharedConfig::openConfig( QStringLiteral("breezerc") ) ) { reconfigure(); } //__________________________________________________________________ SettingsProvider::~SettingsProvider() { s_self = nullptr; } //__________________________________________________________________ SettingsProvider *SettingsProvider::self() { // TODO: this is not thread safe! if (!s_self) { s_self = new SettingsProvider(); } return s_self; } //__________________________________________________________________ void SettingsProvider::reconfigure( void ) { if( !m_defaultSettings ) { m_defaultSettings = InternalSettingsPtr(new InternalSettings()); m_defaultSettings->setCurrentGroup( QStringLiteral("Windeco") ); } m_defaultSettings->load(); ExceptionList exceptions; exceptions.readConfig( m_config ); m_exceptions = exceptions.get(); } //__________________________________________________________________ InternalSettingsPtr SettingsProvider::internalSettings( Decoration *decoration ) const { QString windowTitle; QString className; // get the client auto client = decoration->client().data(); foreach( auto internalSettings, m_exceptions ) { // discard disabled exceptions if( !internalSettings->enabled() ) continue; // discard exceptions with empty exception pattern if( internalSettings->exceptionPattern().isEmpty() ) continue; /* decide which value is to be compared to the regular expression, based on exception type */ QString value; switch( internalSettings->exceptionType() ) { case InternalSettings::ExceptionWindowTitle: { value = windowTitle.isEmpty() ? (windowTitle = client->caption()):windowTitle; break; } default: case InternalSettings::ExceptionWindowClassName: { if( className.isEmpty() ) { // retrieve class name - KWindowInfo info( client->windowId(), 0, NET::WM2WindowClass ); + KWindowInfo info( client->windowId(), nullptr, NET::WM2WindowClass ); QString window_className( QString::fromUtf8(info.windowClassName()) ); QString window_class( QString::fromUtf8(info.windowClassClass()) ); className = window_className + QStringLiteral(" ") + window_class; } value = className; break; } } // check matching if( QRegExp( internalSettings->exceptionPattern() ).indexIn( value ) >= 0 ) { return internalSettings; } } return m_defaultSettings; } } diff --git a/kdecoration/breezesizegrip.cpp b/kdecoration/breezesizegrip.cpp index d5dfb6f5..08b2f99f 100644 --- a/kdecoration/breezesizegrip.cpp +++ b/kdecoration/breezesizegrip.cpp @@ -1,308 +1,308 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezesizegrip.h" #include #include #include #include #if BREEZE_HAVE_X11 #include #endif namespace Breeze { //* scoped pointer convenience typedef template using ScopedPointer = QScopedPointer; //_____________________________________________ SizeGrip::SizeGrip( Decoration* decoration ):QWidget(nullptr) ,m_decoration( decoration ) { setAttribute(Qt::WA_NoSystemBackground ); setAutoFillBackground( false ); // cursor setCursor( Qt::SizeFDiagCursor ); // size setFixedSize( QSize( GripSize, GripSize ) ); // mask QPolygon p; p << QPoint( 0, GripSize ) << QPoint( GripSize, 0 ) << QPoint( GripSize, GripSize ) << QPoint( 0, GripSize ); setMask( QRegion( p ) ); // embed embed(); updatePosition(); // connections auto c = decoration->client().data(); connect( c, &KDecoration2::DecoratedClient::widthChanged, this, &SizeGrip::updatePosition ); connect( c, &KDecoration2::DecoratedClient::heightChanged, this, &SizeGrip::updatePosition ); connect( c, &KDecoration2::DecoratedClient::activeChanged, this, &SizeGrip::updateActiveState ); // show show(); } //_____________________________________________ SizeGrip::~SizeGrip( void ) {} //_____________________________________________ void SizeGrip::updateActiveState( void ) { #if BREEZE_HAVE_X11 if( QX11Info::isPlatformX11() ) { const quint32 value = XCB_STACK_MODE_ABOVE; xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_STACK_MODE, &value ); xcb_map_window( QX11Info::connection(), winId() ); } #endif update(); } //_____________________________________________ void SizeGrip::embed( void ) { #if BREEZE_HAVE_X11 if( !QX11Info::isPlatformX11() ) return; auto c = m_decoration.data()->client().data(); xcb_window_t windowId = c->windowId(); if( windowId ) { /* find client's parent we want the size grip to be at the same level as the client in the stack */ xcb_window_t current = windowId; auto connection = QX11Info::connection(); xcb_query_tree_cookie_t cookie = xcb_query_tree_unchecked( connection, current ); ScopedPointer tree(xcb_query_tree_reply( connection, cookie, nullptr ) ); if( !tree.isNull() && tree->parent ) current = tree->parent; // reparent xcb_reparent_window( connection, winId(), current, 0, 0 ); setWindowTitle( "Breeze::SizeGrip" ); } else { hide(); } #endif } //_____________________________________________ void SizeGrip::paintEvent( QPaintEvent* ) { if( !m_decoration ) return; // get relevant colors const QColor backgroundColor( m_decoration.data()->titleBarColor() ); // create and configure painter QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing ); painter.setPen( Qt::NoPen ); painter.setBrush( backgroundColor ); // polygon QPolygon p; p << QPoint( 0, GripSize ) << QPoint( GripSize, 0 ) << QPoint( GripSize, GripSize ) << QPoint( 0, GripSize ); painter.drawPolygon( p ); } //_____________________________________________ void SizeGrip::mousePressEvent( QMouseEvent* event ) { switch (event->button()) { case Qt::RightButton: { hide(); QTimer::singleShot(5000, this, SLOT(show())); break; } case Qt::MidButton: { hide(); break; } case Qt::LeftButton: if( rect().contains( event->pos() ) ) { sendMoveResizeEvent( event->pos() ); } break; default: break; } return; } //_______________________________________________________________________________ void SizeGrip::updatePosition( void ) { #if BREEZE_HAVE_X11 if( !QX11Info::isPlatformX11() ) return; auto c = m_decoration.data()->client().data(); QPoint position( c->width() - GripSize - Offset, c->height() - GripSize - Offset ); quint32 values[2] = { quint32(position.x()), quint32(position.y()) }; xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values ); #endif } //_____________________________________________ void SizeGrip::sendMoveResizeEvent( QPoint position ) { #if BREEZE_HAVE_X11 if( !QX11Info::isPlatformX11() ) return; // pointer to connection auto connection( QX11Info::connection() ); // client auto c = m_decoration.data()->client().data(); /* get root position matching position need to use xcb because the embedding of the widget breaks QT's mapToGlobal and other methods */ QPoint rootPosition( position ); xcb_get_geometry_cookie_t cookie( xcb_get_geometry( connection, winId() ) ); - ScopedPointer reply( xcb_get_geometry_reply( connection, cookie, 0x0 ) ); + ScopedPointer reply( xcb_get_geometry_reply( connection, cookie, nullptr ) ); if( reply ) { // translate coordinates xcb_translate_coordinates_cookie_t coordCookie( xcb_translate_coordinates( connection, winId(), reply.data()->root, -reply.data()->border_width, -reply.data()->border_width ) ); - ScopedPointer< xcb_translate_coordinates_reply_t> coordReply( xcb_translate_coordinates_reply( connection, coordCookie, 0x0 ) ); + ScopedPointer< xcb_translate_coordinates_reply_t> coordReply( xcb_translate_coordinates_reply( connection, coordCookie, nullptr ) ); if( coordReply ) { rootPosition.rx() += coordReply.data()->dst_x; rootPosition.ry() += coordReply.data()->dst_y; } } // move/resize atom if( !m_moveResizeAtom ) { // create atom if not found const QString atomName( "_NET_WM_MOVERESIZE" ); xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) ); - ScopedPointer reply( xcb_intern_atom_reply( connection, cookie, 0x0 ) ); + ScopedPointer reply( xcb_intern_atom_reply( connection, cookie, nullptr ) ); m_moveResizeAtom = reply ? reply->atom:0; } if( !m_moveResizeAtom ) return; // button release event xcb_button_release_event_t releaseEvent; memset(&releaseEvent, 0, sizeof(releaseEvent)); releaseEvent.response_type = XCB_BUTTON_RELEASE; releaseEvent.event = winId(); releaseEvent.child = XCB_WINDOW_NONE; releaseEvent.root = QX11Info::appRootWindow(); releaseEvent.event_x = position.x(); releaseEvent.event_y = position.y(); releaseEvent.root_x = rootPosition.x(); releaseEvent.root_y = rootPosition.y(); releaseEvent.detail = XCB_BUTTON_INDEX_1; releaseEvent.state = XCB_BUTTON_MASK_1; releaseEvent.time = XCB_CURRENT_TIME; releaseEvent.same_screen = true; xcb_send_event( connection, false, winId(), XCB_EVENT_MASK_BUTTON_RELEASE, reinterpret_cast(&releaseEvent)); xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME ); // move resize event xcb_client_message_event_t clientMessageEvent; memset(&clientMessageEvent, 0, sizeof(clientMessageEvent)); clientMessageEvent.response_type = XCB_CLIENT_MESSAGE; clientMessageEvent.type = m_moveResizeAtom; clientMessageEvent.format = 32; clientMessageEvent.window = c->windowId(); clientMessageEvent.data.data32[0] = rootPosition.x(); clientMessageEvent.data.data32[1] = rootPosition.y(); clientMessageEvent.data.data32[2] = 4; // bottom right clientMessageEvent.data.data32[3] = Qt::LeftButton; clientMessageEvent.data.data32[4] = 0; xcb_send_event( connection, false, QX11Info::appRootWindow(), XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, reinterpret_cast(&clientMessageEvent) ); xcb_flush( connection ); #endif } } diff --git a/kdecoration/config/breezedetectwidget.cpp b/kdecoration/config/breezedetectwidget.cpp index e603cce9..80e1b64e 100644 --- a/kdecoration/config/breezedetectwidget.cpp +++ b/kdecoration/config/breezedetectwidget.cpp @@ -1,184 +1,184 @@ ////////////////////////////////////////////////////////////////////////////// // breezedetectwidget.cpp // Note: this class is a stripped down version of // /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp // Copyright (c) 2004 Lubos Lunak // ------------------- // // Copyright (c) 2009 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 "breezedetectwidget.h" #include "breeze.h" #include #include #include #include #if BREEZE_HAVE_X11 #include #include #endif namespace Breeze { //_________________________________________________________ DetectDialog::DetectDialog( QWidget* parent ): QDialog( parent ) { // setup m_ui.setupUi( this ); connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL(clicked()), this, SLOT(close()) ); m_ui.windowClassCheckBox->setChecked( true ); #if BREEZE_HAVE_X11 if (QX11Info::isPlatformX11()) { // create atom xcb_connection_t* connection( QX11Info::connection() ); const QString atomName( QStringLiteral( "WM_STATE" ) ); xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) ); QScopedPointer reply( xcb_intern_atom_reply( connection, cookie, nullptr) ); m_wmStateAtom = reply ? reply->atom : 0; } #endif } //_________________________________________________________ void DetectDialog::detect( WId window ) { if( window == 0 ) selectWindow(); else readWindow( window ); } //_________________________________________________________ void DetectDialog::readWindow( WId window ) { if( window == 0 ) { emit detectionDone( false ); return; } m_info.reset(new KWindowInfo( window, NET::WMAllProperties, NET::WM2AllProperties )); if( !m_info->valid()) { emit detectionDone( false ); return; } const QString wmClassClass( QString::fromUtf8( m_info->windowClassClass() ) ); const QString wmClassName( QString::fromUtf8( m_info->windowClassName() ) ); m_ui.windowClass->setText( QStringLiteral( "%1 (%2 %3)" ).arg( wmClassClass ).arg( wmClassName ).arg( wmClassClass ) ); m_ui.windowTitle->setText( m_info->name() ); emit detectionDone( exec() == QDialog::Accepted ); return; } //_________________________________________________________ void DetectDialog::selectWindow() { // use a dialog, so that all user input is blocked // use WX11BypassWM and moving away so that it's not actually visible // grab only mouse, so that keyboard can be used e.g. for switching windows - m_grabber = new QDialog( 0, Qt::X11BypassWindowManagerHint ); + m_grabber = new QDialog( nullptr, Qt::X11BypassWindowManagerHint ); m_grabber->move( -1000, -1000 ); m_grabber->setModal( true ); m_grabber->show(); // need to explicitly override cursor for Qt5 qApp->setOverrideCursor( Qt::CrossCursor ); m_grabber->grabMouse( Qt::CrossCursor ); m_grabber->installEventFilter( this ); } //_________________________________________________________ bool DetectDialog::eventFilter( QObject* o, QEvent* e ) { // check object and event type if( o != m_grabber ) return false; if( e->type() != QEvent::MouseButtonRelease ) return false; // need to explicitely release cursor for Qt5 qApp->restoreOverrideCursor(); // delete old m_grabber delete m_grabber; - m_grabber = 0; + m_grabber = nullptr; // check button if( static_cast< QMouseEvent* >( e )->button() != Qt::LeftButton ) return true; // read window information readWindow( findWindow() ); return true; } //_________________________________________________________ WId DetectDialog::findWindow() { #if BREEZE_HAVE_X11 if (!QX11Info::isPlatformX11()) { return 0; } // check atom if( !m_wmStateAtom ) return 0; xcb_connection_t* connection( QX11Info::connection() ); xcb_window_t parent( QX11Info::appRootWindow() ); // why is there a loop of only 10 here for( int i = 0; i < 10; ++i ) { // query pointer xcb_query_pointer_cookie_t pointerCookie( xcb_query_pointer( connection, parent ) ); QScopedPointer pointerReply( xcb_query_pointer_reply( connection, pointerCookie, nullptr ) ); if( !( pointerReply && pointerReply->child ) ) return 0; const xcb_window_t child( pointerReply->child ); xcb_get_property_cookie_t cookie( xcb_get_property( connection, 0, child, m_wmStateAtom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0 ) ); QScopedPointer reply( xcb_get_property_reply( connection, cookie, nullptr ) ); if( reply && reply->type ) return child; else parent = child; } #endif return 0; } } diff --git a/kdecoration/config/breezeexceptiondialog.cpp b/kdecoration/config/breezeexceptiondialog.cpp index f491e0ca..f3ca3f09 100644 --- a/kdecoration/config/breezeexceptiondialog.cpp +++ b/kdecoration/config/breezeexceptiondialog.cpp @@ -1,184 +1,184 @@ ////////////////////////////////////////////////////////////////////////////// // breezeexceptiondialog.cpp // ------------------- // // Copyright (c) 2009 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 "breezeexceptiondialog.h" #include "breezedetectwidget.h" #include "config-breeze.h" #if BREEZE_HAVE_X11 #include #endif namespace Breeze { //___________________________________________ ExceptionDialog::ExceptionDialog( QWidget* parent ): QDialog( parent ) { m_ui.setupUi( this ); connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL(clicked()), this, SLOT(close()) ); // store checkboxes from ui into list m_checkboxes.insert( BorderSize, m_ui.borderSizeCheckBox ); // detect window properties connect( m_ui.detectDialogButton, SIGNAL(clicked()), SLOT(selectWindowProperties()) ); // connections connect( m_ui.exceptionType, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( m_ui.exceptionEditor, SIGNAL(textChanged(QString)), SLOT(updateChanged()) ); connect( m_ui.borderSizeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) { connect( iter.value(), SIGNAL(clicked()), SLOT(updateChanged()) ); } connect( m_ui.hideTitleBar, SIGNAL(clicked()), SLOT(updateChanged()) ); // hide detection dialog on non X11 platforms #if BREEZE_HAVE_X11 if( !QX11Info::isPlatformX11() ) m_ui.detectDialogButton->hide(); #else m_ui.detectDialogButton->hide(); #endif } //___________________________________________ void ExceptionDialog::setException( InternalSettingsPtr exception ) { // store exception internally m_exception = exception; // type m_ui.exceptionType->setCurrentIndex(m_exception->exceptionType() ); m_ui.exceptionEditor->setText( m_exception->exceptionPattern() ); m_ui.borderSizeComboBox->setCurrentIndex( m_exception->borderSize() ); m_ui.hideTitleBar->setChecked( m_exception->hideTitleBar() ); // mask for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) { iter.value()->setChecked( m_exception->mask() & iter.key() ); } setChanged( false ); } //___________________________________________ void ExceptionDialog::save( void ) { m_exception->setExceptionType( m_ui.exceptionType->currentIndex() ); m_exception->setExceptionPattern( m_ui.exceptionEditor->text() ); m_exception->setBorderSize( m_ui.borderSizeComboBox->currentIndex() ); m_exception->setHideTitleBar( m_ui.hideTitleBar->isChecked() ); // mask unsigned int mask = None; for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) { if( iter.value()->isChecked() ) mask |= iter.key(); } m_exception->setMask( mask ); setChanged( false ); } //___________________________________________ void ExceptionDialog::updateChanged( void ) { bool modified( false ); if( m_exception->exceptionType() != m_ui.exceptionType->currentIndex() ) modified = true; else if( m_exception->exceptionPattern() != m_ui.exceptionEditor->text() ) modified = true; else if( m_exception->borderSize() != m_ui.borderSizeComboBox->currentIndex() ) modified = true; else if( m_exception->hideTitleBar() != m_ui.hideTitleBar->isChecked() ) modified = true; else { // check mask for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter ) { if( iter.value()->isChecked() != (bool)( m_exception->mask() & iter.key() ) ) { modified = true; break; } } } setChanged( modified ); } //___________________________________________ void ExceptionDialog::selectWindowProperties( void ) { // create widget if( !m_detectDialog ) { m_detectDialog = new DetectDialog( this ); connect( m_detectDialog, SIGNAL(detectionDone(bool)), SLOT(readWindowProperties(bool)) ); } m_detectDialog->detect(0); } //___________________________________________ void ExceptionDialog::readWindowProperties( bool valid ) { Q_CHECK_PTR( m_detectDialog ); if( valid ) { // type m_ui.exceptionType->setCurrentIndex( m_detectDialog->exceptionType() ); // window info const KWindowInfo& info( m_detectDialog->windowInfo() ); switch( m_detectDialog->exceptionType() ) { default: case InternalSettings::ExceptionWindowClassName: m_ui.exceptionEditor->setText( QString::fromUtf8( info.windowClassClass() ) ); break; case InternalSettings::ExceptionWindowTitle: m_ui.exceptionEditor->setText( info.name() ); break; } } delete m_detectDialog; - m_detectDialog = 0; + m_detectDialog = nullptr; } } diff --git a/kdecoration/config/breezeexceptionlistwidget.h b/kdecoration/config/breezeexceptionlistwidget.h index 94b90d42..45e18eff 100644 --- a/kdecoration/config/breezeexceptionlistwidget.h +++ b/kdecoration/config/breezeexceptionlistwidget.h @@ -1,124 +1,124 @@ #ifndef breezeexceptionlistwidget_h #define breezeexceptionlistwidget_h ////////////////////////////////////////////////////////////////////////////// // breezeexceptionlistwidget.h // ------------------- // // Copyright (c) 2009 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 "ui_breezeexceptionlistwidget.h" #include "breezeexceptionmodel.h" //* QDialog used to commit selected files namespace Breeze { class ExceptionListWidget: public QWidget { //* Qt meta object Q_OBJECT public: //* constructor - explicit ExceptionListWidget( QWidget* = 0 ); + explicit ExceptionListWidget( QWidget* = nullptr ); //* set exceptions void setExceptions( const InternalSettingsList& ); //* get exceptions InternalSettingsList exceptions( void ); //* true if changed virtual bool isChanged( void ) const { return m_changed; } Q_SIGNALS: //* emitted when changed void changed( bool ); protected: //* model const ExceptionModel& model() const { return m_model; } //* model ExceptionModel& model() { return m_model; } protected Q_SLOTS: //* update button states virtual void updateButtons( void ); //* add virtual void add( void ); //* edit virtual void edit( void ); //* remove virtual void remove( void ); //* toggle virtual void toggle( const QModelIndex& ); //* move up virtual void up( void ); //* move down virtual void down( void ); protected: //* resize columns void resizeColumns( void ) const; //* check exception bool checkException( InternalSettingsPtr ); //* set changed state virtual void setChanged( bool value ) { m_changed = value; emit changed( value ); } private: //* model ExceptionModel m_model; //* ui Ui_BreezeExceptionListWidget m_ui; //* changed state bool m_changed = false; }; } #endif diff --git a/kdecoration/config/breezeitemmodel.h b/kdecoration/config/breezeitemmodel.h index a50ab8f2..71bf85e1 100644 --- a/kdecoration/config/breezeitemmodel.h +++ b/kdecoration/config/breezeitemmodel.h @@ -1,113 +1,113 @@ #ifndef ItemModel_h #define ItemModel_h ////////////////////////////////////////////////////////////////////////////// // itemmodel.h // ------------------- // // Copyright (c) 2009-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 namespace Breeze { //* Job model. Stores job information for display in lists class ItemModel : public QAbstractItemModel { public: //* constructor - explicit ItemModel(QObject *parent = 0); + explicit ItemModel(QObject *parent = nullptr); //* destructor virtual ~ItemModel() {} //* return all indexes in model starting from parent [recursive] QModelIndexList indexes( int column = 0, const QModelIndex& parent = QModelIndex() ) const; //*@name sorting //@{ //* sort virtual void sort( void ) { sort( sortColumn(), sortOrder() ); } //* sort void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override; //* current sorting column const int& sortColumn( void ) const { return m_sortColumn; } //* current sort order const Qt::SortOrder& sortOrder( void ) const { return m_sortOrder; } //@} protected: //* this sort columns without calling the layout changed callbacks void privateSort( void ) { privateSort( m_sortColumn, m_sortOrder ); } //* private sort, with no signals emmitted virtual void privateSort( int column, Qt::SortOrder order ) = 0; //* used to sort items in list class SortFTor { public: //* constructor explicit SortFTor( const int& type, Qt::SortOrder order = Qt::AscendingOrder ): _type( type ), _order( order ) {} protected: //* column int _type; //* order Qt::SortOrder _order; }; private: //* sorting column int m_sortColumn = 0; //* sorting order Qt::SortOrder m_sortOrder = Qt::AscendingOrder; }; } #endif diff --git a/kdecoration/config/breezelistmodel.h b/kdecoration/config/breezelistmodel.h index 267c78df..1cc0e548 100644 --- a/kdecoration/config/breezelistmodel.h +++ b/kdecoration/config/breezelistmodel.h @@ -1,369 +1,369 @@ #ifndef ListModel_h #define ListModel_h ////////////////////////////////////////////////////////////////////////////// // listmodel.h // ------------------- // // Copyright (c) 2009 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 "breezeitemmodel.h" #include #include #include namespace Breeze { //! Job model. Stores job information for display in lists template class ListModel : public ItemModel { public: //! value type typedef T ValueType; //! reference typedef T& Reference; //! pointer typedef T* Pointer; //! value list and iterators typedef QList List; typedef QListIterator ListIterator; typedef QMutableListIterator MutableListIterator; //! list of vector // typedef QSet Set; //! constructor - ListModel(QObject *parent = 0): + ListModel(QObject *parent = nullptr): ItemModel( parent ) {} //! destructor virtual ~ListModel() {} //!@name methods reimplemented from base class //@{ //! flags Qt::ItemFlags flags(const QModelIndex &index) const override { - if (!index.isValid()) return 0; + if (!index.isValid()) return nullptr; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } //! unique index for given row, column and parent index QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override { // check if index is valid if( !hasIndex( row, column, parent ) ) return QModelIndex(); // return invalid index if parent is valid if( parent.isValid() ) return QModelIndex(); // check against _values return ( row < (int) _values.size() ) ? createIndex( row, column ):QModelIndex(); } //! index of parent QModelIndex parent(const QModelIndex &) const override { return QModelIndex(); } //! number of rows below given index int rowCount(const QModelIndex &parent = QModelIndex()) const override { return parent.isValid() ? 0:_values.size(); } //@} //!@name selection //@{ //! clear internal list selected items virtual void clearSelectedIndexes( void ) { _selection.clear(); } //! store index internal selection state virtual void setIndexSelected( const QModelIndex& index, bool value ) { if( value ) _selection.push_back( get(index) ); else _selection.erase( std::remove( _selection.begin(), _selection.end(), get(index) ), _selection.end() ); } //! get list of internal selected items virtual QModelIndexList selectedIndexes( void ) const { QModelIndexList out; for( typename List::const_iterator iter = _selection.begin(); iter != _selection.end(); iter++ ) { QModelIndex index( ListModel::index( *iter ) ); if( index.isValid() ) out.push_back( index ); } return out; } //@} //!@name interface //@{ //! add value virtual void add( const ValueType& value ) { emit layoutAboutToBeChanged(); _add( value ); privateSort(); emit layoutChanged(); } //! add values virtual void add( const List& values ) { // check if not empty // this avoids sending useless signals if( values.empty() ) return; emit layoutAboutToBeChanged(); for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ ) { _add( *iter ); } privateSort(); emit layoutChanged(); } //! insert values virtual void insert( const QModelIndex& index, const ValueType& value ) { emit layoutAboutToBeChanged(); _insert( index, value ); emit layoutChanged(); } //! insert values virtual void insert( const QModelIndex& index, const List& values ) { emit layoutAboutToBeChanged(); // need to loop in reverse order so that the "values" ordering is preserved ListIterator iter( values ); iter.toBack(); while( iter.hasPrevious() ) { _insert( index, iter.previous() ); } emit layoutChanged(); } //! insert values virtual void replace( const QModelIndex& index, const ValueType& value ) { if( !index.isValid() ) add( value ); else { emit layoutAboutToBeChanged(); setIndexSelected( index, false ); _values[index.row()] = value; setIndexSelected( index, true ); emit layoutChanged(); } } //! remove virtual void remove( const ValueType& value ) { emit layoutAboutToBeChanged(); _remove( value ); emit layoutChanged(); return; } //! remove virtual void remove( const List& values ) { // check if not empty // this avoids sending useless signals if( values.empty() ) return; emit layoutAboutToBeChanged(); for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ ) { _remove( *iter ); } emit layoutChanged(); return; } //! clear virtual void clear( void ) { set( List() ); } //! update values from list /*! values that are not found in current are removed new values are set to the end. This is slower than the "set" method, but the selection is not cleared in the process */ virtual void update( List values ) { emit layoutAboutToBeChanged(); // store values to be removed List removed_values; // update values that are common to both lists for( typename List::iterator iter = _values.begin(); iter != _values.end(); iter++ ) { // see if iterator is in list typename List::iterator found_iter( std::find( values.begin(), values.end(), *iter ) ); if( found_iter == values.end() ) removed_values.push_back( *iter ); else { *iter = *found_iter; values.erase( found_iter ); } } // remove values that have not been found in new list for( typename List::const_iterator iter = removed_values.constBegin(); iter != removed_values.constEnd(); iter++ ) { _remove( *iter ); } // add remaining values for( typename List::const_iterator iter = values.constBegin(); iter != values.constEnd(); iter++ ) { _add( *iter ); } privateSort(); emit layoutChanged(); } //! set all values virtual void set( const List& values ) { emit layoutAboutToBeChanged(); _values = values; _selection.clear(); privateSort(); emit layoutChanged(); return; } //! return all values const List& get( void ) const { return _values; } //! return value for given index virtual ValueType get( const QModelIndex& index ) const { return (index.isValid() && index.row() < int(_values.size()) ) ? _values[index.row()]:ValueType(); } //! return value for given index virtual ValueType& get( const QModelIndex& index ) { Q_ASSERT( index.isValid() && index.row() < int( _values.size() ) ); return _values[index.row()]; } //! return all values List get( const QModelIndexList& indexes ) const { List out; for( QModelIndexList::const_iterator iter = indexes.begin(); iter != indexes.end(); iter++ ) { if( iter->isValid() && iter->row() < int(_values.size()) ) out.push_back( get( *iter ) ); } return out; } //! return index associated to a given value virtual QModelIndex index( const ValueType& value, int column = 0 ) const { for( int row = 0; row < _values.size(); ++row ) { if( value == _values[row] ) return index( row, column ); } return QModelIndex(); } //@} //! return true if model contains given index virtual bool contains( const QModelIndex& index ) const { return index.isValid() && index.row() < _values.size(); } protected: //! return all values List& _get( void ) { return _values; } //! add, without update virtual void _add( const ValueType& value ) { typename List::iterator iter = std::find( _values.begin(), _values.end(), value ); if( iter == _values.end() ) _values.push_back( value ); else *iter = value; } //! add, without update virtual void _insert( const QModelIndex& index, const ValueType& value ) { if( !index.isValid() ) add( value ); int row = 0; typename List::iterator iter( _values.begin() ); for( ;iter != _values.end() && row != index.row(); iter++, row++ ) {} _values.insert( iter, value ); } //! remove, without update virtual void _remove( const ValueType& value ) { _values.erase( std::remove( _values.begin(), _values.end(), value ), _values.end() ); _selection.erase( std::remove( _selection.begin(), _selection.end(), value ), _selection.end() ); } private: //! values List _values; //! selection List _selection; }; } #endif diff --git a/kstyle/animations/breezetransitionwidget.cpp b/kstyle/animations/breezetransitionwidget.cpp index da8d29dc..79ef688d 100644 --- a/kstyle/animations/breezetransitionwidget.cpp +++ b/kstyle/animations/breezetransitionwidget.cpp @@ -1,309 +1,309 @@ ////////////////////////////////////////////////////////////////////////////// // breezetransitionwidget.cpp // stores event filters and maps widgets to transitions for transitions // ------------------- // // Copyright (c) 2009 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 "breezetransitionwidget.h" #include #include #include #include namespace Breeze { //________________________________________________ bool TransitionWidget::_paintEnabled = true; bool TransitionWidget::paintEnabled() { return _paintEnabled; } int TransitionWidget::_steps = 0; //________________________________________________ TransitionWidget::TransitionWidget( QWidget* parent, int duration ): QWidget( parent ), _animation( new Animation( duration, this ) ) { // background flags setAttribute( Qt::WA_NoSystemBackground ); setAutoFillBackground( false ); // setup animation _animation.data()->setStartValue( 0 ); _animation.data()->setEndValue( 1.0 ); _animation.data()->setTargetObject( this ); _animation.data()->setPropertyName( "opacity" ); // hide when animation is finished connect( _animation.data(), SIGNAL(finished()), SLOT(hide()) ); } //________________________________________________ QPixmap TransitionWidget::grab( QWidget* widget, QRect rect ) { // change rect if( !rect.isValid() ) rect = widget->rect(); if( !rect.isValid() ) return QPixmap(); // initialize pixmap QPixmap out( rect.size() ); out.fill( Qt::transparent ); _paintEnabled = false; if( testFlag( GrabFromWindow ) ) { rect = rect.translated( widget->mapTo( widget->window(), widget->rect().topLeft() ) ); widget = widget->window(); #if QT_VERSION < 0x050000 out = QPixmap::grabWidget( widget, rect ); #else out = widget->grab( rect ); #endif } else { if( !testFlag( Transparent ) ) { grabBackground( out, widget, rect ); } grabWidget( out, widget, rect ); } _paintEnabled = true; return out; } //________________________________________________ bool TransitionWidget::event( QEvent* event ) { switch( event->type() ) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::KeyPress: case QEvent::KeyRelease: endAnimation(); hide(); event->ignore(); return false; default: return QWidget::event( event ); } } //________________________________________________ void TransitionWidget::paintEvent( QPaintEvent* event ) { // fully transparent case if( opacity() >= 1.0 && endPixmap().isNull() ) return; if( !_paintEnabled ) return; // get rect QRect rect = event->rect(); if( !rect.isValid() ) rect = this->rect(); // local pixmap const bool paintOnWidget( testFlag( PaintOnWidget ) && !testFlag( Transparent ) ); if( !paintOnWidget ) { if( _currentPixmap.isNull() || _currentPixmap.size() != size() ) { _currentPixmap = QPixmap( size() ); } } // fill _currentPixmap.fill( Qt::transparent ); // copy local pixmap to current { QPainter p; // draw end pixmap first, provided that opacity is small enough if( opacity() >= 0.004 && !_endPixmap.isNull() ) { // faded endPixmap if parent target is transparent and opacity is if( opacity() <= 0.996 && testFlag( Transparent ) ) { fade( _endPixmap, _currentPixmap, opacity(), rect ); p.begin( &_currentPixmap ); p.setClipRect( event->rect() ); } else { if( paintOnWidget ) p.begin( this ); else p.begin( &_currentPixmap ); p.setClipRect( event->rect() ); p.drawPixmap( QPoint(), _endPixmap ); } } else { if( paintOnWidget ) p.begin( this ); else p.begin( &_currentPixmap ); p.setClipRect( event->rect() ); } // draw fading start pixmap if( opacity() <= 0.996 && !_startPixmap.isNull() ) { if( opacity() >= 0.004 ) { fade( _startPixmap, _localStartPixmap, 1.0-opacity(), rect ); p.drawPixmap( QPoint(), _localStartPixmap ); } else p.drawPixmap( QPoint(), _startPixmap ); } p.end(); } // copy current pixmap on widget if( !paintOnWidget ) { QPainter p( this ); p.setClipRect( event->rect() ); p.drawPixmap( QPoint(0,0), _currentPixmap ); p.end(); } } //________________________________________________ void TransitionWidget::grabBackground( QPixmap& pixmap, QWidget* widget, QRect& rect ) const { if( !widget ) return; QWidgetList widgets; if( widget->autoFillBackground() ) { widgets.append( widget ); } - QWidget *parent(0); + QWidget *parent(nullptr); // get highest level parent for( parent = widget->parentWidget(); parent; parent = parent->parentWidget() ) { if( !( parent->isVisible() && parent->rect().isValid() ) ) continue; // store in list widgets.append( parent ); // stop at topLevel if( parent->isTopLevel() || parent->autoFillBackground() ) break; } if( !parent ) parent = widget; // painting QPainter p(&pixmap); p.setClipRect( rect ); const QBrush backgroundBrush = parent->palette().brush( parent->backgroundRole()); if( backgroundBrush.style() == Qt::TexturePattern) { p.drawTiledPixmap( rect, backgroundBrush.texture(), widget->mapTo( parent, rect.topLeft() ) ); } else { p.fillRect( pixmap.rect(), backgroundBrush ); } if( parent->isTopLevel() && parent->testAttribute(Qt::WA_StyledBackground)) { QStyleOption option; option.initFrom(parent); option.rect = rect; option.rect.translate( widget->mapTo( parent, rect.topLeft() ) ); p.translate(-option.rect.topLeft()); parent->style()->drawPrimitive ( QStyle::PE_Widget, &option, &p, parent ); p.translate(option.rect.topLeft()); } // draw all widgets in parent list // backward QPaintEvent event(rect); for( int i = widgets.size() - 1; i>=0; i-- ) { QWidget* w = widgets.at(i); - w->render( &p, -widget->mapTo( w, rect.topLeft() ), rect, 0 ); + w->render( &p, -widget->mapTo( w, rect.topLeft() ), rect, nullptr ); } // end p.end(); } //________________________________________________ void TransitionWidget::grabWidget( QPixmap& pixmap, QWidget* widget, QRect& rect ) const { widget->render( &pixmap, pixmap.rect().topLeft(), rect, QWidget::DrawChildren ); } //________________________________________________ void TransitionWidget::fade( const QPixmap& source, QPixmap& target, qreal opacity, const QRect& rect ) const { if( target.isNull() || target.size() != size() ) { target = QPixmap( size() ); } // erase target target.fill( Qt::transparent ); // check opacity if( opacity*255 < 1 ) return; QPainter p( &target ); p.setClipRect( rect ); // draw pixmap p.drawPixmap( QPoint(0,0), source ); // opacity mask (0.996 corresponds to 254/255) if( opacity <= 0.996 ) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); QColor color( Qt::black ); color.setAlphaF( opacity ); p.fillRect(rect, color ); } p.end(); return; } } diff --git a/kstyle/animations/breezetransitionwidget.h b/kstyle/animations/breezetransitionwidget.h index e355671c..c3e2443e 100644 --- a/kstyle/animations/breezetransitionwidget.h +++ b/kstyle/animations/breezetransitionwidget.h @@ -1,235 +1,235 @@ #ifndef breezetransitionwidget_h #define breezetransitionwidget_h ////////////////////////////////////////////////////////////////////////////// // breezetransitionwidget.h // stores event filters and maps widgets to transitions for transitions // ------------------- // // Copyright (c) 2009 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 "breezeanimation.h" #include "breeze.h" #include #include namespace Breeze { //* temporary widget used to perform smooth transition between one widget state and another class TransitionWidget: public QWidget { Q_OBJECT //* declare opacity property Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) public: //* shortcut to painter typedef WeakPointer Pointer; //* constructor TransitionWidget( QWidget* parent, int duration ); //* destructor virtual ~TransitionWidget() = default; //*@name flags //@{ enum Flag { None = 0, GrabFromWindow = 1<<0, Transparent = 1<<1, PaintOnWidget = 1<<2 }; Q_DECLARE_FLAGS(Flags, Flag) void setFlags( Flags value ) { _flags = value; } void setFlag( Flag flag, bool value = true ) { if( value ) _flags |= flag; else _flags &= (~flag); } bool testFlag( Flag flag ) const { return _flags.testFlag( flag ); } //@} //* duration void setDuration( int duration ) { if( _animation ) { _animation.data()->setDuration( duration ); } } //* duration int duration() const { return ( _animation ) ? _animation.data()->duration() : 0; } //* steps static void setSteps( int value ) { _steps = value; } //*@name opacity //@{ virtual qreal opacity() const { return _opacity; } virtual void setOpacity( qreal value ) { value = digitize( value ); if( _opacity == value ) return; _opacity = value; update(); } //@} //@name pixmaps handling //@{ //* start void resetStartPixmap() { setStartPixmap( QPixmap() ); } //* start void setStartPixmap( QPixmap pixmap ) { _startPixmap = pixmap; } //* start const QPixmap& startPixmap() const { return _startPixmap; } //* end void resetEndPixmap() { setEndPixmap( QPixmap() ); } //* end void setEndPixmap( QPixmap pixmap ) { _endPixmap = pixmap; _currentPixmap = pixmap; } //* start const QPixmap& endPixmap() const { return _endPixmap; } //* current const QPixmap& currentPixmap() const { return _currentPixmap; } //@} //* grap pixmap - QPixmap grab( QWidget* = 0, QRect = QRect() ); + QPixmap grab( QWidget* = nullptr, QRect = QRect() ); //* true if animated virtual bool isAnimated() const { return _animation.data()->isRunning(); } //* end animation virtual void endAnimation() { if( _animation.data()->isRunning() ) _animation.data()->stop(); } //* animate transition virtual void animate() { if( _animation.data()->isRunning() ) _animation.data()->stop(); _animation.data()->start(); } //* true if paint is enabled static bool paintEnabled(); protected: //* generic event filter virtual bool event( QEvent* ); //* paint event virtual void paintEvent( QPaintEvent* ); //* grab widget background /*! Background is not rendered properly using QWidget::render. Use home-made grabber instead. This is directly inspired from bespin. Copyright (C) 2007 Thomas Luebking */ virtual void grabBackground( QPixmap&, QWidget*, QRect& ) const; //* grab widget virtual void grabWidget( QPixmap&, QWidget*, QRect& ) const; //* fade pixmap virtual void fade( const QPixmap& source, QPixmap& target, qreal opacity, const QRect& ) const; //* apply step virtual qreal digitize( const qreal& value ) const { if( _steps > 0 ) return std::floor( value*_steps )/_steps; else return value; } private: //* Flags Flags _flags = None; //* paint enabled static bool _paintEnabled; //* internal transition animation Animation::Pointer _animation; //* animation starting pixmap QPixmap _startPixmap; //* animation starting pixmap QPixmap _localStartPixmap; //* animation starting pixmap QPixmap _endPixmap; //* current pixmap QPixmap _currentPixmap; //* current state opacity qreal _opacity = 0; //* steps static int _steps; }; } #endif diff --git a/kstyle/breezeframeshadow.cpp b/kstyle/breezeframeshadow.cpp index 5dad7512..86a41bff 100644 --- a/kstyle/breezeframeshadow.cpp +++ b/kstyle/breezeframeshadow.cpp @@ -1,361 +1,361 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezeframeshadow.h" #include "breeze.h" #include #include #include #include #include #include #include #include namespace Breeze { //____________________________________________________________________________________ bool FrameShadowFactory::registerWidget( QWidget* widget, Helper& helper ) { if( !widget ) return false; if( isRegistered( widget ) ) return false; // check whether widget is a frame, and has the proper shape bool accepted = false; // cast to frame and check QFrame* frame( qobject_cast( widget ) ); if( frame ) { // also do not install on QSplitter /* due to Qt, splitters are set with a frame style that matches the condition below, though no shadow should be installed, obviously */ if( qobject_cast( widget ) ) return false; // further checks on frame shape, and parent if( frame->frameStyle() == (QFrame::StyledPanel | QFrame::Sunken) ) accepted = true; } else if( widget->inherits( "KTextEditor::View" ) ) accepted = true; if( !accepted ) return false; // make sure that the widget is not embedded into a KHTMLView QWidget* parent( widget->parentWidget() ); while( parent && !parent->isTopLevel() ) { if( parent->inherits( "KHTMLView" ) ) return false; parent = parent->parentWidget(); } // store in set _registeredWidgets.insert( widget ); // catch object destruction connect( widget, SIGNAL(destroyed(QObject*)), SLOT(widgetDestroyed(QObject*)) ); // install shadow installShadows( widget, helper ); return true; } //____________________________________________________________________________________ void FrameShadowFactory::unregisterWidget( QWidget* widget ) { if( !isRegistered( widget ) ) return; _registeredWidgets.remove( widget ); removeShadows( widget ); } //____________________________________________________________________________________ bool FrameShadowFactory::eventFilter( QObject* object, QEvent* event ) { switch( event->type() ) { // TODO: possibly implement ZOrderChange event, to make sure that // the shadow is always painted on top case QEvent::ZOrderChange: { raiseShadows( object ); break; } default: break; } return QObject::eventFilter( object, event ); } //____________________________________________________________________________________ void FrameShadowFactory::installShadows( QWidget* widget, Helper& helper ) { removeShadows(widget); widget->installEventFilter(this); widget->installEventFilter( &_addEventFilter ); installShadow( widget, helper, SideTop ); installShadow( widget, helper, SideBottom ); widget->removeEventFilter( &_addEventFilter ); } //____________________________________________________________________________________ void FrameShadowFactory::removeShadows( QWidget* widget ) { widget->removeEventFilter( this ); const QList children = widget->children(); foreach( QObject *child, children ) { if( FrameShadow* shadow = qobject_cast(child) ) { shadow->hide(); - shadow->setParent(0); + shadow->setParent(nullptr); shadow->deleteLater(); } } } //____________________________________________________________________________________ void FrameShadowFactory::updateShadowsGeometry( const QObject* object, QRect rect ) const { const QList children = object->children(); foreach( QObject *child, children ) { if( FrameShadow* shadow = qobject_cast(child) ) { shadow->updateGeometry( rect ); } } } //____________________________________________________________________________________ void FrameShadowFactory::raiseShadows( QObject* object ) const { const QList children = object->children(); foreach( QObject *child, children ) { if( FrameShadow* shadow = qobject_cast(child) ) { shadow->raise(); } } } //____________________________________________________________________________________ void FrameShadowFactory::update( QObject* object ) const { const QList children = object->children(); foreach( QObject *child, children ) { if( FrameShadow* shadow = qobject_cast(child) ) { shadow->update();} } } //____________________________________________________________________________________ void FrameShadowFactory::updateState( const QWidget* widget, bool focus, bool hover, qreal opacity, AnimationMode mode ) const { const QList children = widget->children(); foreach( QObject *child, children ) { if( FrameShadow* shadow = qobject_cast(child) ) { shadow->updateState( focus, hover, opacity, mode ); } } } //____________________________________________________________________________________ void FrameShadowFactory::installShadow( QWidget* widget, Helper& helper, Side area ) const { - FrameShadow *shadow(0); + FrameShadow *shadow(nullptr); shadow = new FrameShadow( area, helper ); shadow->setParent(widget); shadow->hide(); } //____________________________________________________________________________________ void FrameShadowFactory::widgetDestroyed( QObject* object ) { _registeredWidgets.remove( object ); } //____________________________________________________________________________________ FrameShadow::FrameShadow( Side area, Helper& helper ): _helper( helper ), _area( area ), _hasFocus( false ), _mouseOver( false ), _opacity( -1 ), _mode( AnimationNone ) { setAttribute(Qt::WA_OpaquePaintEvent, false); setFocusPolicy(Qt::NoFocus); setAttribute(Qt::WA_TransparentForMouseEvents, true); setContextMenuPolicy(Qt::NoContextMenu); // grab viewport widget QWidget *viewport( this->viewport() ); // set cursor from viewport if (viewport) setCursor(viewport->cursor()); } //____________________________________________________________________________________ void FrameShadow::updateGeometry( QRect rect ) { // show on first call if( isHidden() ) show(); // store offsets between passed rect and parent widget rect QRect parentRect( parentWidget()->contentsRect() ); _margins = QMargins( rect.left() - parentRect.left(), rect.top() - parentRect.top(), rect.right() - parentRect.right(), rect.bottom() - parentRect.bottom() ); // for efficiency, take out the part for which nothing is rendered rect.adjust( 1, 1, -1, -1 ); // adjust geometry const int shadowSize( Metrics::Frame_FrameRadius ); switch( _area ) { case SideTop: rect.setHeight( shadowSize ); break; case SideBottom: rect.setTop( rect.bottom() - shadowSize + 1 ); break; case SideLeft: rect.setWidth(shadowSize); rect.adjust(0, shadowSize, 0, -shadowSize ); break; case SideRight: rect.setLeft(rect.right() - shadowSize + 1 ); rect.adjust(0, shadowSize, 0, -shadowSize ); break; default: return; } setGeometry(rect); } //____________________________________________________________________________________ void FrameShadow::updateState( bool focus, bool hover, qreal opacity, AnimationMode mode ) { bool changed( false ); if( _hasFocus != focus ) { _hasFocus = focus; changed |= true; } if( _mouseOver != hover ) { _mouseOver = hover; changed |= !_hasFocus; } if( _mode != mode ) { _mode = mode; changed |= (_mode == AnimationNone) || (_mode == AnimationFocus) || (_mode == AnimationHover && !_hasFocus ); } if( _opacity != opacity ) { _opacity = opacity; changed |= (_mode != AnimationNone ); } if( changed ) { if( QWidget* viewport = this->viewport() ) { // need to disable viewport updates to avoid some redundant painting // besides it fixes one visual glitch (from Qt) in QTableViews viewport->setUpdatesEnabled( false ); update() ; viewport->setUpdatesEnabled( true ); } else update(); } } //____________________________________________________________________________________ void FrameShadow::paintEvent(QPaintEvent *event ) { // this fixes shadows in frames that change frameStyle() after polish() if( QFrame *frame = qobject_cast( parentWidget() ) ) { if (frame->frameStyle() != (QFrame::StyledPanel | QFrame::Sunken)) return; } const QRect parentRect( parentWidget()->contentsRect().translated( mapFromParent( QPoint( 0, 0 ) ) ) ); const QRect rect( parentRect.adjusted( _margins.left(), _margins.top(), _margins.right(), _margins.bottom() ) ); // render QPainter painter(this); painter.setClipRegion( event->region() ); painter.setRenderHint( QPainter::Antialiasing ); const QColor outline( _helper.frameOutlineColor( palette(), _mouseOver, _hasFocus, _opacity, _mode ) ); painter.setCompositionMode( QPainter::CompositionMode_SourceOver ); _helper.renderFrame( &painter, rect, QColor(), outline ); return; } //____________________________________________________________________________________ QWidget* FrameShadow::viewport() const { if( !parentWidget() ) return nullptr; else if( QAbstractScrollArea *widget = qobject_cast(parentWidget()) ) { return widget->viewport(); } else return nullptr; } } diff --git a/kstyle/breezehelper.cpp b/kstyle/breezehelper.cpp index 5ca81b3d..a16c0f9e 100644 --- a/kstyle/breezehelper.cpp +++ b/kstyle/breezehelper.cpp @@ -1,1617 +1,1617 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezehelper.h" #include "breeze.h" #include "breezestyleconfigdata.h" #include #include #include #include #if BREEZE_HAVE_X11 && QT_VERSION < 0x050000 #include #endif #include namespace Breeze { //* contrast for arrow and treeline rendering static const qreal arrowShade = 0.15; //____________________________________________________________________ Helper::Helper( KSharedConfig::Ptr config ): _config( config ) { init(); } //____________________________________________________________________ #if BREEZE_USE_KDE4 Helper::Helper( const QByteArray& name ): - _componentData( name, 0, KComponentData::SkipMainComponentRegistration ), + _componentData( name, nullptr, KComponentData::SkipMainComponentRegistration ), _config( _componentData.config() ) { init(); } #endif //____________________________________________________________________ KSharedConfig::Ptr Helper::config() const { return _config; } //____________________________________________________________________ void Helper::loadConfig() { _viewFocusBrush = KStatefulBrush( KColorScheme::View, KColorScheme::FocusColor, _config ); _viewHoverBrush = KStatefulBrush( KColorScheme::View, KColorScheme::HoverColor, _config ); _viewNegativeTextBrush = KStatefulBrush( KColorScheme::View, KColorScheme::NegativeText, _config ); const QPalette palette( QApplication::palette() ); const KConfigGroup group( _config->group( "WM" ) ); _activeTitleBarColor = group.readEntry( "activeBackground", palette.color( QPalette::Active, QPalette::Highlight ) ); _activeTitleBarTextColor = group.readEntry( "activeForeground", palette.color( QPalette::Active, QPalette::HighlightedText ) ); _inactiveTitleBarColor = group.readEntry( "inactiveBackground", palette.color( QPalette::Disabled, QPalette::Highlight ) ); _inactiveTitleBarTextColor = group.readEntry( "inactiveForeground", palette.color( QPalette::Disabled, QPalette::HighlightedText ) ); } //____________________________________________________________________ QColor Helper::frameOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor outline( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.25 ) ); // focus takes precedence over hover if( mode == AnimationFocus ) { const QColor focus( focusColor( palette ) ); const QColor hover( hoverColor( palette ) ); if( mouseOver ) outline = KColorUtils::mix( hover, focus, opacity ); else outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = focusColor( palette ); } else if( mode == AnimationHover ) { const QColor hover( hoverColor( palette ) ); outline = KColorUtils::mix( outline, hover, opacity ); } else if( mouseOver ) { outline = hoverColor( palette ); } return outline; } //____________________________________________________________________ QColor Helper::focusOutlineColor( const QPalette& palette ) const { return KColorUtils::mix( focusColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); } //____________________________________________________________________ QColor Helper::hoverOutlineColor( const QPalette& palette ) const { return KColorUtils::mix( hoverColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); } //____________________________________________________________________ QColor Helper::buttonFocusOutlineColor( const QPalette& palette ) const { return KColorUtils::mix( focusColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); } //____________________________________________________________________ QColor Helper::buttonHoverOutlineColor( const QPalette& palette ) const { return KColorUtils::mix( hoverColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); } //____________________________________________________________________ QColor Helper::sidePanelOutlineColor( const QPalette& palette, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor outline( palette.color( QPalette::Inactive, QPalette::Highlight ) ); QColor focus( palette.color( QPalette::Active, QPalette::Highlight ) ); if( mode == AnimationFocus ) { outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = focus; } return outline; } //____________________________________________________________________ QColor Helper::frameBackgroundColor( const QPalette& palette, QPalette::ColorGroup group ) const { return KColorUtils::mix( palette.color( group, QPalette::Window ), palette.color( group, QPalette::Base ), 0.3 ); } //____________________________________________________________________ QColor Helper::arrowColor( const QPalette& palette, QPalette::ColorGroup group, QPalette::ColorRole role ) const { switch( role ) { case QPalette::Text: return KColorUtils::mix( palette.color( group, QPalette::Text ), palette.color( group, QPalette::Base ), arrowShade ); case QPalette::WindowText: return KColorUtils::mix( palette.color( group, QPalette::WindowText ), palette.color( group, QPalette::Window ), arrowShade ); case QPalette::ButtonText: return KColorUtils::mix( palette.color( group, QPalette::ButtonText ), palette.color( group, QPalette::Button ), arrowShade ); default: return palette.color( group, role ); } } //____________________________________________________________________ QColor Helper::arrowColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor outline( arrowColor( palette, QPalette::WindowText ) ); if( mode == AnimationHover ) { const QColor focus( focusColor( palette ) ); const QColor hover( hoverColor( palette ) ); if( hasFocus ) outline = KColorUtils::mix( focus, hover, opacity ); else outline = KColorUtils::mix( outline, hover, opacity ); } else if( mouseOver ) { outline = hoverColor( palette ); } else if( mode == AnimationFocus ) { const QColor focus( focusColor( palette ) ); outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = focusColor( palette ); } return outline; } //____________________________________________________________________ QColor Helper::buttonOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor outline( KColorUtils::mix( palette.color( QPalette::Button ), palette.color( QPalette::ButtonText ), 0.3 ) ); if( mode == AnimationHover ) { if( hasFocus ) { const QColor focus( buttonFocusOutlineColor( palette ) ); const QColor hover( buttonHoverOutlineColor( palette ) ); outline = KColorUtils::mix( focus, hover, opacity ); } else { const QColor hover( hoverColor( palette ) ); outline = KColorUtils::mix( outline, hover, opacity ); } } else if( mouseOver ) { if( hasFocus ) outline = buttonHoverOutlineColor( palette ); else outline = hoverColor( palette ); } else if( mode == AnimationFocus ) { const QColor focus( buttonFocusOutlineColor( palette ) ); outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = buttonFocusOutlineColor( palette ); } return outline; } //____________________________________________________________________ QColor Helper::buttonBackgroundColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const { QColor background( sunken ? KColorUtils::mix( palette.color( QPalette::Button ), palette.color( QPalette::ButtonText ), 0.2 ): palette.color( QPalette::Button ) ); if( mode == AnimationHover ) { const QColor focus( focusColor( palette ) ); const QColor hover( hoverColor( palette ) ); if( hasFocus ) background = KColorUtils::mix( focus, hover, opacity ); } else if( mouseOver && hasFocus ) { background = hoverColor( palette ); } else if( mode == AnimationFocus ) { const QColor focus( focusColor( palette ) ); background = KColorUtils::mix( background, focus, opacity ); } else if( hasFocus ) { background = focusColor( palette ); } return background; } //____________________________________________________________________ QColor Helper::toolButtonColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const { QColor outline; const QColor hoverColor( this->hoverColor( palette ) ); const QColor focusColor( this->focusColor( palette ) ); const QColor sunkenColor = alphaColor( palette.color( QPalette::WindowText ), 0.2 ); // hover takes precedence over focus if( mode == AnimationHover ) { if( hasFocus ) outline = KColorUtils::mix( focusColor, hoverColor, opacity ); else if( sunken ) outline = sunkenColor; else outline = alphaColor( hoverColor, opacity ); } else if( mouseOver ) { outline = hoverColor; } else if( mode == AnimationFocus ) { if( sunken ) outline = KColorUtils::mix( sunkenColor, focusColor, opacity ); else outline = alphaColor( focusColor, opacity ); } else if( hasFocus ) { outline = focusColor; } else if( sunken ) { outline = sunkenColor; } return outline; } //____________________________________________________________________ QColor Helper::sliderOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor outline( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.4 ) ); // hover takes precedence over focus if( mode == AnimationHover ) { const QColor hover( hoverColor( palette ) ); const QColor focus( focusColor( palette ) ); if( hasFocus ) outline = KColorUtils::mix( focus, hover, opacity ); else outline = KColorUtils::mix( outline, hover, opacity ); } else if( mouseOver ) { outline = hoverColor( palette ); } else if( mode == AnimationFocus ) { const QColor focus( focusColor( palette ) ); outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = focusColor( palette ); } return outline; } //____________________________________________________________________ QColor Helper::scrollBarHandleColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor color( alphaColor( palette.color( QPalette::WindowText ), 0.5 ) ); // hover takes precedence over focus if( mode == AnimationHover ) { const QColor hover( hoverColor( palette ) ); const QColor focus( focusColor( palette ) ); if( hasFocus ) color = KColorUtils::mix( focus, hover, opacity ); else color = KColorUtils::mix( color, hover, opacity ); } else if( mouseOver ) { color = hoverColor( palette ); } else if( mode == AnimationFocus ) { const QColor focus( focusColor( palette ) ); color = KColorUtils::mix( color, focus, opacity ); } else if( hasFocus ) { color = focusColor( palette ); } return color; } //______________________________________________________________________________ QColor Helper::checkBoxIndicatorColor( const QPalette& palette, bool mouseOver, bool active, qreal opacity, AnimationMode mode ) const { QColor color( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.6 ) ); if( mode == AnimationHover ) { const QColor focus( focusColor( palette ) ); const QColor hover( hoverColor( palette ) ); if( active ) color = KColorUtils::mix( focus, hover, opacity ); else color = KColorUtils::mix( color, hover, opacity ); } else if( mouseOver ) { color = hoverColor( palette ); } else if( active ) { color = focusColor( palette ); } return color; } //______________________________________________________________________________ QColor Helper::separatorColor( const QPalette& palette ) const { return KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.25 ); } //______________________________________________________________________________ QPalette Helper::disabledPalette( const QPalette& source, qreal ratio ) const { QPalette copy( source ); const QList roles = { QPalette::Background, QPalette::Highlight, QPalette::WindowText, QPalette::ButtonText, QPalette::Text, QPalette::Button }; foreach( const QPalette::ColorRole& role, roles ) { copy.setColor( role, KColorUtils::mix( source.color( QPalette::Active, role ), source.color( QPalette::Disabled, role ), 1.0-ratio ) ); } return copy; } //____________________________________________________________________ QColor Helper::alphaColor( QColor color, qreal alpha ) const { if( alpha >= 0 && alpha < 1.0 ) { color.setAlphaF( alpha*color.alphaF() ); } return color; } //______________________________________________________________________________ void Helper::renderDebugFrame( QPainter* painter, const QRect& rect ) const { painter->save(); painter->setRenderHints( QPainter::Antialiasing ); painter->setBrush( Qt::NoBrush ); painter->setPen( Qt::red ); painter->drawRect( QRectF( rect ).adjusted( 0.5, 0.5, -0.5, -0.5 ) ); painter->restore(); } //______________________________________________________________________________ void Helper::renderFocusRect( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Sides sides ) const { if( !color.isValid() ) return; painter->save(); painter->setRenderHints( QPainter::Antialiasing ); painter->setBrush( color ); if( !( outline.isValid() && sides ) ) { painter->setPen( Qt::NoPen ); painter->drawRect( rect ); } else { painter->setClipRect( rect ); QRectF copy( rect ); copy.adjust( 0.5, 0.5, -0.5, -0.5 ); const qreal radius( frameRadius( -1.0 ) ); if( !(sides&SideTop) ) copy.adjust( 0, -radius, 0, 0 ); if( !(sides&SideBottom) ) copy.adjust( 0, 0, 0, radius ); if( !(sides&SideLeft) ) copy.adjust( -radius, 0, 0, 0 ); if( !(sides&SideRight) ) copy.adjust( 0, 0, radius, 0 ); painter->setPen( outline ); // painter->setBrush( Qt::NoBrush ); painter->drawRoundedRect( copy, radius, radius ); } painter->restore(); return; } //______________________________________________________________________________ void Helper::renderFocusLine( QPainter* painter, const QRect& rect, const QColor& color ) const { if( !color.isValid() ) return; painter->save(); painter->setRenderHint( QPainter::Antialiasing, false ); painter->setBrush( Qt::NoBrush ); painter->setPen( color ); painter->translate( 0, 2 ); painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); painter->restore(); } //______________________________________________________________________________ void Helper::renderFrame( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline ) const { painter->setRenderHint( QPainter::Antialiasing ); QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); qreal radius( frameRadius() ); // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); radius = qMax( radius - 1, qreal( 0.0 ) ); } else { painter->setPen( Qt::NoPen ); } // set brush if( color.isValid() ) painter->setBrush( color ); else painter->setBrush( Qt::NoBrush ); // render painter->drawRoundedRect( frameRect, radius, radius ); } //______________________________________________________________________________ void Helper::renderSidePanelFrame( QPainter* painter, const QRect& rect, const QColor& outline, Side side ) const { // check color if( !outline.isValid() ) return; // adjust rect QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); // setup painter painter->setRenderHint( QPainter::Antialiasing ); painter->setPen( outline ); // render switch( side ) { default: case SideLeft: frameRect.adjust( 0, 1, 0, -1 ); painter->drawLine( frameRect.topRight(), frameRect.bottomRight() ); break; case SideTop: frameRect.adjust( 1, 0, -1, 0 ); painter->drawLine( frameRect.topLeft(), frameRect.topRight() ); break; case SideRight: frameRect.adjust( 0, 1, 0, -1 ); painter->drawLine( frameRect.topLeft(), frameRect.bottomLeft() ); break; case SideBottom: frameRect.adjust( 1, 0, -1, 0 ); painter->drawLine( frameRect.bottomLeft(), frameRect.bottomRight() ); break; case AllSides: { const qreal radius( frameRadius( -1.0 ) ); painter->drawRoundedRect( frameRect, radius, radius ); break; } } } //______________________________________________________________________________ void Helper::renderMenuFrame( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, bool roundCorners ) const { // set brush if( color.isValid() ) painter->setBrush( color ); else painter->setBrush( Qt::NoBrush ); if( roundCorners ) { painter->setRenderHint( QPainter::Antialiasing ); QRectF frameRect( rect ); qreal radius( frameRadius() ); // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); radius = qMax( radius - 1, qreal( 0.0 ) ); } else painter->setPen( Qt::NoPen ); // render painter->drawRoundedRect( frameRect, radius, radius ); } else { painter->setRenderHint( QPainter::Antialiasing, false ); QRect frameRect( rect ); if( outline.isValid() ) { painter->setPen( outline ); frameRect.adjust( 0, 0, -1, -1 ); } else painter->setPen( Qt::NoPen ); painter->drawRect( frameRect ); } } //______________________________________________________________________________ void Helper::renderButtonFrame( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, const QColor& shadow, bool hasFocus, bool sunken ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); // copy rect QRectF frameRect( rect ); frameRect.adjust( 1, 1, -1, -1 ); qreal radius( frameRadius() ); // shadow if( sunken ) { frameRect.translate( 1, 1 ); } else if( shadow.isValid() ) { const qreal shadowRadius = qMax( radius - 1, qreal( 0.0 ) ); painter->setPen( QPen( shadow, 2 ) ); painter->setBrush( Qt::NoBrush ); painter->drawRoundedRect( shadowRect( frameRect ), shadowRadius, shadowRadius ); } if( outline.isValid() ) { QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() ); gradient.setColorAt( 0, outline.lighter( hasFocus ? 103:101 ) ); gradient.setColorAt( 1, outline.darker( hasFocus ? 110:103 ) ); painter->setPen( QPen( QBrush( gradient ), 1.0 ) ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); radius = qMax( radius - 1, qreal( 0.0 ) ); } else painter->setPen( Qt::NoPen ); // content if( color.isValid() ) { QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() ); gradient.setColorAt( 0, color.lighter( hasFocus ? 103:101 ) ); gradient.setColorAt( 1, color.darker( hasFocus ? 110:103 ) ); painter->setBrush( gradient ); } else painter->setBrush( Qt::NoBrush ); // render painter->drawRoundedRect( frameRect, radius, radius ); } //______________________________________________________________________________ void Helper::renderToolButtonFrame( QPainter* painter, const QRect& rect, const QColor& color, bool sunken ) const { // do nothing for invalid color if( !color.isValid() ) return; // setup painter painter->setRenderHints( QPainter::Antialiasing ); const QRectF baseRect( rect ); if( sunken ) { const qreal radius( frameRadius() ); painter->setPen( Qt::NoPen ); painter->setBrush( color ); const QRectF contentRect( baseRect.adjusted( 1, 1, -1, -1 ) ); painter->drawRoundedRect( contentRect, radius, radius ); } else { const qreal radius( frameRadius(-0.5) ); painter->setPen( color ); painter->setBrush( Qt::NoBrush ); const QRectF outlineRect( baseRect.adjusted( 1.5, 1.5, -1.5, -1.5 ) ); painter->drawRoundedRect( outlineRect, radius, radius ); } } //______________________________________________________________________________ void Helper::renderToolBoxFrame( QPainter* painter, const QRect& rect, int tabWidth, const QColor& outline ) const { if( !outline.isValid() ) return; // round radius const qreal radius( frameRadius() ); const QSizeF cornerSize( 2*radius, 2*radius ); // if rect - tabwidth is even, need to increase tabWidth by 1 unit // for anti aliasing if( !((rect.width() - tabWidth)%2) ) ++tabWidth; // adjust rect for antialiasing QRectF baseRect( rect ); baseRect.adjust( 0.5, 0.5, -0.5, -0.5 ); // create path QPainterPath path; path.moveTo( 0, baseRect.height()-1 ); path.lineTo( ( baseRect.width() - tabWidth )/2 - radius, baseRect.height()-1 ); path.arcTo( QRectF( QPointF( ( baseRect.width() - tabWidth )/2 - 2*radius, baseRect.height()-1 - 2*radius ), cornerSize ), 270, 90 ); path.lineTo( ( baseRect.width() - tabWidth )/2, radius ); path.arcTo( QRectF( QPointF( ( baseRect.width() - tabWidth )/2, 0 ), cornerSize ), 180, -90 ); path.lineTo( ( baseRect.width() + tabWidth )/2 -1 - radius, 0 ); path.arcTo( QRectF( QPointF( ( baseRect.width() + tabWidth )/2 - 1 - 2*radius, 0 ), cornerSize ), 90, -90 ); path.lineTo( ( baseRect.width() + tabWidth )/2 -1, baseRect.height()-1 - radius ); path.arcTo( QRectF( QPointF( ( baseRect.width() + tabWidth )/2 -1, baseRect.height()-1 - 2*radius ), cornerSize ), 180, 90 ); path.lineTo( baseRect.width()-1, baseRect.height()-1 ); // render painter->setRenderHints( QPainter::Antialiasing ); painter->setBrush( Qt::NoBrush ); painter->setPen( outline ); painter->translate( baseRect.topLeft() ); painter->drawPath( path ); return; } //______________________________________________________________________________ void Helper::renderTabWidgetFrame( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Corners corners ) const { painter->setRenderHint( QPainter::Antialiasing ); QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); qreal radius( frameRadius() ); // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); radius = qMax( radius-1, qreal( 0.0 ) ); } else painter->setPen( Qt::NoPen ); // set brush if( color.isValid() ) painter->setBrush( color ); else painter->setBrush( Qt::NoBrush ); // render QPainterPath path( roundedPath( frameRect, corners, radius ) ); painter->drawPath( path ); } //______________________________________________________________________________ void Helper::renderSelection( QPainter* painter, const QRect& rect, const QColor& color ) const { painter->setRenderHint( QPainter::Antialiasing ); painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRect( rect ); } //______________________________________________________________________________ void Helper::renderSeparator( QPainter* painter, const QRect& rect, const QColor& color, bool vertical ) const { painter->setRenderHint( QPainter::Antialiasing, false ); painter->setBrush( Qt::NoBrush ); painter->setPen( color ); if( vertical ) { painter->translate( rect.width()/2, 0 ); painter->drawLine( rect.topLeft(), rect.bottomLeft() ); } else { painter->translate( 0, rect.height()/2 ); painter->drawLine( rect.topLeft(), rect.topRight() ); } return; } //______________________________________________________________________________ void Helper::renderCheckBoxBackground( QPainter* painter, const QRect& rect, const QColor& color, bool sunken ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); // copy rect and radius QRectF frameRect( rect ); frameRect.adjust( 3, 3, -3, -3 ); if( sunken ) frameRect.translate(1, 1); painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRect( frameRect ); } //______________________________________________________________________________ void Helper::renderCheckBox( QPainter* painter, const QRect& rect, const QColor& color, const QColor& shadow, bool sunken, CheckBoxState state, qreal animation ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); // copy rect and radius QRectF frameRect( rect ); frameRect.adjust( 2, 2, -2, -2 ); qreal radius( frameRadius() ); // shadow if( sunken ) { frameRect.translate(1, 1); } else { painter->setPen( QPen( shadow, 1 ) ); painter->setBrush( Qt::NoBrush ); const qreal shadowRadius( radius + 0.5 ); painter->drawRoundedRect( shadowRect( frameRect ).adjusted( -0.5, -0.5, 0.5, 0.5 ), shadowRadius, shadowRadius ); } // content { painter->setPen( QPen( color, 1 ) ); painter->setBrush( Qt::NoBrush ); radius = qMax( radius-1, qreal( 0.0 ) ); const QRectF contentRect( frameRect.adjusted( 0.5, 0.5, -0.5, -0.5 ) ); painter->drawRoundedRect( contentRect, radius, radius ); } // mark if( state == CheckOn ) { painter->setBrush( color ); painter->setPen( Qt::NoPen ); const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); painter->drawRect( markerRect ); } else if( state == CheckPartial ) { QPen pen( color, 2 ); pen.setJoinStyle( Qt::MiterJoin ); painter->setPen( pen ); const QRectF markerRect( frameRect.adjusted( 4, 4, -4, -4 ) ); painter->drawRect( markerRect ); painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->setRenderHint( QPainter::Antialiasing, false ); QPainterPath path; path.moveTo( markerRect.topLeft() ); path.lineTo( markerRect.right() - 1, markerRect.top() ); path.lineTo( markerRect.left(), markerRect.bottom()-1 ); painter->drawPath( path ); } else if( state == CheckAnimated ) { const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); QPainterPath path; path.moveTo( markerRect.topRight() ); path.lineTo( markerRect.center() + animation*( markerRect.topLeft() - markerRect.center() ) ); path.lineTo( markerRect.bottomLeft() ); path.lineTo( markerRect.center() + animation*( markerRect.bottomRight() - markerRect.center() ) ); path.closeSubpath(); painter->setBrush( color ); painter->setPen( Qt::NoPen ); painter->drawPath( path ); } } //______________________________________________________________________________ void Helper::renderRadioButtonBackground( QPainter* painter, const QRect& rect, const QColor& color, bool sunken ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); // copy rect QRectF frameRect( rect ); frameRect.adjust( 3, 3, -3, -3 ); if( sunken ) frameRect.translate(1, 1); painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawEllipse( frameRect ); } //______________________________________________________________________________ void Helper::renderRadioButton( QPainter* painter, const QRect& rect, const QColor& color, const QColor& shadow, bool sunken, RadioButtonState state, qreal animation ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); // copy rect QRectF frameRect( rect ); frameRect.adjust( 2, 2, -2, -2 ); // shadow if( sunken ) { frameRect.translate( 1, 1 ); } else { painter->setPen( QPen( shadow, 1 ) ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( shadowRect( frameRect ).adjusted( -0.5, -0.5, 0.5, 0.5 ) ); } // content { painter->setPen( QPen( color, 1 ) ); painter->setBrush( Qt::NoBrush ); const QRectF contentRect( frameRect.adjusted( 0.5, 0.5, -0.5, -0.5 ) ); painter->drawEllipse( contentRect ); } // mark if( state == RadioOn ) { painter->setBrush( color ); painter->setPen( Qt::NoPen ); const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); painter->drawEllipse( markerRect ); } else if( state == RadioAnimated ) { painter->setBrush( color ); painter->setPen( Qt::NoPen ); QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); painter->translate( markerRect.center() ); painter->rotate( 45 ); markerRect.setWidth( markerRect.width()*animation ); markerRect.translate( -markerRect.center() ); painter->drawEllipse( markerRect ); } } //______________________________________________________________________________ void Helper::renderSliderGroove( QPainter* painter, const QRect& rect, const QColor& color ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); const QRectF baseRect( rect ); const qreal radius( 0.5*Metrics::Slider_GrooveThickness ); // content if( color.isValid() ) { painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRoundedRect( baseRect, radius, radius ); } return; } //______________________________________________________________________________ void Helper::renderDialGroove( QPainter* painter, const QRect& rect, const QColor& color ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); const QRectF baseRect( rect ); // content if( color.isValid() ) { const qreal penWidth( Metrics::Slider_GrooveThickness ); const QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) ); painter->setPen( QPen( color, penWidth ) ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( grooveRect ); } return; } //______________________________________________________________________________ void Helper::renderDialContents( QPainter* painter, const QRect& rect, const QColor& color, qreal first, qreal second ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); const QRectF baseRect( rect ); // content if( color.isValid() ) { // setup groove rect const qreal penWidth( Metrics::Slider_GrooveThickness ); const QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) ); // setup angles const int angleStart( first * 180 * 16 / M_PI ); const int angleSpan( (second - first ) * 180 * 16 / M_PI ); // setup pen if( angleSpan != 0 ) { QPen pen( color, penWidth ); pen.setCapStyle( Qt::RoundCap ); painter->setPen( pen ); painter->setBrush( Qt::NoBrush ); painter->drawArc( grooveRect, angleStart, angleSpan ); } } return; } //______________________________________________________________________________ void Helper::renderSliderHandle( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, const QColor& shadow, bool sunken ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); // copy rect QRectF frameRect( rect ); frameRect.adjust( 1, 1, -1, -1 ); // shadow if( shadow.isValid() && !sunken ) { painter->setPen( QPen( shadow, 2 ) ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( shadowRect( frameRect ) ); } // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); } else painter->setPen( Qt::NoPen ); // set brush if( color.isValid() ) painter->setBrush( color ); else painter->setBrush( Qt::NoBrush ); // render painter->drawEllipse( frameRect ); } //______________________________________________________________________________ void Helper::renderProgressBarGroove( QPainter* painter, const QRect& rect, const QColor& color ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); const QRectF baseRect( rect ); const qreal radius( 0.5*Metrics::ProgressBar_Thickness ); // content if( color.isValid() ) { painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRoundedRect( baseRect, radius, radius ); } return; } //______________________________________________________________________________ void Helper::renderProgressBarBusyContents( QPainter* painter, const QRect& rect, const QColor& first, const QColor& second, bool horizontal, bool reverse, int progress ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); const QRectF baseRect( rect ); const qreal radius( 0.5*Metrics::ProgressBar_Thickness ); // setup brush QPixmap pixmap( horizontal ? 2*Metrics::ProgressBar_BusyIndicatorSize : 1, horizontal ? 1:2*Metrics::ProgressBar_BusyIndicatorSize ); pixmap.fill( second ); if( horizontal ) { QPainter painter( &pixmap ); painter.setBrush( first ); painter.setPen( Qt::NoPen ); progress %= 2*Metrics::ProgressBar_BusyIndicatorSize; if( reverse ) progress = 2*Metrics::ProgressBar_BusyIndicatorSize - progress - 1; painter.drawRect( QRect( 0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1 ).translated( progress, 0 ) ); if( progress > Metrics::ProgressBar_BusyIndicatorSize ) { painter.drawRect( QRect( 0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1 ).translated( progress - 2*Metrics::ProgressBar_BusyIndicatorSize, 0 ) ); } } else { QPainter painter( &pixmap ); painter.setBrush( first ); painter.setPen( Qt::NoPen ); progress %= 2*Metrics::ProgressBar_BusyIndicatorSize; progress = 2*Metrics::ProgressBar_BusyIndicatorSize - progress - 1; painter.drawRect( QRect( 0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize ).translated( 0, progress ) ); if( progress > Metrics::ProgressBar_BusyIndicatorSize ) { painter.drawRect( QRect( 0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize ).translated( 0, progress - 2*Metrics::ProgressBar_BusyIndicatorSize ) ); } } painter->setPen( Qt::NoPen ); painter->setBrush( pixmap ); painter->drawRoundedRect( baseRect, radius, radius ); return; } //______________________________________________________________________________ void Helper::renderScrollBarHandle( QPainter* painter, const QRect& rect, const QColor& color ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); const QRectF baseRect( rect ); const qreal radius( 0.5 * std::min({baseRect.width(), baseRect.height(), (qreal)Metrics::ScrollBar_SliderWidth}) ); // content if( color.isValid() ) { painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRoundedRect( baseRect, radius, radius ); } return; } //______________________________________________________________________________ void Helper::renderTabBarTab( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Corners corners ) const { // setup painter painter->setRenderHint( QPainter::Antialiasing, true ); QRectF frameRect( rect ); qreal radius( frameRadius() ); // pen if( outline.isValid() ) { painter->setPen( outline ); frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); radius = qMax( radius-1, qreal( 0.0 ) ); } else painter->setPen( Qt::NoPen ); // brush if( color.isValid() ) painter->setBrush( color ); else painter->setBrush( Qt::NoBrush ); // render QPainterPath path( roundedPath( frameRect, corners, radius ) ); painter->drawPath( path ); } //______________________________________________________________________________ void Helper::renderArrow( QPainter* painter, const QRect& rect, const QColor& color, ArrowOrientation orientation ) const { // define polygon QPolygonF arrow; switch( orientation ) { case ArrowUp: arrow << QPointF( -4, 2 ) << QPointF( 0, -2 ) << QPointF( 4, 2 ); break; case ArrowDown: arrow << QPointF( -4, -2 ) << QPointF( 0, 2 ) << QPointF( 4, -2 ); break; case ArrowLeft: arrow << QPointF( 2, -4 ) << QPointF( -2, 0 ) << QPointF( 2, 4 ); break; case ArrowRight: arrow << QPointF( -2, -4 ) << QPointF( 2, 0 ) << QPointF( -2, 4 ); break; default: break; } painter->save(); painter->setRenderHints( QPainter::Antialiasing ); painter->translate( QRectF( rect ).center() ); painter->setBrush( Qt::NoBrush ); painter->setPen( QPen( color, 1.1 ) ); painter->drawPolyline( arrow ); painter->restore(); return; } //______________________________________________________________________________ void Helper::renderDecorationButton( QPainter* painter, const QRect& rect, const QColor& color, ButtonType buttonType, bool inverted ) const { painter->save(); painter->setViewport( rect ); painter->setWindow( 0, 0, 18, 18 ); painter->setRenderHints( QPainter::Antialiasing ); // initialize pen QPen pen; pen.setCapStyle( Qt::RoundCap ); pen.setJoinStyle( Qt::MiterJoin ); if( inverted ) { // render circle painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawEllipse( QRectF( 0, 0, 18, 18 ) ); // take out the inner part painter->setCompositionMode( QPainter::CompositionMode_DestinationOut ); painter->setBrush( Qt::NoBrush ); pen.setColor( Qt::black ); } else { painter->setBrush( Qt::NoBrush ); pen.setColor( color ); } pen.setCapStyle( Qt::RoundCap ); pen.setJoinStyle( Qt::MiterJoin ); pen.setWidthF( 1.1*qMax(1.0, 18.0/rect.width() ) ); painter->setPen( pen ); switch( buttonType ) { case ButtonClose: { painter->drawLine( QPointF( 5, 5 ), QPointF( 13, 13 ) ); painter->drawLine( 13, 5, 5, 13 ); break; } case ButtonMaximize: { painter->drawPolyline( QPolygonF() << QPointF( 4, 11 ) << QPointF( 9, 6 ) << QPointF( 14, 11 ) ); break; } case ButtonMinimize: { painter->drawPolyline( QPolygonF() << QPointF( 4, 7 ) << QPointF( 9, 12 ) << QPointF( 14, 7 ) ); break; } case ButtonRestore: { pen.setJoinStyle( Qt::RoundJoin ); painter->setPen( pen ); painter->drawPolygon( QPolygonF() << QPointF( 4.5, 9 ) << QPointF( 9, 4.5 ) << QPointF( 13.5, 9 ) << QPointF( 9, 13.5 ) ); break; } default: break; } painter->restore(); return; } //______________________________________________________________________________ bool Helper::isX11() { #if BREEZE_HAVE_X11 #if QT_VERSION >= 0x050000 static const bool s_isX11 = KWindowSystem::isPlatformX11(); return s_isX11; #else return true; #endif #endif return false; } //______________________________________________________________________________ bool Helper::isWayland() { #if QT_VERSION >= 0x050000 static const bool s_isWayland = KWindowSystem::isPlatformWayland(); return s_isWayland; #else return false; #endif } //______________________________________________________________________________ QRectF Helper::shadowRect( const QRectF& rect ) const { return rect.adjusted( 0.5, 0.5, -0.5, -0.5 ).translated( 0.5, 0.5 ); } //______________________________________________________________________________ QPainterPath Helper::roundedPath( const QRectF& rect, Corners corners, qreal radius ) const { QPainterPath path; // simple cases if( corners == 0 ) { path.addRect( rect ); return path; } if( corners == AllCorners ) { path.addRoundedRect( rect, radius, radius ); return path; } const QSizeF cornerSize( 2*radius, 2*radius ); // rotate counterclockwise // top left corner if( corners & CornerTopLeft ) { path.moveTo( rect.topLeft() + QPointF( radius, 0 ) ); path.arcTo( QRectF( rect.topLeft(), cornerSize ), 90, 90 ); } else path.moveTo( rect.topLeft() ); // bottom left corner if( corners & CornerBottomLeft ) { path.lineTo( rect.bottomLeft() - QPointF( 0, radius ) ); path.arcTo( QRectF( rect.bottomLeft() - QPointF( 0, 2*radius ), cornerSize ), 180, 90 ); } else path.lineTo( rect.bottomLeft() ); // bottom right corner if( corners & CornerBottomRight ) { path.lineTo( rect.bottomRight() - QPointF( radius, 0 ) ); path.arcTo( QRectF( rect.bottomRight() - QPointF( 2*radius, 2*radius ), cornerSize ), 270, 90 ); } else path.lineTo( rect.bottomRight() ); // top right corner if( corners & CornerTopRight ) { path.lineTo( rect.topRight() + QPointF( 0, radius ) ); path.arcTo( QRectF( rect.topRight() - QPointF( 2*radius, 0 ), cornerSize ), 0, 90 ); } else path.lineTo( rect.topRight() ); path.closeSubpath(); return path; } //________________________________________________________________________________________________________ bool Helper::compositingActive() const { #if BREEZE_HAVE_X11 if( isX11() ) { // direct call to X xcb_get_selection_owner_cookie_t cookie( xcb_get_selection_owner( connection(), _compositingManagerAtom ) ); ScopedPointer reply( xcb_get_selection_owner_reply( connection(), cookie, nullptr ) ); return reply && reply->owner; } #endif // use KWindowSystem return KWindowSystem::compositingActive(); } //____________________________________________________________________ bool Helper::hasAlphaChannel( const QWidget* widget ) const { return compositingActive() && widget && widget->testAttribute( Qt::WA_TranslucentBackground ); } //______________________________________________________________________________________ QPixmap Helper::highDpiPixmap( int width, int height ) const { #if QT_VERSION >= 0x050300 const qreal dpiRatio( qApp->devicePixelRatio() ); QPixmap pixmap( width*dpiRatio, height*dpiRatio ); pixmap.setDevicePixelRatio( dpiRatio ); return pixmap; #else return QPixmap( width, height ); #endif } //______________________________________________________________________________________ qreal Helper::devicePixelRatio( const QPixmap& pixmap ) const { #if QT_VERSION >= 0x050300 return pixmap.devicePixelRatio(); #else Q_UNUSED(pixmap); return 1; #endif } #if BREEZE_HAVE_X11 //____________________________________________________________________ xcb_connection_t* Helper::connection() { #if QT_VERSION >= 0x050000 return QX11Info::connection(); #else static xcb_connection_t* connection = nullptr; if( !connection ) { Display* display = QX11Info::display(); if( display ) connection = XGetXCBConnection( display ); } return connection; #endif } //____________________________________________________________________ xcb_atom_t Helper::createAtom( const QString& name ) const { if( isX11() ) { xcb_connection_t* connection( Helper::connection() ); xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, name.size(), qPrintable( name ) ) ); ScopedPointer reply( xcb_intern_atom_reply( connection, cookie, nullptr) ); return reply ? reply->atom:0; } else return 0; } #endif //____________________________________________________________________ void Helper::init() { #if BREEZE_HAVE_X11 if( isX11() ) { // create compositing screen const QString atomName( QStringLiteral( "_NET_WM_CM_S%1" ).arg( QX11Info::appScreen() ) ); _compositingManagerAtom = createAtom( atomName ); } #endif } } diff --git a/kstyle/breezeshadowhelper.cpp b/kstyle/breezeshadowhelper.cpp index 62911f59..7dedeeef 100644 --- a/kstyle/breezeshadowhelper.cpp +++ b/kstyle/breezeshadowhelper.cpp @@ -1,597 +1,597 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezeshadowhelper.h" #include "breeze.h" #include "breezehelper.h" #include "breezepropertynames.h" #include "breezestyleconfigdata.h" #include #include #include #include #include #include #include #include #if BREEZE_HAVE_X11 #include #endif #if BREEZE_HAVE_KWAYLAND #include #include #include #include #include #include #endif namespace Breeze { const char ShadowHelper::netWMShadowAtomName[] ="_KDE_NET_WM_SHADOW"; //_____________________________________________________ int ShadowHelper::shadowSize( int shadowSizeEnum ) { switch( shadowSizeEnum ) { default: case Breeze::StyleConfigData::ShadowLarge: return 16; case Breeze::StyleConfigData::ShadowNone: return 0; case Breeze::StyleConfigData::ShadowSmall: return 12; case Breeze::StyleConfigData::ShadowMedium: return 14; case Breeze::StyleConfigData::ShadowVeryLarge: return 24; } } //_____________________________________________________ ShadowHelper::ShadowHelper( QObject* parent, Helper& helper ): QObject( parent ), _helper( helper ) #if BREEZE_HAVE_X11 ,_gc( 0 ), _atom( 0 ) #endif #if BREEZE_HAVE_KWAYLAND , _shadowManager( nullptr ) , _shmPool( nullptr ) #endif { // delay till event dispatcher is running as Wayland is highly async QMetaObject::invokeMethod(this, "initializeWayland", Qt::QueuedConnection); } //_______________________________________________________ ShadowHelper::~ShadowHelper() { #if BREEZE_HAVE_X11 if( Helper::isX11() ) { foreach( const quint32& value, _pixmaps ) xcb_free_pixmap( Helper::connection(), value ); } #endif } //_______________________________________________________ void ShadowHelper::initializeWayland() { #if BREEZE_HAVE_KWAYLAND if( !Helper::isWayland() ) return; using namespace KWayland::Client; auto connection = ConnectionThread::fromApplication( this ); if( !connection ) { return; } auto registry = new Registry( connection ); registry->create( connection ); connect(registry, &Registry::interfacesAnnounced, this, [registry, this] { const auto interface = registry->interface( Registry::Interface::Shadow ); if( interface.name != 0 ) { _shadowManager = registry->createShadowManager( interface.name, interface.version, registry ); } const auto shmInterface = registry->interface( Registry::Interface::Shm ); if( shmInterface.name != 0 ) { _shmPool = registry->createShmPool( shmInterface.name, shmInterface.version, registry ); } } ); registry->setup(); connection->roundtrip(); #endif } //______________________________________________ void ShadowHelper::reset() { #if BREEZE_HAVE_X11 if( Helper::isX11() ) { foreach( const quint32& value, _pixmaps ) xcb_free_pixmap( Helper::connection(), value ); } #endif _pixmaps.clear(); _shadowTiles = TileSet(); } //_______________________________________________________ bool ShadowHelper::registerWidget( QWidget* widget, bool force ) { // make sure widget is not already registered if( _widgets.contains( widget ) ) return false; // check if widget qualifies if( !( force || acceptWidget( widget ) ) ) { return false; } // try create shadow directly if( installShadows( widget ) ) _widgets.insert( widget, widget->winId() ); else _widgets.insert( widget, 0 ); // install event filter widget->removeEventFilter( this ); widget->installEventFilter( this ); // connect destroy signal connect( widget, SIGNAL(destroyed(QObject*)), SLOT(objectDeleted(QObject*)) ); return true; } //_______________________________________________________ void ShadowHelper::unregisterWidget( QWidget* widget ) { if( _widgets.remove( widget ) ) { uninstallShadows( widget ); } } //_______________________________________________________ void ShadowHelper::loadConfig() { // reset reset(); // update property for registered widgets for( QMap::const_iterator iter = _widgets.constBegin(); iter != _widgets.constEnd(); ++iter ) { installShadows( iter.key() ); } } //_______________________________________________________ bool ShadowHelper::eventFilter( QObject* object, QEvent* event ) { if( Helper::isWayland() ) { #if BREEZE_HAVE_KWAYLAND QWidget* widget( static_cast( object ) ); if( event->type() == QEvent::Paint ) { auto iter = _widgetSurfaces.constFind( widget ); if( iter == _widgetSurfaces.constEnd() ) { // install shadows and update winId installShadows( widget ); } } else if( event->type() == QEvent::Hide ) { auto iter = _widgetSurfaces.find( widget ); if( iter != _widgetSurfaces.end() ) { _widgetSurfaces.erase( iter ); } } #endif } else if( Helper::isX11() ) { // check event type if( event->type() != QEvent::WinIdChange ) return false; // cast widget QWidget* widget( static_cast( object ) ); // install shadows and update winId if( installShadows( widget ) ) { _widgets.insert( widget, widget->winId() ); } } return false; } //_______________________________________________________ TileSet ShadowHelper::shadowTiles() { // metrics const int shadowSize = this->shadowSize( StyleConfigData::shadowSize() ); if( !shadowSize ) return TileSet(); else if( !_shadowTiles.isValid() ) { const QPalette palette( QApplication::palette() ); const QColor shadowColor( StyleConfigData::shadowColor() ); const int shadowOffset = qMax( shadowSize/2, Metrics::Shadow_Overlap*2 ); const int shadowStrength = StyleConfigData::shadowStrength(); // pixmap QPixmap pixmap = _helper.highDpiPixmap( shadowSize*2 ); pixmap.fill( Qt::transparent ); // create gradient // gaussian delta function auto alpha = [](qreal x) { return std::exp( -x*x/0.15 ); }; // color calculation delta function auto gradientStopColor = [](QColor color, int alpha) { color.setAlpha(alpha); return color; }; QRadialGradient radialGradient( shadowSize, shadowSize, shadowSize); for( int i = 0; i < 10; ++i ) { const qreal x( qreal( i )/9 ); radialGradient.setColorAt(x, gradientStopColor(shadowColor, alpha(x)*shadowStrength)); } radialGradient.setColorAt(1, gradientStopColor( shadowColor, 0 ) ); // fill QPainter p(&pixmap); p.setRenderHint( QPainter::Antialiasing, true ); p.fillRect( pixmap.rect(), radialGradient); p.setPen( Qt::NoPen ); p.setBrush( Qt::black ); QRectF innerRect( shadowSize - Metrics::Shadow_Overlap, shadowSize - shadowOffset - Metrics::Shadow_Overlap, 2*Metrics::Shadow_Overlap,shadowOffset + 2*Metrics::Shadow_Overlap ); p.setCompositionMode(QPainter::CompositionMode_DestinationOut ); const qreal radius( _helper.frameRadius() ); p.drawRoundedRect( innerRect, radius, radius ); p.end(); // create tiles from pixmap _shadowTiles = TileSet( pixmap, shadowSize, shadowSize, 1, 1 ); } return _shadowTiles; } //_______________________________________________________ void ShadowHelper::objectDeleted( QObject* object ) { _widgets.remove( static_cast( object ) ); } //_______________________________________________________ bool ShadowHelper::isMenu( QWidget* widget ) const { return qobject_cast( widget ); } //_______________________________________________________ bool ShadowHelper::isToolTip( QWidget* widget ) const { return widget->inherits( "QTipLabel" ) || (widget->windowFlags() & Qt::WindowType_Mask) == Qt::ToolTip; } //_______________________________________________________ bool ShadowHelper::isDockWidget( QWidget* widget ) const { return qobject_cast( widget ); } //_______________________________________________________ bool ShadowHelper::isToolBar( QWidget* widget ) const { return qobject_cast( widget ); } //_______________________________________________________ bool ShadowHelper::acceptWidget( QWidget* widget ) const { // flags if( widget->property( PropertyNames::netWMSkipShadow ).toBool() ) return false; if( widget->property( PropertyNames::netWMForceShadow ).toBool() ) return true; // menus if( isMenu( widget ) ) return true; // combobox dropdown lists if( widget->inherits( "QComboBoxPrivateContainer" ) ) return true; // tooltips if( isToolTip( widget ) && !widget->inherits( "Plasma::ToolTip" ) ) { return true; } // detached widgets if( isDockWidget( widget ) || isToolBar( widget ) ) { return true; } // reject return false; } //______________________________________________ const QVector& ShadowHelper::createPixmapHandles() { /** shadow atom and property specification available at http://community.kde.org/KWin/Shadow */ // create atom #if BREEZE_HAVE_X11 if( !_atom && Helper::isX11() ) _atom = _helper.createAtom( QLatin1String( netWMShadowAtomName ) ); #endif shadowTiles(); // make sure size is valid if( _pixmaps.empty() && _shadowTiles.isValid() ) { _pixmaps.append( createPixmap( _shadowTiles.pixmap( 1 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 2 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 5 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 8 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 7 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 6 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 3 ) ) ); _pixmaps.append( createPixmap( _shadowTiles.pixmap( 0 ) ) ); } // return relevant list of pixmap handles return _pixmaps; } //______________________________________________ quint32 ShadowHelper::createPixmap( const QPixmap& source ) { // do nothing for invalid pixmaps if( source.isNull() ) return 0; if( !Helper::isX11() ) return 0; /* in some cases, pixmap handle is invalid. This is the case notably when Qt uses to RasterEngine. In this case, we create an X11 Pixmap explicitly and draw the source pixmap on it. */ #if BREEZE_HAVE_X11 const int width( source.width() ); const int height( source.height() ); // create X11 pixmap xcb_pixmap_t pixmap = xcb_generate_id( Helper::connection() ); xcb_create_pixmap( Helper::connection(), 32, pixmap, QX11Info::appRootWindow(), width, height ); // create gc if( !_gc ) { _gc = xcb_generate_id( Helper::connection() ); - xcb_create_gc( Helper::connection(), _gc, pixmap, 0, 0x0 ); + xcb_create_gc( Helper::connection(), _gc, pixmap, 0, nullptr ); } // create image from QPixmap and assign to pixmap QImage image( source.toImage() ); xcb_put_image( Helper::connection(), XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, _gc, image.width(), image.height(), 0, 0, 0, 32, image.byteCount(), image.constBits()); return pixmap; #else return 0; #endif } //_______________________________________________________ bool ShadowHelper::installShadows( QWidget* widget ) { if( !widget ) return false; /* From bespin code. Supposibly prevent playing with some 'pseudo-widgets' that have winId matching some other -random- window */ if( !(widget->testAttribute(Qt::WA_WState_Created) && widget->internalWinId() )) { return false; } if( Helper::isX11() ) return installX11Shadows( widget ); if( Helper::isWayland() ) return installWaylandShadows( widget ); return false; } //_______________________________________________________ bool ShadowHelper::installX11Shadows( QWidget* widget ) { #if BREEZE_HAVE_X11 #ifndef QT_NO_XRENDER // create pixmap handles if needed const QVector& pixmaps( createPixmapHandles() ); if( pixmaps.size() != numPixmaps ) return false; // create data // add pixmap handles QVector data; foreach( const quint32& value, pixmaps ) { data.append( value ); } const QMargins margins = shadowMargins( widget ); const int topSize = margins.top(); const int bottomSize = margins.bottom(); const int leftSize( margins.left() ); const int rightSize( margins.right() ); // assign to data and xcb property data << topSize << rightSize << bottomSize << leftSize; xcb_change_property( Helper::connection(), XCB_PROP_MODE_REPLACE, widget->winId(), _atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData() ); xcb_flush( Helper::connection() ); return true; #endif #endif return false; } //_______________________________________________________ bool ShadowHelper::installWaylandShadows( QWidget* widget ) { #if BREEZE_HAVE_KWAYLAND if( widget->windowHandle()->parent() ) return false; if( !_shadowManager || !_shmPool ) return false; if( !_shadowTiles.isValid() ) return false; // create shadow using namespace KWayland::Client; auto s = Surface::fromWindow( widget->windowHandle() ); if( !s ) return false; auto shadow = _shadowManager->createShadow( s, widget ); if( !shadow->isValid() ) return false; // add the shadow elements shadow->attachTop( _shmPool->createBuffer( _shadowTiles.pixmap( 1 ).toImage() ) ); shadow->attachTopRight( _shmPool->createBuffer( _shadowTiles.pixmap( 2 ).toImage() ) ); shadow->attachRight( _shmPool->createBuffer( _shadowTiles.pixmap( 5 ).toImage() ) ); shadow->attachBottomRight( _shmPool->createBuffer( _shadowTiles.pixmap( 8 ).toImage() ) ); shadow->attachBottom( _shmPool->createBuffer( _shadowTiles.pixmap( 7 ).toImage() ) ); shadow->attachBottomLeft( _shmPool->createBuffer( _shadowTiles.pixmap( 6 ).toImage() ) ); shadow->attachLeft( _shmPool->createBuffer( _shadowTiles.pixmap( 3 ).toImage() ) ); shadow->attachTopLeft( _shmPool->createBuffer( _shadowTiles.pixmap( 0 ).toImage() ) ); shadow->setOffsets( shadowMargins( widget ) ); shadow->commit(); s->commit( Surface::CommitFlag::None ); _widgetSurfaces.insert(widget, s); return true; #else Q_UNUSED( widget ); #endif return false; } //_______________________________________________________ QMargins ShadowHelper::shadowMargins( QWidget* widget ) const { // get devicePixelRatio // for testing purposes only const qreal devicePixelRatio( _helper.devicePixelRatio( _shadowTiles.pixmap( 0 ) ) ); // metrics const int shadowSize = this->shadowSize( StyleConfigData::shadowSize() ); if( !shadowSize ) return QMargins(); const int shadowOffset = qMax( shadowSize/2, Metrics::Shadow_Overlap*2 ); // define shadows padding int size( shadowSize - Metrics::Shadow_Overlap ); int topSize = ( size - shadowOffset ) * devicePixelRatio; int bottomSize = size * devicePixelRatio; const int leftSize( size * devicePixelRatio ); const int rightSize( size * devicePixelRatio ); if( widget->inherits( "QBalloonTip" ) ) { // balloon tip needs special margins to deal with the arrow int top = 0; int bottom = 0; widget->getContentsMargins( nullptr, &top, nullptr, &bottom ); // also need to decrement default size further due to extra hard coded round corner size -= 2 * devicePixelRatio; // it seems arrow can be either to the top or the bottom. Adjust margins accordingly if( top > bottom ) topSize -= (top - bottom); else bottomSize -= (bottom - top ); } return QMargins( leftSize, topSize, rightSize, bottomSize ); } //_______________________________________________________ void ShadowHelper::uninstallShadows( QWidget* widget ) const { if( !( widget && widget->testAttribute(Qt::WA_WState_Created) ) ) return; if( Helper::isX11() ) uninstallX11Shadows( widget ); if( Helper::isWayland() ) uninstallWaylandShadows( widget ); } //_______________________________________________________ void ShadowHelper::uninstallX11Shadows( QWidget* widget ) const { #if BREEZE_HAVE_X11 xcb_delete_property( Helper::connection(), widget->winId(), _atom); #else Q_UNUSED( widget ) #endif } //_______________________________________________________ void ShadowHelper::uninstallWaylandShadows( QWidget* widget ) const { #if BREEZE_HAVE_KWAYLAND if( widget->windowHandle() && widget->windowHandle()->parent() ) return; if( !_shadowManager ) return; using namespace KWayland::Client; auto s = Surface::fromWindow( widget->windowHandle() ); if( !s ) return; _shadowManager->removeShadow( s ); s->commit( Surface::CommitFlag::None ); #else Q_UNUSED( widget ) #endif } } diff --git a/kstyle/breezestyle.cpp b/kstyle/breezestyle.cpp index b7a1c24a..9472a622 100644 --- a/kstyle/breezestyle.cpp +++ b/kstyle/breezestyle.cpp @@ -1,7167 +1,7167 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezestyle.h" #include "breeze.h" #include "breezeanimations.h" #include "breezeframeshadow.h" #include "breezemdiwindowshadow.h" #include "breezemnemonics.h" #include "breezepropertynames.h" #include "breezeshadowhelper.h" #include "breezesplitterproxy.h" #include "breezestyleconfigdata.h" #include "breezewidgetexplorer.h" #include "breezewindowmanager.h" #include "breezeblurhelper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace BreezePrivate { // needed to keep track of tabbars when being dragged class TabBarData: public QObject { public: //* constructor explicit TabBarData( QObject* parent ): QObject( parent ) {} //* assign target tabBar void lock( const QWidget* widget ) { _tabBar = widget; } //* true if tabbar is locked bool isLocked( const QWidget* widget ) const { return _tabBar && _tabBar.data() == widget; } //* release void release() { _tabBar.clear(); } private: //* pointer to target tabBar Breeze::WeakPointer _tabBar; }; //* needed to have spacing added to items in combobox class ComboBoxItemDelegate: public QItemDelegate { public: //* constructor explicit ComboBoxItemDelegate( QAbstractItemView* parent ): QItemDelegate( parent ), _proxy( parent->itemDelegate() ), _itemMargin( Breeze::Metrics::ItemView_ItemMarginWidth ) {} //* paint void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { // call either proxy or parent class if( _proxy ) _proxy.data()->paint( painter, option, index ); else QItemDelegate::paint( painter, option, index ); } //* size hint for index virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { // get size from either proxy or parent class auto size( _proxy ? _proxy.data()->sizeHint( option, index ): QItemDelegate::sizeHint( option, index ) ); // adjust and return if( size.isValid() ) { size.rheight() += _itemMargin*2; } return size; } private: //* proxy Breeze::WeakPointer _proxy; //* margin int _itemMargin; }; } namespace Breeze { //______________________________________________________________ Style::Style(): _addLineButtons( SingleButton ) , _subLineButtons( SingleButton ) #if BREEZE_USE_KDE4 , _helper( new Helper( "breeze" ) ) #else , _helper( new Helper( StyleConfigData::self()->sharedConfig() ) ) #endif , _shadowHelper( new ShadowHelper( this, *_helper ) ) , _animations( new Animations( this ) ) , _mnemonics( new Mnemonics( this ) ) #if !BREEZE_USE_KDE4 , _blurHelper( new BlurHelper( this ) ) #endif , _windowManager( new WindowManager( this ) ) , _frameShadowFactory( new FrameShadowFactory( this ) ) , _mdiWindowShadowFactory( new MdiWindowShadowFactory( this ) ) , _splitterFactory( new SplitterFactory( this ) ) , _widgetExplorer( new WidgetExplorer( this ) ) , _tabBarData( new BreezePrivate::TabBarData( this ) ) #if BREEZE_HAVE_KSTYLE||BREEZE_USE_KDE4 , SH_ArgbDndWindow( newStyleHint( QStringLiteral( "SH_ArgbDndWindow" ) ) ) , CE_CapacityBar( newControlElement( QStringLiteral( "CE_CapacityBar" ) ) ) #endif { // use DBus connection to update on breeze configuration change auto dbus = QDBusConnection::sessionBus(); dbus.connect( QString(), QStringLiteral( "/BreezeStyle" ), QStringLiteral( "org.kde.Breeze.Style" ), QStringLiteral( "reparseConfiguration" ), this, SLOT(configurationChanged()) ); dbus.connect( QString(), QStringLiteral( "/BreezeDecoration" ), QStringLiteral( "org.kde.Breeze.Style" ), QStringLiteral( "reparseConfiguration" ), this, SLOT(configurationChanged()) ); // call the slot directly; this initial call will set up things that also // need to be reset when the system palette changes loadConfiguration(); } //______________________________________________________________ Style::~Style() { delete _shadowHelper; delete _helper; } //______________________________________________________________ void Style::polish( QWidget* widget ) { if( !widget ) return; // register widget to animations _animations->registerWidget( widget ); _windowManager->registerWidget( widget ); _frameShadowFactory->registerWidget( widget, *_helper ); _mdiWindowShadowFactory->registerWidget( widget ); _shadowHelper->registerWidget( widget ); _splitterFactory->registerWidget( widget ); // enable mouse over effects for all necessary widgets if( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || widget->inherits( "KTextEditor::View" ) ) { widget->setAttribute( Qt::WA_Hover ); } // enforce translucency for drag and drop window if( widget->testAttribute( Qt::WA_X11NetWmWindowTypeDND ) && _helper->compositingActive() ) { widget->setAttribute( Qt::WA_TranslucentBackground ); widget->clearMask(); } // scrollarea polishing is somewhat complex. It is moved to a dedicated method polishScrollArea( qobject_cast( widget ) ); if( auto itemView = qobject_cast( widget ) ) { // enable mouse over effects in itemviews' viewport itemView->viewport()->setAttribute( Qt::WA_Hover ); } else if( auto groupBox = qobject_cast( widget ) ) { // checkable group boxes if( groupBox->isCheckable() ) { groupBox->setAttribute( Qt::WA_Hover ); } } else if( qobject_cast( widget ) && qobject_cast( widget->parent() ) ) { widget->setAttribute( Qt::WA_Hover ); } else if( qobject_cast( widget ) && qobject_cast( widget->parent() ) ) { widget->setAttribute( Qt::WA_Hover ); } else if( qobject_cast( widget ) && widget->parent() && widget->parent()->inherits( "KTitleWidget" ) ) { widget->setAutoFillBackground( false ); if( !StyleConfigData::titleWidgetDrawFrame() ) { widget->setBackgroundRole( QPalette::Window ); } } if( qobject_cast( widget ) ) { // remove opaque painting for scrollbars widget->setAttribute( Qt::WA_OpaquePaintEvent, false ); } else if( widget->inherits( "KTextEditor::View" ) ) { addEventFilter( widget ); } else if( auto toolButton = qobject_cast( widget ) ) { if( toolButton->autoRaise() ) { // for flat toolbuttons, adjust foreground and background role accordingly widget->setBackgroundRole( QPalette::NoRole ); widget->setForegroundRole( QPalette::WindowText ); } if( widget->parentWidget() && widget->parentWidget()->parentWidget() && widget->parentWidget()->parentWidget()->inherits( "Gwenview::SideBarGroup" ) ) { widget->setProperty( PropertyNames::toolButtonAlignment, Qt::AlignLeft ); } } else if( qobject_cast( widget ) ) { // add event filter on dock widgets // and alter palette widget->setAutoFillBackground( false ); widget->setContentsMargins( Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth ); addEventFilter( widget ); } else if( qobject_cast( widget ) ) { widget->setAutoFillBackground( false ); addEventFilter( widget ); } else if( qobject_cast( widget ) ) { widget->setBackgroundRole( QPalette::NoRole ); widget->setAutoFillBackground( false ); } else if( widget->parentWidget() && widget->parentWidget()->parentWidget() && qobject_cast( widget->parentWidget()->parentWidget()->parentWidget() ) ) { widget->setBackgroundRole( QPalette::NoRole ); widget->setAutoFillBackground( false ); widget->parentWidget()->setAutoFillBackground( false ); } else if( qobject_cast( widget ) ) { setTranslucentBackground( widget ); #if !BREEZE_USE_KDE4 if ( _helper->hasAlphaChannel( widget ) && StyleConfigData::menuOpacity() < 100 ) { _blurHelper->registerWidget( widget->window() ); } #endif #if QT_VERSION >= 0x050000 } else if( qobject_cast( widget ) ) { addEventFilter( widget ); #endif } else if( auto comboBox = qobject_cast( widget ) ) { if( !hasParent( widget, "QWebView" ) ) { auto itemView( comboBox->view() ); if( itemView && itemView->itemDelegate() && itemView->itemDelegate()->inherits( "QComboBoxDelegate" ) ) { itemView->setItemDelegate( new BreezePrivate::ComboBoxItemDelegate( itemView ) ); } } } else if( widget->inherits( "QComboBoxPrivateContainer" ) ) { addEventFilter( widget ); setTranslucentBackground( widget ); } else if( widget->inherits( "QTipLabel" ) ) { setTranslucentBackground( widget ); } // base class polishing ParentStyleClass::polish( widget ); } //______________________________________________________________ void Style::polishScrollArea( QAbstractScrollArea* scrollArea ) { // check argument if( !scrollArea ) return; // enable mouse over effect in sunken scrollareas that support focus if( scrollArea->frameShadow() == QFrame::Sunken && scrollArea->focusPolicy()&Qt::StrongFocus ) { scrollArea->setAttribute( Qt::WA_Hover ); } if( scrollArea->viewport() && scrollArea->inherits( "KItemListContainer" ) && scrollArea->frameShape() == QFrame::NoFrame ) { scrollArea->viewport()->setBackgroundRole( QPalette::Window ); scrollArea->viewport()->setForegroundRole( QPalette::WindowText ); } // add event filter, to make sure proper background is rendered behind scrollbars addEventFilter( scrollArea ); // force side panels as flat, on option if( scrollArea->inherits( "KDEPrivate::KPageListView" ) || scrollArea->inherits( "KDEPrivate::KPageTreeView" ) ) { scrollArea->setProperty( PropertyNames::sidePanelView, true ); } // for all side view panels, unbold font (design choice) if( scrollArea->property( PropertyNames::sidePanelView ).toBool() ) { // upbold list font auto font( scrollArea->font() ); font.setBold( false ); scrollArea->setFont( font ); // adjust background role if( !StyleConfigData::sidePanelDrawFrame() ) { scrollArea->setBackgroundRole( QPalette::Window ); scrollArea->setForegroundRole( QPalette::WindowText ); if( scrollArea->viewport() ) { scrollArea->viewport()->setBackgroundRole( QPalette::Window ); scrollArea->viewport()->setForegroundRole( QPalette::WindowText ); } // QTreeView animates expanding/collapsing branches. It paints them into a // temp pixmap whose background is unconditionally filled with the palette's // *base* color which is usually different from the window's color // cf. QTreeViewPrivate::renderTreeToPixmapForAnimation() if ( auto treeView = qobject_cast( scrollArea ) ) { if (treeView->isAnimated()) { QPalette pal( treeView->palette() ); pal.setColor( QPalette::Active, QPalette::Base, treeView->palette().color( treeView->backgroundRole() ) ); treeView->setPalette(pal); } } } } // disable autofill background for flat (== NoFrame) scrollareas, with QPalette::Window as a background // this fixes flat scrollareas placed in a tinted widget, such as groupboxes, tabwidgets or framed dock-widgets if( !(scrollArea->frameShape() == QFrame::NoFrame || scrollArea->backgroundRole() == QPalette::Window ) ) { return; } // get viewport and check background role auto viewport( scrollArea->viewport() ); if( !( viewport && viewport->backgroundRole() == QPalette::Window ) ) return; // change viewport autoFill background. // do the same for all children if the background role is QPalette::Window viewport->setAutoFillBackground( false ); QList children( viewport->findChildren() ); foreach( QWidget* child, children ) { if( child->parent() == viewport && child->backgroundRole() == QPalette::Window ) { child->setAutoFillBackground( false ); } } } //_______________________________________________________________ void Style::unpolish( QWidget* widget ) { // register widget to animations _animations->unregisterWidget( widget ); _frameShadowFactory->unregisterWidget( widget ); _mdiWindowShadowFactory->unregisterWidget( widget ); _shadowHelper->unregisterWidget( widget ); _windowManager->unregisterWidget( widget ); _splitterFactory->unregisterWidget( widget ); #if !BREEZE_USE_KDE4 _blurHelper->unregisterWidget( widget ); #endif // remove event filter if( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || widget->inherits( "QComboBoxPrivateContainer" ) ) { widget->removeEventFilter( this ); } ParentStyleClass::unpolish( widget ); } //______________________________________________________________ int Style::pixelMetric( PixelMetric metric, const QStyleOption* option, const QWidget* widget ) const { // handle special cases switch( metric ) { // frame width case PM_DefaultFrameWidth: if( qobject_cast( widget ) ) return Metrics::Menu_FrameWidth; if( qobject_cast( widget ) ) return Metrics::LineEdit_FrameWidth; #if QT_VERSION >= 0x050000 else if( isQtQuickControl( option, widget ) ) { const QString &elementType = option->styleObject->property( "elementType" ).toString(); if( elementType == QLatin1String( "edit" ) || elementType == QLatin1String( "spinbox" ) ) { return Metrics::LineEdit_FrameWidth; } else if( elementType == QLatin1String( "combobox" ) ) { return Metrics::ComboBox_FrameWidth; } } #endif // fallback return Metrics::Frame_FrameWidth; case PM_ComboBoxFrameWidth: { const auto comboBoxOption( qstyleoption_cast< const QStyleOptionComboBox*>( option ) ); return comboBoxOption && comboBoxOption->editable ? Metrics::LineEdit_FrameWidth : Metrics::ComboBox_FrameWidth; } case PM_SpinBoxFrameWidth: return Metrics::SpinBox_FrameWidth; case PM_ToolBarFrameWidth: return Metrics::ToolBar_FrameWidth; case PM_ToolTipLabelFrameWidth: return Metrics::ToolTip_FrameWidth; // layout case PM_LayoutLeftMargin: case PM_LayoutTopMargin: case PM_LayoutRightMargin: case PM_LayoutBottomMargin: { /* * use either Child margin or TopLevel margin, * depending on widget type */ if( ( option && ( option->state & QStyle::State_Window ) ) || ( widget && widget->isWindow() ) ) { return Metrics::Layout_TopLevelMarginWidth; } else if( widget && widget->inherits( "KPageView" ) ) { return 0; } else { return Metrics::Layout_ChildMarginWidth; } } case PM_LayoutHorizontalSpacing: return Metrics::Layout_DefaultSpacing; case PM_LayoutVerticalSpacing: return Metrics::Layout_DefaultSpacing; // buttons case PM_ButtonMargin: { // needs special case for kcalc buttons, to prevent the application to set too small margins if( widget && widget->inherits( "KCalcButton" ) ) return Metrics::Button_MarginWidth + 4; else return Metrics::Button_MarginWidth; } case PM_ButtonDefaultIndicator: return 0; case PM_ButtonShiftHorizontal: return 0; case PM_ButtonShiftVertical: return 0; // menubars case PM_MenuBarPanelWidth: return 0; case PM_MenuBarHMargin: return 0; case PM_MenuBarVMargin: return 0; case PM_MenuBarItemSpacing: return 0; case PM_MenuDesktopFrameWidth: return 0; // menu buttons case PM_MenuButtonIndicator: return Metrics::MenuButton_IndicatorWidth; // toolbars case PM_ToolBarHandleExtent: return Metrics::ToolBar_HandleExtent; case PM_ToolBarSeparatorExtent: return Metrics::ToolBar_SeparatorWidth; case PM_ToolBarExtensionExtent: return pixelMetric( PM_SmallIconSize, option, widget ) + 2*Metrics::ToolButton_MarginWidth; case PM_ToolBarItemMargin: return 0; case PM_ToolBarItemSpacing: return Metrics::ToolBar_ItemSpacing; // tabbars case PM_TabBarTabShiftVertical: return 0; case PM_TabBarTabShiftHorizontal: return 0; case PM_TabBarTabOverlap: return Metrics::TabBar_TabOverlap; case PM_TabBarBaseOverlap: return Metrics::TabBar_BaseOverlap; case PM_TabBarTabHSpace: return 2*Metrics::TabBar_TabMarginWidth; case PM_TabBarTabVSpace: return 2*Metrics::TabBar_TabMarginHeight; case PM_TabCloseIndicatorWidth: case PM_TabCloseIndicatorHeight: return pixelMetric( PM_SmallIconSize, option, widget ); // scrollbars case PM_ScrollBarExtent: return Metrics::ScrollBar_Extend; case PM_ScrollBarSliderMin: return Metrics::ScrollBar_MinSliderHeight; // title bar case PM_TitleBarHeight: return 2*Metrics::TitleBar_MarginWidth + pixelMetric( PM_SmallIconSize, option, widget ); // sliders case PM_SliderThickness: return Metrics::Slider_ControlThickness; case PM_SliderControlThickness: return Metrics::Slider_ControlThickness; case PM_SliderLength: return Metrics::Slider_ControlThickness; // checkboxes and radio buttons case PM_IndicatorWidth: return Metrics::CheckBox_Size; case PM_IndicatorHeight: return Metrics::CheckBox_Size; case PM_ExclusiveIndicatorWidth: return Metrics::CheckBox_Size; case PM_ExclusiveIndicatorHeight: return Metrics::CheckBox_Size; // list heaaders case PM_HeaderMarkSize: return Metrics::Header_ArrowSize; case PM_HeaderMargin: return Metrics::Header_MarginWidth; // dock widget // return 0 here, since frame is handled directly in polish case PM_DockWidgetFrameWidth: return 0; case PM_DockWidgetTitleMargin: return Metrics::Frame_FrameWidth; case PM_DockWidgetTitleBarButtonMargin: return Metrics::ToolButton_MarginWidth; case PM_SplitterWidth: return Metrics::Splitter_SplitterWidth; case PM_DockWidgetSeparatorExtent: return Metrics::Splitter_SplitterWidth; // fallback default: return ParentStyleClass::pixelMetric( metric, option, widget ); } } //______________________________________________________________ int Style::styleHint( StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData ) const { switch( hint ) { case SH_RubberBand_Mask: { if( auto mask = qstyleoption_cast( returnData ) ) { mask->region = option->rect; /* * need to check on widget before removing inner region * in order to still preserve rubberband in MainWindow and QGraphicsView * in QMainWindow because it looks better * in QGraphicsView because the painting fails completely otherwise */ if( widget && ( qobject_cast( widget->parent() ) || qobject_cast( widget->parent() ) || qobject_cast( widget->parent() ) ) ) { return true; } // also check if widget's parent is some itemView viewport if( widget && widget->parent() && qobject_cast( widget->parent()->parent() ) && static_cast( widget->parent()->parent() )->viewport() == widget->parent() ) { return true; } // mask out center mask->region -= insideMargin( option->rect, 1 ); return true; } return false; } case SH_ComboBox_ListMouseTracking: return true; case SH_MenuBar_MouseTracking: return true; case SH_Menu_MouseTracking: return true; case SH_Menu_SubMenuPopupDelay: return 150; case SH_Menu_SloppySubMenus: return true; #if QT_VERSION >= 0x050000 // TODO Qt6: drop deprecated SH_Widget_Animate case SH_Widget_Animate: return StyleConfigData::animationsEnabled(); case SH_Menu_SupportsSections: return true; #endif #if QT_VERSION >= 0x050A00 case SH_Widget_Animation_Duration: return StyleConfigData::animationsEnabled() ? StyleConfigData::animationsDuration() : 0; #endif case SH_DialogButtonBox_ButtonsHaveIcons: return true; case SH_GroupBox_TextLabelVerticalAlignment: return Qt::AlignVCenter; case SH_TabBar_Alignment: return StyleConfigData::tabBarDrawCenteredTabs() ? Qt::AlignCenter:Qt::AlignLeft; case SH_ToolBox_SelectedPageTitleBold: return false; case SH_ScrollBar_MiddleClickAbsolutePosition: return true; case SH_ScrollView_FrameOnlyAroundContents: return false; case SH_FormLayoutFormAlignment: return Qt::AlignLeft | Qt::AlignTop; case SH_FormLayoutLabelAlignment: return Qt::AlignRight; case SH_FormLayoutFieldGrowthPolicy: return QFormLayout::ExpandingFieldsGrow; case SH_FormLayoutWrapPolicy: return QFormLayout::DontWrapRows; case SH_MessageBox_TextInteractionFlags: return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; case SH_ProgressDialog_CenterCancelButton: return false; case SH_MessageBox_CenterButtons: return false; case SH_RequestSoftwareInputPanel: return RSIP_OnMouseClick; case SH_TitleBar_NoBorder: return true; case SH_DockWidget_ButtonsHaveFrame: return false; default: return ParentStyleClass::styleHint( hint, option, widget, returnData ); } } //______________________________________________________________ QRect Style::subElementRect( SubElement element, const QStyleOption* option, const QWidget* widget ) const { switch( element ) { case SE_PushButtonContents: return pushButtonContentsRect( option, widget ); case SE_CheckBoxContents: return checkBoxContentsRect( option, widget ); case SE_RadioButtonContents: return checkBoxContentsRect( option, widget ); case SE_LineEditContents: return lineEditContentsRect( option, widget ); case SE_ProgressBarGroove: return progressBarGrooveRect( option, widget ); case SE_ProgressBarContents: return progressBarContentsRect( option, widget ); case SE_ProgressBarLabel: return progressBarLabelRect( option, widget ); case SE_HeaderArrow: return headerArrowRect( option, widget ); case SE_HeaderLabel: return headerLabelRect( option, widget ); case SE_TabBarTabLeftButton: return tabBarTabLeftButtonRect( option, widget ); case SE_TabBarTabRightButton: return tabBarTabRightButtonRect( option, widget ); case SE_TabWidgetTabBar: return tabWidgetTabBarRect( option, widget ); case SE_TabWidgetTabContents: return tabWidgetTabContentsRect( option, widget ); case SE_TabWidgetTabPane: return tabWidgetTabPaneRect( option, widget ); case SE_TabWidgetLeftCorner: return tabWidgetCornerRect( SE_TabWidgetLeftCorner, option, widget ); case SE_TabWidgetRightCorner: return tabWidgetCornerRect( SE_TabWidgetRightCorner, option, widget ); case SE_ToolBoxTabContents: return toolBoxTabContentsRect( option, widget ); // fallback default: return ParentStyleClass::subElementRect( element, option, widget ); } } //______________________________________________________________ QRect Style::subControlRect( ComplexControl element, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { switch( element ) { case CC_GroupBox: return groupBoxSubControlRect( option, subControl, widget ); case CC_ToolButton: return toolButtonSubControlRect( option, subControl, widget ); case CC_ComboBox: return comboBoxSubControlRect( option, subControl, widget ); case CC_SpinBox: return spinBoxSubControlRect( option, subControl, widget ); case CC_ScrollBar: return scrollBarSubControlRect( option, subControl, widget ); case CC_Dial: return dialSubControlRect( option, subControl, widget ); case CC_Slider: return sliderSubControlRect( option, subControl, widget ); // fallback default: return ParentStyleClass::subControlRect( element, option, subControl, widget ); } } //______________________________________________________________ QSize Style::sizeFromContents( ContentsType element, const QStyleOption* option, const QSize& size, const QWidget* widget ) const { switch( element ) { case CT_CheckBox: return checkBoxSizeFromContents( option, size, widget ); case CT_RadioButton: return checkBoxSizeFromContents( option, size, widget ); case CT_LineEdit: return lineEditSizeFromContents( option, size, widget ); case CT_ComboBox: return comboBoxSizeFromContents( option, size, widget ); case CT_SpinBox: return spinBoxSizeFromContents( option, size, widget ); case CT_Slider: return sliderSizeFromContents( option, size, widget ); case CT_PushButton: return pushButtonSizeFromContents( option, size, widget ); case CT_ToolButton: return toolButtonSizeFromContents( option, size, widget ); case CT_MenuBar: return defaultSizeFromContents( option, size, widget ); case CT_MenuBarItem: return menuBarItemSizeFromContents( option, size, widget ); case CT_MenuItem: return menuItemSizeFromContents( option, size, widget ); case CT_ProgressBar: return progressBarSizeFromContents( option, size, widget ); case CT_TabWidget: return tabWidgetSizeFromContents( option, size, widget ); case CT_TabBarTab: return tabBarTabSizeFromContents( option, size, widget ); case CT_HeaderSection: return headerSectionSizeFromContents( option, size, widget ); case CT_ItemViewItem: return itemViewItemSizeFromContents( option, size, widget ); // fallback default: return ParentStyleClass::sizeFromContents( element, option, size, widget ); } } //______________________________________________________________ QStyle::SubControl Style::hitTestComplexControl( ComplexControl control, const QStyleOptionComplex* option, const QPoint& point, const QWidget* widget ) const { switch( control ) { case CC_ScrollBar: { auto grooveRect = subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ); if( grooveRect.contains( point ) ) { // Must be either page up/page down, or just click on the slider. auto sliderRect = subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ); if( sliderRect.contains( point ) ) return SC_ScrollBarSlider; else if( preceeds( point, sliderRect, option ) ) return SC_ScrollBarSubPage; else return SC_ScrollBarAddPage; } // This is one of the up/down buttons. First, decide which one it is. if( preceeds( point, grooveRect, option ) ) { if( _subLineButtons == DoubleButton ) { auto buttonRect = scrollBarInternalSubControlRect( option, SC_ScrollBarSubLine ); return scrollBarHitTest( buttonRect, point, option ); } else return SC_ScrollBarSubLine; } if( _addLineButtons == DoubleButton ) { auto buttonRect = scrollBarInternalSubControlRect( option, SC_ScrollBarAddLine ); return scrollBarHitTest( buttonRect, point, option ); } else return SC_ScrollBarAddLine; } // fallback default: return ParentStyleClass::hitTestComplexControl( control, option, point, widget ); } } //______________________________________________________________ void Style::drawPrimitive( PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { StylePrimitive fcn; switch( element ) { case PE_PanelButtonCommand: fcn = &Style::drawPanelButtonCommandPrimitive; break; case PE_PanelButtonTool: fcn = &Style::drawPanelButtonToolPrimitive; break; case PE_PanelScrollAreaCorner: fcn = &Style::drawPanelScrollAreaCornerPrimitive; break; case PE_PanelMenu: fcn = &Style::drawPanelMenuPrimitive; break; case PE_PanelTipLabel: fcn = &Style::drawPanelTipLabelPrimitive; break; case PE_PanelItemViewItem: fcn = &Style::drawPanelItemViewItemPrimitive; break; case PE_IndicatorCheckBox: fcn = &Style::drawIndicatorCheckBoxPrimitive; break; case PE_IndicatorRadioButton: fcn = &Style::drawIndicatorRadioButtonPrimitive; break; case PE_IndicatorButtonDropDown: fcn = &Style::drawIndicatorButtonDropDownPrimitive; break; case PE_IndicatorTabClose: fcn = &Style::drawIndicatorTabClosePrimitive; break; case PE_IndicatorTabTear: fcn = &Style::drawIndicatorTabTearPrimitive; break; case PE_IndicatorArrowUp: fcn = &Style::drawIndicatorArrowUpPrimitive; break; case PE_IndicatorArrowDown: fcn = &Style::drawIndicatorArrowDownPrimitive; break; case PE_IndicatorArrowLeft: fcn = &Style::drawIndicatorArrowLeftPrimitive; break; case PE_IndicatorArrowRight: fcn = &Style::drawIndicatorArrowRightPrimitive; break; case PE_IndicatorHeaderArrow: fcn = &Style::drawIndicatorHeaderArrowPrimitive; break; case PE_IndicatorToolBarHandle: fcn = &Style::drawIndicatorToolBarHandlePrimitive; break; case PE_IndicatorToolBarSeparator: fcn = &Style::drawIndicatorToolBarSeparatorPrimitive; break; case PE_IndicatorBranch: fcn = &Style::drawIndicatorBranchPrimitive; break; case PE_FrameStatusBar: fcn = &Style::emptyPrimitive; break; case PE_Frame: fcn = &Style::drawFramePrimitive; break; case PE_FrameLineEdit: fcn = &Style::drawFrameLineEditPrimitive; break; case PE_FrameMenu: fcn = &Style::drawFrameMenuPrimitive; break; case PE_FrameGroupBox: fcn = &Style::drawFrameGroupBoxPrimitive; break; case PE_FrameTabWidget: fcn = &Style::drawFrameTabWidgetPrimitive; break; case PE_FrameTabBarBase: fcn = &Style::drawFrameTabBarBasePrimitive; break; case PE_FrameWindow: fcn = &Style::drawFrameWindowPrimitive; break; case PE_FrameFocusRect: fcn = _frameFocusPrimitive; break; // fallback default: break; } painter->save(); // call function if implemented if( !( fcn && fcn( *this, option, painter, widget ) ) ) { ParentStyleClass::drawPrimitive( element, option, painter, widget ); } painter->restore(); } //______________________________________________________________ void Style::drawControl( ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { StyleControl fcn; #if BREEZE_HAVE_KSTYLE||BREEZE_USE_KDE4 if( element == CE_CapacityBar ) { fcn = &Style::drawProgressBarControl; } else #endif switch( element ) { case CE_PushButtonBevel: fcn = &Style::drawPanelButtonCommandPrimitive; break; case CE_PushButtonLabel: fcn = &Style::drawPushButtonLabelControl; break; case CE_CheckBoxLabel: fcn = &Style::drawCheckBoxLabelControl; break; case CE_RadioButtonLabel: fcn = &Style::drawCheckBoxLabelControl; break; case CE_ToolButtonLabel: fcn = &Style::drawToolButtonLabelControl; break; case CE_ComboBoxLabel: fcn = &Style::drawComboBoxLabelControl; break; case CE_MenuBarEmptyArea: fcn = &Style::emptyControl; break; case CE_MenuBarItem: fcn = &Style::drawMenuBarItemControl; break; case CE_MenuItem: fcn = &Style::drawMenuItemControl; break; case CE_ToolBar: fcn = &Style::emptyControl; break; case CE_ProgressBar: fcn = &Style::drawProgressBarControl; break; case CE_ProgressBarContents: fcn = &Style::drawProgressBarContentsControl; break; case CE_ProgressBarGroove: fcn = &Style::drawProgressBarGrooveControl; break; case CE_ProgressBarLabel: fcn = &Style::drawProgressBarLabelControl; break; case CE_ScrollBarSlider: fcn = &Style::drawScrollBarSliderControl; break; case CE_ScrollBarAddLine: fcn = &Style::drawScrollBarAddLineControl; break; case CE_ScrollBarSubLine: fcn = &Style::drawScrollBarSubLineControl; break; case CE_ScrollBarAddPage: fcn = &Style::emptyControl; break; case CE_ScrollBarSubPage: fcn = &Style::emptyControl; break; case CE_ShapedFrame: fcn = &Style::drawShapedFrameControl; break; case CE_RubberBand: fcn = &Style::drawRubberBandControl; break; case CE_SizeGrip: fcn = &Style::emptyControl; break; case CE_HeaderSection: fcn = &Style::drawHeaderSectionControl; break; case CE_HeaderEmptyArea: fcn = &Style::drawHeaderEmptyAreaControl; break; case CE_TabBarTabLabel: fcn = &Style::drawTabBarTabLabelControl; break; case CE_TabBarTabShape: fcn = &Style::drawTabBarTabShapeControl; break; case CE_ToolBoxTabLabel: fcn = &Style::drawToolBoxTabLabelControl; break; case CE_ToolBoxTabShape: fcn = &Style::drawToolBoxTabShapeControl; break; case CE_DockWidgetTitle: fcn = &Style::drawDockWidgetTitleControl; break; // fallback default: break; } painter->save(); // call function if implemented if( !( fcn && fcn( *this, option, painter, widget ) ) ) { ParentStyleClass::drawControl( element, option, painter, widget ); } painter->restore(); } //______________________________________________________________ void Style::drawComplexControl( ComplexControl element, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { StyleComplexControl fcn; switch( element ) { case CC_GroupBox: fcn = &Style::drawGroupBoxComplexControl; break; case CC_ToolButton: fcn = &Style::drawToolButtonComplexControl; break; case CC_ComboBox: fcn = &Style::drawComboBoxComplexControl; break; case CC_SpinBox: fcn = &Style::drawSpinBoxComplexControl; break; case CC_Slider: fcn = &Style::drawSliderComplexControl; break; case CC_Dial: fcn = &Style::drawDialComplexControl; break; case CC_ScrollBar: fcn = &Style::drawScrollBarComplexControl; break; case CC_TitleBar: fcn = &Style::drawTitleBarComplexControl; break; // fallback default: break; } painter->save(); // call function if implemented if( !( fcn && fcn( *this, option, painter, widget ) ) ) { ParentStyleClass::drawComplexControl( element, option, painter, widget ); } painter->restore(); } //___________________________________________________________________________________ void Style::drawItemText( QPainter* painter, const QRect& rect, int flags, const QPalette& palette, bool enabled, const QString &text, QPalette::ColorRole textRole ) const { // hide mnemonics if requested if( !_mnemonics->enabled() && ( flags&Qt::TextShowMnemonic ) && !( flags&Qt::TextHideMnemonic ) ) { flags &= ~Qt::TextShowMnemonic; flags |= Qt::TextHideMnemonic; } // make sure vertical alignment is defined // fallback on Align::VCenter if not if( !(flags&Qt::AlignVertical_Mask) ) flags |= Qt::AlignVCenter; if( _animations->widgetEnabilityEngine().enabled() ) { /* * check if painter engine is registered to WidgetEnabilityEngine, and animated * if yes, merge the palettes. Note: a static_cast is safe here, since only the address * of the pointer is used, not the actual content. */ const QWidget* widget( static_cast( painter->device() ) ); if( _animations->widgetEnabilityEngine().isAnimated( widget, AnimationEnable ) ) { const QPalette copy( _helper->disabledPalette( palette, _animations->widgetEnabilityEngine().opacity( widget, AnimationEnable ) ) ); return ParentStyleClass::drawItemText( painter, rect, flags, copy, enabled, text, textRole ); } } // fallback return ParentStyleClass::drawItemText( painter, rect, flags, palette, enabled, text, textRole ); } //_____________________________________________________________________ bool Style::eventFilter( QObject *object, QEvent *event ) { if( auto dockWidget = qobject_cast( object ) ) { return eventFilterDockWidget( dockWidget, event ); } else if( auto subWindow = qobject_cast( object ) ) { return eventFilterMdiSubWindow( subWindow, event ); } #if QT_VERSION >= 0x050000 else if( auto commandLinkButton = qobject_cast( object ) ) { return eventFilterCommandLinkButton( commandLinkButton, event ); } #endif // cast to QWidget QWidget *widget = static_cast( object ); if( widget->inherits( "QAbstractScrollArea" ) || widget->inherits( "KTextEditor::View" ) ) { return eventFilterScrollArea( widget, event ); } else if( widget->inherits( "QComboBoxPrivateContainer" ) ) { return eventFilterComboBoxContainer( widget, event ); } // fallback return ParentStyleClass::eventFilter( object, event ); } //____________________________________________________________________________ bool Style::eventFilterScrollArea( QWidget* widget, QEvent* event ) { switch( event->type() ) { case QEvent::Paint: { // get scrollarea viewport auto scrollArea( qobject_cast( widget ) ); QWidget* viewport; if( !( scrollArea && (viewport = scrollArea->viewport()) ) ) break; // get scrollarea horizontal and vertical containers QWidget* child( nullptr ); QList children; if( ( child = scrollArea->findChild( "qt_scrollarea_vcontainer" ) ) && child->isVisible() ) { children.append( child ); } if( ( child = scrollArea->findChild( "qt_scrollarea_hcontainer" ) ) && child->isVisible() ) { children.append( child ); } if( children.empty() ) break; if( !scrollArea->styleSheet().isEmpty() ) break; // make sure proper background is rendered behind the containers QPainter painter( scrollArea ); painter.setClipRegion( static_cast( event )->region() ); painter.setPen( Qt::NoPen ); // decide background color const QPalette::ColorRole role( viewport->backgroundRole() ); QColor background; if( role == QPalette::Window && hasAlteredBackground( viewport ) ) background = _helper->frameBackgroundColor( viewport->palette() ); else background = viewport->palette().color( role ); painter.setBrush( background ); // render foreach( auto* child, children ) { painter.drawRect( child->geometry() ); } } break; case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { // case event QMouseEvent* mouseEvent( static_cast( event ) ); // get frame framewidth - const int frameWidth( pixelMetric( PM_DefaultFrameWidth, 0, widget ) ); + const int frameWidth( pixelMetric( PM_DefaultFrameWidth, nullptr, widget ) ); // find list of scrollbars QList scrollBars; if( auto scrollArea = qobject_cast( widget ) ) { if( scrollArea->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff ) scrollBars.append( scrollArea->horizontalScrollBar() ); if( scrollArea->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff )scrollBars.append( scrollArea->verticalScrollBar() ); } else if( widget->inherits( "KTextEditor::View" ) ) { scrollBars = widget->findChildren(); } // loop over found scrollbars foreach( QScrollBar* scrollBar, scrollBars ) { if( !( scrollBar && scrollBar->isVisible() ) ) continue; QPoint offset; if( scrollBar->orientation() == Qt::Horizontal ) offset = QPoint( 0, frameWidth ); else offset = QPoint( QApplication::isLeftToRight() ? frameWidth : -frameWidth, 0 ); // map position to scrollarea QPoint position( scrollBar->mapFrom( widget, mouseEvent->pos() - offset ) ); // check if contains if( !scrollBar->rect().contains( position ) ) continue; // copy event, send and return QMouseEvent copy( mouseEvent->type(), position, scrollBar->mapToGlobal( position ), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); QCoreApplication::sendEvent( scrollBar, © ); event->setAccepted( true ); return true; } break; } default: break; } return ParentStyleClass::eventFilter( widget, event ); } //_________________________________________________________ bool Style::eventFilterComboBoxContainer( QWidget* widget, QEvent* event ) { if( event->type() == QEvent::Paint ) { QPainter painter( widget ); auto paintEvent = static_cast( event ); painter.setClipRegion( paintEvent->region() ); const auto rect( widget->rect() ); const auto& palette( widget->palette() ); const auto background( _helper->frameBackgroundColor( palette ) ); const auto outline( _helper->frameOutlineColor( palette ) ); const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); if( hasAlpha ) { painter.setCompositionMode( QPainter::CompositionMode_Source ); _helper->renderMenuFrame( &painter, rect, background, outline, true ); } else { _helper->renderMenuFrame( &painter, rect, background, outline, false ); } } return false; } //____________________________________________________________________________ bool Style::eventFilterDockWidget( QDockWidget* dockWidget, QEvent* event ) { if( event->type() == QEvent::Paint ) { // create painter and clip QPainter painter( dockWidget ); QPaintEvent *paintEvent = static_cast( event ); painter.setClipRegion( paintEvent->region() ); // store palette and set colors const auto& palette( dockWidget->palette() ); const auto background( _helper->frameBackgroundColor( palette ) ); const auto outline( _helper->frameOutlineColor( palette ) ); // store rect const auto rect( dockWidget->rect() ); // render if( dockWidget->isFloating() ) { _helper->renderMenuFrame( &painter, rect, background, outline, false ); } else if( StyleConfigData::dockWidgetDrawFrame() || (dockWidget->features()&QDockWidget::AllDockWidgetFeatures) ) { _helper->renderFrame( &painter, rect, background, outline ); } } return false; } //____________________________________________________________________________ bool Style::eventFilterMdiSubWindow( QMdiSubWindow* subWindow, QEvent* event ) { if( event->type() == QEvent::Paint ) { QPainter painter( subWindow ); QPaintEvent* paintEvent( static_cast( event ) ); painter.setClipRegion( paintEvent->region() ); const auto rect( subWindow->rect() ); const auto background( subWindow->palette().color( QPalette::Window ) ); if( subWindow->isMaximized() ) { // full painting painter.setPen( Qt::NoPen ); painter.setBrush( background ); painter.drawRect( rect ); } else { // framed painting _helper->renderMenuFrame( &painter, rect, background, QColor() ); } } // continue with normal painting return false; } //____________________________________________________________________________ #if QT_VERSION >= 0x050000 bool Style::eventFilterCommandLinkButton( QCommandLinkButton* button, QEvent* event ) { if( event->type() == QEvent::Paint ) { // painter QPainter painter( button ); painter.setClipRegion( static_cast( event )->region() ); const bool isFlat = false; // option QStyleOptionButton option; option.initFrom( button ); option.features |= QStyleOptionButton::CommandLinkButton; if( isFlat ) option.features |= QStyleOptionButton::Flat; option.text = QString(); option.icon = QIcon(); if( button->isChecked() ) option.state|=State_On; if( button->isDown() ) option.state|=State_Sunken; // frame drawControl(QStyle::CE_PushButton, &option, &painter, button ); // offset const int margin( Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); QPoint offset( margin, margin ); if( button->isDown() && !isFlat ) painter.translate( 1, 1 ); { offset += QPoint( 1, 1 ); } // state const State& state( option.state ); const bool enabled( state & State_Enabled ); bool mouseOver( enabled && ( state & State_MouseOver ) ); bool hasFocus( enabled && ( state & State_HasFocus ) ); // icon if( !button->icon().isNull() ) { const auto pixmapSize( button->icon().actualSize( button->iconSize() ) ); const QRect pixmapRect( QPoint( offset.x(), button->description().isEmpty() ? (button->height() - pixmapSize.height())/2:offset.y() ), pixmapSize ); const QPixmap pixmap( button->icon().pixmap(pixmapSize, enabled ? QIcon::Normal : QIcon::Disabled, button->isChecked() ? QIcon::On : QIcon::Off) ); drawItemPixmap( &painter, pixmapRect, Qt::AlignCenter, pixmap ); offset.rx() += pixmapSize.width() + Metrics::Button_ItemSpacing; } // text rect QRect textRect( offset, QSize( button->size().width() - offset.x() - margin, button->size().height() - 2*margin ) ); const QPalette::ColorRole textRole = (enabled && hasFocus && !mouseOver && !isFlat ) ? QPalette::HighlightedText : QPalette::ButtonText; if( !button->text().isEmpty() ) { QFont font( button->font() ); font.setBold( true ); painter.setFont( font ); if( button->description().isEmpty() ) { drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole ); } else { drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignTop|Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole ); textRect.setTop( textRect.top() + QFontMetrics( font ).height() ); } painter.setFont( button->font() ); } if( !button->description().isEmpty() ) { drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextWordWrap, button->palette(), enabled, button->description(), textRole ); } return true; } // continue with normal painting return false; } #endif //_____________________________________________________________________ void Style::configurationChanged() { // reload #if BREEZE_USE_KDE4 StyleConfigData::self()->readConfig(); #else StyleConfigData::self()->load(); #endif // reload configuration loadConfiguration(); } //____________________________________________________________________ QIcon Style::standardIconImplementation( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const { // lookup cache if( _iconCache.contains( standardPixmap ) ) return _iconCache.value( standardPixmap ); QIcon icon; switch( standardPixmap ) { case SP_TitleBarNormalButton: case SP_TitleBarMinButton: case SP_TitleBarMaxButton: case SP_TitleBarCloseButton: case SP_DockWidgetCloseButton: icon = titleBarButtonIcon( standardPixmap, option, widget ); break; case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: icon = toolBarExtensionIcon( standardPixmap, option, widget ); break; default: break; } if( icon.isNull() ) { // do not cache parent style icon, since it may change at runtime #if QT_VERSION >= 0x050000 return ParentStyleClass::standardIcon( standardPixmap, option, widget ); #else return ParentStyleClass::standardIconImplementation( standardPixmap, option, widget ); #endif } else { const_cast(&_iconCache)->insert( standardPixmap, icon ); return icon; } } //_____________________________________________________________________ void Style::loadConfiguration() { // load helper configuration _helper->loadConfig(); // reinitialize engines _animations->setupEngines(); _windowManager->initialize(); // mnemonics _mnemonics->setMode( StyleConfigData::mnemonicsMode() ); // splitter proxy _splitterFactory->setEnabled( StyleConfigData::splitterProxyEnabled() ); // reset shadow tiles _shadowHelper->loadConfig(); // set mdiwindow factory shadow tiles _mdiWindowShadowFactory->setShadowTiles( _shadowHelper->shadowTiles() ); // clear icon cache _iconCache.clear(); // scrollbar buttons switch( StyleConfigData::scrollBarAddLineButtons() ) { case 0: _addLineButtons = NoButton; break; case 1: _addLineButtons = SingleButton; break; default: case 2: _addLineButtons = DoubleButton; break; } switch( StyleConfigData::scrollBarSubLineButtons() ) { case 0: _subLineButtons = NoButton; break; case 1: _subLineButtons = SingleButton; break; default: case 2: _subLineButtons = DoubleButton; break; } // frame focus if( StyleConfigData::viewDrawFocusIndicator() ) _frameFocusPrimitive = &Style::drawFrameFocusRectPrimitive; else _frameFocusPrimitive = &Style::emptyPrimitive; // widget explorer _widgetExplorer->setEnabled( StyleConfigData::widgetExplorerEnabled() ); _widgetExplorer->setDrawWidgetRects( StyleConfigData::drawWidgetRects() ); } //___________________________________________________________________________________________________________________ QRect Style::pushButtonContentsRect( const QStyleOption* option, const QWidget* ) const { return insideMargin( option->rect, Metrics::Frame_FrameWidth ); } //___________________________________________________________________________________________________________________ QRect Style::checkBoxContentsRect( const QStyleOption* option, const QWidget* ) const { return visualRect( option, option->rect.adjusted( Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0 ) ); } //___________________________________________________________________________________________________________________ QRect Style::lineEditContentsRect( const QStyleOption* option, const QWidget* widget ) const { // cast option and check const auto frameOption( qstyleoption_cast( option ) ); if( !frameOption ) return option->rect; // check flatness const bool flat( frameOption->lineWidth == 0 ); if( flat ) return option->rect; // copy rect and take out margins auto rect( option->rect ); // take out margins if there is enough room const int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); if( rect.height() >= option->fontMetrics.height() + 2*frameWidth ) return insideMargin( rect, frameWidth ); else return rect; } //___________________________________________________________________________________________________________________ QRect Style::progressBarGrooveRect( const QStyleOption* option, const QWidget* widget ) const { // cast option and check const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return option->rect; // get flags and orientation const bool textVisible( progressBarOption->textVisible ); const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); const auto progressBarOption2( qstyleoption_cast( option ) ); const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); // copy rectangle and adjust auto rect( option->rect ); const int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); if( horizontal ) rect = insideMargin( rect, frameWidth, 0 ); else rect = insideMargin( rect, 0, frameWidth ); if( textVisible && !busy && horizontal ) { auto textRect( subElementRect( SE_ProgressBarLabel, option, widget ) ); textRect = visualRect( option, textRect ); rect.setRight( textRect.left() - Metrics::ProgressBar_ItemSpacing - 1 ); rect = visualRect( option, rect ); rect = centerRect( rect, rect.width(), Metrics::ProgressBar_Thickness ); } else if( horizontal ) { rect = centerRect( rect, rect.width(), Metrics::ProgressBar_Thickness ); } else { rect = centerRect( rect, Metrics::ProgressBar_Thickness, rect.height() ); } return rect; } //___________________________________________________________________________________________________________________ QRect Style::progressBarContentsRect( const QStyleOption* option, const QWidget* widget ) const { // cast option and check const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return QRect(); // get groove rect const auto rect( progressBarGrooveRect( option, widget ) ); // in busy mode, grooveRect is used const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); if( busy ) return rect; // get orientation const auto progressBarOption2( qstyleoption_cast( option ) ); const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); // check inverted appearance const bool inverted( progressBarOption2 ? progressBarOption2->invertedAppearance : false ); // get progress and steps const qreal progress( progressBarOption->progress - progressBarOption->minimum ); const int steps( qMax( progressBarOption->maximum - progressBarOption->minimum, 1 ) ); //Calculate width fraction const qreal widthFrac = qMin( qreal(1), progress/steps ); // convert the pixel width const int indicatorSize( widthFrac*( horizontal ? rect.width():rect.height() ) ); QRect indicatorRect; if( horizontal ) { indicatorRect = QRect( inverted ? ( rect.right() - indicatorSize + 1):rect.left(), rect.y(), indicatorSize, rect.height() ); indicatorRect = visualRect( option->direction, rect, indicatorRect ); } else indicatorRect = QRect( rect.x(), inverted ? rect.top() : (rect.bottom() - indicatorSize + 1), rect.width(), indicatorSize ); return indicatorRect; } //___________________________________________________________________________________________________________________ QRect Style::progressBarLabelRect( const QStyleOption* option, const QWidget* ) const { // cast option and check const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return QRect(); // get flags and check const bool textVisible( progressBarOption->textVisible ); const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); if( !textVisible || busy ) return QRect(); // get direction and check const auto progressBarOption2( qstyleoption_cast( option ) ); const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); if( !horizontal ) return QRect(); int textWidth = qMax( option->fontMetrics.size( _mnemonics->textFlags(), progressBarOption->text ).width(), option->fontMetrics.size( _mnemonics->textFlags(), QStringLiteral( "100%" ) ).width() ); auto rect( insideMargin( option->rect, Metrics::Frame_FrameWidth, 0 ) ); rect.setLeft( rect.right() - textWidth + 1 ); rect = visualRect( option, rect ); return rect; } //___________________________________________________________________________________________________________________ QRect Style::headerArrowRect( const QStyleOption* option, const QWidget* ) const { // cast option and check const auto headerOption( qstyleoption_cast( option ) ); if( !headerOption ) return option->rect; // check if arrow is necessary if( headerOption->sortIndicator == QStyleOptionHeader::None ) return QRect(); auto arrowRect( insideMargin( option->rect, Metrics::Header_MarginWidth ) ); arrowRect.setLeft( arrowRect.right() - Metrics::Header_ArrowSize + 1 ); return visualRect( option, arrowRect ); } //___________________________________________________________________________________________________________________ QRect Style::headerLabelRect( const QStyleOption* option, const QWidget* ) const { // cast option and check const auto headerOption( qstyleoption_cast( option ) ); if( !headerOption ) return option->rect; // check if arrow is necessary auto labelRect( insideMargin( option->rect, Metrics::Header_MarginWidth, 0 ) ); if( headerOption->sortIndicator == QStyleOptionHeader::None ) return labelRect; labelRect.adjust( 0, 0, -Metrics::Header_ArrowSize-Metrics::Header_ItemSpacing, 0 ); return visualRect( option, labelRect ); } //____________________________________________________________________ QRect Style::tabBarTabLeftButtonRect( const QStyleOption* option, const QWidget* ) const { // cast option and check const auto tabOptionV3( qstyleoption_cast( option ) ); if( !tabOptionV3 || tabOptionV3->leftButtonSize.isEmpty() ) return QRect(); const auto rect( option->rect ); const QSize size( tabOptionV3->leftButtonSize ); QRect buttonRect( QPoint(0,0), size ); // vertical positioning switch( tabOptionV3->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: buttonRect.moveLeft( rect.left() + Metrics::TabBar_TabMarginWidth ); buttonRect.moveTop( ( rect.height() - buttonRect.height() )/2 ); buttonRect = visualRect( option, buttonRect ); break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: buttonRect.moveBottom( rect.bottom() - Metrics::TabBar_TabMarginWidth ); buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: buttonRect.moveTop( rect.top() + Metrics::TabBar_TabMarginWidth ); buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); break; default: break; } return buttonRect; } //____________________________________________________________________ QRect Style::tabBarTabRightButtonRect( const QStyleOption* option, const QWidget* ) const { // cast option and check const auto tabOptionV3( qstyleoption_cast( option ) ); if( !tabOptionV3 || tabOptionV3->rightButtonSize.isEmpty() ) return QRect(); const auto rect( option->rect ); const auto size( tabOptionV3->rightButtonSize ); QRect buttonRect( QPoint(0,0), size ); // vertical positioning switch( tabOptionV3->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: buttonRect.moveRight( rect.right() - Metrics::TabBar_TabMarginWidth ); buttonRect.moveTop( ( rect.height() - buttonRect.height() )/2 ); buttonRect = visualRect( option, buttonRect ); break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: buttonRect.moveTop( rect.top() + Metrics::TabBar_TabMarginWidth ); buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: buttonRect.moveBottom( rect.bottom() - Metrics::TabBar_TabMarginWidth ); buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); break; default: break; } return buttonRect; } //____________________________________________________________________ QRect Style::tabWidgetTabBarRect( const QStyleOption* option, const QWidget* widget ) const { // cast option and check const auto tabOption = qstyleoption_cast( option ); if( !tabOption ) return ParentStyleClass::subElementRect( SE_TabWidgetTabBar, option, widget ); // do nothing if tabbar is hidden const QSize tabBarSize( tabOption->tabBarSize ); auto rect( option->rect ); QRect tabBarRect( QPoint(0, 0), tabBarSize ); Qt::Alignment tabBarAlignment( styleHint( SH_TabBar_Alignment, option, widget ) ); // horizontal positioning const bool verticalTabs( isVerticalTab( tabOption->shape ) ); if( verticalTabs ) { tabBarRect.setHeight( qMin( tabBarRect.height(), rect.height() - 2 ) ); if( tabBarAlignment == Qt::AlignCenter ) tabBarRect.moveTop( rect.top() + ( rect.height() - tabBarRect.height() )/2 ); else tabBarRect.moveTop( rect.top()+1 ); } else { // account for corner rects // need to re-run visualRect to remove right-to-left handling, since it is re-added on tabBarRect at the end const auto leftButtonRect( visualRect( option, subElementRect( SE_TabWidgetLeftCorner, option, widget ) ) ); const auto rightButtonRect( visualRect( option, subElementRect( SE_TabWidgetRightCorner, option, widget ) ) ); rect.setLeft( leftButtonRect.width() ); rect.setRight( rightButtonRect.left() - 1 ); tabBarRect.setWidth( qMin( tabBarRect.width(), rect.width() - 2 ) ); if( tabBarAlignment == Qt::AlignCenter ) tabBarRect.moveLeft( rect.left() + (rect.width() - tabBarRect.width())/2 ); else tabBarRect.moveLeft( rect.left() + 1 ); tabBarRect = visualRect( option, tabBarRect ); } // vertical positioning switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: tabBarRect.moveTop( rect.top()+1 ); break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: tabBarRect.moveBottom( rect.bottom()-1 ); break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: tabBarRect.moveLeft( rect.left()+1 ); break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: tabBarRect.moveRight( rect.right()-1 ); break; default: break; } return tabBarRect; } //____________________________________________________________________ QRect Style::tabWidgetTabContentsRect( const QStyleOption* option, const QWidget* widget ) const { // cast option and check const auto tabOption = qstyleoption_cast( option ); if( !tabOption ) return option->rect; // do nothing if tabbar is hidden if( tabOption->tabBarSize.isEmpty() ) return option->rect; const auto rect = tabWidgetTabPaneRect( option, widget ); const bool documentMode( tabOption->lineWidth == 0 ); if( documentMode ) { // add margin only to the relevant side switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: return rect.adjusted( 0, Metrics::TabWidget_MarginWidth, 0, 0 ); case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: return rect.adjusted( 0, 0, 0, -Metrics::TabWidget_MarginWidth ); case QTabBar::RoundedWest: case QTabBar::TriangularWest: return rect.adjusted( Metrics::TabWidget_MarginWidth, 0, 0, 0 ); case QTabBar::RoundedEast: case QTabBar::TriangularEast: return rect.adjusted( 0, 0, -Metrics::TabWidget_MarginWidth, 0 ); default: return rect; } } else return insideMargin( rect, Metrics::TabWidget_MarginWidth ); } //____________________________________________________________________ QRect Style::tabWidgetTabPaneRect( const QStyleOption* option, const QWidget* ) const { const auto tabOption = qstyleoption_cast( option ); if( !tabOption || tabOption->tabBarSize.isEmpty() ) return option->rect; const int overlap = Metrics::TabBar_BaseOverlap - 1; const QSize tabBarSize( tabOption->tabBarSize - QSize( overlap, overlap ) ); auto rect( option->rect ); switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: rect.adjust( 0, tabBarSize.height(), 0, 0 ); break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: rect.adjust( 0, 0, 0, -tabBarSize.height() ); break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: rect.adjust( tabBarSize.width(), 0, 0, 0 ); break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: rect.adjust( 0, 0, -tabBarSize.width(), 0 ); break; default: return QRect(); } return rect; } //____________________________________________________________________ QRect Style::tabWidgetCornerRect( SubElement element, const QStyleOption* option, const QWidget* ) const { // cast option and check const auto tabOption = qstyleoption_cast( option ); if( !tabOption ) return option->rect; // do nothing if tabbar is hidden const QSize tabBarSize( tabOption->tabBarSize ); if( tabBarSize.isEmpty() ) return QRect(); // do nothing for vertical tabs const bool verticalTabs( isVerticalTab( tabOption->shape ) ); if( verticalTabs ) return QRect(); const auto rect( option->rect ); QRect cornerRect; switch( element ) { case SE_TabWidgetLeftCorner: cornerRect = QRect( QPoint(0,0), tabOption->leftCornerWidgetSize ); cornerRect.moveLeft( rect.left() ); break; case SE_TabWidgetRightCorner: cornerRect = QRect( QPoint(0,0), tabOption->rightCornerWidgetSize ); cornerRect.moveRight( rect.right() ); break; default: break; } // expend height to tabBarSize, if needed, to make sure base is properly rendered cornerRect.setHeight( qMax( cornerRect.height(), tabBarSize.height() + 1 ) ); switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: cornerRect.moveTop( rect.top() ); break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: cornerRect.moveBottom( rect.bottom() ); break; default: break; } // return cornerRect; cornerRect = visualRect( option, cornerRect ); return cornerRect; } //____________________________________________________________________ QRect Style::toolBoxTabContentsRect( const QStyleOption* option, const QWidget* widget ) const { // cast option and check const auto toolBoxOption( qstyleoption_cast( option ) ); if( !toolBoxOption ) return option->rect; // copy rect const auto& rect( option->rect ); int contentsWidth(0); if( !toolBoxOption->icon.isNull() ) { const int iconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); contentsWidth += iconSize; if( !toolBoxOption->text.isEmpty() ) contentsWidth += Metrics::ToolBox_TabItemSpacing; } if( !toolBoxOption->text.isEmpty() ) { const int textWidth = toolBoxOption->fontMetrics.size( _mnemonics->textFlags(), toolBoxOption->text ).width(); contentsWidth += textWidth; } contentsWidth += 2*Metrics::ToolBox_TabMarginWidth; contentsWidth = qMin( contentsWidth, rect.width() ); contentsWidth = qMax( contentsWidth, int(Metrics::ToolBox_TabMinWidth) ); return centerRect( rect, contentsWidth, rect.height() ); } //____________________________________________________________________ QRect Style::genericLayoutItemRect( const QStyleOption* option, const QWidget* ) const { return insideMargin( option->rect, -Metrics::Frame_FrameWidth ); } //______________________________________________________________ QRect Style::groupBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { QRect rect = option->rect; switch( subControl ) { case SC_GroupBoxFrame: return rect; case SC_GroupBoxContents: { // cast option and check const auto groupBoxOption = qstyleoption_cast( option ); if( !groupBoxOption ) break; // take out frame width rect = insideMargin( rect, Metrics::Frame_FrameWidth ); // get state const bool checkable( groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox ); const bool emptyText( groupBoxOption->text.isEmpty() ); // calculate title height int titleHeight( 0 ); if( !emptyText ) titleHeight = groupBoxOption->fontMetrics.height(); if( checkable ) titleHeight = qMax( titleHeight, int(Metrics::CheckBox_Size) ); // add margin if( titleHeight > 0 ) titleHeight += 2*Metrics::GroupBox_TitleMarginWidth; rect.adjust( 0, titleHeight, 0, 0 ); return rect; } case SC_GroupBoxCheckBox: case SC_GroupBoxLabel: { // cast option and check const auto groupBoxOption = qstyleoption_cast( option ); if( !groupBoxOption ) break; // take out frame width rect = insideMargin( rect, Metrics::Frame_FrameWidth ); const bool emptyText( groupBoxOption->text.isEmpty() ); const bool checkable( groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox ); // calculate title height int titleHeight( 0 ); int titleWidth( 0 ); if( !emptyText ) { const QFontMetrics fontMetrics = option->fontMetrics; titleHeight = qMax( titleHeight, fontMetrics.height() ); titleWidth += fontMetrics.size( _mnemonics->textFlags(), groupBoxOption->text ).width(); } if( checkable ) { titleHeight = qMax( titleHeight, int(Metrics::CheckBox_Size) ); titleWidth += Metrics::CheckBox_Size; if( !emptyText ) titleWidth += Metrics::CheckBox_ItemSpacing; } // adjust height auto titleRect( rect ); titleRect.setHeight( titleHeight ); titleRect.translate( 0, Metrics::GroupBox_TitleMarginWidth ); // center titleRect = centerRect( titleRect, titleWidth, titleHeight ); if( subControl == SC_GroupBoxCheckBox ) { // vertical centering titleRect = centerRect( titleRect, titleWidth, Metrics::CheckBox_Size ); // horizontal positioning const QRect subRect( titleRect.topLeft(), QSize( Metrics::CheckBox_Size, titleRect.height() ) ); return visualRect( option->direction, titleRect, subRect ); } else { // vertical centering QFontMetrics fontMetrics = option->fontMetrics; titleRect = centerRect( titleRect, titleWidth, fontMetrics.height() ); // horizontal positioning auto subRect( titleRect ); if( checkable ) subRect.adjust( Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0 ); return visualRect( option->direction, titleRect, subRect ); } } default: break; } return ParentStyleClass::subControlRect( CC_GroupBox, option, subControl, widget ); } //___________________________________________________________________________________________________________________ QRect Style::toolButtonSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { // cast option and check const auto toolButtonOption = qstyleoption_cast( option ); if( !toolButtonOption ) return ParentStyleClass::subControlRect( CC_ToolButton, option, subControl, widget ); const bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); const bool hasInlineIndicator( toolButtonOption->features&QStyleOptionToolButton::HasMenu && toolButtonOption->features&QStyleOptionToolButton::PopupDelay && !hasPopupMenu ); // store rect const auto& rect( option->rect ); const int menuButtonWidth( Metrics::MenuButton_IndicatorWidth ); switch( subControl ) { case SC_ToolButtonMenu: { // check fratures if( !(hasPopupMenu || hasInlineIndicator ) ) return QRect(); // check features auto menuRect( rect ); menuRect.setLeft( rect.right() - menuButtonWidth + 1 ); if( hasInlineIndicator ) { menuRect.setTop( menuRect.bottom() - menuButtonWidth + 1 ); } return visualRect( option, menuRect ); } case SC_ToolButton: { if( hasPopupMenu ) { auto contentsRect( rect ); contentsRect.setRight( rect.right() - menuButtonWidth ); return visualRect( option, contentsRect ); } else return rect; } default: return QRect(); } } //___________________________________________________________________________________________________________________ QRect Style::comboBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { // cast option and check const auto comboBoxOption( qstyleoption_cast( option ) ); if( !comboBoxOption ) return ParentStyleClass::subControlRect( CC_ComboBox, option, subControl, widget ); const bool editable( comboBoxOption->editable ); const bool flat( editable && !comboBoxOption->frame ); // copy rect auto rect( option->rect ); switch( subControl ) { case SC_ComboBoxFrame: return flat ? rect : QRect(); case SC_ComboBoxListBoxPopup: return rect; case SC_ComboBoxArrow: { // take out frame width if( !flat ) rect = insideMargin( rect, Metrics::Frame_FrameWidth ); QRect arrowRect( rect.right() - Metrics::MenuButton_IndicatorWidth + 1, rect.top(), Metrics::MenuButton_IndicatorWidth, rect.height() ); arrowRect = centerRect( arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); return visualRect( option, arrowRect ); } case SC_ComboBoxEditField: { QRect labelRect; const int frameWidth( pixelMetric( PM_ComboBoxFrameWidth, option, widget ) ); labelRect = QRect( rect.left(), rect.top(), rect.width() - Metrics::MenuButton_IndicatorWidth, rect.height() ); // remove margins if( !flat && rect.height() >= option->fontMetrics.height() + 2*frameWidth ) { labelRect.adjust( frameWidth, frameWidth, 0, -frameWidth ); } return visualRect( option, labelRect ); } default: break; } return ParentStyleClass::subControlRect( CC_ComboBox, option, subControl, widget ); } //___________________________________________________________________________________________________________________ QRect Style::spinBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { // cast option and check const auto spinBoxOption( qstyleoption_cast( option ) ); if( !spinBoxOption ) return ParentStyleClass::subControlRect( CC_SpinBox, option, subControl, widget ); const bool flat( !spinBoxOption->frame ); // copy rect auto rect( option->rect ); switch( subControl ) { case SC_SpinBoxFrame: return flat ? QRect():rect; case SC_SpinBoxUp: case SC_SpinBoxDown: { // take out frame width if( !flat && rect.height() >= 2*Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth ) rect = insideMargin( rect, Metrics::Frame_FrameWidth ); QRect arrowRect; arrowRect = QRect( rect.right() - Metrics::SpinBox_ArrowButtonWidth + 1, rect.top(), Metrics::SpinBox_ArrowButtonWidth, rect.height() ); const int arrowHeight( qMin( rect.height(), int(Metrics::SpinBox_ArrowButtonWidth) ) ); arrowRect = centerRect( arrowRect, Metrics::SpinBox_ArrowButtonWidth, arrowHeight ); arrowRect.setHeight( arrowHeight/2 ); if( subControl == SC_SpinBoxDown ) arrowRect.translate( 0, arrowHeight/2 ); return visualRect( option, arrowRect ); } case SC_SpinBoxEditField: { QRect labelRect; labelRect = QRect( rect.left(), rect.top(), rect.width() - Metrics::SpinBox_ArrowButtonWidth, rect.height() ); // remove right side line editor margins const int frameWidth( pixelMetric( PM_SpinBoxFrameWidth, option, widget ) ); if( !flat && labelRect.height() >= option->fontMetrics.height() + 2*frameWidth ) { labelRect.adjust( frameWidth, frameWidth, 0, -frameWidth ); } return visualRect( option, labelRect ); } default: break; } return ParentStyleClass::subControlRect( CC_SpinBox, option, subControl, widget ); } //___________________________________________________________________________________________________________________ QRect Style::scrollBarInternalSubControlRect( const QStyleOptionComplex* option, SubControl subControl ) const { const auto& rect = option->rect; const State& state( option->state ); const bool horizontal( state & State_Horizontal ); switch( subControl ) { case SC_ScrollBarSubLine: { int majorSize( scrollBarButtonHeight( _subLineButtons ) ); if( horizontal ) return visualRect( option, QRect( rect.left(), rect.top(), majorSize, rect.height() ) ); else return visualRect( option, QRect( rect.left(), rect.top(), rect.width(), majorSize ) ); } case SC_ScrollBarAddLine: { int majorSize( scrollBarButtonHeight( _addLineButtons ) ); if( horizontal ) return visualRect( option, QRect( rect.right() - majorSize + 1, rect.top(), majorSize, rect.height() ) ); else return visualRect( option, QRect( rect.left(), rect.bottom() - majorSize + 1, rect.width(), majorSize ) ); } default: return QRect(); } } //___________________________________________________________________________________________________________________ QRect Style::scrollBarSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return ParentStyleClass::subControlRect( CC_ScrollBar, option, subControl, widget ); // get relevant state const State& state( option->state ); const bool horizontal( state & State_Horizontal ); switch( subControl ) { case SC_ScrollBarSubLine: case SC_ScrollBarAddLine: return scrollBarInternalSubControlRect( option, subControl ); case SC_ScrollBarGroove: { auto topRect = visualRect( option, scrollBarInternalSubControlRect( option, SC_ScrollBarSubLine ) ); auto bottomRect = visualRect( option, scrollBarInternalSubControlRect( option, SC_ScrollBarAddLine ) ); QPoint topLeftCorner; QPoint botRightCorner; if( horizontal ) { topLeftCorner = QPoint( topRect.right() + 1, topRect.top() ); botRightCorner = QPoint( bottomRect.left() - 1, topRect.bottom() ); } else { topLeftCorner = QPoint( topRect.left(), topRect.bottom() + 1 ); botRightCorner = QPoint( topRect.right(), bottomRect.top() - 1 ); } // define rect return visualRect( option, QRect( topLeftCorner, botRightCorner ) ); } case SC_ScrollBarSlider: { // handle RTL here to unreflect things if need be auto groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); if( sliderOption->minimum == sliderOption->maximum ) return groove; // Figure out how much room there is int space( horizontal ? groove.width() : groove.height() ); // Calculate the portion of this space that the slider should occupy int sliderSize = space * qreal( sliderOption->pageStep ) / ( sliderOption->maximum - sliderOption->minimum + sliderOption->pageStep ); sliderSize = qMax( sliderSize, static_cast(Metrics::ScrollBar_MinSliderHeight ) ); sliderSize = qMin( sliderSize, space ); space -= sliderSize; if( space <= 0 ) return groove; int pos = qRound( qreal( sliderOption->sliderPosition - sliderOption->minimum )/ ( sliderOption->maximum - sliderOption->minimum )*space ); if( sliderOption->upsideDown ) pos = space - pos; if( horizontal ) return visualRect( option, QRect( groove.left() + pos, groove.top(), sliderSize, groove.height() ) ); else return visualRect( option, QRect( groove.left(), groove.top() + pos, groove.width(), sliderSize ) ); } case SC_ScrollBarSubPage: { // handle RTL here to unreflect things if need be auto slider = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ) ); auto groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); if( horizontal ) return visualRect( option, QRect( groove.left(), groove.top(), slider.left() - groove.left(), groove.height() ) ); else return visualRect( option, QRect( groove.left(), groove.top(), groove.width(), slider.top() - groove.top() ) ); } case SC_ScrollBarAddPage: { // handle RTL here to unreflect things if need be auto slider = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ) ); auto groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); if( horizontal ) return visualRect( option, QRect( slider.right() + 1, groove.top(), groove.right() - slider.right(), groove.height() ) ); else return visualRect( option, QRect( groove.left(), slider.bottom() + 1, groove.width(), groove.bottom() - slider.bottom() ) ); } default: return ParentStyleClass::subControlRect( CC_ScrollBar, option, subControl, widget );; } } //___________________________________________________________________________________________________________________ QRect Style::dialSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return ParentStyleClass::subControlRect( CC_Dial, option, subControl, widget ); // adjust rect to be square, and centered auto rect( option->rect ); const int dimension( qMin( rect.width(), rect.height() ) ); rect = centerRect( rect, dimension, dimension ); switch( subControl ) { case QStyle::SC_DialGroove: return insideMargin( rect, (Metrics::Slider_ControlThickness - Metrics::Slider_GrooveThickness)/2 ); case QStyle::SC_DialHandle: { // calculate angle at which handle needs to be drawn const qreal angle( dialAngle( sliderOption, sliderOption->sliderPosition ) ); // groove rect const QRectF grooveRect( insideMargin( rect, Metrics::Slider_ControlThickness/2 ) ); qreal radius( grooveRect.width()/2 ); // slider center QPointF center( grooveRect.center() + QPointF( radius*std::cos( angle ), -radius*std::sin( angle ) ) ); // slider rect QRect handleRect( 0, 0, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness ); handleRect.moveCenter( center.toPoint() ); return handleRect; } default: return ParentStyleClass::subControlRect( CC_Dial, option, subControl, widget );; } } //___________________________________________________________________________________________________________________ QRect Style::sliderSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ); switch( subControl ) { case SC_SliderGroove: { // direction const bool horizontal( sliderOption->orientation == Qt::Horizontal ); // get base class rect auto grooveRect( ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ) ); grooveRect = insideMargin( grooveRect, pixelMetric( PM_DefaultFrameWidth, option, widget ) ); // centering if( horizontal ) grooveRect = centerRect( grooveRect, grooveRect.width(), Metrics::Slider_GrooveThickness ); else grooveRect = centerRect( grooveRect, Metrics::Slider_GrooveThickness, grooveRect.height() ); return grooveRect; } default: return ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ); } } //______________________________________________________________ QSize Style::checkBoxSizeFromContents( const QStyleOption*, const QSize& contentsSize, const QWidget* ) const { // get contents size QSize size( contentsSize ); // add focus height size = expandSize( size, 0, Metrics::CheckBox_FocusMarginWidth ); // make sure there is enough height for indicator size.setHeight( qMax( size.height(), int(Metrics::CheckBox_Size) ) ); // Add space for the indicator and the icon size.rwidth() += Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing; // also add extra space, to leave room to the right of the label size.rwidth() += Metrics::CheckBox_ItemSpacing; return size; } //______________________________________________________________ QSize Style::lineEditSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // cast option and check const auto frameOption( qstyleoption_cast( option ) ); if( !frameOption ) return contentsSize; const bool flat( frameOption->lineWidth == 0 ); const int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); return flat ? contentsSize : expandSize( contentsSize, frameWidth ); } //______________________________________________________________ QSize Style::comboBoxSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // cast option and check const auto comboBoxOption( qstyleoption_cast( option ) ); if( !comboBoxOption ) return contentsSize; // copy size QSize size( contentsSize ); // add relevant margin const bool flat( !comboBoxOption->frame ); const int frameWidth( pixelMetric( PM_ComboBoxFrameWidth, option, widget ) ); if( !flat ) size = expandSize( size, frameWidth ); // make sure there is enough height for the button size.setHeight( qMax( size.height(), int(Metrics::MenuButton_IndicatorWidth) ) ); // add button width and spacing size.rwidth() += Metrics::MenuButton_IndicatorWidth+2; return size; } //______________________________________________________________ QSize Style::spinBoxSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // cast option and check const auto spinBoxOption( qstyleoption_cast( option ) ); if( !spinBoxOption ) return contentsSize; const bool flat( !spinBoxOption->frame ); // copy size QSize size( contentsSize ); // add editor margins const int frameWidth( pixelMetric( PM_SpinBoxFrameWidth, option, widget ) ); if( !flat ) size = expandSize( size, frameWidth ); // make sure there is enough height for the button size.setHeight( qMax( size.height(), int(Metrics::SpinBox_ArrowButtonWidth) ) ); // add button width and spacing size.rwidth() += Metrics::SpinBox_ArrowButtonWidth; return size; } //______________________________________________________________ QSize Style::sliderSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return contentsSize; // store tick position and orientation const QSlider::TickPosition& tickPosition( sliderOption->tickPosition ); const bool horizontal( sliderOption->orientation == Qt::Horizontal ); const bool disableTicks( !StyleConfigData::sliderDrawTickMarks() ); // do nothing if no ticks are requested if( tickPosition == QSlider::NoTicks ) return contentsSize; /* * Qt adds its own tick length directly inside QSlider. * Take it out and replace by ours, if needed */ const int tickLength( disableTicks ? 0 : ( Metrics::Slider_TickLength + Metrics::Slider_TickMarginWidth + (Metrics::Slider_GrooveThickness - Metrics::Slider_ControlThickness)/2 ) ); const int builtInTickLength( 5 ); QSize size( contentsSize ); if( horizontal ) { if(tickPosition & QSlider::TicksAbove) size.rheight() += tickLength - builtInTickLength; if(tickPosition & QSlider::TicksBelow) size.rheight() += tickLength - builtInTickLength; } else { if(tickPosition & QSlider::TicksAbove) size.rwidth() += tickLength - builtInTickLength; if(tickPosition & QSlider::TicksBelow) size.rwidth() += tickLength - builtInTickLength; } return size; } //______________________________________________________________ QSize Style::pushButtonSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // cast option and check const auto buttonOption( qstyleoption_cast( option ) ); if( !buttonOption ) return contentsSize; // output QSize size; // check text and icon const bool hasText( !buttonOption->text.isEmpty() ); const bool flat( buttonOption->features & QStyleOptionButton::Flat ); bool hasIcon( !buttonOption->icon.isNull() ); if( !( hasText||hasIcon ) ) { /* no text nor icon is passed. assume custom button and use contentsSize as a starting point */ size = contentsSize; } else { /* rather than trying to guess what Qt puts into its contents size calculation, we recompute the button size entirely, based on button option this ensures consistency with the rendering stage */ // update has icon to honour showIconsOnPushButtons, when possible hasIcon &= (showIconsOnPushButtons() || flat || !hasText ); // text if( hasText ) size = buttonOption->fontMetrics.size( Qt::TextShowMnemonic, buttonOption->text ); // icon if( hasIcon ) { QSize iconSize = buttonOption->iconSize; if( !iconSize.isValid() ) iconSize = QSize( pixelMetric( PM_SmallIconSize, option, widget ), pixelMetric( PM_SmallIconSize, option, widget ) ); size.setHeight( qMax( size.height(), iconSize.height() ) ); size.rwidth() += iconSize.width(); if( hasText ) size.rwidth() += Metrics::Button_ItemSpacing; } } // menu const bool hasMenu( buttonOption->features & QStyleOptionButton::HasMenu ); if( hasMenu ) { size.rwidth() += Metrics::MenuButton_IndicatorWidth; if( hasText||hasIcon ) size.rwidth() += Metrics::Button_ItemSpacing; } // expand with buttons margin size = expandSize( size, Metrics::Button_MarginWidth ); // make sure buttons have a minimum width if( hasText ) { size.setWidth( qMax( size.width(), int( Metrics::Button_MinWidth ) ) ); } // finally add frame margins return expandSize( size, Metrics::Frame_FrameWidth ); } //______________________________________________________________ QSize Style::toolButtonSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const { // cast option and check const auto toolButtonOption = qstyleoption_cast( option ); if( !toolButtonOption ) return contentsSize; // copy size QSize size = contentsSize; // get relevant state flags const State& state( option->state ); const bool autoRaise( state & State_AutoRaise ); const bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); const bool hasInlineIndicator( toolButtonOption->features&QStyleOptionToolButton::HasMenu && toolButtonOption->features&QStyleOptionToolButton::PopupDelay && !hasPopupMenu ); const int marginWidth( autoRaise ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); if( hasInlineIndicator ) size.rwidth() += Metrics::ToolButton_InlineIndicatorWidth; size = expandSize( size, marginWidth ); return size; } //______________________________________________________________ QSize Style::menuBarItemSizeFromContents( const QStyleOption*, const QSize& contentsSize, const QWidget* ) const { return expandSize( contentsSize, Metrics::MenuBarItem_MarginWidth, Metrics::MenuBarItem_MarginHeight ); } //______________________________________________________________ QSize Style::menuItemSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // cast option and check const auto menuItemOption = qstyleoption_cast( option ); if( !menuItemOption ) return contentsSize; /* * First calculate the intrinsic size of the item. * this must be kept consistent with what's in drawMenuItemControl */ QSize size( contentsSize ); switch( menuItemOption->menuItemType ) { case QStyleOptionMenuItem::Normal: case QStyleOptionMenuItem::DefaultItem: case QStyleOptionMenuItem::SubMenu: { int iconWidth = 0; if( showIconsInMenuItems() ) iconWidth = isQtQuickControl( option, widget ) ? qMax( pixelMetric(PM_SmallIconSize, option, widget ), menuItemOption->maxIconWidth ) : menuItemOption->maxIconWidth; int leftColumnWidth = 0; // add icon width if( iconWidth > 0 ) { leftColumnWidth += iconWidth + Metrics::MenuItem_ItemSpacing; } // add checkbox indicator width if( menuItemOption->menuHasCheckableItems ) { leftColumnWidth += Metrics::CheckBox_Size + Metrics::MenuItem_ItemSpacing; } // add spacing for accelerator /* * Note: * The width of the accelerator itself is not included here since * Qt will add that on separately after obtaining the * sizeFromContents() for each menu item in the menu to be shown * ( see QMenuPrivate::calcActionRects() ) */ const bool hasAccelerator( menuItemOption->text.indexOf( QLatin1Char( '\t' ) ) >= 0 ); if( hasAccelerator ) size.rwidth() += Metrics::MenuItem_AcceleratorSpace; // right column const int rightColumnWidth = Metrics::MenuButton_IndicatorWidth + Metrics::MenuItem_ItemSpacing; size.rwidth() += leftColumnWidth + rightColumnWidth; // make sure height is large enough for icon and arrow size.setHeight( qMax( size.height(), int(Metrics::MenuButton_IndicatorWidth) ) ); size.setHeight( qMax( size.height(), int(Metrics::CheckBox_Size) ) ); size.setHeight( qMax( size.height(), iconWidth ) ); return expandSize( size, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ); } case QStyleOptionMenuItem::Separator: { if( menuItemOption->text.isEmpty() && menuItemOption->icon.isNull() ) { return expandSize( QSize(0,1), Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ); } else { // build toolbutton option const QStyleOptionToolButton toolButtonOption( separatorMenuItemOption( menuItemOption, widget ) ); // make sure height is large enough for icon and text const int iconWidth( menuItemOption->maxIconWidth ); const int textHeight( menuItemOption->fontMetrics.height() ); if( !menuItemOption->icon.isNull() ) size.setHeight( qMax( size.height(), iconWidth ) ); if( !menuItemOption->text.isEmpty() ) { size.setHeight( qMax( size.height(), textHeight ) ); size.setWidth( qMax( size.width(), menuItemOption->fontMetrics.width( menuItemOption->text ) ) ); } return sizeFromContents( CT_ToolButton, &toolButtonOption, size, widget ); } } // for all other cases, return input default: return contentsSize; } } //______________________________________________________________ QSize Style::progressBarSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const { // cast option const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return contentsSize; const auto progressBarOption2( qstyleoption_cast( option ) ); const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); // make local copy QSize size( contentsSize ); if( horizontal ) { // check text visibility const bool textVisible( progressBarOption->textVisible ); size.setWidth( qMax( size.width(), int(Metrics::ProgressBar_Thickness) ) ); size.setHeight( qMax( size.height(), int(Metrics::ProgressBar_Thickness) ) ); if( textVisible ) size.setHeight( qMax( size.height(), option->fontMetrics.height() ) ); } else { size.setHeight( qMax( size.height(), int(Metrics::ProgressBar_Thickness) ) ); size.setWidth( qMax( size.width(), int(Metrics::ProgressBar_Thickness) ) ); } return size; } //______________________________________________________________ QSize Style::tabWidgetSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // cast option and check const auto tabOption = qstyleoption_cast( option ); if( !tabOption ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); // try find direct children of type QTabBar and QStackedWidget // this is needed in order to add TabWidget margins only if they are necessary around tabWidget content, not the tabbar if( !widget ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); QTabBar* tabBar = nullptr; QStackedWidget* stack = nullptr; auto children( widget->children() ); foreach( auto child, children ) { if( !tabBar ) tabBar = qobject_cast( child ); if( !stack ) stack = qobject_cast( child ); if( tabBar && stack ) break; } if( !( tabBar && stack ) ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); // tab orientation const bool verticalTabs( tabOption && isVerticalTab( tabOption->shape ) ); if( verticalTabs ) { const int tabBarHeight = tabBar->minimumSizeHint().height(); const int stackHeight = stack->minimumSizeHint().height(); if( contentsSize.height() == tabBarHeight && tabBarHeight + 2*(Metrics::Frame_FrameWidth - 1) >= stackHeight + 2*Metrics::TabWidget_MarginWidth ) return QSize( contentsSize.width() + 2*Metrics::TabWidget_MarginWidth, contentsSize.height() + 2*(Metrics::Frame_FrameWidth - 1) ); else return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); } else { const int tabBarWidth = tabBar->minimumSizeHint().width(); const int stackWidth = stack->minimumSizeHint().width(); if( contentsSize.width() == tabBarWidth && tabBarWidth + 2*(Metrics::Frame_FrameWidth - 1) >= stackWidth + 2*Metrics::TabWidget_MarginWidth) return QSize( contentsSize.width() + 2*(Metrics::Frame_FrameWidth - 1), contentsSize.height() + 2*Metrics::TabWidget_MarginWidth ); else return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); } } //______________________________________________________________ QSize Style::tabBarTabSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const { const auto tabOption( qstyleoption_cast( option ) ); const auto tabOptionV3( qstyleoption_cast( option ) ); const bool hasText( tabOption && !tabOption->text.isEmpty() ); const bool hasIcon( tabOption && !tabOption->icon.isNull() ); const bool hasLeftButton( tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty() ); const bool hasRightButton( tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty() ); // calculate width increment for horizontal tabs int widthIncrement = 0; if( hasIcon && !( hasText || hasLeftButton || hasRightButton ) ) widthIncrement -= 4; if( hasText && hasIcon ) widthIncrement += Metrics::TabBar_TabItemSpacing; if( hasLeftButton && ( hasText || hasIcon ) ) widthIncrement += Metrics::TabBar_TabItemSpacing; if( hasRightButton && ( hasText || hasIcon || hasLeftButton ) ) widthIncrement += Metrics::TabBar_TabItemSpacing; // add margins QSize size( contentsSize ); // compare to minimum size const bool verticalTabs( tabOption && isVerticalTab( tabOption ) ); if( verticalTabs ) { size.rheight() += widthIncrement; if( hasIcon && !hasText ) size = size.expandedTo( QSize( Metrics::TabBar_TabMinHeight, 0 ) ); else size = size.expandedTo( QSize( Metrics::TabBar_TabMinHeight, Metrics::TabBar_TabMinWidth ) ); } else { size.rwidth() += widthIncrement; if( hasIcon && !hasText ) size = size.expandedTo( QSize( 0, Metrics::TabBar_TabMinHeight ) ); else size = size.expandedTo( QSize( Metrics::TabBar_TabMinWidth, Metrics::TabBar_TabMinHeight ) ); } return size; } //______________________________________________________________ QSize Style::headerSectionSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const { // cast option and check const auto headerOption( qstyleoption_cast( option ) ); if( !headerOption ) return contentsSize; // get text size const bool horizontal( headerOption->orientation == Qt::Horizontal ); const bool hasText( !headerOption->text.isEmpty() ); const bool hasIcon( !headerOption->icon.isNull() ); const QSize textSize( hasText ? headerOption->fontMetrics.size( 0, headerOption->text ) : QSize() ); const QSize iconSize( hasIcon ? QSize( 22,22 ) : QSize() ); // contents width int contentsWidth( 0 ); if( hasText ) contentsWidth += textSize.width(); if( hasIcon ) { contentsWidth += iconSize.width(); if( hasText ) contentsWidth += Metrics::Header_ItemSpacing; } // contents height int contentsHeight( headerOption->fontMetrics.height() ); if( hasIcon ) contentsHeight = qMax( contentsHeight, iconSize.height() ); if( horizontal && headerOption->sortIndicator != QStyleOptionHeader::None ) { // also add space for sort indicator contentsWidth += Metrics::Header_ArrowSize + Metrics::Header_ItemSpacing; contentsHeight = qMax( contentsHeight, int(Metrics::Header_ArrowSize) ); } // update contents size, add margins and return const QSize size( contentsSize.expandedTo( QSize( contentsWidth, contentsHeight ) ) ); return expandSize( size, Metrics::Header_MarginWidth ); } //______________________________________________________________ QSize Style::itemViewItemSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const { // call base class const QSize size( ParentStyleClass::sizeFromContents( CT_ItemViewItem, option, contentsSize, widget ) ); return expandSize( size, Metrics::ItemView_ItemMarginWidth ); } //______________________________________________________________ bool Style::drawFramePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // copy palette and rect const auto& palette( option->palette ); const auto& rect( option->rect ); // detect title widgets const bool isTitleWidget( StyleConfigData::titleWidgetDrawFrame() && widget && widget->parent() && widget->parent()->inherits( "KTitleWidget" ) ); // copy state const State& state( option->state ); if( !isTitleWidget && !( state & (State_Sunken | State_Raised ) ) ) return true; #if QT_VERSION >= 0x050000 const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) || ( isQtQuickControl( option, widget ) && option->styleObject->property( "elementType" ).toString() == QStringLiteral( "edit") ) ); #else const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) ); #endif const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && isInputWidget && ( state & State_MouseOver ) ); const bool hasFocus( enabled && isInputWidget && ( state & State_HasFocus ) ); // focus takes precedence over mouse over _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); // retrieve animation mode and opacity const AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); const qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); // render if( !StyleConfigData::sidePanelDrawFrame() && widget && widget->property( PropertyNames::sidePanelView ).toBool() ) { const auto outline( _helper->sidePanelOutlineColor( palette, hasFocus, opacity, mode ) ); const bool reverseLayout( option->direction == Qt::RightToLeft ); const Side side( reverseLayout ? SideRight : SideLeft ); _helper->renderSidePanelFrame( painter, rect, outline, side ); } else { if( _frameShadowFactory->isRegistered( widget ) ) { // update frame shadow factory _frameShadowFactory->updateShadowsGeometry( widget, rect ); _frameShadowFactory->updateState( widget, hasFocus, mouseOver, opacity, mode ); } const auto background( isTitleWidget ? palette.color( widget->backgroundRole() ):QColor() ); const auto outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); _helper->renderFrame( painter, rect, background, outline ); } return true; } //______________________________________________________________ bool Style::drawFrameLineEditPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // copy palette and rect const auto& palette( option->palette ); const auto& rect( option->rect ); // make sure there is enough room to render frame if( rect.height() < 2*Metrics::LineEdit_FrameWidth + option->fontMetrics.height()) { const auto background( palette.color( QPalette::Base ) ); painter->setPen( Qt::NoPen ); painter->setBrush( background ); painter->drawRect( rect ); return true; } else { // copy state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool hasFocus( enabled && ( state & State_HasFocus ) ); // focus takes precedence over mouse over _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); // retrieve animation mode and opacity const AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); const qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); // render const auto background( palette.color( QPalette::Base ) ); const auto outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); _helper->renderFrame( painter, rect, background, outline ); } return true; } //___________________________________________________________________________________ bool Style::drawFrameFocusRectPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // no focus indicator on buttons / scrollbars, since it is rendered elsewhere if ( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) ) { return true; } // no focus indicator on ComboBox list items if (widget && widget->inherits("QComboBoxListView")) { return true; } #if QT_VERSION >= 0x050000 if ( option->styleObject && option->styleObject->property("elementType") == QLatin1String("button") ) { return true; } #endif const State& state( option->state ); // no focus indicator on selected list items if ((state & State_Selected) && qobject_cast(widget)) { return true; } const auto rect( option->rect.adjusted( 0, 0, 0, 1 ) ); const auto& palette( option->palette ); if( rect.width() < 10 ) return true; const auto outlineColor( state & State_Selected ? palette.color( QPalette::HighlightedText ):palette.color( QPalette::Highlight ) ); painter->setRenderHint( QPainter::Antialiasing, false ); painter->setPen( outlineColor ); painter->drawLine( QPoint( rect.bottomLeft() - QPoint( 0,1 ) ), QPoint( rect.bottomRight() - QPoint( 0,1 ) ) ); return true; } //___________________________________________________________________________________ bool Style::drawFrameMenuPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // only draw frame for (expanded) toolbars and QtQuick controls // do nothing for other cases, for which frame is rendered via drawPanelMenuPrimitive if( qobject_cast( widget ) ) { const auto& palette( option->palette ); const auto background( _helper->frameBackgroundColor( palette ) ); const auto outline( _helper->frameOutlineColor( palette ) ); const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); } else if( isQtQuickControl( option, widget ) ) { const auto& palette( option->palette ); const auto background( _helper->frameBackgroundColor( palette ) ); const auto outline( _helper->frameOutlineColor( palette ) ); const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); } return true; } //______________________________________________________________ bool Style::drawFrameGroupBoxPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // cast option and check const auto frameOption( qstyleoption_cast( option ) ); if( !frameOption ) return true; // no frame for flat groupboxes QStyleOptionFrameV2 frameOption2( *frameOption ); if( frameOption2.features & QStyleOptionFrameV2::Flat ) return true; // normal frame const auto& palette( option->palette ); const auto background( _helper->frameBackgroundColor( palette ) ); const auto outline( _helper->frameOutlineColor( palette ) ); /* * need to reset painter's clip region in order to paint behind textbox label * (was taken out in QCommonStyle) */ painter->setClipRegion( option->rect ); _helper->renderFrame( painter, option->rect, background, outline ); return true; } //___________________________________________________________________________________ bool Style::drawFrameTabWidgetPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto tabOption( qstyleoption_cast( option ) ); if( !tabOption ) return true; // do nothing if tabbar is hidden const bool isQtQuickControl( this->isQtQuickControl( option, widget ) ); if( tabOption->tabBarSize.isEmpty() && !isQtQuickControl ) return true; // adjust rect to handle overlaps auto rect( option->rect ); const auto tabBarRect( tabOption->tabBarRect ); const QSize tabBarSize( tabOption->tabBarSize ); Corners corners = AllCorners; // adjust corners to deal with oversized tabbars switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: if( isQtQuickControl ) rect.adjust( -1, -1, 1, 0 ); if( tabBarSize.width() >= rect.width() - 2*Metrics::Frame_FrameRadius ) corners &= ~CornersTop; if( tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopLeft; if( tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius ) corners &= ~CornerTopRight; break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: if( isQtQuickControl ) rect.adjust( -1, 0, 1, 1 ); if( tabBarSize.width() >= rect.width()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersBottom; if( tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius ) corners &= ~CornerBottomLeft; if( tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomRight; break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: if( isQtQuickControl ) rect.adjust( -1, 0, 0, 0 ); if( tabBarSize.height() >= rect.height()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersLeft; if( tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopLeft; if( tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomLeft; break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: if( isQtQuickControl ) rect.adjust( 0, 0, 1, 0 ); if( tabBarSize.height() >= rect.height()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersRight; if( tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopRight; if( tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomRight; break; default: break; } // define colors const auto& palette( option->palette ); const auto background( _helper->frameBackgroundColor( palette ) ); const auto outline( _helper->frameOutlineColor( palette ) ); _helper->renderTabWidgetFrame( painter, rect, background, outline, corners ); return true; } //___________________________________________________________________________________ bool Style::drawFrameTabBarBasePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // tabbar frame used either for 'separate' tabbar, or in 'document mode' // cast option and check const auto tabOption( qstyleoption_cast( option ) ); if( !tabOption ) return true; // get rect, orientation, palette const auto rect( option->rect ); const auto outline( _helper->frameOutlineColor( option->palette ) ); // setup painter painter->setBrush( Qt::NoBrush ); painter->setRenderHint( QPainter::Antialiasing, false ); painter->setPen( QPen( outline, 1 ) ); // render switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: painter->drawLine( rect.bottomLeft() - QPoint( 1, 0 ), rect.bottomRight() + QPoint( 1, 0 ) ); break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: painter->drawLine( rect.topLeft() - QPoint( 1, 0 ), rect.topRight() + QPoint( 1, 0 ) ); break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: painter->drawLine( rect.topRight() - QPoint( 0, 1 ), rect.bottomRight() + QPoint( 1, 0 ) ); break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: painter->drawLine( rect.topLeft() - QPoint( 0, 1 ), rect.bottomLeft() + QPoint( 1, 0 ) ); break; default: break; } return true; } //___________________________________________________________________________________ bool Style::drawFrameWindowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); const State state( option->state ); const bool selected( state & State_Selected ); // render frame outline const auto outline( _helper->frameOutlineColor( palette, false, selected ) ); _helper->renderMenuFrame( painter, rect, QColor(), outline ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorArrowPrimitive( ArrowOrientation orientation, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // store rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // store state const State& state( option->state ); const bool enabled( state & State_Enabled ); bool mouseOver( enabled && ( state & State_MouseOver ) ); bool hasFocus( enabled && ( state & State_HasFocus ) ); // detect special buttons const bool inTabBar( widget && qobject_cast( widget->parentWidget() ) ); const bool inToolButton( qstyleoption_cast( option ) ); // color QColor color; if( inTabBar ) { // for tabbar arrows one uses animations to get the arrow color /* * get animation state * there is no need to update the engine since this was already done when rendering the frame */ const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); color = _helper->arrowColor( palette, mouseOver, hasFocus, opacity, mode ); } else if( mouseOver && !inToolButton ) { color = _helper->hoverColor( palette ); } else if( inToolButton ) { const bool flat( state & State_AutoRaise ); // cast option const QStyleOptionToolButton* toolButtonOption( static_cast( option ) ); const bool hasPopupMenu( toolButtonOption->subControls & SC_ToolButtonMenu ); if( flat && hasPopupMenu ) { // for menu arrows in flat toolbutton one uses animations to get the arrow color // handle arrow over animation const bool arrowHover( mouseOver && ( toolButtonOption->activeSubControls & SC_ToolButtonMenu ) ); _animations->toolButtonEngine().updateState( widget, AnimationHover, arrowHover ); const bool animated( _animations->toolButtonEngine().isAnimated( widget, AnimationHover ) ); const qreal opacity( _animations->toolButtonEngine().opacity( widget, AnimationHover ) ); color = _helper->arrowColor( palette, arrowHover, false, opacity, animated ? AnimationHover:AnimationNone ); } else { const bool sunken( state & (State_On | State_Sunken) ); if( flat ) { if( sunken && hasFocus && !mouseOver ) color = palette.color( QPalette::HighlightedText ); else color = _helper->arrowColor( palette, QPalette::WindowText ); } else if( hasFocus && !mouseOver ) { color = palette.color( QPalette::HighlightedText ); } else { color = _helper->arrowColor( palette, QPalette::ButtonText ); } } } else color = _helper->arrowColor( palette, QPalette::WindowText ); // render _helper->renderArrow( painter, rect, color, orientation ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorHeaderArrowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { const auto headerOption( qstyleoption_cast( option ) ); const State& state( option->state ); // arrow orientation ArrowOrientation orientation( ArrowNone ); if( state & State_UpArrow || ( headerOption && headerOption->sortIndicator==QStyleOptionHeader::SortUp ) ) orientation = ArrowUp; else if( state & State_DownArrow || ( headerOption && headerOption->sortIndicator==QStyleOptionHeader::SortDown ) ) orientation = ArrowDown; if( orientation == ArrowNone ) return true; // invert arrows if requested by (hidden) options if( StyleConfigData::viewInvertSortIndicator() ) orientation = (orientation == ArrowUp) ? ArrowDown:ArrowUp; // state, rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // define color and polygon for drawing arrow const auto color = _helper->arrowColor( palette, QPalette::ButtonText ); // render _helper->renderArrow( painter, rect, color, orientation ); return true; } //______________________________________________________________ bool Style::drawPanelButtonCommandPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto buttonOption( qstyleoption_cast< const QStyleOptionButton* >( option ) ); if( !buttonOption ) return true; // rect and palette const auto& rect( option->rect ); // button state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool hasFocus( ( enabled && ( state & State_HasFocus ) ) && !( widget && widget->focusProxy())); const bool sunken( state & ( State_On|State_Sunken ) ); const bool flat( buttonOption->features & QStyleOptionButton::Flat ); // update animation state // mouse over takes precedence over focus _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); if( flat ) { // define colors and render const auto& palette( option->palette ); const auto color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); _helper->renderToolButtonFrame( painter, rect, color, sunken ); } else { // update button color from palette in case button is default QPalette palette( option->palette ); if( enabled && buttonOption->features & QStyleOptionButton::DefaultButton ) { const auto button( palette.color( QPalette::Button ) ); const auto base( palette.color( QPalette::Base ) ); palette.setColor( QPalette::Button, KColorUtils::mix( button, base, 0.7 ) ); } const auto shadow( _helper->shadowColor( palette ) ); const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); // render _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken ); } return true; } //______________________________________________________________ bool Style::drawPanelButtonToolPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // copy palette and rect const auto& palette( option->palette ); auto rect( option->rect ); // store relevant flags const State& state( option->state ); const bool autoRaise( state & State_AutoRaise ); const bool enabled( state & State_Enabled ); const bool sunken( state & (State_On | State_Sunken) ); const bool mouseOver( enabled && (option->state & State_MouseOver) ); const bool hasFocus( enabled && (option->state & (State_HasFocus | State_Sunken)) ); /* * get animation state * no need to update, this was already done in drawToolButtonComplexControl */ const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); if( !autoRaise ) { // need to check widget for popup mode, because option is not set properly const auto toolButton( qobject_cast( widget ) ); const bool hasPopupMenu( toolButton && toolButton->popupMode() == QToolButton::MenuButtonPopup ); // render as push button const auto shadow( _helper->shadowColor( palette ) ); const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); // adjust frame in case of menu if( hasPopupMenu ) { painter->setClipRect( rect ); rect.adjust( 0, 0, Metrics::Frame_FrameRadius + 2, 0 ); rect = visualRect( option, rect ); } // render _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken ); } else { const auto color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); _helper->renderToolButtonFrame( painter, rect, color, sunken ); } return true; } //______________________________________________________________ bool Style::drawTabBarPanelButtonToolPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // copy palette and rect auto rect( option->rect ); // static_cast is safe here since check was already performed in calling function const QTabBar* tabBar( static_cast( widget->parentWidget() ) ); // overlap. // subtract 1, because of the empty pixel left the tabwidget frame const int overlap( Metrics::TabBar_BaseOverlap - 1 ); // adjust rect based on tabbar shape switch( tabBar->shape() ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: rect.adjust( 0, 0, 0, -overlap ); break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: rect.adjust( 0, overlap, 0, 0 ); break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: rect.adjust( 0, 0, -overlap, 0 ); break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: rect.adjust( overlap, 0, 0, 0 ); break; default: break; } // get the relevant palette const QWidget* parent( tabBar->parentWidget() ); if( qobject_cast( parent ) ) parent = parent->parentWidget(); const auto& palette( parent ? parent->palette() : QApplication::palette() ); const auto color = hasAlteredBackground(parent) ? _helper->frameBackgroundColor( palette ):palette.color( QPalette::Window ); // render flat background painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRect( rect ); return true; } //___________________________________________________________________________________ bool Style::drawPanelScrollAreaCornerPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // make sure background role matches viewport const QAbstractScrollArea* scrollArea; if( ( scrollArea = qobject_cast( widget ) ) && scrollArea->viewport() ) { // need to adjust clipRect in order not to render outside of frame - const int frameWidth( pixelMetric( PM_DefaultFrameWidth, 0, scrollArea ) ); + const int frameWidth( pixelMetric( PM_DefaultFrameWidth, nullptr, scrollArea ) ); painter->setClipRect( insideMargin( scrollArea->rect(), frameWidth ) ); painter->setBrush( scrollArea->viewport()->palette().color( scrollArea->viewport()->backgroundRole() ) ); painter->setPen( Qt::NoPen ); painter->drawRect( option->rect ); return true; } else { return false; } } //___________________________________________________________________________________ bool Style::drawPanelMenuPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { /* * do nothing if menu is embedded in another widget * this corresponds to having a transparent background */ if( widget && !widget->isWindow() ) return true; const auto& palette( option->palette ); const auto outline( _helper->frameOutlineColor( palette ) ); const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); auto background( _helper->frameBackgroundColor( palette ) ); #if !BREEZE_USE_KDE4 if ( hasAlpha ) { background.setAlphaF(StyleConfigData::menuOpacity() / 100.0); } #endif _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); return true; } //___________________________________________________________________________________ bool Style::drawPanelTipLabelPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // force registration of widget if( widget && widget->window() ) { _shadowHelper->registerWidget( widget->window(), true ); } const auto& palette( option->palette ); const auto background( palette.color( QPalette::ToolTipBase ) ); const auto outline( KColorUtils::mix( palette.color( QPalette::ToolTipBase ), palette.color( QPalette::ToolTipText ), 0.25 ) ); const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); return true; } //___________________________________________________________________________________ bool Style::drawPanelItemViewItemPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto viewItemOption = qstyleoption_cast( option ); if( !viewItemOption ) return false; // try cast widget const auto abstractItemView = qobject_cast( widget ); // store palette and rect const auto& palette( option->palette ); auto rect( option->rect ); // store flags const State& state( option->state ); const bool mouseOver( ( state & State_MouseOver ) && ( !abstractItemView || abstractItemView->selectionMode() != QAbstractItemView::NoSelection ) ); const bool selected( state & State_Selected ); const bool enabled( state & State_Enabled ); const bool active( state & State_Active ); const bool hasCustomBackground = viewItemOption->backgroundBrush.style() != Qt::NoBrush && !( state & State_Selected ); const bool hasSolidBackground = !hasCustomBackground || viewItemOption->backgroundBrush.style() == Qt::SolidPattern; const bool hasAlternateBackground( viewItemOption->features & QStyleOptionViewItemV2::Alternate ); // do nothing if no background is to be rendered if( !( mouseOver || selected || hasCustomBackground || hasAlternateBackground ) ) { return true; } // define color group QPalette::ColorGroup colorGroup; if( enabled ) colorGroup = active ? QPalette::Active : QPalette::Inactive; else colorGroup = QPalette::Disabled; // render alternate background if( viewItemOption && ( viewItemOption->features & QStyleOptionViewItemV2::Alternate ) ) { painter->setPen( Qt::NoPen ); painter->setBrush( palette.brush( colorGroup, QPalette::AlternateBase ) ); painter->drawRect( rect ); } // stop here if no highlight is needed if( !( mouseOver || selected ||hasCustomBackground ) ) { return true; } // render custom background if( hasCustomBackground && !hasSolidBackground ) { painter->setBrushOrigin( viewItemOption->rect.topLeft() ); painter->setBrush( viewItemOption->backgroundBrush ); painter->setPen( Qt::NoPen ); painter->drawRect( viewItemOption->rect ); return true; } // render selection // define color QColor color; if( hasCustomBackground && hasSolidBackground ) color = viewItemOption->backgroundBrush.color(); else color = palette.color( colorGroup, QPalette::Highlight ); // change color to implement mouse over if( mouseOver && !hasCustomBackground ) { if( !selected ) color.setAlphaF( 0.2 ); else color = color.lighter( 110 ); } // render _helper->renderSelection( painter, rect, color ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorCheckBoxPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // store flags const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool sunken( enabled && ( state & State_Sunken ) ); const bool active( ( state & (State_On|State_NoChange) ) ); // checkbox state CheckBoxState checkBoxState( CheckOff ); if( state & State_NoChange ) checkBoxState = CheckPartial; else if( state & State_On ) checkBoxState = CheckOn; // detect checkboxes in lists const bool isSelectedItem( this->isSelectedItem( widget, rect.center() ) ); // animation state _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationPressed, checkBoxState != CheckOff ); if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) checkBoxState = CheckAnimated; const qreal animation( _animations->widgetStateEngine().opacity( widget, AnimationPressed ) ); QColor color; if( isSelectedItem ) { color = _helper->checkBoxIndicatorColor( palette, false, enabled && active ); _helper->renderCheckBoxBackground( painter, rect, palette.color( QPalette::Base ), sunken ); } else { const AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); color = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && active, opacity, mode ); } // render const auto shadow( _helper->shadowColor( palette ) ); _helper->renderCheckBox( painter, rect, color, shadow, sunken, checkBoxState, animation ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorRadioButtonPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // store flags const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool sunken( state & State_Sunken ); const bool checked( state & State_On ); // radio button state RadioButtonState radioButtonState( state & State_On ? RadioOn:RadioOff ); // detect radiobuttons in lists const bool isSelectedItem( this->isSelectedItem( widget, rect.center() ) ); // animation state _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationPressed, radioButtonState != RadioOff ); if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) radioButtonState = RadioAnimated; const qreal animation( _animations->widgetStateEngine().opacity( widget, AnimationPressed ) ); // colors const auto shadow( _helper->shadowColor( palette ) ); QColor color; if( isSelectedItem ) { color = _helper->checkBoxIndicatorColor( palette, false, enabled && checked ); _helper->renderRadioButtonBackground( painter, rect, palette.color( QPalette::Base ), sunken ); } else { const AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); color = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && checked, opacity, mode ); } // render _helper->renderRadioButton( painter, rect, color, shadow, sunken, radioButtonState, animation ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorButtonDropDownPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto toolButtonOption( qstyleoption_cast( option ) ); if( !toolButtonOption ) return true; // store state const State& state( option->state ); const bool autoRaise( state & State_AutoRaise ); // do nothing for autoraise buttons if( autoRaise || !(toolButtonOption->subControls & SC_ToolButtonMenu) ) return true; // store palette and rect const auto& palette( option->palette ); const auto& rect( option->rect ); // store state const bool enabled( state & State_Enabled ); const bool hasFocus( enabled && ( state & ( State_HasFocus | State_Sunken ) ) ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool sunken( enabled && ( state & State_Sunken ) ); // update animation state // mouse over takes precedence over focus _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); // render as push button const auto shadow( _helper->shadowColor( palette ) ); const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, false, opacity, mode ) ); auto frameRect( rect ); painter->setClipRect( rect ); frameRect.adjust( -Metrics::Frame_FrameRadius - 1, 0, 0, 0 ); frameRect = visualRect( option, frameRect ); // render _helper->renderButtonFrame( painter, frameRect, background, outline, shadow, hasFocus, sunken ); // also render separator auto separatorRect( rect.adjusted( 0, 2, -2, -2 ) ); separatorRect.setWidth( 1 ); separatorRect = visualRect( option, separatorRect ); _helper->renderSeparator( painter, separatorRect, outline, true ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorTabClosePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // get icon and check QIcon icon( standardIcon( SP_TitleBarCloseButton, option, widget ) ); if( icon.isNull() ) return false; // store state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool active( state & State_Raised ); const bool sunken( state & State_Sunken ); // decide icon mode and state QIcon::Mode iconMode; QIcon::State iconState; if( !enabled ) { iconMode = QIcon::Disabled; iconState = QIcon::Off; } else { if( active ) iconMode = QIcon::Active; else iconMode = QIcon::Normal; iconState = sunken ? QIcon::On : QIcon::Off; } // icon size const int iconWidth( pixelMetric(QStyle::PM_SmallIconSize, option, widget ) ); const QSize iconSize( iconWidth, iconWidth ); // get pixmap const QPixmap pixmap( icon.pixmap( iconSize, iconMode, iconState ) ); // render drawItemPixmap( painter, option->rect, Qt::AlignCenter, pixmap ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorTabTearPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // cast option and check const auto tabOption( qstyleoption_cast( option ) ); if( !tabOption ) return true; // store palette and rect const auto& palette( option->palette ); auto rect( option->rect ); const bool reverseLayout( option->direction == Qt::RightToLeft ); const auto color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.2 ) ); painter->setRenderHint( QPainter::Antialiasing, false ); painter->setPen( color ); painter->setBrush( Qt::NoBrush ); switch( tabOption->shape ) { case QTabBar::TriangularNorth: case QTabBar::RoundedNorth: rect.adjust( 0, 1, 0, 0 ); if( reverseLayout ) painter->drawLine( rect.topRight(), rect.bottomRight() ); else painter->drawLine( rect.topLeft(), rect.bottomLeft() ); break; case QTabBar::TriangularSouth: case QTabBar::RoundedSouth: rect.adjust( 0, 0, 0, -1 ); if( reverseLayout ) painter->drawLine( rect.topRight(), rect.bottomRight() ); else painter->drawLine( rect.topLeft(), rect.bottomLeft() ); break; case QTabBar::TriangularWest: case QTabBar::RoundedWest: rect.adjust( 1, 0, 0, 0 ); painter->drawLine( rect.topLeft(), rect.topRight() ); break; case QTabBar::TriangularEast: case QTabBar::RoundedEast: rect.adjust( 0, 0, -1, 0 ); painter->drawLine( rect.topLeft(), rect.topRight() ); break; default: break; } return true; } //___________________________________________________________________________________ bool Style::drawIndicatorToolBarHandlePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // do nothing if disabled from options if( !StyleConfigData::toolBarDrawItemSeparator() ) return true; // store rect and palette auto rect( option->rect ); const auto& palette( option->palette ); // store state const State& state( option->state ); const bool separatorIsVertical( state & State_Horizontal ); // define color and render const auto color( _helper->separatorColor( palette ) ); if( separatorIsVertical ) { rect.setWidth( Metrics::ToolBar_HandleWidth ); rect = centerRect( option->rect, rect.size() ); rect.setWidth( 3 ); _helper->renderSeparator( painter, rect, color, separatorIsVertical ); rect.translate( 2, 0 ); _helper->renderSeparator( painter, rect, color, separatorIsVertical ); } else { rect.setHeight( Metrics::ToolBar_HandleWidth ); rect = centerRect( option->rect, rect.size() ); rect.setHeight( 3 ); _helper->renderSeparator( painter, rect, color, separatorIsVertical ); rect.translate( 0, 2 ); _helper->renderSeparator( painter, rect, color, separatorIsVertical ); } return true; } //___________________________________________________________________________________ bool Style::drawIndicatorToolBarSeparatorPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { /* * do nothing if disabled from options * also need to check if widget is a combobox, because of Qt hack using 'toolbar' separator primitive * for rendering separators in comboboxes */ if( !( StyleConfigData::toolBarDrawItemSeparator() || qobject_cast( widget ) ) ) { return true; } // store rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // store state const State& state( option->state ); const bool separatorIsVertical( state & State_Horizontal ); // define color and render const auto color( _helper->separatorColor( palette ) ); _helper->renderSeparator( painter, rect, color, separatorIsVertical ); return true; } //___________________________________________________________________________________ bool Style::drawIndicatorBranchPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // state const State& state( option->state ); const bool reverseLayout( option->direction == Qt::RightToLeft ); //draw expander int expanderAdjust = 0; if( state & State_Children ) { // state const bool expanderOpen( state & State_Open ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); // expander rect int expanderSize = qMin( rect.width(), rect.height() ); expanderSize = qMin( expanderSize, int(Metrics::ItemView_ArrowSize) ); expanderAdjust = expanderSize/2 + 1; const auto arrowRect = centerRect( rect, expanderSize, expanderSize ); // get orientation from option ArrowOrientation orientation; if( expanderOpen ) orientation = ArrowDown; else if( reverseLayout ) orientation = ArrowLeft; else orientation = ArrowRight; // color const auto arrowColor( mouseOver ? _helper->hoverColor( palette ) : _helper->arrowColor( palette, QPalette::Text ) ); // render _helper->renderArrow( painter, arrowRect, arrowColor, orientation ); } // tree branches if( !StyleConfigData::viewDrawTreeBranchLines() ) return true; const auto center( rect.center() ); const auto lineColor( KColorUtils::mix( palette.color( QPalette::Base ), palette.color( QPalette::Text ), 0.25 ) ); painter->setRenderHint( QPainter::Antialiasing, true ); painter->translate( 0.5, 0.5 ); painter->setPen( QPen( lineColor, 1 ) ); if( state & ( State_Item | State_Children | State_Sibling ) ) { const QLineF line( QPointF( center.x(), rect.top() ), QPointF( center.x(), center.y() - expanderAdjust - 1 ) ); painter->drawLine( line ); } // The right/left (depending on direction) line gets drawn if we have an item if( state & State_Item ) { const QLineF line = reverseLayout ? QLineF( QPointF( rect.left(), center.y() ), QPointF( center.x() - expanderAdjust, center.y() ) ): QLineF( QPointF( center.x() + expanderAdjust, center.y() ), QPointF( rect.right(), center.y() ) ); painter->drawLine( line ); } // The bottom if we have a sibling if( state & State_Sibling ) { const QLineF line( QPointF( center.x(), center.y() + expanderAdjust ), QPointF( center.x(), rect.bottom() ) ); painter->drawLine( line ); } return true; } //___________________________________________________________________________________ bool Style::drawPushButtonLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto buttonOption( qstyleoption_cast( option ) ); if( !buttonOption ) return true; // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool sunken( state & (State_On | State_Sunken) ); const bool mouseOver( enabled && (option->state & State_MouseOver) ); const bool hasFocus( enabled && !mouseOver && (option->state & State_HasFocus) ); const bool flat( buttonOption->features & QStyleOptionButton::Flat ); // content const bool hasText( !buttonOption->text.isEmpty() ); const bool hasIcon( (showIconsOnPushButtons() || flat || !hasText ) && !buttonOption->icon.isNull() ); // contents auto contentsRect( rect ); if( sunken && !flat ) contentsRect.translate( 1, 1 ); // color role QPalette::ColorRole textRole; if( flat ) { if( hasFocus && sunken ) textRole = QPalette::HighlightedText; else textRole = QPalette::WindowText; } else if( hasFocus ) textRole = QPalette::HighlightedText; else textRole = QPalette::ButtonText; // menu arrow if( buttonOption->features & QStyleOptionButton::HasMenu ) { // define rect auto arrowRect( contentsRect ); arrowRect.setLeft( contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1 ); arrowRect = centerRect( arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); contentsRect.setRight( arrowRect.left() - Metrics::Button_ItemSpacing - 1 ); contentsRect.adjust( Metrics::Button_MarginWidth, 0, 0, 0 ); arrowRect = visualRect( option, arrowRect ); // define color const auto arrowColor( _helper->arrowColor( palette, textRole ) ); _helper->renderArrow( painter, arrowRect, arrowColor, ArrowDown ); } // icon size QSize iconSize; if( hasIcon ) { iconSize = buttonOption->iconSize; if( !iconSize.isValid() ) { const int metric( pixelMetric( PM_SmallIconSize, option, widget ) ); iconSize = QSize( metric, metric ); } } // text size const int textFlags( _mnemonics->textFlags() | Qt::AlignCenter ); const QSize textSize( option->fontMetrics.size( textFlags, buttonOption->text ) ); // adjust text and icon rect based on options QRect iconRect; QRect textRect; if( hasText && !hasIcon ) textRect = contentsRect; else if( hasIcon && !hasText ) iconRect = contentsRect; else { const int contentsWidth( iconSize.width() + textSize.width() + Metrics::Button_ItemSpacing ); iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - contentsWidth )/2, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); textRect = QRect( QPoint( iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height())/2 ), textSize ); } // handle right to left if( iconRect.isValid() ) iconRect = visualRect( option, iconRect ); if( textRect.isValid() ) textRect = visualRect( option, textRect ); // make sure there is enough room for icon if( iconRect.isValid() ) iconRect = centerRect( iconRect, iconSize ); // render icon if( hasIcon && iconRect.isValid() ) { // icon state and mode const QIcon::State iconState( sunken ? QIcon::On : QIcon::Off ); QIcon::Mode iconMode; if( !enabled ) iconMode = QIcon::Disabled; else if( !flat && hasFocus ) iconMode = QIcon::Selected; else if( mouseOver && flat ) iconMode = QIcon::Active; else iconMode = QIcon::Normal; const auto pixmap = buttonOption->icon.pixmap( iconSize, iconMode, iconState ); drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); } // render text if( hasText && textRect.isValid() ) { drawItemText( painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole ); } return true; } //___________________________________________________________________________________ bool Style::drawToolButtonLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto toolButtonOption( qstyleoption_cast(option) ); // copy rect and palette const auto& rect = option->rect; const auto& palette = option->palette; // state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool sunken( state & (State_On | State_Sunken) ); const bool mouseOver( enabled && (option->state & State_MouseOver) ); const bool flat( state & State_AutoRaise ); // focus flag is set to match the background color in either renderButtonFrame or renderToolButtonFrame bool hasFocus( false ); if( flat ) hasFocus = enabled && !mouseOver && (option->state & State_HasFocus); else hasFocus = enabled && !mouseOver && (option->state & (State_HasFocus|State_Sunken) ); const bool hasArrow( toolButtonOption->features & QStyleOptionToolButton::Arrow ); const bool hasIcon( !( hasArrow || toolButtonOption->icon.isNull() ) ); const bool hasText( !toolButtonOption->text.isEmpty() ); // contents auto contentsRect( rect ); if( sunken && !flat ) contentsRect.translate( 1, 1 ); // icon size const QSize iconSize( toolButtonOption->iconSize ); // text size int textFlags( _mnemonics->textFlags() ); const QSize textSize( option->fontMetrics.size( textFlags, toolButtonOption->text ) ); // adjust text and icon rect based on options QRect iconRect; QRect textRect; if( hasText && ( !(hasArrow||hasIcon) || toolButtonOption->toolButtonStyle == Qt::ToolButtonTextOnly ) ) { // text only textRect = contentsRect; textFlags |= Qt::AlignCenter; } else if( (hasArrow||hasIcon) && (!hasText || toolButtonOption->toolButtonStyle == Qt::ToolButtonIconOnly ) ) { // icon only iconRect = contentsRect; } else if( toolButtonOption->toolButtonStyle == Qt::ToolButtonTextUnderIcon ) { const int contentsHeight( iconSize.height() + textSize.height() + Metrics::ToolButton_ItemSpacing ); iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - iconSize.width())/2, contentsRect.top() + (contentsRect.height() - contentsHeight)/2 ), iconSize ); textRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - textSize.width())/2, iconRect.bottom() + Metrics::ToolButton_ItemSpacing + 1 ), textSize ); textFlags |= Qt::AlignCenter; } else { const bool leftAlign( widget && widget->property( PropertyNames::toolButtonAlignment ).toInt() == Qt::AlignLeft ); if( leftAlign ) { const int marginWidth( Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth + 1 ); iconRect = QRect( QPoint( contentsRect.left() + marginWidth, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); } else { const int contentsWidth( iconSize.width() + textSize.width() + Metrics::ToolButton_ItemSpacing ); iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - contentsWidth )/2, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); } textRect = QRect( QPoint( iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height())/2 ), textSize ); // handle right to left layouts iconRect = visualRect( option, iconRect ); textRect = visualRect( option, textRect ); textFlags |= Qt::AlignLeft | Qt::AlignVCenter; } // make sure there is enough room for icon if( iconRect.isValid() ) iconRect = centerRect( iconRect, iconSize ); // render arrow or icon if( hasArrow && iconRect.isValid() ) { QStyleOptionToolButton copy( *toolButtonOption ); copy.rect = iconRect; switch( toolButtonOption->arrowType ) { case Qt::LeftArrow: drawPrimitive( PE_IndicatorArrowLeft, ©, painter, widget ); break; case Qt::RightArrow: drawPrimitive( PE_IndicatorArrowRight, ©, painter, widget ); break; case Qt::UpArrow: drawPrimitive( PE_IndicatorArrowUp, ©, painter, widget ); break; case Qt::DownArrow: drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); break; default: break; } } else if( hasIcon && iconRect.isValid() ) { // icon state and mode const QIcon::State iconState( sunken ? QIcon::On : QIcon::Off ); QIcon::Mode iconMode; if( !enabled ) iconMode = QIcon::Disabled; else if( (!flat && hasFocus) || (flat && (state & State_Sunken) && !mouseOver) ) iconMode = QIcon::Selected; else if( mouseOver && flat ) iconMode = QIcon::Active; else iconMode = QIcon::Normal; const QPixmap pixmap = toolButtonOption->icon.pixmap( iconSize, iconMode, iconState ); drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); } // render text if( hasText && textRect.isValid() ) { QPalette::ColorRole textRole( QPalette::ButtonText ); if( flat ) textRole = ( ((hasFocus&&sunken) || (state & State_Sunken))&&!mouseOver) ? QPalette::HighlightedText: QPalette::WindowText; else if( hasFocus&&!mouseOver ) textRole = QPalette::HighlightedText; painter->setFont(toolButtonOption->font); drawItemText( painter, textRect, textFlags, palette, enabled, toolButtonOption->text, textRole ); } return true; } //___________________________________________________________________________________ bool Style::drawCheckBoxLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto buttonOption( qstyleoption_cast(option) ); if( !buttonOption ) return true; // copy palette and rect const auto& palette( option->palette ); const auto& rect( option->rect ); // store state const State& state( option->state ); const bool enabled( state & State_Enabled ); // text alignment const bool reverseLayout( option->direction == Qt::RightToLeft ); const int textFlags( _mnemonics->textFlags() | Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight:Qt::AlignLeft ) ); // text rect auto textRect( rect ); // render icon if( !buttonOption->icon.isNull() ) { const QIcon::Mode mode( enabled ? QIcon::Normal : QIcon::Disabled ); const QPixmap pixmap( buttonOption->icon.pixmap( buttonOption->iconSize, mode ) ); drawItemPixmap( painter, rect, textFlags, pixmap ); // adjust rect (copied from QCommonStyle) textRect.setLeft( textRect.left() + buttonOption->iconSize.width() + 4 ); textRect = visualRect( option, textRect ); } // render text if( !buttonOption->text.isEmpty() ) { textRect = option->fontMetrics.boundingRect( textRect, textFlags, buttonOption->text ); drawItemText( painter, textRect, textFlags, palette, enabled, buttonOption->text, QPalette::WindowText ); // check focus state const bool hasFocus( enabled && ( state & State_HasFocus ) ); // update animation state _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); const bool isFocusAnimated( _animations->widgetStateEngine().isAnimated( widget, AnimationFocus ) ); const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationFocus ) ); // focus color QColor focusColor; if( isFocusAnimated ) focusColor = _helper->alphaColor( _helper->focusColor( palette ), opacity ); else if( hasFocus ) focusColor = _helper->focusColor( palette ); // render focus _helper->renderFocusLine( painter, textRect, focusColor ); } return true; } //___________________________________________________________________________________ bool Style::drawComboBoxLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { const auto comboBoxOption( qstyleoption_cast( option ) ); if( !comboBoxOption ) return false; if( comboBoxOption->editable ) return false; // need to alter palette for focused buttons const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool sunken( state & (State_On | State_Sunken) ); const bool mouseOver( enabled && (option->state & State_MouseOver) ); const bool hasFocus( enabled && !mouseOver && (option->state & State_HasFocus) ); const bool flat( !comboBoxOption->frame ); QPalette::ColorRole textRole; if( flat ) { if( hasFocus && sunken ) textRole = QPalette::HighlightedText; else textRole = QPalette::WindowText; } else if( hasFocus ) textRole = QPalette::HighlightedText; else textRole = QPalette::ButtonText; // change pen color directly painter->setPen( QPen( option->palette.color( textRole ), 1 ) ); // translate painter for pressed down comboboxes if( sunken && !flat ) { painter->translate( 1, 1 ); } #if QT_VERSION >= 0x050000 if (const auto cb = qstyleoption_cast(option)) { auto editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); painter->save(); painter->setClipRect(editRect); if (!cb->currentIcon.isNull()) { QIcon::Mode mode; if ((cb->state & QStyle::State_Selected) && (cb->state & QStyle::State_Active)) { mode = QIcon::Selected; } else if (cb->state & QStyle::State_Enabled) { mode = QIcon::Normal; } else { mode = QIcon::Disabled; } const auto pixmap = cb->currentIcon.pixmap(widget->windowHandle(), cb->iconSize, mode); auto iconRect(editRect); iconRect.setWidth(cb->iconSize.width() + 4); iconRect = alignedRect(cb->direction, Qt::AlignLeft | Qt::AlignVCenter, iconRect.size(), editRect); if (cb->editable) painter->fillRect(iconRect, option->palette.brush(QPalette::Base)); proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); if (cb->direction == Qt::RightToLeft) editRect.translate(-4 - cb->iconSize.width(), 0); else editRect.translate(cb->iconSize.width() + 4, 0); } if (!cb->currentText.isEmpty() && !cb->editable) { proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0), visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter), cb->palette, cb->state & State_Enabled, cb->currentText); } painter->restore(); } #else // call base class method ParentStyleClass::drawControl( CE_ComboBoxLabel, option, painter, widget ); #endif return true; } //___________________________________________________________________________________ bool Style::drawMenuBarItemControl( const QStyleOption* option, QPainter* painter, const QWidget* widget) const { // cast option and check const auto menuItemOption = qstyleoption_cast( option ); if( !menuItemOption ) return true; // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // store state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool selected( enabled && (state & State_Selected) ); const bool sunken( enabled && (state & State_Sunken) ); const bool useStrongFocus( StyleConfigData::menuItemDrawStrongFocus() ); // render hover and focus if( useStrongFocus && ( selected || sunken ) ) { QColor outlineColor; if( sunken ) outlineColor = _helper->focusColor( palette ); else if( selected ) outlineColor = _helper->hoverColor( palette ); _helper->renderFocusRect( painter, rect, outlineColor ); } /* check if item as an icon, in which case only the icon should be rendered consistently with comment in QMenuBarPrivate::calcActionRects */ if( !menuItemOption->icon.isNull() ) { // icon size is forced to SmallIconSize const auto iconSize = pixelMetric(QStyle::PM_SmallIconSize, nullptr, widget); const auto iconRect = centerRect( rect, iconSize, iconSize ); // decide icon mode and state QIcon::Mode iconMode; QIcon::State iconState; if( !enabled ) { iconMode = QIcon::Disabled; iconState = QIcon::Off; } else { if( useStrongFocus && sunken ) iconMode = QIcon::Selected; else if( useStrongFocus && selected ) iconMode = QIcon::Active; else iconMode = QIcon::Normal; iconState = sunken ? QIcon::On : QIcon::Off; } const auto pixmap = menuItemOption->icon.pixmap( iconSize, iconMode, iconState ); drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); // render outline if( !useStrongFocus && ( selected || sunken ) ) { QColor outlineColor; if( sunken ) outlineColor = _helper->focusColor( palette ); else if( selected ) outlineColor = _helper->hoverColor( palette ); _helper->renderFocusLine( painter, iconRect, outlineColor ); } } else { // get text rect const int textFlags( Qt::AlignCenter|_mnemonics->textFlags() ); const auto textRect = option->fontMetrics.boundingRect( rect, textFlags, menuItemOption->text ); // render text const QPalette::ColorRole role = (useStrongFocus && sunken ) ? QPalette::HighlightedText : QPalette::WindowText; drawItemText( painter, textRect, textFlags, palette, enabled, menuItemOption->text, role ); // render outline if( !useStrongFocus && ( selected || sunken ) ) { QColor outlineColor; if( sunken ) outlineColor = _helper->focusColor( palette ); else if( selected ) outlineColor = _helper->hoverColor( palette ); _helper->renderFocusLine( painter, textRect, outlineColor ); } } return true; } //___________________________________________________________________________________ bool Style::drawMenuItemControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto menuItemOption = qstyleoption_cast( option ); if( !menuItemOption ) return true; if( menuItemOption->menuItemType == QStyleOptionMenuItem::EmptyArea ) return true; // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // deal with separators if( menuItemOption->menuItemType == QStyleOptionMenuItem::Separator ) { // normal separator if( menuItemOption->text.isEmpty() && menuItemOption->icon.isNull() ) { const auto color( _helper->separatorColor( palette ) ); _helper->renderSeparator( painter, rect, color ); return true; } else { /* * separator can have a title and an icon * in that case they are rendered as menu title buttons */ QStyleOptionToolButton copy( separatorMenuItemOption( menuItemOption, widget ) ); renderMenuTitle( ©, painter, widget ); return true; } } // store state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool selected( enabled && (state & State_Selected) ); const bool sunken( enabled && (state & (State_On|State_Sunken) ) ); const bool reverseLayout( option->direction == Qt::RightToLeft ); const bool useStrongFocus( StyleConfigData::menuItemDrawStrongFocus() ); // render hover and focus if( useStrongFocus && ( selected || sunken ) ) { const auto color = _helper->focusColor( palette ); const auto outlineColor = _helper->focusOutlineColor( palette ); - Sides sides = 0; + Sides sides = nullptr; if( !menuItemOption->menuRect.isNull() ) { if( rect.top() <= menuItemOption->menuRect.top() ) sides |= SideTop; if( rect.bottom() >= menuItemOption->menuRect.bottom() ) sides |= SideBottom; if( rect.left() <= menuItemOption->menuRect.left() ) sides |= SideLeft; if( rect.right() >= menuItemOption->menuRect.right() ) sides |= SideRight; } _helper->renderFocusRect( painter, rect, color, outlineColor, sides ); } // get rect available for contents auto contentsRect( insideMargin( rect, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ) ); // define relevant rectangles // checkbox QRect checkBoxRect; if( menuItemOption->menuHasCheckableItems ) { checkBoxRect = QRect( contentsRect.left(), contentsRect.top() + (contentsRect.height()-Metrics::CheckBox_Size)/2, Metrics::CheckBox_Size, Metrics::CheckBox_Size ); contentsRect.setLeft( checkBoxRect.right() + Metrics::MenuItem_ItemSpacing + 1 ); } // render checkbox indicator if( menuItemOption->checkType == QStyleOptionMenuItem::NonExclusive ) { checkBoxRect = visualRect( option, checkBoxRect ); // checkbox state if( useStrongFocus && ( selected || sunken ) ) { _helper->renderCheckBoxBackground( painter, checkBoxRect, palette.color( QPalette::Window ), sunken ); } CheckBoxState state( menuItemOption->checked ? CheckOn : CheckOff ); const bool active( menuItemOption->checked ); const auto shadow( _helper->shadowColor( palette ) ); const auto color( _helper->checkBoxIndicatorColor( palette, false, enabled && active ) ); _helper->renderCheckBox( painter, checkBoxRect, color, shadow, sunken, state ); } else if( menuItemOption->checkType == QStyleOptionMenuItem::Exclusive ) { checkBoxRect = visualRect( option, checkBoxRect ); if( useStrongFocus && ( selected || sunken ) ) { _helper->renderRadioButtonBackground( painter, checkBoxRect, palette.color( QPalette::Window ), sunken ); } const bool active( menuItemOption->checked ); const auto shadow( _helper->shadowColor( palette ) ); const auto color( _helper->checkBoxIndicatorColor( palette, false, enabled && active ) ); _helper->renderRadioButton( painter, checkBoxRect, color, shadow, sunken, active ? RadioOn:RadioOff ); } // icon int iconWidth = 0; const bool showIcon( showIconsInMenuItems() ); if( showIcon ) iconWidth = isQtQuickControl( option, widget ) ? qMax( pixelMetric(PM_SmallIconSize, option, widget ), menuItemOption->maxIconWidth ) : menuItemOption->maxIconWidth; QRect iconRect; if( showIcon && iconWidth > 0 ) { iconRect = QRect( contentsRect.left(), contentsRect.top() + (contentsRect.height()-iconWidth)/2, iconWidth, iconWidth ); contentsRect.setLeft( iconRect.right() + Metrics::MenuItem_ItemSpacing + 1 ); const QSize iconSize( pixelMetric( PM_SmallIconSize, option, widget ), pixelMetric( PM_SmallIconSize, option, widget ) ); iconRect = centerRect( iconRect, iconSize ); } if( showIcon && !menuItemOption->icon.isNull() ) { iconRect = visualRect( option, iconRect ); // icon mode QIcon::Mode mode; if( selected && !useStrongFocus) mode = QIcon::Active; else if( selected ) mode = QIcon::Selected; else if( enabled ) mode = QIcon::Normal; else mode = QIcon::Disabled; // icon state const QIcon::State iconState( sunken ? QIcon::On:QIcon::Off ); const QPixmap icon = menuItemOption->icon.pixmap( iconRect.size(), mode, iconState ); painter->drawPixmap( iconRect, icon ); } // arrow QRect arrowRect( contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1, contentsRect.top() + (contentsRect.height()-Metrics::MenuButton_IndicatorWidth)/2, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); contentsRect.setRight( arrowRect.left() - Metrics::MenuItem_ItemSpacing - 1 ); if( menuItemOption->menuItemType == QStyleOptionMenuItem::SubMenu ) { // apply right-to-left layout arrowRect = visualRect( option, arrowRect ); // arrow orientation const ArrowOrientation orientation( reverseLayout ? ArrowLeft:ArrowRight ); // color QColor arrowColor; if( useStrongFocus && ( selected || sunken ) ) arrowColor = palette.color( QPalette::HighlightedText ); else if( sunken ) arrowColor = _helper->focusColor( palette ); else if( selected ) arrowColor = _helper->hoverColor( palette ); else arrowColor = _helper->arrowColor( palette, QPalette::WindowText ); // render _helper->renderArrow( painter, arrowRect, arrowColor, orientation ); } // text auto textRect = contentsRect; if( !menuItemOption->text.isEmpty() ) { // adjust textRect QString text = menuItemOption->text; textRect = centerRect( textRect, textRect.width(), option->fontMetrics.size( _mnemonics->textFlags(), text ).height() ); textRect = visualRect( option, textRect ); // set font painter->setFont( menuItemOption->font ); // color role const QPalette::ColorRole role = (useStrongFocus && ( selected || sunken )) ? QPalette::HighlightedText : QPalette::WindowText; // locate accelerator and render const int tabPosition( text.indexOf( QLatin1Char( '\t' ) ) ); if( tabPosition >= 0 ) { const int textFlags( Qt::AlignVCenter | Qt::AlignRight ); QString accelerator( text.mid( tabPosition + 1 ) ); text = text.left( tabPosition ); drawItemText( painter, textRect, textFlags, palette, enabled, accelerator, role ); } // render text const int textFlags( Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight : Qt::AlignLeft ) | _mnemonics->textFlags() ); textRect = option->fontMetrics.boundingRect( textRect, textFlags, text ); drawItemText( painter, textRect, textFlags, palette, enabled, text, role ); // render hover and focus if( !useStrongFocus && ( selected || sunken ) ) { QColor outlineColor; if( sunken ) outlineColor = _helper->focusColor( palette ); else if( selected ) outlineColor = _helper->hoverColor( palette ); _helper->renderFocusLine( painter, textRect, outlineColor ); } } return true; } //___________________________________________________________________________________ bool Style::drawProgressBarControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return true; // render groove QStyleOptionProgressBarV2 progressBarOption2 = *progressBarOption; progressBarOption2.rect = subElementRect( SE_ProgressBarGroove, progressBarOption, widget ); drawControl( CE_ProgressBarGroove, &progressBarOption2, painter, widget ); #if QT_VERSION >= 0x050000 const QObject* styleObject( widget ? widget:progressBarOption->styleObject ); #else const QObject* styleObject( widget ); #endif // enable busy animations // need to check both widget and passed styleObject, used for QML if( styleObject && _animations->busyIndicatorEngine().enabled() ) { #if QT_VERSION >= 0x050000 // register QML object if defined if( !widget && progressBarOption->styleObject ) { _animations->busyIndicatorEngine().registerWidget( progressBarOption->styleObject ); } #endif _animations->busyIndicatorEngine().setAnimated( styleObject, progressBarOption->maximum == 0 && progressBarOption->minimum == 0 ); } // check if animated and pass to option if( _animations->busyIndicatorEngine().isAnimated( styleObject ) ) { progressBarOption2.progress = _animations->busyIndicatorEngine().value(); } // render contents progressBarOption2.rect = subElementRect( SE_ProgressBarContents, progressBarOption, widget ); drawControl( CE_ProgressBarContents, &progressBarOption2, painter, widget ); // render text const bool textVisible( progressBarOption->textVisible ); const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); if( textVisible && !busy ) { progressBarOption2.rect = subElementRect( SE_ProgressBarLabel, progressBarOption, widget ); drawControl( CE_ProgressBarLabel, &progressBarOption2, painter, widget ); } return true; } //___________________________________________________________________________________ bool Style::drawProgressBarContentsControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const { const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return true; // copy rect and palette auto rect( option->rect ); const auto& palette( option->palette ); // get direction const auto progressBarOption2( qstyleoption_cast( option ) ); const bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; const bool inverted( progressBarOption2 ? progressBarOption2->invertedAppearance : false ); bool reverse = horizontal && option->direction == Qt::RightToLeft; if( inverted ) reverse = !reverse; // check if anything is to be drawn const bool busy( ( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ) ); if( busy ) { const qreal progress( _animations->busyIndicatorEngine().value() ); const auto first( palette.color( QPalette::Highlight ) ); const auto second( KColorUtils::mix( palette.color( QPalette::Highlight ), palette.color( QPalette::Window ), 0.7 ) ); _helper->renderProgressBarBusyContents( painter, rect, first, second, horizontal, reverse, progress ); } else { const QRegion oldClipRegion( painter->clipRegion() ); if( horizontal ) { if( rect.width() < Metrics::ProgressBar_Thickness ) { painter->setClipRect( rect, Qt::IntersectClip ); if( reverse ) rect.setLeft( rect.left() - Metrics::ProgressBar_Thickness + rect.width() ); else rect.setWidth( Metrics::ProgressBar_Thickness ); } } else { if( rect.height() < Metrics::ProgressBar_Thickness ) { painter->setClipRect( rect, Qt::IntersectClip ); if( reverse ) rect.setHeight( Metrics::ProgressBar_Thickness ); else rect.setTop( rect.top() - Metrics::ProgressBar_Thickness + rect.height() ); } } auto contentsColor( option->state.testFlag( QStyle::State_Selected ) ? palette.color( QPalette::HighlightedText ) : palette.color( QPalette::Highlight ) ); _helper->renderProgressBarContents( painter, rect, contentsColor ); painter->setClipRegion( oldClipRegion ); } return true; } //___________________________________________________________________________________ bool Style::drawProgressBarGrooveControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const { const auto& palette( option->palette ); const auto color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.3 ) ); _helper->renderProgressBarGroove( painter, option->rect, color ); return true; } //___________________________________________________________________________________ bool Style::drawProgressBarLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // cast option and check const auto progressBarOption( qstyleoption_cast( option ) ); if( !progressBarOption ) return true; // get direction and check const auto progressBarOption2( qstyleoption_cast( option ) ); const bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; if( !horizontal ) return true; // store rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // store state and direction const State& state( option->state ); const bool enabled( state & State_Enabled ); // define text rect Qt::Alignment hAlign( ( progressBarOption->textAlignment == Qt::AlignLeft ) ? Qt::AlignHCenter : progressBarOption->textAlignment ); drawItemText( painter, rect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::WindowText ); return true; } //___________________________________________________________________________________ bool Style::drawScrollBarSliderControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return true; // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); //try to understand if anywhere the widget is under mouse, not just the handle, use _animations in case of QWidget, option->styleObject in case of QML #if QT_VERSION >= 0x050000 const bool widgetMouseOver( widget ? _animations->scrollBarEngine().isHovered( widget, QStyle::SC_ScrollBarGroove ) : option->styleObject->property("hover").toBool()); #else const bool widgetMouseOver( _animations->scrollBarEngine().isHovered( widget, QStyle::SC_ScrollBarGroove ) ); #endif qreal grooveAnimationOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); if( grooveAnimationOpacity == AnimationData::OpacityInvalid ) grooveAnimationOpacity = (widgetMouseOver ? 1 : 0); const qreal handleSize = StyleConfigData::animationsEnabled() ? ((Metrics::ScrollBar_SliderWidth / 2.0) * (1 - grooveAnimationOpacity) + Metrics::ScrollBar_SliderWidth * grooveAnimationOpacity) : (int)Metrics::ScrollBar_SliderWidth; // define handle rect QRect handleRect; const State& state( option->state ); const bool horizontal( state & State_Horizontal ); if( horizontal ) handleRect = centerRect( rect, rect.width(), handleSize ); else handleRect = centerRect( rect, handleSize, rect.height() ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); // check focus from relevant parent const QWidget* parent( scrollBarParent( widget ) ); const bool hasFocus( enabled && ( (widget && widget->hasFocus()) || (parent && parent->hasFocus()) ) ); // enable animation state const bool handleActive( sliderOption->activeSubControls & SC_ScrollBarSlider ); _animations->scrollBarEngine().updateState( widget, AnimationFocus, hasFocus ); _animations->scrollBarEngine().updateState( widget, AnimationHover, mouseOver && handleActive ); const auto mode( _animations->scrollBarEngine().animationMode( widget, SC_ScrollBarSlider ) ); const qreal opacity( _animations->scrollBarEngine().opacity( widget, SC_ScrollBarSlider ) ); auto color = _helper->scrollBarHandleColor( palette, mouseOver, hasFocus, opacity, mode ); if (StyleConfigData::animationsEnabled()) { color.setAlphaF(color.alphaF() * (0.7 + 0.3 * grooveAnimationOpacity)); } _helper->renderScrollBarHandle( painter, handleRect, color ); return true; } //___________________________________________________________________________________ bool Style::drawScrollBarAddLineControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // do nothing if no buttons are defined if( _addLineButtons == NoButton ) return true; // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return true; const State& state( option->state ); const bool horizontal( state & State_Horizontal ); const bool reverseLayout( option->direction == Qt::RightToLeft ); // adjust rect, based on number of buttons to be drawn const auto rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarAddLine ) ); QColor color; QStyleOptionSlider copy( *sliderOption ); if( _addLineButtons == DoubleButton ) { if( horizontal ) { //Draw the arrows const QSize halfSize( rect.width()/2, rect.height() ); const QRect leftSubButton( rect.topLeft(), halfSize ); const QRect rightSubButton( leftSubButton.topRight() + QPoint( 1, 0 ), halfSize ); copy.rect = leftSubButton; color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarAddLine:SC_ScrollBarSubLine, widget ); _helper->renderArrow( painter, leftSubButton, color, ArrowLeft ); copy.rect = rightSubButton; color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarSubLine:SC_ScrollBarAddLine, widget ); _helper->renderArrow( painter, rightSubButton, color, ArrowRight ); } else { const QSize halfSize( rect.width(), rect.height()/2 ); const QRect topSubButton( rect.topLeft(), halfSize ); const QRect botSubButton( topSubButton.bottomLeft() + QPoint( 0, 1 ), halfSize ); copy.rect = topSubButton; color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); _helper->renderArrow( painter, topSubButton, color, ArrowUp ); copy.rect = botSubButton; color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); _helper->renderArrow( painter, botSubButton, color, ArrowDown ); } } else if( _addLineButtons == SingleButton ) { copy.rect = rect; color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); if( horizontal ) { if( reverseLayout ) _helper->renderArrow( painter, rect, color, ArrowLeft ); else _helper->renderArrow( painter, rect.translated( 1, 0 ), color, ArrowRight ); } else _helper->renderArrow( painter, rect.translated( 0, 1 ), color, ArrowDown ); } return true; } //___________________________________________________________________________________ bool Style::drawScrollBarSubLineControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // do nothing if no buttons are set if( _subLineButtons == NoButton ) return true; // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return true; const State& state( option->state ); const bool horizontal( state & State_Horizontal ); const bool reverseLayout( option->direction == Qt::RightToLeft ); // colors const auto& palette( option->palette ); const auto background( palette.color( QPalette::Window ) ); // adjust rect, based on number of buttons to be drawn const auto rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarSubLine ) ); QColor color; QStyleOptionSlider copy( *sliderOption ); if( _subLineButtons == DoubleButton ) { if( horizontal ) { //Draw the arrows const QSize halfSize( rect.width()/2, rect.height() ); const QRect leftSubButton( rect.topLeft(), halfSize ); const QRect rightSubButton( leftSubButton.topRight() + QPoint( 1, 0 ), halfSize ); copy.rect = leftSubButton; color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarAddLine:SC_ScrollBarSubLine, widget ); _helper->renderArrow( painter, leftSubButton, color, ArrowLeft ); copy.rect = rightSubButton; color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarSubLine:SC_ScrollBarAddLine, widget ); _helper->renderArrow( painter, rightSubButton, color, ArrowRight ); } else { const QSize halfSize( rect.width(), rect.height()/2 ); const QRect topSubButton( rect.topLeft(), halfSize ); const QRect botSubButton( topSubButton.bottomLeft() + QPoint( 0, 1 ), halfSize ); copy.rect = topSubButton; color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); _helper->renderArrow( painter, topSubButton, color, ArrowUp ); copy.rect = botSubButton; color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); _helper->renderArrow( painter, botSubButton, color, ArrowDown ); } } else if( _subLineButtons == SingleButton ) { copy.rect = rect; color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); if( horizontal ) { if( reverseLayout ) _helper->renderArrow( painter, rect.translated( 1, 0 ), color, ArrowRight ); else _helper->renderArrow( painter, rect, color, ArrowLeft ); } else _helper->renderArrow( painter, rect, color, ArrowUp ); } return true; } //___________________________________________________________________________________ bool Style::drawShapedFrameControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto frameOpt = qstyleoption_cast( option ); if( !frameOpt ) return false; switch( frameOpt->frameShape ) { case QFrame::Box: { if( option->state & State_Sunken ) return true; else break; } case QFrame::HLine: case QFrame::VLine: { const auto& rect( option->rect ); const auto color( _helper->separatorColor( option->palette ) ); const bool isVertical( frameOpt->frameShape == QFrame::VLine ); _helper->renderSeparator( painter, rect, color, isVertical ); return true; } case QFrame::StyledPanel: { if( isQtQuickControl( option, widget ) ) { // ComboBox popup frame drawFrameMenuPrimitive( option, painter, widget ); return true; } else break; } default: break; } return false; } //___________________________________________________________________________________ bool Style::drawRubberBandControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const { const auto& palette( option->palette ); const auto rect( option->rect ); auto color = palette.color( QPalette::Highlight ); painter->setPen( KColorUtils::mix( color, palette.color( QPalette::Active, QPalette::WindowText ) ) ); color.setAlpha( 50 ); painter->setBrush( color ); painter->setClipRegion( rect ); painter->drawRect( rect.adjusted( 0, 0, -1, -1 ) ); return true; } //___________________________________________________________________________________ bool Style::drawHeaderSectionControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { const auto& rect( option->rect ); const auto& palette( option->palette ); const auto& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool sunken( enabled && ( state & (State_On|State_Sunken) ) ); const auto headerOption( qstyleoption_cast( option ) ); if( !headerOption ) return true; const bool horizontal( headerOption->orientation == Qt::Horizontal ); const bool isFirst( horizontal && ( headerOption->position == QStyleOptionHeader::Beginning ) ); const bool isCorner( widget && widget->inherits( "QTableCornerButton" ) ); const bool reverseLayout( option->direction == Qt::RightToLeft ); // update animation state _animations->headerViewEngine().updateState( widget, rect.topLeft(), mouseOver ); const bool animated( enabled && _animations->headerViewEngine().isAnimated( widget, rect.topLeft() ) ); const qreal opacity( _animations->headerViewEngine().opacity( widget, rect.topLeft() ) ); // fill const auto normal( palette.color( QPalette::Button ) ); const auto focus( KColorUtils::mix( normal, _helper->focusColor( palette ), 0.2 ) ); const auto hover( KColorUtils::mix( normal, _helper->hoverColor( palette ), 0.2 ) ); QColor color; if( sunken ) color = focus; else if( animated ) color = KColorUtils::mix( normal, hover, opacity ); else if( mouseOver ) color = hover; else color = normal; painter->setRenderHint( QPainter::Antialiasing, false ); painter->setBrush( color ); painter->setPen( Qt::NoPen ); painter->drawRect( rect ); // outline painter->setBrush( Qt::NoBrush ); painter->setPen( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.1 ) ); if( isCorner ) { if( reverseLayout ) painter->drawPoint( rect.bottomLeft() ); else painter->drawPoint( rect.bottomRight() ); } else if( horizontal ) { painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); } else { if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() ); else painter->drawLine( rect.topRight(), rect.bottomRight() ); } // separators painter->setPen( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.2 ) ); if( horizontal ) { if( headerOption->section != 0 || isFirst ) { if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() - QPoint( 0, 1 ) ); else painter->drawLine( rect.topRight(), rect.bottomRight() - QPoint( 0, 1 ) ); } } else { if( reverseLayout ) painter->drawLine( rect.bottomLeft()+QPoint( 1, 0 ), rect.bottomRight() ); else painter->drawLine( rect.bottomLeft(), rect.bottomRight() - QPoint( 1, 0 ) ); } return true; } //___________________________________________________________________________________ bool Style::drawHeaderEmptyAreaControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const { // use the same background as in drawHeaderPrimitive const auto& rect( option->rect ); auto palette( option->palette ); const bool horizontal( option->state & QStyle::State_Horizontal ); const bool reverseLayout( option->direction == Qt::RightToLeft ); // fill painter->setRenderHint( QPainter::Antialiasing, false ); painter->setBrush( palette.color( QPalette::Button ) ); painter->setPen( Qt::NoPen ); painter->drawRect( rect ); // outline painter->setBrush( Qt::NoBrush ); painter->setPen( _helper->alphaColor( palette.color( QPalette::ButtonText ), 0.1 ) ); if( horizontal ) { painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); } else { if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() ); else painter->drawLine( rect.topRight(), rect.bottomRight() ); } return true; } //___________________________________________________________________________________ bool Style::drawTabBarTabLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // call parent style method ParentStyleClass::drawControl( CE_TabBarTabLabel, option, painter, widget ); // store rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // check focus const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool selected( state & State_Selected ); const bool hasFocus( enabled && selected && (state & State_HasFocus) ); // update mouse over animation state _animations->tabBarEngine().updateState( widget, rect.topLeft(), AnimationFocus, hasFocus ); const bool animated( enabled && selected && _animations->tabBarEngine().isAnimated( widget, rect.topLeft(), AnimationFocus ) ); const qreal opacity( _animations->tabBarEngine().opacity( widget, rect.topLeft(), AnimationFocus ) ); if( !( hasFocus || animated ) ) return true; // code is copied from QCommonStyle, but adds focus // cast option and check const auto tabOption( qstyleoption_cast(option) ); if( !tabOption || tabOption->text.isEmpty() ) return true; // tab option rect const bool verticalTabs( isVerticalTab( tabOption ) ); const int textFlags( Qt::AlignCenter | _mnemonics->textFlags() ); // text rect auto textRect( subElementRect(SE_TabBarTabText, option, widget) ); if( verticalTabs ) { // properly rotate painter painter->save(); int newX, newY, newRot; if( tabOption->shape == QTabBar::RoundedEast || tabOption->shape == QTabBar::TriangularEast) { newX = rect.width() + rect.x(); newY = rect.y(); newRot = 90; } else { newX = rect.x(); newY = rect.y() + rect.height(); newRot = -90; } QTransform transform; transform.translate( newX, newY ); transform.rotate(newRot); painter->setTransform( transform, true ); } // adjust text rect based on font metrics textRect = option->fontMetrics.boundingRect( textRect, textFlags, tabOption->text ); // focus color QColor focusColor; if( animated ) focusColor = _helper->alphaColor( _helper->focusColor( palette ), opacity ); else if( hasFocus ) focusColor = _helper->focusColor( palette ); // render focus line _helper->renderFocusLine( painter, textRect, focusColor ); if( verticalTabs ) painter->restore(); return true; } //___________________________________________________________________________________ bool Style::drawTabBarTabShapeControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { const auto tabOption( qstyleoption_cast( option ) ); if( !tabOption ) return true; // palette and state const auto& palette( option->palette ); const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool selected( state & State_Selected ); const bool mouseOver( enabled && !selected && ( state & State_MouseOver ) ); // check if tab is being dragged const bool isDragged( widget && selected && painter->device() != widget ); const bool isLocked( widget && _tabBarData->isLocked( widget ) ); // store rect auto rect( option->rect ); // update mouse over animation state _animations->tabBarEngine().updateState( widget, rect.topLeft(), AnimationHover, mouseOver ); const bool animated( enabled && !selected && _animations->tabBarEngine().isAnimated( widget, rect.topLeft(), AnimationHover ) ); const qreal opacity( _animations->tabBarEngine().opacity( widget, rect.topLeft(), AnimationHover ) ); // lock state if( selected && widget && isDragged ) _tabBarData->lock( widget ); else if( widget && selected && _tabBarData->isLocked( widget ) ) _tabBarData->release(); // tab position const QStyleOptionTab::TabPosition& position = tabOption->position; const bool isSingle( position == QStyleOptionTab::OnlyOneTab ); const bool isQtQuickControl( this->isQtQuickControl( option, widget ) ); bool isFirst( isSingle || position == QStyleOptionTab::Beginning ); bool isLast( isSingle || position == QStyleOptionTab::End ); bool isLeftOfSelected( !isLocked && tabOption->selectedPosition == QStyleOptionTab::NextIsSelected ); bool isRightOfSelected( !isLocked && tabOption->selectedPosition == QStyleOptionTab::PreviousIsSelected ); // true if widget is aligned to the frame // need to check for 'isRightOfSelected' because for some reason the isFirst flag is set when active tab is being moved isFirst &= !isRightOfSelected; isLast &= !isLeftOfSelected; // swap state based on reverse layout, so that they become layout independent const bool reverseLayout( option->direction == Qt::RightToLeft ); const bool verticalTabs( isVerticalTab( tabOption ) ); if( reverseLayout && !verticalTabs ) { qSwap( isFirst, isLast ); qSwap( isLeftOfSelected, isRightOfSelected ); } // overlap // for QtQuickControls, ovelap is already accounted of in the option. Unlike in the qwidget case const int overlap( isQtQuickControl ? 0:Metrics::TabBar_TabOverlap ); // adjust rect and define corners based on tabbar orientation Corners corners; switch( tabOption->shape ) { case QTabBar::RoundedNorth: case QTabBar::TriangularNorth: if( selected ) { corners = CornerTopLeft|CornerTopRight; rect.adjust( 0, 0, 0, 1 ); } else { rect.adjust( 0, 0, 0, -1 ); if( isFirst ) corners |= CornerTopLeft; if( isLast ) corners |= CornerTopRight; if( isRightOfSelected ) rect.adjust( -Metrics::Frame_FrameRadius, 0, 0, 0 ); if( isLeftOfSelected ) rect.adjust( 0, 0, Metrics::Frame_FrameRadius, 0 ); else if( !isLast ) rect.adjust( 0, 0, overlap, 0 ); } break; case QTabBar::RoundedSouth: case QTabBar::TriangularSouth: if( selected ) { corners = CornerBottomLeft|CornerBottomRight; rect.adjust( 0, - 1, 0, 0 ); } else { rect.adjust( 0, 1, 0, 0 ); if( isFirst ) corners |= CornerBottomLeft; if( isLast ) corners |= CornerBottomRight; if( isRightOfSelected ) rect.adjust( -Metrics::Frame_FrameRadius, 0, 0, 0 ); if( isLeftOfSelected ) rect.adjust( 0, 0, Metrics::Frame_FrameRadius, 0 ); else if( !isLast ) rect.adjust( 0, 0, overlap, 0 ); } break; case QTabBar::RoundedWest: case QTabBar::TriangularWest: if( selected ) { corners = CornerTopLeft|CornerBottomLeft; rect.adjust( 0, 0, 1, 0 ); } else { rect.adjust( 0, 0, -1, 0 ); if( isFirst ) corners |= CornerTopLeft; if( isLast ) corners |= CornerBottomLeft; if( isRightOfSelected ) rect.adjust( 0, -Metrics::Frame_FrameRadius, 0, 0 ); if( isLeftOfSelected ) rect.adjust( 0, 0, 0, Metrics::Frame_FrameRadius ); else if( !isLast ) rect.adjust( 0, 0, 0, overlap ); } break; case QTabBar::RoundedEast: case QTabBar::TriangularEast: if( selected ) { corners = CornerTopRight|CornerBottomRight; rect.adjust( -1, 0, 0, 0 ); } else { rect.adjust( 1, 0, 0, 0 ); if( isFirst ) corners |= CornerTopRight; if( isLast ) corners |= CornerBottomRight; if( isRightOfSelected ) rect.adjust( 0, -Metrics::Frame_FrameRadius, 0, 0 ); if( isLeftOfSelected ) rect.adjust( 0, 0, 0, Metrics::Frame_FrameRadius ); else if( !isLast ) rect.adjust( 0, 0, 0, overlap ); } break; default: break; } // color QColor color; if( selected ) { #if QT_VERSION >= 0x050000 bool documentMode = tabOption->documentMode; #else bool documentMode = false; if( const auto tabOptionV3 = qstyleoption_cast( option ) ) { documentMode = tabOptionV3->documentMode; } #endif // flag passed to QStyleOptionTab is unfortunately not reliable enough // also need to check on parent widget const auto tabWidget = ( widget && widget->parentWidget() ) ? qobject_cast( widget->parentWidget() ) : nullptr; documentMode |= ( tabWidget ? tabWidget->documentMode() : true ); color = (documentMode&&!isQtQuickControl&&!hasAlteredBackground(widget)) ? palette.color( QPalette::Window ) : _helper->frameBackgroundColor( palette ); } else { const auto normal( _helper->alphaColor( palette.color( QPalette::Shadow ), 0.2 ) ); const auto hover( _helper->alphaColor( _helper->hoverColor( palette ), 0.2 ) ); if( animated ) color = KColorUtils::mix( normal, hover, opacity ); else if( mouseOver ) color = hover; else color = normal; } // outline const auto outline( selected ? _helper->alphaColor( palette.color( QPalette::WindowText ), 0.25 ) : QColor() ); // render if( selected ) { QRegion oldRegion( painter->clipRegion() ); painter->setClipRect( option->rect, Qt::IntersectClip ); _helper->renderTabBarTab( painter, rect, color, outline, corners ); painter->setClipRegion( oldRegion ); } else { _helper->renderTabBarTab( painter, rect, color, outline, corners ); } return true; } //___________________________________________________________________________________ bool Style::drawToolBoxTabLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // rendering is similar to drawPushButtonLabelControl // cast option and check const auto toolBoxOption( qstyleoption_cast( option ) ); if( !toolBoxOption ) return true; // copy palette const auto& palette( option->palette ); const State& state( option->state ); const bool enabled( state & State_Enabled ); // text alignment const int textFlags( _mnemonics->textFlags() | Qt::AlignCenter ); // contents rect const auto rect( subElementRect( SE_ToolBoxTabContents, option, widget ) ); // store icon size const int iconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); // find contents size and rect auto contentsRect( rect ); QSize contentsSize; if( !toolBoxOption->text.isEmpty() ) { contentsSize = option->fontMetrics.size( _mnemonics->textFlags(), toolBoxOption->text ); if( !toolBoxOption->icon.isNull() ) contentsSize.rwidth() += Metrics::ToolBox_TabItemSpacing; } // icon size if( !toolBoxOption->icon.isNull() ) { contentsSize.setHeight( qMax( contentsSize.height(), iconSize ) ); contentsSize.rwidth() += iconSize; } // adjust contents rect contentsRect = centerRect( contentsRect, contentsSize ); // render icon if( !toolBoxOption->icon.isNull() ) { // icon rect QRect iconRect; if( toolBoxOption->text.isEmpty() ) iconRect = centerRect( contentsRect, iconSize, iconSize ); else { iconRect = contentsRect; iconRect.setWidth( iconSize ); iconRect = centerRect( iconRect, iconSize, iconSize ); contentsRect.setLeft( iconRect.right() + Metrics::ToolBox_TabItemSpacing + 1 ); } iconRect = visualRect( option, iconRect ); const QIcon::Mode mode( enabled ? QIcon::Normal : QIcon::Disabled ); const QPixmap pixmap( toolBoxOption->icon.pixmap( iconSize, mode ) ); drawItemPixmap( painter, iconRect, textFlags, pixmap ); } // render text if( !toolBoxOption->text.isEmpty() ) { contentsRect = visualRect( option, contentsRect ); drawItemText( painter, contentsRect, textFlags, palette, enabled, toolBoxOption->text, QPalette::WindowText ); } return true; } //___________________________________________________________________________________ bool Style::drawToolBoxTabShapeControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto toolBoxOption( qstyleoption_cast( option ) ); if( !toolBoxOption ) return true; // copy rect and palette const auto& rect( option->rect ); const auto tabRect( toolBoxTabContentsRect( option, widget ) ); /* * important: option returns the wrong palette. * we use the widget palette instead, when set */ const auto& palette( widget ? widget->palette() : option->palette ); // store flags const State& flags( option->state ); const bool enabled( flags&State_Enabled ); const bool selected( flags&State_Selected ); const bool mouseOver( enabled && !selected && ( flags&State_MouseOver ) ); // update animation state /* * the proper widget ( the toolbox tab ) is not passed as argument by Qt. * What is passed is the toolbox directly. To implement animations properly, *the painter->device() is used instead */ bool isAnimated( false ); qreal opacity( AnimationData::OpacityInvalid ); QPaintDevice* device = painter->device(); if( enabled && device ) { _animations->toolBoxEngine().updateState( device, mouseOver ); isAnimated = _animations->toolBoxEngine().isAnimated( device ); opacity = _animations->toolBoxEngine().opacity( device ); } // color QColor outline; if( selected ) outline = _helper->focusColor( palette ); else outline = _helper->frameOutlineColor( palette, mouseOver, false, opacity, isAnimated ? AnimationHover:AnimationNone ); // render _helper->renderToolBoxFrame( painter, rect, tabRect.width(), outline ); return true; } //___________________________________________________________________________________ bool Style::drawDockWidgetTitleControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto dockWidgetOption = qstyleoption_cast( option ); if( !dockWidgetOption ) return true; const auto& palette( option->palette ); const auto& state( option->state ); const bool enabled( state & State_Enabled ); const bool reverseLayout( option->direction == Qt::RightToLeft ); // cast to v2 to check vertical bar const auto v2 = qstyleoption_cast( option ); const bool verticalTitleBar( v2 ? v2->verticalTitleBar : false ); const auto buttonRect( subElementRect( dockWidgetOption->floatable ? SE_DockWidgetFloatButton : SE_DockWidgetCloseButton, option, widget ) ); // get rectangle and adjust to properly accounts for buttons auto rect( insideMargin( dockWidgetOption->rect, Metrics::Frame_FrameWidth ) ); if( verticalTitleBar ) { if( buttonRect.isValid() ) rect.setTop( buttonRect.bottom() + 1 ); } else if( reverseLayout ) { if( buttonRect.isValid() ) rect.setLeft( buttonRect.right() + 1 ); rect.adjust( 0, 0, -4, 0 ); } else { if( buttonRect.isValid() ) rect.setRight( buttonRect.left() - 1 ); rect.adjust( 4, 0, 0, 0 ); } QString title( dockWidgetOption->title ); int titleWidth = dockWidgetOption->fontMetrics.size( _mnemonics->textFlags(), title ).width(); int width = verticalTitleBar ? rect.height() : rect.width(); if( width < titleWidth ) title = dockWidgetOption->fontMetrics.elidedText( title, Qt::ElideRight, width, Qt::TextShowMnemonic ); if( verticalTitleBar ) { QSize size = rect.size(); size.transpose(); rect.setSize( size ); painter->save(); painter->translate( rect.left(), rect.top() + rect.width() ); painter->rotate( -90 ); painter->translate( -rect.left(), -rect.top() ); drawItemText( painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText ); painter->restore(); } else { drawItemText( painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText ); } return true; } //______________________________________________________________ bool Style::drawGroupBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { // base class method ParentStyleClass::drawComplexControl( CC_GroupBox, option, painter, widget ); // cast option and check const auto groupBoxOption = qstyleoption_cast( option ); if( !groupBoxOption ) return true; // do nothing if either label is not selected or groupbox is empty if( !(option->subControls & QStyle::SC_GroupBoxLabel) || groupBoxOption->text.isEmpty() ) { return true; } // store palette and rect const auto& palette( option->palette ); // check focus state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool hasFocus( enabled && (option->state & State_HasFocus) ); if( !hasFocus ) return true; // alignment const int textFlags( groupBoxOption->textAlignment | _mnemonics->textFlags() ); // update animation state _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); const bool isFocusAnimated( _animations->widgetStateEngine().isAnimated( widget, AnimationFocus ) ); const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationFocus ) ); // get relevant rect auto textRect = subControlRect( CC_GroupBox, option, SC_GroupBoxLabel, widget ); textRect = option->fontMetrics.boundingRect( textRect, textFlags, groupBoxOption->text ); // focus color QColor focusColor; if( isFocusAnimated ) focusColor = _helper->alphaColor( _helper->focusColor( palette ), opacity ); else if( hasFocus ) focusColor = _helper->focusColor( palette ); // render focus _helper->renderFocusLine( painter, textRect, focusColor ); return true; } //______________________________________________________________ bool Style::drawToolButtonComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto toolButtonOption( qstyleoption_cast( option ) ); if( !toolButtonOption ) return true; // need to alter palette for focused buttons const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && (option->state & State_MouseOver) ); const bool hasFocus( enabled && (option->state & State_HasFocus) ); const bool sunken( state & (State_On | State_Sunken) ); const bool flat( state & State_AutoRaise ); // update animation state // mouse over takes precedence over focus _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); // detect buttons in tabbar, for which special rendering is needed const bool inTabBar( widget && qobject_cast( widget->parentWidget() ) ); const bool isMenuTitle( this->isMenuTitle( widget ) ); if( isMenuTitle ) { // copy option to adust state, and set font as not-bold QStyleOptionToolButton copy( *toolButtonOption ); copy.font.setBold( false ); copy.state = State_Enabled; // render renderMenuTitle( ©, painter, widget ); return true; } // copy option and alter palette QStyleOptionToolButton copy( *toolButtonOption ); const bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); const bool hasInlineIndicator( toolButtonOption->features&QStyleOptionToolButton::HasMenu && toolButtonOption->features&QStyleOptionToolButton::PopupDelay && !hasPopupMenu ); const auto buttonRect( subControlRect( CC_ToolButton, option, SC_ToolButton, widget ) ); const auto menuRect( subControlRect( CC_ToolButton, option, SC_ToolButtonMenu, widget ) ); // frame if( toolButtonOption->subControls & SC_ToolButton ) { copy.rect = buttonRect; if( inTabBar ) drawTabBarPanelButtonToolPrimitive( ©, painter, widget ); else drawPrimitive( PE_PanelButtonTool, ©, painter, widget); } // arrow if( hasPopupMenu ) { copy.rect = menuRect; if( !flat ) drawPrimitive( PE_IndicatorButtonDropDown, ©, painter, widget ); if( sunken && !flat ) copy.rect.translate( 1, 1 ); drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); } else if( hasInlineIndicator ) { copy.rect = menuRect; if( sunken && !flat ) copy.rect.translate( 1, 1 ); drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); } // contents { // restore state copy.state = state; // define contents rect auto contentsRect( buttonRect ); // detect dock widget title button // for dockwidget title buttons, do not take out margins, so that icon do not get scaled down const bool isDockWidgetTitleButton( widget && widget->inherits( "QDockWidgetTitleButton" ) ); if( isDockWidgetTitleButton ) { // cast to abstract button // adjust state to have correct icon rendered const auto button( qobject_cast( widget ) ); if( button->isChecked() || button->isDown() ) copy.state |= State_On; } else if( !inTabBar && hasInlineIndicator ) { const int marginWidth( flat ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); contentsRect = insideMargin( contentsRect, marginWidth, 0 ); contentsRect.setRight( contentsRect.right() - Metrics::ToolButton_InlineIndicatorWidth ); contentsRect = visualRect( option, contentsRect ); } copy.rect = contentsRect; // render drawControl( CE_ToolButtonLabel, ©, painter, widget); } return true; } //______________________________________________________________ bool Style::drawComboBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto comboBoxOption( qstyleoption_cast( option ) ); if( !comboBoxOption ) return true; // rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool hasFocus( enabled && ( state & (State_HasFocus | State_Sunken ) ) ); const bool editable( comboBoxOption->editable ); const bool sunken( state & (State_On|State_Sunken) ); bool flat( !comboBoxOption->frame ); // frame if( option->subControls & SC_ComboBoxFrame ) { if( editable ) { flat |= ( rect.height() <= 2*Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth ); if( flat ) { const auto background( palette.color( QPalette::Base ) ); painter->setBrush( background ); painter->setPen( Qt::NoPen ); painter->drawRect( rect ); } else { drawPrimitive( PE_FrameLineEdit, option, painter, widget ); } } else { // update animation state // hover takes precedence over focus _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver ); _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); const AnimationMode mode( _animations->inputWidgetEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->inputWidgetEngine().buttonOpacity( widget ) ); if( flat ) { // define colors and render const auto color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); _helper->renderToolButtonFrame( painter, rect, color, sunken ); } else { // define colors const auto shadow( _helper->shadowColor( palette ) ); const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, false, opacity, mode ) ); // render _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken ); } } } // arrow if( option->subControls & SC_ComboBoxArrow ) { // detect empty comboboxes const auto comboBox = qobject_cast( widget ); const bool empty( comboBox && !comboBox->count() ); // arrow color QColor arrowColor; if( editable ) { if( empty || !enabled ) arrowColor = palette.color( QPalette::Disabled, QPalette::Text ); else { // check animation state const bool subControlHover( enabled && mouseOver && comboBoxOption->activeSubControls&SC_ComboBoxArrow ); _animations->comboBoxEngine().updateState( widget, AnimationHover, subControlHover ); const bool animated( enabled && _animations->comboBoxEngine().isAnimated( widget, AnimationHover ) ); const qreal opacity( _animations->comboBoxEngine().opacity( widget, AnimationHover ) ); // color const auto normal( _helper->arrowColor( palette, QPalette::WindowText ) ); const auto hover( _helper->hoverColor( palette ) ); if( animated ) { arrowColor = KColorUtils::mix( normal, hover, opacity ); } else if( subControlHover ) { arrowColor = hover; } else arrowColor = normal; } } else if( flat ) { if( empty || !enabled ) arrowColor = _helper->arrowColor( palette, QPalette::Disabled, QPalette::WindowText ); else if( hasFocus && !mouseOver && sunken ) arrowColor = palette.color( QPalette::HighlightedText ); else arrowColor = _helper->arrowColor( palette, QPalette::WindowText ); } else if( empty || !enabled ) arrowColor = _helper->arrowColor( palette, QPalette::Disabled, QPalette::ButtonText ); else if( hasFocus && !mouseOver ) arrowColor = palette.color( QPalette::HighlightedText ); else arrowColor = _helper->arrowColor( palette, QPalette::ButtonText ); // arrow rect auto arrowRect( subControlRect( CC_ComboBox, option, SC_ComboBoxArrow, widget ) ); // translate for non editable, non flat, sunken comboboxes if( sunken && !flat && !editable ) arrowRect.translate( 1, 1 ); // render _helper->renderArrow( painter, arrowRect, arrowColor, ArrowDown ); } return true; } //______________________________________________________________ bool Style::drawSpinBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { const auto spinBoxOption( qstyleoption_cast( option ) ); if( !spinBoxOption ) return true; // store palette and rect const auto& palette( option->palette ); const auto& rect( option->rect ); if( option->subControls & SC_SpinBoxFrame ) { // detect flat spinboxes bool flat( !spinBoxOption->frame ); flat |= ( rect.height() < 2*Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth ); if( flat ) { const auto background( palette.color( QPalette::Base ) ); painter->setBrush( background ); painter->setPen( Qt::NoPen ); painter->drawRect( rect ); } else { drawPrimitive( PE_FrameLineEdit, option, painter, widget ); } } if( option->subControls & SC_SpinBoxUp ) renderSpinBoxArrow( SC_SpinBoxUp, spinBoxOption, painter, widget ); if( option->subControls & SC_SpinBoxDown ) renderSpinBoxArrow( SC_SpinBoxDown, spinBoxOption, painter, widget ); return true; } //______________________________________________________________ bool Style::drawSliderComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return true; // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // copy state const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool hasFocus( enabled && ( state & State_HasFocus ) ); // direction const bool horizontal( sliderOption->orientation == Qt::Horizontal ); // tickmarks if( StyleConfigData::sliderDrawTickMarks() && ( sliderOption->subControls & SC_SliderTickmarks ) ) { const bool upsideDown( sliderOption->upsideDown ); const int tickPosition( sliderOption->tickPosition ); const int available( pixelMetric( PM_SliderSpaceAvailable, option, widget ) ); int interval = sliderOption->tickInterval; if( interval < 1 ) interval = sliderOption->pageStep; if( interval >= 1 ) { const int fudge( pixelMetric( PM_SliderLength, option, widget ) / 2 ); int current( sliderOption->minimum ); // store tick lines const auto grooveRect( subControlRect( CC_Slider, sliderOption, SC_SliderGroove, widget ) ); QList tickLines; if( horizontal ) { if( tickPosition & QSlider::TicksAbove ) tickLines.append( QLine( rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength ) ); if( tickPosition & QSlider::TicksBelow ) tickLines.append( QLine( rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength ) ); } else { if( tickPosition & QSlider::TicksAbove ) tickLines.append( QLine( grooveRect.left() - Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.left() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength, rect.top() ) ); if( tickPosition & QSlider::TicksBelow ) tickLines.append( QLine( grooveRect.right() + Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.right() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength, rect.top() ) ); } // colors const auto base( _helper->separatorColor( palette ) ); const auto highlight( palette.color( QPalette::Highlight ) ); while( current <= sliderOption->maximum ) { // adjust color const auto color( (enabled && current <= sliderOption->sliderPosition) ? highlight:base ); painter->setPen( color ); // calculate positions and draw lines int position( sliderPositionFromValue( sliderOption->minimum, sliderOption->maximum, current, available ) + fudge ); foreach( const QLine& tickLine, tickLines ) { if( horizontal ) painter->drawLine( tickLine.translated( upsideDown ? (rect.width() - position) : position, 0 ) ); else painter->drawLine( tickLine.translated( 0, upsideDown ? (rect.height() - position):position ) ); } // go to next position current += interval; } } } // groove if( sliderOption->subControls & SC_SliderGroove ) { // retrieve groove rect auto grooveRect( subControlRect( CC_Slider, sliderOption, SC_SliderGroove, widget ) ); // base color const auto grooveColor( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.3 ) ); if( !enabled ) _helper->renderSliderGroove( painter, grooveRect, grooveColor ); else { const bool upsideDown( sliderOption->upsideDown ); // handle rect auto handleRect( subControlRect( CC_Slider, sliderOption, SC_SliderHandle, widget ) ); // highlight color const auto highlight( palette.color( QPalette::Highlight ) ); if( sliderOption->orientation == Qt::Horizontal ) { auto leftRect( grooveRect ); leftRect.setRight( handleRect.right() - Metrics::Slider_ControlThickness/2 ); _helper->renderSliderGroove( painter, leftRect, upsideDown ? grooveColor:highlight ); auto rightRect( grooveRect ); rightRect.setLeft( handleRect.left() + Metrics::Slider_ControlThickness/2 ); _helper->renderSliderGroove( painter, rightRect, upsideDown ? highlight:grooveColor ); } else { auto topRect( grooveRect ); topRect.setBottom( handleRect.bottom() - Metrics::Slider_ControlThickness/2 ); _helper->renderSliderGroove( painter, topRect, upsideDown ? grooveColor:highlight ); auto bottomRect( grooveRect ); bottomRect.setTop( handleRect.top() + Metrics::Slider_ControlThickness/2 ); _helper->renderSliderGroove( painter, bottomRect, upsideDown ? highlight:grooveColor ); } } } // handle if( sliderOption->subControls & SC_SliderHandle ) { // get rect and center auto handleRect( subControlRect( CC_Slider, sliderOption, SC_SliderHandle, widget ) ); // handle state const bool handleActive( sliderOption->activeSubControls & SC_SliderHandle ); const bool sunken( state & (State_On|State_Sunken) ); // animation state _animations->widgetStateEngine().updateState( widget, AnimationHover, handleActive && mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); // define colors const auto background( palette.color( QPalette::Button ) ); const auto outline( _helper->sliderOutlineColor( palette, handleActive && mouseOver, hasFocus, opacity, mode ) ); const auto shadow( _helper->shadowColor( palette ) ); // render _helper->renderSliderHandle( painter, handleRect, background, outline, shadow, sunken ); } return true; } //______________________________________________________________ bool Style::drawDialComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto sliderOption( qstyleoption_cast( option ) ); if( !sliderOption ) return true; const auto& palette( option->palette ); const State& state( option->state ); const bool enabled( state & State_Enabled ); const bool mouseOver( enabled && ( state & State_MouseOver ) ); const bool hasFocus( enabled && ( state & State_HasFocus ) ); // do not render tickmarks if( sliderOption->subControls & SC_DialTickmarks ) {} // groove if( sliderOption->subControls & SC_DialGroove ) { // groove rect auto grooveRect( subControlRect( CC_Dial, sliderOption, SC_SliderGroove, widget ) ); // groove const auto grooveColor( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.3 ) ); // render groove _helper->renderDialGroove( painter, grooveRect, grooveColor ); if( enabled ) { // highlight const auto highlight( palette.color( QPalette::Highlight ) ); // angles const qreal first( dialAngle( sliderOption, sliderOption->minimum ) ); const qreal second( dialAngle( sliderOption, sliderOption->sliderPosition ) ); // render contents _helper->renderDialContents( painter, grooveRect, highlight, first, second ); } } // handle if( sliderOption->subControls & SC_DialHandle ) { // get handle rect auto handleRect( subControlRect( CC_Dial, sliderOption, SC_DialHandle, widget ) ); handleRect = centerRect( handleRect, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness ); // handle state const bool handleActive( mouseOver && handleRect.contains( _animations->dialEngine().position( widget ) ) ); const bool sunken( state & (State_On|State_Sunken) ); // animation state _animations->dialEngine().setHandleRect( widget, handleRect ); _animations->dialEngine().updateState( widget, AnimationHover, handleActive && mouseOver ); _animations->dialEngine().updateState( widget, AnimationFocus, hasFocus ); const auto mode( _animations->dialEngine().buttonAnimationMode( widget ) ); const qreal opacity( _animations->dialEngine().buttonOpacity( widget ) ); // define colors const auto background( palette.color( QPalette::Button ) ); const auto outline( _helper->sliderOutlineColor( palette, handleActive && mouseOver, hasFocus, opacity, mode ) ); const auto shadow( _helper->shadowColor( palette ) ); // render _helper->renderSliderHandle( painter, handleRect, background, outline, shadow, sunken ); } return true; } //______________________________________________________________ bool Style::drawScrollBarComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { //the animation for QStyle::SC_ScrollBarGroove is special: it will animate //the opacity of everything else as well, included slider and arrows qreal opacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); const bool animated( StyleConfigData::animationsEnabled() && _animations->scrollBarEngine().isAnimated( widget, AnimationHover, QStyle::SC_ScrollBarGroove ) ); const bool mouseOver( option->state & State_MouseOver ); if( opacity == AnimationData::OpacityInvalid ) opacity = 1; // render full groove directly, rather than using the addPage and subPage control element methods if( (!StyleConfigData::animationsEnabled() || mouseOver || animated) && option->subControls & SC_ScrollBarGroove ) { // retrieve groove rectangle auto grooveRect( subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); const auto& palette( option->palette ); const auto color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.3 * (animated ? opacity : 1) ) ); const auto& state( option->state ); const bool horizontal( state & State_Horizontal ); if( horizontal ) grooveRect = centerRect( grooveRect, grooveRect.width(), Metrics::ScrollBar_SliderWidth ); else grooveRect = centerRect( grooveRect, Metrics::ScrollBar_SliderWidth, grooveRect.height() ); // render _helper->renderScrollBarGroove( painter, grooveRect, color ); } // call base class primitive ParentStyleClass::drawComplexControl( CC_ScrollBar, option, painter, widget ); return true; } //______________________________________________________________ bool Style::drawTitleBarComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { // cast option and check const auto titleBarOption( qstyleoption_cast( option ) ); if( !titleBarOption ) return true; // store palette and rect auto palette( option->palette ); const auto& rect( option->rect ); const State& flags( option->state ); const bool enabled( flags & State_Enabled ); const bool active( enabled && ( titleBarOption->titleBarState & Qt::WindowActive ) ); if( titleBarOption->subControls & SC_TitleBarLabel ) { // render background painter->setClipRect( rect ); const auto outline( active ? QColor():_helper->frameOutlineColor( palette, false, false ) ); const auto background( _helper->titleBarColor( active ) ); _helper->renderTabWidgetFrame( painter, rect.adjusted( -1, -1, 1, 3 ), background, outline, CornersTop ); const bool useSeparator( active && _helper->titleBarColor( active ) != palette.color( QPalette::Window ) && !( titleBarOption->titleBarState & Qt::WindowMinimized ) ); if( useSeparator ) { painter->setRenderHint( QPainter::Antialiasing, false ); painter->setBrush( Qt::NoBrush ); painter->setPen( palette.color( QPalette::Highlight ) ); painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); } // render text palette.setColor( QPalette::WindowText, _helper->titleBarTextColor( active ) ); const auto textRect( subControlRect( CC_TitleBar, option, SC_TitleBarLabel, widget ) ); ParentStyleClass::drawItemText( painter, textRect, Qt::AlignCenter, palette, active, titleBarOption->text, QPalette::WindowText ); } // buttons static const QList subControls = { SC_TitleBarMinButton, SC_TitleBarMaxButton, SC_TitleBarCloseButton, SC_TitleBarNormalButton, SC_TitleBarSysMenu }; // loop over supported buttons foreach( const SubControl& subControl, subControls ) { // skip if not requested if( !( titleBarOption->subControls & subControl ) ) continue; // find matching icon QIcon icon; switch( subControl ) { case SC_TitleBarMinButton: icon = standardIcon( SP_TitleBarMinButton, option, widget ); break; case SC_TitleBarMaxButton: icon = standardIcon( SP_TitleBarMaxButton, option, widget ); break; case SC_TitleBarCloseButton: icon = standardIcon( SP_TitleBarCloseButton, option, widget ); break; case SC_TitleBarNormalButton: icon = standardIcon( SP_TitleBarNormalButton, option, widget ); break; case SC_TitleBarSysMenu: icon = titleBarOption->icon; break; default: break; } // check icon if( icon.isNull() ) continue; // define icon rect auto iconRect( subControlRect( CC_TitleBar, option, subControl, widget ) ); if( iconRect.isEmpty() ) continue; // active state const bool subControlActive( titleBarOption->activeSubControls & subControl ); // mouse over state const bool mouseOver( !subControlActive && widget && iconRect.translated( widget->mapToGlobal( QPoint( 0,0 ) ) ).contains( QCursor::pos() ) ); // adjust iconRect const int iconWidth( pixelMetric( PM_SmallIconSize, option, widget ) ); const QSize iconSize( iconWidth, iconWidth ); iconRect = centerRect( iconRect, iconSize ); // set icon mode and state QIcon::Mode iconMode; QIcon::State iconState; if( !enabled ) { iconMode = QIcon::Disabled; iconState = QIcon::Off; } else { if( mouseOver ) iconMode = QIcon::Active; else if( active ) iconMode = QIcon::Selected; else iconMode = QIcon::Normal; iconState = subControlActive ? QIcon::On : QIcon::Off; } // get pixmap and render const QPixmap pixmap = icon.pixmap( iconSize, iconMode, iconState ); painter->drawPixmap( iconRect, pixmap ); } return true; } //____________________________________________________________________________________________________ void Style::renderSpinBoxArrow( const SubControl& subControl, const QStyleOptionSpinBox* option, QPainter* painter, const QWidget* widget ) const { const auto& palette( option->palette ); const State& state( option->state ); // enable state bool enabled( state & State_Enabled ); // check steps enable step const bool atLimit( (subControl == SC_SpinBoxUp && !(option->stepEnabled & QAbstractSpinBox::StepUpEnabled )) || (subControl == SC_SpinBoxDown && !(option->stepEnabled & QAbstractSpinBox::StepDownEnabled ) ) ); // update enabled state accordingly enabled &= !atLimit; // update mouse-over effect const bool mouseOver( enabled && ( state & State_MouseOver ) ); // check animation state const bool subControlHover( enabled && mouseOver && ( option->activeSubControls & subControl ) ); _animations->spinBoxEngine().updateState( widget, subControl, subControlHover ); const bool animated( enabled && _animations->spinBoxEngine().isAnimated( widget, subControl ) ); const qreal opacity( _animations->spinBoxEngine().opacity( widget, subControl ) ); auto color = _helper->arrowColor( palette, QPalette::Text ); if( animated ) { auto highlight = _helper->hoverColor( palette ); color = KColorUtils::mix( color, highlight, opacity ); } else if( subControlHover ) { color = _helper->hoverColor( palette ); } else if( atLimit ) { color = _helper->arrowColor( palette, QPalette::Disabled, QPalette::Text ); } // arrow orientation ArrowOrientation orientation( ( subControl == SC_SpinBoxUp ) ? ArrowUp:ArrowDown ); // arrow rect const auto arrowRect( subControlRect( CC_SpinBox, option, subControl, widget ) ); // render _helper->renderArrow( painter, arrowRect, color, orientation ); return; } //______________________________________________________________________________ void Style::renderMenuTitle( const QStyleOptionToolButton* option, QPainter* painter, const QWidget* ) const { // render a separator at the bottom const auto& palette( option->palette ); const auto color( _helper->separatorColor( palette ) ); _helper->renderSeparator( painter, QRect( option->rect.bottomLeft()-QPoint( 0, Metrics::MenuItem_MarginHeight), QSize( option->rect.width(), 1 ) ), color ); // render text in the center of the rect // icon is discarded on purpose painter->setFont( option->font ); const auto contentsRect = insideMargin( option->rect, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ); drawItemText( painter, contentsRect, Qt::AlignCenter, palette, true, option->text, QPalette::WindowText ); } //______________________________________________________________________________ qreal Style::dialAngle( const QStyleOptionSlider* sliderOption, int value ) const { // calculate angle at which handle needs to be drawn qreal angle( 0 ); if( sliderOption->maximum == sliderOption->minimum ) angle = M_PI / 2; else { qreal fraction( qreal( value - sliderOption->minimum )/qreal( sliderOption->maximum - sliderOption->minimum ) ); if( !sliderOption->upsideDown ) fraction = 1 - fraction; if( sliderOption->dialWrapping ) angle = 1.5*M_PI - fraction*2*M_PI; else angle = ( M_PI*8 - fraction*10*M_PI )/6; } return angle; } //______________________________________________________________________________ const QWidget* Style::scrollBarParent( const QWidget* widget ) const { // check widget and parent if( !(widget && widget->parentWidget() ) ) return nullptr; // try cast to scroll area. Must test both parent and grandparent QAbstractScrollArea* scrollArea; if( !(scrollArea = qobject_cast( widget->parentWidget() ) ) ) { scrollArea = qobject_cast( widget->parentWidget()->parentWidget() ); } // check scrollarea if( scrollArea && (widget == scrollArea->verticalScrollBar() || widget == scrollArea->horizontalScrollBar() ) ) { return scrollArea; } else if( widget->parentWidget()->inherits( "KTextEditor::View" ) ) { return widget->parentWidget(); } else return nullptr; } //______________________________________________________________________________ QColor Style::scrollBarArrowColor( const QStyleOptionSlider* option, const SubControl& control, const QWidget* widget ) const { const auto& rect( option->rect ); const auto& palette( option->palette ); auto color( _helper->arrowColor( palette, QPalette::WindowText ) ); bool widgetMouseOver( ( option->state & State_MouseOver ) ); if( widget ) widgetMouseOver = widget->underMouse(); #if QT_VERSION >= 0x050000 // in case this QStyle is used by QQuickControls QStyle wrapper else if( option->styleObject ) widgetMouseOver = option->styleObject->property("hover").toBool(); #endif // check enabled state const bool enabled( option->state & State_Enabled ); if( !enabled ) { if( StyleConfigData::animationsEnabled() ) { // finally, global opacity when ScrollBarShowOnMouseOver const qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); // no mouse over and no animation in progress, don't draw arrows at all else if( !widgetMouseOver ) return Qt::transparent; } return color; } if( ( control == SC_ScrollBarSubLine && option->sliderValue == option->minimum ) || ( control == SC_ScrollBarAddLine && option->sliderValue == option->maximum ) ) { // manually disable arrow, to indicate that scrollbar is at limit color = _helper->arrowColor( palette, QPalette::Disabled, QPalette::WindowText ); if( StyleConfigData::animationsEnabled() ) { // finally, global opacity when ScrollBarShowOnMouseOver const qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); // no mouse over and no animation in progress, don't draw arrows at all else if( !widgetMouseOver ) return Qt::transparent; } return color; } const bool mouseOver( _animations->scrollBarEngine().isHovered( widget, control ) ); const bool animated( _animations->scrollBarEngine().isAnimated( widget, AnimationHover, control ) ); const qreal opacity( _animations->scrollBarEngine().opacity( widget, control ) ); // retrieve mouse position from engine QPoint position( mouseOver ? _animations->scrollBarEngine().position( widget ) : QPoint( -1, -1 ) ); if( mouseOver && rect.contains( position ) ) { /* * need to update the arrow controlRect on fly because there is no * way to get it from the styles directly, outside of repaint events */ _animations->scrollBarEngine().setSubControlRect( widget, control, rect ); } if( rect.intersects( _animations->scrollBarEngine().subControlRect( widget, control ) ) ) { auto highlight = _helper->hoverColor( palette ); if( animated ) { color = KColorUtils::mix( color, highlight, opacity ); } else if( mouseOver ) { color = highlight; } } if( StyleConfigData::animationsEnabled() ) { // finally, global opacity when ScrollBarShowOnMouseOver const qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); // no mouse over and no animation in progress, don't draw arrows at all else if( !widgetMouseOver ) return Qt::transparent; } return color; } //____________________________________________________________________________________ void Style::setTranslucentBackground( QWidget* widget ) const { widget->setAttribute( Qt::WA_TranslucentBackground ); #ifdef Q_WS_WIN // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly widget->setWindowFlags( widget->windowFlags() | Qt::FramelessWindowHint ); #endif } //____________________________________________________________________________________ QStyleOptionToolButton Style::separatorMenuItemOption( const QStyleOptionMenuItem* menuItemOption, const QWidget* widget ) const { // separator can have a title and an icon // in that case they are rendered as sunken flat toolbuttons QStyleOptionToolButton toolButtonOption; toolButtonOption.initFrom( widget ); toolButtonOption.rect = menuItemOption->rect; toolButtonOption.features = QStyleOptionToolButton::None; toolButtonOption.state = State_Enabled|State_AutoRaise; toolButtonOption.subControls = SC_ToolButton; toolButtonOption.icon = QIcon(); toolButtonOption.iconSize = QSize(); toolButtonOption.text = menuItemOption->text; toolButtonOption.toolButtonStyle = Qt::ToolButtonTextBesideIcon; return toolButtonOption; } //____________________________________________________________________________________ QIcon Style::toolBarExtensionIcon( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const { // store palette // due to Qt, it is not always safe to assume that either option, nor widget are defined QPalette palette; if( option ) palette = option->palette; else if( widget ) palette = widget->palette(); else palette = QApplication::palette(); // convenience class to map color to icon mode struct IconData { QColor _color; QIcon::Mode _mode; QIcon::State _state; }; // map colors to icon states const QList iconTypes = { { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Normal, QIcon::Off }, { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Selected, QIcon::Off }, { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Active, QIcon::Off }, { palette.color( QPalette::Disabled, QPalette::WindowText ), QIcon::Disabled, QIcon::Off }, { palette.color( QPalette::Active, QPalette::HighlightedText ), QIcon::Normal, QIcon::On }, { palette.color( QPalette::Active, QPalette::HighlightedText ), QIcon::Selected, QIcon::On }, { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Active, QIcon::On }, { palette.color( QPalette::Disabled, QPalette::WindowText ), QIcon::Disabled, QIcon::On } }; // default icon sizes static const QList iconSizes = { 8, 16, 22, 32, 48 }; // decide arrow orientation const ArrowOrientation orientation( standardPixmap == SP_ToolBarHorizontalExtensionButton ? ArrowRight : ArrowDown ); // create icon and fill QIcon icon; foreach( const IconData& iconData, iconTypes ) { foreach( const int& iconSize, iconSizes ) { // create pixmap QPixmap pixmap( iconSize, iconSize ); pixmap.fill( Qt::transparent ); // render QPainter painter( &pixmap ); // icon size const int fixedIconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); const QRect fixedRect( 0, 0, fixedIconSize, fixedIconSize ); painter.setWindow( fixedRect ); painter.translate( standardPixmap == SP_ToolBarHorizontalExtensionButton ? QPoint( 1, 0 ) : QPoint( 0, 1 ) ); _helper->renderArrow( &painter, fixedRect, iconData._color, orientation ); painter.end(); // add to icon icon.addPixmap( pixmap, iconData._mode, iconData._state ); } } return icon; } //____________________________________________________________________________________ QIcon Style::titleBarButtonIcon( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const { // map standardPixmap to button type ButtonType buttonType; switch( standardPixmap ) { case SP_TitleBarNormalButton: buttonType = ButtonRestore; break; case SP_TitleBarMinButton: buttonType = ButtonMinimize; break; case SP_TitleBarMaxButton: buttonType = ButtonMaximize; break; case SP_TitleBarCloseButton: case SP_DockWidgetCloseButton: buttonType = ButtonClose; break; default: return QIcon(); } // store palette // due to Qt, it is not always safe to assume that either option, nor widget are defined QPalette palette; if( option ) palette = option->palette; else if( widget ) palette = widget->palette(); else palette = QApplication::palette(); const bool isCloseButton( buttonType == ButtonClose && StyleConfigData::outlineCloseButton() ); palette.setCurrentColorGroup( QPalette::Active ); const auto base( palette.color( QPalette::WindowText ) ); const auto selected( palette.color( QPalette::HighlightedText ) ); const auto negative( buttonType == ButtonClose ? _helper->negativeText( palette ):base ); const auto negativeSelected( buttonType == ButtonClose ? _helper->negativeText( palette ):selected ); const bool invertNormalState( isCloseButton ); // convenience class to map color to icon mode struct IconData { QColor _color; bool _inverted; QIcon::Mode _mode; QIcon::State _state; }; // map colors to icon states const QList iconTypes = { // state off icons { KColorUtils::mix( palette.color( QPalette::Window ), base, 0.5 ), invertNormalState, QIcon::Normal, QIcon::Off }, { KColorUtils::mix( palette.color( QPalette::Window ), selected, 0.5 ), invertNormalState, QIcon::Selected, QIcon::Off }, { KColorUtils::mix( palette.color( QPalette::Window ), negative, 0.5 ), true, QIcon::Active, QIcon::Off }, { KColorUtils::mix( palette.color( QPalette::Window ), base, 0.2 ), invertNormalState, QIcon::Disabled, QIcon::Off }, // state on icons { KColorUtils::mix( palette.color( QPalette::Window ), negative, 0.7 ), true, QIcon::Normal, QIcon::On }, { KColorUtils::mix( palette.color( QPalette::Window ), negativeSelected, 0.7 ), true, QIcon::Selected, QIcon::On }, { KColorUtils::mix( palette.color( QPalette::Window ), negative, 0.7 ), true, QIcon::Active, QIcon::On }, { KColorUtils::mix( palette.color( QPalette::Window ), base, 0.2 ), invertNormalState, QIcon::Disabled, QIcon::On } }; // default icon sizes static const QList iconSizes = { 8, 16, 22, 32, 48 }; // output icon QIcon icon; foreach( const IconData& iconData, iconTypes ) { foreach( const int& iconSize, iconSizes ) { // create pixmap QPixmap pixmap( iconSize, iconSize ); pixmap.fill( Qt::transparent ); // create painter and render QPainter painter( &pixmap ); _helper->renderDecorationButton( &painter, pixmap.rect(), iconData._color, buttonType, iconData._inverted ); painter.end(); // store icon.addPixmap( pixmap, iconData._mode, iconData._state ); } } return icon; } //______________________________________________________________________________ const QAbstractItemView* Style::itemViewParent( const QWidget* widget ) const { const QAbstractItemView* itemView( nullptr ); // check widget directly if( ( itemView = qobject_cast( widget ) ) ) return itemView; // check widget grand-parent else if( widget && widget->parentWidget() && ( itemView = qobject_cast( widget->parentWidget()->parentWidget() ) ) && itemView->viewport() == widget->parentWidget() ) { return itemView; } // return null otherwise else return nullptr; } //____________________________________________________________________ bool Style::isSelectedItem( const QWidget* widget, const QPoint& localPosition ) const { // get relevant itemview parent and check const QAbstractItemView* itemView( itemViewParent( widget ) ); if( !( itemView && itemView->hasFocus() && itemView->selectionModel() ) ) return false; #if QT_VERSION >= 0x050000 QPoint position = widget->mapTo( itemView, localPosition ); #else // qt4 misses a const for mapTo argument, although nothing is actually changed to the passed widget QPoint position = widget->mapTo( const_cast( itemView ), localPosition ); #endif // get matching QModelIndex and check const QModelIndex index( itemView->indexAt( position ) ); if( !index.isValid() ) return false; // check whether index is selected return itemView->selectionModel()->isSelected( index ); } //____________________________________________________________________ bool Style::isQtQuickControl( const QStyleOption* option, const QWidget* widget ) const { #if QT_VERSION >= 0x050000 const bool is = (widget == nullptr) && option && option->styleObject && option->styleObject->inherits( "QQuickItem" ); if ( is ) _windowManager->registerQuickItem( static_cast( option->styleObject ) ); return is; #else Q_UNUSED( widget ); Q_UNUSED( option ); return false; #endif } //____________________________________________________________________ bool Style::showIconsInMenuItems() const { const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); return g.readEntry("ShowIconsInMenuItems", true); } //____________________________________________________________________ bool Style::showIconsOnPushButtons() const { const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); return g.readEntry("ShowIconsOnPushButtons", true); } //____________________________________________________________________ bool Style::isMenuTitle( const QWidget* widget ) const { // check widget if( !widget ) return false; // check property const QVariant property( widget->property( PropertyNames::menuTitle ) ); if( property.isValid() ) return property.toBool(); // detect menu toolbuttons QWidget* parent = widget->parentWidget(); if( qobject_cast( parent ) ) { foreach( auto child, parent->findChildren() ) { if( child->defaultWidget() != widget ) continue; const_cast(widget)->setProperty( PropertyNames::menuTitle, true ); return true; } } const_cast(widget)->setProperty( PropertyNames::menuTitle, false ); return false; } //____________________________________________________________________ bool Style::hasAlteredBackground( const QWidget* widget ) const { // check widget if( !widget ) return false; // check property const QVariant property( widget->property( PropertyNames::alteredBackground ) ); if( property.isValid() ) return property.toBool(); // check if widget is of relevant type bool hasAlteredBackground( false ); if( const auto groupBox = qobject_cast( widget ) ) hasAlteredBackground = !groupBox->isFlat(); else if( const auto tabWidget = qobject_cast( widget ) ) hasAlteredBackground = !tabWidget->documentMode(); else if( qobject_cast( widget ) ) hasAlteredBackground = true; else if( StyleConfigData::dockWidgetDrawFrame() && qobject_cast( widget ) ) hasAlteredBackground = true; if( widget->parentWidget() && !hasAlteredBackground ) hasAlteredBackground = this->hasAlteredBackground( widget->parentWidget() ); const_cast(widget)->setProperty( PropertyNames::alteredBackground, hasAlteredBackground ); return hasAlteredBackground; } } diff --git a/kstyle/breezestyleplugin.h b/kstyle/breezestyleplugin.h index d35d2e0d..b560b216 100644 --- a/kstyle/breezestyleplugin.h +++ b/kstyle/breezestyleplugin.h @@ -1,57 +1,57 @@ #ifndef breezestyleplugin_h #define breezestyleplugin_h /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include namespace Breeze { class StylePlugin : public QStylePlugin { Q_OBJECT #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "breeze.json" ) #endif public: //* constructor - explicit StylePlugin(QObject *parent = 0): + explicit StylePlugin(QObject *parent = nullptr): QStylePlugin(parent) {} //* destructor ~StylePlugin(); //* returns list of valid keys QStringList keys() const; //* create style QStyle* create( const QString& ); }; } #endif diff --git a/kstyle/config/breezestyleconfig.cpp b/kstyle/config/breezestyleconfig.cpp index 6fb5302a..9c699f3f 100644 --- a/kstyle/config/breezestyleconfig.cpp +++ b/kstyle/config/breezestyleconfig.cpp @@ -1,181 +1,181 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezestyleconfig.h" #include "../breeze.h" #include "../config-breeze.h" #include "breezestyleconfigdata.h" #include #include #if !BREEZE_USE_KDE4 #include #endif extern "C" { Q_DECL_EXPORT QWidget* allocate_kstyle_config(QWidget* parent) { return new Breeze::StyleConfig(parent); } } namespace Breeze { //__________________________________________________________________ StyleConfig::StyleConfig(QWidget* parent): QWidget(parent) { setupUi(this); // load setup from configData load(); connect( _tabBarDrawCenteredTabs, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _toolBarDrawItemSeparator, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _viewDrawFocusIndicator, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _dockWidgetDrawFrame, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _titleWidgetDrawFrame, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _sidePanelDrawFrame, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _menuItemDrawThinFocus, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _sliderDrawTickMarks, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _splitterProxyEnabled, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _mnemonicsMode, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _animationsEnabled, SIGNAL(toggled(bool)), SLOT(updateChanged()) ); connect( _animationsDuration, SIGNAL(valueChanged(int)), SLOT(updateChanged()) ); connect( _scrollBarAddLineButtons, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _scrollBarSubLineButtons, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _windowDragMode, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _menuOpacity, SIGNAL(valueChanged(int)), SLOT(updateChanged()) ); } //__________________________________________________________________ void StyleConfig::save() { StyleConfigData::setTabBarDrawCenteredTabs( _tabBarDrawCenteredTabs->isChecked() ); StyleConfigData::setToolBarDrawItemSeparator( _toolBarDrawItemSeparator->isChecked() ); StyleConfigData::setViewDrawFocusIndicator( _viewDrawFocusIndicator->isChecked() ); StyleConfigData::setDockWidgetDrawFrame( _dockWidgetDrawFrame->isChecked() ); StyleConfigData::setTitleWidgetDrawFrame( _titleWidgetDrawFrame->isChecked() ); StyleConfigData::setSidePanelDrawFrame( _sidePanelDrawFrame->isChecked() ); StyleConfigData::setMenuItemDrawStrongFocus( !_menuItemDrawThinFocus->isChecked() ); StyleConfigData::setSliderDrawTickMarks( _sliderDrawTickMarks->isChecked() ); StyleConfigData::setSplitterProxyEnabled( _splitterProxyEnabled->isChecked() ); StyleConfigData::setMnemonicsMode( _mnemonicsMode->currentIndex() ); StyleConfigData::setScrollBarAddLineButtons( _scrollBarAddLineButtons->currentIndex() ); StyleConfigData::setScrollBarSubLineButtons( _scrollBarSubLineButtons->currentIndex() ); StyleConfigData::setAnimationsEnabled( _animationsEnabled->isChecked() ); StyleConfigData::setAnimationsDuration( _animationsDuration->value() ); StyleConfigData::setWindowDragMode( _windowDragMode->currentIndex() ); StyleConfigData::setMenuOpacity( _menuOpacity->value() ); #if BREEZE_USE_KDE4 StyleConfigData::self()->writeConfig(); #else StyleConfigData::self()->save(); //update the KDE4 config to match Kdelibs4Migration migration; const QString kde4ConfigDirPath = migration.saveLocation("config"); - QScopedPointer kde4Config(StyleConfigData::self()->config()->copyTo(kde4ConfigDirPath+"/breezerc", 0)); + QScopedPointer kde4Config(StyleConfigData::self()->config()->copyTo(kde4ConfigDirPath+"/breezerc", nullptr)); kde4Config->sync(); #endif // emit dbus signal QDBusMessage message( QDBusMessage::createSignal( QStringLiteral( "/BreezeStyle" ), QStringLiteral( "org.kde.Breeze.Style" ), QStringLiteral( "reparseConfiguration" ) ) ); QDBusConnection::sessionBus().send(message); } //__________________________________________________________________ void StyleConfig::defaults() { StyleConfigData::self()->setDefaults(); load(); } //__________________________________________________________________ void StyleConfig::reset() { // reparse configuration #if BREEZE_USE_KDE4 StyleConfigData::self()->readConfig(); #else StyleConfigData::self()->load(); #endif load(); } //__________________________________________________________________ void StyleConfig::updateChanged() { bool modified( false ); // check if any value was modified if( _tabBarDrawCenteredTabs->isChecked() != StyleConfigData::tabBarDrawCenteredTabs() ) modified = true; else if( _toolBarDrawItemSeparator->isChecked() != StyleConfigData::toolBarDrawItemSeparator() ) modified = true; else if( _viewDrawFocusIndicator->isChecked() != StyleConfigData::viewDrawFocusIndicator() ) modified = true; else if( _dockWidgetDrawFrame->isChecked() != StyleConfigData::dockWidgetDrawFrame() ) modified = true; else if( _titleWidgetDrawFrame->isChecked() != StyleConfigData::titleWidgetDrawFrame() ) modified = true; else if( _sidePanelDrawFrame->isChecked() != StyleConfigData::sidePanelDrawFrame() ) modified = true; else if( _menuItemDrawThinFocus->isChecked() == StyleConfigData::menuItemDrawStrongFocus() ) modified = true; else if( _sliderDrawTickMarks->isChecked() != StyleConfigData::sliderDrawTickMarks() ) modified = true; else if( _mnemonicsMode->currentIndex() != StyleConfigData::mnemonicsMode() ) modified = true; else if( _scrollBarAddLineButtons->currentIndex() != StyleConfigData::scrollBarAddLineButtons() ) modified = true; else if( _scrollBarSubLineButtons->currentIndex() != StyleConfigData::scrollBarSubLineButtons() ) modified = true; else if( _splitterProxyEnabled->isChecked() != StyleConfigData::splitterProxyEnabled() ) modified = true; else if( _animationsEnabled->isChecked() != StyleConfigData::animationsEnabled() ) modified = true; else if( _animationsDuration->value() != StyleConfigData::animationsDuration() ) modified = true; else if( _windowDragMode->currentIndex() != StyleConfigData::windowDragMode() ) modified = true; else if( _menuOpacity->value() != StyleConfigData::menuOpacity() ) modified = true; emit changed(modified); } //__________________________________________________________________ void StyleConfig::load() { _tabBarDrawCenteredTabs->setChecked( StyleConfigData::tabBarDrawCenteredTabs() ); _toolBarDrawItemSeparator->setChecked( StyleConfigData::toolBarDrawItemSeparator() ); _viewDrawFocusIndicator->setChecked( StyleConfigData::viewDrawFocusIndicator() ); _dockWidgetDrawFrame->setChecked( StyleConfigData::dockWidgetDrawFrame() ); _titleWidgetDrawFrame->setChecked( StyleConfigData::titleWidgetDrawFrame() ); _sidePanelDrawFrame->setChecked( StyleConfigData::sidePanelDrawFrame() ); _menuItemDrawThinFocus->setChecked( !StyleConfigData::menuItemDrawStrongFocus() ); _sliderDrawTickMarks->setChecked( StyleConfigData::sliderDrawTickMarks() ); _mnemonicsMode->setCurrentIndex( StyleConfigData::mnemonicsMode() ); _splitterProxyEnabled->setChecked( StyleConfigData::splitterProxyEnabled() ); _scrollBarAddLineButtons->setCurrentIndex( StyleConfigData::scrollBarAddLineButtons() ); _scrollBarSubLineButtons->setCurrentIndex( StyleConfigData::scrollBarSubLineButtons() ); _animationsEnabled->setChecked( StyleConfigData::animationsEnabled() ); _animationsDuration->setValue( StyleConfigData::animationsDuration() ); _windowDragMode->setCurrentIndex( StyleConfigData::windowDragMode() ); _menuOpacity->setValue( StyleConfigData::menuOpacity() ); } }