diff --git a/kstyle/CMakeLists.txt b/kstyle/CMakeLists.txt index 39d0deb1..107d82dd 100644 --- a/kstyle/CMakeLists.txt +++ b/kstyle/CMakeLists.txt @@ -1,199 +1,199 @@ set(BREEZE_USE_KDE4 ${USE_KDE4}) if(BREEZE_USE_KDE4) ############ Language and toolchain features ############ copied from ECM if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" AND NOT WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") endif() endif() ################# Qt/KDE ################# if(BREEZE_USE_KDE4) ### XCB if(UNIX AND NOT APPLE) find_package(PkgConfig REQUIRED) pkg_check_modules(XCB xcb x11-xcb) add_feature_info("x11-xcb" XCB_FOUND "Required to pass style properties to native Windows on X11 Platform") set_feature_info("x11-xcb" "Required to pass style properties to native Windows on X11 Platform" "http://xcb.freedesktop.org") set(BREEZE_HAVE_X11 ${XCB_FOUND}) else() set(BREEZE_HAVE_X11 FALSE) endif() set(BREEZE_HAVE_QTQUICK FALSE) set(BREEZE_HAVE_KWAYLAND FALSE) ### KStyle set(BREEZE_HAVE_KSTYLE FALSE) else() find_package(Qt5 REQUIRED CONFIG COMPONENTS Widgets DBus) find_package(KF5 REQUIRED COMPONENTS I18n Config GuiAddons ConfigWidgets WindowSystem) find_package(Qt5 COMPONENTS Quick) set(BREEZE_HAVE_QTQUICK ${Qt5Quick_FOUND}) find_package( KF5FrameworkIntegration CONFIG ) set_package_properties(KF5FrameworkIntegration PROPERTIES DESCRIPTION "KF5 Framework Integration" URL "https://projects.kde.org/projects/frameworks/frameworkintegration" TYPE OPTIONAL PURPOSE "Required to use KStyle convenience functionalities in style") set(BREEZE_HAVE_KSTYLE ${KF5FrameworkIntegration_FOUND}) find_package(XCB COMPONENTS XCB) set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" URL "http://xcb.freedesktop.org" TYPE OPTIONAL PURPOSE "Required to pass style properties to native Windows on X11 Platform" ) find_package(KF5Wayland CONFIG) set(BREEZE_HAVE_KWAYLAND ${KF5Wayland_FOUND}) if(UNIX AND NOT APPLE) set(BREEZE_HAVE_X11 ${XCB_XCB_FOUND}) if (XCB_XCB_FOUND) find_package(Qt5 REQUIRED CONFIG COMPONENTS X11Extras) endif() else() set(BREEZE_HAVE_X11 FALSE) endif() endif() ################# includes ################# include_directories( animations debug ) include_directories(${CMAKE_SOURCE_DIR}/libbreezecommon) include_directories(${CMAKE_BINARY_DIR}/libbreezecommon) ################# configuration ################# configure_file(config-breeze.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-breeze.h ) ########### next target ############### set(breeze_PART_SRCS animations/breezeanimation.cpp animations/breezeanimations.cpp animations/breezeanimationdata.cpp animations/breezebaseengine.cpp animations/breezebusyindicatordata.cpp animations/breezebusyindicatorengine.cpp animations/breezedialdata.cpp animations/breezedialengine.cpp animations/breezeenabledata.cpp animations/breezegenericdata.cpp animations/breezeheaderviewdata.cpp animations/breezeheaderviewengine.cpp animations/breezescrollbardata.cpp animations/breezescrollbarengine.cpp animations/breezespinboxengine.cpp animations/breezespinboxdata.cpp animations/breezestackedwidgetdata.cpp animations/breezestackedwidgetengine.cpp animations/breezetabbarengine.cpp animations/breezetabbardata.cpp animations/breezetoolboxengine.cpp animations/breezetransitiondata.cpp animations/breezetransitionwidget.cpp animations/breezewidgetstateengine.cpp animations/breezewidgetstatedata.cpp - animations/breezemultistateengine.cpp - animations/breezemultistatedata.cpp + animations/breezecheckboxengine.cpp + animations/breezecheckboxdata.cpp debug/breezewidgetexplorer.cpp breezeaddeventfilter.cpp breezeframeshadow.cpp breezehelper.cpp breezemdiwindowshadow.cpp breezemnemonics.cpp breezepropertynames.cpp breezeshadowhelper.cpp breezesplitterproxy.cpp breezestyle.cpp checkbox.cpp breezestyleplugin.cpp breezetileset.cpp breezewindowmanager.cpp ) if(NOT BREEZE_USE_KDE4) set(breeze_PART_SRCS ${breeze_PART_SRCS} breezeblurhelper.cpp ) endif() if(BREEZE_USE_KDE4) kde4_add_kcfg_files(breeze_PART_SRCS breezestyleconfigdata.kcfgc) kde4_add_plugin(breeze ${breeze_PART_SRCS} kstylekde4compat.cpp) target_link_libraries(breeze ${KDE4_KDEUI_LIBS}) target_link_libraries(breeze breezecommon4) if(BREEZE_HAVE_X11) target_link_libraries(breeze ${X11_XCB_LIBRARIES}) target_link_libraries(breeze ${XCB_LIBRARIES}) endif() install(TARGETS breeze DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/styles/) else() kconfig_add_kcfg_files(breeze_PART_SRCS breezestyleconfigdata.kcfgc) add_library(breeze MODULE ${breeze_PART_SRCS}) target_link_libraries(breeze Qt5::Core Qt5::Gui Qt5::Widgets Qt5::DBus) if( BREEZE_HAVE_QTQUICK ) target_link_libraries(breeze Qt5::Quick) endif() target_link_libraries(breeze KF5::ConfigCore KF5::ConfigWidgets KF5::GuiAddons KF5::WindowSystem) target_link_libraries(breeze breezecommon5) if( KF5FrameworkIntegration_FOUND ) target_link_libraries(breeze KF5::Style) endif() if (WIN32) # As stated in http://msdn.microsoft.com/en-us/library/4hwaceh6.aspx M_PI only gets defined # when if _USE_MATH_DEFINES is defined target_compile_definitions(breeze PRIVATE _USE_MATH_DEFINES _BSD_SOURCE) endif() if(BREEZE_HAVE_X11) target_link_libraries(breeze ${XCB_LIBRARIES}) target_link_libraries(breeze Qt5::X11Extras) endif() if(BREEZE_HAVE_KWAYLAND) target_link_libraries(breeze KF5::WaylandClient) endif() install(TARGETS breeze DESTINATION ${QT_PLUGIN_INSTALL_DIR}/styles/) endif() ########### install files ############### install(FILES breeze.themerc DESTINATION ${DATA_INSTALL_DIR}/kstyle/themes) ########### subdirectories ############### add_subdirectory(config) diff --git a/kstyle/animations/breezeanimations.cpp b/kstyle/animations/breezeanimations.cpp index b3924003..eb49d3ba 100644 --- a/kstyle/animations/breezeanimations.cpp +++ b/kstyle/animations/breezeanimations.cpp @@ -1,235 +1,235 @@ /************************************************************************* * 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 "breezeanimations.h" #include "breezepropertynames.h" #include "breezestyleconfigdata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Breeze { //____________________________________________________________ Animations::Animations( QObject* parent ): QObject( parent ) { _widgetEnabilityEngine = new WidgetStateEngine( this ); _busyIndicatorEngine = new BusyIndicatorEngine( this ); _comboBoxEngine = new WidgetStateEngine( this ); _toolButtonEngine = new WidgetStateEngine( this ); _spinBoxEngine = new SpinBoxEngine( this ); _toolBoxEngine = new ToolBoxEngine( this ); registerEngine( _headerViewEngine = new HeaderViewEngine( this ) ); registerEngine( _widgetStateEngine = new WidgetStateEngine( this ) ); registerEngine( _inputWidgetEngine = new WidgetStateEngine( this ) ); registerEngine( _scrollBarEngine = new ScrollBarEngine( this ) ); registerEngine( _stackedWidgetEngine = new StackedWidgetEngine( this ) ); registerEngine( _tabBarEngine = new TabBarEngine( this ) ); registerEngine( _dialEngine = new DialEngine( this ) ); - registerEngine( _multiStateEngine = new MultiStateEngine( this ) ); + registerEngine( _multiStateEngine = new CheckBoxEngine( this ) ); } //____________________________________________________________ void Animations::setupEngines() { // animation steps AnimationData::setSteps( StyleConfigData::animationSteps() ); const bool animationsEnabled( StyleConfigData::animationsEnabled() ); const int animationsDuration( StyleConfigData::animationsDuration() ); _widgetEnabilityEngine->setEnabled( animationsEnabled ); _comboBoxEngine->setEnabled( animationsEnabled ); _toolButtonEngine->setEnabled( animationsEnabled ); _spinBoxEngine->setEnabled( animationsEnabled ); _toolBoxEngine->setEnabled( animationsEnabled ); _widgetEnabilityEngine->setDuration( animationsDuration ); _comboBoxEngine->setDuration( animationsDuration ); _toolButtonEngine->setDuration( animationsDuration ); _spinBoxEngine->setDuration( animationsDuration ); _stackedWidgetEngine->setDuration( animationsDuration ); _toolBoxEngine->setDuration( animationsDuration ); // registered engines foreach( const BaseEngine::Pointer& engine, _engines ) { engine.data()->setEnabled( animationsEnabled ); engine.data()->setDuration( animationsDuration ); } // stacked widget transition has an extra flag for animations _stackedWidgetEngine->setEnabled( animationsEnabled && StyleConfigData::stackedWidgetTransitionsEnabled() ); // busy indicator _busyIndicatorEngine->setEnabled( StyleConfigData::progressBarAnimated() ); _busyIndicatorEngine->setDuration( StyleConfigData::progressBarBusyStepDuration() ); } //____________________________________________________________ void Animations::registerWidget( QWidget* widget ) const { if( !widget ) return; // check against noAnimations propery QVariant propertyValue( widget->property( PropertyNames::noAnimations ) ); if( propertyValue.isValid() && propertyValue.toBool() ) return; // all widgets are registered to the enability engine. _widgetEnabilityEngine->registerWidget( widget, AnimationEnable ); // install animation timers // for optimization, one should put with most used widgets here first // buttons if( qobject_cast(widget) ) { _toolButtonEngine->registerWidget( widget, AnimationHover|AnimationFocus ); _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } else if( qobject_cast(widget) || qobject_cast(widget) ) { _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus|AnimationPressed ); _multiStateEngine->registerWidget( widget ); } else if( qobject_cast(widget) ) { // register to toolbox engine if needed if( qobject_cast( widget->parent() ) ) { _toolBoxEngine->registerWidget( widget ); } _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } // groupboxes else if( QGroupBox* groupBox = qobject_cast( widget ) ) { if( groupBox->isCheckable() ) { _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus ); _multiStateEngine->registerWidget( widget ); } } // sliders else if( qobject_cast( widget ) ) { _scrollBarEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } else if( qobject_cast( widget ) ) { _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } else if( qobject_cast( widget ) ) { _dialEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } // progress bar else if( qobject_cast( widget ) ) { _busyIndicatorEngine->registerWidget( widget ); } // combo box else if( qobject_cast( widget ) ) { _comboBoxEngine->registerWidget( widget, AnimationHover ); _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } // spinbox else if( qobject_cast( widget ) ) { _spinBoxEngine->registerWidget( widget ); _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } // editors else if( qobject_cast( widget ) ) { _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } else if( qobject_cast( widget ) ) { _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } else if( widget->inherits( "KTextEditor::View" ) ) { _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } // header views // need to come before abstract item view, otherwise is skipped else if( qobject_cast( widget ) ) { _headerViewEngine->registerWidget( widget ); } // lists else if( qobject_cast( widget ) ) { _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } // tabbar else if( qobject_cast( widget ) ) { _tabBarEngine->registerWidget( widget ); } // scrollarea else if( QAbstractScrollArea* scrollArea = qobject_cast( widget ) ) { if( scrollArea->frameShadow() == QFrame::Sunken && (widget->focusPolicy()&Qt::StrongFocus) ) { _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } } // stacked widgets if( QStackedWidget* stack = qobject_cast( widget ) ) { _stackedWidgetEngine->registerWidget( stack ); } } //____________________________________________________________ void Animations::unregisterWidget( QWidget* widget ) const { if( !widget ) return; _widgetEnabilityEngine->unregisterWidget( widget ); _spinBoxEngine->unregisterWidget( widget ); _comboBoxEngine->unregisterWidget( widget ); _busyIndicatorEngine->registerWidget( widget ); // the following allows some optimization of widget unregistration // it assumes that a widget can be registered atmost in one of the // engines stored in the list. foreach( const BaseEngine::Pointer& engine, _engines ) { if( engine && engine.data()->unregisterWidget( widget ) ) break; } } //_______________________________________________________________ void Animations::unregisterEngine( QObject* object ) { int index( _engines.indexOf( qobject_cast(object) ) ); if( index >= 0 ) _engines.removeAt( index ); } //_______________________________________________________________ void Animations::registerEngine( BaseEngine* engine ) { _engines.append( engine ); connect( engine, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterEngine(QObject*)) ); } } diff --git a/kstyle/animations/breezeanimations.h b/kstyle/animations/breezeanimations.h index cbaa764e..f7c0b7b8 100644 --- a/kstyle/animations/breezeanimations.h +++ b/kstyle/animations/breezeanimations.h @@ -1,170 +1,170 @@ #ifndef breezeanimations_h #define breezeanimations_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 "breezebusyindicatorengine.h" #include "breezedialengine.h" #include "breezeheaderviewengine.h" #include "breezescrollbarengine.h" #include "breezespinboxengine.h" #include "breezestackedwidgetengine.h" #include "breezetabbarengine.h" #include "breezetoolboxengine.h" #include "breezewidgetstateengine.h" -#include "breezemultistateengine.h" +#include "breezecheckboxengine.h" #include #include namespace Breeze { //* stores engines class Animations: public QObject { Q_OBJECT public: //* constructor explicit Animations( QObject* ); //* register animations corresponding to given widget, depending on its type. void registerWidget( QWidget* widget ) const; /** unregister all animations associated to a widget */ void unregisterWidget( QWidget* widget ) const; //* enability engine WidgetStateEngine& widgetEnabilityEngine() const { return *_widgetEnabilityEngine; } //* abstractButton engine WidgetStateEngine& widgetStateEngine() const { return *_widgetStateEngine; } //* editable combobox arrow hover engine WidgetStateEngine& comboBoxEngine() const { return *_comboBoxEngine; } //* Tool buttons arrow hover engine WidgetStateEngine& toolButtonEngine() const { return *_toolButtonEngine; } //* item view engine WidgetStateEngine& inputWidgetEngine() const { return *_inputWidgetEngine; } //* busy indicator BusyIndicatorEngine& busyIndicatorEngine() const { return *_busyIndicatorEngine; } //* header view engine HeaderViewEngine& headerViewEngine() const { return *_headerViewEngine; } //* scrollbar engine ScrollBarEngine& scrollBarEngine() const { return *_scrollBarEngine; } //* dial engine DialEngine& dialEngine() const { return *_dialEngine; } //* spinbox engine SpinBoxEngine& spinBoxEngine() const { return *_spinBoxEngine; } //* tabbar TabBarEngine& tabBarEngine() const { return *_tabBarEngine; } //* toolbox ToolBoxEngine& toolBoxEngine() const { return *_toolBoxEngine; } //* multi state engine - MultiStateEngine& multiStateEngine() const + CheckBoxEngine& multiStateEngine() const { return *_multiStateEngine; } //* setup engines void setupEngines(); protected Q_SLOTS: //* enregister engine void unregisterEngine( QObject* ); private: //* register new engine void registerEngine( BaseEngine* ); //* busy indicator BusyIndicatorEngine* _busyIndicatorEngine = nullptr; //* headerview hover effect HeaderViewEngine* _headerViewEngine = nullptr; //* widget enability engine WidgetStateEngine* _widgetEnabilityEngine = nullptr; //* abstract button engine WidgetStateEngine* _widgetStateEngine = nullptr; //* editable combobox arrow hover effect WidgetStateEngine* _comboBoxEngine = nullptr; //* mennu toolbutton arrow hover effect WidgetStateEngine* _toolButtonEngine = nullptr; //* item view engine WidgetStateEngine* _inputWidgetEngine = nullptr; //* scrollbar engine ScrollBarEngine* _scrollBarEngine = nullptr; //* dial engine DialEngine* _dialEngine = nullptr; //* spinbox engine SpinBoxEngine* _spinBoxEngine = nullptr; //* stacked widget engine StackedWidgetEngine* _stackedWidgetEngine = nullptr; //* tabbar engine TabBarEngine* _tabBarEngine = nullptr; //* toolbar engine ToolBoxEngine* _toolBoxEngine = nullptr; //* multi state engine - MultiStateEngine *_multiStateEngine = nullptr; + CheckBoxEngine *_multiStateEngine = nullptr; //* keep list of existing engines QList< BaseEngine::Pointer > _engines; }; } #endif diff --git a/kstyle/animations/breezecheckboxdata.cpp b/kstyle/animations/breezecheckboxdata.cpp new file mode 100644 index 00000000..81ae57ca --- /dev/null +++ b/kstyle/animations/breezecheckboxdata.cpp @@ -0,0 +1,142 @@ +/************************************************************************* + * 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 "breezecheckboxdata.h" + +namespace Breeze +{ + const CheckBoxRenderState CheckBoxData::offState { + /* Position */ QPointF(0, 0), + /* LinePointPosition */ invalidPointF, invalidPointF, invalidPointF, + /* PointPosition */ invalidPointF, invalidPointF, invalidPointF, + /* PointRadius */ 0.0f, 0.0f, 0.0f + }; + const CheckBoxRenderState CheckBoxData::onState { + /* Position */ QPointF(-1, 3), + /* LinePointPosition */ QPointF(-3, -3), QPointF(0, 0), QPointF(5, -5), + /* PointPosition */ invalidPointF, invalidPointF, invalidPointF, + /* PointRadius */ 0.0f, 0.0f, 0.0f, + }; + const CheckBoxRenderState CheckBoxData::partialState { + /* Position */ QPointF(0, 0), + /* LinePointPosition */ invalidPointF, invalidPointF, invalidPointF, + /* PointPosition */ QPointF(-4, 0), QPointF( 0, 0), QPointF(4, 0), + /* PointRadius */ 1.0f, 1.0f, 1.0f, + }; + + const TimelineAnimation::EntryList CheckBoxData::offToOnTransition { + {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, + {0.0f, "position", CheckBoxData::onState.position}, + {0.0f, "linePointPosition0", CheckBoxData::onState.linePointPosition0}, + {0.0f, 0.4f, "linePointPosition1", CheckBoxData::onState.linePointPosition0, CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "linePointPosition2", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, + {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, + }; + + const TimelineAnimation::EntryList CheckBoxData::onToOffTransition { + {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, + {0.0f, 0.5f, "linePointPosition0", CheckBoxData::onState.linePointPosition0, CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, + {0.6f, 0.4f, "linePointPosition0", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, + {0.6f, 0.4f, "linePointPosition1", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, + {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, + }; + + const TimelineAnimation::EntryList CheckBoxData::offToPartialTransition { + {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, + {0.0f, "pointPosition0", CheckBoxData::partialState.pointPosition0}, + {0.0f, "pointPosition1", CheckBoxData::partialState.pointPosition1}, + {0.0f, "pointPosition2", CheckBoxData::partialState.pointPosition2}, + {0.0f, 0.6f, "pointRadius0", QVariant(), CheckBoxData::partialState.pointRadius0, QEasingCurve::OutCubic}, + {0.2f, 0.6f, "pointRadius1", QVariant(), CheckBoxData::partialState.pointRadius1, QEasingCurve::OutCubic}, + {0.4f, 0.6f, "pointRadius2", QVariant(), CheckBoxData::partialState.pointRadius2, QEasingCurve::OutCubic}, + {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, + }; + const TimelineAnimation::EntryList CheckBoxData::partialToOffTransition { + {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, + {0.0f, 0.6f, "pointRadius0", CheckBoxData::partialState.pointRadius0, CheckBoxData::offState.pointRadius0, QEasingCurve::InCubic}, + {0.2f, 0.6f, "pointRadius1", CheckBoxData::partialState.pointRadius1, CheckBoxData::offState.pointRadius1, QEasingCurve::InCubic}, + {0.4f, 0.6f, "pointRadius2", CheckBoxData::partialState.pointRadius2, CheckBoxData::offState.pointRadius2, QEasingCurve::InCubic}, + {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, + }; + + static const float partialPointRadiusSqrt2 = CheckBoxData::partialState.pointRadius0 * sqrtf(2); + static const float partialPointRadiusSqrt3 = CheckBoxData::partialState.pointRadius0 * sqrtf(3); + static const QPointF onStateAbsLinePointPosition2 = CheckBoxData::onState.linePointPosition2 + CheckBoxData::onState.position; + + const TimelineAnimation::EntryList CheckBoxData::partialToOnTransition { + {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, + {0.0f, "position", CheckBoxData::onState.position}, + {0.0f, "linePointPosition0", CheckBoxData::onState.linePointPosition0}, + + {0.0f, 0.4f, "linePointPosition1", CheckBoxData::onState.linePointPosition0, CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, + {0.0f, 0.4f, "pointRadius0", QVariant(), CheckBoxData::onState.pointRadius0, QEasingCurve::InOutCubic}, + {0.0f, 0.5f, "pointPosition1", QVariant(), CheckBoxData::onState.position, QEasingCurve::InOutCubic}, + {0.0f, 0.5f, "pointRadius1", QVariant(), partialPointRadiusSqrt2, QEasingCurve::InOutCubic}, + {0.0f, 0.5f, "pointPosition2", QVariant(), CheckBoxData::onState.position, QEasingCurve::InOutCubic}, + {0.0f, 0.5f, "pointRadius2", QVariant(), partialPointRadiusSqrt2, QEasingCurve::InOutCubic}, + + {0.5f, 0.5f, "linePointPosition2", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointPosition2", QVariant(), onStateAbsLinePointPosition2, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointRadius1", QVariant(), CheckBoxData::onState.pointRadius1, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointRadius2", QVariant(), CheckBoxData::onState.pointRadius2, QEasingCurve::InOutCubic}, + {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, + }; + const TimelineAnimation::EntryList CheckBoxData::onToPartialTransition { + {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, + {0.0f, 0.4f, "position", QVariant(), CheckBoxData::partialState.position, QEasingCurve::InOutCubic}, + {0.0f, 0.4f, "linePointPosition0", QVariant(), CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, + {0.0f, 0.4f, "linePointPosition2", QVariant(), CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, + {0.0f, 0.4f, "pointPosition1", CheckBoxData::onState.position, CheckBoxData::partialState.pointPosition1, QEasingCurve::InOutCubic}, + {0.0f, 0.4f, "pointRadius1", QVariant(), partialPointRadiusSqrt3, QEasingCurve::InOutCubic}, + + {0.5f, 0.5f, "pointPosition0", CheckBoxData::partialState.pointPosition1, CheckBoxData::partialState.pointPosition0, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointPosition2", CheckBoxData::partialState.pointPosition1, CheckBoxData::partialState.pointPosition2, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointRadius0", partialPointRadiusSqrt3, CheckBoxData::partialState.pointRadius0, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointRadius1", partialPointRadiusSqrt3, CheckBoxData::partialState.pointRadius1, QEasingCurve::InOutCubic}, + {0.5f, 0.5f, "pointRadius2", partialPointRadiusSqrt3, CheckBoxData::partialState.pointRadius2, QEasingCurve::InOutCubic}, + {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, + }; + + //______________________________________________ + bool CheckBoxData::updateState( CheckBoxState value ) + { + if( !_initialized ) + { + + _state = value; + _initialized = true; + return false; + + } else if( _state == value ) { + + return false; + + } else { + + _previousState = _state; + _state = value; + animation().data()->setDirection(Animation::Forward); + if( !animation().data()->isRunning() ) animation().data()->start(); + return true; + + } + + } + +} diff --git a/kstyle/animations/breezemultistatedata.h b/kstyle/animations/breezecheckboxdata.h similarity index 56% rename from kstyle/animations/breezemultistatedata.h rename to kstyle/animations/breezecheckboxdata.h index d680540d..eb096942 100644 --- a/kstyle/animations/breezemultistatedata.h +++ b/kstyle/animations/breezecheckboxdata.h @@ -1,299 +1,348 @@ -#ifndef breezemultistatedata_h -#define breezemultistatedata_h +#ifndef breezecheckboxdata_h +#define breezecheckboxdata_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 #include "breezegenericdata.h" namespace Breeze { +#define declvaluetype(v) std::remove_reference::type + //// //// //// //// /// /// /// // // / / / / static constexpr const qreal qrealQNaN {std::numeric_limits::quiet_NaN()}; // TODO: remove if unused anywhere but below static constexpr const QPointF invalidPointF {qrealQNaN, qrealQNaN}; static const auto isInvalidPointF = [](const QPointF &point) { return std::isnan(point.x()) && std::isnan(point.y()); }; + struct CheckBoxRenderState { + Q_GADGET + Q_PROPERTY(QPointF position MEMBER position) + Q_PROPERTY(QPointF linePointPosition0 MEMBER linePointPosition0) + Q_PROPERTY(QPointF linePointPosition1 MEMBER linePointPosition1) + Q_PROPERTY(QPointF linePointPosition2 MEMBER linePointPosition2) + Q_PROPERTY(QPointF pointPosition0 MEMBER pointPosition0) + Q_PROPERTY(QPointF pointPosition1 MEMBER pointPosition1) + Q_PROPERTY(QPointF pointPosition2 MEMBER pointPosition2) + Q_PROPERTY(qreal pointRadius0 MEMBER pointRadius0) + Q_PROPERTY(qreal pointRadius1 MEMBER pointRadius1) + Q_PROPERTY(qreal pointRadius2 MEMBER pointRadius2) + + public: + QPointF position; + QPointF linePointPosition0, linePointPosition1, linePointPosition2; + QPointF pointPosition0, pointPosition1, pointPosition2; + qreal pointRadius0, pointRadius1, pointRadius2; + + QString toString() const { + QString str("CheckBoxRenderState {\n"); + static const auto pointFToString = [](const QPointF &p)->QString { + if (isInvalidPointF(p)) { + return QStringLiteral("(InvalidPointF)"); + } + return QStringLiteral("{%1, %2}").arg(p.x()).arg(p.y()); + }; + str.append(QStringLiteral(" position = %1,\n").arg(pointFToString(position))); + str.append(QStringLiteral(" linePointPosition = {%1, %2, %3},\n") + .arg(pointFToString(linePointPosition0)) + .arg(pointFToString(linePointPosition1)) + .arg(pointFToString(linePointPosition2))); + str.append(QStringLiteral(" pointPosition = {%1, %2, %3},\n") + .arg(pointFToString(pointPosition0)) + .arg(pointFToString(pointPosition1)) + .arg(pointFToString(pointPosition2))); + str.append(QStringLiteral(" pointRadius = {%1, %2, %3},\n") + .arg(pointRadius0) + .arg(pointRadius1) + .arg(pointRadius2)); + str.append("}"); + return str; + } + }; + class TimelineAnimation: public QAbstractAnimation { Q_OBJECT public: struct Entry { /**************************************/ - Entry(float relStartTime, float relDuration, unsigned dataId, QVariant from, QVariant to, QEasingCurve easingCurve) + using ActionFunc = void (*)(void *renderState); + + Entry(float relStartTime, ActionFunc action) : relStartTime(relStartTime) - , state(nullptr) - , dataId(dataId) - , from(std::move(from)) - , to(std::move(to)) - , relDuration(relDuration) - , easingCurve(std::move(easingCurve)) + , relDuration(0) + , action(action) {} - Entry(float relStartTime, unsigned member, QVariant to) + Entry(float relStartTime, QByteArray propertyName, QVariant to) : relStartTime(relStartTime) - , state(nullptr) - , dataId(member) + , relDuration(0) + , action(nullptr) + , propertyName(std::move(propertyName)) , from(QVariant()) , to(std::move(to)) - , relDuration(0) {} - Entry(float relStartTime, const QVector *state) + Entry(float relStartTime, float relDuration, QByteArray propertyName, QVariant from, QVariant to, QEasingCurve easingCurve) : relStartTime(relStartTime) - , state(q_check_ptr(state)) - , relDuration(0) + , relDuration(relDuration) + , action(nullptr) + , propertyName(std::move(propertyName)) + , from(std::move(from)) + , to(std::move(to)) + , easingCurve(std::move(easingCurve)) {} float relStartTime; - const QVector * state; - unsigned dataId; + float relDuration; + ActionFunc action; + QByteArray propertyName; QVariant from; QVariant to; - float relDuration; QEasingCurve easingCurve; inline bool isSetter() const { return qFuzzyIsNull(relDuration) && !from.isValid(); } inline bool isStartingFromPreviousValue() const { return !from.isValid() && to.isValid(); } }; /*******************************************************/ - using EntryList = QVector; + using EntryList = QList; - TimelineAnimation(QObject *parent, int durationMs, QVector *data, const EntryList *transitions = nullptr) + TimelineAnimation(QObject *parent, int durationMs, CheckBoxRenderState *data, const EntryList *transitions = nullptr) : QAbstractAnimation(parent) , _durationMs(durationMs) , _data(q_check_ptr(data)) { setTransitions(transitions); } void setDuration(int durationMs) { _durationMs = durationMs; } int duration() const override { return _durationMs; } void setTransitions(const EntryList *transitions) { stop(); _transitions = transitions; if(transitions != nullptr) { _transitionStates = QVector(transitions->size()); } else { _transitionStates.clear(); } } Q_SIGNALS: void valueChanged(); protected: void updateCurrentTime(int currentTime) override { if(_transitions == nullptr) { return; } - - const qreal progress = qreal(currentTime)/_durationMs; bool changed = false; for (int i = 0; i < _transitions->size(); ++i) { const Entry &transition = (*_transitions)[i]; TransitionState &state = _transitionStates[i]; if (state.processed) { continue; } - float relEndTime = transition.relStartTime + transition.relDuration; + int absStartTime = qRound(transition.relStartTime * _durationMs); + int absEndTime = qRound((transition.relStartTime + transition.relDuration) * _durationMs); - if (transition.state != nullptr) { - if (relEndTime <= progress) { - *_data = *transition.state; + if (transition.action != nullptr) { + if (absEndTime <= currentTime) { + transition.action(_data); state.processed = true; } continue; } - Q_ASSERT(transition.dataId < _data->size()); - QVariant &value = (*_data)[transition.dataId]; + int propertyIndex = _data->staticMetaObject.indexOfProperty(transition.propertyName); + Q_ASSERT(propertyIndex >= 0); + auto property = _data->staticMetaObject.property(propertyIndex); + const QVariant value = property.readOnGadget(_data); - if (relEndTime < progress) { + if (absEndTime < currentTime) { // Already ended if (value != transition.to) { - value = transition.to; + property.writeOnGadget(_data, transition.to); changed = true; } state.processed = true; - } else if (transition.relStartTime <= progress) { + } else if (absStartTime <= currentTime) { // Is running if (transition.isStartingFromPreviousValue() && !state.previousValue.isValid()) { state.previousValue = value; } - const qreal transitionProgress = (progress - transition.relStartTime) / transition.relDuration; + const qreal transitionProgress = (qreal(currentTime)/_durationMs - transition.relStartTime) / transition.relDuration; const QVariant &from = transition.isStartingFromPreviousValue() ? state.previousValue : transition.from; const QVariant newValue = interpolate(from, transition.to, transition.easingCurve.valueForProgress(transitionProgress)); if (value != newValue) { - value = newValue; + property.writeOnGadget(_data, newValue); changed = true; } } else { // Too early break; } } if (changed) { emit valueChanged(); } } void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override { Q_UNUSED(oldState); switch(newState) { case Running: for(auto &state: _transitionStates) { state = TransitionState(); } break; default: break; } } private: int _durationMs; template static ValueType interpolateGeneric(const QVariant &from, const QVariant &to, qreal progress) { const auto a = from.value(); const auto b = to.value(); return a * (1.0 - progress) + b * progress; } static QVariant interpolate(const QVariant &from, const QVariant &to, qreal progress) { switch(QMetaType::Type(from.type())) { case QMetaType::Int: return interpolateGeneric(from, to, progress); case QMetaType::UInt: return interpolateGeneric(from, to, progress); case QMetaType::LongLong: return interpolateGeneric(from, to, progress); case QMetaType::ULongLong: return interpolateGeneric(from, to, progress); case QMetaType::Float: return interpolateGeneric(from, to, progress); case QMetaType::Double: return interpolateGeneric(from, to, progress); case QMetaType::QPoint: return interpolateGeneric(from, to, progress); case QMetaType::QPointF: return interpolateGeneric(from, to, progress); default: qWarning("Interpolation not supported for type %s", from.typeName()); return to; } } struct TransitionState { QVariant previousValue {QVariant()}; bool processed {false}; }; - QVector *_data; + CheckBoxRenderState *_data; const EntryList *_transitions; QVector _transitionStates; }; + struct AbstractState { + virtual QVariant get(unsigned id) = 0; + virtual void set(unsigned id, const QVariant &value) = 0; + }; - class CheckMarkRenderer { -// Q_OBJECT + struct CheckMarkState { + QPointF position; + QPointF linePointPosition[3]; + QPointF pointPosition[3]; + qreal pointRadius[3]; - public: enum DataId: unsigned { Position, - LinePointPosition_0, - LinePointPosition_1, - LinePointPosition_2, - PointPosition_0, - PointPosition_1, - PointPosition_2, - PointRadius_0, - PointRadius_1, - PointRadius_2, - - DataIdCount, - - LinePointPosition = LinePointPosition_0, - LinePointPosition_Last = LinePointPosition_2, - - PointPosition = PointPosition_0, - PointPosition_Last = PointPosition_2, - - PointRadius = PointRadius_0, - PointRadius_Last = PointRadius_2, + LinePointPosition_0, LinePointPosition_1, LinePointPosition_2, + PointPosition_0, PointPosition_1, PointPosition_2, + PointRadius_0, PointRadius_1, PointRadius_2, }; - - void setState(CheckBoxState newState); - void render(QPainter &painter) {} }; - //* Tracks arbitrary states (e.g. tri-state checkbox check state) - class MultiStateData: public GenericData + class CheckBoxData: public GenericData { Q_OBJECT - public: + public: //* constructor - MultiStateData( QObject* parent, QWidget* target, int duration, QVariant state = QVariant() ): + CheckBoxData( QObject* parent, QWidget* target, int duration, CheckBoxState state = CheckBoxState::CheckUnknown ): GenericData( parent, target, duration ), _initialized( false ), _state( state ), - _previousState( state ), - timeline(new TimelineAnimation(this, 250, &variables)) + _previousState( CheckBoxState::CheckUnknown ), + timeline(new TimelineAnimation(this, 250, &renderState)) { connect(timeline, &TimelineAnimation::valueChanged, target, QOverload<>::of(&QWidget::update)); } //* destructor - ~MultiStateData() override + ~CheckBoxData() override { timeline->stop(); } /** returns true if state has changed and starts timer accordingly */ - virtual bool updateState( const QVariant &value ); + virtual bool updateState( CheckBoxState value ); - virtual QVariant state() const { return _state; } - virtual QVariant previousState() const { return _previousState; } + virtual CheckBoxState state() const { return _state; } + virtual CheckBoxState previousState() const { return _previousState; } - QVector variables; TimelineAnimation *timeline; - private: + static const CheckBoxRenderState offState; + static const CheckBoxRenderState onState; + static const CheckBoxRenderState partialState; - bool _initialized; - QVariant _state; - QVariant _previousState; + static const TimelineAnimation::EntryList offToOnTransition; + static const TimelineAnimation::EntryList onToOffTransition; + static const TimelineAnimation::EntryList offToPartialTransition; + static const TimelineAnimation::EntryList partialToOffTransition; + static const TimelineAnimation::EntryList partialToOnTransition; + static const TimelineAnimation::EntryList onToPartialTransition; + + CheckBoxRenderState renderState; + private: + + static void initTransitions(); + + bool _initialized; + CheckBoxState _state; + CheckBoxState _previousState; }; } -#endif +#endif \ No newline at end of file diff --git a/kstyle/animations/breezemultistateengine.cpp b/kstyle/animations/breezecheckboxengine.cpp similarity index 77% rename from kstyle/animations/breezemultistateengine.cpp rename to kstyle/animations/breezecheckboxengine.cpp index 4a90045e..6e9185d2 100644 --- a/kstyle/animations/breezemultistateengine.cpp +++ b/kstyle/animations/breezecheckboxengine.cpp @@ -1,88 +1,88 @@ /************************************************************************* * 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 "breezemultistateengine.h" +#include "breezecheckboxengine.h" namespace Breeze { //____________________________________________________________ - bool MultiStateEngine::registerWidget( QWidget* widget) + bool CheckBoxEngine::registerWidget( QWidget* widget) { if( !widget ) return false; - if( !_state.contains( widget ) ) { _state.insert( widget, new MultiStateData( this, widget, duration() ), enabled() ); } + if( !_state.contains( widget ) ) { _state.insert( widget, new CheckBoxData( this, widget, duration() ), enabled() ); } // connect destruction signal connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); return true; } //____________________________________________________________ - BaseEngine::WidgetList MultiStateEngine::registeredWidgets() const + BaseEngine::WidgetList CheckBoxEngine::registeredWidgets() const { WidgetList out; - using Value = DataMap::Value; + using Value = DataMap::Value; for(const Value& value: _state) { if( value ) out.insert( value.data()->target().data() ); } return out; } //____________________________________________________________ - bool MultiStateEngine::updateState( const QObject* object, const QVariant &value ) + bool CheckBoxEngine::updateState( const QObject* object, CheckBoxState value ) { - DataMap::Value data( MultiStateEngine::data( object ) ); + DataMap::Value data( CheckBoxEngine::data( object ) ); return ( data && data.data()->updateState( value ) ); } //____________________________________________________________ - bool MultiStateEngine::isAnimated( const QObject* object) + bool CheckBoxEngine::isAnimated( const QObject* object) { - DataMap::Value data( MultiStateEngine::data( object) ); + DataMap::Value data( CheckBoxEngine::data( object) ); return ( data && data.data()->animation() && data.data()->animation().data()->isRunning() ); } //____________________________________________________________ - DataMap::Value MultiStateEngine::data(const QObject* object) const + DataMap::Value CheckBoxEngine::data(const QObject* object) const { return _state.find( object ).data(); } //____________________________________________________________ - DataMap& MultiStateEngine::dataMap() + DataMap& CheckBoxEngine::dataMap() { return _state; } } diff --git a/kstyle/animations/breezemultistateengine.h b/kstyle/animations/breezecheckboxengine.h similarity index 73% rename from kstyle/animations/breezemultistateengine.h rename to kstyle/animations/breezecheckboxengine.h index f17dcaaa..3a19705e 100644 --- a/kstyle/animations/breezemultistateengine.h +++ b/kstyle/animations/breezecheckboxengine.h @@ -1,121 +1,121 @@ -#ifndef breezemultistateengine_h -#define breezemultistateengine_h +#ifndef breezecheckboxengine_h +#define breezecheckboxengine_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 "breeze.h" #include "breezebaseengine.h" #include "breezedatamap.h" -#include "breezemultistatedata.h" +#include "breezecheckboxdata.h" namespace Breeze { - //* used for simple widgets - class MultiStateEngine: public BaseEngine + class CheckBoxEngine: public BaseEngine { Q_OBJECT public: //* constructor - explicit MultiStateEngine( QObject* parent ): + explicit CheckBoxEngine( QObject* parent ): BaseEngine( parent ) {} //* destructor - virtual ~MultiStateEngine() + virtual ~CheckBoxEngine() {} //* register widget virtual bool registerWidget( QWidget* ); //* returns registered widgets virtual WidgetList registeredWidgets() const; using BaseEngine::registeredWidgets; //* true if widget hover state is changed - virtual bool updateState( const QObject*, const QVariant & ); + virtual bool updateState(const QObject*, CheckBoxState ); virtual QVariant state( const QObject *widget) const { - DataMap::Value dataPtr = data(widget); + DataMap::Value dataPtr = data(widget); if(!dataPtr.isNull()) { return dataPtr.data()->state(); } return QVariant(); } virtual QVariant previousState( const QObject *widget) const { - DataMap::Value dataPtr = data(widget); + DataMap::Value dataPtr = data(widget); if(!dataPtr.isNull()) { return dataPtr.data()->previousState(); } return QVariant(); } //* true if widget is animated - virtual bool isAnimated( const QObject* ); + bool isAnimated( const QObject* ); - //* animation opacity - virtual qreal opacity( const QObject* object) - { return isAnimated( object) ? data( object).data()->opacity(): AnimationData::OpacityInvalid; } + qreal progress( const QObject* object) + { + return isAnimated(object) ? data(object).data()->opacity(): AnimationData::OpacityInvalid; + } //* duration - virtual void setEnabled( bool value ) + void setEnabled( bool value ) override { BaseEngine::setEnabled( value ); _state.setEnabled( value ); } //* duration - virtual void setDuration( int value ) + void setDuration( int value ) override { BaseEngine::setDuration( value ); _state.setDuration( value ); } public Q_SLOTS: //* remove widget from map - virtual bool unregisterWidget( QObject* object ) + bool unregisterWidget( QObject* object ) override { if( !object ) return false; return _state.unregisterWidget( object ); } //* returns data associated to widget - DataMap::Value data( const QObject*) const; + DataMap::Value data(const QObject*) const; protected: - DataMap &dataMap(); + DataMap &dataMap(); private: - DataMap _state; + DataMap _state; }; } #endif diff --git a/kstyle/animations/breezemultistatedata.cpp b/kstyle/animations/breezemultistatedata.cpp deleted file mode 100644 index 7f13564a..00000000 --- a/kstyle/animations/breezemultistatedata.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/************************************************************************* - * 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 "breezemultistatedata.h" - -namespace Breeze -{ - - //______________________________________________ - bool MultiStateData::updateState( const QVariant &value ) - { - if( !_initialized ) - { - - _state = value; - _initialized = true; - return false; - - } else if( _state == value ) { - - return false; - - } else { - - _previousState = _state; - _state = value; - animation().data()->setDirection(Animation::Forward); - if( !animation().data()->isRunning() ) animation().data()->start(); - return true; - - } - - } - -} diff --git a/kstyle/breeze.h b/kstyle/breeze.h index c39bfa59..608594d7 100644 --- a/kstyle/breeze.h +++ b/kstyle/breeze.h @@ -1,258 +1,258 @@ #ifndef breeze_h #define breeze_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 #include #include #include namespace Breeze { //*@name convenience typedef //@{ #if QT_VERSION >= 0x050000 //* scoped pointer convenience typedef template using WeakPointer = QPointer; #else //* scoped pointer convenience typedef template using WeakPointer = QWeakPointer; #endif //* scoped pointer convenience typedef template using ScopedPointer = QScopedPointer; //* disable QStringLiteral for older Qt version #if QT_VERSION < 0x050000 using QStringLiteral = QString; #endif //@} //* metrics enum Metrics { // frames Frame_FrameWidth = 2, Frame_FrameRadius = 3, // layout Layout_TopLevelMarginWidth = 10, Layout_ChildMarginWidth = 6, Layout_DefaultSpacing = 6, // line editors LineEdit_FrameWidth = 6, // menu items Menu_FrameWidth = 0, MenuItem_MarginWidth = 5, MenuItem_MarginHeight = 3, MenuItem_ItemSpacing = 4, MenuItem_AcceleratorSpace = 16, MenuButton_IndicatorWidth = 20, // combobox ComboBox_FrameWidth = 6, // spinbox SpinBox_FrameWidth = LineEdit_FrameWidth, SpinBox_ArrowButtonWidth = 20, // groupbox title margin GroupBox_TitleMarginWidth = 4, // buttons Button_MinWidth = 80, Button_MarginWidth = 6, Button_ItemSpacing = 4, // tool buttons ToolButton_MarginWidth = 6, ToolButton_ItemSpacing = 4, ToolButton_InlineIndicatorWidth = 12, // checkboxes and radio buttons CheckBox_Size = 22, CheckBox_FocusMarginWidth = 2, CheckBox_ItemSpacing = 4, // menubar items MenuBarItem_MarginWidth = 10, MenuBarItem_MarginHeight = 6, // scrollbars ScrollBar_Extend = 20, ScrollBar_SliderWidth = 6, ScrollBar_MinSliderHeight = 20, ScrollBar_NoButtonHeight = (ScrollBar_Extend-ScrollBar_SliderWidth)/2, ScrollBar_SingleButtonHeight = ScrollBar_Extend, ScrollBar_DoubleButtonHeight = 2*ScrollBar_Extend, // toolbars ToolBar_FrameWidth = 2, ToolBar_HandleExtent = 10, ToolBar_HandleWidth = 6, ToolBar_SeparatorWidth = 8, ToolBar_ExtensionWidth = 20, ToolBar_ItemSpacing = 0, // progressbars ProgressBar_BusyIndicatorSize = 14, ProgressBar_Thickness = 6, ProgressBar_ItemSpacing = 4, // mdi title bar TitleBar_MarginWidth = 4, // sliders Slider_TickLength = 8, Slider_TickMarginWidth = 2, Slider_GrooveThickness = 6, Slider_ControlThickness = 20, // tabbar TabBar_TabMarginHeight = 4, TabBar_TabMarginWidth = 8, TabBar_TabMinWidth = 80, TabBar_TabMinHeight = 28, TabBar_TabItemSpacing = 8, TabBar_TabOverlap = 1, TabBar_BaseOverlap = 2, // tab widget TabWidget_MarginWidth = 4, // toolbox ToolBox_TabMinWidth = 80, ToolBox_TabItemSpacing = 4, ToolBox_TabMarginWidth = 8, // tooltips ToolTip_FrameWidth = 3, // list headers Header_MarginWidth = 6, Header_ItemSpacing = 4, Header_ArrowSize = 10, // tree view ItemView_ArrowSize = 10, ItemView_ItemMarginWidth = 3, SidePanel_ItemMarginWidth = 4, // splitter Splitter_SplitterWidth = 1, // shadow dimensions Shadow_Overlap = 2 }; //* animation mode enum AnimationMode { AnimationNone = 0, AnimationHover = 0x1, AnimationFocus = 0x2, AnimationEnable = 0x4, AnimationPressed = 0x8 }; Q_DECLARE_FLAGS(AnimationModes, AnimationMode) //* corners enum Corner { CornerTopLeft = 0x1, CornerTopRight = 0x2, CornerBottomLeft = 0x4, CornerBottomRight = 0x8, CornersTop = CornerTopLeft|CornerTopRight, CornersBottom = CornerBottomLeft|CornerBottomRight, CornersLeft = CornerTopLeft|CornerBottomLeft, CornersRight = CornerTopRight|CornerBottomRight, AllCorners = CornerTopLeft|CornerTopRight|CornerBottomLeft|CornerBottomRight }; Q_DECLARE_FLAGS( Corners, Corner ) //* sides enum Side { SideLeft = 0x1, SideTop = 0x2, SideRight = 0x4, SideBottom = 0x8, AllSides = SideLeft|SideTop|SideRight|SideBottom }; Q_DECLARE_FLAGS( Sides, Side ) //* checkbox state enum CheckBoxState { + CheckUnknown, CheckOff, CheckPartial, CheckOn, - CheckAnimated }; //* radio button state enum RadioButtonState { RadioOff, RadioOn, RadioAnimated, // TODO (mglb): remove? RadioOffToOn, RadioOnToOff, }; //* arrow orientation enum ArrowOrientation { ArrowNone, ArrowUp, ArrowDown, ArrowLeft, ArrowRight }; //* button type enum ButtonType { ButtonClose, ButtonMaximize, ButtonMinimize, ButtonRestore }; } Q_DECLARE_OPERATORS_FOR_FLAGS( Breeze::AnimationModes ) Q_DECLARE_OPERATORS_FOR_FLAGS( Breeze::Corners ) Q_DECLARE_OPERATORS_FOR_FLAGS( Breeze::Sides ) Q_DECLARE_METATYPE( Breeze::CheckBoxState ) #endif diff --git a/kstyle/breezehelper.cpp b/kstyle/breezehelper.cpp index f8131111..4ba7cbf3 100644 --- a/kstyle/breezehelper.cpp +++ b/kstyle/breezehelper.cpp @@ -1,1608 +1,1498 @@ /************************************************************************* * 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 #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, nullptr, KComponentData::SkipMainComponentRegistration ), _config( _componentData.config() ) { init(); } #endif //____________________________________________________________________ KSharedConfig::Ptr Helper::config() const { return _config; } //____________________________________________________________________ void Helper::loadConfig() { _viewFocusBrush = KStatefulBrush( KColorScheme::View, KColorScheme::FocusColor ); _viewHoverBrush = KStatefulBrush( KColorScheme::View, KColorScheme::HoverColor ); _viewNegativeTextBrush = KStatefulBrush( KColorScheme::View, KColorScheme::NegativeText ); 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(); } //______________________________________________________________________________ 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, bool circle ) 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 if(!circle) { painter->drawRoundedRect( frameRect, radius, radius ); } else { painter->drawEllipse( frameRect ); } } //______________________________________________________________________________ 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 ); } //______________________________________________________________________________ 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() ); } } - //______________________________________________________________________________ - 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 { + // FIXME (mglb): use for drawing radio button control // 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 ); } } //______________________________________________________________________________ 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 ); } } //______________________________________________________________________________ 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 ); } } } //______________________________________________________________________________ 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 ); } } //______________________________________________________________________________ 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 ); } //______________________________________________________________________________ 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 ); } } //______________________________________________________________________________ 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 = QVector{QPointF( -4, 2 ), QPointF( 0, -2 ), QPointF( 4, 2 )}; break; case ArrowDown: arrow = QVector{QPointF( -4, -2 ), QPointF( 0, 2 ), QPointF( 4, -2 )}; break; case ArrowLeft: arrow = QVector{QPointF( 2, -4 ), QPointF( -2, 0 ), QPointF( 2, 4 )}; break; case ArrowRight: arrow = QVector{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(); } //______________________________________________________________________________ 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( QVector{ QPointF( 4, 11 ), QPointF( 9, 6 ), QPointF( 14, 11 )}); break; } case ButtonMinimize: { painter->drawPolyline(QVector{ QPointF( 4, 7 ), QPointF( 9, 12 ), QPointF( 14, 7 )} ); break; } case ButtonRestore: { pen.setJoinStyle( Qt::RoundJoin ); painter->setPen( pen ); painter->drawPolygon( QVector{ QPointF( 4.5, 9 ), QPointF( 9, 4.5 ), QPointF( 13.5, 9 ), QPointF( 9, 13.5 )}); break; } default: break; } painter->restore(); } //______________________________________________________________________________ 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/checkbox.cpp b/kstyle/checkbox.cpp index 02f01c02..dec12c07 100644 --- a/kstyle/checkbox.cpp +++ b/kstyle/checkbox.cpp @@ -1,328 +1,305 @@ #include "breezestyle.h" #include "breeze.h" #include "breezeanimations.h" -#include "breezemultistatedata.h" +#include "breezecheckboxdata.h" #include #include #include #include #include #include #include #include +#include namespace Breeze { - using Id = CheckMarkRenderer::DataId; - - namespace { - const QVector offStateData { - /* Position */ QPointF(0, 0), - /* LinePointPosition */ invalidPointF, invalidPointF, invalidPointF, - /* PointPosition */ invalidPointF, invalidPointF, invalidPointF, - /* PointRadius */ 0.0f, 0.0f, 0.0f - }; - const QVector onStateData = { - /* Position */ QPointF(-1, 3), - /* LinePointPosition */ QPointF(-3, -3), QPointF(0, 0), QPointF(5, -5), - /* PointPosition */ invalidPointF, invalidPointF, invalidPointF, - /* PointRadius */ 0.0f, 0.0f, 0.0f, - }; - const QVector partialStateData = { - /* Position */ QPointF(0, 0), - /* LinePointPosition */ invalidPointF, invalidPointF, invalidPointF, - /* PointPosition */ QPointF(-4, 0), QPointF( 0, 0), QPointF(4, 0), - /* PointRadius */ 1.0f, 1.0f, 1.0f, - }; - - const TimelineAnimation::EntryList offToOnTransition { - {0.0f, &offStateData}, - {0.0f, Id::Position, onStateData[Id::Position]}, - {0.0f, Id::LinePointPosition_0, onStateData[Id::LinePointPosition_0]}, - {0.0f, 0.4f, Id::LinePointPosition_1, onStateData[Id::LinePointPosition_0], onStateData[Id::LinePointPosition_1], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::LinePointPosition_2, onStateData[Id::LinePointPosition_1], onStateData[Id::LinePointPosition_2], QEasingCurve::InOutCubic}, - {1.0f, &onStateData}, - }; - const TimelineAnimation::EntryList onToOffTransition { - {0.0f, &onStateData}, - {0.0f, 0.5f, Id::LinePointPosition_0, onStateData[Id::LinePointPosition_0], onStateData[Id::LinePointPosition_1], QEasingCurve::InOutCubic}, - {0.6f, 0.4f, Id::LinePointPosition_0, onStateData[Id::LinePointPosition_1], onStateData[Id::LinePointPosition_2], QEasingCurve::InOutCubic}, - {0.6f, 0.4f, Id::LinePointPosition_1, onStateData[Id::LinePointPosition_1], onStateData[Id::LinePointPosition_2], QEasingCurve::InOutCubic}, - {1.0f, &offStateData}, - }; - - const TimelineAnimation::EntryList offToPartialTransition { - {0.0f, &offStateData}, - {0.0f, Id::PointPosition_0, partialStateData[Id::PointPosition_0]}, - {0.0f, Id::PointPosition_1, partialStateData[Id::PointPosition_1]}, - {0.0f, Id::PointPosition_2, partialStateData[Id::PointPosition_2]}, - {0.0f, 0.6f, Id::PointRadius_0, QVariant(), partialStateData[Id::PointRadius_0], QEasingCurve::OutCubic}, - {0.2f, 0.6f, Id::PointRadius_1, QVariant(), partialStateData[Id::PointRadius_1], QEasingCurve::OutCubic}, - {0.4f, 0.6f, Id::PointRadius_2, QVariant(), partialStateData[Id::PointRadius_2], QEasingCurve::OutCubic}, - {1.0f, &partialStateData}, - }; - const TimelineAnimation::EntryList partialToOffTransition { - {0.0f, &partialStateData}, - {0.0f, 0.6f, Id::PointRadius_0, partialStateData[Id::PointRadius_0], offStateData[Id::PointRadius_0], QEasingCurve::InCubic}, - {0.2f, 0.6f, Id::PointRadius_1, partialStateData[Id::PointRadius_1], offStateData[Id::PointRadius_1], QEasingCurve::InCubic}, - {0.4f, 0.6f, Id::PointRadius_2, partialStateData[Id::PointRadius_2], offStateData[Id::PointRadius_2], QEasingCurve::InCubic}, - {1.0f, &offStateData}, - }; - - const float partialPointRadiusSqrt2 = partialStateData[Id::PointRadius_0].toFloat() * sqrtf(2); - const float partialPointRadiusSqrt3 = partialStateData[Id::PointRadius_0].toFloat() * sqrtf(3); - const QPointF onAbsLinePointPosition_2 = onStateData[Id::LinePointPosition_2].toPointF() + onStateData[Id::Position].toPointF(); - - const TimelineAnimation::EntryList partialToOnTransition { - {0.0f, &partialStateData}, - {0.0f, Id::Position, onStateData[Id::Position]}, - {0.0f, Id::LinePointPosition_0, onStateData[Id::LinePointPosition_0]}, - - {0.0f, 0.4f, Id::LinePointPosition_1, onStateData[Id::LinePointPosition_0], onStateData[Id::LinePointPosition_1], QEasingCurve::InOutCubic}, - {0.0f, 0.4f, Id::PointRadius_0, QVariant(), onStateData[Id::PointRadius_0], QEasingCurve::InOutCubic}, - {0.0f, 0.5f, Id::PointPosition_1, QVariant(), onStateData[Id::Position], QEasingCurve::InOutCubic}, - {0.0f, 0.5f, Id::PointPosition_2, QVariant(), onStateData[Id::Position], QEasingCurve::InOutCubic}, - {0.0f, 0.5f, Id::PointRadius_1, QVariant(), partialPointRadiusSqrt2, QEasingCurve::InOutCubic}, - {0.0f, 0.5f, Id::PointRadius_2, QVariant(), partialPointRadiusSqrt2, QEasingCurve::InOutCubic}, - - {0.5f, 0.5f, Id::LinePointPosition_2, onStateData[Id::LinePointPosition_1], onStateData[Id::LinePointPosition_2], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointPosition_2, QVariant(), onAbsLinePointPosition_2, QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointRadius_1, QVariant(), onStateData[Id::PointRadius_1], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointRadius_2, QVariant(), onStateData[Id::PointRadius_2], QEasingCurve::InOutCubic}, - {1.0f, &onStateData}, - }; - const TimelineAnimation::EntryList onToPartialTransition { - {0.0f, &onStateData}, - {0.0f, 0.4f, Id::Position, QVariant(), partialStateData[Id::Position], QEasingCurve::InOutCubic}, - {0.0f, 0.4f, Id::LinePointPosition_0, QVariant(), onStateData[Id::LinePointPosition_1], QEasingCurve::InOutCubic}, - {0.0f, 0.4f, Id::LinePointPosition_2, QVariant(), onStateData[Id::LinePointPosition_1], QEasingCurve::InOutCubic}, - {0.0f, 0.4f, Id::PointPosition_1, onStateData[Id::Position], partialStateData[Id::PointPosition_1], QEasingCurve::InOutCubic}, - {0.0f, 0.4f, Id::PointRadius_1, QVariant(), partialPointRadiusSqrt3, QEasingCurve::InOutCubic}, - - {0.5f, 0.5f, Id::PointPosition_0, partialStateData[Id::PointPosition_1], partialStateData[Id::PointPosition_0], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointPosition_2, partialStateData[Id::PointPosition_1], partialStateData[Id::PointPosition_2], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointRadius_0, partialPointRadiusSqrt3, partialStateData[Id::PointRadius_0], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointRadius_1, partialPointRadiusSqrt3, partialStateData[Id::PointRadius_1], QEasingCurve::InOutCubic}, - {0.5f, 0.5f, Id::PointRadius_2, partialPointRadiusSqrt3, partialStateData[Id::PointRadius_2], QEasingCurve::InOutCubic}, - {1.0f, &partialStateData}, - }; - } - static void renderCheckMark(QPainter *painter, const QPoint &position, const QColor &color, - const QVector &vars) + const CheckBoxRenderState &s) { painter->setBrush(Qt::NoBrush); painter->setPen(QPen(color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); QPainterPath pp; - const QPointF relPosition = vars[Id::Position].toPointF(); - const QPointF linePointPos[] = { - vars[Id::LinePointPosition_0].toPointF(), - vars[Id::LinePointPosition_1].toPointF(), - vars[Id::LinePointPosition_2].toPointF(), - }; - const QPointF pointPos[] = { - vars[Id::PointPosition_0].toPointF(), - vars[Id::PointPosition_1].toPointF(), - vars[Id::PointPosition_2].toPointF(), - }; - const float pointRadius[] = { - vars[Id::PointRadius_0].toFloat(), - vars[Id::PointRadius_1].toFloat(), - vars[Id::PointRadius_2].toFloat(), - }; + const QPointF linePointPosition[] = {s.linePointPosition0, s.linePointPosition1, s.linePointPosition2}; + const QPointF pointPosition[] = {s.pointPosition0, s.pointPosition1, s.pointPosition2}; + const qreal pointRadius[] = {s.pointRadius0, s.pointRadius1, s.pointRadius2}; int i = 0; for(; i < 3; ++i) { - if(!isInvalidPointF(linePointPos[i])) { - pp.moveTo(linePointPos[i]); + if(!isInvalidPointF(linePointPosition[i])) { + pp.moveTo(linePointPosition[i]); break; } } for(; i < 3; ++i) { - if(!isInvalidPointF(linePointPos[i])) { - pp.lineTo(linePointPos[i]); + if(!isInvalidPointF(linePointPosition[i])) { + pp.lineTo(linePointPosition[i]); } } - pp.translate(relPosition + position); + pp.translate(s.position + position); painter->drawPath(pp); painter->setPen(Qt::NoPen); for (int i = 0; i < 3; ++i) { - if (isInvalidPointF(pointPos[i]) || qFuzzyIsNull(pointRadius[i])) { + if (isInvalidPointF(pointPosition[i]) || qFuzzyIsNull(pointRadius[i])) { continue; } painter->setBrush(color); - painter->drawEllipse(pointPos[i] + position, pointRadius[i], pointRadius[i]); + painter->drawEllipse(pointPosition[i] + position, pointRadius[i], pointRadius[i]); } } +//______________________________________________________________________________ +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 +{ + // FIXME (mglb): use for drawing radio button control + + // 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 ); + + } + +} + //___________________________________________________________________________________ void Style::drawChoicePrimitive(const QStyleOption *option, QPainter *painter, const QWidget* widget, bool isRadioButton) const { // 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 ) ); - // FIXME (mglb): move to some animation engine - QVariant lastStateVariant = widget ? widget->property("_breeze_lastState") : QVariant(); - int lastState; - if(lastStateVariant.isValid()) { - lastState = lastStateVariant.toInt(); - } else { - lastState = option->state & (State_On | State_NoChange | State_Off); - } - if(widget) { - auto *widgetRw = const_cast(widget); - widgetRw->setProperty("_breeze_lastState", QVariant(option->state & (State_On | State_NoChange | State_Off))); - } - // focus takes precedence over mouse over _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); // retrieve animation mode and opacity const AnimationMode mode( _animations->widgetStateEngine().frameAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().frameOpacity( widget ) ); // Render background and frame // Foreground and background color const auto &normalBackground = palette.color(QPalette::Base); const auto &normalForeground = palette.color(QPalette::Text); const auto &focusBackground = palette.color(QPalette::Highlight); const auto &focusForeground = palette.color(QPalette::HighlightedText); const auto focusOpacityOrInvalid = _animations->widgetStateEngine().opacity(widget, AnimationFocus); const auto focusOpacity = focusOpacityOrInvalid != AnimationData::OpacityInvalid ? focusOpacityOrInvalid : 1.0 * int(hasFocus); const auto background = KColorUtils::mix(normalBackground, focusBackground, focusOpacity); const auto foreground = hasFocus ? focusForeground : normalForeground; // Frame color - hover priority QColor outline = _helper->frameOutlineColor(palette, mouseOver, hasFocus, opacity, mode); _helper->renderFrame( painter, rect.adjusted(0, 0, -0, -0), background, outline , isRadioButton); // Render mark static const auto inQuadEasingCurve = [](qreal v) { return v*v; }; static const auto outQuadEasingCurve = [](qreal v) { return 1.0-inQuadEasingCurve(1.0-v); }; painter->setRenderHint( QPainter::Antialiasing, true ); if(isRadioButton) { RadioButtonState radioButtonState = state & State_On ? RadioOn : RadioOff; _animations->widgetStateEngine().updateState( widget, AnimationPressed, radioButtonState != RadioOff ); if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) { radioButtonState = radioButtonState == RadioOn ? RadioOffToOn : RadioOnToOff; } const qreal animation = _animations->widgetStateEngine().opacity( widget, AnimationPressed ); if(radioButtonState == RadioOff) { return; } /* painter->setBrush( Qt::NoBrush ); painter->setPen( QPen(foreground, 4, Qt::SolidLine, Qt::RoundCap) ); */ const QPointF center = {rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0}; const qreal fullRadius = 4.0; if(radioButtonState == RadioOn) { painter->setBrush( foreground ); painter->setPen( Qt::NoPen ); painter->drawEllipse(center, fullRadius, fullRadius); } else { qreal radius; QColor color = foreground; if(radioButtonState == RadioOffToOn) { radius = outQuadEasingCurve(animation) * fullRadius; color.setAlphaF(outQuadEasingCurve(animation)); painter->setBrush(color); painter->setPen( Qt::NoPen ); } else { qreal penWidth = fullRadius * inQuadEasingCurve(animation); radius = fullRadius / 2.0 + ((rect.width() - fullRadius) / 2 - 2) * outQuadEasingCurve(1.0-animation); color.setAlphaF(inQuadEasingCurve(animation)); painter->setBrush(Qt::NoBrush); painter->setPen(QPen(color, penWidth)); } painter->drawEllipse(center, radius, radius); } } else { const CheckBoxState checkBoxState = state & State_NoChange ? CheckPartial : state & State_On ? CheckOn : CheckOff; bool startAnim = (checkBoxState != _animations->multiStateEngine().state(widget).value()); _animations->multiStateEngine().updateState(widget, checkBoxState); const QVariant lastStateVariant = _animations->multiStateEngine().previousState(widget); const CheckBoxState previousCheckBoxState = lastStateVariant.isValid() ? lastStateVariant.value() - : CheckBoxState::CheckOff; + : CheckBoxState::CheckUnknown; - qreal progress = _animations->multiStateEngine().opacity(widget); + qreal progress = _animations->multiStateEngine().progress(widget); if(!_animations->multiStateEngine().isAnimated(widget)) { progress = 1.0; } const QPoint centerOffset = {rect.width()/2 + rect.x(), rect.height()/2 + rect.y()}; - DataMap::Value dataPtr = _animations->multiStateEngine().data(widget); + DataMap::Value dataPtr = _animations->multiStateEngine().data(widget); - static const auto stateToData = [](CheckBoxState state) -> const QVector * { + static const auto stateToData = [](CheckBoxState state) -> const CheckBoxRenderState * { switch(state) { - case CheckOff: return &offStateData; - case CheckOn: return &onStateData; - case CheckPartial: return &partialStateData; + case CheckUnknown: + case CheckOff: return &CheckBoxData::offState; + case CheckOn: return &CheckBoxData::onState; + case CheckPartial: return &CheckBoxData::partialState; }; return nullptr; }; - const QVector *vars = nullptr; + const CheckBoxRenderState *state = nullptr; if (dataPtr.isNull()) { - vars = stateToData(checkBoxState); - Q_CHECK_PTR(vars); + state = stateToData(checkBoxState); + Q_CHECK_PTR(state); } else { - MultiStateData *data = dataPtr.data(); - vars = &data->variables; - if(data->variables.isEmpty()) { + CheckBoxData *data = dataPtr.data(); + state = &data->renderState; + if(previousCheckBoxState == CheckBoxState::CheckUnknown) { // First rendering. Don't animate, it is initial state. - data->variables = *q_check_ptr(stateToData(checkBoxState)); + data->renderState = *q_check_ptr(stateToData(checkBoxState)); } else { if (startAnim) { data->timeline->stop(); - if (previousCheckBoxState == CheckOff && checkBoxState == CheckOn) { data->timeline->setTransitions(&offToOnTransition); } - if (previousCheckBoxState == CheckOn && checkBoxState == CheckOff) { data->timeline->setTransitions(&onToOffTransition); } - if (previousCheckBoxState == CheckOff && checkBoxState == CheckPartial) { data->timeline->setTransitions(&offToPartialTransition); } - if (previousCheckBoxState == CheckPartial && checkBoxState == CheckOff) { data->timeline->setTransitions(&partialToOffTransition); } - if (previousCheckBoxState == CheckPartial && checkBoxState == CheckOn) { data->timeline->setTransitions(&partialToOnTransition); } - if (previousCheckBoxState == CheckOn && checkBoxState == CheckPartial) { data->timeline->setTransitions(&onToPartialTransition); } + if (previousCheckBoxState == CheckOff && checkBoxState == CheckOn) { data->timeline->setTransitions(&CheckBoxData::offToOnTransition); } + if (previousCheckBoxState == CheckOn && checkBoxState == CheckOff) { data->timeline->setTransitions(&CheckBoxData::onToOffTransition); } + if (previousCheckBoxState == CheckOff && checkBoxState == CheckPartial) { data->timeline->setTransitions(&CheckBoxData::offToPartialTransition); } + if (previousCheckBoxState == CheckPartial && checkBoxState == CheckOff) { data->timeline->setTransitions(&CheckBoxData::partialToOffTransition); } + if (previousCheckBoxState == CheckPartial && checkBoxState == CheckOn) { data->timeline->setTransitions(&CheckBoxData::partialToOnTransition); } + if (previousCheckBoxState == CheckOn && checkBoxState == CheckPartial) { data->timeline->setTransitions(&CheckBoxData::onToPartialTransition); } data->timeline->start(); } } } - renderCheckMark(painter, centerOffset, foreground, *vars); + renderCheckMark(painter, centerOffset, foreground, *state); } } }