diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 0000000..bc0df43 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "phabricator.uri" : "https://phabricator.kde.org/" +} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7dfef6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.kdev4 +build +CMakeLists.txt.user* + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..38e4151 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +Cursors: + Ken Vermette + +Kstyle: + Hugo Pereira Da Costa - Developer + Andrew Lake - Designer diff --git a/AdwaitaConfig.cmake.in b/AdwaitaConfig.cmake.in new file mode 100644 index 0000000..c112d26 --- /dev/null +++ b/AdwaitaConfig.cmake.in @@ -0,0 +1,10 @@ +@PACKAGE_INIT@ + +set(ADWAITA_WITH_KDECORATION @WITH_DECORATIONS@) +if(${ADWAITA_WITH_KDECORATION}) + set(ADWAITA_KDECORATION_PLUGIN_ID "org.kde.adwaita") +else() + set(ADWAITA_KDECORATION_PLUGIN_ID "") +endif() + +set(ADWAITA_STYLE_NAME "adwaita") diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d32b0cd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,51 @@ +project(Adwaita) +cmake_minimum_required(VERSION 2.8.11) +set(CMAKE_AUTOMOC ON) +add_definitions(-std=c++11) + +option(USE_QT4 "Use Qt4 instead of Qt5" OFF) +if (USE_QT4) + find_package(Qt4 REQUIRED) + set(QT_VERSION_NUMBER "4") +else() + find_package(Qt5Core REQUIRED) + find_package(Qt5Gui REQUIRED) + find_package(Qt5Widgets REQUIRED) + find_package(Qt5DBus REQUIRED) + set(QT_QTGUI_LIBRARY Qt5::Gui Qt5::Widgets) + set(QT_QTCORE_LIBRARY Qt5::Core) + set(QT_QTDBUS_LIBRARY Qt5::DBus) + #target_link_libraries(${LIBRARY_NAME} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) + set(QT_VERSION_NUMBER "5") + get_target_property(REAL_QMAKE_EXECUTABLE ${Qt5Core_QMAKE_EXECUTABLE} + IMPORTED_LOCATION) + if (NOT QT_PLUGINS_DIR) + execute_process(COMMAND "${REAL_QMAKE_EXECUTABLE}" -query QT_INSTALL_PLUGINS + OUTPUT_VARIABLE QT_PLUGINS_DIR + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() +endif() + +if (NOT CMAKE_INSTALL_PREFIX) + set (CMAKE_INSTALL_PREFIX "/usr/local") +endif() + +if (NOT DATA_INSTALL_DIR) + set (DATA_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share") +endif() +if (NOT THEME_INSTALL_DIR) + set (THEME_INSTALL_DIR "${DATA_INSTALL_DIR}/themes") +endif() + +set(ADWAITA_THEME_DIR "${THEME_INSTALL_DIR}/Adwaita/qt") + +option(BUILD_EXAMPLE "Build an example widget factory app" OFF) +if (BUILD_EXAMPLE) + if (USE_QT4) + find_package(KDE4) + else() + error("It's not possible to build the example using Qt5 yet, sorry.") + endif() +endif() + +add_subdirectory(style) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5185fd3 --- /dev/null +++ b/COPYING @@ -0,0 +1,346 @@ +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde programs) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/COPYING-ICONS b/COPYING-ICONS new file mode 100644 index 0000000..7ae69ed --- /dev/null +++ b/COPYING-ICONS @@ -0,0 +1,209 @@ +The Adwaita Icon Theme in icons/ + + Copyright (C) 2014 Uri Herrera and others + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . + +Clarification: + + The GNU Lesser General Public License or LGPL is written for + software libraries in the first place. We expressly want the LGPL to + be valid for this artwork library too. + + KDE Adwaita theme icons is a special kind of software library, it is an + artwork library, it's elements can be used in a Graphical User Interface, or + GUI. + + Source code, for this library means: + - where they exist, SVG; + - otherwise, if applicable, the multi-layered formats xcf or psd, or + otherwise png. + + The LGPL in some sections obliges you to make the files carry + notices. With images this is in some cases impossible or hardly useful. + + With this library a notice is placed at a prominent place in the directory + containing the elements. You may follow this practice. + + The exception in section 5 of the GNU Lesser General Public License covers + the use of elements of this art library in a GUI. + + https://vdesign.kde.org/ + +----- + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/LICENSE.GPL2 b/LICENSE.GPL2 new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE.GPL2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSE.LGPL2 b/LICENSE.LGPL2 new file mode 100644 index 0000000..ec47efc --- /dev/null +++ b/LICENSE.LGPL2 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..6f1251d --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +adwaita-qt +========== + +A native style to bend Qt4 and Qt5 applications to look like they belong into GNOME Shell. + +![Widget Factory](/screenshots/widgets.png) + +![KCalc](/screenshots/kcalc.png) + +## How to compile + +The project uses the standard CMake buildsystem. + +So for example, the whole compilation process could look like this: + +``` +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. +make +make install +``` + +## Usage + +After install, you'll be able to either set the theme as your default via your DE's tools (like `systemsettings` or `qt-config`) or start your qt applications with the `-style adwaita` parameter. diff --git a/cmake/GtkUpdateIconCache.cmake b/cmake/GtkUpdateIconCache.cmake new file mode 100644 index 0000000..4be82c7 --- /dev/null +++ b/cmake/GtkUpdateIconCache.cmake @@ -0,0 +1,21 @@ +# Copyright 2015 Volker Krause +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file COPYING-CMAKE-SCRIPTS for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. + +find_program(GTK_UPDATE_ICON_CACHE_EXECUTABLE NAMES gtk-update-icon-cache) + +macro(gtk_update_icon_cache _dir) + if (GTK_UPDATE_ICON_CACHE_EXECUTABLE) + install(CODE " + set(DESTDIR_VALUE \"\$ENV{DESTDIR}\") + if (NOT DESTDIR_VALUE) + execute_process(COMMAND ${GTK_UPDATE_ICON_CACHE_EXECUTABLE} -q -i . WORKING_DIRECTORY ${_dir}) + endif() + ") + endif() +endmacro() diff --git a/screenshots/kcalc.png b/screenshots/kcalc.png new file mode 100644 index 0000000..d596f1b Binary files /dev/null and b/screenshots/kcalc.png differ diff --git a/screenshots/widgets.png b/screenshots/widgets.png new file mode 100644 index 0000000..38310a2 Binary files /dev/null and b/screenshots/widgets.png differ diff --git a/style/CMakeLists.txt b/style/CMakeLists.txt new file mode 100644 index 0000000..ff646ba --- /dev/null +++ b/style/CMakeLists.txt @@ -0,0 +1,64 @@ + + + +configure_file(config-adwaita.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-adwaita.h ) + +set(Adwaita_SRCS + animations/adwaitaanimation.cpp + animations/adwaitaanimations.cpp + animations/adwaitaanimationdata.cpp + animations/adwaitabaseengine.cpp + animations/adwaitabusyindicatordata.cpp + animations/adwaitabusyindicatorengine.cpp + animations/adwaitadialdata.cpp + animations/adwaitadialengine.cpp + animations/adwaitaenabledata.cpp + animations/adwaitagenericdata.cpp + animations/adwaitaheaderviewdata.cpp + animations/adwaitaheaderviewengine.cpp + animations/adwaitascrollbardata.cpp + animations/adwaitascrollbarengine.cpp + animations/adwaitaspinboxengine.cpp + animations/adwaitaspinboxdata.cpp + animations/adwaitastackedwidgetdata.cpp + animations/adwaitastackedwidgetengine.cpp + animations/adwaitatabbarengine.cpp + animations/adwaitatabbardata.cpp + animations/adwaitatoolboxengine.cpp + animations/adwaitatransitiondata.cpp + animations/adwaitatransitionwidget.cpp + animations/adwaitawidgetstateengine.cpp + animations/adwaitawidgetstatedata.cpp + debug/adwaitawidgetexplorer.cpp + adwaitaaddeventfilter.cpp + adwaitahelper.cpp + adwaitamnemonics.cpp + adwaitapropertynames.cpp + adwaitasplitterproxy.cpp + adwaitastyle.cpp + adwaitastyleplugin.cpp + adwaitatileset.cpp + adwaitawindowmanager.cpp + fakeadwaitastyleconfigdata.cpp +) +add_definitions(-DQT_PLUGIN) + +include_directories( + ${QT_INCLUDES} + ${CMAKE_CURRENT_BINARY_DIR} + . + animations + debug +) + +set(LIBRARY_NAME "adwaita-qt${QT_VERSION_NUMBER}") + +add_library(${LIBRARY_NAME} MODULE ${Adwaita_SRCS}) +target_link_libraries(${LIBRARY_NAME} ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTDBUS_LIBRARY}) +set_target_properties(${LIBRARY_NAME} PROPERTIES + LINK_FLAGS "-Wl,--no-undefined" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + OUTPUT_NAME "adwaita" + PREFIX "") + +install(TARGETS ${LIBRARY_NAME} DESTINATION "${QT_PLUGINS_DIR}/styles") diff --git a/style/adwaita.h b/style/adwaita.h new file mode 100644 index 0000000..8aaece0 --- /dev/null +++ b/style/adwaita.h @@ -0,0 +1,269 @@ +#ifndef adwaita_h +#define adwaita_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 Adwaita +{ + + //*@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 + + //@} + + //* Settings + namespace Settings + { + + const bool SingleClick { true }; + const bool ShowIconsOnPushButtons { true }; + const int ToolButtonStyle { Qt::ToolButtonTextBesideIcon }; + const bool ShowIconsInMenuItems { true }; + + } + + //* metrics + enum Metrics + { + + // frames + Frame_FrameWidth = 4, + Frame_FrameRadius = 4, + + // layout + Layout_TopLevelMarginWidth = 10, + Layout_ChildMarginWidth = 6, + Layout_DefaultSpacing = 6, + + // line editors + LineEdit_FrameWidth = 7, + + // menu items + Menu_FrameWidth = 0, + MenuItem_MarginWidth = 5, + MenuItem_ItemSpacing = 4, + MenuItem_AcceleratorSpace = 16, + MenuButton_IndicatorWidth = 20, + + // combobox + ComboBox_FrameWidth = 7, + + // spinbox + SpinBox_FrameWidth = LineEdit_FrameWidth, + SpinBox_ArrowButtonWidth = 20, + + // groupbox title margin + GroupBox_TitleMarginWidth = 4, + + // buttons + Button_MinWidth = 80, + Button_MarginWidth = 4, + Button_ItemSpacing = 3, + + // tool buttons + ToolButton_MarginWidth = 6, + ToolButton_ItemSpacing = 4, + ToolButton_InlineIndicatorWidth = 12, + + // checkboxes and radio buttons + CheckBox_Size = 20, + CheckBox_FocusMarginWidth = 3, + CheckBox_ItemSpacing = 4, + + // menubar items + MenuBarItem_MarginWidth = 8, + MenuBarItem_MarginHeight = 4, + + // scrollbars + ScrollBar_Extend = 14, + ScrollBar_SliderWidth = 8, + ScrollBar_MinSliderHeight = 24, + ScrollBar_NoButtonHeight = (ScrollBar_Extend-ScrollBar_SliderWidth)/2, + ScrollBar_SingleButtonHeight = 0, + ScrollBar_DoubleButtonHeight = 0, + + // toolbars + ToolBar_FrameWidth = 2, + ToolBar_HandleExtent = 10, + ToolBar_HandleWidth = 6, + ToolBar_SeparatorWidth = 8, + ToolBar_ExtensionWidth = 20, + ToolBar_ItemSpacing = 0, + + // progressbars + ProgressBar_BusyIndicatorSize = 24, + ProgressBar_Thickness = 3, + ProgressBar_ItemSpacing = 3, + + // mdi title bar + TitleBar_MarginWidth = 4, + + // sliders + Slider_TickLength = 4, + Slider_TickMarginWidth = 6, + Slider_GrooveThickness = 3, + Slider_ControlThickness = 24, + + // tabbar + TabBar_TabMarginHeight = 9, + TabBar_TabMarginWidth = 8, + TabBar_TabMinWidth = 80, + TabBar_TabMinHeight = 36, + TabBar_TabItemSpacing = 8, + TabBar_TabOverlap = 1, + TabBar_BaseOverlap = 0, + + // tab widget + TabWidget_MarginWidth = 4, + + // toolbox + ToolBox_TabMinWidth = 80, + ToolBox_TabItemSpacing = 4, + ToolBox_TabMarginWidth = 8, + + // tooltips + ToolTip_FrameWidth = 3, + + // scroll areas + ScrollArea_FrameWidth = 2, + + // list headers + Header_MarginWidth = 3, + Header_ItemSpacing = 2, + Header_ArrowSize = 10, + + // tree view + ItemView_ArrowSize = 10, + ItemView_ItemMarginWidth = 3, + SidePanel_ItemMarginWidth = 4, + + // splitter + Splitter_SplitterWidth = 1, + + // shadow dimensions + Shadow_Overlap = 0 + + }; + + //* 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 + { + SideNone = 0x0, + SideLeft = 0x1, + SideTop = 0x2, + SideRight = 0x4, + SideBottom = 0x8, + AllSides = SideLeft|SideTop|SideRight|SideBottom + }; + + Q_DECLARE_FLAGS( Sides, Side ) + + //* checkbox state + enum CheckBoxState + { + CheckOff, + CheckPartial, + CheckOn, + CheckAnimated + }; + + //* radio button state + enum RadioButtonState + { + RadioOff, + RadioOn, + RadioAnimated + }; + + //* arrow orientation + enum ArrowOrientation + { + ArrowNone, + ArrowUp, + ArrowDown, + ArrowLeft, + ArrowRight + }; + + //* button type + enum ButtonType + { + ButtonClose, + ButtonMaximize, + ButtonMinimize, + ButtonRestore + }; + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS( Adwaita::AnimationModes ) +Q_DECLARE_OPERATORS_FOR_FLAGS( Adwaita::Corners ) +Q_DECLARE_OPERATORS_FOR_FLAGS( Adwaita::Sides ) + +#endif diff --git a/style/adwaita.json b/style/adwaita.json new file mode 100644 index 0000000..64fc989 --- /dev/null +++ b/style/adwaita.json @@ -0,0 +1 @@ +{ "Keys": [ "Adwaita", "Adwaita-Dark" ] } diff --git a/style/adwaita.kcfg b/style/adwaita.kcfg new file mode 100644 index 0000000..78690b1 --- /dev/null +++ b/style/adwaita.kcfg @@ -0,0 +1,189 @@ + + + + + + + + + + + 90 + 25 + 255 + + + + 16 + 6 + 64 + + + + 0, 0, 0 + + + + + true + + + + + + + + + + true + + + + 10 + + + + 100 + + + + + false + + + + + true + + + + + 800 + + + + + 1 + + + + 1 + + + + + true + + + + + + + + + + MN_AUTO + + + + + true + + + + + true + + + + + true + + + + + true + + + + false + + + + + false + + + + + false + + + + false + + + + false + + + + true + + + + + + + + + + WD_FULL + + + + + + + + + + + + + + + true + + + + + true + + + + 12 + + + + + false + + + + false + + + + + diff --git a/style/adwaita.themerc b/style/adwaita.themerc new file mode 100644 index 0000000..2be74ad --- /dev/null +++ b/style/adwaita.themerc @@ -0,0 +1,5 @@ +[Misc] +Name=Adwaita +Comment=Qt widget style for GNOME +[KDE] +WidgetStyle=Adwaita diff --git a/style/adwaitaaddeventfilter.cpp b/style/adwaitaaddeventfilter.cpp new file mode 100644 index 0000000..76677e5 --- /dev/null +++ b/style/adwaitaaddeventfilter.cpp @@ -0,0 +1,20 @@ +/************************************************************************* + * 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 "adwaitaaddeventfilter.h" diff --git a/style/adwaitaaddeventfilter.h b/style/adwaitaaddeventfilter.h new file mode 100644 index 0000000..4ac920c --- /dev/null +++ b/style/adwaitaaddeventfilter.h @@ -0,0 +1,54 @@ +#ifndef adwaitaaddeventfilter_h +#define adwaitaaddeventfilter_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 + +namespace Adwaita +{ + + class AddEventFilter: public QObject + { + + Q_OBJECT + + public: + + //* constructor + AddEventFilter( void ): + QObject() + {} + + //* destructor + virtual ~AddEventFilter( void ) + {} + + //* event filter + /** blocks all AddChild events */ + virtual bool eventFilter( QObject*, QEvent* event ) + { return event->type() == QEvent::ChildAdded; } + + }; + +} + +#endif diff --git a/style/adwaitahelper.cpp b/style/adwaitahelper.cpp new file mode 100644 index 0000000..658f220 --- /dev/null +++ b/style/adwaitahelper.cpp @@ -0,0 +1,1748 @@ +/************************************************************************* + * 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 "adwaitahelper.h" + +#include "adwaita.h" +#include "fakeadwaitastyleconfigdata.h" + +#include +#include +#include + +#if ADWAITA_HAVE_X11 && QT_VERSION < 0x050000 +#include +#endif + +namespace Adwaita +{ + + //* contrast for arrow and treeline rendering + static const qreal arrowShade = 0.15; + + //____________________________________________________________________ + Helper::Helper( ) + { init(); } + + //____________________________________________________________________ + #if ADWAITA_USE_KDE4 + Helper::Helper( const QByteArray& name ) + { init(); } + #endif + + //____________________________________________________________________ + QColor Helper::frameOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const + { + + // I really can't remember why we have differed these two cases. This seems right. + return inputOutlineColor(palette, mouseOver, hasFocus, opacity, mode); + + } + + QColor Helper::inputOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const + { + QColor outline( buttonOutlineColor( palette, mouseOver, false ) ); + QColor focus( palette.color( QPalette::Active, QPalette::Highlight ) ); + + + // focus takes precedence over hover + if( mode == AnimationFocus ) + { + + outline = mix( outline, focus, opacity ); + + } else if( hasFocus ) { + + outline = focusColor( palette ); + + } + + return outline; + } + + //____________________________________________________________________ + QColor Helper::focusOutlineColor( const QPalette& palette ) const + { return mix( focusColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); } + + //____________________________________________________________________ + QColor Helper::hoverOutlineColor( const QPalette& palette ) const + { return mix( hoverColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); } + + //____________________________________________________________________ + QColor Helper::buttonFocusOutlineColor( const QPalette& palette ) const + { return mix( focusColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); } + + //____________________________________________________________________ + QColor Helper::buttonHoverOutlineColor( const QPalette& palette ) const + { return 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 = mix( outline, focus, opacity ); + + } else if( hasFocus ) { + + outline = focus; + + } + + return outline; + + } + + //____________________________________________________________________ + QColor Helper::frameBackgroundColor( const QPalette& palette, QPalette::ColorGroup group ) const + { return 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 mix( palette.color( group, QPalette::Text ), palette.color( group, QPalette::Base ), arrowShade ); + case QPalette::WindowText: return mix( palette.color( group, QPalette::WindowText ), palette.color( group, QPalette::Window ), arrowShade ); + case QPalette::ButtonText: return 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 + { + + Q_UNUSED(mouseOver); + Q_UNUSED(hasFocus); + Q_UNUSED(opacity); + Q_UNUSED(mode); + return palette.text().color(); + + } + + //____________________________________________________________________ + QColor Helper::buttonOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const + { + + QColor outline( mix( palette.color( QPalette::Button ), palette.color( QPalette::Shadow ), 0.3 ) ); + + return outline; + + } + + //____________________________________________________________________ + QColor Helper::buttonBackgroundColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const + { + + QColor background( palette.color( QPalette::Button ) ); + + if ( mode == AnimationPressed) { + background = background.darker(100 + 15.0 * opacity); + } else if ( sunken ) { + background = background.darker(115); + } else if( mode == AnimationHover ) + { + background = mix(background, background.lighter( 120 ), opacity); + //if( hasFocus ) background = mix( focus, hover, opacity ); + + } else if( mouseOver ) { + + background = background.lighter( 120 ); + //background = hoverColor( palette ); + } + + return background; + + } + + //____________________________________________________________________ + QColor Helper::toolButtonColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const + { + + if (sunken || (mode != AnimationNone && mode != AnimationHover) ) + return buttonBackgroundColor(palette, mouseOver, hasFocus, sunken, opacity, mode); + return Qt::transparent; + + } + + //____________________________________________________________________ + QColor Helper::sliderOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const + { + + QColor outline( mix( palette.color( QPalette::Window ), palette.color( QPalette::Shadow ), 0.5 ) ); + + // hover takes precedence over focus + if( mode == AnimationHover ) + { + + QColor hover( hoverColor( palette ) ); + QColor focus( focusColor( palette ) ); + if( hasFocus ) outline = mix( focus, hover, opacity ); + else outline = mix( outline, hover, opacity ); + + } else if( mouseOver ) { + + outline = hoverColor( palette ); + + } else if( mode == AnimationFocus ) { + + QColor focus( focusColor( palette ) ); + outline = 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 ) + { + + QColor hover( hoverColor( palette ) ); + QColor focus( focusColor( palette ) ); + if( hasFocus ) color = mix( focus, hover, opacity ); + else color = mix( color, hover, opacity ); + + } else if( mouseOver ) { + + color = hoverColor( palette ); + + } else if( mode == AnimationFocus ) { + + QColor focus( focusColor( palette ) ); + color = 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 + { + + Q_UNUSED(mouseOver); + Q_UNUSED(active); + Q_UNUSED(opacity); + Q_UNUSED(mode); + return palette.text().color(); + + } + + //______________________________________________________________________________ + QColor Helper::separatorColor( const QPalette& palette ) const + { return mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.25 ); } + + //____________________________________________________________________ + QColor Helper::headerTextColor( const QPalette& palette, const QStyle::State state ) const + { + QColor col(palette.color(QPalette::WindowText)); + + if (state & QStyle::State_Enabled) + { + if (state & QStyle::State_Sunken) + return alphaColor( col, 0.9 ); + else if (state & QStyle::State_MouseOver) + return alphaColor( col, 0.7 ); + } + return alphaColor( col, 0.5 ); + } + + QColor Helper::tabBarColor(const QPalette &palette, const QStyle::State state) const + { + + QColor background( mix(palette.window().color(), palette.shadow().color(), 0.15) ); + if (!(state & QStyle::State_Enabled)) + background = background.lighter(115); + if (!(state & QStyle::State_Active)) + background = background.lighter(115); + return background; + + } + + //______________________________________________________________________________ + 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, 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 ); + + qreal radius( frameRadius( -1.0 ) ); + if( !(sides&SideTop) ) copy.adjust( 0, -radius, 0, 0 ); + if( !(sides&SideBottom) ) copy.adjust( 0, 0, 0, radius ); + if( !(sides&SideLeft) ) copy.adjust( -radius, 0, 0, 0 ); + if( !(sides&SideRight) ) copy.adjust( 0, 0, radius, 0 ); + + painter->setPen( outline ); + // painter->setBrush( Qt::NoBrush ); + painter->drawRoundedRect( copy, radius, radius ); + + } + + painter->restore(); + return; + } + + //______________________________________________________________________________ + void Helper::renderFocusLine( QPainter* painter, const QRect& rect, const QColor& color ) const + { + if( !color.isValid() ) return; + + painter->save(); + + QPen pen(color, 1); + pen.setStyle(Qt::DotLine); + + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setPen( pen ); + painter->setBrush( Qt::NoBrush ); + + painter->drawRoundedRect( rect, 1, 1 ); + + painter->restore(); + } + + //______________________________________________________________________________ + void Helper::renderFrame( + QPainter* painter, const QRect& rect, + const QColor& color, const QColor& outline, bool hasFocus ) const + { + + painter->setRenderHint( QPainter::Antialiasing ); + + QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); + qreal radius( frameRadius() ); + + // set pen + if( outline.isValid() ) + { + + if (hasFocus) { + painter->setPen( QPen( outline, 2 ) ); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + } + else { + painter->setPen( outline ); + } + frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); + radius = qMax( radius - 1, qreal( 0.0 ) ); + + } else { + + painter->setPen( Qt::NoPen ); + + } + + // set brush + if( color.isValid() ) painter->setBrush( color ); + else painter->setBrush( Qt::NoBrush ); + + // render + painter->drawRoundedRect( frameRect, radius, radius ); + + } + + //______________________________________________________________________________ + void Helper::renderSquareFrame( + QPainter* painter, const QRect& rect, + QColor color, bool hasFocus ) const + { + painter->setPen( color ); + painter->drawRect( rect.adjusted(1, 1, -2, -2) ); + if (hasFocus) { + color.setAlphaF( 0.5 ); + painter->setPen( color ); + painter->drawRect( rect.adjusted(0, 0, -1, -1) ); + } + } + + //______________________________________________________________________________ + void Helper::renderFlatFrame( + QPainter* painter, const QRect& rect, + const QColor& color, const QColor& outline, bool hasFocus ) const + { + + painter->setRenderHint( QPainter::Antialiasing ); + + QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); + qreal radius( frameRadius() ); + + // set pen + if( outline.isValid() ) + { + + if (hasFocus) { + painter->setPen( QPen( outline, 2 ) ); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + } + else { + 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 ); + + QPainterPath path; + path.setFillRule( Qt::WindingFill ); + path.addRect( frameRect.adjusted(2 * radius, 0, 0, 0) ); + path.addRoundedRect( frameRect.adjusted(0, 0, - 2 *radius, 0), radius, radius); + + painter->drawPath( path.simplified() ); + + // render + //painter->drawRoundedRect( frameRect, radius, radius ); + + } + + //______________________________________________________________________________ + void Helper::renderSidePanelFrame( QPainter* painter, const QRect& rect, const QColor& outline, Side side ) const + { + + // check color + if( !outline.isValid() ) return; + + // adjust rect + QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); + frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); + + // setup painter + painter->setRenderHint( QPainter::Antialiasing ); + painter->setPen( outline ); + + // render + switch( side ) + { + default: + case SideLeft: + frameRect.adjust( 0, 1, 0, -1 ); + painter->drawLine( frameRect.topRight(), frameRect.bottomRight() ); + break; + + case SideTop: + frameRect.adjust( 1, 0, -1, 0 ); + painter->drawLine( frameRect.topLeft(), frameRect.topRight() ); + break; + + case SideRight: + frameRect.adjust( 0, 1, 0, -1 ); + painter->drawLine( frameRect.topLeft(), frameRect.bottomLeft() ); + break; + + case SideBottom: + frameRect.adjust( 1, 0, -1, 0 ); + painter->drawLine( frameRect.bottomLeft(), frameRect.bottomRight() ); + break; + + case AllSides: + { + 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 ); + + + 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, bool mouseOver, bool active ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + // copy rect + QRectF frameRect( rect ); + frameRect.adjust( 1, 1, -1, -1 ); + qreal radius( frameRadius() ); + + if( outline.isValid() ) + { + + painter->setPen( QPen( outline, 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.darker( sunken ? 110 : (hasFocus|mouseOver) ? 85 : 100 ) ); + //gradient.setColorAt( 1, color.darker( sunken ? 130 : (hasFocus|mouseOver) ? 95 : 110 ) ); + if (!active) { + gradient.setColorAt( 0, color ); + } + else if (sunken) { + gradient.setColorAt( 0, color ); + } + else { + gradient.setColorAt( 0, mix(color, Qt::white, 0.07) ); + gradient.setColorAt( 1, mix(color, Qt::black, 0.1) ); + } + painter->setBrush( gradient ); + + } else painter->setBrush( Qt::NoBrush ); + + // render + painter->drawRoundedRect( frameRect, radius, radius ); + + if (!sunken && active && color.isValid()) { + painter->setPen(color.lighter(140)); + painter->drawLine(frameRect.topLeft() + QPoint(3, 1), frameRect.topRight() + QPoint(-3, 1)); + painter->setPen(outline.darker(114)); + painter->drawLine(frameRect.bottomLeft() + QPointF(2.7, 0), frameRect.bottomRight() + QPointF(-2.7, 0)); + } + + } + + //______________________________________________________________________________ + void Helper::renderFlatButtonFrame( + QPainter* painter, const QRect& rect, + const QColor& color, const QColor& outline, const QColor& shadow, + bool hasFocus, bool sunken, bool mouseOver, bool active ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + // copy rect + QRectF frameRect( rect ); + frameRect.adjust( 1, 1, -1, -1 ); + qreal radius( frameRadius() ); + + if( outline.isValid() ) + { + + painter->setPen( QPen( outline, 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.darker( sunken ? 110 : (hasFocus|mouseOver) ? 85 : 100 ) ); + //gradient.setColorAt( 1, color.darker( sunken ? 130 : (hasFocus|mouseOver) ? 95 : 110 ) ); + + if (!active) { + gradient.setColorAt( 0, color ); + } + else if (sunken) { + gradient.setColorAt( 0, color); + } + else { + gradient.setColorAt( 0, mix(color, Qt::white, 0.07) ); + gradient.setColorAt( 1, mix(color, Qt::black, 0.1) ); + } + painter->setBrush( gradient ); + + } else painter->setBrush( Qt::NoBrush ); + + QPainterPath path; + path.setFillRule( Qt::WindingFill ); + path.addRoundedRect( frameRect.adjusted(2*radius, 0, 0, 0), radius, radius ); + path.addRect( frameRect.adjusted(0, 0, -2*radius, 0) ); + painter->drawPath( path.simplified() ); + + if (!sunken && active) { + painter->setPen(color.lighter(140)); + painter->drawLine(frameRect.topLeft() + QPoint(1, 1), frameRect.topRight() + QPoint(-3, 1)); + painter->setPen(outline.darker(114)); + painter->drawLine(frameRect.bottomLeft() + QPointF(0.7, 0), frameRect.bottomRight() + QPointF(-2.7, 0)); + } + + // 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 ); + + QRectF baseRect( rect ); + + if( sunken ) + { + + qreal radius( frameRadius() ); + + painter->setPen( Qt::NoPen ); + painter->setBrush( color ); + + QRectF contentRect( baseRect.adjusted( 1, 1, -1, -1 ) ); + painter->drawRoundedRect( contentRect, radius, radius ); + + } else { + + qreal radius( frameRadius(-0.5) ); + + painter->setPen( color ); + painter->setBrush( Qt::NoBrush ); + 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 + qreal radius( frameRadius() ); + 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->save(); + painter->setRenderHints( QPainter::Antialiasing ); + painter->setBrush( Qt::NoBrush ); + painter->setPen( outline ); + painter->translate( baseRect.topLeft() ); + painter->drawPath( path ); + painter->restore(); + + return; + + } + + //______________________________________________________________________________ + void Helper::renderTabWidgetFrame( + QPainter* painter, const QRect& rect, + const QColor& color, const QColor& outline, Corners corners ) const + { + + painter->setRenderHint( QPainter::Antialiasing ); + + QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); + qreal radius( frameRadius() ); + + // set pen + if( outline.isValid() ) + { + + painter->setPen( outline ); + frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); + radius = qMax( radius-1, qreal( 0.0 ) ); + + } else painter->setPen( Qt::NoPen ); + + // set brush + if( color.isValid() ) painter->setBrush( color ); + else painter->setBrush( Qt::NoBrush ); + + // render + QPainterPath path( roundedPath( frameRect, corners, radius ) ); + painter->drawPath( path ); + + } + + + //______________________________________________________________________________ + void Helper::renderSelection( + QPainter* painter, const QRect& rect, + const QColor& color ) const + { + + painter->setRenderHint( QPainter::Antialiasing ); + painter->setPen( Qt::NoPen ); + painter->setBrush( color ); + painter->drawRect( rect ); + + } + + //______________________________________________________________________________ + void Helper::renderSeparator( + QPainter* painter, const QRect& rect, + const QColor& color, bool vertical ) const + { + + painter->save(); + 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() ); + + + } + + painter->restore(); + + return; + + } + + //______________________________________________________________________________ + void Helper::renderCheckBoxBackground( + QPainter* painter, const QRect& rect, + const QColor& color, const QColor &outline, bool sunken ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + // copy rect and radius + QRectF frameRect( rect ); + frameRect.adjust( 3, 3, -3, -3 ); + + painter->setPen( outline ); + painter->setBrush( color ); + painter->drawRect( frameRect ); + + } + + //______________________________________________________________________________ + void Helper::renderCheckBox( + QPainter* painter, const QRect& rect, + const QColor& background, const QColor& outline, const QColor& tickColor, + bool sunken, CheckBoxState state, qreal animation, bool active ) const + { + + // setup painter + painter->save(); + painter->setRenderHint( QPainter::Antialiasing, true ); + + // copy rect and radius + QRectF frameRect( rect ); + frameRect.adjust( 2, 2, -2, -2 ); + qreal radius( frameRadius() ); + + // content + { + + renderButtonFrame(painter, rect, background, outline, Qt::transparent, false, sunken, false, active); + + } + + // mark + if( state == CheckOn ) + { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setBrush( Qt::NoBrush ); + QPen pen( tickColor, 3 ); + pen.setJoinStyle(Qt::MiterJoin); + painter->setPen( pen ); + + QRectF markerRect(frameRect); + + QPainterPath path; + path.moveTo( markerRect.right(), markerRect.top() + markerRect.height() / 4 ); + path.lineTo( markerRect.center().x(), markerRect.bottom() - markerRect.height() / 3.0 ); + path.lineTo( markerRect.left() + markerRect.width() / 3.0, markerRect.center().y() ); + + painter->setClipRect(markerRect); + painter->drawPath( path ); + painter->restore(); + + } else if( state == CheckPartial ) { + + QPen pen( tickColor, 4 ); + pen.setCapStyle( Qt::RoundCap ); + painter->setPen( pen ); + + QRectF markerRect( frameRect.adjusted( 4, 4, -4, -4 ) ); + + painter->drawLine( markerRect.center() - QPoint(3, 0), markerRect.center() + QPoint(3, 0) ); + + } else if( state == CheckAnimated ) { + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setBrush( Qt::NoBrush ); + QPen pen( tickColor, 3 ); + pen.setJoinStyle(Qt::MiterJoin); + painter->setPen( pen ); + + QRectF markerRect(frameRect); + + QPainterPath path; + path.moveTo( markerRect.right(), markerRect.top() + markerRect.height() / 4 ); + path.lineTo( markerRect.center().x(), markerRect.bottom() - markerRect.height() / 3.0 ); + path.lineTo( markerRect.left() + markerRect.width() / 3.0, markerRect.center().y() ); + path.translate(-markerRect.right(), -markerRect.top()); + + painter->setClipRect(markerRect.adjusted(1, 1, -1, -1)); + painter->translate(markerRect.right(), markerRect.top()); + painter->scale(animation, 0.5 + 0.5 * animation); + painter->drawPath( path ); + painter->restore(); + + } + + painter->restore(); + } + + //______________________________________________________________________________ + void Helper::renderRadioButtonBackground( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, 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( outline ); + painter->setBrush( color ); + painter->drawEllipse( frameRect ); + + } + + //______________________________________________________________________________ + void Helper::renderRadioButton( + QPainter* painter, const QRect& rect, + const QColor& background, const QColor& outline, const QColor& tickColor, + bool sunken, bool enabled, RadioButtonState state, qreal animation ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + // copy rect + QRectF frameRect( rect ); + frameRect.adjust( 2, 2, -2, -2 ); + + // content + { + + if (background.isValid()) { + if (enabled) { + QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() ); + if (sunken) { + gradient.setColorAt( 0, background); + } + else { + gradient.setColorAt( 0, mix(background, Qt::white, 0.07) ); + gradient.setColorAt( 1, mix(background, Qt::black, 0.1) ); + } + painter->setBrush( gradient ); + } + else { + painter->setBrush( background ); + } + } else { + painter->setBrush( Qt::NoBrush ); + } + + painter->setPen( QPen( outline, 1 ) ); + + QRectF contentRect( frameRect.adjusted( 0.5, 0.5, -0.5, -0.5 ) ); + painter->drawEllipse( contentRect ); + + } + + // mark + if( state == RadioOn ) + { + + painter->setBrush( tickColor ); + painter->setPen( Qt::NoPen ); + + QRectF markerRect( frameRect.adjusted( 5, 5, -5, -5 ) ); + painter->drawEllipse( markerRect ); + + } else if( state == RadioAnimated ) { + + painter->setBrush( tickColor ); + painter->setPen( Qt::NoPen ); + QRectF markerRect( frameRect.adjusted( 5, 5, -5, -5 ) ); + qreal remaining = markerRect.width() / 2.0 * (1.0 - animation); + markerRect.adjust(remaining, remaining, -remaining, -remaining); + + painter->drawEllipse( markerRect ); + + } + + } + + //______________________________________________________________________________ + void Helper::renderSliderGroove( + QPainter* painter, const QRect& rect, + const QColor& color ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + QRectF baseRect( rect ); + qreal radius( 0.5*Metrics::Slider_GrooveThickness ); + + // content + if( color.isValid() ) + { + painter->setPen( Qt::NoPen ); + painter->setBrush( color ); + painter->drawRoundedRect( baseRect, radius, radius ); + } + + return; + + } + + //______________________________________________________________________________ + void Helper::renderDialGroove( + QPainter* painter, const QRect& rect, + const QColor& color ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + QRectF baseRect( rect ); + + // content + if( color.isValid() ) + { + qreal penWidth( Metrics::Slider_GrooveThickness ); + QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) ); + + painter->setPen( QPen( color, penWidth ) ); + painter->setBrush( Qt::NoBrush ); + painter->drawEllipse( grooveRect ); + } + + return; + + } + + //______________________________________________________________________________ + void Helper::renderDialContents( + QPainter* painter, const QRect& rect, + const QColor& color, + qreal first, qreal second ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + QRectF baseRect( rect ); + + // content + if( color.isValid() ) + { + + // setup groove rect + qreal penWidth( Metrics::Slider_GrooveThickness ); + QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) ); + + // setup angles + int angleStart( first * 180 * 16 / M_PI ); + int angleSpan( (second - first ) * 180 * 16 / M_PI ); + + // setup pen + if( angleSpan != 0 ) + { + QPen pen( color, penWidth ); + pen.setCapStyle( Qt::RoundCap ); + painter->setPen( pen ); + painter->setBrush( Qt::NoBrush ); + painter->drawArc( grooveRect, angleStart, angleSpan ); + } + + } + + return; + + } + + //______________________________________________________________________________ + void Helper::renderSliderHandle(QPainter* painter, const QRect& rect, + const QColor& color, + const QColor& outline, + const QColor& shadow, + bool sunken, + bool enabled, + Side ticks, + qreal angle) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + // copy rect + QRectF frameRect( rect ); + frameRect.adjust( 1, 1, -1, -1 ); + + // set pen + if( outline.isValid() ) + { + + QPen pen(outline); + pen.setCapStyle( Qt::FlatCap ); + pen.setJoinStyle( Qt::MiterJoin ); + painter->setPen(pen); + + frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); + + } else painter->setPen( Qt::NoPen ); + + // set brush + if( color.isValid() ) { + + if (enabled) { + QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() ); + if (sunken) { + gradient.setColorAt( 0, color); + } + else { + gradient.setColorAt( 0, mix(color, Qt::white, 0.07) ); + gradient.setColorAt( 1, mix(color, Qt::black, 0.1) ); + } + painter->setBrush(gradient); + } + else { + painter->setBrush(color); + } + + } + else painter->setBrush( Qt::NoBrush ); + + QRect r(rect.right() - rect.height(), rect.top(), rect.height(), rect.height()); + r.adjust(4.5, 3.5, -2.5, -3.5); + + QPainterPath circle; + circle.addEllipse(r); + circle.closeSubpath(); + + if (ticks & SideBottom) { + QPainterPath triangle(r.center()); + triangle.moveTo(r.left() + 1.5, r.center().y() + 5.5); + triangle.lineTo(r.center().x() + 1, r.bottom() + 4.5); + triangle.lineTo(r.right() - 0.5, r.center().y() + 5.5); + triangle.closeSubpath(); + circle = circle.united(triangle); + } + else if (ticks & SideTop) { + QPainterPath triangle(r.center()); + triangle.moveTo(r.left() + 1.5, r.center().y() - 3.5); + triangle.lineTo(r.center().x() + 1, r.top() - 2.5); + triangle.lineTo(r.right() - 0.5, r.center().y() - 3.5); + triangle.closeSubpath(); + circle = circle.united(triangle); + } + else if (ticks & SideLeft) { + QPainterPath triangle(r.center()); + triangle.moveTo(r.center().x() - 3.5, r.top() + 1.5); + triangle.lineTo(r.left() - 2.5, r.center().y() + 1); + triangle.lineTo(r.center().x() - 3.5, r.bottom() - 0.5); + triangle.closeSubpath(); + circle = circle.united(triangle); + } + else if (ticks & SideRight) { + QPainterPath triangle(r.center()); + triangle.moveTo(r.center().x() + 3.5, r.top() + 1.5); + triangle.lineTo(r.right() + 2.5, r.center().y() + 1); + triangle.lineTo(r.center().x() + 3.5, r.bottom() - 0.5); + triangle.closeSubpath(); + circle = circle.united(triangle); + } + + QTransform rotate; + rotate.translate(frameRect.center().x(), frameRect.center().y()); + rotate.rotate(angle); + rotate.translate(-frameRect.center().x(), -frameRect.center().y()); + painter->drawPolygon(circle.toFillPolygon(rotate)); + + } + + //______________________________________________________________________________ + void Helper::renderProgressBarGroove(QPainter* painter, const QRect& rect, + const QColor& color , const QColor& outline) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + painter->setRenderHint( QPainter::SmoothPixmapTransform, true ); + + QRectF baseRect( rect ); + qreal radius( 0.5 ); + + // content + if( color.isValid() ) + { + painter->setPen( outline ); + painter->setBrush( color ); + painter->drawRoundedRect( baseRect.translated(0.5, 0.5), radius, radius ); + } + + return; + + } + + + //______________________________________________________________________________ + void Helper::renderProgressBarBusyContents( + QPainter* painter, const QRect& rect, + const QColor& color, + const QColor& outline, + bool horizontal, + bool reverse, + int progress + ) const + { + Q_UNUSED(reverse); + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + QRectF baseRect( rect ); + qreal radius( 0.25*Metrics::ProgressBar_Thickness ); + QRectF contentRect; + if (horizontal) { + contentRect = QRect(baseRect.left(), baseRect.top(), Metrics::ProgressBar_BusyIndicatorSize, baseRect.height()); + contentRect.translate(fabs(progress - 50) / 50.0 * (baseRect.width() - contentRect.width()), 0); + } + else { + contentRect = QRect(baseRect.left(), baseRect.top(), baseRect.width(), Metrics::ProgressBar_BusyIndicatorSize); + contentRect.translate(0, fabs(progress - 50) / 50.0 * (baseRect.height() - contentRect.height())); + } + + painter->setBrush(color); + painter->setPen(outline); + painter->drawRoundedRect(contentRect.translated(0.5, 0.5), radius, radius); + + return; + + } + + //______________________________________________________________________________ + void Helper::renderScrollBarHandle( + QPainter* painter, const QRect& rect, + const QColor& color ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, true ); + + QRectF baseRect( rect ); + qreal metric( rect.width() < rect.height() ? rect.width() : rect.height()); + qreal radius( 0.5*metric ); + + // content + if( color.isValid() ) + { + painter->setPen( Qt::NoPen ); + painter->setBrush( color ); + painter->drawRoundedRect( baseRect, radius, radius ); + } + + return; + + } + + //______________________________________________________________________________ + void Helper::renderTabBarTab( QPainter* painter, const QRect& rect, const QColor& background, const QColor& color, const QColor& outline, Corners corners, bool renderFrame ) const + { + + // setup painter + painter->setRenderHint( QPainter::Antialiasing, false ); + + QRectF frameRect( rect ); + qreal adjustment; + + // pen + if( outline.isValid() ) + { + + painter->setPen( outline ); + frameRect.adjust( 1.0, 1.0, -1.0, -1.0 ); + adjustment = 0; + + painter->setBrush( background ); + + // render + painter->drawRect( frameRect ); + + } else if (!renderFrame) { + adjustment = 9; + } + + painter->setPen( QPen( color, 6 ) ); + + switch (corners) { + case CornerTopLeft|CornerTopRight: + painter->drawLine(frameRect.left() + adjustment, frameRect.bottom(), frameRect.right() - adjustment, frameRect.bottom()); + break; + + case CornerBottomLeft|CornerBottomRight: + painter->drawLine(frameRect.left() + adjustment, frameRect.top(), frameRect.right() - adjustment, frameRect.top()); + break; + + case CornerTopLeft|CornerBottomLeft: + painter->drawLine(frameRect.right(), frameRect.top() + adjustment, frameRect.right(), frameRect.bottom() - adjustment); + break; + + case CornerTopRight|CornerBottomRight: + painter->drawLine(frameRect.left(), frameRect.top() + adjustment, frameRect.left(), frameRect.bottom() - adjustment); + break; + + } + + + } + + //______________________________________________________________________________ + // TODO blurry edges + void Helper::renderArrow( QPainter* painter, const QRect& rect, const QColor& color, ArrowOrientation orientation ) const + { + + // define polygon + QPolygonF arrow; + switch( orientation ) + { + case ArrowUp: arrow << QPointF( -4, 2 ) << QPointF( 0, -2 ) << QPointF( 4, 2 ); break; + case ArrowDown: arrow << QPointF( -4, -2 ) << QPointF( 0, 2 ) << QPointF( 4, -2 ); break; + case ArrowLeft: arrow << QPointF( 2, -4 ) << QPointF( -2, 0 ) << QPointF( 2, 4 ); break; + case ArrowRight: arrow << QPointF( -2, -4 ) << QPointF( 2, 0 ) << QPointF( -2, 4 ); break; + default: break; + } + + QPen pen(color, 1.2); + pen.setCapStyle( Qt::FlatCap ); + pen.setJoinStyle( Qt::MiterJoin ); + + painter->save(); + painter->setRenderHints( QPainter::Antialiasing ); + painter->translate( QRectF( rect ).center() ); + painter->setBrush( color ); + painter->setPen( pen ); + painter->drawPolygon( arrow ); + + painter->restore(); + + return; + } + + void Helper::renderSign(QPainter *painter, const QRect &rect, const QColor &color, bool orientation) const { + QPen pen( color, 2 ); + pen.setCapStyle( Qt::FlatCap ); + + QRect r = rect.adjusted(1, 2, 0, 0); + + painter->setPen(pen); + painter->drawLine(r.center() - QPointF(5, 0), r.center() + QPointF(5, 0)); + if (orientation) + painter->drawLine(r.center() - QPointF(0, 5), r.center() + QPointF(0, 5)); + } + + //______________________________________________________________________________ + 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, false ); + + // initialize pen + QPen pen; + pen.setCapStyle( Qt::RoundCap ); + pen.setJoinStyle( Qt::MiterJoin ); + + painter->setBrush( Qt::NoBrush ); + + pen.setColor( color ); + pen.setCapStyle( Qt::RoundCap ); + pen.setJoinStyle( Qt::MiterJoin ); + pen.setWidthF( 2.0*qMax(1.0, 18.0/rect.width() ) ); + painter->setPen( pen ); + + switch( buttonType ) + { + case ButtonClose: + { + painter->setRenderHints( QPainter::Antialiasing, true ); + painter->drawLine( QPointF( 5, 5 ), QPointF( 13, 13 ) ); + painter->drawLine( 13, 5, 5, 13 ); + break; + } + + case ButtonMaximize: + { + painter->drawPolyline( QPolygonF() + << QPointF( 4, 4 ) + << QPointF( 4, 14 ) + << QPointF( 14, 14 ) + << QPointF( 14, 4 ) ); + break; + } + + case ButtonMinimize: + { + + painter->drawPolyline( QPolygonF() + << QPointF( 4, 14 ) + << QPointF( 14, 14 ) ); + break; + } + + case ButtonRestore: + { + painter->setPen( pen ); + QPolygonF rect = QPolygonF() << QPointF( 0, 0 ) << QPointF( 8, 0 ) << QPointF( 8, 8 ) << QPointF( 0, 8 ); + painter->drawPolygon( rect.translated(7, 3) ); + painter->drawPolygon( rect.translated(3, 7) ); + break; + } + + default: break; + } + + painter->restore(); + return; + + } + + //______________________________________________________________________________ + bool Helper::isX11( void ) + { + #if QT_VERSION >= 0x050000 + static const bool s_isX11 = qApp->platformName()==QLatin1String("xcb"); + return s_isX11; + #else + return false; + #endif + } + + bool Helper::isWayland( void ) + { + #if QT_VERSION >= 0x050000 + static const bool s_isWayland = qApp->platformName().startsWith(QLatin1String("wayland")); + return s_isWayland; + #else + return false; + #endif + } + + //______________________________________________________________________________ + QRectF Helper::shadowRect( const QRectF& rect ) const + { return rect; } + + //______________________________________________________________________________ + 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; + + } + + 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( void ) const + { + + #if ADWAITA_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(); + return false; + + } + + //____________________________________________________________________ + 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 + 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 ADWAITA_HAVE_X11 + + //____________________________________________________________________ + xcb_connection_t* Helper::connection( void ) + { + + #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( void ) + { + #if ADWAITA_HAVE_X11 + + if( isX11() ) + { + // create compositing screen + QString atomName( QStringLiteral( "_NET_WM_CM_S%1" ).arg( QX11Info::appScreen() ) ); + _compositingManagerAtom = createAtom( atomName ); + } + + #endif + + } + + //____________________________________________________________________ + void Helper::setVariant(QWidget *widget, const QByteArray &variant) + { + if (isX11() && widget) { // && !widget->testAttribute(Qt::WA_)) { + static const char *_GTK_THEME_VARIANT="_GTK_THEME_VARIANT"; + + // Check if already set + QVariant var=widget->property("_GTK_THEME_VARIANT"); + if (var.isValid() && var.toByteArray()==variant) { + return; + } + + // Typedef's from xcb/xcb.h - copied so that there is no + // direct xcb dependency + typedef quint32 XcbAtom; + + struct XcbInternAtomCookie { + unsigned int sequence; + }; + + struct XcbInternAtomReply { + quint8 response_type; + quint8 pad0; + quint16 sequence; + quint32 length; + XcbAtom atom; + }; + + typedef void * (*XcbConnectFn)(int, int); + typedef XcbInternAtomCookie (*XcbInternAtomFn)(void *, int, int, const char *); + typedef XcbInternAtomReply * (*XcbInternAtomReplyFn)(void *, XcbInternAtomCookie, int); + typedef int (*XcbChangePropertyFn)(void *, int, int, XcbAtom, XcbAtom, int, int, const void *); + typedef int (*XcbFlushFn)(void *); + + static QLibrary *lib = 0; + static XcbAtom variantAtom = 0; + static XcbAtom utf8TypeAtom = 0; + static void *xcbConn = 0; + static XcbChangePropertyFn XcbChangePropertyFnPtr = 0; + static XcbFlushFn XcbFlushFnPtr = 0; + + if (!lib) { + lib = new QLibrary("libxcb", qApp); + + if (lib->load()) { + XcbConnectFn XcbConnectFnPtr=(XcbConnectFn)lib->resolve("xcb_connect"); + XcbInternAtomFn XcbInternAtomFnPtr=(XcbInternAtomFn)lib->resolve("xcb_intern_atom"); + XcbInternAtomReplyFn XcbInternAtomReplyFnPtr=(XcbInternAtomReplyFn)lib->resolve("xcb_intern_atom_reply"); + + XcbChangePropertyFnPtr=(XcbChangePropertyFn)lib->resolve("xcb_change_property"); + XcbFlushFnPtr=(XcbFlushFn)lib->resolve("xcb_flush"); + if (XcbConnectFnPtr && XcbInternAtomFnPtr && XcbInternAtomReplyFnPtr && XcbChangePropertyFnPtr && XcbFlushFnPtr) { + xcbConn=(*XcbConnectFnPtr)(0, 0); + if (xcbConn) { + XcbInternAtomReply *typeReply = (*XcbInternAtomReplyFnPtr)(xcbConn, (*XcbInternAtomFnPtr)(xcbConn, 0, 11, "UTF8_STRING"), 0); + + if (typeReply) { + XcbInternAtomReply *gtkVarReply = (*XcbInternAtomReplyFnPtr)(xcbConn, + (*XcbInternAtomFnPtr)(xcbConn, 0, strlen(_GTK_THEME_VARIANT), + _GTK_THEME_VARIANT), 0); + if (gtkVarReply) { + utf8TypeAtom = typeReply->atom; + variantAtom = gtkVarReply->atom; + free(gtkVarReply); + } + free(typeReply); + } + } + } + } + } + + if (0!=variantAtom) { + (*XcbChangePropertyFnPtr)(xcbConn, 0, widget->effectiveWinId(), variantAtom, utf8TypeAtom, 8, + variant.length(), (const void *)variant.constData()); + (*XcbFlushFnPtr)(xcbConn); + widget->setProperty(_GTK_THEME_VARIANT, variant); + } + } + } + +} diff --git a/style/adwaitahelper.h b/style/adwaitahelper.h new file mode 100644 index 0000000..55efe39 --- /dev/null +++ b/style/adwaitahelper.h @@ -0,0 +1,368 @@ +#ifndef adwaita_helper_h +#define adwaita_helper_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 "adwaita.h" +#include "adwaitaanimationdata.h" +#include "config-adwaita.h" + +#include +#include +#include + +#if ADWAITA_HAVE_X11 +#include +#include +#endif + +#include + +namespace Adwaita +{ + + //* adwaita style helper class. + /** contains utility functions used at multiple places in both adwaita style and adwaita window decoration */ + class Helper + { + public: + + //* constructor + explicit Helper( ); + + #if ADWAITA_USE_KDE4 + //* constructor + explicit Helper( const QByteArray& ); + #endif + + //* destructor + virtual ~Helper() + {} + + //*@name color utilities + //@{ + + // Borrowed from the KColorUtils code + static QColor mix(const QColor &c1, const QColor &c2, qreal bias = 0.5) + { + auto mixQreal = [](qreal a, qreal b, qreal bias) { return a + (b - a) * bias; }; + + if (bias <= 0.0) return c1; + if (bias >= 1.0) return c2; + if (std::isnan(bias)) return c1; + + qreal r = mixQreal(c1.redF(), c2.redF(), bias); + qreal g = mixQreal(c1.greenF(), c2.greenF(), bias); + qreal b = mixQreal(c1.blueF(), c2.blueF(), bias); + qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias); + + return QColor::fromRgbF(r, g, b, a); + } + + //* add alpha channel multiplier to color + QColor alphaColor( QColor color, qreal alpha ) const; + + // ADWAITA TODO + + //* mouse over color + QColor hoverColor( const QPalette& palette ) const + { return palette.highlight().color(); } + + //* focus color + QColor focusColor( const QPalette& palette ) const + { return palette.highlight().color(); } + + //* negative text color (used for close button) + QColor negativeText( const QPalette& palette ) const + // { return _viewNegativeTextBrush.brush( palette ).color(); } + { Q_UNUSED(palette); return Qt::red; } + + //* shadow + QColor shadowColor( const QPalette& palette ) const + { return alphaColor( palette.color( QPalette::Shadow ), 0.15 ); } + + //* titlebar color + QColor titleBarColor( const QPalette& palette, bool active ) const + { return palette.color(active ? QPalette::Active : QPalette::Inactive, QPalette::Window); } + + //* titlebar text color + QColor titleBarTextColor( const QPalette& palette, bool active ) const + { return palette.color(active ? QPalette::Active : QPalette::Inactive, QPalette::WindowText); } + + //* frame outline color, using animations + QColor frameOutlineColor( const QPalette&, bool mouseOver = false, bool hasFocus = false, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* input outline color, using animations + QColor inputOutlineColor( const QPalette& palette, bool mouseOver = false, bool hasFocus = false, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* focus outline color, using animations + QColor focusOutlineColor( const QPalette& ) const; + + //* hover outline color, using animations + QColor hoverOutlineColor( const QPalette& ) const; + + //* focus outline color, using animations + QColor buttonFocusOutlineColor( const QPalette& ) const; + + //* hover outline color, using animations + QColor buttonHoverOutlineColor( const QPalette& ) const; + + //* side panel outline color, using animations + QColor sidePanelOutlineColor( const QPalette&, bool hasFocus = false, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* frame background color + QColor frameBackgroundColor( const QPalette& palette ) const + { return frameBackgroundColor( palette, palette.currentColorGroup() ); } + + //* frame background color + QColor frameBackgroundColor( const QPalette&, QPalette::ColorGroup ) const; + + //* arrow outline color + QColor arrowColor( const QPalette&, QPalette::ColorGroup, QPalette::ColorRole ) const; + + //* arrow outline color + QColor arrowColor( const QPalette& palette, QPalette::ColorRole role ) const + { return arrowColor( palette, palette.currentColorGroup(), role ); } + + //* arrow outline color, using animations + QColor arrowColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* button outline color, using animations + QColor buttonOutlineColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* button panel color, using animations + QColor buttonBackgroundColor( const QPalette&, bool mouseOver, bool hasFocus, bool sunken, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* tool button color + QColor toolButtonColor( const QPalette&, bool mouseOver, bool hasFocus, bool sunken, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* slider outline color, using animations + QColor sliderOutlineColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* scrollbar handle color, using animations + QColor scrollBarHandleColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* checkbox indicator, using animations + QColor checkBoxIndicatorColor( const QPalette&, bool mouseOver, bool active, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; + + //* separator color + QColor separatorColor( const QPalette& ) const; + + //* TreeView header text color + QColor headerTextColor( const QPalette& palette, const QStyle::State state ) const; + + //* TabBar background color + QColor tabBarColor( const QPalette& palette, const QStyle::State state ) const; + + //* merge active and inactive palettes based on ratio, for smooth enable state change transition + QPalette disabledPalette( const QPalette&, qreal ratio ) const; + + //@} + + //*@name rendering utilities + //@{ + + //* debug frame + void renderDebugFrame( QPainter*, const QRect& ) const; + + //* focus rect + void renderFocusRect( QPainter*, const QRect&, const QColor&, const QColor& outline = QColor(), Sides = 0 ) const; + + //* focus line + void renderFocusLine( QPainter*, const QRect&, const QColor& ) const; + + //* generic frame + void renderFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline = QColor(), bool hasFocus = false ) const; + + //* square frame + void renderSquareFrame( QPainter* painter, const QRect& rect, QColor color, bool hasFocus ) const; + + //* generic frame flat on right side + void renderFlatFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline = QColor(), bool hasFocus = false ) const; + + //* side panel frame + void renderSidePanelFrame( QPainter*, const QRect&, const QColor& outline, Side ) const; + + //* menu frame + void renderMenuFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline, bool roundCorners = true ) const; + + //* button frame + void renderButtonFrame(QPainter*, const QRect&, const QColor& color, const QColor& outline, const QColor& shadow, bool focus, bool sunken, bool mouseOver , bool active) const; + + //* button frame + void renderFlatButtonFrame(QPainter*, const QRect&, const QColor& color, const QColor& outline, const QColor& shadow, bool focus, bool sunken, bool mouseOver , bool active) const; + + //* toolbutton frame + void renderToolButtonFrame( QPainter*, const QRect&, const QColor& color, bool sunken ) const; + + //* toolbutton frame + void renderToolBoxFrame( QPainter*, const QRect&, int tabWidth, const QColor& color ) const; + + //* tab widget frame + void renderTabWidgetFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline, Corners ) const; + + //* selection frame + void renderSelection( QPainter*, const QRect&, const QColor& ) const; + + //* separator + void renderSeparator( QPainter*, const QRect&, const QColor&, bool vertical = false ) const; + + //* checkbox + void renderCheckBoxBackground( QPainter*, const QRect&, const QColor& color, const QColor& outline, bool sunken ) const; + + //* checkbox + void renderCheckBox( QPainter*, const QRect&, const QColor& background, const QColor& outline, const QColor& tickColor, bool sunken, CheckBoxState state, qreal animation = AnimationData::OpacityInvalid, bool active = true ) const; + + //* radio button + void renderRadioButtonBackground( QPainter*, const QRect&, const QColor& color, const QColor& outline, bool sunken ) const; + + //* radio button + void renderRadioButton(QPainter*, const QRect&, const QColor& background, const QColor& outline, const QColor& tickColor, bool sunken, bool enabled, RadioButtonState state, qreal animation = AnimationData::OpacityInvalid ) const; + + //* slider groove + void renderSliderGroove( QPainter*, const QRect&, const QColor& ) const; + + //* slider handle + void renderSliderHandle( QPainter*, const QRect&, const QColor&, const QColor& outline, const QColor& shadow, bool sunken, bool enabled, Side ticks, qreal angle = 0.0 ) const; + + //* dial groove + void renderDialGroove( QPainter*, const QRect&, const QColor& ) const; + + //* dial groove + void renderDialContents( QPainter*, const QRect&, const QColor&, qreal first, qreal second ) const; + + //* progress bar groove + void renderProgressBarGroove( QPainter*, const QRect&, const QColor&, const QColor& ) const; + + //* progress bar contents + void renderProgressBarContents( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline ) const + { return renderProgressBarGroove( painter, rect, color, outline ); } + + //* progress bar contents (animated) + void renderProgressBarBusyContents( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, bool horizontal, bool reverse, int progress ) const; + + //* scrollbar groove + void renderScrollBarGroove( QPainter* painter, const QRect& rect, const QColor& color ) const + { return renderScrollBarHandle( painter, rect, color ); } + + //* scrollbar handle + void renderScrollBarHandle( QPainter*, const QRect&, const QColor& ) const; + + //* toolbar handle + void renderToolBarHandle( QPainter* painter, const QRect& rect, const QColor& color ) const + { return renderProgressBarGroove( painter, rect, color, Qt::transparent ); } + + //* tabbar tab + void renderTabBarTab(QPainter*, const QRect&, const QColor &background, const QColor& color, const QColor& outline, Corners, bool renderFrame ) const; + + //* generic arrow + void renderArrow( QPainter*, const QRect&, const QColor&, ArrowOrientation ) const; + + //* generic sign (+-) + void renderSign(QPainter*painter, const QRect&rect, const QColor&color, bool orientation ) const; + + //* generic button (for mdi decorations, tabs and dock widgets) + void renderDecorationButton( QPainter*, const QRect&, const QColor&, ButtonType, bool inverted ) const; + + //@} + + //*@name compositing utilities + //@{ + + //* true if style was compiled for and is running on X11 + static bool isX11( void ); + + //* true if running on platform Wayland + static bool isWayland( void ); + + //* returns true if compositing is active + bool compositingActive( void ) const; + + //* returns true if a given widget supports alpha channel + bool hasAlphaChannel( const QWidget* ) const; + + //@} + + //@name high dpi utility functions + //@{ + + //* return dpi-aware pixmap of given size + virtual QPixmap highDpiPixmap( const QSize& size ) const + { return highDpiPixmap( size.width(), size.height() ); } + + //* return dpi-aware pixmap of given size + virtual QPixmap highDpiPixmap( int width ) const + { return highDpiPixmap( width, width ); } + + //* return dpi-aware pixmap of given size + virtual QPixmap highDpiPixmap( int width, int height ) const; + + //* return device pixel ratio for a given pixmap + virtual qreal devicePixelRatio( const QPixmap& ) const; + + //@} + + //*@name X11 utilities + //@{ + + #if ADWAITA_HAVE_X11 + + //* get xcb connection + static xcb_connection_t* connection( void ); + + //* create xcb atom + xcb_atom_t createAtom( const QString& ) const; + + #endif + + //@} + + //* frame radius + qreal frameRadius( qreal bias = 0 ) const + { return qMax( qreal( Metrics::Frame_FrameRadius ) - 0.5 + bias, 0.0 ); } + + void setVariant(QWidget *widget, const QByteArray &variant); + + protected: + + //* initialize + void init( void ); + + //* return rectangle for widgets shadow, offset depending on light source + QRectF shadowRect( const QRectF& ) const; + + //* return rounded path in a given rect, with only selected corners rounded, and for a given radius + QPainterPath roundedPath( const QRectF&, Corners, qreal ) const; + + private: + + #if ADWAITA_HAVE_X11 + + //* atom used for compositing manager + xcb_atom_t _compositingManagerAtom; + + #endif + + }; + +} + +#endif diff --git a/style/adwaitamnemonics.cpp b/style/adwaitamnemonics.cpp new file mode 100644 index 0000000..708c03b --- /dev/null +++ b/style/adwaitamnemonics.cpp @@ -0,0 +1,101 @@ +/************************************************************************* + * 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 "adwaitamnemonics.h" + +#include +#include + +namespace Adwaita +{ + + //____________________________________________________ + void Mnemonics::setMode( int mode ) + { + + switch( mode ) + { + case StyleConfigData::MN_NEVER: + qApp->removeEventFilter( this ); + setEnabled( false ); + break; + + default: + case StyleConfigData::MN_ALWAYS: + qApp->removeEventFilter( this ); + setEnabled( true ); + break; + + case StyleConfigData::MN_AUTO: + qApp->removeEventFilter( this ); + qApp->installEventFilter( this ); + setEnabled( false ); + break; + + } + + return; + + } + + //____________________________________________________ + bool Mnemonics::eventFilter( QObject*, QEvent* event ) + { + + switch( event->type() ) + { + + case QEvent::KeyPress: + if( static_cast(event)->key() == Qt::Key_Alt ) + { setEnabled( true ); } + break; + + case QEvent::KeyRelease: + if( static_cast(event)->key() == Qt::Key_Alt ) + { setEnabled( false ); } + break; + + #if QT_VERSION >= 0x050000 + case QEvent::ApplicationStateChange: + { setEnabled( false ); } + break; + #endif + + default: break; + + } + + return false; + + } + + //____________________________________________________ + void Mnemonics::setEnabled( bool value ) + { + if( _enabled == value ) return; + + _enabled = value; + + // update all top level widgets + foreach( QWidget* widget, qApp->topLevelWidgets() ) + { widget->update(); } + + } + +} diff --git a/style/adwaitamnemonics.h b/style/adwaitamnemonics.h new file mode 100644 index 0000000..44c41a1 --- /dev/null +++ b/style/adwaitamnemonics.h @@ -0,0 +1,77 @@ +#ifndef adwaitamnemonics_h +#define adwaitamnemonics_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 "fakeadwaitastyleconfigdata.h" + +namespace Adwaita +{ + + class Mnemonics: public QObject + { + + Q_OBJECT + + public: + + //* constructor + explicit Mnemonics( QObject* parent ): + QObject( parent ), + _enabled( true ) + {} + + //* destructor + virtual ~Mnemonics( void ) + {} + + //* set mode + void setMode( int ); + + //* event filter + virtual bool eventFilter( QObject*, QEvent* ); + + //* true if mnemonics are enabled + const bool& enabled( void ) const + { return _enabled; } + + //* alignment flag + int textFlags( void ) const + { return _enabled ? Qt::TextShowMnemonic : Qt::TextHideMnemonic; } + + protected: + + //* set enable state + void setEnabled( bool ); + + private: + + //* enable state + bool _enabled; + + }; + +} + +#endif diff --git a/style/adwaitapropertynames.cpp b/style/adwaitapropertynames.cpp new file mode 100644 index 0000000..713bcfa --- /dev/null +++ b/style/adwaitapropertynames.cpp @@ -0,0 +1,35 @@ +/************************************************************************* + * 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 "adwaitapropertynames.h" + +namespace Adwaita +{ + + const char PropertyNames::noAnimations[] = "_kde_no_animations"; + const char PropertyNames::noWindowGrab[] = "_kde_no_window_grab"; + const char PropertyNames::netWMForceShadow[] = "_KDE_NET_WM_FORCE_SHADOW"; + const char PropertyNames::netWMSkipShadow[] = "_KDE_NET_WM_SKIP_SHADOW"; + const char PropertyNames::sidePanelView[] = "_kde_side_panel_view"; + const char PropertyNames::toolButtonAlignment[] = "_kde_toolButton_alignment"; + const char PropertyNames::menuTitle[] = "_adwaita_toolButton_menutitle"; + const char PropertyNames::alteredBackground[] = "_adwaita_altered_background"; + +} diff --git a/style/adwaitapropertynames.h b/style/adwaitapropertynames.h new file mode 100644 index 0000000..7479d9e --- /dev/null +++ b/style/adwaitapropertynames.h @@ -0,0 +1,41 @@ +#ifndef adwaitapropertynames_h +#define adwaitapropertynames_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 . * + *************************************************************************/ + + +namespace Adwaita +{ + + struct PropertyNames + { + static const char noAnimations[]; + static const char noWindowGrab[]; + static const char netWMForceShadow[]; + static const char netWMSkipShadow[]; + static const char sidePanelView[]; + static const char toolButtonAlignment[]; + static const char menuTitle[]; + static const char alteredBackground[]; + }; + +} + +#endif diff --git a/style/adwaitasplitterproxy.cpp b/style/adwaitasplitterproxy.cpp new file mode 100644 index 0000000..f777c45 --- /dev/null +++ b/style/adwaitasplitterproxy.cpp @@ -0,0 +1,362 @@ +/************************************************************************* + * 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 "adwaitasplitterproxy.h" + +#include "adwaita.h" +#include "fakeadwaitastyleconfigdata.h" + +#include +#include +#include + +namespace Adwaita +{ + + //____________________________________________________________________ + void SplitterFactory::setEnabled( bool value ) + { + if( _enabled != value ) + { + // store + _enabled = value; + + // assign to existing splitters + for( WidgetMap::iterator iter = _widgets.begin(); iter != _widgets.end(); ++iter ) + { if( iter.value() ) iter.value().data()->setEnabled( value ); } + } + } + + //____________________________________________________________________ + bool SplitterFactory::registerWidget( QWidget *widget ) + { + + // check widget type + if( qobject_cast( widget ) ) + { + + WidgetMap::iterator iter( _widgets.find( widget ) ); + if( iter == _widgets.end() || !iter.value() ) + { + widget->installEventFilter( &_addEventFilter ); + SplitterProxy* proxy( new SplitterProxy( widget, _enabled ) ); + widget->removeEventFilter( &_addEventFilter ); + + widget->installEventFilter( proxy ); + _widgets.insert( widget, proxy ); + + } else { + + widget->removeEventFilter( iter.value().data() ); + widget->installEventFilter( iter.value().data() ); + + } + + return true; + + } else if( qobject_cast( widget ) ) { + + QWidget* window( widget->window() ); + WidgetMap::iterator iter( _widgets.find( window ) ); + if( iter == _widgets.end() || !iter.value() ) + { + + + window->installEventFilter( &_addEventFilter ); + SplitterProxy* proxy( new SplitterProxy( window, _enabled ) ); + window->removeEventFilter( &_addEventFilter ); + + widget->installEventFilter( proxy ); + _widgets.insert( window, proxy ); + + } else { + + widget->removeEventFilter( iter.value().data() ); + widget->installEventFilter( iter.value().data() ); + + } + + return true; + + } else return false; + + } + + //____________________________________________________________________ + void SplitterFactory::unregisterWidget( QWidget *widget ) + { + WidgetMap::iterator iter( _widgets.find( widget ) ); + if( iter != _widgets.end() ) + { + if( iter.value() ) iter.value().data()->deleteLater(); + _widgets.erase( iter ); + } + + } + + //____________________________________________________________________ + SplitterProxy::SplitterProxy( QWidget* parent, bool enabled ): + QWidget( parent ), + _enabled( enabled ), + _timerId( 0 ) + { + setAttribute( Qt::WA_TranslucentBackground, true ); + setAttribute( Qt::WA_OpaquePaintEvent, false ); + hide(); + } + + //____________________________________________________________________ + SplitterProxy::~SplitterProxy( void ) + {} + + //____________________________________________________________________ + void SplitterProxy::setEnabled( bool value ) + { + // make sure status has changed + if( _enabled != value ) + { + _enabled = value; + if( _enabled ) clearSplitter(); + } + } + + //____________________________________________________________________ + bool SplitterProxy::eventFilter( QObject* object, QEvent* event ) + { + + // do nothing if disabled + if( !_enabled ) return false; + + // do nothing in case of mouse grab + if( mouseGrabber() ) return false; + + switch( event->type() ) + { + + case QEvent::HoverEnter: + if( !isVisible() ) + { + + // cast to splitter handle + if( QSplitterHandle* handle = qobject_cast( object ) ) + { setSplitter( handle ); } + + } + + return false; + + case QEvent::HoverMove: + case QEvent::HoverLeave: + return isVisible() && object == _splitter.data(); + + case QEvent::MouseMove: + case QEvent::Timer: + case QEvent::Move: + return false; + + case QEvent::CursorChange: + if( QWidget *window = qobject_cast( object ) ) + { + if( window->cursor().shape() == Qt::SplitHCursor || window->cursor().shape() == Qt::SplitVCursor ) + { setSplitter( window ); } + } + return false; + + case QEvent::WindowDeactivate: + case QEvent::MouseButtonRelease: + clearSplitter(); + return false; + + default: + return false; + + } + + } + + //____________________________________________________________________ + bool SplitterProxy::event( QEvent *event ) + { + switch( event->type() ) + { + + #if 0 + case QEvent::Paint: + { + QPainter painter( this ); + painter.setClipRegion( static_cast( event )->region() ); + painter.setRenderHints( QPainter::Antialiasing ); + painter.setPen( Qt::red ); + painter.drawRect( QRectF( rect() ).adjusted( 0.5, 0.5, -0.5, -0.5 ) ); + return true; + } + #endif + + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + { + + // check splitter + if( !_splitter ) return false; + + event->accept(); + + // grab on mouse press + if( event->type() == QEvent::MouseButtonPress) + { + grabMouse(); + resize(1,1); + } + + // cast to mouse event + QMouseEvent *mouseEvent( static_cast( event ) ); + + // get relevant position to post mouse drag event to application + if( event->type() == QEvent::MouseButtonPress ) + { + + // use hook, to make sure splitter is properly dragged + QMouseEvent copy( + mouseEvent->type(), + _hook, + _splitter.data()->mapToGlobal(_hook), + mouseEvent->button(), + mouseEvent->buttons(), mouseEvent->modifiers()); + + QCoreApplication::sendEvent( _splitter.data(), © ); + + } else { + + // map event position to current splitter and post. + QMouseEvent copy( + mouseEvent->type(), + _splitter.data()->mapFromGlobal( mouseEvent->globalPos() ), + mouseEvent->globalPos(), + mouseEvent->button(), + mouseEvent->buttons(), mouseEvent->modifiers()); + + QCoreApplication::sendEvent( _splitter.data(), © ); + + + } + + // release grab on mouse-Release + if( event->type() == QEvent::MouseButtonRelease && mouseGrabber() == this ) + { releaseMouse(); } + + return true; + + } + + case QEvent::Timer: + if( static_cast( event )->timerId() != _timerId ) + { return QWidget::event( event ); } + + /* + Fall through is intended. + We somehow lost a QEvent::Leave before timeout. We fix it from here + */ + + case QEvent::HoverLeave: + case QEvent::Leave: + { + + if( mouseGrabber() == this ) + { return true; } + + // reset splitter + if( isVisible() && !rect().contains( mapFromGlobal( QCursor::pos() ) ) ) + { clearSplitter(); } + return true; + + } + + default: + return QWidget::event( event ); + + } + + } + + //____________________________________________________________________ + void SplitterProxy::setSplitter( QWidget* widget ) + { + + // check if changed + if( _splitter.data() == widget ) return; + + // get cursor position + QPoint position( QCursor::pos() ); + + // store splitter and hook + _splitter = widget; + _hook = _splitter.data()->mapFromGlobal( position ); + + // adjust rect + QRect rect( 0, 0, 2*StyleConfigData::splitterProxyWidth(), 2*StyleConfigData::splitterProxyWidth() ); + rect.moveCenter( parentWidget()->mapFromGlobal( position ) ); + setGeometry( rect ); + setCursor( _splitter.data()->cursor().shape() ); + + // show + raise(); + show(); + + // timer used to automatically hide proxy in case leave events are lost + if( !_timerId ) _timerId = startTimer(150); + } + + + //____________________________________________________________________ + void SplitterProxy::clearSplitter( void ) + { + + // check if changed + if( !_splitter ) return; + + // release mouse + if( mouseGrabber() == this ) releaseMouse(); + + // hide + parentWidget()->setUpdatesEnabled(false); + hide(); + parentWidget()->setUpdatesEnabled(true); + + // send hover event + if( _splitter ) + { + QHoverEvent hoverEvent( + qobject_cast(_splitter.data()) ? QEvent::HoverLeave : QEvent::HoverMove, + _splitter.data()->mapFromGlobal(QCursor::pos()), _hook); + QCoreApplication::sendEvent( _splitter.data(), &hoverEvent ); + _splitter.clear(); + + } + + // kill timer if any + if( _timerId ) + { + killTimer( _timerId ); + _timerId = 0; + } + + } + +} diff --git a/style/adwaitasplitterproxy.h b/style/adwaitasplitterproxy.h new file mode 100644 index 0000000..0a8bfdc --- /dev/null +++ b/style/adwaitasplitterproxy.h @@ -0,0 +1,138 @@ +#ifndef adwaitasplitterproxy_h +#define adwaitasplitterproxy_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 "adwaita.h" +#include "adwaitaaddeventfilter.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace Adwaita +{ + + class SplitterProxy; + + //* factory + class SplitterFactory: public QObject + { + + Q_OBJECT + + public: + + //* constructor + explicit SplitterFactory( QObject* parent ): + QObject( parent ), + _enabled( false ) + {} + + //* destructor + virtual ~SplitterFactory( void ) + {} + + //* enabled state + void setEnabled( bool ); + + //* register widget + bool registerWidget( QWidget* ); + + //* unregister widget + void unregisterWidget( QWidget* ); + + private: + + //* enabled state + bool _enabled; + + //* needed to block ChildAdded events when creating proxy + AddEventFilter _addEventFilter; + + //* pointer to SplitterProxy + using SplitterProxyPointer = WeakPointer; + + //* registered widgets + using WidgetMap = QMap; + WidgetMap _widgets; + + }; + + //* splitter 'proxy' widget, with extended hit area + class SplitterProxy : public QWidget + { + + Q_OBJECT + + public: + + //* constructor + explicit SplitterProxy( QWidget*, bool = false ); + + //* destructor + virtual ~SplitterProxy( void ); + + //* event filter + virtual bool eventFilter( QObject*, QEvent* ); + + //* enable state + void setEnabled( bool ); + + //* enable state + bool enabled( void ) const + { return _enabled; } + + protected: + + //* event handler + virtual bool event( QEvent* ); + + protected: + + //* reset 'true' splitter widget + void clearSplitter( void ); + + //* keep track of 'true' splitter widget + void setSplitter( QWidget* ); + + private: + + //* enabled state + bool _enabled; + + //* splitter object + WeakPointer _splitter; + + //* hook + QPoint _hook; + + //* timer id + int _timerId; + + }; + +} + +#endif diff --git a/style/adwaitastyle.cpp b/style/adwaitastyle.cpp new file mode 100644 index 0000000..3a47007 --- /dev/null +++ b/style/adwaitastyle.cpp @@ -0,0 +1,7396 @@ +/************************************************************************* + * 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 "adwaitastyle.h" + +#include "adwaita.h" +#include "adwaitaanimations.h" +#include "adwaitahelper.h" +#include "adwaitamnemonics.h" +#include "adwaitapropertynames.h" +#include "adwaitasplitterproxy.h" +#include "fakeadwaitastyleconfigdata.h" +#include "adwaitawidgetexplorer.h" +#include "adwaitawindowmanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AdwaitaPrivate +{ + + // needed to keep track of tabbars when being dragged + class TabBarData: public QObject + { + + public: + + //* constructor + explicit TabBarData( QObject* parent ): + QObject( parent ) + {} + + //* destructor + virtual ~TabBarData( void ) + {} + + //* assign target tabBar + void lock( const QWidget* widget ) + { _tabBar = widget; } + + //* true if tabbar is locked + bool isLocked( const QWidget* widget ) const + { return _tabBar && _tabBar.data() == widget; } + + //* release + void release( void ) + { _tabBar.clear(); } + + private: + + //* pointer to target tabBar + Adwaita::WeakPointer _tabBar; + + }; + + //* needed to have spacing added to items in combobox + class ComboBoxItemDelegate: public QItemDelegate + { + + public: + + //* constructor + ComboBoxItemDelegate( QAbstractItemView* parent ): + QItemDelegate( parent ), + _proxy( parent->itemDelegate() ), + _itemMargin( Adwaita::Metrics::ItemView_ItemMarginWidth ) + {} + + //* destructor + virtual ~ComboBoxItemDelegate( void ) + {} + + //* paint + void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const + { + // call either proxy or parent class + if( _proxy ) _proxy.data()->paint( painter, option, index ); + else QItemDelegate::paint( painter, option, index ); + } + + //* size hint for index + virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const + { + + // get size from either proxy or parent class + QSize size( _proxy ? + _proxy.data()->sizeHint( option, index ): + QItemDelegate::sizeHint( option, index ) ); + + // adjust and return + if( size.isValid() ) { size.rheight() += _itemMargin*2; } + return size; + + } + + private: + + //* proxy + Adwaita::WeakPointer _proxy; + + //* margin + int _itemMargin; + + }; + +} + +void tabLayout(const QStyleOptionTabV3 *opt, const QWidget *widget, QRect *textRect, QRect *iconRect, const QStyle *proxyStyle) { + Q_ASSERT(textRect); + Q_ASSERT(iconRect); + QRect tr = opt->rect; + bool verticalTabs = opt->shape == QTabBar::RoundedEast + || opt->shape == QTabBar::RoundedWest + || opt->shape == QTabBar::TriangularEast + || opt->shape == QTabBar::TriangularWest; + if (verticalTabs) + tr.setRect(0, 0, tr.height(), tr.width()); //0, 0 as we will have a translate transform + + int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget); + int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget); + int hpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2; + int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2; + if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth) + verticalShift = -verticalShift; + tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding); + bool selected = opt->state & QStyle::State_Selected; + if (selected) { + tr.setTop(tr.top() - verticalShift); + tr.setRight(tr.right() - horizontalShift); + } + + // left widget + if (!opt->leftButtonSize.isEmpty()) { + tr.setLeft(tr.left() + 4 + + (verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width())); + } + // right widget + if (!opt->rightButtonSize.isEmpty()) { + tr.setRight(tr.right() - 4 - + (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width())); + } + + // icon + if (!opt->icon.isNull()) { + QSize iconSize = opt->iconSize; + if (!iconSize.isValid()) { + int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize); + iconSize = QSize(iconExtent, iconExtent); + } + QSize tabIconSize = opt->icon.actualSize(iconSize, + (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled, + (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off ); + + *iconRect = QRect(tr.left(), tr.center().y() - tabIconSize.height() / 2, + tabIconSize.width(), tabIconSize .height()); + if (!verticalTabs) + *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect); + tr.setLeft(tr.left() + tabIconSize.width() + 4); + } + + if (!verticalTabs) + tr = proxyStyle->visualRect(opt->direction, opt->rect, tr); + + *textRect = tr; +} + +namespace Adwaita +{ + + //______________________________________________________________ + Style::Style( bool dark ): + _addLineButtons( SingleButton ) + , _subLineButtons( SingleButton ) + + #if ADWAITA_USE_KDE4 + , _helper( new Helper( "adwaita" ) ) + #else + , _helper( new Helper( ) ) + #endif + + + , _animations( new Animations( this ) ) + , _mnemonics( new Mnemonics( this ) ) + , _windowManager( new WindowManager( this ) ) + , _splitterFactory( new SplitterFactory( this ) ) + , _widgetExplorer( new WidgetExplorer( this ) ) + , _tabBarData( new AdwaitaPrivate::TabBarData( this ) ) + #if ADWAITA_USE_KDE4 + , SH_ArgbDndWindow( newStyleHint( QStringLiteral( "SH_ArgbDndWindow" ) ) ) + , CE_CapacityBar( newControlElement( QStringLiteral( "CE_CapacityBar" ) ) ) + #endif + , _dark(dark) + { + + // use DBus connection to update on adwaita configuration change + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.connect( QString(), + QStringLiteral( "/AdwaitaStyle" ), + QStringLiteral( "org.kde.Adwaita.Style" ), + QStringLiteral( "reparseConfiguration" ), this, SLOT(configurationChanged()) ); + + dbus.connect( QString(), + QStringLiteral( "/AdwaitaDecoration" ), + QStringLiteral( "org.kde.Adwaita.Style" ), + QStringLiteral( "reparseConfiguration" ), this, SLOT(configurationChanged()) ); + + // Detect if running under KDE, if so set menus, etc, to have translucent background. + // For GNOME desktop, dont want translucent backgrounds otherwise no menu shadow is drawn. + _isKDE = qgetenv("XDG_CURRENT_DESKTOP").toLower()=="kde"; + _isGNOME = qgetenv("XDG_CURRENT_DESKTOP").toLower()=="gnome"; + + // call the slot directly; this initial call will set up things that also + // need to be reset when the system palette changes + loadConfiguration(); + + } + + //______________________________________________________________ + Style::~Style( void ) + { + delete _helper; + } + + //______________________________________________________________ + void Style::polish( QWidget* widget ) + { + if( !widget ) return; + + // register widget to animations + _animations->registerWidget( widget ); + _windowManager->registerWidget( widget ); + _splitterFactory->registerWidget( widget ); + + // enable mouse over effects for all necessary widgets + if( + qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + || qobject_cast( widget ) + #if QT_VERSION >= 0x050000 + || qobject_cast( widget ) + #endif + || widget->inherits( "KTextEditor::View" ) + ) + { widget->setAttribute( Qt::WA_Hover ); } + + if (qobject_cast(widget)) { + qobject_cast(widget)->setDrawBase(true); + } + + // enforce translucency for drag and drop window + if( widget->testAttribute( Qt::WA_X11NetWmWindowTypeDND ) && _helper->compositingActive() ) + { + widget->setAttribute( Qt::WA_TranslucentBackground ); + widget->clearMask(); + } + + // scrollarea polishing is somewhat complex. It is moved to a dedicated method + polishScrollArea( qobject_cast( widget ) ); + + if( QAbstractItemView *itemView = qobject_cast( widget ) ) + { + + // enable mouse over effects in itemviews' viewport + itemView->viewport()->setAttribute( Qt::WA_Hover ); + + } else if( QGroupBox* groupBox = qobject_cast( widget ) ) { + + // checkable group boxes + if( groupBox->isCheckable() ) + { groupBox->setAttribute( Qt::WA_Hover ); } + + } else if( qobject_cast( widget ) && qobject_cast( widget->parent() ) ) { + + widget->setAttribute( Qt::WA_Hover ); + + } else if( qobject_cast( widget ) && qobject_cast( widget->parent() ) ) { + + widget->setAttribute( Qt::WA_Hover ); + + } else if( qobject_cast( widget ) && widget->parent() && widget->parent()->inherits( "KTitleWidget" ) ) { + + widget->setAutoFillBackground( false ); + if( !StyleConfigData::titleWidgetDrawFrame() ) + { widget->setBackgroundRole( QPalette::Window ); } + + } + + if( qobject_cast( widget ) ) + { + + // remove opaque painting for scrollbars + widget->setAttribute( Qt::WA_OpaquePaintEvent, false ); + + } else if( widget->inherits( "KTextEditor::View" ) ) { + + addEventFilter( widget ); + + } else if( QToolButton* toolButton = qobject_cast( widget ) ) { + + if( toolButton->autoRaise() ) + { + // for flat toolbuttons, adjust foreground and background role accordingly + widget->setBackgroundRole( QPalette::NoRole ); + widget->setForegroundRole( QPalette::WindowText ); + } + + if( widget->parentWidget() && + widget->parentWidget()->parentWidget() && + widget->parentWidget()->parentWidget()->inherits( "Gwenview::SideBarGroup" ) ) + { widget->setProperty( PropertyNames::toolButtonAlignment, Qt::AlignLeft ); } + + } else if( qobject_cast( widget ) ) { + + // add event filter on dock widgets + // and alter palette + widget->setAutoFillBackground( false ); + widget->setContentsMargins( Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth ); + addEventFilter( widget ); + + } else if( qobject_cast( widget ) ) { + + widget->setAutoFillBackground( false ); + addEventFilter( widget ); + + } else if( qobject_cast( widget ) ) { + + widget->setBackgroundRole( QPalette::NoRole ); + widget->setAutoFillBackground( false ); + + } else if( widget->parentWidget() && widget->parentWidget()->parentWidget() && qobject_cast( widget->parentWidget()->parentWidget()->parentWidget() ) ) { + + widget->setBackgroundRole( QPalette::NoRole ); + widget->setAutoFillBackground( false ); + widget->parentWidget()->setAutoFillBackground( false ); + + } else if( qobject_cast( widget ) ) { + + setTranslucentBackground( widget ); + + #if QT_VERSION >= 0x050000 + } else if( qobject_cast( widget ) ) { + + addEventFilter( widget ); + #endif + } else if( QComboBox *comboBox = qobject_cast( widget ) ) { + + if( !hasParent( widget, "QWebView" ) ) + { + QAbstractItemView *itemView( comboBox->view() ); + if( itemView && itemView->itemDelegate() && itemView->itemDelegate()->inherits( "QComboBoxDelegate" ) ) + { itemView->setItemDelegate( new AdwaitaPrivate::ComboBoxItemDelegate( itemView ) ); } + } + + } else if( widget->inherits( "QComboBoxPrivateContainer" ) ) { + + addEventFilter( widget ); + setTranslucentBackground( widget ); + + } else if( widget->inherits( "QTipLabel" ) ) { + + setTranslucentBackground( widget ); + + } + + if (!widget->parent() || !qobject_cast(widget->parent())) { + addEventFilter( widget ); + } + + // base class polishing + ParentStyleClass::polish( widget ); + + } + + //______________________________________________________________ + void Style::polishScrollArea( QAbstractScrollArea* scrollArea ) + { + + // check argument + if( !scrollArea ) return; + + // enable mouse over effect in sunken scrollareas that support focus + if( scrollArea->frameShadow() == QFrame::Sunken && scrollArea->focusPolicy()&Qt::StrongFocus ) + { scrollArea->setAttribute( Qt::WA_Hover ); } + + if( scrollArea->viewport() && scrollArea->inherits( "KItemListContainer" ) && scrollArea->frameShape() == QFrame::NoFrame ) + { + scrollArea->viewport()->setBackgroundRole( QPalette::Window ); + scrollArea->viewport()->setForegroundRole( QPalette::WindowText ); + } + + // add event filter, to make sure proper background is rendered behind scrollbars + addEventFilter( scrollArea ); + + // force side panels as flat, on option + if( scrollArea->inherits( "KDEPrivate::KPageListView" ) || scrollArea->inherits( "KDEPrivate::KPageTreeView" ) ) + { scrollArea->setProperty( PropertyNames::sidePanelView, true ); } + + // for all side view panels, unbold font (design choice) + if( scrollArea->property( PropertyNames::sidePanelView ).toBool() ) + { + // upbold list font + QFont font( scrollArea->font() ); + font.setBold( false ); + scrollArea->setFont( font ); + + // adjust background role + if( !StyleConfigData::sidePanelDrawFrame() ) + { + scrollArea->setBackgroundRole( QPalette::Window ); + scrollArea->setForegroundRole( QPalette::WindowText ); + + if( scrollArea->viewport() ) + { + scrollArea->viewport()->setBackgroundRole( QPalette::Window ); + scrollArea->viewport()->setForegroundRole( QPalette::WindowText ); + } + + } + + } + + // disable autofill background for flat (== NoFrame) scrollareas, with QPalette::Window as a background + // this fixes flat scrollareas placed in a tinted widget, such as groupboxes, tabwidgets or framed dock-widgets + if( !(scrollArea->frameShape() == QFrame::NoFrame || scrollArea->backgroundRole() == QPalette::Window ) ) + { return; } + + // get viewport and check background role + QWidget* viewport( scrollArea->viewport() ); + if( !( viewport && viewport->backgroundRole() == QPalette::Window ) ) return; + + // change viewport autoFill background. + // do the same for all children if the background role is QPalette::Window + viewport->setAutoFillBackground( false ); + QList children( viewport->findChildren() ); + foreach( QWidget* child, children ) + { + if( child->parent() == viewport && child->backgroundRole() == QPalette::Window ) + { child->setAutoFillBackground( false ); } + } + + } + + //_______________________________________________________________ + void Style::unpolish( QWidget* widget ) + { + + // register widget to animations + _animations->unregisterWidget( widget ); + _windowManager->unregisterWidget( widget ); + _splitterFactory->unregisterWidget( widget ); + + // remove event filter + if( qobject_cast( widget ) || + qobject_cast( widget ) || + qobject_cast( widget ) || + widget->inherits( "QComboBoxPrivateContainer" ) || + qobject_cast(widget) || + qobject_cast(widget)) + { widget->removeEventFilter( this ); } + + ParentStyleClass::unpolish( widget ); + + } + + void Style::polish(QPalette &palette) + { + + if (_dark) { + palette.setColor(QPalette::All, QPalette::Window, QColor("#33393b")); + palette.setColor(QPalette::All, QPalette::WindowText, QColor("white")); + palette.setColor(QPalette::All, QPalette::Base, QColor("#232729")); + palette.setColor(QPalette::All, QPalette::AlternateBase, QColor("#1c1f20")); + palette.setColor(QPalette::All, QPalette::ToolTipBase, QColor("#1c1f20")); + palette.setColor(QPalette::All, QPalette::ToolTipText, QColor("white")); + palette.setColor(QPalette::All, QPalette::Text, QColor("white")); + palette.setColor(QPalette::All, QPalette::Button, QColor("#25292b")); + palette.setColor(QPalette::All, QPalette::ButtonText, QColor("white")); + palette.setColor(QPalette::All, QPalette::BrightText, QColor("black")); + + palette.setColor(QPalette::All, QPalette::Light, QColor("white")); + palette.setColor(QPalette::All, QPalette::Midlight, QColor("#d7d7d7")); + palette.setColor(QPalette::All, QPalette::Mid, QColor("#b4b4b4")); + palette.setColor(QPalette::All, QPalette::Dark, QColor("#1a1a1a")); + palette.setColor(QPalette::All, QPalette::Shadow, QColor("black")); + + palette.setColor(QPalette::All, QPalette::Highlight, QColor("#4a90d9")); + palette.setColor(QPalette::All, QPalette::HighlightedText, QColor("white")); + + palette.setColor(QPalette::All, QPalette::Link, QColor("#2a76c6")); + palette.setColor(QPalette::All, QPalette::LinkVisited, QColor("#2a76c6")); + + + palette.setColor(QPalette::Disabled, QPalette::Window, QColor("#2e3436")); + palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor("#8d9091")); + palette.setColor(QPalette::Disabled, QPalette::Base, QColor("#3d4244")); + palette.setColor(QPalette::Disabled, QPalette::AlternateBase, QColor("#3a3d3e")); + palette.setColor(QPalette::Disabled, QPalette::Text, QColor("#8d9091")); + palette.setColor(QPalette::Disabled, QPalette::Button, QColor("#33393b")); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor("#8d9091")); + palette.setColor(QPalette::Disabled, QPalette::BrightText, QColor("#ededed")); + + palette.setColor(QPalette::Disabled, QPalette::Light, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::Midlight, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::Dark, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::Mid, QColor("#c3c3c3")); + palette.setColor(QPalette::Disabled, QPalette::Shadow, QColor("black")); + + palette.setColor(QPalette::Disabled, QPalette::Highlight, QColor("#4a90d9")); + palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor("white")); + + palette.setColor(QPalette::Disabled, QPalette::Link, QColor("#4a90d9")); + palette.setColor(QPalette::Disabled, QPalette::LinkVisited, QColor("#4a90d9")); + + + palette.setColor(QPalette::Inactive, QPalette::Window, QColor("#33393b")); + palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor("#d3d4d5")); + palette.setColor(QPalette::Inactive, QPalette::Base, QColor("#252a2c")); + palette.setColor(QPalette::Inactive, QPalette::AlternateBase, QColor("#1d2021")); + palette.setColor(QPalette::Inactive, QPalette::Text, QColor("#d3d4d5")); + palette.setColor(QPalette::Inactive, QPalette::Button, QColor("#33393b")); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, QColor("#eeeeec")); + palette.setColor(QPalette::Inactive, QPalette::BrightText, QColor("#d3d4d5")); + + palette.setColor(QPalette::Inactive, QPalette::Light, QColor("white")); + palette.setColor(QPalette::Inactive, QPalette::Midlight, QColor("#d7d7d7")); + palette.setColor(QPalette::Inactive, QPalette::Mid, QColor("#b4b4b4")); + palette.setColor(QPalette::Inactive, QPalette::Dark, QColor("#33393b")); + palette.setColor(QPalette::Inactive, QPalette::Shadow, QColor("black")); + + palette.setColor(QPalette::Inactive, QPalette::Highlight, QColor("#4a90d9")); + palette.setColor(QPalette::Inactive, QPalette::HighlightedText, QColor("white")); + + palette.setColor(QPalette::Inactive, QPalette::Link, QColor("#4a90d9")); + palette.setColor(QPalette::Inactive, QPalette::LinkVisited, QColor("#4a90d9")); + } + else { + palette.setColor(QPalette::All, QPalette::Window, QColor("#ededed")); + palette.setColor(QPalette::All, QPalette::WindowText, QColor("#2e3436")); + palette.setColor(QPalette::All, QPalette::Base, QColor("white")); + palette.setColor(QPalette::All, QPalette::AlternateBase, QColor("#ededed")); + palette.setColor(QPalette::All, QPalette::ToolTipBase, QColor("#060606")); + palette.setColor(QPalette::All, QPalette::ToolTipText, QColor("white")); + palette.setColor(QPalette::All, QPalette::Text, QColor("#2e3436")); + palette.setColor(QPalette::All, QPalette::Button, QColor("#eeeeee")); + palette.setColor(QPalette::All, QPalette::ButtonText, QColor("#2e3436")); + palette.setColor(QPalette::All, QPalette::BrightText, QColor("white")); + + palette.setColor(QPalette::All, QPalette::Light, QColor("#fafafa")); + palette.setColor(QPalette::All, QPalette::Midlight, QColor("#f3f3f3")); + palette.setColor(QPalette::All, QPalette::Dark, QColor("#d3d3d3")); + palette.setColor(QPalette::All, QPalette::Mid, QColor("#b4b4b4")); + palette.setColor(QPalette::All, QPalette::Shadow, QColor("black")); + + palette.setColor(QPalette::All, QPalette::Highlight, QColor("#4a90d9")); + palette.setColor(QPalette::All, QPalette::HighlightedText, QColor("white")); + + palette.setColor(QPalette::All, QPalette::Link, QColor("#2a76c6")); + palette.setColor(QPalette::All, QPalette::LinkVisited, QColor("#2a76c6")); + + + palette.setColor(QPalette::Disabled, QPalette::Window, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor("#8d9091")); + palette.setColor(QPalette::Disabled, QPalette::Base, QColor("white")); + palette.setColor(QPalette::Disabled, QPalette::AlternateBase, QColor("#ededed")); + palette.setColor(QPalette::Disabled, QPalette::Text, QColor("#8d9091")); + palette.setColor(QPalette::Disabled, QPalette::Button, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor("#8d9091")); + palette.setColor(QPalette::Disabled, QPalette::BrightText, QColor("#ededed")); + + palette.setColor(QPalette::Disabled, QPalette::Light, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::Midlight, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::Dark, QColor("#f4f4f4")); + palette.setColor(QPalette::Disabled, QPalette::Mid, QColor("#c3c3c3")); + palette.setColor(QPalette::Disabled, QPalette::Shadow, QColor("black")); + + palette.setColor(QPalette::Disabled, QPalette::Highlight, QColor("#4a90d9")); + palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor("white")); + + palette.setColor(QPalette::Disabled, QPalette::Link, QColor("#4a90d9")); + palette.setColor(QPalette::Disabled, QPalette::LinkVisited, QColor("#4a90d9")); + + + palette.setColor(QPalette::Inactive, QPalette::Window, QColor("#ededed")); + palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor("#54595a")); + palette.setColor(QPalette::Inactive, QPalette::Base, QColor("#fcfcfc")); + palette.setColor(QPalette::Inactive, QPalette::AlternateBase, QColor("#ededed")); + palette.setColor(QPalette::Inactive, QPalette::Text, QColor("#54595a")); + palette.setColor(QPalette::Inactive, QPalette::Button, QColor("#ededed")); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, QColor("#54595a")); + palette.setColor(QPalette::Inactive, QPalette::BrightText, QColor("#ededed")); + + palette.setColor(QPalette::Inactive, QPalette::Light, QColor("#ededed")); + palette.setColor(QPalette::Inactive, QPalette::Midlight, QColor("#ededed")); + palette.setColor(QPalette::Inactive, QPalette::Dark, QColor("#ededed")); + palette.setColor(QPalette::Inactive, QPalette::Mid, QColor("#c3c3c3")); + palette.setColor(QPalette::Inactive, QPalette::Shadow, QColor("black")); + + palette.setColor(QPalette::Inactive, QPalette::Highlight, QColor("#4a90d9")); + palette.setColor(QPalette::Inactive, QPalette::HighlightedText, QColor("white")); + + palette.setColor(QPalette::Inactive, QPalette::Link, QColor("#4a90d9")); + palette.setColor(QPalette::Inactive, QPalette::LinkVisited, QColor("#4a90d9")); + } + } + + //______________________________________________________________ + int Style::pixelMetric( PixelMetric metric, const QStyleOption* option, const QWidget* widget ) const + { + + // handle special cases + switch( metric ) + { + + // frame width + case PM_DefaultFrameWidth: + if ( widget && widget->inherits("QComboBoxPrivateContainer") ) return 1; + if( qobject_cast( widget ) ) return Metrics::Menu_FrameWidth; + if( qobject_cast( widget ) ) return Metrics::LineEdit_FrameWidth; + if( qobject_cast( widget ) ) return Metrics::ScrollArea_FrameWidth; + #if QT_VERSION >= 0x050000 + else if( isQtQuickControl( option, widget ) ) + { + const QString &elementType = option->styleObject->property( "elementType" ).toString(); + if( elementType == QLatin1String( "edit" ) || elementType == QLatin1String( "spinbox" ) ) + { + + return Metrics::LineEdit_FrameWidth; + + } else if( elementType == QLatin1String( "combobox" ) ) { + + return Metrics::ComboBox_FrameWidth; + } + + } + #endif + + // fallback + return Metrics::Frame_FrameWidth; + + case PM_ComboBoxFrameWidth: + { + const QStyleOptionComboBox* comboBoxOption( qstyleoption_cast< const QStyleOptionComboBox*>( option ) ); + return comboBoxOption && comboBoxOption->editable ? Metrics::LineEdit_FrameWidth : Metrics::ComboBox_FrameWidth; + } + + case PM_SpinBoxFrameWidth: return Metrics::SpinBox_FrameWidth; + case PM_ToolBarFrameWidth: return Metrics::ToolBar_FrameWidth; + case PM_ToolTipLabelFrameWidth: return Metrics::ToolTip_FrameWidth; + + // layout + case PM_LayoutLeftMargin: + case PM_LayoutTopMargin: + case PM_LayoutRightMargin: + case PM_LayoutBottomMargin: + { + /* + * use either Child margin or TopLevel margin, + * depending on widget type + */ + if( ( option && ( option->state & QStyle::State_Window ) ) || ( widget && widget->isWindow() ) ) + { + + return Metrics::Layout_TopLevelMarginWidth; + + } else if( widget && widget->inherits( "KPageView" ) ) { + + return 0; + + } else { + + return Metrics::Layout_ChildMarginWidth; + + } + + } + + case PM_LayoutHorizontalSpacing: return Metrics::Layout_DefaultSpacing; + case PM_LayoutVerticalSpacing: return Metrics::Layout_DefaultSpacing; + + // buttons + case PM_ButtonMargin: + { + // needs special case for kcalc buttons, to prevent the application to set too small margins + if( widget && widget->inherits( "KCalcButton" ) ) return Metrics::Button_MarginWidth + 4; + else return Metrics::Button_MarginWidth; + } + + case PM_ButtonDefaultIndicator: return 0; + case PM_ButtonShiftHorizontal: return 0; + case PM_ButtonShiftVertical: return 0; + + // menubars + case PM_MenuBarPanelWidth: return 0; + case PM_MenuBarHMargin: return 0; + case PM_MenuBarVMargin: return 0; + case PM_MenuBarItemSpacing: return 0; + case PM_MenuDesktopFrameWidth: return 0; + + // menu buttons + case PM_MenuButtonIndicator: return Metrics::MenuButton_IndicatorWidth; + case PM_MenuVMargin: return 2; + case PM_MenuHMargin: return _isGNOME ? 0 : 1; + + // toolbars + case PM_ToolBarHandleExtent: return Metrics::ToolBar_HandleExtent; + case PM_ToolBarSeparatorExtent: return Metrics::ToolBar_SeparatorWidth; + case PM_ToolBarExtensionExtent: + return pixelMetric( PM_SmallIconSize, option, widget ) + 2*Metrics::ToolButton_MarginWidth; + + case PM_ToolBarItemMargin: return 0; + case PM_ToolBarItemSpacing: return Metrics::ToolBar_ItemSpacing; + + // tabbars + case PM_TabBarTabShiftVertical: return 0; + case PM_TabBarTabShiftHorizontal: return 0; + case PM_TabBarTabOverlap: return Metrics::TabBar_TabOverlap; + case PM_TabBarBaseOverlap: return Metrics::TabBar_BaseOverlap; + case PM_TabBarTabHSpace: return 2*Metrics::TabBar_TabMarginWidth; + case PM_TabBarTabVSpace: return 2*Metrics::TabBar_TabMarginHeight; + case PM_TabCloseIndicatorWidth: + case PM_TabCloseIndicatorHeight: + return pixelMetric( PM_SmallIconSize, option, widget ); + + // scrollbars + case PM_ScrollBarExtent: return Metrics::ScrollBar_Extend; + case PM_ScrollBarSliderMin: return Metrics::ScrollBar_MinSliderHeight; + + // title bar + case PM_TitleBarHeight: return 2*Metrics::TitleBar_MarginWidth + pixelMetric( PM_SmallIconSize, option, widget ); + + // sliders + case PM_SliderThickness: return Metrics::Slider_ControlThickness; + case PM_SliderControlThickness: return Metrics::Slider_ControlThickness; + case PM_SliderLength: return Metrics::Slider_ControlThickness; + + // checkboxes and radio buttons + case PM_IndicatorWidth: return Metrics::CheckBox_Size; + case PM_IndicatorHeight: return Metrics::CheckBox_Size; + case PM_ExclusiveIndicatorWidth: return Metrics::CheckBox_Size; + case PM_ExclusiveIndicatorHeight: return Metrics::CheckBox_Size; + + // list heaaders + case PM_HeaderMarkSize: return Metrics::Header_ArrowSize; + case PM_HeaderMargin: return Metrics::Header_MarginWidth; + + // dock widget + // return 0 here, since frame is handled directly in polish + case PM_DockWidgetFrameWidth: return 0; + case PM_DockWidgetTitleMargin: return Metrics::Frame_FrameWidth; + case PM_DockWidgetTitleBarButtonMargin: return Metrics::ToolButton_MarginWidth; + + case PM_SplitterWidth: return Metrics::Splitter_SplitterWidth; + case PM_DockWidgetSeparatorExtent: return Metrics::Splitter_SplitterWidth; + + // fallback + default: return ParentStyleClass::pixelMetric( metric, option, widget ); + + } + + } + + //______________________________________________________________ + int Style::styleHint( StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData ) const + { + switch( hint ) + { + + case SH_RubberBand_Mask: + { + + if( QStyleHintReturnMask *mask = qstyleoption_cast( returnData ) ) + { + + mask->region = option->rect; + + /* + * need to check on widget before removing inner region + * in order to still preserve rubberband in MainWindow and QGraphicsView + * in QMainWindow because it looks better + * in QGraphicsView because the painting fails completely otherwise + */ + if( widget && ( + qobject_cast( widget->parent() ) || + qobject_cast( widget->parent() ) || + qobject_cast( widget->parent() ) ) ) + { return true; } + + // also check if widget's parent is some itemView viewport + if( widget && widget->parent() && + qobject_cast( widget->parent()->parent() ) && + static_cast( widget->parent()->parent() )->viewport() == widget->parent() ) + { return true; } + + // mask out center + mask->region -= insideMargin( option->rect, 1 ); + + return true; + } + return false; + } + + case SH_ComboBox_ListMouseTracking: return true; + case SH_MenuBar_MouseTracking: return true; + case SH_Menu_MouseTracking: return true; + case SH_Menu_SubMenuPopupDelay: return 150; + case SH_Menu_SloppySubMenus: return true; + + #if QT_VERSION >= 0x050000 + case SH_Widget_Animate: return StyleConfigData::animationsEnabled(); + case SH_Menu_SupportsSections: return true; + #endif + + case SH_DialogButtonBox_ButtonsHaveIcons: return false; + + case SH_GroupBox_TextLabelVerticalAlignment: return Qt::AlignVCenter; + case SH_TabBar_Alignment: return StyleConfigData::tabBarDrawCenteredTabs() ? Qt::AlignCenter:Qt::AlignLeft; + case SH_ToolBox_SelectedPageTitleBold: return false; + case SH_ScrollBar_MiddleClickAbsolutePosition: return true; + case SH_ScrollView_FrameOnlyAroundContents: return false; + case SH_FormLayoutFormAlignment: return Qt::AlignLeft | Qt::AlignTop; + case SH_FormLayoutLabelAlignment: return Qt::AlignRight; + case SH_FormLayoutFieldGrowthPolicy: return QFormLayout::ExpandingFieldsGrow; + case SH_FormLayoutWrapPolicy: return QFormLayout::DontWrapRows; + case SH_MessageBox_TextInteractionFlags: return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; + case SH_ProgressDialog_CenterCancelButton: return false; + case SH_MessageBox_CenterButtons: return false; + + case SH_RequestSoftwareInputPanel: return RSIP_OnMouseClick; + case SH_TitleBar_NoBorder: return true; + case SH_DockWidget_ButtonsHaveFrame: return false; + default: return ParentStyleClass::styleHint( hint, option, widget, returnData ); + + } + + } + + //______________________________________________________________ + QRect Style::subElementRect( SubElement element, const QStyleOption* option, const QWidget* widget ) const + { + switch( element ) + { + + case SE_PushButtonContents: return pushButtonContentsRect( option, widget ); + case SE_PushButtonFocusRect: return pushButtonFocusRect( option, widget ); + case SE_CheckBoxContents: return checkBoxContentsRect( option, widget ); + case SE_CheckBoxIndicator: return checkBoxIndicatorRect( option, widget ); + case SE_CheckBoxFocusRect: return checkBoxFocusRect( option, widget ); + case SE_RadioButtonContents: return checkBoxContentsRect( option, widget ); + case SE_RadioButtonIndicator: return checkBoxIndicatorRect( option, widget ); + case SE_RadioButtonFocusRect: return checkBoxFocusRect( option, widget ); + case SE_LineEditContents: return lineEditContentsRect( option, widget ); + case SE_ProgressBarGroove: return progressBarGrooveRect( option, widget ); + case SE_ProgressBarContents: return progressBarContentsRect( option, widget ); + case SE_ProgressBarLabel: return progressBarLabelRect( option, widget ); + case SE_HeaderArrow: return headerArrowRect( option, widget ); + case SE_HeaderLabel: return headerLabelRect( option, widget ); + case SE_SliderFocusRect: return sliderFocusRect( option, widget ); + case SE_TabBarTabLeftButton: return tabBarTabLeftButtonRect( option, widget ); + case SE_TabBarTabRightButton: return tabBarTabRightButtonRect( option, widget ); + case SE_TabWidgetTabBar: return tabWidgetTabBarRect( option, widget ); + case SE_TabWidgetTabContents: return tabWidgetTabContentsRect( option, widget ); + case SE_TabWidgetTabPane: return tabWidgetTabPaneRect( option, widget ); + case SE_TabWidgetLeftCorner: return tabWidgetCornerRect( SE_TabWidgetLeftCorner, option, widget ); + case SE_TabWidgetRightCorner: return tabWidgetCornerRect( SE_TabWidgetRightCorner, option, widget ); + case SE_ToolBoxTabContents: return toolBoxTabContentsRect( option, widget ); + // fallback + default: return ParentStyleClass::subElementRect( element, option, widget ); + + } + } + + //______________________________________________________________ + QRect Style::subControlRect( ComplexControl element, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + + switch( element ) + { + + case CC_GroupBox: return groupBoxSubControlRect( option, subControl, widget ); + case CC_ToolButton: return toolButtonSubControlRect( option, subControl, widget ); + case CC_ComboBox: return comboBoxSubControlRect( option, subControl, widget ); + case CC_SpinBox: return spinBoxSubControlRect( option, subControl, widget ); + case CC_ScrollBar: return scrollBarSubControlRect( option, subControl, widget ); + case CC_Dial: return dialSubControlRect( option, subControl, widget ); + case CC_Slider: return sliderSubControlRect( option, subControl, widget ); + + // fallback + default: return ParentStyleClass::subControlRect( element, option, subControl, widget ); + + } + + } + + //______________________________________________________________ + QSize Style::sizeFromContents( ContentsType element, const QStyleOption* option, const QSize& size, const QWidget* widget ) const + { + + switch( element ) + { + case CT_CheckBox: return checkBoxSizeFromContents( option, size, widget ); + case CT_RadioButton: return checkBoxSizeFromContents( option, size, widget ); + case CT_LineEdit: return lineEditSizeFromContents( option, size, widget ); + case CT_ComboBox: return comboBoxSizeFromContents( option, size, widget ); + case CT_SpinBox: return spinBoxSizeFromContents( option, size, widget ); + case CT_Slider: return sliderSizeFromContents( option, size, widget ); + case CT_PushButton: return pushButtonSizeFromContents( option, size, widget ); + case CT_ToolButton: return toolButtonSizeFromContents( option, size, widget ); + case CT_MenuBar: return defaultSizeFromContents( option, size, widget ); + case CT_MenuBarItem: return menuBarItemSizeFromContents( option, size, widget ); + case CT_MenuItem: return menuItemSizeFromContents( option, size, widget ); + case CT_ProgressBar: return progressBarSizeFromContents( option, size, widget ); + case CT_TabWidget: return tabWidgetSizeFromContents( option, size, widget ); + case CT_TabBarTab: return tabBarTabSizeFromContents( option, size, widget ); + case CT_HeaderSection: return headerSectionSizeFromContents( option, size, widget ); + case CT_ItemViewItem: return itemViewItemSizeFromContents( option, size, widget ); + + // fallback + default: return ParentStyleClass::sizeFromContents( element, option, size, widget ); + } + + } + + //______________________________________________________________ + QStyle::SubControl Style::hitTestComplexControl( ComplexControl control, const QStyleOptionComplex* option, const QPoint& point, const QWidget* widget ) const + { + switch( control ) + { + case CC_ScrollBar: + { + + QRect grooveRect = subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ); + if( grooveRect.contains( point ) ) + { + // Must be either page up/page down, or just click on the slider. + QRect sliderRect = subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ); + + if( sliderRect.contains( point ) ) return SC_ScrollBarSlider; + else if( preceeds( point, sliderRect, option ) ) return SC_ScrollBarSubPage; + else return SC_ScrollBarAddPage; + + } + + // This is one of the up/down buttons. First, decide which one it is. + if( preceeds( point, grooveRect, option ) ) + { + + if( _subLineButtons == DoubleButton ) + { + + QRect buttonRect = scrollBarInternalSubControlRect( option, SC_ScrollBarSubLine ); + return scrollBarHitTest( buttonRect, point, option ); + + } else return SC_ScrollBarSubLine; + + } + + if( _addLineButtons == DoubleButton ) + { + + QRect buttonRect = scrollBarInternalSubControlRect( option, SC_ScrollBarAddLine ); + return scrollBarHitTest( buttonRect, point, option ); + + } else return SC_ScrollBarAddLine; + } + + // fallback + default: return ParentStyleClass::hitTestComplexControl( control, option, point, widget ); + + } + + } + + //______________________________________________________________ + void Style::drawPrimitive( PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + StylePrimitive fcn( nullptr ); + switch( element ) + { + + + case PE_PanelButtonCommand: fcn = &Style::drawPanelButtonCommandPrimitive; break; + case PE_PanelButtonTool: fcn = &Style::drawPanelButtonToolPrimitive; break; + case PE_PanelScrollAreaCorner: fcn = &Style::drawPanelScrollAreaCornerPrimitive; break; + case PE_PanelMenu: fcn = &Style::drawPanelMenuPrimitive; break; + case PE_PanelTipLabel: fcn = &Style::drawPanelTipLabelPrimitive; break; + case PE_PanelItemViewItem: fcn = &Style::drawPanelItemViewItemPrimitive; break; + case PE_IndicatorCheckBox: fcn = &Style::drawIndicatorCheckBoxPrimitive; break; + case PE_IndicatorRadioButton: fcn = &Style::drawIndicatorRadioButtonPrimitive; break; + case PE_IndicatorButtonDropDown: fcn = &Style::drawIndicatorButtonDropDownPrimitive; break; + case PE_IndicatorTabClose: fcn = &Style::drawIndicatorTabClosePrimitive; break; + case PE_IndicatorTabTear: fcn = &Style::drawIndicatorTabTearPrimitive; break; + case PE_IndicatorArrowUp: fcn = &Style::drawIndicatorArrowUpPrimitive; break; + case PE_IndicatorArrowDown: fcn = &Style::drawIndicatorArrowDownPrimitive; break; + case PE_IndicatorArrowLeft: fcn = &Style::drawIndicatorArrowLeftPrimitive; break; + case PE_IndicatorArrowRight: fcn = &Style::drawIndicatorArrowRightPrimitive; break; + case PE_IndicatorHeaderArrow: fcn = &Style::drawIndicatorHeaderArrowPrimitive; break; + case PE_IndicatorToolBarHandle: fcn = &Style::drawIndicatorToolBarHandlePrimitive; break; + case PE_IndicatorToolBarSeparator: fcn = &Style::drawIndicatorToolBarSeparatorPrimitive; break; + case PE_IndicatorBranch: fcn = &Style::drawIndicatorBranchPrimitive; break; + case PE_FrameStatusBar: fcn = &Style::emptyPrimitive; break; + case PE_Frame: fcn = &Style::drawFramePrimitive; break; + case PE_FrameLineEdit: fcn = &Style::drawFrameLineEditPrimitive; break; + case PE_FrameMenu: fcn = &Style::drawFrameMenuPrimitive; break; + case PE_FrameGroupBox: fcn = &Style::drawFrameGroupBoxPrimitive; break; + case PE_FrameTabWidget: fcn = &Style::drawFrameTabWidgetPrimitive; break; + case PE_FrameTabBarBase: fcn = &Style::drawFrameTabBarBasePrimitive; break; + case PE_FrameWindow: fcn = &Style::drawFrameWindowPrimitive; break; + case PE_FrameFocusRect: fcn = _frameFocusPrimitive; break; + // fallback + default: break; + + } + + painter->save(); + + // call function if implemented + if( !( fcn && ( this->*fcn )( option, painter, widget ) ) ) + { ParentStyleClass::drawPrimitive( element, option, painter, widget ); } + + painter->restore(); + + } + + //______________________________________________________________ + void Style::drawControl( ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + StyleControl fcn( nullptr ); + + #if ADWAITA_HAVE_KSTYLE||ADWAITA_USE_KDE4 + if( element == CE_CapacityBar ) + { + fcn = &Style::drawProgressBarControl; + + } else + #endif + + switch( element ) { + case CE_PushButtonBevel: fcn = &Style::drawPanelButtonCommandPrimitive; break; + case CE_PushButtonLabel: fcn = &Style::drawPushButtonLabelControl; break; + case CE_CheckBoxLabel: fcn = &Style::drawCheckBoxLabelControl; break; + case CE_RadioButtonLabel: fcn = &Style::drawCheckBoxLabelControl; break; + case CE_ToolButtonLabel: fcn = &Style::drawToolButtonLabelControl; break; + case CE_ComboBoxLabel: fcn = &Style::drawComboBoxLabelControl; break; + case CE_MenuBarEmptyArea: fcn = &Style::drawMenuBarEmptyArea; break; + case CE_MenuBarItem: fcn = &Style::drawMenuBarItemControl; break; + case CE_MenuEmptyArea: fcn = &Style::drawMenuEmptyAreaControl; break; + case CE_MenuItem: fcn = &Style::drawMenuItemControl; break; + case CE_ToolBar: fcn = &Style::emptyControl; break; + case CE_ProgressBar: fcn = &Style::drawProgressBarControl; break; + case CE_ProgressBarContents: fcn = &Style::drawProgressBarContentsControl; break; + case CE_ProgressBarGroove: fcn = &Style::drawProgressBarGrooveControl; break; + case CE_ProgressBarLabel: fcn = &Style::drawProgressBarLabelControl; break; + case CE_ScrollBarSlider: fcn = &Style::drawScrollBarSliderControl; break; + case CE_ScrollBarAddLine: fcn = &Style::drawScrollBarAddLineControl; break; + case CE_ScrollBarSubLine: fcn = &Style::drawScrollBarSubLineControl; break; + case CE_ScrollBarAddPage: fcn = &Style::emptyControl; break; + case CE_ScrollBarSubPage: fcn = &Style::emptyControl; break; + case CE_ShapedFrame: fcn = &Style::drawShapedFrameControl; break; + case CE_RubberBand: fcn = &Style::drawRubberBandControl; break; + case CE_SizeGrip: fcn = &Style::emptyControl; break; + case CE_HeaderSection: fcn = &Style::drawHeaderSectionControl; break; + case CE_HeaderLabel: fcn = &Style::drawHeaderLabelControl; break; + case CE_HeaderEmptyArea: fcn = &Style::drawHeaderEmptyAreaControl; break; + case CE_TabBarTabLabel: fcn = &Style::drawTabBarTabLabelControl; break; + case CE_TabBarTabShape: fcn = &Style::drawTabBarTabShapeControl; break; + case CE_ToolBoxTabLabel: fcn = &Style::drawToolBoxTabLabelControl; break; + case CE_ToolBoxTabShape: fcn = &Style::drawToolBoxTabShapeControl; break; + case CE_DockWidgetTitle: fcn = &Style::drawDockWidgetTitleControl; break; + // fallback + default: break; + + } + + painter->save(); + + // call function if implemented + if( !( fcn && ( this->*fcn )( option, painter, widget ) ) ) + { ParentStyleClass::drawControl( element, option, painter, widget ); } + + painter->restore(); + + } + + //______________________________________________________________ + void Style::drawComplexControl( ComplexControl element, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + StyleComplexControl fcn( nullptr ); + switch( element ) + { + case CC_GroupBox: fcn = &Style::drawGroupBoxComplexControl; break; + case CC_ToolButton: fcn = &Style::drawToolButtonComplexControl; break; + case CC_ComboBox: fcn = &Style::drawComboBoxComplexControl; break; + case CC_SpinBox: fcn = &Style::drawSpinBoxComplexControl; break; + case CC_Slider: fcn = &Style::drawSliderComplexControl; break; + case CC_Dial: fcn = &Style::drawDialComplexControl; break; + case CC_ScrollBar: fcn = &Style::drawScrollBarComplexControl; break; + case CC_TitleBar: fcn = &Style::drawTitleBarComplexControl; break; + + // fallback + default: break; + } + + + painter->save(); + + // call function if implemented + if( !( fcn && ( this->*fcn )( option, painter, widget ) ) ) + { ParentStyleClass::drawComplexControl( element, option, painter, widget ); } + + painter->restore(); + } + + + //___________________________________________________________________________________ + void Style::drawItemText( + QPainter* painter, const QRect& rect, int flags, const QPalette& palette, bool enabled, + const QString &text, QPalette::ColorRole textRole ) const + { + + // hide mnemonics if requested + if( !_mnemonics->enabled() && ( flags&Qt::TextShowMnemonic ) && !( flags&Qt::TextHideMnemonic ) ) + { + flags &= ~Qt::TextShowMnemonic; + flags |= Qt::TextHideMnemonic; + } + + // make sure vertical alignment is defined + // fallback on Align::VCenter if not + if( !(flags&Qt::AlignVertical_Mask) ) flags |= Qt::AlignVCenter; + + if( _animations->widgetEnabilityEngine().enabled() ) + { + + /* + * check if painter engine is registered to WidgetEnabilityEngine, and animated + * if yes, merge the palettes. Note: a static_cast is safe here, since only the address + * of the pointer is used, not the actual content. + */ + const QWidget* widget( static_cast( painter->device() ) ); + if( _animations->widgetEnabilityEngine().isAnimated( widget, AnimationEnable ) ) + { + + QPalette copy( _helper->disabledPalette( palette, _animations->widgetEnabilityEngine().opacity( widget, AnimationEnable ) ) ); + return ParentStyleClass::drawItemText( painter, rect, flags, copy, enabled, text, textRole ); + + } + + } + + // fallback + return ParentStyleClass::drawItemText( painter, rect, flags, palette, enabled, text, textRole ); + + } + + //_____________________________________________________________________ + bool Style::eventFilter( QObject *object, QEvent *event ) + { + + if( QDockWidget* dockWidget = qobject_cast( object ) ) { return eventFilterDockWidget( dockWidget, event ); } + else if( QMdiSubWindow* subWindow = qobject_cast( object ) ) { return eventFilterMdiSubWindow( subWindow, event ); } + #if QT_VERSION >= 0x050000 + else if( QCommandLinkButton* commandLinkButton = qobject_cast( object ) ) { return eventFilterCommandLinkButton( commandLinkButton, event ); } + #endif + // cast to QWidget + QWidget *widget = static_cast( object ); + if( widget->inherits( "QAbstractScrollArea" ) || widget->inherits( "KTextEditor::View" ) ) { return eventFilterScrollArea( widget, event ); } + else if( widget->inherits( "QComboBoxPrivateContainer" ) ) { return eventFilterComboBoxContainer( widget, event ); } + + if ((!widget->parent() || !qobject_cast(widget->parent())) && + (QEvent::Show==event->type() || QEvent::StyleChange==event->type())) { + _helper->setVariant(widget, _dark ? "dark" : "light"); + } + + // fallback + return ParentStyleClass::eventFilter( object, event ); + + } + + //____________________________________________________________________________ + bool Style::eventFilterScrollArea( QWidget* widget, QEvent* event ) + { + + switch( event->type() ) + { + case QEvent::Paint: + { + + // get scrollarea viewport + QAbstractScrollArea* scrollArea( qobject_cast( widget ) ); + QWidget* viewport; + if( !( scrollArea && (viewport = scrollArea->viewport()) ) ) break; + + // get scrollarea horizontal and vertical containers + QWidget* child( nullptr ); + QList children; + if( ( child = scrollArea->findChild( "qt_scrollarea_vcontainer" ) ) && child->isVisible() ) + { children.append( child ); } + + if( ( child = scrollArea->findChild( "qt_scrollarea_hcontainer" ) ) && child->isVisible() ) + { children.append( child ); } + + if( children.empty() ) break; + if( !scrollArea->styleSheet().isEmpty() ) break; + + // make sure proper background is rendered behind the containers + QPainter painter( scrollArea ); + painter.setClipRegion( static_cast( event )->region() ); + + painter.setPen( Qt::NoPen ); + + // decide background color + const QPalette::ColorRole role( viewport->backgroundRole() ); + QColor background; + if( role == QPalette::Window && hasAlteredBackground( viewport ) ) background = _helper->frameBackgroundColor( viewport->palette() ); + else background = viewport->palette().color( role ); + painter.setBrush( background ); + + // render + foreach( auto* child, children ) + { painter.drawRect( child->geometry() ); } + + } + break; + + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + { + + // case event + QMouseEvent* mouseEvent( static_cast( event ) ); + + // get frame framewidth + int frameWidth( pixelMetric( PM_DefaultFrameWidth, 0, widget ) ); + + // find list of scrollbars + QList scrollBars; + if( QAbstractScrollArea* scrollArea = qobject_cast( widget ) ) + { + + if( scrollArea->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff ) scrollBars.append( scrollArea->horizontalScrollBar() ); + if( scrollArea->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff )scrollBars.append( scrollArea->verticalScrollBar() ); + + } else if( widget->inherits( "KTextEditor::View" ) ) { + + scrollBars = widget->findChildren(); + + } + + // loop over found scrollbars + foreach( QScrollBar* scrollBar, scrollBars ) + { + + if( !( scrollBar && scrollBar->isVisible() ) ) continue; + + QPoint offset; + if( scrollBar->orientation() == Qt::Horizontal ) offset = QPoint( 0, frameWidth ); + else offset = QPoint( QApplication::isLeftToRight() ? frameWidth : -frameWidth, 0 ); + + // map position to scrollarea + QPoint position( scrollBar->mapFrom( widget, mouseEvent->pos() - offset ) ); + + // check if contains + if( !scrollBar->rect().contains( position ) ) continue; + + // copy event, send and return + QMouseEvent copy( + mouseEvent->type(), + position, + scrollBar->mapToGlobal( position ), + mouseEvent->button(), + mouseEvent->buttons(), mouseEvent->modifiers()); + + QCoreApplication::sendEvent( scrollBar, © ); + event->setAccepted( true ); + return true; + + } + + break; + + } + + default: break; + + } + + return ParentStyleClass::eventFilter( widget, event ); + + } + + //_________________________________________________________ + bool Style::eventFilterComboBoxContainer( QWidget* widget, QEvent* event ) + { + if( event->type() == QEvent::Paint ) + { + + QPainter painter( widget ); + QPaintEvent *paintEvent = static_cast( event ); + painter.setClipRegion( paintEvent->region() ); + + QRect rect( widget->rect() ); + const QPalette& palette( widget->palette() ); + QColor background( _helper->frameBackgroundColor( palette ) ); + QColor outline( _helper->frameOutlineColor( palette ) ); + + bool hasAlpha( _helper->hasAlphaChannel( widget ) ); + if( hasAlpha ) + { + + painter.setCompositionMode( QPainter::CompositionMode_Source ); + _helper->renderMenuFrame( &painter, rect, background, outline, true ); + + } else { + + _helper->renderMenuFrame( &painter, rect, background, outline, false ); + + } + + } + + return false; + + } + + //____________________________________________________________________________ + bool Style::eventFilterDockWidget( QDockWidget* dockWidget, QEvent* event ) + { + if( event->type() == QEvent::Paint ) + { + // create painter and clip + QPainter painter( dockWidget ); + QPaintEvent *paintEvent = static_cast( event ); + painter.setClipRegion( paintEvent->region() ); + + // store palette and set colors + const QPalette& palette( dockWidget->palette() ); + QColor background( _helper->frameBackgroundColor( palette ) ); + QColor outline( _helper->frameOutlineColor( palette ) ); + + // store rect + QRect rect( dockWidget->rect() ); + + // render + if( dockWidget->isFloating() ) + { + _helper->renderMenuFrame( &painter, rect, background, outline, false ); + + } else if( StyleConfigData::dockWidgetDrawFrame() || (dockWidget->features()&QDockWidget::AllDockWidgetFeatures) ) { + + _helper->renderFrame( &painter, rect, background, outline ); + + } + + } + + return false; + + } + + //____________________________________________________________________________ + bool Style::eventFilterMdiSubWindow( QMdiSubWindow* subWindow, QEvent* event ) + { + + if( event->type() == QEvent::Paint ) + { + QPainter painter( subWindow ); + QPaintEvent* paintEvent( static_cast( event ) ); + painter.setClipRegion( paintEvent->region() ); + + QRect rect( subWindow->rect() ); + QColor background( subWindow->palette().color( QPalette::Window ) ); + + if( subWindow->isMaximized() ) + { + + // full painting + painter.setPen( Qt::NoPen ); + painter.setBrush( background ); + painter.drawRect( rect ); + + } else { + + // framed painting + _helper->renderMenuFrame( &painter, rect, background, QColor() ); + + } + + } + + // continue with normal painting + return false; + + } + + //____________________________________________________________________________ + #if QT_VERSION >= 0x050000 + bool Style::eventFilterCommandLinkButton( QCommandLinkButton* button, QEvent* event ) + { + + if( event->type() == QEvent::Paint ) + { + + // painter + QPainter painter( button ); + painter.setClipRegion( static_cast( event )->region() ); + + bool isFlat = false; + + // option + QStyleOptionButton option; + option.initFrom( button ); + option.features |= QStyleOptionButton::CommandLinkButton; + if( isFlat ) option.features |= QStyleOptionButton::Flat; + option.text = QString(); + option.icon = QIcon(); + + if( button->isChecked() ) option.state|=State_On; + if( button->isDown() ) option.state|=State_Sunken; + + // frame + drawControl(QStyle::CE_PushButton, &option, &painter, button ); + + // offset + int margin( Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); + QPoint offset( margin, margin ); + + if( button->isDown() && !isFlat ) painter.translate( 1, 1 ); + { offset += QPoint( 1, 1 ); } + + // state + const State& state( option.state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool hasFocus( enabled && ( state & State_HasFocus ) ); + + // icon + if( !button->icon().isNull() ) + { + + QSize pixmapSize( button->icon().actualSize( button->iconSize() ) ); + QRect pixmapRect( QPoint( offset.x(), button->description().isEmpty() ? (button->height() - pixmapSize.height())/2:offset.y() ), pixmapSize ); + const QPixmap pixmap( button->icon().pixmap(pixmapSize, + enabled ? QIcon::Normal : QIcon::Disabled, + button->isChecked() ? QIcon::On : QIcon::Off) ); + drawItemPixmap( &painter, pixmapRect, Qt::AlignCenter, pixmap ); + + offset.rx() += pixmapSize.width() + Metrics::Button_ItemSpacing; + + } + + // text rect + QRect textRect( offset, QSize( button->size().width() - offset.x() - margin, button->size().height() - 2*margin ) ); + const QPalette::ColorRole textRole = (enabled && hasFocus && !mouseOver && !isFlat ) ? QPalette::HighlightedText : QPalette::ButtonText; + if( !button->text().isEmpty() ) + { + + QFont font( button->font() ); + font.setBold( true ); + painter.setFont( font ); + if( button->description().isEmpty() ) + { + + drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole ); + + } else { + + drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignTop|Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole ); + textRect.setTop( textRect.top() + QFontMetrics( font ).height() ); + + } + + painter.setFont( button->font() ); + + } + + if( !button->description().isEmpty() ) + { drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextWordWrap, button->palette(), enabled, button->description(), textRole ); } + + return true; + } + + // continue with normal painting + return false; + + } + #endif + + //_____________________________________________________________________ + void Style::configurationChanged( void ) + { + + // reload + StyleConfigData::self(); + + // reload configuration + loadConfiguration(); + + } + + //____________________________________________________________________ + QIcon Style::standardIconImplementation( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const + { + + // lookup cache + if( _iconCache.contains( standardPixmap ) ) return _iconCache.value( standardPixmap ); + + QIcon icon; + switch( standardPixmap ) + { + + case SP_TitleBarNormalButton: + case SP_TitleBarMinButton: + case SP_TitleBarMaxButton: + case SP_TitleBarCloseButton: + case SP_DockWidgetCloseButton: + icon = titleBarButtonIcon( standardPixmap, option, widget ); + break; + + case SP_ToolBarHorizontalExtensionButton: + case SP_ToolBarVerticalExtensionButton: + icon = toolBarExtensionIcon( standardPixmap, option, widget ); + break; + + default: + break; + + } + + if( icon.isNull() ) + { + + // do not cache parent style icon, since it may change at runtime + #if QT_VERSION >= 0x050000 + return ParentStyleClass::standardIcon( standardPixmap, option, widget ); + #else + return ParentStyleClass::standardIconImplementation( standardPixmap, option, widget ); + #endif + + } else { + const_cast(&_iconCache)->insert( standardPixmap, icon ); + return icon; + } + + } + + //_____________________________________________________________________ + void Style::loadConfiguration() + { + // reinitialize engines + _animations->setupEngines(); + _windowManager->initialize(); + + // mnemonics + _mnemonics->setMode( StyleConfigData::mnemonicsMode() ); + + // splitter proxy + _splitterFactory->setEnabled( StyleConfigData::splitterProxyEnabled() ); + + // clear icon cache + _iconCache.clear(); + + // scrollbar buttons + switch( StyleConfigData::scrollBarAddLineButtons() ) + { + case 0: _addLineButtons = NoButton; break; + case 1: _addLineButtons = SingleButton; break; + + default: + case 2: _addLineButtons = DoubleButton; break; + } + + switch( StyleConfigData::scrollBarSubLineButtons() ) + { + case 0: _subLineButtons = NoButton; break; + case 1: _subLineButtons = SingleButton; break; + + default: + case 2: _subLineButtons = DoubleButton; break; + } + + // frame focus + if( StyleConfigData::viewDrawFocusIndicator() ) _frameFocusPrimitive = &Style::drawFrameFocusRectPrimitive; + else _frameFocusPrimitive = &Style::emptyPrimitive; + + // widget explorer + _widgetExplorer->setEnabled( StyleConfigData::widgetExplorerEnabled() ); + _widgetExplorer->setDrawWidgetRects( StyleConfigData::drawWidgetRects() ); + + } + + //___________________________________________________________________________________________________________________ + QRect Style::pushButtonContentsRect( const QStyleOption* option, const QWidget* ) const + { return insideMargin( option->rect, Metrics::Frame_FrameWidth ); } + + //___________________________________________________________________________________________________________________ + QRect Style::pushButtonFocusRect(const QStyleOption* option, const QWidget* ) const + { return insideMargin( option->rect, 3 ); } + + //___________________________________________________________________________________________________________________ + QRect Style::checkBoxContentsRect( const QStyleOption* option, const QWidget* ) const + { return visualRect( option, option->rect.adjusted( Metrics::CheckBox_Size + 2 * Metrics::CheckBox_ItemSpacing, 0, 0, 0 ) ); } + + //___________________________________________________________________________________________________________________ + QRect Style::checkBoxIndicatorRect(const QStyleOption* option, const QWidget* widget ) const + { return ParentStyleClass::subElementRect( SE_CheckBoxIndicator, option, widget ).translated( Metrics::CheckBox_ItemSpacing, 0 ); } + + //___________________________________________________________________________________________________________________ + QRect Style::checkBoxFocusRect(const QStyleOption* option, const QWidget* widget ) const + { + return QRect( option->rect.left() + 2, + option->rect.top() + 1, + ParentStyleClass::subElementRect( SE_CheckBoxFocusRect, option, widget ).right() - option->rect.left(), + option->rect.height() - 2 + ); + } + + //___________________________________________________________________________________________________________________ + QRect Style::lineEditContentsRect( const QStyleOption* option, const QWidget* widget ) const + { + // cast option and check + const QStyleOptionFrame* frameOption( qstyleoption_cast( option ) ); + if( !frameOption ) return option->rect; + + // check flatness + bool flat( frameOption->lineWidth == 0 ); + if( flat ) return option->rect; + + // copy rect and take out margins + QRect rect( option->rect ); + + // take out margins if there is enough room + int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); + if( rect.height() >= option->fontMetrics.height() + 2*frameWidth ) return insideMargin( rect, frameWidth ); + else return rect; + } + + //___________________________________________________________________________________________________________________ + QRect Style::progressBarGrooveRect( const QStyleOption* option, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return option->rect; + + // get flags and orientation + bool textVisible( progressBarOption->textVisible ); + bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); + + const QStyleOptionProgressBarV2* progressBarOption2( qstyleoption_cast( option ) ); + bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); + + // copy rectangle and adjust + QRect rect( option->rect ); + int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); + if( horizontal ) rect = insideMargin( rect, frameWidth, 0 ); + else rect = insideMargin( rect, 0, frameWidth ); + + if( textVisible && !busy && horizontal ) + { + + QRect textRect( subElementRect( SE_ProgressBarLabel, option, widget ) ); + textRect = visualRect( option, textRect ); + rect.setRight( textRect.left() - Metrics::ProgressBar_ItemSpacing - 1 ); + rect = visualRect( option, rect ); + rect = centerRect( rect, rect.width(), Metrics::ProgressBar_Thickness ); + + } else if( horizontal ) { + + rect = centerRect( rect, rect.width(), Metrics::ProgressBar_Thickness ); + + } else { + + rect = centerRect( rect, Metrics::ProgressBar_Thickness, rect.height() ); + + } + + return rect; + + } + + //___________________________________________________________________________________________________________________ + QRect Style::progressBarContentsRect( const QStyleOption* option, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return QRect(); + + // get groove rect + QRect rect( progressBarGrooveRect( option, widget ) ); + + // in busy mode, grooveRect is used + bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); + if( busy ) return rect; + + // get orientation + const QStyleOptionProgressBarV2* progressBarOption2( qstyleoption_cast( option ) ); + bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); + + // check inverted appearance + bool inverted( progressBarOption2 ? progressBarOption2->invertedAppearance : false ); + + // get progress and steps + qreal progress( progressBarOption->progress - progressBarOption->minimum ); + int steps( qMax( progressBarOption->maximum - progressBarOption->minimum, 1 ) ); + + //Calculate width fraction + qreal widthFrac = qMin( qreal(1), progress/steps ); + + // convert the pixel width + int indicatorSize( widthFrac*( horizontal ? rect.width():rect.height() ) ); + + QRect indicatorRect; + if( horizontal ) + { + + indicatorRect = QRect( inverted ? ( rect.right() - indicatorSize + 1):rect.left(), rect.y(), indicatorSize, rect.height() ); + indicatorRect = visualRect( option->direction, rect, indicatorRect ); + + } else indicatorRect = QRect( rect.x(), inverted ? rect.top() : (rect.bottom() - indicatorSize + 1), rect.width(), indicatorSize ); + + return indicatorRect; + + } + + //___________________________________________________________________________________________________________________ + QRect Style::progressBarLabelRect( const QStyleOption* option, const QWidget* ) const + { + + // cast option and check + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return QRect(); + + // get flags and check + bool textVisible( progressBarOption->textVisible ); + bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); + if( !textVisible || busy ) return QRect(); + + // get direction and check + const QStyleOptionProgressBarV2* progressBarOption2( qstyleoption_cast( option ) ); + bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); + if( !horizontal ) return QRect(); + + int textWidth = qMax( + option->fontMetrics.size( _mnemonics->textFlags(), progressBarOption->text ).width(), + option->fontMetrics.size( _mnemonics->textFlags(), QStringLiteral( "100%" ) ).width() ); + + QRect rect( insideMargin( option->rect, Metrics::Frame_FrameWidth, 0 ) ); + rect.setLeft( rect.right() - textWidth + 1 ); + rect = visualRect( option, rect ); + + return rect; + + } + + //___________________________________________________________________________________________________________________ + QRect Style::headerArrowRect( const QStyleOption* option, const QWidget* ) const + { + + // cast option and check + const QStyleOptionHeader* headerOption( qstyleoption_cast( option ) ); + if( !headerOption ) return option->rect; + + // check if arrow is necessary + if( headerOption->sortIndicator == QStyleOptionHeader::None ) return QRect(); + + QRect arrowRect( insideMargin( option->rect, Metrics::Header_MarginWidth ) ); + arrowRect.setLeft( arrowRect.right() - Metrics::Header_ArrowSize + 1 ); + + return visualRect( option, arrowRect ); + + } + + //___________________________________________________________________________________________________________________ + QRect Style::headerLabelRect( const QStyleOption* option, const QWidget* ) const + { + + // cast option and check + const QStyleOptionHeader* headerOption( qstyleoption_cast( option ) ); + if( !headerOption ) return option->rect; + + // check if arrow is necessary + // QRect labelRect( insideMargin( option->rect, Metrics::Header_MarginWidth ) ); + QRect labelRect( insideMargin( option->rect, Metrics::Header_MarginWidth, 0 ) ); + if( headerOption->sortIndicator == QStyleOptionHeader::None ) return labelRect; + + labelRect.adjust( 0, 0, -Metrics::Header_ArrowSize-Metrics::Header_ItemSpacing, 0 ); + return visualRect( option, labelRect ); + + } + + //___________________________________________________________________________________________________________________ + QRect Style::sliderFocusRect(const QStyleOption *option, const QWidget *widget) const + { + + const QStyleOptionSlider* sliderOption( qstyleoption_cast( option ) ); + + QRect r( option->rect ); + + if (sliderOption->orientation == Qt::Vertical) { + int thickness = Slider_GrooveThickness + 8; + return QRect(r.center().x() - thickness / 2, r.top() + 1, thickness + 1, r.height() - 1); + } + else { + int thickness = Slider_GrooveThickness + 6; + return QRect(r.left() + 1, r.center().y() - thickness / 2, r.width() - 1, thickness + 1); + } + + } + + //____________________________________________________________________ + QRect Style::tabBarTabLeftButtonRect( const QStyleOption* option, const QWidget* ) const + { + + // cast option and check + const QStyleOptionTabV3 *tabOptionV3( qstyleoption_cast( option ) ); + if( !tabOptionV3 || tabOptionV3->leftButtonSize.isEmpty() ) return QRect(); + + QRect rect( option->rect ); + QSize size( tabOptionV3->leftButtonSize ); + QRect buttonRect( QPoint(0,0), size ); + + // vertical positioning + switch( tabOptionV3->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + buttonRect.moveLeft( rect.left() + Metrics::TabBar_TabMarginWidth ); + buttonRect.moveTop( ( rect.height() - buttonRect.height() )/2 ); + buttonRect = visualRect( option, buttonRect ); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + buttonRect.moveBottom( rect.bottom() - Metrics::TabBar_TabMarginWidth ); + buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + buttonRect.moveTop( rect.top() + Metrics::TabBar_TabMarginWidth ); + buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); + break; + + default: break; + } + + return buttonRect; + + } + + //____________________________________________________________________ + QRect Style::tabBarTabRightButtonRect( const QStyleOption* option, const QWidget* ) const + { + + // cast option and check + const QStyleOptionTabV3 *tabOptionV3( qstyleoption_cast( option ) ); + if( !tabOptionV3 || tabOptionV3->rightButtonSize.isEmpty() ) return QRect(); + + QRect rect( option->rect ); + QSize size( tabOptionV3->rightButtonSize ); + QRect buttonRect( QPoint(0,0), size ); + + // vertical positioning + switch( tabOptionV3->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + buttonRect.moveRight( rect.right() - Metrics::TabBar_TabMarginWidth ); + buttonRect.moveTop( ( rect.height() - buttonRect.height() )/2 ); + buttonRect = visualRect( option, buttonRect ); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + buttonRect.moveTop( rect.top() + Metrics::TabBar_TabMarginWidth ); + buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + buttonRect.moveBottom( rect.bottom() - Metrics::TabBar_TabMarginWidth ); + buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); + break; + + default: break; + } + + return buttonRect; + + } + + //____________________________________________________________________ + QRect Style::tabWidgetTabBarRect( const QStyleOption* option, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionTabWidgetFrame* tabOption = qstyleoption_cast( option ); + if( !tabOption ) return ParentStyleClass::subElementRect( SE_TabWidgetTabBar, option, widget ); + + // do nothing if tabbar is hidden + QSize tabBarSize( tabOption->tabBarSize ); + + QRect rect( option->rect ); + QRect tabBarRect( QPoint(0, 0), tabBarSize ); + + Qt::Alignment tabBarAlignment( styleHint( SH_TabBar_Alignment, option, widget ) ); + + // horizontal positioning + bool verticalTabs( isVerticalTab( tabOption->shape ) ); + if( verticalTabs ) + { + + tabBarRect.setTop(option->rect.top() + 1); + tabBarRect.setBottom(option->rect.bottom() - 1); + //tabBarRect.setHeight( qMin( tabBarRect.height(), rect.height() - 2 ) ); + //if( tabBarAlignment == Qt::AlignCenter ) tabBarRect.moveTop( rect.top() + ( rect.height() - tabBarRect.height() )/2 ); + //else tabBarRect.moveTop( rect.top()+1 ); + + } else { + + // account for corner rects + // need to re-run visualRect to remove right-to-left handling, since it is re-added on tabBarRect at the end + QRect leftButtonRect( visualRect( option, subElementRect( SE_TabWidgetLeftCorner, option, widget ) ) ); + QRect rightButtonRect( visualRect( option, subElementRect( SE_TabWidgetRightCorner, option, widget ) ) ); + + rect.setLeft( leftButtonRect.width() ); + rect.setRight( rightButtonRect.left() - 1 ); + + tabBarRect.moveLeft( rect.left() + 1 ); + tabBarRect.setWidth( rect.width() - 2 ); + + tabBarRect = visualRect( option, tabBarRect ); + + } + + // vertical positioning + switch( tabOption->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + tabBarRect.moveTop( rect.top()+1 ); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + tabBarRect.moveBottom( rect.bottom()-1 ); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + tabBarRect.moveLeft( rect.left()+1 ); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + tabBarRect.moveRight( rect.right()-1 ); + break; + + default: break; + + } + + return tabBarRect; + + } + + //____________________________________________________________________ + QRect Style::tabWidgetTabContentsRect( const QStyleOption* option, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionTabWidgetFrame* tabOption = qstyleoption_cast( option ); + if( !tabOption ) return option->rect; + + // do nothing if tabbar is hidden + if( tabOption->tabBarSize.isEmpty() ) return option->rect; + QRect rect = tabWidgetTabPaneRect( option, widget ); + + bool documentMode( tabOption->lineWidth == 0 ); + if( documentMode ) + { + + // add margin only to the relevant side + switch( tabOption->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + return rect.adjusted( 0, Metrics::TabWidget_MarginWidth, 0, 0 ); + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + return rect.adjusted( 0, 0, 0, -Metrics::TabWidget_MarginWidth ); + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + return rect.adjusted( Metrics::TabWidget_MarginWidth, 0, 0, 0 ); + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + return rect.adjusted( 0, 0, -Metrics::TabWidget_MarginWidth, 0 ); + + default: return rect; + } + + } else return insideMargin( rect, Metrics::TabWidget_MarginWidth ); + + } + + //____________________________________________________________________ + QRect Style::tabWidgetTabPaneRect( const QStyleOption* option, const QWidget* ) const + { + + const QStyleOptionTabWidgetFrame* tabOption = qstyleoption_cast( option ); + if( !tabOption || tabOption->tabBarSize.isEmpty() ) return option->rect; + + int overlap = Metrics::TabBar_BaseOverlap + 1; + QSize tabBarSize( tabOption->tabBarSize - QSize( overlap, overlap ) ); + + QRect rect( option->rect ); + switch( tabOption->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + rect.adjust( 0, tabBarSize.height(), 0, 0 ); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + rect.adjust( 0, 0, 0, -tabBarSize.height() ); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + rect.adjust( tabBarSize.width(), 0, 0, 0 ); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + rect.adjust( 0, 0, -tabBarSize.width(), 0 ); + break; + + default: return QRect(); + } + + return rect; + + } + + //____________________________________________________________________ + QRect Style::tabWidgetCornerRect( SubElement element, const QStyleOption* option, const QWidget* ) const + { + + // cast option and check + const QStyleOptionTabWidgetFrame* tabOption = qstyleoption_cast( option ); + if( !tabOption ) return option->rect; + + // do nothing if tabbar is hidden + QSize tabBarSize( tabOption->tabBarSize ); + if( tabBarSize.isEmpty() ) return QRect(); + + // do nothing for vertical tabs + bool verticalTabs( isVerticalTab( tabOption->shape ) ); + if( verticalTabs ) return QRect(); + + QRect rect( option->rect ); + QRect cornerRect; + switch( element ) + { + case SE_TabWidgetLeftCorner: + cornerRect = QRect( QPoint(0,0), tabOption->leftCornerWidgetSize ); + cornerRect.moveLeft( rect.left() ); + break; + + case SE_TabWidgetRightCorner: + cornerRect = QRect( QPoint(0,0), tabOption->rightCornerWidgetSize ); + cornerRect.moveRight( rect.right() ); + break; + + default: break; + + } + + // expend height to tabBarSize, if needed, to make sure base is properly rendered + cornerRect.setHeight( qMax( cornerRect.height(), tabBarSize.height() + 1 ) ); + + switch( tabOption->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + cornerRect.moveTop( rect.top() ); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + cornerRect.moveBottom( rect.bottom() ); + break; + + default: break; + } + + // return cornerRect; + cornerRect = visualRect( option, cornerRect ); + return cornerRect; + + } + + //____________________________________________________________________ + QRect Style::toolBoxTabContentsRect( const QStyleOption* option, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionToolBox* toolBoxOption( qstyleoption_cast( option ) ); + if( !toolBoxOption ) return option->rect; + + // copy rect + const QRect& rect( option->rect ); + + int contentsWidth(0); + if( !toolBoxOption->icon.isNull() ) + { + int iconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); + contentsWidth += iconSize; + + if( !toolBoxOption->text.isEmpty() ) contentsWidth += Metrics::ToolBox_TabItemSpacing; + } + + if( !toolBoxOption->text.isEmpty() ) + { + + int textWidth = toolBoxOption->fontMetrics.size( _mnemonics->textFlags(), toolBoxOption->text ).width(); + contentsWidth += textWidth; + + } + + contentsWidth += 2*Metrics::ToolBox_TabMarginWidth; + contentsWidth = qMin( contentsWidth, rect.width() ); + contentsWidth = qMax( contentsWidth, int(Metrics::ToolBox_TabMinWidth) ); + return centerRect( rect, contentsWidth, rect.height() ); + + } + + //____________________________________________________________________ + QRect Style::genericLayoutItemRect( const QStyleOption* option, const QWidget* ) const + { return insideMargin( option->rect, -Metrics::Frame_FrameWidth ); } + + //______________________________________________________________ + QRect Style::groupBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(option)) + { + QRect rect = ParentStyleClass::subControlRect(CC_GroupBox, option, subControl, widget); + int topMargin = 0; + int topHeight = 0; + int verticalAlignment = proxy()->styleHint(SH_GroupBox_TextLabelVerticalAlignment, groupBox, widget); + + if (!groupBox->text.isEmpty()) + { + topHeight = groupBox->fontMetrics.height(); + if (verticalAlignment & Qt::AlignVCenter) + { + topMargin = topHeight / 2; + } + else if (verticalAlignment & Qt::AlignTop) + { + topMargin = topHeight; + } + } + QRect frameRect = groupBox->rect; + frameRect.setTop(topMargin); + if (subControl == SC_GroupBoxFrame) + { + return rect; + } + else if (subControl == SC_GroupBoxContents) + { + int margin = 0; + int leftMarginExtension = 16; + return frameRect.adjusted(leftMarginExtension + margin, margin + topHeight, -margin, -margin); + } + + if (const QGroupBox *groupBoxWidget = qobject_cast(widget)) + { + //Prepare metrics for a bold font + QFont font = widget->font(); + font.setBold(true); + QFontMetrics fontMetrics(font); + + QSize textRect = fontMetrics.boundingRect(groupBoxWidget->title()).size() + QSize(2, 2); + if (subControl == SC_GroupBoxCheckBox) + { + int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); + int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); + rect.setWidth(indicatorWidth); + rect.setHeight(indicatorHeight); + rect.moveTop((textRect.height() - indicatorHeight) / 2); + } + else if (subControl == SC_GroupBoxLabel) + { + rect.setSize(textRect); + } + } + return rect; + } + + return ParentStyleClass::subControlRect( CC_GroupBox, option, subControl, widget ); + + } + + //___________________________________________________________________________________________________________________ + QRect Style::toolButtonSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionToolButton* toolButtonOption = qstyleoption_cast( option ); + if( !toolButtonOption ) return ParentStyleClass::subControlRect( CC_ToolButton, option, subControl, widget ); + + bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); + const bool hasInlineIndicator( + toolButtonOption->features&QStyleOptionToolButton::HasMenu + && toolButtonOption->features&QStyleOptionToolButton::PopupDelay + && !hasPopupMenu ); + + // store rect + const QRect& rect( option->rect ); + int menuButtonWidth( Metrics::MenuButton_IndicatorWidth ); + switch( subControl ) + { + case SC_ToolButtonMenu: + { + + // check fratures + if( !(hasPopupMenu || hasInlineIndicator ) ) return QRect(); + + // check features + QRect menuRect( rect ); + menuRect.setLeft( rect.right() - menuButtonWidth + 1 ); + if( hasInlineIndicator ) + { menuRect.setTop( menuRect.bottom() - menuButtonWidth + 1 ); } + + return visualRect( option, menuRect ); + } + + case SC_ToolButton: + { + + if( hasPopupMenu ) + { + + QRect contentsRect( rect ); + contentsRect.setRight( rect.right() - menuButtonWidth ); + return visualRect( option, contentsRect ); + + } else return rect; + + } + + default: return QRect(); + + } + + } + + //___________________________________________________________________________________________________________________ + QRect Style::comboBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + // cast option and check + const QStyleOptionComboBox *comboBoxOption( qstyleoption_cast( option ) ); + if( !comboBoxOption ) return ParentStyleClass::subControlRect( CC_ComboBox, option, subControl, widget ); + + bool editable( comboBoxOption->editable ); + bool flat( editable && !comboBoxOption->frame ); + + // copy rect + QRect rect( option->rect ); + + switch( subControl ) + { + case SC_ComboBoxFrame: return flat ? rect : QRect(); + case SC_ComboBoxListBoxPopup: return rect; + + case SC_ComboBoxArrow: + { + + QRect arrowRect( + rect.right() - rect.height() + 1, + rect.top(), + rect.height(), + rect.height() ); + + return arrowRect; + + } + + case SC_ComboBoxEditField: + { + + QRect labelRect; + int frameWidth( pixelMetric( PM_ComboBoxFrameWidth, option, widget ) ); + labelRect = QRect( + rect.left(), rect.top(), + rect.width() - rect.height() - 4, + rect.height() ); + + // remove margins + if( !flat && rect.height() >= option->fontMetrics.height() + 2*frameWidth ) + { labelRect.adjust( frameWidth, frameWidth, 0, -frameWidth ); } + + return visualRect( option, labelRect ); + + } + + default: break; + + } + + return ParentStyleClass::subControlRect( CC_ComboBox, option, subControl, widget ); + + } + + //___________________________________________________________________________________________________________________ + QRect Style::spinBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSpinBox *spinBoxOption( qstyleoption_cast( option ) ); + if( !spinBoxOption ) return ParentStyleClass::subControlRect( CC_SpinBox, option, subControl, widget ); + bool flat( !spinBoxOption->frame ); + + // copy rect + QRect rect( option->rect ); + + switch( subControl ) + { + case SC_SpinBoxFrame: return flat ? QRect():rect; + + case SC_SpinBoxUp: + + if (rect.width() > 2 * rect.height() + 24) + return QRect(rect.right() - rect.height() - 1, + rect.top(), + rect.height(), + rect.height() - 1 + ); + else + return QRect(rect.right() - 0.6 * rect.height(), + rect.top(), + rect.height() * 0.6, + rect.height() / 2 + 3 ); + + case SC_SpinBoxDown: + { + + if (rect.width() > 2 * rect.height() + 24) + return QRect(rect.right() - 2 * rect.height(), + rect.top(), + rect.height(), + rect.height() - 1 + ); + else + return QRect(rect.right() - 0.6 * rect.height(), + rect.top() + rect.height() / 2 - 2, + rect.height() * 0.6, + rect.height() / 2 + 1 ); + + } + + case SC_SpinBoxEditField: + { + + + int frameWidth( pixelMetric( PM_SpinBoxFrameWidth, option, widget ) ); + + QRect labelRect; + + if (rect.width() > 2 * rect.height() + 24) + labelRect = QRect( + rect.left(), rect.top(), + rect.width() - 2 * rect.height() - frameWidth, + rect.height() ); + else + labelRect = QRect( + rect.left(), rect.top(), + rect.width() - 0.6 * rect.height() - frameWidth, + rect.height() ); + + // remove right side line editor margins + if( !flat && labelRect.height() >= option->fontMetrics.height() + 2*frameWidth ) + { labelRect.adjust( frameWidth, frameWidth, 0, -frameWidth ); } + + return visualRect( option, labelRect ); + + } + + default: break; + + } + + return ParentStyleClass::subControlRect( CC_SpinBox, option, subControl, widget ); + + } + + //___________________________________________________________________________________________________________________ + QRect Style::scrollBarInternalSubControlRect( const QStyleOptionComplex* option, SubControl subControl ) const + { + + const QRect& rect = option->rect; + const State& state( option->state ); + bool horizontal( state & State_Horizontal ); + + switch( subControl ) + { + + case SC_ScrollBarSubLine: + { + int majorSize( scrollBarButtonHeight( _subLineButtons ) ); + if( horizontal ) return visualRect( option, QRect( rect.left(), rect.top(), majorSize, rect.height() ) ); + else return visualRect( option, QRect( rect.left(), rect.top(), rect.width(), majorSize ) ); + + } + + case SC_ScrollBarAddLine: + { + int majorSize( scrollBarButtonHeight( _addLineButtons ) ); + if( horizontal ) return visualRect( option, QRect( rect.right() - majorSize + 1, rect.top(), majorSize, rect.height() ) ); + else return visualRect( option, QRect( rect.left(), rect.bottom() - majorSize + 1, rect.width(), majorSize ) ); + } + + default: return QRect(); + + } + } + + //___________________________________________________________________________________________________________________ + QRect Style::scrollBarSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSlider* sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return ParentStyleClass::subControlRect( CC_ScrollBar, option, subControl, widget ); + + // get relevant state + const State& state( option->state ); + bool horizontal( state & State_Horizontal ); + + switch( subControl ) + { + + case SC_ScrollBarSubLine: + case SC_ScrollBarAddLine: + return QRect(); + + case SC_ScrollBarGroove: + { + QRect topRect = visualRect( option, scrollBarInternalSubControlRect( option, SC_ScrollBarSubLine ) ); + QRect bottomRect = visualRect( option, scrollBarInternalSubControlRect( option, SC_ScrollBarAddLine ) ); + + QPoint topLeftCorner; + QPoint botRightCorner; + + if( horizontal ) + { + + topLeftCorner = QPoint( topRect.right() + 1, topRect.top() ); + botRightCorner = QPoint( bottomRect.left() - 1, topRect.bottom() ); + + } else { + + topLeftCorner = QPoint( topRect.left(), topRect.bottom() + 1 ); + botRightCorner = QPoint( topRect.right(), bottomRect.top() - 1 ); + + } + + // define rect + return visualRect( option, QRect( topLeftCorner, botRightCorner ) ); + + } + + case SC_ScrollBarSlider: + { + + // handle RTL here to unreflect things if need be + QRect groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); + groove.adjust(0, 0, 1, 1); + + if( sliderOption->minimum == sliderOption->maximum ) return groove; + + // Figure out how much room there is + int space( horizontal ? groove.width() : groove.height() ); + + // Calculate the portion of this space that the slider should occupy + int sliderSize = space * qreal( sliderOption->pageStep ) / ( sliderOption->maximum - sliderOption->minimum + sliderOption->pageStep ); + sliderSize = qMax( sliderSize, static_cast(Metrics::ScrollBar_MinSliderHeight ) ); + sliderSize = qMin( sliderSize, space ); + + space -= sliderSize; + if( space <= 0 ) return groove; + + int pos = qRound( qreal( sliderOption->sliderPosition - sliderOption->minimum )/ ( sliderOption->maximum - sliderOption->minimum )*space ); + if( sliderOption->upsideDown ) pos = space - pos; + if( horizontal ) return visualRect( option, QRect( groove.left() + pos, groove.top(), sliderSize, groove.height() ) ); + else return visualRect( option, QRect( groove.left(), groove.top() + pos, groove.width(), sliderSize ) ); + } + + case SC_ScrollBarSubPage: + { + + // handle RTL here to unreflect things if need be + QRect slider = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ) ); + QRect groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); + + if( horizontal ) return visualRect( option, QRect( groove.left(), groove.top(), slider.left() - groove.left(), groove.height() ) ); + else return visualRect( option, QRect( groove.left(), groove.top(), groove.width(), slider.top() - groove.top() ) ); + } + + case SC_ScrollBarAddPage: + { + + // handle RTL here to unreflect things if need be + QRect slider = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ) ); + QRect groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); + + if( horizontal ) return visualRect( option, QRect( slider.right() + 1, groove.top(), groove.right() - slider.right(), groove.height() ) ); + else return visualRect( option, QRect( groove.left(), slider.bottom() + 1, groove.width(), groove.bottom() - slider.bottom() ) ); + + } + + default: return ParentStyleClass::subControlRect( CC_ScrollBar, option, subControl, widget );; + } + } + + //___________________________________________________________________________________________________________________ + QRect Style::dialSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSlider* sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return ParentStyleClass::subControlRect( CC_Dial, option, subControl, widget ); + + // adjust rect to be square, and centered + QRect rect( option->rect ); + int dimension( qMin( rect.width(), rect.height() ) ); + rect = centerRect( rect, dimension, dimension ); + + switch( subControl ) + { + case QStyle::SC_DialGroove: return insideMargin( rect, (Metrics::Slider_ControlThickness - Metrics::Slider_GrooveThickness)/2 + 2 ); + case QStyle::SC_DialHandle: + { + + // calculate angle at which handle needs to be drawn + qreal angle( dialAngle( sliderOption, sliderOption->sliderPosition ) ); + + // groove rect + QRectF grooveRect( insideMargin( rect, Metrics::Slider_ControlThickness/2 ) ); + qreal radius( grooveRect.width()/2 ); + + // slider center + QPointF center( grooveRect.center() + QPointF( radius*std::cos( angle ), -radius*std::sin( angle ) ) ); + + // slider rect + QRect handleRect( 0, 0, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness ); + handleRect.moveCenter( center.toPoint() ); + return handleRect; + + } + + default: return ParentStyleClass::subControlRect( CC_Dial, option, subControl, widget );; + + } + + } + + //___________________________________________________________________________________________________________________ + QRect Style::sliderSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSlider* sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ); + + switch( subControl ) + { + case SC_SliderGroove: + { + + // direction + bool horizontal( sliderOption->orientation == Qt::Horizontal ); + + // get base class rect + QRect grooveRect( ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ) ); + grooveRect = insideMargin( grooveRect, pixelMetric( PM_DefaultFrameWidth, option, widget ) ); + + // centering + if( horizontal ) grooveRect = centerRect( grooveRect, grooveRect.width(), Metrics::Slider_GrooveThickness ); + else grooveRect = centerRect( grooveRect, Metrics::Slider_GrooveThickness, grooveRect.height() ); + return grooveRect; + + } + + default: return ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ); + } + + } + + //______________________________________________________________ + QSize Style::checkBoxSizeFromContents( const QStyleOption*, const QSize& contentsSize, const QWidget* ) const + { + // get contents size + QSize size( contentsSize ); + + // add focus height + size = expandSize( size, 0, Metrics::CheckBox_FocusMarginWidth ); + + // make sure there is enough height for indicator + size.setHeight( qMax( size.height(), int(Metrics::CheckBox_Size) ) ); + + // Add space for the indicator and the icon + size.rwidth() += Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing; + + // also add extra space, to leave room to the right of the label + size.rwidth() += Metrics::CheckBox_ItemSpacing; + + return size; + + } + + //______________________________________________________________ + QSize Style::lineEditSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + // cast option and check + const QStyleOptionFrame* frameOption( qstyleoption_cast( option ) ); + if( !frameOption ) return contentsSize; + + bool flat( frameOption->lineWidth == 0 ); + int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); + return flat ? contentsSize : expandSize( contentsSize, frameWidth ); + } + + //______________________________________________________________ + QSize Style::comboBoxSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionComboBox* comboBoxOption( qstyleoption_cast( option ) ); + if( !comboBoxOption ) return contentsSize; + + // copy size + QSize size( contentsSize ); + + // add relevant margin + bool flat( !comboBoxOption->frame ); + int frameWidth( pixelMetric( PM_ComboBoxFrameWidth, option, widget ) ); + if( !flat ) size = expandSize( size, frameWidth ); + + // make sure there is enough height for the button + size.setHeight( qMax( size.height(), int(Metrics::MenuButton_IndicatorWidth) ) ); + + // add button width and spacing + size.rwidth() += size.height() + 4; + + return size; + + } + + //______________________________________________________________ + QSize Style::spinBoxSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSpinBox *spinBoxOption( qstyleoption_cast( option ) ); + if( !spinBoxOption ) return contentsSize; + + bool flat( !spinBoxOption->frame ); + + // copy size + QSize size( contentsSize ); + + // add editor margins + int frameWidth( pixelMetric( PM_SpinBoxFrameWidth, option, widget ) ); + if( !flat ) size = expandSize( size, frameWidth ); + + // add button width and spacing + size.rwidth() += 2 * size.height() - 1; + + return size; + + } + + //______________________________________________________________ + QSize Style::sliderSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const + { + + // cast option and check + const QStyleOptionSlider *sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return contentsSize; + + // store tick position and orientation + const QSlider::TickPosition& tickPosition( sliderOption->tickPosition ); + bool horizontal( sliderOption->orientation == Qt::Horizontal ); + bool disableTicks( !StyleConfigData::sliderDrawTickMarks() ); + + // do nothing if no ticks are requested + if( tickPosition == QSlider::NoTicks ) return contentsSize; + + /* + * Qt adds its own tick length directly inside QSlider. + * Take it out and replace by ours, if needed + */ + const int tickLength( disableTicks ? 0 : ( + Metrics::Slider_TickLength + Metrics::Slider_TickMarginWidth + + (Metrics::Slider_GrooveThickness - Metrics::Slider_ControlThickness)/2 ) ); + + int builtInTickLength( 5 ); + + QSize size( contentsSize ); + if( horizontal ) + { + + if(tickPosition & QSlider::TicksAbove) size.rheight() += tickLength - builtInTickLength; + if(tickPosition & QSlider::TicksBelow) size.rheight() += tickLength - builtInTickLength; + + } else { + + if(tickPosition & QSlider::TicksAbove) size.rwidth() += tickLength - builtInTickLength; + if(tickPosition & QSlider::TicksBelow) size.rwidth() += tickLength - builtInTickLength; + + } + + return size; + + } + + //______________________________________________________________ + QSize Style::pushButtonSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionButton* buttonOption( qstyleoption_cast( option ) ); + if( !buttonOption ) return contentsSize; + + // output + QSize size; + + // check text and icon + bool hasText( !buttonOption->text.isEmpty() ); + bool flat( buttonOption->features & QStyleOptionButton::Flat ); + bool hasIcon( !buttonOption->icon.isNull() ); + + if( !( hasText||hasIcon ) ) + { + + /* + no text nor icon is passed. + assume custom button and use contentsSize as a starting point + */ + size = contentsSize; + + } else { + + /* + rather than trying to guess what Qt puts into its contents size calculation, + we recompute the button size entirely, based on button option + this ensures consistency with the rendering stage + */ + + // update has icon to honour showIconsOnPushButtons, when possible + hasIcon &= (showIconsOnPushButtons() || flat || !hasText ); + + // text + if( hasText ) size = buttonOption->fontMetrics.size( Qt::TextShowMnemonic, buttonOption->text ); + + // icon + if( hasIcon ) + { + QSize iconSize = buttonOption->iconSize; + if( !iconSize.isValid() ) iconSize = QSize( pixelMetric( PM_SmallIconSize, option, widget ), pixelMetric( PM_SmallIconSize, option, widget ) ); + + size.setHeight( qMax( size.height(), iconSize.height() ) ); + size.rwidth() += iconSize.width(); + + if( hasText ) size.rwidth() += Metrics::Button_ItemSpacing; + } + + } + + // menu + bool hasMenu( buttonOption->features & QStyleOptionButton::HasMenu ); + if( hasMenu ) + { + size.rwidth() += Metrics::MenuButton_IndicatorWidth; + if( hasText||hasIcon ) size.rwidth() += Metrics::Button_ItemSpacing; + } + + // expand with buttons margin + size = expandSize( size, Metrics::Button_MarginWidth ); + + // make sure buttons have a minimum width + if( hasText ) + { size.setWidth( qMax( size.width(), int( Metrics::Button_MinWidth ) ) ); } + + // finally add frame margins + return expandSize( size, Metrics::Frame_FrameWidth ); + + } + + //______________________________________________________________ + QSize Style::toolButtonSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const + { + + // cast option and check + const QStyleOptionToolButton* toolButtonOption = qstyleoption_cast( option ); + if( !toolButtonOption ) return contentsSize; + + // copy size + QSize size = contentsSize; + + // get relevant state flags + const State& state( option->state ); + bool autoRaise( state & State_AutoRaise ); + bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); + const bool hasInlineIndicator( + toolButtonOption->features&QStyleOptionToolButton::HasMenu + && toolButtonOption->features&QStyleOptionToolButton::PopupDelay + && !hasPopupMenu ); + + int marginWidth( Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); + + if( hasInlineIndicator ) size.rwidth() += Metrics::ToolButton_InlineIndicatorWidth; + size = expandSize( size, marginWidth ); + + return size; + + } + + //______________________________________________________________ + QSize Style::menuBarItemSizeFromContents( const QStyleOption*, const QSize& contentsSize, const QWidget* ) const + { return expandSize( contentsSize, Metrics::MenuBarItem_MarginWidth, Metrics::MenuBarItem_MarginHeight ); } + + //______________________________________________________________ + QSize Style::menuItemSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionMenuItem* menuItemOption = qstyleoption_cast( option ); + if( !menuItemOption ) return contentsSize; + + /* + * First calculate the intrinsic size of the item. + * this must be kept consistent with what's in drawMenuItemControl + */ + QSize size( contentsSize ); + switch( menuItemOption->menuItemType ) + { + + case QStyleOptionMenuItem::Normal: + case QStyleOptionMenuItem::DefaultItem: + case QStyleOptionMenuItem::SubMenu: + { + + int iconWidth = 0; + if( showIconsInMenuItems() ) iconWidth = isQtQuickControl( option, widget ) ? qMax( pixelMetric(PM_SmallIconSize, option, widget ), menuItemOption->maxIconWidth ) : menuItemOption->maxIconWidth; + + int leftColumnWidth( iconWidth ); + + // add space with respect to text + leftColumnWidth += Metrics::MenuItem_ItemSpacing; + + // add checkbox indicator width + if( menuItemOption->menuHasCheckableItems ) + { leftColumnWidth += Metrics::CheckBox_Size + Metrics::MenuItem_ItemSpacing; } + + // add spacing for accelerator + /* + * Note: + * The width of the accelerator itself is not included here since + * Qt will add that on separately after obtaining the + * sizeFromContents() for each menu item in the menu to be shown + * ( see QMenuPrivate::calcActionRects() ) + */ + bool hasAccelerator( menuItemOption->text.indexOf( QLatin1Char( '\t' ) ) >= 0 ); + if( hasAccelerator ) size.rwidth() += Metrics::MenuItem_AcceleratorSpace; + + // right column + int rightColumnWidth = Metrics::MenuButton_IndicatorWidth + Metrics::MenuItem_ItemSpacing; + size.rwidth() += leftColumnWidth + rightColumnWidth; + + // make sure height is large enough for icon and arrow + size.setHeight( qMax( size.height(), int(Metrics::MenuButton_IndicatorWidth) ) ); + size.setHeight( qMax( size.height(), int(Metrics::CheckBox_Size) ) ); + size.setHeight( qMax( size.height(), iconWidth ) ); + return expandSize( size, Metrics::MenuItem_MarginWidth ); + + } + + case QStyleOptionMenuItem::Separator: + { + + if( menuItemOption->text.isEmpty() && menuItemOption->icon.isNull() ) + { + + return expandSize( QSize(0,1), Metrics::MenuItem_MarginWidth ); + + } else { + + // build toolbutton option + QStyleOptionToolButton toolButtonOption( separatorMenuItemOption( menuItemOption, widget ) ); + + // make sure height is large enough for icon and text + int iconWidth( menuItemOption->maxIconWidth ); + int textHeight( menuItemOption->fontMetrics.height() ); + if( !menuItemOption->icon.isNull() ) size.setHeight( qMax( size.height(), iconWidth ) ); + if( !menuItemOption->text.isEmpty() ) + { + size.setHeight( qMax( size.height(), textHeight ) ); + size.setWidth( qMax( size.width(), menuItemOption->fontMetrics.width( menuItemOption->text ) ) ); + } + + return sizeFromContents( CT_ToolButton, &toolButtonOption, size, widget ); + + } + + } + + // for all other cases, return input + default: return contentsSize; + } + + } + + //______________________________________________________________ + QSize Style::progressBarSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const + { + + // cast option + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return contentsSize; + + const QStyleOptionProgressBarV2* progressBarOption2( qstyleoption_cast( option ) ); + bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); + + // make local copy + QSize size( contentsSize ); + + if( horizontal ) + { + + // check text visibility + bool textVisible( progressBarOption->textVisible ); + + size.setWidth( qMax( size.width(), int(Metrics::ProgressBar_Thickness) ) ); + size.setHeight( qMax( size.height(), int(Metrics::ProgressBar_Thickness) ) ); + if( textVisible ) size.setHeight( qMax( size.height(), option->fontMetrics.height() ) ); + + } else { + + size.setHeight( qMax( size.height(), int(Metrics::ProgressBar_Thickness) ) ); + size.setWidth( qMax( size.width(), int(Metrics::ProgressBar_Thickness) ) ); + + } + + return size; + + } + + //______________________________________________________________ + QSize Style::tabWidgetSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + // cast option and check + const QStyleOptionTabWidgetFrame* tabOption = qstyleoption_cast( option ); + if( !tabOption ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); + + // try find direct children of type QTabBar and QStackedWidget + // this is needed in order to add TabWidget margins only if they are necessary around tabWidget content, not the tabbar + if( !widget ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); + QTabBar* tabBar = nullptr; + QStackedWidget* stack = nullptr; + auto children( widget->children() ); + foreach( auto child, children ) + { + if( !tabBar ) tabBar = qobject_cast( child ); + if( !stack ) stack = qobject_cast( child ); + if( tabBar && stack ) break; + } + + if( !( tabBar && stack ) ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); + + // tab orientation + bool verticalTabs( tabOption && isVerticalTab( tabOption->shape ) ); + if( verticalTabs ) + { + int tabBarHeight = tabBar->minimumSizeHint().height(); + int stackHeight = stack->minimumSizeHint().height(); + if( contentsSize.height() == tabBarHeight && tabBarHeight + 2*(Metrics::Frame_FrameWidth - 1) >= stackHeight + 2*Metrics::TabWidget_MarginWidth ) return QSize( contentsSize.width() + 2*Metrics::TabWidget_MarginWidth, contentsSize.height() + 2*(Metrics::Frame_FrameWidth - 1) ); + else return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); + + } else { + + int tabBarWidth = tabBar->minimumSizeHint().width(); + int stackWidth = stack->minimumSizeHint().width(); + if( contentsSize.width() == tabBarWidth && tabBarWidth + 2*(Metrics::Frame_FrameWidth - 1) >= stackWidth + 2*Metrics::TabWidget_MarginWidth) return QSize( contentsSize.width() + 2*(Metrics::Frame_FrameWidth - 1), contentsSize.height() + 2*Metrics::TabWidget_MarginWidth ); + else return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); + + } + + } + + //______________________________________________________________ + QSize Style::tabBarTabSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const + { + const QStyleOptionTab *tabOption( qstyleoption_cast( option ) ); + const QStyleOptionTabV3 *tabOptionV3( qstyleoption_cast( option ) ); + bool hasText( tabOption && !tabOption->text.isEmpty() ); + bool hasIcon( tabOption && !tabOption->icon.isNull() ); + bool hasLeftButton( tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty() ); + bool hasRightButton( tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty() ); + + // calculate width increment for horizontal tabs + int widthIncrement = 0; + if( hasIcon && !( hasText || hasLeftButton || hasRightButton ) ) widthIncrement -= 4; + if( hasText && hasIcon ) widthIncrement += Metrics::TabBar_TabItemSpacing; + if( hasLeftButton && ( hasText || hasIcon ) ) widthIncrement += Metrics::TabBar_TabItemSpacing; + if( hasRightButton && ( hasText || hasIcon || hasLeftButton ) ) widthIncrement += Metrics::TabBar_TabItemSpacing; + + // add margins + QSize size( contentsSize ); + + if ( hasText ) { + widthIncrement += option->fontMetrics.width(tabOption->text) * 0.2; + } + + // compare to minimum size + bool verticalTabs( tabOption && isVerticalTab( tabOption ) ); + if( verticalTabs ) + { + + size.rheight() += widthIncrement; + if( hasIcon && !hasText ) size = size.expandedTo( QSize( Metrics::TabBar_TabMinHeight, 0 ) ); + else size = size.expandedTo( QSize( Metrics::TabBar_TabMinHeight, Metrics::TabBar_TabMinWidth ) ); + + } else { + + size.rwidth() += widthIncrement; + if( hasIcon && !hasText ) size = size.expandedTo( QSize( 0, Metrics::TabBar_TabMinHeight ) ); + else size = size.expandedTo( QSize( Metrics::TabBar_TabMinWidth, Metrics::TabBar_TabMinHeight ) ); + + } + + return size; + + } + + //______________________________________________________________ + QSize Style::headerSectionSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const + { + + // cast option and check + const QStyleOptionHeader* headerOption( qstyleoption_cast( option ) ); + if( !headerOption ) return contentsSize; + + // get text size + bool horizontal( headerOption->orientation == Qt::Horizontal ); + bool hasText( !headerOption->text.isEmpty() ); + bool hasIcon( !headerOption->icon.isNull() ); + + QSize textSize( hasText ? headerOption->fontMetrics.size( 0, headerOption->text ) : QSize() ); + QSize iconSize( hasIcon ? QSize( 22,22 ) : QSize() ); + + // contents width + int contentsWidth( 0 ); + if( hasText ) contentsWidth += textSize.width(); + if( hasIcon ) + { + contentsWidth += iconSize.width(); + if( hasText ) contentsWidth += Metrics::Header_ItemSpacing; + } + + // contents height + int contentsHeight( headerOption->fontMetrics.height() ); + if( hasIcon ) contentsHeight = qMax( contentsHeight, iconSize.height() ); + + if( horizontal ) + { + // also add space for icon + contentsWidth += Metrics::Header_ArrowSize + Metrics::Header_ItemSpacing; + contentsHeight = qMax( contentsHeight, int(Metrics::Header_ArrowSize) ); + } + + // update contents size, add margins and return + QSize size( contentsSize.expandedTo( QSize( contentsWidth, contentsHeight ) ) ); + return expandSize( size, Metrics::Header_MarginWidth ); + + } + + //______________________________________________________________ + QSize Style::itemViewItemSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const + { + // call base class + QSize size( ParentStyleClass::sizeFromContents( CT_ItemViewItem, option, contentsSize, widget ) ); + return expandSize( size, Metrics::ItemView_ItemMarginWidth ); + } + + //______________________________________________________________ + bool Style::drawFramePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // copy palette and rect + const QPalette& palette( option->palette ); + const QRect& rect( option->rect ); + + // detect title widgets + const bool isTitleWidget( + StyleConfigData::titleWidgetDrawFrame() && + widget && + widget->parent() && + widget->parent()->inherits( "KTitleWidget" ) ); + + // copy state + const State& state( option->state ); + if( !isTitleWidget && !( state & (State_Sunken | State_Raised ) ) ) return true; + + #if QT_VERSION >= 0x050000 + const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) || + ( isQtQuickControl( option, widget ) && option->styleObject->property( "elementType" ).toString() == QStringLiteral( "edit") ) ); + #else + bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) ); + #endif + + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && isInputWidget && ( state & State_MouseOver ) ); + bool hasFocus( enabled && isInputWidget && ( state & State_HasFocus ) ); + + // focus takes precedence over mouse over + _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); + _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); + + // retrieve animation mode and opacity + AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); + qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); + + // render + if( !StyleConfigData::sidePanelDrawFrame() && widget && widget->property( PropertyNames::sidePanelView ).toBool() ) + { + + QColor outline( _helper->sidePanelOutlineColor( palette, hasFocus, opacity, mode ) ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + Side side( reverseLayout ? SideRight : SideLeft ); + _helper->renderSidePanelFrame( painter, rect, outline, side ); + + } else if (qobject_cast(widget)) { + QColor outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + _helper->renderSquareFrame( painter, rect, outline, hasFocus ); + } else { + + QColor background( isTitleWidget ? palette.color( widget->backgroundRole() ):QColor() ); + QColor outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + _helper->renderFrame( painter, rect, background, outline, hasFocus ); + + } + + return true; + + } + + //______________________________________________________________ + bool Style::drawFrameLineEditPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + // copy palette and rect + const QPalette& palette( option->palette ); + const QRect& rect( option->rect ); + + // make sure there is enough room to render frame + if( rect.height() < 2*Metrics::LineEdit_FrameWidth + option->fontMetrics.height()) + { + + QColor background( palette.color( QPalette::Base ) ); + + painter->setPen( Qt::NoPen ); + painter->setBrush( background ); + painter->drawRect( rect ); + return true; + + } else { + + // copy state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool hasFocus( enabled && ( state & State_HasFocus ) ); + + // focus takes precedence over mouse over + _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); + _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); + + // retrieve animation mode and opacity + AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); + qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); + + // render + QColor background( palette.color( QPalette::Base ) ); + QColor outline( _helper->inputOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + if (qobject_cast(widget)) + _helper->renderFlatFrame( painter, rect, background, outline, hasFocus ); + else + _helper->renderFrame( painter, rect, background, outline, hasFocus ); + + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawFrameFocusRectPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + #if QT_VERSION >= 0x050000 + if ( option->styleObject && option->styleObject->property("elementType") == QLatin1String("button") ) + return true; + #endif + + const State& state( option->state ); + QRectF rect( QRectF(option->rect).adjusted( 0, 0, -1, -1 ) ); + const QPalette& palette( option->palette ); + + if( rect.width() < 10 ) return true; + + QColor outlineColor( Helper::mix(palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.35) ); + QPen pen(outlineColor, 1); + pen.setStyle( Qt::CustomDashLine ); + pen.setDashPattern(QVector() << 2 << 1); + + painter->setRenderHint( QPainter::Antialiasing, false ); + + painter->setPen( pen ); + painter->drawRoundedRect( rect, 2, 2 ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawFrameMenuPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + // only draw frame for (expanded) toolbars and QtQuick controls + // do nothing for other cases, for which frame is rendered via drawPanelMenuPrimitive + if( qobject_cast( widget ) ) + { + + const QPalette& palette( option->palette ); + QColor background( _helper->frameBackgroundColor( palette ) ); + QColor outline( _helper->frameOutlineColor( palette ) ); + + bool hasAlpha( _helper->hasAlphaChannel( widget ) ); + _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); + + } else if( isQtQuickControl( option, widget ) ) { + + const QPalette& palette( option->palette ); + QColor background( _helper->frameBackgroundColor( palette ) ); + QColor outline( _helper->frameOutlineColor( palette ) ); + + bool hasAlpha( _helper->hasAlphaChannel( widget ) ); + _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); + + } + + return true; + + } + + //______________________________________________________________ + bool Style::drawFrameGroupBoxPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawFrameTabWidgetPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionTabWidgetFrameV2* tabOption( qstyleoption_cast( option ) ); + if( !tabOption ) return true; + + // do nothing if tabbar is hidden + bool isQtQuickControl( this->isQtQuickControl( option, widget ) ); + if( tabOption->tabBarSize.isEmpty() && !isQtQuickControl ) return true; + + // adjust rect to handle overlaps + QRect rect( option->rect ); + + QRect tabBarRect( tabOption->tabBarRect ); + QSize tabBarSize( tabOption->tabBarSize ); + Corners corners = AllCorners; + + // adjust corners to deal with oversized tabbars + switch( tabOption->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + if( isQtQuickControl ) rect.adjust( -1, -1, 1, 0 ); + if( tabBarSize.width() >= rect.width() - 2*Metrics::Frame_FrameRadius ) corners &= ~CornersTop; + if( tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopLeft; + if( tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius ) corners &= ~CornerTopRight; + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + if( isQtQuickControl ) rect.adjust( -1, 0, 1, 1 ); + if( tabBarSize.width() >= rect.width()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersBottom; + if( tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius ) corners &= ~CornerBottomLeft; + if( tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomRight; + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + if( isQtQuickControl ) rect.adjust( -1, 0, 0, 0 ); + if( tabBarSize.height() >= rect.height()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersLeft; + if( tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopLeft; + if( tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomLeft; + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + if( isQtQuickControl ) rect.adjust( 0, 0, 1, 0 ); + if( tabBarSize.height() >= rect.height()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersRight; + if( tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopRight; + if( tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomRight; + break; + + default: break; + } + + // define colors + const QPalette& palette( option->palette ); + QColor background( palette.color(QPalette::Base) ); + QColor outline( _helper->frameOutlineColor( palette ) ); + _helper->renderTabWidgetFrame( painter, rect, background, outline, corners ); + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawFrameTabBarBasePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // tabbar frame used either for 'separate' tabbar, or in 'document mode' + + // cast option and check + const QStyleOptionTabBarBase* tabOption( qstyleoption_cast( option ) ); + if( !tabOption ) return true; + + // get rect, orientation, palette + QRect rect( option->rect ); + QColor outline( _helper->frameOutlineColor( option->palette ) ); + QColor background = _helper->tabBarColor( option->palette, option->state ); + + // setup painter + painter->setBrush( background ); + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setPen( QPen( outline, 1 ) ); + + painter->drawRect(rect.adjusted(0, 0, -1, -1)); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawFrameWindowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + State state( option->state ); + bool selected( state & State_Selected ); + + // render frame outline + QColor outline( _helper->frameOutlineColor( palette, false, selected ) ); + _helper->renderMenuFrame( painter, rect, QColor(), outline ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorArrowPrimitive( ArrowOrientation orientation, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // store rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // store state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool hasFocus( enabled && ( state & State_HasFocus ) ); + + // detect special buttons + bool inTabBar( widget && qobject_cast( widget->parentWidget() ) ); + bool inToolButton( qstyleoption_cast( option ) ); + + // color + QColor color; + if( inTabBar ) { + + // for tabbar arrows one uses animations to get the arrow color + /* + * get animation state + * there is no need to update the engine since this was already done when rendering the frame + */ + AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); + color = _helper->arrowColor( palette, mouseOver, hasFocus, opacity, mode ); + + } else if( mouseOver && !inToolButton ) { + + color = _helper->hoverColor( palette ); + + } else if( inToolButton ) { + + bool flat( state & State_AutoRaise ); + + // cast option + const QStyleOptionToolButton* toolButtonOption( static_cast( option ) ); + bool hasPopupMenu( toolButtonOption->subControls & SC_ToolButtonMenu ); + if( flat && hasPopupMenu ) + { + + // for menu arrows in flat toolbutton one uses animations to get the arrow color + // handle arrow over animation + bool arrowHover( mouseOver && ( toolButtonOption->activeSubControls & SC_ToolButtonMenu ) ); + _animations->toolButtonEngine().updateState( widget, AnimationHover, arrowHover ); + + bool animated( _animations->toolButtonEngine().isAnimated( widget, AnimationHover ) ); + qreal opacity( _animations->toolButtonEngine().opacity( widget, AnimationHover ) ); + + color = _helper->arrowColor( palette, arrowHover, false, opacity, animated ? AnimationHover:AnimationNone ); + + } else { + + bool sunken( state & (State_On | State_Sunken) ); + if( flat ) + { + + if( sunken && hasFocus && !mouseOver ) color = palette.color( QPalette::HighlightedText ); + else color = _helper->arrowColor( palette, QPalette::WindowText ); + + } else if( hasFocus && !mouseOver ) { + + color = palette.color( QPalette::HighlightedText ); + + } else { + + color = _helper->arrowColor( palette, QPalette::ButtonText ); + + } + } + + } else color = _helper->arrowColor( palette, QPalette::WindowText ); + + // render + _helper->renderArrow( painter, rect, color, orientation ); + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorHeaderArrowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + const QStyleOptionHeader *headerOption( qstyleoption_cast( option ) ); + const State& state( option->state ); + + // arrow orientation + ArrowOrientation orientation( ArrowNone ); + if( state & State_UpArrow || ( headerOption && headerOption->sortIndicator==QStyleOptionHeader::SortUp ) ) orientation = ArrowUp; + else if( state & State_DownArrow || ( headerOption && headerOption->sortIndicator==QStyleOptionHeader::SortDown ) ) orientation = ArrowDown; + if( orientation == ArrowNone ) return true; + + // invert arrows if requested by (hidden) options + if( StyleConfigData::viewInvertSortIndicator() ) orientation = (orientation == ArrowUp) ? ArrowDown:ArrowUp; + + // define color and polygon for drawing arrow + QColor color = _helper->headerTextColor( option->palette, state ); + + // render + _helper->renderArrow( painter, option->rect, color, orientation ); + + return true; + } + + //______________________________________________________________ + bool Style::drawPanelButtonCommandPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionButton* buttonOption( qstyleoption_cast< const QStyleOptionButton* >( option ) ); + if( !buttonOption ) return true; + + // rect and palette + const QRect& rect( option->rect ); + + // button state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool hasFocus( ( enabled && ( state & State_HasFocus ) ) && !( widget && widget->focusProxy())); + bool sunken( state & ( State_On|State_Sunken ) ); + bool flat( buttonOption->features & QStyleOptionButton::Flat ); + + // update animation state + // mouse over takes precedence over focus + _animations->widgetStateEngine().updateState( widget, AnimationPressed, sunken ); + _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); + + AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); + + if( flat ) + { + + // define colors and render + const QPalette& palette( option->palette ); + QColor color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + _helper->renderToolButtonFrame( painter, rect, color, sunken ); + + } else { + + // update button color from palette in case button is default + QPalette palette( option->palette ); + if( enabled && buttonOption->features & QStyleOptionButton::DefaultButton ) + { + QColor button( palette.color( QPalette::Button ) ); + QColor base( palette.color( QPalette::Base ) ); + palette.setColor( QPalette::Button, Helper::mix( button, base, 0.7 ) ); + } + + QColor shadow( _helper->shadowColor( palette ) ); + QColor outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + QColor background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + + // render + _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken, mouseOver, enabled && windowActive ); + + } + + return true; + + } + + //______________________________________________________________ + bool Style::drawPanelButtonToolPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // copy palette and rect + const QPalette& palette( option->palette ); + QRect rect( option->rect ); + + // store relevant flags + const State& state( option->state ); + bool autoRaise( state & State_AutoRaise ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + bool sunken( state & (State_On | State_Sunken) ); + bool mouseOver( (state & State_Active) && enabled && (option->state & State_MouseOver) ); + bool hasFocus( enabled && (option->state & (State_HasFocus | State_Sunken)) ); + + /* + * get animation state + * no need to update, this was already done in drawToolButtonComplexControl + */ + AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); + + if( !autoRaise || mouseOver || sunken ) + { + + // need to check widget for popup mode, because option is not set properly + const QToolButton* toolButton( qobject_cast( widget ) ); + bool hasPopupMenu( toolButton && toolButton->popupMode() == QToolButton::MenuButtonPopup ); + + // render as push button + QColor shadow( _helper->shadowColor( palette ) ); + QColor outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + QColor background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + + // adjust frame in case of menu + if( hasPopupMenu ) + { + painter->setClipRect( rect ); + rect.adjust( 0, 0, Metrics::Frame_FrameRadius + 2, 0 ); + rect = visualRect( option, rect ); + } + + // render + _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken, mouseOver, windowActive ); + + } else { + + QColor color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + _helper->renderToolButtonFrame( painter, rect, color, sunken ); + + } + + return true; + } + + //______________________________________________________________ + bool Style::drawTabBarPanelButtonToolPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // copy palette and rect + QRect rect( option->rect ); + + // static_cast is safe here since check was already performed in calling function + const QTabBar* tabBar( static_cast( widget->parentWidget() ) ); + + // overlap. + // subtract 1, because of the empty pixel left the tabwidget frame + int overlap( Metrics::TabBar_BaseOverlap - 1 ); + + // adjust rect based on tabbar shape + switch( tabBar->shape() ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + rect.adjust( 0, 0, 0, -overlap ); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + rect.adjust( 0, overlap, 0, 0 ); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + rect.adjust( 0, 0, -overlap, 0 ); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + rect.adjust( overlap, 0, 0, 0 ); + break; + + default: break; + + } + + // get the relevant palette + const QWidget* parent( tabBar->parentWidget() ); + if( qobject_cast( parent ) ) parent = parent->parentWidget(); + QPalette palette( parent ? parent->palette() : QApplication::palette() ); + QColor color = hasAlteredBackground(parent) ? _helper->frameBackgroundColor( palette ):palette.color( QPalette::Window ); + + // render flat background + painter->setPen( Qt::NoPen ); + painter->setBrush( color ); + painter->drawRect( rect ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawPanelScrollAreaCornerPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // make sure background role matches viewport + const QAbstractScrollArea* scrollArea; + if( ( scrollArea = qobject_cast( widget ) ) && scrollArea->viewport() ) + { + + // need to adjust clipRect in order not to render outside of frame + int frameWidth( pixelMetric( PM_DefaultFrameWidth, 0, scrollArea ) ); + painter->setClipRect( insideMargin( scrollArea->rect(), frameWidth ) ); + painter->setBrush( scrollArea->viewport()->palette().color( scrollArea->viewport()->backgroundRole() ) ); + painter->setPen( Qt::NoPen ); + painter->drawRect( option->rect ); + return true; + + } else { + + return false; + + } + + } + //___________________________________________________________________________________ + bool Style::drawPanelMenuPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + /* + * do nothing if menu is embedded in another widget + * this corresponds to having a transparent background + */ + if( widget && !widget->isWindow() ) return true; + + const QPalette& palette( option->palette ); + QColor background( _helper->frameBackgroundColor( palette ) ); + QColor outline( _helper->frameOutlineColor( palette ) ); + + bool hasAlpha( _helper->hasAlphaChannel( widget ) ); + _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawPanelTipLabelPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + const QPalette& palette( option->palette ); + QColor background( palette.color( QPalette::ToolTipBase ) ); + QColor outline( Helper::mix( palette.color( QPalette::ToolTipBase ), palette.color( QPalette::ToolTipText ), 0.25 ) ); + bool hasAlpha( _helper->hasAlphaChannel( widget ) ); + + _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawPanelItemViewItemPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionViewItemV4 *viewItemOption = qstyleoption_cast( option ); + if( !viewItemOption ) return false; + + // try cast widget + const QAbstractItemView *abstractItemView = qobject_cast( widget ); + + // store palette and rect + const QPalette& palette( option->palette ); + QRect rect( option->rect ); + + // store flags + const State& state( option->state ); + bool mouseOver( (state & State_Active) && ( state & State_MouseOver ) && ( !abstractItemView || abstractItemView->selectionMode() != QAbstractItemView::NoSelection ) ); + bool selected( state & State_Selected ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + + bool hasCustomBackground = viewItemOption->backgroundBrush.style() != Qt::NoBrush && !( state & State_Selected ); + bool hasSolidBackground = !hasCustomBackground || viewItemOption->backgroundBrush.style() == Qt::SolidPattern; + bool hasAlternateBackground( viewItemOption->features & QStyleOptionViewItemV2::Alternate ); + + // do nothing if no background is to be rendered + if( !( mouseOver || selected || hasCustomBackground || hasAlternateBackground ) ) + { return true; } + + // define color group + QPalette::ColorGroup colorGroup; + if( enabled ) colorGroup = windowActive ? QPalette::Active : QPalette::Inactive; + else colorGroup = QPalette::Disabled; + + // render alternate background + if( viewItemOption && ( viewItemOption->features & QStyleOptionViewItemV2::Alternate ) ) + { + painter->setPen( Qt::NoPen ); + painter->setBrush( palette.brush( colorGroup, QPalette::AlternateBase ) ); + painter->drawRect( rect ); + } + + // stop here if no highlight is needed + if( !( mouseOver || selected ||hasCustomBackground ) ) + { return true; } + + // render custom background + if( hasCustomBackground && !hasSolidBackground ) + { + + painter->setBrushOrigin( viewItemOption->rect.topLeft() ); + painter->setBrush( viewItemOption->backgroundBrush ); + painter->setPen( Qt::NoPen ); + painter->drawRect( viewItemOption->rect ); + return true; + + } + + // render selection + // define color + QColor color; + if( hasCustomBackground && hasSolidBackground ) color = viewItemOption->backgroundBrush.color(); + else color = palette.color( colorGroup, QPalette::Highlight ); + + // change color to implement mouse over + if( mouseOver && !hasCustomBackground ) + { + if( !selected ) color.setAlphaF( 0.2 ); + else color = color.lighter( 110 ); + } + + // render + _helper->renderSelection( painter, rect, color ); + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorCheckBoxPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // copy rect and palette + const QRect& rect( option->rect.adjusted(1, 1, -1, -1) ); + const QPalette& palette( option->palette ); + + // store flags + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool sunken( enabled && ( state & State_Sunken ) ); + bool active( ( state & (State_On|State_NoChange) ) ); + bool windowActive( state & State_Active ); + + const QColor& outline( _helper->frameOutlineColor( palette ) ); + const QColor& background( _helper->buttonBackgroundColor(palette, mouseOver, false, sunken ) ); + + // checkbox state + CheckBoxState checkBoxState( CheckOff ); + if( state & State_NoChange ) checkBoxState = CheckPartial; + else if( state & State_On ) checkBoxState = CheckOn; + + // detect checkboxes in lists + bool isSelectedItem( this->isSelectedItem( widget, rect.center() ) ); + + // animation state + _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); + if (checkBoxState != CheckPartial) { + _animations->widgetStateEngine().updateState( widget, AnimationPressed, checkBoxState != CheckOff ); + if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) checkBoxState = CheckAnimated; + } + qreal animation( _animations->widgetStateEngine().opacity( widget, AnimationPressed ) ); + + QColor tickColor; + if( isSelectedItem ) { + + tickColor = _helper->checkBoxIndicatorColor( palette, false, enabled && active ); + _helper->renderCheckBoxBackground( painter, rect, palette.color( QPalette::Base ), outline, sunken ); + + } else { + + AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); + qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); + tickColor = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && active, opacity, mode ); + + } + + // render + QColor shadow( _helper->shadowColor( palette ) ); + _helper->renderCheckBox( painter, rect, background, outline, tickColor, sunken, checkBoxState, animation, enabled && windowActive ); + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorRadioButtonPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // store flags + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool sunken( state & State_Sunken ); + bool checked( state & State_On ); + bool windowActive( state & State_Active ); + + const QColor& outline( _helper->frameOutlineColor( palette ) ); + const QColor& background( _helper->buttonBackgroundColor(palette, mouseOver, false, sunken ) ); + + // radio button state + RadioButtonState radioButtonState( state & State_On ? RadioOn:RadioOff ); + + // detect radiobuttons in lists + bool isSelectedItem( this->isSelectedItem( widget, rect.center() ) ); + + // animation state + _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); + _animations->widgetStateEngine().updateState( widget, AnimationPressed, radioButtonState != RadioOff ); + if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) radioButtonState = RadioAnimated; + qreal animation( _animations->widgetStateEngine().opacity( widget, AnimationPressed ) ); + + // colors + QColor shadow( _helper->shadowColor( palette ) ); + QColor tickColor; + if( isSelectedItem ) + { + + tickColor = _helper->checkBoxIndicatorColor( palette, false, enabled && checked ); + _helper->renderRadioButtonBackground( painter, rect, palette.color( QPalette::Base ), outline, sunken ); + + } else { + + AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); + qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); + tickColor = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && checked, opacity, mode ); + + } + + // render + _helper->renderRadioButton( painter, rect, background, outline, tickColor, sunken, enabled && windowActive, radioButtonState, animation ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorButtonDropDownPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionToolButton* toolButtonOption( qstyleoption_cast( option ) ); + if( !toolButtonOption ) return true; + + // store state + const State& state( option->state ); + bool autoRaise( state & State_AutoRaise ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + bool hasFocus( enabled && ( state & ( State_HasFocus | State_Sunken ) ) ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool sunken( enabled && ( state & State_Sunken ) ); + + // do nothing for autoraise buttons + if( (autoRaise && !sunken && !mouseOver) || !(toolButtonOption->subControls & SC_ToolButtonMenu) ) return true; + + // store palette and rect + const QPalette& palette( option->palette ); + const QRect& rect( option->rect ); + + // update animation state + // mouse over takes precedence over focus + _animations->widgetStateEngine().updateState( widget, AnimationPressed, sunken ); + _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); + + AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); + + // render as push button + QColor shadow( _helper->shadowColor( palette ) ); + QColor outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + QColor background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + + QRect frameRect( rect ); + painter->setClipRect( rect ); + frameRect.adjust( -Metrics::Frame_FrameRadius - 1, 0, 0, 0 ); + frameRect = visualRect( option, frameRect ); + + // render + _helper->renderButtonFrame( painter, frameRect, background, outline, shadow, hasFocus, sunken, mouseOver, windowActive ); + + // also render separator + QRect separatorRect( rect.adjusted( 0, 2, -2, -2 ) ); + separatorRect.setWidth( 1 ); + separatorRect = visualRect( option, separatorRect ); + _helper->renderSeparator( painter, separatorRect, outline, true ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorTabClosePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // get icon and check + QIcon icon( standardIcon( SP_TitleBarCloseButton, option, widget ) ); + if( icon.isNull() ) return false; + + // store state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool active( state & State_Raised ); + bool sunken( state & State_Sunken ); + + // decide icon mode and state + QIcon::Mode iconMode; + QIcon::State iconState; + if( !enabled ) + { + iconMode = QIcon::Disabled; + iconState = QIcon::Off; + + } else { + + if( active ) iconMode = QIcon::Active; + else iconMode = QIcon::Normal; + + iconState = sunken ? QIcon::On : QIcon::Off; + } + + // icon size + int iconWidth( pixelMetric(QStyle::PM_SmallIconSize, option, widget ) ); + QSize iconSize( iconWidth, iconWidth ); + + // get pixmap + QPixmap pixmap( icon.pixmap( iconSize, iconMode, iconState ) ); + + // render + drawItemPixmap( painter, option->rect, Qt::AlignCenter, pixmap ); + return true; + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorTabTearPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // cast option and check + const QStyleOptionTab* tabOption( qstyleoption_cast( option ) ); + if( !tabOption ) return true; + + // store palette and rect + const QPalette& palette( option->palette ); + QRect rect( option->rect ); + + bool reverseLayout( option->direction == Qt::RightToLeft ); + + QColor color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.2 ) ); + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setPen( color ); + painter->setBrush( Qt::NoBrush ); + switch( tabOption->shape ) + { + + case QTabBar::TriangularNorth: + case QTabBar::RoundedNorth: + rect.adjust( 0, 1, 0, 0 ); + if( reverseLayout ) painter->drawLine( rect.topRight(), rect.bottomRight() ); + else painter->drawLine( rect.topLeft(), rect.bottomLeft() ); + break; + + case QTabBar::TriangularSouth: + case QTabBar::RoundedSouth: + rect.adjust( 0, 0, 0, -1 ); + if( reverseLayout ) painter->drawLine( rect.topRight(), rect.bottomRight() ); + else painter->drawLine( rect.topLeft(), rect.bottomLeft() ); + break; + + case QTabBar::TriangularWest: + case QTabBar::RoundedWest: + rect.adjust( 1, 0, 0, 0 ); + painter->drawLine( rect.topLeft(), rect.topRight() ); + break; + + case QTabBar::TriangularEast: + case QTabBar::RoundedEast: + rect.adjust( 0, 0, -1, 0 ); + painter->drawLine( rect.topLeft(), rect.topRight() ); + break; + + default: break; + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorToolBarHandlePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // do nothing if disabled from options + if( !StyleConfigData::toolBarDrawItemSeparator() ) return true; + + // store rect and palette + QRect rect( option->rect ); + const QPalette& palette( option->palette ); + + // store state + const State& state( option->state ); + bool separatorIsVertical( state & State_Horizontal ); + + // define color and render + QColor color( _helper->separatorColor( palette ) ); + if( separatorIsVertical ) + { + rect.setWidth( Metrics::ToolBar_HandleWidth ); + rect = centerRect( option->rect, rect.size() ); + rect.setWidth( 3 ); + _helper->renderSeparator( painter, rect, color, separatorIsVertical ); + + rect.translate( 2, 0 ); + _helper->renderSeparator( painter, rect, color, separatorIsVertical ); + + } else { + + rect.setHeight( Metrics::ToolBar_HandleWidth ); + rect = centerRect( option->rect, rect.size() ); + rect.setHeight( 3 ); + _helper->renderSeparator( painter, rect, color, separatorIsVertical ); + + rect.translate( 0, 2 ); + _helper->renderSeparator( painter, rect, color, separatorIsVertical ); + + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorToolBarSeparatorPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + /* + * do nothing if disabled from options + * also need to check if widget is a combobox, because of Qt hack using 'toolbar' separator primitive + * for rendering separators in comboboxes + */ + if( !( StyleConfigData::toolBarDrawItemSeparator() || qobject_cast( widget ) ) ) + { return true; } + + // store rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // store state + const State& state( option->state ); + bool separatorIsVertical( state & State_Horizontal ); + + // define color and render + QColor color( _helper->separatorColor( palette ) ); + _helper->renderSeparator( painter, rect, color, separatorIsVertical ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawIndicatorBranchPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // state + const State& state( option->state ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + + //draw expander + int expanderAdjust = 0; + if( state & State_Children ) + { + + // state + bool expanderOpen( state & State_Open ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + + // expander rect + int expanderSize = qMin( rect.width(), rect.height() ); + expanderSize = qMin( expanderSize, int(Metrics::ItemView_ArrowSize) ); + expanderAdjust = expanderSize/2 + 1; + QRect arrowRect = centerRect( rect, expanderSize, expanderSize ); + + // get orientation from option + ArrowOrientation orientation; + if( expanderOpen ) orientation = ArrowDown; + else if( reverseLayout ) orientation = ArrowLeft; + else orientation = ArrowRight; + + // color + QColor arrowColor( mouseOver ? _helper->hoverColor( palette ) : _helper->arrowColor( palette, QPalette::Text ) ); + + // render + _helper->renderArrow( painter, arrowRect, arrowColor, orientation ); + + } + + // tree branches + if( !StyleConfigData::viewDrawTreeBranchLines() ) return true; + + QPoint center( rect.center() ); + QColor lineColor( Helper::mix( palette.color( QPalette::Base ), palette.color( QPalette::Text ), 0.25 ) ); + painter->save(); + painter->setRenderHint( QPainter::Antialiasing, true ); + painter->translate( 0.5, 0.5 ); + painter->setPen( QPen( lineColor, 1 ) ); + if( state & ( State_Item | State_Children | State_Sibling ) ) + { + QLineF line( QPointF( center.x(), rect.top() ), QPointF( center.x(), center.y() - expanderAdjust - 1 ) ); + painter->drawLine( line ); + } + + // The right/left (depending on direction) line gets drawn if we have an item + if( state & State_Item ) + { + const QLineF line = reverseLayout ? + QLineF( QPointF( rect.left(), center.y() ), QPointF( center.x() - expanderAdjust, center.y() ) ): + QLineF( QPointF( center.x() + expanderAdjust, center.y() ), QPointF( rect.right(), center.y() ) ); + painter->drawLine( line ); + + } + + // The bottom if we have a sibling + if( state & State_Sibling ) + { + QLineF line( QPointF( center.x(), center.y() + expanderAdjust ), QPointF( center.x(), rect.bottom() ) ); + painter->drawLine( line ); + } + painter->restore(); + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawPushButtonLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionButton* buttonOption( qstyleoption_cast( option ) ); + if( !buttonOption ) return true; + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool sunken( state & (State_On | State_Sunken) ); + bool mouseOver( (state & State_Active) && enabled && (option->state & State_MouseOver) ); + bool hasFocus( enabled && !mouseOver && (option->state & State_HasFocus) ); + bool flat( buttonOption->features & QStyleOptionButton::Flat ); + + // content + bool hasText( !buttonOption->text.isEmpty() ); + bool hasIcon( (showIconsOnPushButtons() || flat || !hasText ) && !buttonOption->icon.isNull() ); + + // contents + QRect contentsRect( rect ); + + // color role + QPalette::ColorRole textRole; + if( flat ) + { + + if( hasFocus && sunken ) textRole = QPalette::ButtonText; + else textRole = QPalette::WindowText; + + } else if( hasFocus ) textRole = QPalette::ButtonText; + else textRole = QPalette::ButtonText; + + // menu arrow + if( buttonOption->features & QStyleOptionButton::HasMenu ) + { + + // define rect + QRect arrowRect( contentsRect ); + arrowRect.setLeft( contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1 ); + arrowRect = centerRect( arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); + + contentsRect.setRight( arrowRect.left() - Metrics::Button_ItemSpacing - 1 ); + contentsRect.adjust( Metrics::Button_MarginWidth, 0, 0, 0 ); + + arrowRect = visualRect( option, arrowRect ); + + // define color + QColor arrowColor( _helper->arrowColor( palette, textRole ) ); + _helper->renderArrow( painter, arrowRect, arrowColor, ArrowDown ); + + } + + // icon size + QSize iconSize; + if( hasIcon ) + { + iconSize = buttonOption->iconSize; + if( !iconSize.isValid() ) + { + int metric( pixelMetric( PM_SmallIconSize, option, widget ) ); + iconSize = QSize( metric, metric ); + } + } + + // text size + int textFlags( _mnemonics->textFlags() | Qt::AlignCenter ); + QSize textSize( option->fontMetrics.size( textFlags, buttonOption->text ) ); + + // adjust text and icon rect based on options + QRect iconRect; + QRect textRect; + + if( hasText && !hasIcon ) textRect = contentsRect; + else if( hasIcon && !hasText ) iconRect = contentsRect; + else { + + int contentsWidth( iconSize.width() + textSize.width() + Metrics::Button_ItemSpacing ); + iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - contentsWidth )/2, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); + textRect = QRect( QPoint( iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height())/2 ), textSize ); + + } + + // handle right to left + if( iconRect.isValid() ) iconRect = visualRect( option, iconRect ); + if( textRect.isValid() ) textRect = visualRect( option, textRect ); + + // make sure there is enough room for icon + if( iconRect.isValid() ) iconRect = centerRect( iconRect, iconSize ); + + // render icon + if( hasIcon && iconRect.isValid() ) { + + // icon state and mode + const QIcon::State iconState( sunken ? QIcon::On : QIcon::Off ); + QIcon::Mode iconMode; + if( !enabled ) iconMode = QIcon::Disabled; + else if( !flat && hasFocus ) iconMode = QIcon::Selected; + else if( mouseOver && flat ) iconMode = QIcon::Active; + else iconMode = QIcon::Normal; + + QPixmap pixmap = buttonOption->icon.pixmap( iconSize, iconMode, iconState ); + drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); + + } + + // render text + if( hasText && textRect.isValid() ) + { + if ( enabled && !sunken && !mouseOver && !flat ) { + if ( _dark ) + drawItemText( painter, textRect.adjusted(0, -1, 0, -1), textFlags, palette, false, buttonOption->text, QPalette::Dark ); + else + drawItemText( painter, textRect.adjusted(0, 1, 0, 1), textFlags, palette, false, buttonOption->text, QPalette::Light ); + } + drawItemText( painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole ); + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawToolButtonLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionToolButton* toolButtonOption( qstyleoption_cast(option) ); + + // copy rect and palette + const QRect& rect = option->rect; + const QPalette& palette = option->palette; + + // state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool sunken( state & (State_On | State_Sunken) ); + bool mouseOver( (state & State_Active) && enabled && (option->state & State_MouseOver) ); + bool flat( state & State_AutoRaise ); + + // focus flag is set to match the background color in either renderButtonFrame or renderToolButtonFrame + bool hasFocus( false ); + if( flat ) hasFocus = enabled && !mouseOver && (option->state & State_HasFocus); + else hasFocus = enabled && !mouseOver && (option->state & (State_HasFocus|State_Sunken) ); + + bool hasArrow( toolButtonOption->features & QStyleOptionToolButton::Arrow ); + bool hasIcon( !( hasArrow || toolButtonOption->icon.isNull() ) ); + bool hasText( !toolButtonOption->text.isEmpty() ); + + // contents + QRect contentsRect( rect ); + + // icon size + QSize iconSize( toolButtonOption->iconSize ); + + // text size + int textFlags( _mnemonics->textFlags() ); + QSize textSize( option->fontMetrics.size( textFlags, toolButtonOption->text ) ); + + // adjust text and icon rect based on options + QRect iconRect; + QRect textRect; + + if( hasText && ( !(hasArrow||hasIcon) || toolButtonOption->toolButtonStyle == Qt::ToolButtonTextOnly ) ) + { + + // text only + textRect = contentsRect; + textFlags |= Qt::AlignCenter; + + } else if( (hasArrow||hasIcon) && (!hasText || toolButtonOption->toolButtonStyle == Qt::ToolButtonIconOnly ) ) { + + // icon only + iconRect = contentsRect; + + } else if( toolButtonOption->toolButtonStyle == Qt::ToolButtonTextUnderIcon ) { + + int contentsHeight( iconSize.height() + textSize.height() + Metrics::ToolButton_ItemSpacing ); + iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - iconSize.width())/2, contentsRect.top() + (contentsRect.height() - contentsHeight)/2 ), iconSize ); + textRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - textSize.width())/2, iconRect.bottom() + Metrics::ToolButton_ItemSpacing + 1 ), textSize ); + textFlags |= Qt::AlignCenter; + + } else { + + bool leftAlign( widget && widget->property( PropertyNames::toolButtonAlignment ).toInt() == Qt::AlignLeft ); + if( leftAlign ) iconRect = QRect( QPoint( contentsRect.left(), contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); + else { + + int contentsWidth( iconSize.width() + textSize.width() + Metrics::ToolButton_ItemSpacing ); + iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - contentsWidth )/2, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); + + } + + textRect = QRect( QPoint( iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height())/2 ), textSize ); + + // handle right to left layouts + iconRect = visualRect( option, iconRect ); + textRect = visualRect( option, textRect ); + + textFlags |= Qt::AlignLeft | Qt::AlignVCenter; + + } + + // make sure there is enough room for icon + if( iconRect.isValid() ) iconRect = centerRect( iconRect, iconSize ); + + // render arrow or icon + if( hasArrow && iconRect.isValid() ) + { + + QStyleOptionToolButton copy( *toolButtonOption ); + copy.rect = iconRect; + switch( toolButtonOption->arrowType ) + { + case Qt::LeftArrow: drawPrimitive( PE_IndicatorArrowLeft, ©, painter, widget ); break; + case Qt::RightArrow: drawPrimitive( PE_IndicatorArrowRight, ©, painter, widget ); break; + case Qt::UpArrow: drawPrimitive( PE_IndicatorArrowUp, ©, painter, widget ); break; + case Qt::DownArrow: drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); break; + default: break; + } + + } else if( hasIcon && iconRect.isValid() ) { + + // icon state and mode + const QIcon::State iconState( sunken ? QIcon::On : QIcon::Off ); + QIcon::Mode iconMode; + if( !enabled ) iconMode = QIcon::Disabled; + else if( !flat && hasFocus ) iconMode = QIcon::Selected; + else if( mouseOver && flat ) iconMode = QIcon::Active; + else iconMode = QIcon::Normal; + + QPixmap pixmap = toolButtonOption->icon.pixmap( iconSize, iconMode, iconState ); + drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); + + } + + // render text + if( hasText && textRect.isValid() ) + { + + QPalette::ColorRole textRole( QPalette::ButtonText ); + if( flat ) textRole = (hasFocus&&sunken&&!mouseOver) ? QPalette::HighlightedText: QPalette::WindowText; + else if( hasFocus&&!mouseOver ) textRole = QPalette::HighlightedText; + + painter->setFont(toolButtonOption->font); + drawItemText( painter, textRect, textFlags, palette, enabled, toolButtonOption->text, textRole ); + + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawCheckBoxLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionButton* buttonOption( qstyleoption_cast(option) ); + if( !buttonOption ) return true; + + // copy palette and rect + const QPalette& palette( option->palette ); + const QRect& rect( option->rect ); + + // store state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + + // text alignment + bool reverseLayout( option->direction == Qt::RightToLeft ); + int textFlags( _mnemonics->textFlags() | Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight:Qt::AlignLeft ) ); + + // text rect + QRect textRect( rect ); + + // render icon + if( !buttonOption->icon.isNull() ) + { + const QIcon::Mode mode( enabled ? QIcon::Normal : QIcon::Disabled ); + QPixmap pixmap( buttonOption->icon.pixmap( buttonOption->iconSize, mode ) ); + drawItemPixmap( painter, rect, textFlags, pixmap ); + + // adjust rect (copied from QCommonStyle) + textRect.setLeft( textRect.left() + buttonOption->iconSize.width() + 4 ); + textRect = visualRect( option, textRect ); + + } + + // render text + if( !buttonOption->text.isEmpty() ) + { + textRect = option->fontMetrics.boundingRect( textRect, textFlags, buttonOption->text ); + drawItemText( painter, textRect, textFlags, palette, enabled, buttonOption->text, QPalette::WindowText ); + + // check focus state + bool hasFocus( enabled && ( state & State_HasFocus ) ); + + // update animation state + _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); + bool isFocusAnimated( _animations->widgetStateEngine().isAnimated( widget, AnimationFocus ) ); + qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationFocus ) ); + + } + + return true; + + } + + + //___________________________________________________________________________________ + bool Style::drawComboBoxLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + const QStyleOptionComboBox* comboBoxOption( qstyleoption_cast( option ) ); + if( !comboBoxOption ) return false; + if( comboBoxOption->editable ) return false; + + // need to alter palette for focused buttons + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool sunken( state & (State_On | State_Sunken) ); + bool mouseOver( (state & State_Active) && enabled && (option->state & State_MouseOver) ); + bool hasFocus( enabled && !mouseOver && (option->state & State_HasFocus) ); + bool flat( !comboBoxOption->frame ); + + QPalette::ColorRole textRole = QPalette::ButtonText; + + // change pen color directly + painter->save(); + painter->setPen( QPen( option->palette.color( textRole ), 1 ) ); + + #if QT_VERSION >= 0x050000 + if (const QStyleOptionComboBox *cb = qstyleoption_cast(option)) { + QRect editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); + painter->save(); + painter->setClipRect(editRect); + if (!cb->currentIcon.isNull()) { + QIcon::Mode mode; + + if ((cb->state & QStyle::State_Selected) && (cb->state & QStyle::State_Active)) { + mode = QIcon::Selected; + } else if (cb->state & QStyle::State_Enabled) { + mode = QIcon::Normal; + } else { + mode = QIcon::Disabled; + } + + QPixmap pixmap = cb->currentIcon.pixmap(widget->windowHandle(), cb->iconSize, mode); + QRect iconRect(editRect); + iconRect.setWidth(cb->iconSize.width() + 4); + iconRect = alignedRect(cb->direction, + Qt::AlignLeft | Qt::AlignVCenter, + iconRect.size(), editRect); + if (cb->editable) + painter->fillRect(iconRect, option->palette.brush(QPalette::Base)); + proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + if (cb->direction == Qt::RightToLeft) + editRect.translate(-4 - cb->iconSize.width(), 0); + else + editRect.translate(cb->iconSize.width() + 4, 0); + } + if (!cb->currentText.isEmpty() && !cb->editable) { + proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0), + visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter), + cb->palette, cb->state & State_Enabled, cb->currentText); + } + painter->restore(); + } + #else + // call base class method + ParentStyleClass::drawControl( CE_ComboBoxLabel, option, painter, widget ); + #endif + + painter->restore(); + + return true; + + } + + + //___________________________________________________________________________________ + bool Style::drawMenuBarEmptyArea( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + const QRect& rect( option->rect); + const QPalette& palette( option->palette ); + + painter->save(); + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setBrush( Qt::NoBrush ); + painter->setPen( Helper::mix( palette.color( QPalette::Window ), palette.color( QPalette::Shadow ), 0.2 ) ); + + painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); + painter->restore(); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawMenuBarItemControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // cast option and check + const QStyleOptionMenuItem* menuItemOption = qstyleoption_cast( option ); + if( !menuItemOption ) return true; + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // store state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool selected( enabled && (state & State_Selected) ); + bool sunken( enabled && (state & State_Sunken) ); + bool useStrongFocus( StyleConfigData::menuItemDrawStrongFocus() ); + + painter->save(); + painter->setRenderHint( QPainter::Antialiasing, false ); + + painter->setBrush( palette.window().color() ); + painter->setPen( Qt::NoPen ); + painter->drawRect( rect ); + + painter->setBrush( Qt::NoBrush ); + painter->setPen( Helper::mix( palette.color( QPalette::Window ), palette.color( QPalette::Shadow ), 0.2 ) ); + + painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); + painter->restore(); + + // render hover and focus + if( useStrongFocus && sunken ) + { + + QColor outlineColor = _helper->focusColor( palette ); + _helper->renderFocusRect( painter, QRect( rect.left(), rect.bottom() - 2, rect.width(), 3 ), outlineColor ); + + } + + // get text rect + int textFlags( Qt::AlignCenter|_mnemonics->textFlags() ); + QRect textRect = option->fontMetrics.boundingRect( rect, textFlags, menuItemOption->text ); + + // render text + const QPalette::ColorRole role = (useStrongFocus && sunken ) ? QPalette::Highlight : QPalette::WindowText; + drawItemText( painter, textRect, textFlags, palette, enabled, menuItemOption->text, role ); + + return true; + + } + + bool Style::drawMenuEmptyAreaControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { + if (_isGNOME) + painter->setPen(Qt::transparent); + else + painter->setPen(option->palette.window().color().darker(150)); + + painter->setBrush(option->palette.base().color()); + if (_isGNOME) + painter->drawRect(option->rect); + else + painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); + return true; + } + + + //___________________________________________________________________________________ + bool Style::drawMenuItemControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionMenuItem* menuItemOption = qstyleoption_cast( option ); + if( !menuItemOption ) return true; + if( menuItemOption->menuItemType == QStyleOptionMenuItem::EmptyArea ) return true; + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + const QColor& background( palette.color(QPalette::Active, QPalette::Base) ); + + painter->setPen(Qt::NoPen); + painter->setBrush(background); + painter->drawRect(rect); + + // deal with separators + if( menuItemOption->menuItemType == QStyleOptionMenuItem::Separator ) + { + + // normal separator + if( menuItemOption->text.isEmpty() && menuItemOption->icon.isNull() ) + { + + QColor color( _helper->separatorColor( palette ) ); + _helper->renderSeparator( painter, rect, color ); + return true; + + } else { + + /* + * separator can have a title and an icon + * in that case they are rendered as menu title buttons + */ + QStyleOptionToolButton copy( separatorMenuItemOption( menuItemOption, widget ) ); + renderMenuTitle( ©, painter, widget ); + + return true; + + } + + } + + // store state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + bool selected( enabled && (state & State_Selected) ); + bool sunken( enabled && (state & (State_On|State_Sunken) ) ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + bool useStrongFocus( StyleConfigData::menuItemDrawStrongFocus() ); + + // render hover and focus + if( useStrongFocus && ( selected || sunken ) ) + { + + QColor color = _helper->focusColor( palette ); + QColor outlineColor = Qt::transparent; + + Sides sides = 0; + _helper->renderFocusRect( painter, rect, color, outlineColor, sides ); + + } + + // get rect available for contents + QRect contentsRect( insideMargin( rect, Metrics::MenuItem_MarginWidth ) ); + + // define relevant rectangles + // checkbox + QRect checkBoxRect; + if( menuItemOption->menuHasCheckableItems ) + { + checkBoxRect = QRect( contentsRect.left(), contentsRect.top() + (contentsRect.height()-Metrics::CheckBox_Size)/2, Metrics::CheckBox_Size, Metrics::CheckBox_Size ); + contentsRect.setLeft( checkBoxRect.right() + Metrics::MenuItem_ItemSpacing + 1 ); + } + + // render checkbox indicator + if( menuItemOption->checkType == QStyleOptionMenuItem::NonExclusive ) + { + + checkBoxRect = visualRect( option, checkBoxRect ); + + // checkbox state + + /* + if( useStrongFocus && ( selected || sunken ) ) + { _helper->renderCheckBoxBackground( painter, checkBoxRect, palette.color( QPalette::Window ), outline, sunken ); } + */ + + QColor color( state&State_Enabled ? state&State_Selected ? palette.highlightedText().color() : palette.foreground().color() : palette.text().color() ); + CheckBoxState state( menuItemOption->checked ? CheckOn : CheckOff ); + _helper->renderCheckBox( painter, checkBoxRect, QColor(QColor::Invalid), color, color, sunken, state, enabled && windowActive); + + } else if( menuItemOption->checkType == QStyleOptionMenuItem::Exclusive ) { + + checkBoxRect = visualRect( option, checkBoxRect ); + + /* + if( useStrongFocus && ( selected || sunken ) ) + { _helper->renderRadioButtonBackground( painter, checkBoxRect, palette.color( QPalette::Window ), outline, sunken ); } + */ + + QColor color( state&State_Enabled ? state&State_Selected ? palette.highlightedText().color() : palette.foreground().color() : palette.text().color() ); + bool active( menuItemOption->checked ); + _helper->renderRadioButton( painter, checkBoxRect, QColor(QColor::Invalid), color, color, sunken, enabled && windowActive, active ? RadioOn:RadioOff ); + + } + + // icon + int iconWidth = 0; + bool showIcon( showIconsInMenuItems() ); + if( showIcon ) iconWidth = isQtQuickControl( option, widget ) ? qMax( pixelMetric(PM_SmallIconSize, option, widget ), menuItemOption->maxIconWidth ) : menuItemOption->maxIconWidth; + + QRect iconRect( contentsRect.left(), contentsRect.top() + (contentsRect.height()-iconWidth)/2, iconWidth, iconWidth ); + contentsRect.setLeft( iconRect.right() + Metrics::MenuItem_ItemSpacing + 1 ); + + if( showIcon && !menuItemOption->icon.isNull() ) + { + + QSize iconSize( pixelMetric( PM_SmallIconSize, option, widget ), pixelMetric( PM_SmallIconSize, option, widget ) ); + iconRect = centerRect( iconRect, iconSize ); + iconRect = visualRect( option, iconRect ); + + // icon mode + QIcon::Mode mode; + if( selected && !useStrongFocus) mode = QIcon::Active; + else if( selected ) mode = QIcon::Selected; + else if( enabled ) mode = QIcon::Normal; + else mode = QIcon::Disabled; + + // icon state + const QIcon::State iconState( sunken ? QIcon::On:QIcon::Off ); + QPixmap icon = menuItemOption->icon.pixmap( iconRect.size(), mode, iconState ); + painter->drawPixmap( iconRect, icon ); + + } + + // arrow + QRect arrowRect( contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1, contentsRect.top() + (contentsRect.height()-Metrics::MenuButton_IndicatorWidth)/2, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); + contentsRect.setRight( arrowRect.left() - Metrics::MenuItem_ItemSpacing - 1 ); + + if( menuItemOption->menuItemType == QStyleOptionMenuItem::SubMenu ) + { + + // apply right-to-left layout + arrowRect = visualRect( option, arrowRect ); + + // arrow orientation + ArrowOrientation orientation( reverseLayout ? ArrowLeft:ArrowRight ); + + // color + QColor arrowColor; + if( useStrongFocus && ( selected || sunken ) ) arrowColor = palette.color( QPalette::HighlightedText ); + else if( sunken ) arrowColor = _helper->focusColor( palette ); + else if( selected ) arrowColor = _helper->hoverColor( palette ); + else arrowColor = _helper->arrowColor( palette, QPalette::WindowText ); + + // render + _helper->renderArrow( painter, arrowRect, arrowColor, orientation ); + + } + + + // text + QRect textRect = contentsRect; + if( !menuItemOption->text.isEmpty() ) + { + + // adjust textRect + QString text = menuItemOption->text; + textRect = centerRect( textRect, textRect.width(), option->fontMetrics.size( _mnemonics->textFlags(), text ).height() ); + textRect = visualRect( option, textRect ); + + // set font + painter->setFont( menuItemOption->font ); + + // color role + const QPalette::ColorRole role = (useStrongFocus && ( selected || sunken )) ? QPalette::HighlightedText : QPalette::WindowText; + + // locate accelerator and render + int tabPosition( text.indexOf( QLatin1Char( '\t' ) ) ); + if( tabPosition >= 0 ) + { + + int textFlags( Qt::AlignVCenter | Qt::AlignRight ); + QString accelerator( text.mid( tabPosition + 1 ) ); + text = text.left( tabPosition ); + drawItemText( painter, textRect, textFlags, palette, enabled, accelerator, role ); + + } + + // render text + int textFlags( Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight : Qt::AlignLeft ) | _mnemonics->textFlags() ); + textRect = option->fontMetrics.boundingRect( textRect, textFlags, text ); + drawItemText( painter, textRect, textFlags, palette, enabled, text, role ); + + } + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawProgressBarControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return true; + + // render groove + QStyleOptionProgressBarV2 progressBarOption2 = *progressBarOption; + progressBarOption2.rect = subElementRect( SE_ProgressBarGroove, progressBarOption, widget ); + drawControl( CE_ProgressBarGroove, &progressBarOption2, painter, widget ); + + #if QT_VERSION >= 0x050000 + const QObject* styleObject( widget ? widget:progressBarOption->styleObject ); + #else + const QObject* styleObject( widget ); + #endif + + // enable busy animations + // need to check both widget and passed styleObject, used for QML + if( styleObject && _animations->busyIndicatorEngine().enabled() ) + { + + #if QT_VERSION >= 0x050000 + // register QML object if defined + if( !widget && progressBarOption->styleObject ) + { _animations->busyIndicatorEngine().registerWidget( progressBarOption->styleObject ); } + #endif + + _animations->busyIndicatorEngine().setAnimated( styleObject, progressBarOption->maximum == 0 && progressBarOption->minimum == 0 ); + + } + + // check if animated and pass to option + if( _animations->busyIndicatorEngine().isAnimated( styleObject ) ) + { progressBarOption2.progress = _animations->busyIndicatorEngine().value(); } + + // render contents + progressBarOption2.rect = subElementRect( SE_ProgressBarContents, progressBarOption, widget ); + drawControl( CE_ProgressBarContents, &progressBarOption2, painter, widget ); + + // render text + bool textVisible( progressBarOption->textVisible ); + bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); + if( textVisible && !busy ) + { + progressBarOption2.rect = subElementRect( SE_ProgressBarLabel, progressBarOption, widget ); + drawControl( CE_ProgressBarLabel, &progressBarOption2, painter, widget ); + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawProgressBarContentsControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return true; + + // copy rect and palette + QRect rect( option->rect ); + const QPalette& palette( option->palette ); + QColor outline( _helper->buttonOutlineColor( palette, false, false ).darker(250) ); + + // get direction + const QStyleOptionProgressBarV2* progressBarOption2( qstyleoption_cast( option ) ); + bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; + bool inverted( progressBarOption2 ? progressBarOption2->invertedAppearance : false ); + bool reverse = horizontal && option->direction == Qt::RightToLeft; + if( inverted ) reverse = !reverse; + + // check if anything is to be drawn + bool busy( ( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ) ); + if( busy ) + { + + qreal progress( _animations->busyIndicatorEngine().value() ); + + QColor color( palette.color( QPalette::Highlight ) ); + _helper->renderProgressBarBusyContents( painter, rect, color, color.darker(), horizontal, reverse, progress ); + + } else { + + QRegion oldClipRegion( painter->clipRegion() ); + if( horizontal ) + { + if( rect.width() < Metrics::ProgressBar_Thickness ) + { + painter->setClipRect( rect, Qt::IntersectClip ); + if( reverse ) rect.setLeft( rect.left() - Metrics::ProgressBar_Thickness + rect.width() ); + else rect.setWidth( Metrics::ProgressBar_Thickness ); + } + + } else { + + if( rect.height() < Metrics::ProgressBar_Thickness ) + { + painter->setClipRect( rect, Qt::IntersectClip ); + if( reverse ) rect.setHeight( Metrics::ProgressBar_Thickness ); + else rect.setTop( rect.top() - Metrics::ProgressBar_Thickness + rect.height() ); + } + + } + + _helper->renderProgressBarContents( painter, rect, palette.color( QPalette::Highlight ), palette.color( QPalette::Highlight ).darker() ); + painter->setClipRegion( oldClipRegion ); + + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawProgressBarGrooveControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + const QPalette& palette( option->palette ); + QColor color( _helper->buttonBackgroundColor( palette, false, false, true ) ); + QColor outline( _helper->buttonOutlineColor( palette, false, false ) ); + _helper->renderProgressBarGroove( painter, option->rect, color, outline ); + return true; + } + + //___________________________________________________________________________________ + bool Style::drawProgressBarLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // cast option and check + const QStyleOptionProgressBar* progressBarOption( qstyleoption_cast( option ) ); + if( !progressBarOption ) return true; + + // get direction and check + const QStyleOptionProgressBarV2* progressBarOption2( qstyleoption_cast( option ) ); + bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; + if( !horizontal ) return true; + + // store rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // store state and direction + const State& state( option->state ); + bool enabled( state & State_Enabled ); + + // define text rect + Qt::Alignment hAlign( ( progressBarOption->textAlignment == Qt::AlignLeft ) ? Qt::AlignHCenter : progressBarOption->textAlignment ); + drawItemText( painter, rect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::WindowText ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawScrollBarSliderControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSlider *sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return true; + + const State& state( option->state ); + bool horizontal( state & State_Horizontal ); + + // copy rect and palette + const QRect& rect( horizontal ? option->rect.adjusted(-1, 4, 0, -4) : option->rect.adjusted(4, -1, -4, 0) ); + const QPalette& palette( option->palette ); + + // define handle rect + QRect handleRect; + + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + + // check focus from relevant parent + const QWidget* parent( scrollBarParent( widget ) ); + bool hasFocus( enabled && parent && parent->hasFocus() ); + + // enable animation state + bool handleActive( sliderOption->activeSubControls & SC_ScrollBarSlider ); + _animations->scrollBarEngine().updateState( widget, AnimationFocus, hasFocus ); + + _animations->scrollBarEngine().updateState( widget, AnimationHover, mouseOver ); + + AnimationMode mode( _animations->scrollBarEngine().animationMode( widget, SC_ScrollBarSlider ) ); + qreal opacity( _animations->scrollBarEngine().opacity( widget, SC_ScrollBarSlider ) ); + QColor color = _helper->scrollBarHandleColor( palette, mouseOver, hasFocus, opacity, mode ); + if (mode == AnimationHover) + opacity = opacity; + else if (mouseOver) + opacity = 1; + else + opacity = 0; + + /* + if( horizontal ) handleRect = centerRect( rect, rect.width(), rect.height() * (0.5 + 0.5 * opacity)); + else handleRect = centerRect( rect, rect.width() * (0.5 + 0.5 * opacity), rect.height() ); + */ + if (horizontal) { + handleRect = rect.adjusted(0, 6, 0, 2); + handleRect.adjust(0, -6.0 * opacity, 0, -2.0 * opacity); + } + else { + handleRect = rect.adjusted(6, 0, 2, 0); + handleRect.adjust(-6.0 * opacity, 0, -2.0 * opacity, 0); + } + + _helper->renderScrollBarHandle( painter, handleRect, color ); + return true; + } + + //___________________________________________________________________________________ + bool Style::drawScrollBarAddLineControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // do nothing if no buttons are defined + if( _addLineButtons == NoButton ) return true; + + // cast option and check + const QStyleOptionSlider* sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return true; + + const State& state( option->state ); + bool horizontal( state & State_Horizontal ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + + // adjust rect, based on number of buttons to be drawn + QRect rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarAddLine ) ); + + QColor color; + QStyleOptionSlider copy( *sliderOption ); + if( _addLineButtons == DoubleButton ) + { + + if( horizontal ) + { + + //Draw the arrows + QSize halfSize( rect.width()/2, rect.height() ); + QRect leftSubButton( rect.topLeft(), halfSize ); + QRect rightSubButton( leftSubButton.topRight() + QPoint( 1, 0 ), halfSize ); + + copy.rect = leftSubButton; + color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarAddLine:SC_ScrollBarSubLine, widget ); + _helper->renderArrow( painter, leftSubButton, color, ArrowLeft ); + + copy.rect = rightSubButton; + color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarSubLine:SC_ScrollBarAddLine, widget ); + _helper->renderArrow( painter, rightSubButton, color, ArrowRight ); + + } else { + + QSize halfSize( rect.width(), rect.height()/2 ); + QRect topSubButton( rect.topLeft(), halfSize ); + QRect botSubButton( topSubButton.bottomLeft() + QPoint( 0, 1 ), halfSize ); + + copy.rect = topSubButton; + color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); + _helper->renderArrow( painter, topSubButton, color, ArrowUp ); + + copy.rect = botSubButton; + color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); + _helper->renderArrow( painter, botSubButton, color, ArrowDown ); + + } + + } else if( _addLineButtons == SingleButton ) { + + copy.rect = rect; + color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); + if( horizontal ) + { + + if( reverseLayout ) _helper->renderArrow( painter, rect, color, ArrowLeft ); + else _helper->renderArrow( painter, rect.translated( 1, 0 ), color, ArrowRight ); + + } else _helper->renderArrow( painter, rect.translated( 0, 1 ), color, ArrowDown ); + + } + + return true; + } + + + //___________________________________________________________________________________ + bool Style::drawScrollBarSubLineControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // do nothing if no buttons are set + if( _subLineButtons == NoButton ) return true; + + // cast option and check + const QStyleOptionSlider* sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return true; + + const State& state( option->state ); + bool horizontal( state & State_Horizontal ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + + // colors + const QPalette& palette( option->palette ); + QColor background( palette.color( QPalette::Window ) ); + + // adjust rect, based on number of buttons to be drawn + QRect rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarSubLine ) ); + + QColor color; + QStyleOptionSlider copy( *sliderOption ); + if( _subLineButtons == DoubleButton ) + { + + if( horizontal ) + { + + //Draw the arrows + QSize halfSize( rect.width()/2, rect.height() ); + QRect leftSubButton( rect.topLeft(), halfSize ); + QRect rightSubButton( leftSubButton.topRight() + QPoint( 1, 0 ), halfSize ); + + copy.rect = leftSubButton; + color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarAddLine:SC_ScrollBarSubLine, widget ); + _helper->renderArrow( painter, leftSubButton, color, ArrowLeft ); + + copy.rect = rightSubButton; + color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarSubLine:SC_ScrollBarAddLine, widget ); + _helper->renderArrow( painter, rightSubButton, color, ArrowRight ); + + } else { + + QSize halfSize( rect.width(), rect.height()/2 ); + QRect topSubButton( rect.topLeft(), halfSize ); + QRect botSubButton( topSubButton.bottomLeft() + QPoint( 0, 1 ), halfSize ); + + copy.rect = topSubButton; + color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); + _helper->renderArrow( painter, topSubButton, color, ArrowUp ); + + copy.rect = botSubButton; + color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); + _helper->renderArrow( painter, botSubButton, color, ArrowDown ); + + } + + } else if( _subLineButtons == SingleButton ) { + + copy.rect = rect; + color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); + if( horizontal ) + { + + if( reverseLayout ) _helper->renderArrow( painter, rect.translated( 1, 0 ), color, ArrowRight ); + else _helper->renderArrow( painter, rect, color, ArrowLeft ); + + } else _helper->renderArrow( painter, rect, color, ArrowUp ); + + } + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawShapedFrameControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionFrameV3* frameOpt = qstyleoption_cast( option ); + if( !frameOpt ) return false; + + switch( frameOpt->frameShape ) + { + + case QFrame::Box: + { + if( option->state & State_Sunken ) return true; + else break; + } + + case QFrame::HLine: + case QFrame::VLine: + { + + const QRect& rect( option->rect ); + QColor color( _helper->separatorColor( option->palette ) ); + bool isVertical( frameOpt->frameShape == QFrame::VLine ); + _helper->renderSeparator( painter, rect, color, isVertical ); + return true; + } + + case QFrame::StyledPanel: + { + + if( isQtQuickControl( option, widget ) ) + { + + // ComboBox popup frame + drawFrameMenuPrimitive( option, painter, widget ); + return true; + + } else break; + } + + default: break; + + } + + return false; + + } + + //___________________________________________________________________________________ + bool Style::drawRubberBandControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + const QPalette& palette( option->palette ); + QRect rect( option->rect ); + + QColor color = palette.color( QPalette::Highlight ); + painter->setPen( Helper::mix( color, palette.color( QPalette::Active, QPalette::WindowText ) ) ); + color.setAlpha( 50 ); + painter->setBrush( color ); + painter->setClipRegion( rect ); + painter->drawRect( rect.adjusted( 0, 0, -1, -1 ) ); + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawHeaderSectionControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool sunken( enabled && ( state & (State_On|State_Sunken) ) ); + + const QStyleOptionHeader* headerOption( qstyleoption_cast( option ) ); + if( !headerOption ) return true; + + bool horizontal( headerOption->orientation == Qt::Horizontal ); + bool isFirst( horizontal && ( headerOption->position == QStyleOptionHeader::Beginning ) ); + bool isCorner( widget && widget->inherits( "QTableCornerButton" ) ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + + // update animation state + _animations->headerViewEngine().updateState( widget, rect.topLeft(), mouseOver ); + bool animated( enabled && _animations->headerViewEngine().isAnimated( widget, rect.topLeft() ) ); + qreal opacity( _animations->headerViewEngine().opacity( widget, rect.topLeft() ) ); + + QBrush color = palette.base(); + + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setBrush( color ); + painter->setPen( Qt::NoPen ); + painter->drawRect( rect ); + + // outline + painter->setBrush( Qt::NoBrush ); + painter->setPen( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.2 ) ); + + if( isCorner ) + { + + if( reverseLayout ) painter->drawPoint( rect.bottomLeft() ); + else painter->drawPoint( rect.bottomRight() ); + + + } else if( horizontal ) { + + painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); + + } else { + + if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() ); + else painter->drawLine( rect.topRight(), rect.bottomRight() ); + + } + + // separators + if( horizontal ) + { + if( headerOption->section != 0 || isFirst ) + { + + if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() - QPoint( 0, 1 ) ); + else painter->drawLine( rect.topRight(), rect.bottomRight() - QPoint( 0, 1 ) ); + + } + + } else { + + if( reverseLayout ) painter->drawLine( rect.bottomLeft()+QPoint( 1, 0 ), rect.bottomRight() ); + else painter->drawLine( rect.bottomLeft(), rect.bottomRight() - QPoint( 1, 0 ) ); + + } + + return true; + + } + + bool Style::drawHeaderLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const + { + if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { + QRect rect = header->rect; + if (!header->icon.isNull()) { + QPixmap pixmap = header->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize), (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); + int pixw = pixmap.width(); + + QRect aligned = alignedRect(header->direction, QFlag(header->iconAlignment), pixmap.size(), rect); + QRect inter = aligned.intersected(rect); + painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width(), inter.height()); + + if (header->direction == Qt::LeftToRight) + rect.setLeft(rect.left() + pixw + 2); + else + rect.setRight(rect.right() - pixw - 2); + } + QFont fnt = painter->font(); + fnt.setBold(true); + painter->setFont(fnt); + QPalette palette(header->palette); + palette.setColor(QPalette::Text, _helper->headerTextColor( palette, header->state ) ); + proxy()->drawItemText(painter, rect, header->textAlignment, palette, (header->state & State_Active), header->text, QPalette::Text); + } + return true; + } + + //___________________________________________________________________________________ + bool Style::drawHeaderEmptyAreaControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { + + // use the same background as in drawHeaderPrimitive + const QRect& rect( option->rect ); + QPalette palette( option->palette ); + + bool horizontal( option->state & QStyle::State_Horizontal ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + + // fill + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setBrush( palette.color( QPalette::Base ) ); + painter->setPen( Qt::NoPen ); + painter->drawRect( rect ); + + // outline + painter->setBrush( Qt::NoBrush ); + painter->setPen( _helper->alphaColor( palette.color( QPalette::ButtonText ), 0.1 ) ); + + if( horizontal ) { + + painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); + + } else { + + if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() ); + else painter->drawLine( rect.topRight(), rect.bottomRight() ); + + } + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawTabBarTabLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + if (const QStyleOptionTab *tab = qstyleoption_cast(option)) { + QStyleOptionTabV3 tabV2(*tab); + QRect tr = tabV2.rect; + bool verticalTabs = tabV2.shape == QTabBar::RoundedEast + || tabV2.shape == QTabBar::RoundedWest + || tabV2.shape == QTabBar::TriangularEast + || tabV2.shape == QTabBar::TriangularWest; + + int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; + if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget)) + alignment |= Qt::TextHideMnemonic; + + if (verticalTabs) { + painter->save(); + int newX, newY, newRot; + if (tabV2.shape == QTabBar::RoundedEast || tabV2.shape == QTabBar::TriangularEast) { + newX = tr.width() + tr.x(); + newY = tr.y(); + newRot = 90; + } else { + newX = tr.x(); + newY = tr.y() + tr.height(); + newRot = -90; + } + QTransform m = QTransform::fromTranslate(newX, newY); + m.rotate(newRot); + painter->setTransform(m, true); + } + QRect iconRect; + tabLayout(&tabV2, widget, &tr, &iconRect, proxy()); + tr = proxy()->subElementRect(SE_TabBarTabText, option, widget); //we compute tr twice because the style may override subElementRect + + if (!tabV2.icon.isNull()) { + QPixmap tabIcon = tabV2.icon.pixmap(tabV2.iconSize, + (tabV2.state & State_Enabled) ? QIcon::Normal + : QIcon::Disabled, + (tabV2.state & State_Selected) ? QIcon::On + : QIcon::Off); + painter->drawPixmap(iconRect.x(), iconRect.y(), tabIcon); + } + + QFont font = painter->font(); + font.setBold(true); + painter->setFont(font); + if (!(tabV2.state & State_Enabled)) { + if (tabV2.state & State_Selected) + painter->setPen(Helper::mix(option->palette.brush(QPalette::Text).color(), option->palette.brush(QPalette::Window).color(), 0.3)); + else + painter->setPen(Helper::mix(option->palette.brush(QPalette::Text).color(), option->palette.brush(QPalette::Window).color(), 0.4)); + } + else { + if (tabV2.state & State_Selected) + painter->setPen(option->palette.brush(QPalette::WindowText).color()); + else if (tabV2.state & State_Active && tabV2.state & State_MouseOver) + painter->setPen(Helper::mix(option->palette.brush(QPalette::Dark).color(), option->palette.brush(QPalette::Text).color(), 0.7)); + else + painter->setPen(Helper::mix(option->palette.brush(QPalette::Dark).color(), option->palette.brush(QPalette::Text).color(), 0.6)); + } + + proxy()->drawItemText(painter, tr, alignment, tab->palette, tab->state & State_Enabled, tab->text, QPalette::NoRole); + + if (verticalTabs) + painter->restore(); + + if (tabV2.state & State_HasFocus) { + int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth); + + int x1, x2; + x1 = tabV2.rect.left(); + x2 = tabV2.rect.right() - 1; + + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*tab); + fropt.rect.setRect(x1 + 1 + OFFSET, tabV2.rect.y() + OFFSET, + x2 - x1 - 2*OFFSET, tabV2.rect.height() - 2*OFFSET); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + + // store rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // check focus + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool selected( state & State_Selected ); + bool hasFocus( enabled && selected && (state & State_HasFocus) ); + + // update mouse over animation state + _animations->tabBarEngine().updateState( widget, rect.topLeft(), AnimationFocus, hasFocus ); + bool animated( enabled && selected && _animations->tabBarEngine().isAnimated( widget, rect.topLeft(), AnimationFocus ) ); + qreal opacity( _animations->tabBarEngine().opacity( widget, rect.topLeft(), AnimationFocus ) ); + + if( !( hasFocus || animated ) ) return true; + + // code is copied from QCommonStyle, but adds focus + // cast option and check + const QStyleOptionTab *tabOption( qstyleoption_cast(option) ); + if( !tabOption || tabOption->text.isEmpty() ) return true; + + // tab option rect + bool verticalTabs( isVerticalTab( tabOption ) ); + int textFlags( Qt::AlignCenter | _mnemonics->textFlags() ); + + // text rect + QRect textRect( subElementRect(SE_TabBarTabText, option, widget) ); + + if( verticalTabs ) + { + + // properly rotate painter + painter->save(); + int newX, newY, newRot; + if( tabOption->shape == QTabBar::RoundedEast || tabOption->shape == QTabBar::TriangularEast) + { + + newX = rect.width() + rect.x(); + newY = rect.y(); + newRot = 90; + + } else { + + newX = rect.x(); + newY = rect.y() + rect.height(); + newRot = -90; + + } + + QTransform transform; + transform.translate( newX, newY ); + transform.rotate(newRot); + painter->setTransform( transform, true ); + + } + + // adjust text rect based on font metrics + textRect = option->fontMetrics.boundingRect( textRect, textFlags, tabOption->text ); + + if( verticalTabs ) painter->restore(); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawTabBarTabShapeControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + const QStyleOptionTab* tabOption( qstyleoption_cast( option ) ); + if( !tabOption ) return true; + + // palette and state + const QPalette& palette( option->palette ); + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool selected( state & State_Selected ); + bool mouseOver( (state & State_Active) && !selected && ( state & State_MouseOver ) && enabled ); + + // check if tab is being dragged + bool isDragged( widget && selected && painter->device() != widget ); + bool isLocked( widget && _tabBarData->isLocked( widget ) ); + + // store rect + QRect rect( option->rect ); + + // update mouse over animation state + _animations->tabBarEngine().updateState( widget, rect.topLeft(), AnimationHover, mouseOver ); + bool animated( enabled && !selected && _animations->tabBarEngine().isAnimated( widget, rect.topLeft(), AnimationHover ) ); + qreal opacity( _animations->tabBarEngine().opacity( widget, rect.topLeft(), AnimationHover ) ); + + // lock state + if( selected && widget && isDragged ) _tabBarData->lock( widget ); + else if( widget && selected && _tabBarData->isLocked( widget ) ) _tabBarData->release(); + + // tab position + const QStyleOptionTab::TabPosition& position = tabOption->position; + bool isSingle( position == QStyleOptionTab::OnlyOneTab ); + bool isQtQuickControl( this->isQtQuickControl( option, widget ) ); + bool isFirst( isSingle || position == QStyleOptionTab::Beginning ); + bool isLast( isSingle || position == QStyleOptionTab::End ); + bool isLeftOfSelected( !isLocked && tabOption->selectedPosition == QStyleOptionTab::NextIsSelected ); + bool isRightOfSelected( !isLocked && tabOption->selectedPosition == QStyleOptionTab::PreviousIsSelected ); + + // true if widget is aligned to the frame + // need to check for 'isRightOfSelected' because for some reason the isFirst flag is set when active tab is being moved + isFirst &= !isRightOfSelected; + isLast &= !isLeftOfSelected; + + // swap state based on reverse layout, so that they become layout independent + bool reverseLayout( option->direction == Qt::RightToLeft ); + bool verticalTabs( isVerticalTab( tabOption ) ); + if( reverseLayout && !verticalTabs ) + { + qSwap( isFirst, isLast ); + qSwap( isLeftOfSelected, isRightOfSelected ); + } + + // overlap + // for QtQuickControls, ovelap is already accounted of in the option. Unlike in the qwidget case + int overlap( isQtQuickControl ? 0:Metrics::TabBar_TabOverlap ); + + // adjust rect and define corners based on tabbar orientation + Corners corners; + switch( tabOption->shape ) + { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + corners = CornerTopLeft|CornerTopRight; + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + corners = CornerBottomLeft|CornerBottomRight; + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + corners = CornerTopLeft|CornerBottomLeft; + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + corners = CornerTopRight|CornerBottomRight; + break; + + default: break; + } + + // underline + QColor underline( enabled && selected ? _helper->focusColor( palette ) : selected || mouseOver ? option->palette.color(QPalette::Window).darker() : Qt::transparent ); + + // outline + QColor outline = QColor(); + if (selected && widget && widget->property("movable").toBool()) { + outline = _helper->frameOutlineColor( palette ); + } + + // background + QColor background = _helper->tabBarColor( option->palette, option->state ); + + // render + QRegion oldRegion( painter->clipRegion() ); + painter->setClipRect( option->rect, Qt::IntersectClip ); + _helper->renderTabBarTab( painter, rect, background, underline, outline, corners, widget && widget->property("movable").toBool() ); + painter->setClipRegion( oldRegion ); + + return true; + + } + + //___________________________________________________________________________________ + bool Style::drawToolBoxTabLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // rendering is similar to drawPushButtonLabelControl + // cast option and check + const QStyleOptionToolBox* toolBoxOption( qstyleoption_cast( option ) ); + if( !toolBoxOption ) return true; + + // copy palette + const QPalette& palette( option->palette ); + + const State& state( option->state ); + bool enabled( state & State_Enabled ); + + // text alignment + int textFlags( _mnemonics->textFlags() | Qt::AlignCenter ); + + // contents rect + QRect rect( subElementRect( SE_ToolBoxTabContents, option, widget ) ); + + // store icon size + int iconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); + + // find contents size and rect + QRect contentsRect( rect ); + QSize contentsSize; + if( !toolBoxOption->text.isEmpty() ) + { + contentsSize = option->fontMetrics.size( _mnemonics->textFlags(), toolBoxOption->text ); + if( !toolBoxOption->icon.isNull() ) contentsSize.rwidth() += Metrics::ToolBox_TabItemSpacing; + } + + // icon size + if( !toolBoxOption->icon.isNull() ) + { + + contentsSize.setHeight( qMax( contentsSize.height(), iconSize ) ); + contentsSize.rwidth() += iconSize; + + } + + // adjust contents rect + contentsRect = centerRect( contentsRect, contentsSize ); + + // render icon + if( !toolBoxOption->icon.isNull() ) + { + + // icon rect + QRect iconRect; + if( toolBoxOption->text.isEmpty() ) iconRect = centerRect( contentsRect, iconSize, iconSize ); + else { + + iconRect = contentsRect; + iconRect.setWidth( iconSize ); + iconRect = centerRect( iconRect, iconSize, iconSize ); + contentsRect.setLeft( iconRect.right() + Metrics::ToolBox_TabItemSpacing + 1 ); + + } + + iconRect = visualRect( option, iconRect ); + const QIcon::Mode mode( enabled ? QIcon::Normal : QIcon::Disabled ); + QPixmap pixmap( toolBoxOption->icon.pixmap( iconSize, mode ) ); + drawItemPixmap( painter, iconRect, textFlags, pixmap ); + + } + + // render text + if( !toolBoxOption->text.isEmpty() ) + { + contentsRect = visualRect( option, contentsRect ); + drawItemText( painter, contentsRect, textFlags, palette, enabled, toolBoxOption->text, QPalette::WindowText ); + } + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawToolBoxTabShapeControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionToolBox* toolBoxOption( qstyleoption_cast( option ) ); + if( !toolBoxOption ) return true; + + // copy rect and palette + const QRect& rect( option->rect ); + QRect tabRect( toolBoxTabContentsRect( option, widget ) ); + + /* + * important: option returns the wrong palette. + * we use the widget palette instead, when set + */ + QPalette palette( widget ? widget->palette() : option->palette ); + + // store flags + const State& flags( option->state ); + bool enabled( flags&State_Enabled ); + bool selected( flags&State_Selected ); + bool mouseOver( (flags & State_Active) && enabled && !selected && ( flags&State_MouseOver ) ); + + // update animation state + /* + * the proper widget ( the toolbox tab ) is not passed as argument by Qt. + * What is passed is the toolbox directly. To implement animations properly, + *the painter->device() is used instead + */ + bool isAnimated( false ); + qreal opacity( AnimationData::OpacityInvalid ); + QPaintDevice* device = painter->device(); + if( enabled && device ) + { + _animations->toolBoxEngine().updateState( device, mouseOver ); + isAnimated = _animations->toolBoxEngine().isAnimated( device ); + opacity = _animations->toolBoxEngine().opacity( device ); + } + + // color + QColor outline; + if( selected ) outline = _helper->focusColor( palette ); + else outline = _helper->frameOutlineColor( palette, mouseOver, false, opacity, isAnimated ? AnimationHover:AnimationNone ); + + // render + _helper->renderToolBoxFrame( painter, rect, tabRect.width(), outline ); + + return true; + } + + //___________________________________________________________________________________ + bool Style::drawDockWidgetTitleControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionDockWidget* dockWidgetOption = ::qstyleoption_cast( option ); + if( !dockWidgetOption ) return true; + + const QPalette& palette( option->palette ); + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool reverseLayout( option->direction == Qt::RightToLeft ); + + // cast to v2 to check vertical bar + const QStyleOptionDockWidgetV2 *v2 = qstyleoption_cast( option ); + bool verticalTitleBar( v2 ? v2->verticalTitleBar : false ); + + QRect buttonRect( subElementRect( dockWidgetOption->floatable ? SE_DockWidgetFloatButton : SE_DockWidgetCloseButton, option, widget ) ); + + // get rectangle and adjust to properly accounts for buttons + QRect rect( insideMargin( dockWidgetOption->rect, Metrics::Frame_FrameWidth ) ); + if( verticalTitleBar ) + { + + if( buttonRect.isValid() ) rect.setTop( buttonRect.bottom() + 1 ); + + } else if( reverseLayout ) { + + if( buttonRect.isValid() ) rect.setLeft( buttonRect.right() + 1 ); + rect.adjust( 0, 0, -4, 0 ); + + } else { + + if( buttonRect.isValid() ) rect.setRight( buttonRect.left() - 1 ); + rect.adjust( 4, 0, 0, 0 ); + + } + + QString title( dockWidgetOption->title ); + int titleWidth = dockWidgetOption->fontMetrics.size( _mnemonics->textFlags(), title ).width(); + int width = verticalTitleBar ? rect.height() : rect.width(); + if( width < titleWidth ) title = dockWidgetOption->fontMetrics.elidedText( title, Qt::ElideMiddle, width, Qt::TextShowMnemonic ); + + if( verticalTitleBar ) + { + + QSize size = rect.size(); + size.transpose(); + rect.setSize( size ); + + painter->save(); + painter->translate( rect.left(), rect.top() + rect.width() ); + painter->rotate( -90 ); + painter->translate( -rect.left(), -rect.top() ); + drawItemText( painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText ); + painter->restore(); + + + } else { + + drawItemText( painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText ); + + } + + return true; + + + } + + //______________________________________________________________ + bool Style::drawGroupBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(option)) + { + painter->save(); + + QRect textRect = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget); + QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxCheckBox, widget); + + // Draw title + if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) + { + QColor textColor = groupBox->textColor; + if (textColor.isValid()) + { + painter->setPen(textColor); + } + int alignment = int(groupBox->textAlignment); + if (!styleHint(QStyle::SH_UnderlineShortcut, option, widget)) + { + alignment |= Qt::TextHideMnemonic; + } + QFont font = painter->font(); + font.setBold(true); + painter->setFont(font); + painter->drawText(textRect, Qt::TextShowMnemonic | Qt::AlignLeft| Qt::AlignVCenter |alignment, groupBox->text); + } + if (groupBox->subControls & SC_GroupBoxCheckBox) + { + QStyleOptionButton box; + box.QStyleOption::operator=(*groupBox); + box.rect = checkBoxRect; + proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget); + } + painter->restore(); + } + + return true; + + } + + //______________________________________________________________ + bool Style::drawToolButtonComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionToolButton* toolButtonOption( qstyleoption_cast( option ) ); + if( !toolButtonOption ) return true; + + // need to alter palette for focused buttons + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && (option->state & State_MouseOver) ); + bool hasFocus( enabled && (option->state & State_HasFocus) ); + bool sunken( state & (State_On | State_Sunken) ); + bool flat( state & State_AutoRaise ); + + // update animation state + // pressed takes precedence over mouse + + qreal mouseOpacity = 0.0; + qreal pressedOpacity = 0.0; + + _animations->widgetStateEngine().updateState( widget, AnimationPressed, sunken); + _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); + + AnimationMode mode ( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); + + if ( mode == AnimationPressed ) { + pressedOpacity = _animations->widgetStateEngine().buttonOpacity( widget ); + } + else if ( sunken ) { + pressedOpacity = 1.0; + } + else if ( mode == AnimationHover ) { + mouseOpacity = _animations->widgetStateEngine().buttonOpacity( widget ); + } + else if (mouseOver) + mouseOpacity = 1.0; + + // detect buttons in tabbar, for which special rendering is needed + bool isDockWidgetTitleButton( widget && widget->inherits( "QDockWidgetTitleButton" ) ); + bool inTabBar( widget && qobject_cast( widget->parentWidget() ) ); + bool isMenuTitle( this->isMenuTitle( widget ) ); + if( isMenuTitle ) + { + // copy option to adust state, and set font as not-bold + QStyleOptionToolButton copy( *toolButtonOption ); + copy.font.setBold( false ); + copy.state = State_Enabled; + + // render + renderMenuTitle( ©, painter, widget ); + return true; + } + + // copy option and alter palette + QStyleOptionToolButton copy( *toolButtonOption ); + + if( isDockWidgetTitleButton ) + { + + // cast to abstract button + // adjust state to have correct icon rendered + const QAbstractButton* button( qobject_cast( widget ) ); + if( button->isChecked() || button->isDown() ) { + copy.state |= State_Enabled | State_On | State_Sunken; + } + if ( button->underMouse() ) { + copy.state |= State_Enabled | State_MouseOver | State_Active; + } + + } + + bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); + const bool hasInlineIndicator( + toolButtonOption->features&QStyleOptionToolButton::HasMenu + && toolButtonOption->features&QStyleOptionToolButton::PopupDelay + && !hasPopupMenu ); + + QRect buttonRect( subControlRect( CC_ToolButton, option, SC_ToolButton, widget ) ); + QRect menuRect( subControlRect( CC_ToolButton, option, SC_ToolButtonMenu, widget ) ); + + // frame + if( toolButtonOption->subControls & SC_ToolButton || isDockWidgetTitleButton ) + { + copy.rect = buttonRect; + if( inTabBar ) { + QRect rect(option->rect); + QColor background( _helper->mix(option->palette.window().color(), option->palette.shadow().color(), 0.15) ); + background = _helper->mix(background, Qt::white, 0.2 * mouseOpacity); + background = _helper->mix(background, Qt::black, 0.15 * pressedOpacity); + QColor outline ( _helper->frameOutlineColor(option->palette) ); + painter->setPen(background); + painter->setBrush(background); + switch (toolButtonOption->arrowType) { + case Qt::UpArrow: painter->drawRect(rect.adjusted(1, 1, -2, -1)); break; + case Qt::DownArrow: painter->drawRect(rect.adjusted(1, 0, -2, -2)); break; + case Qt::LeftArrow: painter->drawRect(rect.adjusted(1, 1, -1, -2)); break; + case Qt::RightArrow: painter->drawRect(rect.adjusted(0, 1, -2, -2)); break; + } + painter->setPen(outline); + switch (toolButtonOption->arrowType) { + case Qt::DownArrow: painter->drawLine(rect.bottomLeft(), rect.bottomRight()); break; + case Qt::RightArrow: painter->drawLine(rect.topRight(), rect.bottomRight()); break; + } + switch (toolButtonOption->arrowType) { + case Qt::UpArrow: + case Qt::DownArrow: + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + break; + case Qt::LeftArrow: + case Qt::RightArrow: + painter->drawLine(rect.topLeft(), rect.topRight()); + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + break; + } + } + else if (sunken && hasPopupMenu && !(toolButtonOption->activeSubControls&SC_ToolButton)) { + // Only menu button is active. so draw left hand side od button raised + QStyleOptionToolButton btn( copy ); + btn.state|=State_Raised; + btn.state&=~State_Sunken; + btn.state&=~State_AutoRaise; + drawPrimitive( PE_PanelButtonTool, &btn, painter, widget); + } + else { + drawPrimitive( PE_PanelButtonTool, ©, painter, widget); + } + } + + // arrow + if( hasPopupMenu ) + { + + copy.rect = menuRect; + if( !flat || mouseOver || sunken ) drawPrimitive( PE_IndicatorButtonDropDown, ©, painter, widget ); + + drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); + + } else if( hasInlineIndicator ) { + + copy.rect = menuRect; + + drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); + + } + + // contents + { + + // restore state + copy.state = state; + + // define contents rect + QRect contentsRect( buttonRect ); + + // detect dock widget title button + // for dockwidget title buttons, do not take out margins, so that icon do not get scaled down + if( isDockWidgetTitleButton ) + { + + // cast to abstract button + // adjust state to have correct icon rendered + const QAbstractButton* button( qobject_cast( widget ) ); + if( button->isChecked() || button->isDown() ) { + copy.state |= State_Enabled | State_On | State_Sunken; + } + if ( button->underMouse() ) { + copy.state |= State_Enabled | State_MouseOver | State_Active; + } + + } else if( !inTabBar && hasInlineIndicator ) { + + int marginWidth( flat ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); + contentsRect = insideMargin( contentsRect, marginWidth, 0 ); + contentsRect.setRight( contentsRect.right() - Metrics::ToolButton_InlineIndicatorWidth ); + contentsRect = visualRect( option, contentsRect ); + + } + + copy.rect = contentsRect; + + // render + drawControl( CE_ToolButtonLabel, ©, painter, widget); + + } + + return true; + } + + //______________________________________________________________ + bool Style::drawComboBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionComboBox* comboBoxOption( qstyleoption_cast( option ) ); + if( !comboBoxOption ) return true; + + // rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + bool editable( comboBoxOption->editable ); + bool arrowActive( comboBoxOption->activeSubControls & SC_ComboBoxArrow ); + bool flat( !comboBoxOption->frame ); + bool mouseOver; + bool hasFocus; + bool sunken; + if (editable) + { + + mouseOver = windowActive && arrowActive && enabled && ( state & State_MouseOver ); + hasFocus = enabled && ( state & ( State_HasFocus | State_Sunken ) ); + sunken = arrowActive && enabled && ( state & (State_On|State_Sunken) ); + + } else { + + mouseOver = windowActive && enabled && ( state & State_MouseOver ); + hasFocus = enabled && ( state & ( State_HasFocus | State_Sunken ) ); + sunken = enabled && ( state & (State_On|State_Sunken) ); + + } + + // update animation state + // sunken takes precedence over hover that takes precedence over focus + _animations->inputWidgetEngine().updateState( widget, AnimationPressed, sunken ); + _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver ); + _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); + + // frame + if( option->subControls & SC_ComboBoxFrame ) + { + + if( editable ) + { + + flat |= ( rect.height() <= 2*Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth ); + if( flat ) + { + + QColor background( palette.color( QPalette::Base ) ); + + painter->setBrush( background ); + painter->setPen( Qt::NoPen ); + painter->drawRect( rect ); + + } else { + + AnimationMode mode( _animations->inputWidgetEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->inputWidgetEngine().buttonOpacity( widget ) ); + + QColor shadow( _helper->shadowColor( palette ) ); + QColor outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + QColor background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + + _helper->renderFlatButtonFrame( painter, subControlRect( CC_ComboBox, option, SC_ComboBoxArrow, widget), background, outline, shadow, hasFocus, sunken, mouseOver, enabled && windowActive ); + + QStyleOptionComplex tmpOpt(*option); + tmpOpt.rect.setWidth(tmpOpt.rect.width() - subControlRect( CC_ComboBox, option, SC_ComboBoxArrow, widget).width() + 3); + + drawPrimitive( PE_FrameLineEdit, &tmpOpt, painter, widget ); + + } + + } else { + + AnimationMode mode( _animations->inputWidgetEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->inputWidgetEngine().buttonOpacity( widget ) ); + + if( flat ) { + + // define colors and render + QColor color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + _helper->renderToolButtonFrame( painter, rect, color, sunken ); + + } else { + + // define colors + QColor shadow( _helper->shadowColor( palette ) ); + QColor outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + QColor background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); + + // render + _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken, mouseOver, enabled && windowActive ); + + if (hasFocus) + { + + QStyleOption copy(*option); + copy.rect.adjust(4, 4, -4, -4); + drawPrimitive( PE_FrameFocusRect, ©, painter, widget); + + } + + } + + } + + } + + // arrow + if( option->subControls & SC_ComboBoxArrow ) + { + + // detect empty comboboxes + const QComboBox* comboBox = qobject_cast( widget ); + bool empty( comboBox && !comboBox->count() ); + + // arrow color + QColor arrowColor = _helper->arrowColor( palette, QPalette::ButtonText ); + + // arrow rect + QRect arrowRect( subControlRect( CC_ComboBox, option, SC_ComboBoxArrow, widget ) ); + + // render + _helper->renderArrow( painter, arrowRect, arrowColor, ArrowDown ); + + } + + return true; + + } + + //______________________________________________________________ + bool Style::drawSpinBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + const QStyleOptionSpinBox *spinBoxOption( qstyleoption_cast( option ) ); + if( !spinBoxOption ) return true; + + // store palette and rect + const QPalette& palette( option->palette ); + const QRect& rect( option->rect ); + + + if( option->subControls & SC_SpinBoxFrame ) + { + + // detect flat spinboxes + bool flat( !spinBoxOption->frame ); + flat |= ( rect.height() < 2*Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth ); + if( flat ) + { + + QColor background( palette.color( QPalette::Base ) ); + + painter->setBrush( background ); + painter->setPen( Qt::NoPen ); + painter->drawRect( rect ); + + } else { + + drawPrimitive( PE_FrameLineEdit, option, painter, widget ); + + } + + } + + if( option->subControls & SC_SpinBoxUp ) renderSpinBoxArrow( SC_SpinBoxUp, spinBoxOption, painter, widget ); + if( option->subControls & SC_SpinBoxDown ) renderSpinBoxArrow( SC_SpinBoxDown, spinBoxOption, painter, widget ); + + return true; + + } + + //______________________________________________________________ + bool Style::drawSliderComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSlider *sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return true; + + // copy rect and palette + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + + // copy state + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool windowActive( state & State_Active ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool hasFocus( enabled && ( state & State_HasFocus ) ); + bool horizontal( sliderOption->orientation == Qt::Horizontal ); + Side tickSide { SideNone }; + if (horizontal && sliderOption->tickPosition == QSlider::TicksAbove) tickSide = (Side) ((int) tickSide | (int) SideTop); + if (horizontal && sliderOption->tickPosition == QSlider::TicksBelow) tickSide = (Side) ((int) tickSide | (int) SideBottom); + if (!horizontal && sliderOption->tickPosition == QSlider::TicksLeft) tickSide = (Side) ((int) tickSide | (int) SideLeft); + if (!horizontal && sliderOption->tickPosition == QSlider::TicksRight) tickSide = (Side) ((int) tickSide | (int) SideRight); + + // tickmarks + if( StyleConfigData::sliderDrawTickMarks() && ( sliderOption->subControls & SC_SliderTickmarks ) ) + { + bool upsideDown( sliderOption->upsideDown ); + int tickPosition( sliderOption->tickPosition ); + int available( pixelMetric( PM_SliderSpaceAvailable, option, widget ) ); + int interval = sliderOption->tickInterval; + if( interval < 1 ) interval = sliderOption->pageStep; + if( interval >= 1 ) + { + int fudge( pixelMetric( PM_SliderLength, option, widget ) / 2 ); + int current( sliderOption->minimum ); + + // store tick lines + QRect grooveRect( subControlRect( CC_Slider, sliderOption, SC_SliderGroove, widget ) ); + QList tickLines; + if( horizontal ) + { + + if( tickPosition & QSlider::TicksAbove ) tickLines.append( QLine( rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength ) ); + if( tickPosition & QSlider::TicksBelow ) tickLines.append( QLine( rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength ) ); + + } else { + + if( tickPosition & QSlider::TicksAbove ) tickLines.append( QLine( grooveRect.left() - Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.left() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength, rect.top() ) ); + if( tickPosition & QSlider::TicksBelow ) tickLines.append( QLine( grooveRect.right() + Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.right() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength, rect.top() ) ); + + } + + // colors + QColor base( _helper->separatorColor( palette ) ); + QColor highlight( palette.color( QPalette::Highlight ) ); + + while( current <= sliderOption->maximum ) + { + + // adjust color + QColor color( (enabled && current <= sliderOption->sliderPosition) ? highlight:base ); + painter->setPen( color ); + + // calculate positions and draw lines + int position( sliderPositionFromValue( sliderOption->minimum, sliderOption->maximum, current, available ) + fudge ); + foreach( const QLine& tickLine, tickLines ) + { + if( horizontal ) painter->drawLine( tickLine.translated( upsideDown ? (rect.width() - position) : position, 0 ) ); + else painter->drawLine( tickLine.translated( 0, upsideDown ? (rect.height() - position):position ) ); + } + + // go to next position + current += interval; + + } + } + } + + // groove + if( sliderOption->subControls & SC_SliderGroove ) + { + + if ( hasFocus ) { + + QRect focusRect = proxy()->subElementRect( SE_SliderFocusRect, option, widget ); + + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*option); + fropt.rect = focusRect; + proxy()->drawPrimitive( PE_FrameFocusRect, &fropt, painter, widget ); + + } + + // retrieve groove rect + QRect grooveRect( subControlRect( CC_Slider, sliderOption, SC_SliderGroove, widget ) ); + + // base color + QColor grooveColor( _helper->buttonBackgroundColor( palette, false, false, true ) ); + QColor outline( _helper->buttonOutlineColor( palette, false, false ) ); + QColor highlightColor( palette.color( QPalette::Highlight ) ); + QColor highlightOutline( _helper->buttonOutlineColor( palette, false, false ).darker(250) ); + + if( !enabled ) _helper->renderProgressBarGroove( painter, grooveRect, grooveColor, outline ); + else { + + bool upsideDown( sliderOption->upsideDown ); + + // handle rect + QRect handleRect( subControlRect( CC_Slider, sliderOption, SC_SliderHandle, widget ) ); + + if( sliderOption->orientation == Qt::Horizontal ) + { + + QRect leftRect( grooveRect ); + QRect rightRect( grooveRect ); + leftRect.setRight( handleRect.right() - Metrics::Slider_ControlThickness/2 ); + rightRect.setLeft( handleRect.left() + Metrics::Slider_ControlThickness/2 ); + + if (upsideDown) { + + _helper->renderProgressBarGroove( painter, leftRect, grooveColor, outline ); + _helper->renderProgressBarContents( painter, rightRect, highlightColor, highlightOutline ); + + } + else { + + _helper->renderProgressBarContents( painter, leftRect, highlightColor, highlightOutline ); + _helper->renderProgressBarGroove( painter, rightRect, grooveColor, outline ); + + } + + } else { + + QRect topRect( grooveRect ); + topRect.setBottom( handleRect.bottom() - Metrics::Slider_ControlThickness/2 ); + QRect bottomRect( grooveRect ); + bottomRect.setTop( handleRect.top() + Metrics::Slider_ControlThickness/2 ); + + if (upsideDown) { + + _helper->renderProgressBarGroove( painter, topRect, grooveColor, outline ); + _helper->renderProgressBarContents( painter, bottomRect, highlightColor, highlightOutline ); + + } + else { + + _helper->renderProgressBarContents( painter, topRect, highlightColor, highlightOutline ); + _helper->renderProgressBarGroove( painter, bottomRect, grooveColor, outline ); + + } + + } + + } + + } + + // handle + if( sliderOption->subControls & SC_SliderHandle ) + { + + // get rect and center + QRect handleRect( subControlRect( CC_Slider, sliderOption, SC_SliderHandle, widget ) ); + + // handle state + bool handleActive( sliderOption->activeSubControls & SC_SliderHandle ); + bool sunken( state & (State_On|State_Sunken) ); + + // animation state + _animations->widgetStateEngine().updateState( widget, AnimationHover, handleActive && mouseOver ); + _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); + AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); + + // define colors + QColor background( _helper->buttonBackgroundColor( palette, mouseOver, false, sunken, opacity, mode ) ); + QColor outline( _helper->sliderOutlineColor( palette, handleActive && mouseOver, hasFocus, opacity, mode ) ); + QColor shadow( _helper->shadowColor( palette ) ); + + // render + _helper->renderSliderHandle( painter, handleRect, background, outline, shadow, sunken, enabled && windowActive, tickSide ); + + } + + return true; + } + + //______________________________________________________________ + bool Style::drawDialComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionSlider *sliderOption( qstyleoption_cast( option ) ); + if( !sliderOption ) return true; + + const QPalette& palette( option->palette ); + const State& state( option->state ); + bool enabled( state & State_Enabled ); + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + bool hasFocus( enabled && ( state & State_HasFocus ) ); + bool horizontal( sliderOption->orientation == Qt::Horizontal ); + Side tickSide { SideNone }; + if (horizontal && sliderOption->tickPosition == QSlider::TicksAbove) tickSide = (Side) ((int) tickSide | (int) SideTop); + if (horizontal && sliderOption->tickPosition == QSlider::TicksBelow) tickSide = (Side) ((int) tickSide | (int) SideBottom); + if (!horizontal && sliderOption->tickPosition == QSlider::TicksLeft) tickSide = (Side) ((int) tickSide | (int) SideLeft); + if (!horizontal && sliderOption->tickPosition == QSlider::TicksRight) tickSide = (Side) ((int) tickSide | (int) SideRight); + + // do not render tickmarks + if( sliderOption->subControls & SC_DialTickmarks ) + {} + + // groove + if( sliderOption->subControls & SC_DialGroove ) + { + + // groove rect + QRect grooveRect( subControlRect( CC_Dial, sliderOption, SC_SliderGroove, widget ) ); + + // groove + QColor grooveColor( Helper::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.3 ) ); + + // render groove + _helper->renderDialGroove( painter, grooveRect, grooveColor ); + + if( enabled ) + { + + // highlight + QColor highlight( palette.color( QPalette::Highlight ) ); + + // angles + qreal first( dialAngle( sliderOption, sliderOption->minimum ) ); + qreal second( dialAngle( sliderOption, sliderOption->sliderPosition ) ); + + // render contents + _helper->renderDialContents( painter, grooveRect, highlight, first, second ); + + } + + } + + // handle + if( sliderOption->subControls & SC_DialHandle ) + { + + // get handle rect + QRect handleRect( subControlRect( CC_Dial, sliderOption, SC_DialHandle, widget ) ); + handleRect = centerRect( handleRect, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness ); + + // handle state + bool handleActive( mouseOver && handleRect.contains( _animations->dialEngine().position( widget ) ) ); + bool sunken( state & (State_On|State_Sunken) ); + + // animation state + _animations->dialEngine().setHandleRect( widget, handleRect ); + _animations->dialEngine().updateState( widget, AnimationHover, handleActive && mouseOver ); + _animations->dialEngine().updateState( widget, AnimationFocus, hasFocus ); + AnimationMode mode( _animations->dialEngine().buttonAnimationMode( widget ) ); + qreal opacity( _animations->dialEngine().buttonOpacity( widget ) ); + + // define colors + QColor background( palette.color( QPalette::Button ) ); + QColor outline( _helper->sliderOutlineColor( palette, handleActive && mouseOver, hasFocus, opacity, mode ) ); + QColor shadow( _helper->shadowColor( palette ) ); + + // render + qreal angle = 270 - 180 * dialAngle( sliderOption, sliderOption->sliderPosition ) / M_PI; + _helper->renderSliderHandle( painter, handleRect, background, outline, shadow, sunken, enabled, tickSide, angle ); + + } + + return true; + } + + //______________________________________________________________ + bool Style::drawScrollBarComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + //the animation for QStyle::SC_ScrollBarGroove is special: it will animate + //the opacity of everything else as well, included slider and arrows + bool enabled( option->state & State_Enabled ); + qreal opacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); + bool animated( StyleConfigData::scrollBarShowOnMouseOver() && _animations->scrollBarEngine().isAnimated( widget, AnimationHover, QStyle::SC_ScrollBarGroove ) ); + bool mouseOver( (option->state & State_Active) && option->state & State_MouseOver ); + + if( opacity == AnimationData::OpacityInvalid ) opacity = 1; + + // render full groove directly, rather than using the addPage and subPage control element methods + if( (mouseOver || animated) && option->subControls & SC_ScrollBarGroove ) + { + // retrieve groove rectangle + QRect grooveRect( subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); + + const QPalette& palette( option->palette ); + QColor color( _helper->alphaColor( palette.color( QPalette::Window ).darker(), (animated ? 0.3 * opacity : 0.3) ) ); + const State& state( option->state ); + bool horizontal( state & State_Horizontal ); + + if( horizontal ) grooveRect = centerRect( grooveRect, grooveRect.width(), Metrics::ScrollBar_SliderWidth ); + else grooveRect = centerRect( grooveRect, Metrics::ScrollBar_SliderWidth, grooveRect.height() ); + + // render + if (enabled) { + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRect(option->rect); + } + } + + // call base class primitive + //ParentStyleClass::drawComplexControl( CC_ScrollBar, option, painter, widget ); + if (const QStyleOptionSlider *scrollbar = qstyleoption_cast(option)) { + + QStyleOptionSlider newScrollbar = *scrollbar; + State saveFlags = scrollbar->state; + + if (scrollbar->subControls & SC_ScrollBarSlider) { + newScrollbar.rect = scrollbar->rect; + newScrollbar.state = saveFlags; + newScrollbar.rect = proxy()->subControlRect( CC_ScrollBar, &newScrollbar, SC_ScrollBarSlider, widget); + if (newScrollbar.rect.isValid()) { + proxy()->drawControl(CE_ScrollBarSlider, &newScrollbar, painter, widget); + + if (scrollbar->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(newScrollbar); + fropt.rect.setRect(newScrollbar.rect.x() + 2, newScrollbar.rect.y() + 2, + newScrollbar.rect.width() - 5, + newScrollbar.rect.height() - 5); + proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + } + } + + return true; + } + + //______________________________________________________________ + bool Style::drawTitleBarComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const + { + + // cast option and check + const QStyleOptionTitleBar *titleBarOption( qstyleoption_cast( option ) ); + if( !titleBarOption ) return true; + + // store palette and rect + QPalette palette( option->palette ); + const QRect& rect( option->rect ); + + const State& flags( option->state ); + bool enabled( flags & State_Enabled ); + bool active( enabled && ( titleBarOption->titleBarState & Qt::WindowActive ) ); + + if( titleBarOption->subControls & SC_TitleBarLabel ) + { + + // render background + painter->setClipRect( rect ); + QColor outline( _helper->frameOutlineColor( palette, false, false ) ); + QColor background( _helper->titleBarColor( palette, active ) ); + _helper->renderTabWidgetFrame( painter, rect.adjusted( -1, -1, 1, 3 ), background, outline, CornersTop ); + + + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setBrush( Qt::NoBrush ); + painter->setPen( outline ); + painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); + + // render text + palette.setColor( QPalette::WindowText, _helper->titleBarTextColor( palette, active ) ); + QRect textRect( subControlRect( CC_TitleBar, option, SC_TitleBarLabel, widget ) ); + ParentStyleClass::drawItemText( painter, textRect, Qt::AlignCenter, palette, active, titleBarOption->text, QPalette::WindowText ); + + } + + // buttons + static const QList subControls = + { + SC_TitleBarMinButton, + SC_TitleBarMaxButton, + SC_TitleBarCloseButton, + SC_TitleBarNormalButton, + SC_TitleBarSysMenu + }; + + // loop over supported buttons + foreach( const SubControl& subControl, subControls ) + { + + // skip if not requested + if( !( titleBarOption->subControls & subControl ) ) continue; + + // find matching icon + QIcon icon; + switch( subControl ) + { + case SC_TitleBarMinButton: icon = standardIcon( SP_TitleBarMinButton, option, widget ); break; + case SC_TitleBarMaxButton: icon = standardIcon( SP_TitleBarMaxButton, option, widget ); break; + case SC_TitleBarCloseButton: icon = standardIcon( SP_TitleBarCloseButton, option, widget ); break; + case SC_TitleBarNormalButton: icon = standardIcon( SP_TitleBarNormalButton, option, widget ); break; + case SC_TitleBarSysMenu: icon = titleBarOption->icon; break; + default: break; + } + + // check icon + if( icon.isNull() ) continue; + + // define icon rect + QRect iconRect( subControlRect( CC_TitleBar, option, subControl, widget ) ); + if( iconRect.isEmpty() ) continue; + + // active state + bool subControlActive( titleBarOption->activeSubControls & subControl ); + + // mouse over state + const bool mouseOver( + !subControlActive && + widget && + iconRect.translated( widget->mapToGlobal( QPoint( 0,0 ) ) ).contains( QCursor::pos() ) ); + + // adjust iconRect + int iconWidth( pixelMetric( PM_SmallIconSize, option, widget ) ); + QSize iconSize( iconWidth, iconWidth ); + iconRect = centerRect( iconRect, iconSize ); + + // set icon mode and state + QIcon::Mode iconMode; + QIcon::State iconState; + + if( !enabled ) + { + iconMode = QIcon::Disabled; + iconState = QIcon::Off; + + } else { + + if( mouseOver ) iconMode = QIcon::Active; +// else if( active ) iconMode = QIcon::Selected; + else iconMode = QIcon::Normal; + + iconState = subControlActive ? QIcon::On : QIcon::Off; + + } + + // get pixmap and render + QPixmap pixmap = icon.pixmap( iconSize, iconMode, iconState ); + painter->drawPixmap( iconRect, pixmap ); + + } + + return true; + + } + + //____________________________________________________________________________________________________ + void Style::renderSpinBoxArrow( const SubControl& subControl, const QStyleOptionSpinBox* option, QPainter* painter, const QWidget* widget ) const + { + + const QPalette& palette( option->palette ); + const State& state( option->state ); + + // enable state + bool hasFocus( state & State_HasFocus ); + bool enabled( state & State_Enabled ); + bool sunken( state & State_Sunken && option->activeSubControls & subControl); + const QColor& outline = _helper->frameOutlineColor(option->palette).lighter(120); + + // check steps enable step + const bool atLimit( + (subControl == SC_SpinBoxUp && !(option->stepEnabled & QAbstractSpinBox::StepUpEnabled )) || + (subControl == SC_SpinBoxDown && !(option->stepEnabled & QAbstractSpinBox::StepDownEnabled ) ) ); + + // update enabled state accordingly + enabled &= !atLimit; + + // update mouse-over effect + bool mouseOver( (state & State_Active) && enabled && ( state & State_MouseOver ) ); + + // check animation state + bool subControlHover( enabled && ( mouseOver ) && ( option->activeSubControls & subControl ) ); + bool subControlSunken( enabled && ( sunken ) && ( option->activeSubControls & subControl ) ); + _animations->spinBoxEngine().updateState( widget, subControl, subControlHover, subControlSunken ); + + bool animated( enabled && _animations->spinBoxEngine().isAnimated( widget, subControl ) ); + qreal opacity( _animations->spinBoxEngine().opacity( widget, subControl ) ); + qreal pressedOpacity( _animations->spinBoxEngine().pressed( widget, subControl ) ); + + QColor color = _helper->arrowColor( palette, QPalette::Text ); + if( atLimit ) { + + color = _helper->arrowColor( palette, QPalette::Disabled, QPalette::Text ); + + } + + // arrow orientation + ArrowOrientation orientation( ( subControl == SC_SpinBoxUp ) ? ArrowUp:ArrowDown ); + + // arrow rect + QRect arrowRect( subControlRect( CC_SpinBox, option, subControl, widget ) ); + + if (subControl == SC_SpinBoxDown) { + painter->setBrush(Qt::NoBrush); + painter->setPen(outline); + int highlight = hasFocus ? 1 : 0; + painter->drawLine(arrowRect.left(), arrowRect.top() + 2 + highlight, arrowRect.left(), arrowRect.bottom() - 1 - highlight); + } + if (subControl == SC_SpinBoxUp) { + painter->setBrush(Qt::NoBrush); + painter->setPen(outline); + int highlight = hasFocus ? 1 : 0; + painter->drawLine(arrowRect.left(), arrowRect.top() + 2 + highlight, arrowRect.left(), arrowRect.bottom() - 1 - highlight); + } + + if (true) { + painter->setPen(Qt::NoPen); + QColor background = Helper::mix( palette.base().color(), palette.text().color(), opacity * 0.1); + background = Helper::mix( background, palette.dark().color(), pressedOpacity); + painter->setBrush(background); + if (hasFocus) + painter->drawRect(arrowRect.adjusted(1, 3, -1, -2)); + else + painter->drawRect(arrowRect.adjusted(1, 2, -1, -1)); + } + + // render + _helper->renderSign( painter, arrowRect, color, orientation == ArrowUp ); + + return; + + } + + //______________________________________________________________________________ + void Style::renderMenuTitle( const QStyleOptionToolButton* option, QPainter* painter, const QWidget* ) const + { + + // render a separator at the bottom + const QPalette& palette( option->palette ); + QColor color( _helper->separatorColor( palette ) ); + _helper->renderSeparator( painter, QRect( option->rect.bottomLeft()-QPoint( 0, Metrics::MenuItem_MarginWidth), QSize( option->rect.width(), 1 ) ), color ); + + // render text in the center of the rect + // icon is discarded on purpose + painter->setFont( option->font ); + QRect contentsRect = insideMargin( option->rect, Metrics::MenuItem_MarginWidth ); + drawItemText( painter, contentsRect, Qt::AlignCenter, palette, true, option->text, QPalette::WindowText ); + + } + + //______________________________________________________________________________ + qreal Style::dialAngle( const QStyleOptionSlider* sliderOption, int value ) const + { + + // calculate angle at which handle needs to be drawn + qreal angle( 0 ); + if( sliderOption->maximum == sliderOption->minimum ) angle = M_PI / 2; + else { + + qreal fraction( qreal( value - sliderOption->minimum )/qreal( sliderOption->maximum - sliderOption->minimum ) ); + if( !sliderOption->upsideDown ) fraction = 1 - fraction; + + if( sliderOption->dialWrapping ) angle = 1.5*M_PI - fraction*2*M_PI; + else angle = ( M_PI*8 - fraction*10*M_PI )/6; + + } + + return angle; + + } + + //______________________________________________________________________________ + const QWidget* Style::scrollBarParent( const QWidget* widget ) const + { + + // check widget and parent + if( !(widget && widget->parentWidget() ) ) return nullptr; + + // try cast to scroll area. Must test both parent and grandparent + QAbstractScrollArea* scrollArea; + if( !(scrollArea = qobject_cast( widget->parentWidget() ) ) ) + { scrollArea = qobject_cast( widget->parentWidget()->parentWidget() ); } + + // check scrollarea + if( scrollArea && + (widget == scrollArea->verticalScrollBar() || + widget == scrollArea->horizontalScrollBar() ) ) + { + + return scrollArea; + + } else if( widget->parentWidget()->inherits( "KTextEditor::View" ) ) { + + return widget->parentWidget(); + + } else return nullptr; + + } + + //______________________________________________________________________________ + QColor Style::scrollBarArrowColor( const QStyleOptionSlider* option, const SubControl& control, const QWidget* widget ) const + { + + const QRect& rect( option->rect ); + const QPalette& palette( option->palette ); + QColor color( _helper->arrowColor( palette, QPalette::WindowText ) ); + + bool widgetMouseOver( ( option->state & State_MouseOver ) && ( option->state & State_MouseOver ) ); + if( widget ) widgetMouseOver = widget->underMouse(); + #if QT_VERSION >= 0x050000 + // in case this QStyle is used by QQuickControls QStyle wrapper + else if( option->styleObject ) widgetMouseOver = option->styleObject->property("hover").toBool(); + #endif + + // check enabled state + bool enabled( option->state & State_Enabled ); + if( !enabled ) { + if( StyleConfigData::scrollBarShowOnMouseOver() ) { + // finally, global opacity when ScrollBarShowOnMouseOver + qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); + if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); + // no mouse over and no animation in progress, don't draw arrows at all + else if( !widgetMouseOver ) return Qt::transparent; + } + return color; + } + + if( + ( control == SC_ScrollBarSubLine && option->sliderValue == option->minimum ) || + ( control == SC_ScrollBarAddLine && option->sliderValue == option->maximum ) ) + { + + // manually disable arrow, to indicate that scrollbar is at limit + color = _helper->arrowColor( palette, QPalette::Disabled, QPalette::WindowText ); + if( StyleConfigData::scrollBarShowOnMouseOver() ) { + // finally, global opacity when ScrollBarShowOnMouseOver + qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); + if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); + // no mouse over and no animation in progress, don't draw arrows at all + else if( !widgetMouseOver ) return Qt::transparent; + } + return color; + } + + bool mouseOver( (option->state & State_Active) && _animations->scrollBarEngine().isHovered( widget, control ) ); + bool animated( _animations->scrollBarEngine().isAnimated( widget, AnimationHover, control ) ); + qreal opacity( _animations->scrollBarEngine().opacity( widget, control ) ); + + // retrieve mouse position from engine + QPoint position( mouseOver ? _animations->scrollBarEngine().position( widget ) : QPoint( -1, -1 ) ); + if( mouseOver && rect.contains( position ) ) + { + /* + * need to update the arrow controlRect on fly because there is no + * way to get it from the styles directly, outside of repaint events + */ + _animations->scrollBarEngine().setSubControlRect( widget, control, rect ); + } + + + if( rect.intersects( _animations->scrollBarEngine().subControlRect( widget, control ) ) ) + { + + QColor highlight = _helper->hoverColor( palette ); + if( animated ) + { + color = Helper::mix( color, highlight, opacity ); + + } else if( mouseOver ) { + + color = highlight; + + } + + } + + if( StyleConfigData::scrollBarShowOnMouseOver() ) + { + // finally, global opacity when ScrollBarShowOnMouseOver + qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); + if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); + // no mouse over and no animation in progress, don't draw arrows at all + else if( !widgetMouseOver ) return Qt::transparent; + } + + return color; + + } + + //____________________________________________________________________________________ + void Style::setTranslucentBackground( QWidget* widget ) const + { + if (!_isKDE) return; + widget->setAttribute( Qt::WA_TranslucentBackground ); + + #ifdef Q_WS_WIN + // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly + widget->setWindowFlags( widget->windowFlags() | Qt::FramelessWindowHint ); + #endif + + } + + //____________________________________________________________________________________ + QStyleOptionToolButton Style::separatorMenuItemOption( const QStyleOptionMenuItem* menuItemOption, const QWidget* widget ) const + { + + // separator can have a title and an icon + // in that case they are rendered as sunken flat toolbuttons + QStyleOptionToolButton toolButtonOption; + toolButtonOption.initFrom( widget ); + toolButtonOption.rect = menuItemOption->rect; + toolButtonOption.features = QStyleOptionToolButton::None; + toolButtonOption.state = State_Enabled|State_AutoRaise; + toolButtonOption.subControls = SC_ToolButton; + toolButtonOption.icon = QIcon(); + toolButtonOption.iconSize = QSize(); + toolButtonOption.text = menuItemOption->text; + + toolButtonOption.toolButtonStyle = Qt::ToolButtonTextBesideIcon; + return toolButtonOption; + + } + + //____________________________________________________________________________________ + QIcon Style::toolBarExtensionIcon( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const + { + + // store palette + // due to Qt, it is not always safe to assume that either option, nor widget are defined + QPalette palette; + if( option ) palette = option->palette; + else if( widget ) palette = widget->palette(); + else palette = QApplication::palette(); + + // convenience class to map color to icon mode + struct IconData + { + QColor _color; + QIcon::Mode _mode; + QIcon::State _state; + }; + + // map colors to icon states + const QList iconTypes = + { + { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Normal, QIcon::Off }, + { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Selected, QIcon::Off }, + { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Active, QIcon::Off }, + { palette.color( QPalette::Disabled, QPalette::WindowText ), QIcon::Disabled, QIcon::Off }, + + { palette.color( QPalette::Active, QPalette::HighlightedText ), QIcon::Normal, QIcon::On }, + { palette.color( QPalette::Active, QPalette::HighlightedText ), QIcon::Selected, QIcon::On }, + { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Active, QIcon::On }, + { palette.color( QPalette::Disabled, QPalette::WindowText ), QIcon::Disabled, QIcon::On } + }; + + // default icon sizes + static const QList iconSizes = { 8, 16, 22, 32, 48 }; + + // decide arrow orientation + ArrowOrientation orientation( standardPixmap == SP_ToolBarHorizontalExtensionButton ? ArrowRight : ArrowDown ); + + // create icon and fill + QIcon icon; + foreach( const IconData& iconData, iconTypes ) + { + + foreach( const int& iconSize, iconSizes ) + { + + // create pixmap + QPixmap pixmap( iconSize, iconSize ); + pixmap.fill( Qt::transparent ); + + // render + QPainter painter( &pixmap ); + + // icon size + int fixedIconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); + QRect fixedRect( 0, 0, fixedIconSize, fixedIconSize ); + + painter.setWindow( fixedRect ); + painter.translate( standardPixmap == SP_ToolBarHorizontalExtensionButton ? QPoint( 1, 0 ) : QPoint( 0, 1 ) ); + _helper->renderArrow( &painter, fixedRect, iconData._color, orientation ); + painter.end(); + + // add to icon + icon.addPixmap( pixmap, iconData._mode, iconData._state ); + + } + + } + + return icon; + + } + + //____________________________________________________________________________________ + QIcon Style::titleBarButtonIcon( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const + { + + // map standardPixmap to button type + ButtonType buttonType; + switch( standardPixmap ) + { + case SP_TitleBarNormalButton: buttonType = ButtonRestore; break; + case SP_TitleBarMinButton: buttonType = ButtonMinimize; break; + case SP_TitleBarMaxButton: buttonType = ButtonMaximize; break; + case SP_TitleBarCloseButton: + case SP_DockWidgetCloseButton: + buttonType = ButtonClose; + break; + + default: return QIcon(); + } + + // store palette + // due to Qt, it is not always safe to assume that either option, nor widget are defined + QPalette palette; + if( option ) palette = option->palette; + else if( widget ) palette = widget->palette(); + else palette = QApplication::palette(); + + bool isCloseButton( buttonType == ButtonClose && StyleConfigData::outlineCloseButton() ); + + palette.setCurrentColorGroup( QPalette::Active ); + QColor base( palette.color( QPalette::WindowText ) ); + QColor selected( palette.color( QPalette::HighlightedText ) ); + QColor negative( buttonType == ButtonClose ? _helper->negativeText( palette ):base ); + QColor negativeSelected( buttonType == ButtonClose ? _helper->negativeText( palette ):selected ); + + bool invertNormalState( isCloseButton ); + + // convenience class to map color to icon mode + struct IconData + { + QColor _color; + bool _inverted; + QIcon::Mode _mode; + QIcon::State _state; + }; + + // map colors to icon states + const QList iconTypes = + { + + // state off icons + { Helper::mix( palette.color( QPalette::Window ), base, 0.5 ), invertNormalState, QIcon::Normal, QIcon::Off }, + { Helper::mix( palette.color( QPalette::Window ), selected, 0.5 ), invertNormalState, QIcon::Selected, QIcon::Off }, + { Helper::mix( palette.color( QPalette::Window ), negative, 0.5 ), true, QIcon::Active, QIcon::Off }, + { Helper::mix( palette.color( QPalette::Window ), base, 0.2 ), invertNormalState, QIcon::Disabled, QIcon::Off }, + + // state on icons + { Helper::mix( palette.color( QPalette::Window ), negative, 0.7 ), true, QIcon::Normal, QIcon::On }, + { Helper::mix( palette.color( QPalette::Window ), negativeSelected, 0.7 ), true, QIcon::Selected, QIcon::On }, + { Helper::mix( palette.color( QPalette::Window ), negative, 0.7 ), true, QIcon::Active, QIcon::On }, + { Helper::mix( palette.color( QPalette::Window ), base, 0.2 ), invertNormalState, QIcon::Disabled, QIcon::On } + + }; + + // default icon sizes + static const QList iconSizes = { 8, 16, 22, 32, 48 }; + + // output icon + QIcon icon; + + foreach( const IconData& iconData, iconTypes ) + { + + foreach( const int& iconSize, iconSizes ) + { + // create pixmap + QPixmap pixmap( iconSize, iconSize ); + pixmap.fill( Qt::transparent ); + + // create painter and render + QPainter painter( &pixmap ); + _helper->renderDecorationButton( &painter, pixmap.rect(), iconData._color, buttonType, iconData._inverted ); + + painter.end(); + + // store + icon.addPixmap( pixmap, iconData._mode, iconData._state ); + } + + } + + return icon; + + } + + //______________________________________________________________________________ + const QAbstractItemView* Style::itemViewParent( const QWidget* widget ) const + { + + const QAbstractItemView* itemView( nullptr ); + + // check widget directly + if( ( itemView = qobject_cast( widget ) ) ) return itemView; + + // check widget grand-parent + else if( + widget && + widget->parentWidget() && + ( itemView = qobject_cast( widget->parentWidget()->parentWidget() ) ) && + itemView->viewport() == widget->parentWidget() ) + { return itemView; } + + // return null otherwise + else return nullptr; + } + + //____________________________________________________________________ + bool Style::isSelectedItem( const QWidget* widget, const QPoint& localPosition ) const + { + + // get relevant itemview parent and check + const QAbstractItemView* itemView( itemViewParent( widget ) ); + if( !( itemView && itemView->hasFocus() && itemView->selectionModel() ) ) return false; + + #if QT_VERSION >= 0x050000 + QPoint position = widget->mapTo( itemView, localPosition ); + #else + // qt4 misses a const for mapTo argument, although nothing is actually changed to the passed widget + QPoint position = widget->mapTo( const_cast( itemView ), localPosition ); + #endif + + // get matching QModelIndex and check + QModelIndex index( itemView->indexAt( position ) ); + if( !index.isValid() ) return false; + + // check whether index is selected + return itemView->selectionModel()->isSelected( index ); + + } + + //____________________________________________________________________ + bool Style::isQtQuickControl( const QStyleOption* option, const QWidget* widget ) const + { + #if QT_VERSION >= 0x050000 + return (widget == nullptr) && option && option->styleObject && option->styleObject->inherits( "QQuickItem" ); + #else + Q_UNUSED( widget ); + Q_UNUSED( option ); + return false; + #endif + } + + //____________________________________________________________________ + bool Style::showIconsInMenuItems( void ) const + { + return Adwaita::Settings::ShowIconsInMenuItems && !QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus); + } + + //____________________________________________________________________ + bool Style::showIconsOnPushButtons( void ) const + { + return Adwaita::Settings::ShowIconsOnPushButtons; + } + + //____________________________________________________________________ + bool Style::isMenuTitle( const QWidget* widget ) const + { + + // check widget + if( !widget ) return false; + + // check property + QVariant property( widget->property( PropertyNames::menuTitle ) ); + if( property.isValid() ) return property.toBool(); + + // detect menu toolbuttons + QWidget* parent = widget->parentWidget(); + if( qobject_cast( parent ) ) + { + foreach( auto child, parent->findChildren() ) + { + if( child->defaultWidget() != widget ) continue; + const_cast(widget)->setProperty( PropertyNames::menuTitle, true ); + return true; + } + + } + + const_cast(widget)->setProperty( PropertyNames::menuTitle, false ); + return false; + + } + + //____________________________________________________________________ + bool Style::hasAlteredBackground( const QWidget* widget ) const + { + + // check widget + if( !widget ) return false; + + // check property + QVariant property( widget->property( PropertyNames::alteredBackground ) ); + if( property.isValid() ) return property.toBool(); + + // check if widget is of relevant type + bool hasAlteredBackground( false ); + if( const QGroupBox* groupBox = qobject_cast( widget ) ) hasAlteredBackground = !groupBox->isFlat(); + else if( const QTabWidget* tabWidget = qobject_cast( widget ) ) hasAlteredBackground = !tabWidget->documentMode(); + else if( qobject_cast( widget ) ) hasAlteredBackground = true; + else if( StyleConfigData::dockWidgetDrawFrame() && qobject_cast( widget ) ) hasAlteredBackground = true; + + if( widget->parentWidget() && !hasAlteredBackground ) hasAlteredBackground = this->hasAlteredBackground( widget->parentWidget() ); + const_cast(widget)->setProperty( PropertyNames::alteredBackground, hasAlteredBackground ); + return hasAlteredBackground; + + } + +} diff --git a/style/adwaitastyle.h b/style/adwaitastyle.h new file mode 100644 index 0000000..b905a02 --- /dev/null +++ b/style/adwaitastyle.h @@ -0,0 +1,589 @@ +#ifndef adwaitastyle_h +#define adwaitastyle_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 "adwaita.h" +#include "config-adwaita.h" + +#if ADWAITA_USE_KDE4 +#include "kstylekde4compat.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if QT_VERSION >= 0x050000 +#include +#endif + +namespace AdwaitaPrivate +{ + class TabBarData; +} + +namespace Adwaita +{ + + class Animations; + class Helper; + class Mnemonics; + class SplitterFactory; + class WidgetExplorer; + class WindowManager; + + //* convenience typedef for base class + #if ADWAITA_USE_KDE4 + using ParentStyleClass = KStyleKDE4Compat; + #else + using ParentStyleClass = QCommonStyle; + #endif + + //* base class for adwaita style + /** it is responsible to draw all the primitives to be displayed on screen, on request from Qt paint engine */ + class Style: public ParentStyleClass + { + Q_OBJECT + + /* this tells kde applications that custom style elements are supported, using the kstyle mechanism */ + Q_CLASSINFO ("X-KDE-CustomElements", "true") + + public: + + //* constructor + explicit Style( bool dark ); + + //* destructor + virtual ~Style( void ); + + //* needed to avoid warnings at compilation time + using ParentStyleClass::polish; + using ParentStyleClass::unpolish; + + //* widget polishing + virtual void polish( QWidget* ); + + //* widget unpolishing + virtual void unpolish( QWidget* ); + + //* palette polishing + virtual void polish( QPalette &palette ); + + //* polish scrollarea + void polishScrollArea( QAbstractScrollArea* ); + + //* pixel metrics + virtual int pixelMetric(PixelMetric, const QStyleOption* = nullptr, const QWidget* = nullptr) const; + + //* style hints + virtual int styleHint(StyleHint, const QStyleOption* = nullptr, const QWidget* = nullptr, QStyleHintReturn* = nullptr) const; + + //* returns rect corresponding to one widget's subelement + virtual QRect subElementRect( SubElement, const QStyleOption*, const QWidget* ) const; + + //* returns rect corresponding to one widget's subcontrol + virtual QRect subControlRect( ComplexControl, const QStyleOptionComplex*, SubControl, const QWidget* ) const; + + //* returns size matching contents + QSize sizeFromContents( ContentsType, const QStyleOption*, const QSize&, const QWidget* ) const; + + //* returns which subcontrol given QPoint corresponds to + SubControl hitTestComplexControl( ComplexControl, const QStyleOptionComplex*, const QPoint&, const QWidget* ) const; + + //* primitives + void drawPrimitive( PrimitiveElement, const QStyleOption*, QPainter*, const QWidget* ) const; + + //* controls + void drawControl( ControlElement, const QStyleOption*, QPainter*, const QWidget* ) const; + + //* complex controls + void drawComplexControl( ComplexControl, const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + + //* generic text rendering + virtual void drawItemText( + QPainter*, const QRect&, int alignment, const QPalette&, bool enabled, + const QString&, QPalette::ColorRole = QPalette::NoRole) const; + + //*@name event filters + //@{ + + virtual bool eventFilter(QObject *, QEvent *); + bool eventFilterScrollArea( QWidget*, QEvent* ); + bool eventFilterComboBoxContainer( QWidget*, QEvent* ); + bool eventFilterDockWidget( QDockWidget*, QEvent* ); + bool eventFilterMdiSubWindow( QMdiSubWindow*, QEvent* ); + + #if QT_VERSION >= 0x050000 + bool eventFilterCommandLinkButton( QCommandLinkButton*, QEvent* ); + #endif + + //* install event filter to object, in a unique way + void addEventFilter( QObject* object ) + { + object->removeEventFilter( this ); + object->installEventFilter( this ); + } + + //@} + + protected Q_SLOTS: + + //* update configuration + void configurationChanged( void ); + + //* standard icons + virtual QIcon standardIconImplementation( StandardPixmap, const QStyleOption*, const QWidget* ) const; + + protected: + + //* standard icons + virtual QIcon standardIcon( StandardPixmap pixmap, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const + { return standardIconImplementation( pixmap, option, widget ); } + + //* load configuration + void loadConfiguration(); + + //*@name subelementRect specialized functions + //@{ + + //* default implementation. Does not change anything + QRect defaultSubElementRect( const QStyleOption* option, const QWidget* ) const + { return option->rect; } + + QRect pushButtonContentsRect( const QStyleOption*, const QWidget* ) const; + QRect pushButtonFocusRect( const QStyleOption*, const QWidget* ) const; + QRect checkBoxContentsRect( const QStyleOption*, const QWidget* ) const; + QRect checkBoxIndicatorRect( const QStyleOption*, const QWidget* ) const; + QRect checkBoxFocusRect( const QStyleOption*, const QWidget* ) const; + QRect lineEditContentsRect( const QStyleOption*, const QWidget* ) const; + QRect progressBarGrooveRect( const QStyleOption*, const QWidget* ) const; + QRect progressBarContentsRect( const QStyleOption*, const QWidget* ) const; + QRect progressBarLabelRect( const QStyleOption*, const QWidget* ) const; + QRect headerArrowRect( const QStyleOption*, const QWidget* ) const; + QRect headerLabelRect( const QStyleOption*, const QWidget* ) const; + QRect sliderFocusRect( const QStyleOption*, const QWidget* ) const; + QRect tabBarTabLeftButtonRect( const QStyleOption*, const QWidget* ) const; + QRect tabBarTabRightButtonRect( const QStyleOption*, const QWidget* ) const; + QRect tabWidgetTabBarRect( const QStyleOption*, const QWidget* ) const; + QRect tabWidgetTabContentsRect( const QStyleOption*, const QWidget* ) const; + QRect tabWidgetTabPaneRect( const QStyleOption*, const QWidget* ) const; + QRect tabWidgetCornerRect( SubElement, const QStyleOption*, const QWidget* widget ) const; + QRect toolBoxTabContentsRect( const QStyleOption*, const QWidget* ) const; + QRect genericLayoutItemRect( const QStyleOption*, const QWidget* ) const; + + //@} + + //*@name subcontrol Rect specialized functions + //@{ + + QRect groupBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + QRect toolButtonSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + QRect comboBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + QRect spinBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + QRect scrollBarInternalSubControlRect( const QStyleOptionComplex*, SubControl ) const; + QRect scrollBarSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + QRect dialSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + QRect sliderSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; + + //@} + + //*@name sizeFromContents + //@{ + QSize defaultSizeFromContents( const QStyleOption*, const QSize& size, const QWidget* ) const + { return size; } + + QSize checkBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize lineEditSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize comboBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize spinBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize sliderSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize pushButtonSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize toolButtonSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize menuBarItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize menuItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize progressBarSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize tabWidgetSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize tabBarTabSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize headerSectionSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + QSize itemViewItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; + + //@} + + //*@name primitives specialized functions + //@{ + + bool emptyPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const + { return true; } + + bool drawFramePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameLineEditPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameFocusRectPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameMenuPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameGroupBoxPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameTabWidgetPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameTabBarBasePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawFrameWindowPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + + bool drawIndicatorArrowUpPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { return drawIndicatorArrowPrimitive( ArrowUp, option, painter, widget ); } + + bool drawIndicatorArrowDownPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { return drawIndicatorArrowPrimitive( ArrowDown, option, painter, widget ); } + + bool drawIndicatorArrowLeftPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { return drawIndicatorArrowPrimitive( ArrowLeft, option, painter, widget ); } + + bool drawIndicatorArrowRightPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { return drawIndicatorArrowPrimitive( ArrowRight, option, painter, widget ); } + + bool drawIndicatorArrowPrimitive( ArrowOrientation, const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorHeaderArrowPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawPanelButtonCommandPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawPanelButtonToolPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawTabBarPanelButtonToolPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawPanelScrollAreaCornerPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawPanelMenuPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawPanelTipLabelPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawPanelItemViewItemPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorCheckBoxPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorRadioButtonPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorButtonDropDownPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorTabClosePrimitive( const QStyleOption*, QPainter* painter, const QWidget* widget ) const; + bool drawIndicatorTabTearPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorToolBarHandlePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorToolBarSeparatorPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawIndicatorBranchPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + + //@} + + //*@name controls specialized functions + //@{ + + bool emptyControl( const QStyleOption*, QPainter*, const QWidget* ) const + { return true; } + + virtual bool drawPushButtonLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawToolButtonLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawCheckBoxLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawComboBoxLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawMenuBarEmptyArea( const QStyleOption*, QPainter* , const QWidget*) const; + virtual bool drawMenuBarItemControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawMenuEmptyAreaControl( const QStyleOption*, QPainter* , const QWidget*) const; + virtual bool drawMenuItemControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawProgressBarControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawProgressBarContentsControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawProgressBarGrooveControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawProgressBarLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawScrollBarSliderControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawScrollBarAddLineControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawScrollBarSubLineControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawShapedFrameControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawRubberBandControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawHeaderSectionControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawHeaderLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawHeaderEmptyAreaControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawTabBarTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawTabBarTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawToolBoxTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawToolBoxTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; + virtual bool drawDockWidgetTitleControl( const QStyleOption*, QPainter*, const QWidget* ) const; + + //*@} + + //*@name complex ontrols specialized functions + //@{ + bool drawGroupBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawToolButtonComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawComboBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawSpinBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawSliderComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawDialComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawScrollBarComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + bool drawTitleBarComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + //@} + + //!*@name various utilty functions + //@{ + + //* spinbox arrows + void renderSpinBoxArrow( const SubControl&, const QStyleOptionSpinBox*, QPainter*, const QWidget*) const; + + //* menu title + void renderMenuTitle( const QStyleOptionToolButton*, QPainter*, const QWidget* ) const; + + //* return dial angle based on option and value + qreal dialAngle( const QStyleOptionSlider*, int ) const; + + //* returns relevant scrollbar parent + /** needed to detect parent focus */ + const QWidget* scrollBarParent( const QWidget* ) const; + + //* returns true if given scrollbar arrow is animated + QColor scrollBarArrowColor( const QStyleOptionSlider*, const SubControl&, const QWidget* ) const; + + //* scrollbar buttons + enum ScrollBarButtonType + { + NoButton, + SingleButton, + DoubleButton + }; + + //* returns height for scrollbar buttons depending of button types + int scrollBarButtonHeight( const ScrollBarButtonType& type ) const + { + switch( type ) + { + case NoButton: return Metrics::ScrollBar_NoButtonHeight; + case SingleButton: return Metrics::ScrollBar_SingleButtonHeight; + case DoubleButton: return Metrics::ScrollBar_DoubleButtonHeight; + default: return 0; + } + } + + //@} + + //* translucent background + void setTranslucentBackground( QWidget* ) const; + + /** + separator can have a title and an icon + in that case they are rendered as sunken flat toolbuttons + return toolbutton option that matches named separator menu items + */ + QStyleOptionToolButton separatorMenuItemOption( const QStyleOptionMenuItem*, const QWidget* ) const; + + //* create toolbar extension icon + QIcon toolBarExtensionIcon( StandardPixmap, const QStyleOption*, const QWidget* ) const; + + //* create title bar button icon + QIcon titleBarButtonIcon( StandardPixmap, const QStyleOption*, const QWidget* ) const; + + //* returns item view parent if any + /** needed to have correct color on focused checkboxes and radiobuttons */ + const QAbstractItemView* itemViewParent( const QWidget* ) const; + + //* returns true if a given widget is a selected item in a focused list + /** + This is necessary to have the correct colors used for e.g. checkboxes and radiobuttons in lists + @param widget The widget to be checked + @param position Used to find the relevant QModelIndex + */ + bool isSelectedItem( const QWidget*, const QPoint& ) const; + + //* return true if option corresponds to QtQuick control + bool isQtQuickControl( const QStyleOption*, const QWidget* ) const; + + //@} + + //* adjust rect based on provided margins + QRect insideMargin( const QRect& r, int margin ) const + { return insideMargin( r, margin, margin ); } + + //* adjust rect based on provided margins + QRect insideMargin( const QRect& r, int marginWidth, int marginHeight ) const + { return r.adjusted( marginWidth, marginHeight, -marginWidth, -marginHeight ); } + + //* expand size based on margins + QSize expandSize( const QSize& size, int margin ) const + { return expandSize( size, margin, margin ); } + + //* expand size based on margins + QSize expandSize( const QSize& size, int marginWidth, int marginHeight ) const + { return size + 2*QSize( marginWidth, marginHeight ); } + + //* returns true for vertical tabs + bool isVerticalTab( const QStyleOptionTab* option ) const + { return isVerticalTab( option->shape ); } + + bool isVerticalTab( const QTabBar::Shape& shape ) const + { + return shape == QTabBar::RoundedEast + || shape == QTabBar::RoundedWest + || shape == QTabBar::TriangularEast + || shape == QTabBar::TriangularWest; + + } + + //* right to left alignment handling + using ParentStyleClass::visualRect; + QRect visualRect(const QStyleOption* opt, const QRect& subRect) const + { return ParentStyleClass::visualRect(opt->direction, opt->rect, subRect); } + + //* centering + QRect centerRect(const QRect &rect, const QSize& size ) const + { return centerRect( rect, size.width(), size.height() ); } + + QRect centerRect(const QRect &rect, int width, int height) const + { return QRect(rect.left() + (rect.width() - width)/2, rect.top() + (rect.height() - height)/2, width, height); } + + /* + Checks whether the point is before the bound rect for bound of given orientation. + This is needed to implement custom number of buttons in scrollbars, + as well as proper mouse-hover + */ + inline bool preceeds( const QPoint&, const QRect&, const QStyleOption* ) const; + + //* return which arrow button is hit by point for scrollbar double buttons + inline QStyle::SubControl scrollBarHitTest( const QRect&, const QPoint&, const QStyleOption* ) const; + + //! return true if one of the widget's parent inherits requested type + inline bool hasParent( const QWidget*, const char* ) const; + + //* return true if one of the widget's parent inherits requested type + template bool hasParent( const QWidget* ) const; + + //* return true if icons should be shown in menus + bool showIconsInMenuItems( void ) const; + + //* return true if icons should be shown on buttons + bool showIconsOnPushButtons( void ) const; + + //* return true if passed widget is a menu title (KMenu::addTitle) + bool isMenuTitle( const QWidget* ) const; + + //* return true if passed widget is a menu title (KMenu::addTitle) + bool hasAlteredBackground( const QWidget* ) const; + + private: + + //*@name scrollbar button types (for addLine and subLine ) + //@{ + ScrollBarButtonType _addLineButtons; + ScrollBarButtonType _subLineButtons; + //@} + + //* helper + Helper* _helper; + + //* animations + Animations* _animations; + + //* keyboard accelerators + Mnemonics* _mnemonics; + + //* window manager + WindowManager* _windowManager; + + //* splitter Factory, to extend splitters hit area + SplitterFactory* _splitterFactory; + + //* widget explorer + WidgetExplorer* _widgetExplorer; + + //* tabbar data + AdwaitaPrivate::TabBarData* _tabBarData; + + //* icon hash + using IconCache = QHash; + IconCache _iconCache; + + //* pointer to primitive specialized function + using StylePrimitive = bool(Style::*)(const QStyleOption*, QPainter*, const QWidget* ) const; + StylePrimitive _frameFocusPrimitive = nullptr; + + //* pointer to control specialized function + using StyleControl = bool (Style::*)( const QStyleOption*, QPainter*, const QWidget* ) const; + + //* pointer to control specialized function + using StyleComplexControl = bool (Style::*)( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; + + //*@name custom elements + //@{ + + //* use Argb Drag and Drop Window + QStyle::StyleHint SH_ArgbDndWindow; + + //! styled painting for KCapacityBar + QStyle::ControlElement CE_CapacityBar; + + bool _dark { false }; + + bool _isGNOME { false }; + bool _isKDE { false }; + + //@} + + }; + + //_________________________________________________________________________ + bool Style::preceeds( const QPoint& point, const QRect& bound, const QStyleOption* option ) const + { + if( option->state&QStyle::State_Horizontal) + { + + if( option->direction == Qt::LeftToRight) return point.x() < bound.right(); + else return point.x() > bound.x(); + + } else return point.y() < bound.y(); + + } + + //_________________________________________________________________________ + QStyle::SubControl Style::scrollBarHitTest( const QRect& rect, const QPoint& point, const QStyleOption* option ) const + { + if( option->state & QStyle::State_Horizontal) + { + + if( option->direction == Qt::LeftToRight ) return point.x() < rect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; + else return point.x() > rect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; + + } else return point.y() < rect.center().y() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; + + } + + //_________________________________________________________________________ + bool Style::hasParent( const QWidget* widget, const char* className ) const + { + + if( !widget ) return false; + + while( (widget = widget->parentWidget()) ) + { if( widget->inherits( className ) ) return true; } + + return false; + + } + + //_________________________________________________________________________ + template< typename T > bool Style::hasParent( const QWidget* widget ) const + { + + if( !widget ) return false; + + while( (widget = widget->parentWidget()) ) + { if( qobject_cast( widget ) ) return true; } + + return false; + + } + + +} + +#endif diff --git a/style/adwaitastyleplugin.cpp b/style/adwaitastyleplugin.cpp new file mode 100644 index 0000000..1d07c08 --- /dev/null +++ b/style/adwaitastyleplugin.cpp @@ -0,0 +1,56 @@ + +/************************************************************************* + * 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 "adwaitastyleplugin.h" +#include "adwaitastyle.h" + +#include + +#if QT_VERSION < 0x050000 +Q_EXPORT_PLUGIN2( adwaita-qt, Adwaita::StylePlugin ) +#endif + +namespace Adwaita +{ + + //_________________________________________________ + QStyle* StylePlugin::create( const QString &key ) + { + if( key.toLower() == QStringLiteral( "adwaita" ) ) + { + return new Style(false); + } + if ( key.toLower() == QStringLiteral( "adwaita-dark") ) + { + return new Style(true); + } + return nullptr; + } + + //_________________________________________________ + StylePlugin::~StylePlugin() + { + } + + //_________________________________________________ + QStringList StylePlugin::keys() const + { return QStringList() << QStringLiteral( "Adwaita" ) << QStringLiteral( "Adwaita-Dark" ); } + +} diff --git a/style/adwaitastyleplugin.h b/style/adwaitastyleplugin.h new file mode 100644 index 0000000..371cbee --- /dev/null +++ b/style/adwaitastyleplugin.h @@ -0,0 +1,57 @@ +#ifndef adwaitastyleplugin_h +#define adwaitastyleplugin_h + +/************************************************************************* + * Copyright (C) 2014 by Hugo Pereira Da Costa * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + *************************************************************************/ + +#include + +namespace Adwaita +{ + + class StylePlugin : public QStylePlugin + { + + Q_OBJECT + + #if QT_VERSION >= 0x050000 + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "adwaita.json" ) + #endif + + public: + + //* constructor + explicit StylePlugin(QObject *parent = 0): + QStylePlugin(parent) + {} + + //* destructor + ~StylePlugin(); + + //* returns list of valid keys + QStringList keys() const; + + //* create style + QStyle* create( const QString& ); + + }; + +} + +#endif diff --git a/style/adwaitatileset.cpp b/style/adwaitatileset.cpp new file mode 100644 index 0000000..d599c96 --- /dev/null +++ b/style/adwaitatileset.cpp @@ -0,0 +1,198 @@ +/************************************************************************* + * 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 "adwaitatileset.h" + +#include + +namespace Adwaita +{ + + //___________________________________________________________ + inline bool bits(TileSet::Tiles flags, TileSet::Tiles testFlags) + { return (flags & testFlags) == testFlags; } + + //______________________________________________________________________________________ + inline qreal devicePixelRatio( const QPixmap& pixmap ) + { + #if QT_VERSION >= 0x050300 + return pixmap.devicePixelRatio(); + #else + Q_UNUSED( pixmap ); + return 1; + #endif + } + + //______________________________________________________________________________________ + inline void setDevicePixelRatio( QPixmap& pixmap, qreal value ) + { + #if QT_VERSION >= 0x050300 + return pixmap.setDevicePixelRatio( value ); + #else + Q_UNUSED( pixmap ); + Q_UNUSED( value ); + #endif + } + + //______________________________________________________________ + void TileSet::initPixmap( PixmapList& pixmaps, const QPixmap &source, int width, int height, const QRect &rect) + { + QSize size( width, height ); + if( !( size.isValid() && rect.isValid() ) ) + { + pixmaps.append( QPixmap() ); + + } else if( size != rect.size() ) { + + qreal dpiRatio( devicePixelRatio( source ) ); + QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio ); + QSize scaledSize( size*dpiRatio ); + QPixmap tile( source.copy(scaledRect) ); + QPixmap pixmap( scaledSize ); + + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + painter.drawTiledPixmap(0, 0, scaledSize.width(), scaledSize.height(), tile); + setDevicePixelRatio( pixmap, dpiRatio ); + pixmaps.append( pixmap ); + + } else { + + qreal dpiRatio( devicePixelRatio( source ) ); + QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio ); + QPixmap pixmap( source.copy( scaledRect ) ); + setDevicePixelRatio( pixmap, dpiRatio ); + pixmaps.append( pixmap ); + + } + + } + + //______________________________________________________________ + TileSet::TileSet( void ): + _w1(0), + _h1(0), + _w3(0), + _h3(0) + { _pixmaps.reserve(9); } + + //______________________________________________________________ + TileSet::TileSet(const QPixmap &source, int w1, int h1, int w2, int h2 ): + _w1(w1), + _h1(h1), + _w3(0), + _h3(0) + { + _pixmaps.reserve(9); + if( source.isNull() ) return; + + _w3 = source.width()/devicePixelRatio( source ) - (w1 + w2); + _h3 = source.height()/devicePixelRatio( source ) - (h1 + h2); + int w = w2; + int h = h2; + + // initialise pixmap array + initPixmap( _pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1) ); + initPixmap( _pixmaps, source, w, _h1, QRect(_w1, 0, w2, _h1) ); + initPixmap( _pixmaps, source, _w3, _h1, QRect(_w1+w2, 0, _w3, _h1) ); + initPixmap( _pixmaps, source, _w1, h, QRect(0, _h1, _w1, h2) ); + initPixmap( _pixmaps, source, w, h, QRect(_w1, _h1, w2, h2) ); + initPixmap( _pixmaps, source, _w3, h, QRect(_w1+w2, _h1, _w3, h2) ); + initPixmap( _pixmaps, source, _w1, _h3, QRect(0, _h1+h2, _w1, _h3) ); + initPixmap( _pixmaps, source, w, _h3, QRect(_w1, _h1+h2, w2, _h3) ); + initPixmap( _pixmaps, source, _w3, _h3, QRect(_w1+w2, _h1+h2, _w3, _h3) ); + } + + //___________________________________________________________ + void TileSet::render(const QRect &constRect, QPainter *painter, Tiles tiles) const + { + + bool oldHint( painter->testRenderHint( QPainter::SmoothPixmapTransform ) ); + painter->setRenderHint( QPainter::SmoothPixmapTransform, true ); + + // check initialization + if( _pixmaps.size() < 9 ) return; + + // copy source rect + QRect rect( constRect ); + + // get rect dimensions + int x0, y0, w, h; + rect.getRect(&x0, &y0, &w, &h); + + // calculate pixmaps widths + int wLeft(0); + int wRight(0); + if( _w1+_w3 > 0 ) + { + qreal wRatio( qreal( _w1 )/qreal( _w1 + _w3 ) ); + wLeft = (tiles&Right) ? qMin( _w1, int(w*wRatio) ):_w1; + wRight = (tiles&Left) ? qMin( _w3, int(w*(1.0-wRatio)) ):_w3; + } + + // calculate pixmap heights + int hTop(0); + int hBottom(0); + if( _h1+_h3 > 0 ) + { + qreal hRatio( qreal( _h1 )/qreal( _h1 + _h3 ) ); + hTop = (tiles&Bottom) ? qMin( _h1, int(h*hRatio) ):_h1; + hBottom = (tiles&Top) ? qMin( _h3, int(h*(1.0-hRatio)) ):_h3; + } + + // calculate corner locations + w -= wLeft + wRight; + h -= hTop + hBottom; + int x1 = x0 + wLeft; + int x2 = x1 + w; + int y1 = y0 + hTop; + int y2 = y1 + h; + + int w2 = _pixmaps.at(7).width()/devicePixelRatio( _pixmaps.at(7) ); + int h2 = _pixmaps.at(5).height()/devicePixelRatio( _pixmaps.at(5) ); + + // corner + if( bits( tiles, Top|Left) ) painter->drawPixmap(x0, y0, _pixmaps.at(0), 0, 0, wLeft*devicePixelRatio( _pixmaps.at(0) ), hTop*devicePixelRatio( _pixmaps.at(0) )); + if( bits( tiles, Top|Right) ) painter->drawPixmap(x2, y0, _pixmaps.at(2), (_w3-wRight)*devicePixelRatio( _pixmaps.at(2) ), 0, wRight*devicePixelRatio( _pixmaps.at(2) ), hTop*devicePixelRatio( _pixmaps.at(2) ) ); + if( bits( tiles, Bottom|Left) ) painter->drawPixmap(x0, y2, _pixmaps.at(6), 0, (_h3-hBottom)*devicePixelRatio( _pixmaps.at(6) ), wLeft*devicePixelRatio( _pixmaps.at(6) ), hBottom*devicePixelRatio( _pixmaps.at(6) )); + if( bits( tiles, Bottom|Right) ) painter->drawPixmap(x2, y2, _pixmaps.at(8), (_w3-wRight)*devicePixelRatio( _pixmaps.at(8) ), (_h3-hBottom)*devicePixelRatio( _pixmaps.at(8) ), wRight*devicePixelRatio( _pixmaps.at(8) ), hBottom*devicePixelRatio( _pixmaps.at(8) ) ); + + // top and bottom + if( w > 0 ) + { + if( tiles&Top ) painter->drawPixmap(x1, y0, w, hTop, _pixmaps.at(1), 0, 0, w2*devicePixelRatio( _pixmaps.at(1) ), hTop*devicePixelRatio( _pixmaps.at(1) ) ); + if( tiles&Bottom ) painter->drawPixmap(x1, y2, w, hBottom, _pixmaps.at(7), 0, (_h3-hBottom)*devicePixelRatio( _pixmaps.at(7) ), w2*devicePixelRatio( _pixmaps.at(7) ), hBottom*devicePixelRatio( _pixmaps.at(7) ) ); + } + + // left and right + if( h > 0 ) + { + if( tiles&Left ) painter->drawPixmap(x0, y1, wLeft, h, _pixmaps.at(3), 0, 0, wLeft*devicePixelRatio( _pixmaps.at(3) ), h2*devicePixelRatio( _pixmaps.at(3) ) ); + if( tiles&Right ) painter->drawPixmap(x2, y1, wRight, h, _pixmaps.at(5), (_w3-wRight)*devicePixelRatio( _pixmaps.at(5) ), 0, wRight*devicePixelRatio( _pixmaps.at(5) ), h2*devicePixelRatio( _pixmaps.at(5) ) ); + } + + // center + if( (tiles&Center) && h > 0 && w > 0 ) painter->drawPixmap(x1, y1, w, h, _pixmaps.at(4)); + + // restore + painter->setRenderHint( QPainter::SmoothPixmapTransform, oldHint ); + + } + +} diff --git a/style/adwaitatileset.h b/style/adwaitatileset.h new file mode 100644 index 0000000..f53cf88 --- /dev/null +++ b/style/adwaitatileset.h @@ -0,0 +1,125 @@ +#ifndef adwaitatileset_h +#define adwaitatileset_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 + +//* handles proper scaling of pixmap to match widget rect. +/** +tilesets are collections of stretchable pixmaps corresponding to a given widget corners, sides, and center. +corner pixmaps are never stretched. center pixmaps are +*/ +namespace Adwaita +{ + class TileSet + { + public: + /** + Create a TileSet from a pixmap. The size of the bottom/right chunks is + whatever is left over from the other chunks, whose size is specified + in the required parameters. + + @param w1 width of the left chunks + @param h1 height of the top chunks + @param w2 width of the not-left-or-right chunks + @param h2 height of the not-top-or-bottom chunks + */ + TileSet(const QPixmap&, int w1, int h1, int w2, int h2 ); + + //* empty constructor + TileSet(); + + //* destructor + virtual ~TileSet() + {} + + /** + Flags specifying what sides to draw in ::render. Corners are drawn when + the sides forming that corner are drawn, e.g. Top|Left draws the + top-center, center-left, and top-left chunks. The center-center chunk is + only drawn when Center is requested. + */ + enum Tile { + Top = 0x1, + Left = 0x2, + Bottom = 0x4, + Right = 0x8, + Center = 0x10, + TopLeft = Top|Left, + TopRight = Top|Right, + BottomLeft = Bottom|Left, + BottomRight = Bottom|Right, + Ring = Top|Left|Bottom|Right, + Horizontal = Left|Right|Center, + Vertical = Top|Bottom|Center, + Full = Ring|Center + }; + Q_DECLARE_FLAGS(Tiles, Tile) + + /** + Fills the specified rect with tiled chunks. Corners are never tiled, + edges are tiled in one direction, and the center chunk is tiled in both + directions. Partial tiles are used as needed so that the entire rect is + perfectly filled. Filling is performed as if all chunks are being drawn. + */ + void render(const QRect&, QPainter*, Tiles = Ring) const; + + //* return size associated to this tileset + QSize size( void ) const + { return QSize( _w1 + _w3, _h1 + _h3 ); } + + //* is valid + bool isValid( void ) const + { return _pixmaps.size() == 9; } + + //* returns pixmap for given index + QPixmap pixmap( int index ) const + { return _pixmaps[index]; } + + protected: + + //* shortcut to pixmap list + using PixmapList = QVector; + + //* initialize pixmap + void initPixmap( PixmapList&, const QPixmap&, int w, int h, const QRect& ); + + private: + + //* pixmap arry + PixmapList _pixmaps; + + // dimensions + int _w1; + int _h1; + int _w3; + int _h3; + + }; + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(Adwaita::TileSet::Tiles) + +#endif //TILESET_H diff --git a/style/adwaitawindowmanager.cpp b/style/adwaitawindowmanager.cpp new file mode 100644 index 0000000..3faefcd --- /dev/null +++ b/style/adwaitawindowmanager.cpp @@ -0,0 +1,927 @@ +/************************************************************************* + * 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 . * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////////// +// adwaitawindowmanager.cpp +// pass some window mouse press/release/move event actions to window manager +// ------------------- +// +// Copyright (c) 2014 Hugo Pereira Da Costa +// +// Largely inspired from BeSpin style +// Copyright (C) 2007 Thomas Luebking +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitawindowmanager.h" +#include "adwaitapropertynames.h" +#include "fakeadwaitastyleconfigdata.h" +#include "adwaitahelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if QT_VERSION >= 0x050300 +// needed to deal with device pixel ratio +#include +#endif + +#if ADWAITA_HAVE_X11 +#include +#include + +#if ADWAITA_USE_KDE4 +#include +#else +#include +#endif + +#endif + +#if ADWAITA_HAVE_KWAYLAND +#include +#include +#include +#include +#include +#endif + +namespace Adwaita +{ + + //* provide application-wise event filter + /** + it us used to unlock dragging and make sure event look is properly restored + after a drag has occurred + */ + class AppEventFilter: public QObject + { + + public: + + //* constructor + explicit AppEventFilter( WindowManager* parent ): + QObject( parent ), + _parent( parent ) + {} + + //* event filter + virtual bool eventFilter( QObject* object, QEvent* event ) + { + + if( event->type() == QEvent::MouseButtonRelease ) + { + + // stop drag timer + if( _parent->_dragTimer.isActive() ) + { _parent->resetDrag(); } + + // unlock + if( _parent->isLocked() ) + { _parent->setLocked( false ); } + + } + + if( !_parent->enabled() ) return false; + + /* + if a drag is in progress, the widget will not receive any event + we trigger on the first MouseMove or MousePress events that are received + by any widget in the application to detect that the drag is finished + */ + if( _parent->useWMMoveResize() && _parent->_dragInProgress && _parent->_target && ( event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress ) ) + { return appMouseEvent( object, event ); } + + return false; + + } + + protected: + + //* application-wise event. + /** needed to catch end of XMoveResize events */ + bool appMouseEvent( QObject*, QEvent* event ) + { + + #if ADWAITA_USE_KDE4 + // store target window (see later) + QWidget* window( _parent->_target.data()->window() ); + #else + Q_UNUSED( event ); + #endif + + /* + post some mouseRelease event to the target, in order to counter balance + the mouse press that triggered the drag. Note that it triggers a resetDrag + */ + QMouseEvent mouseEvent( QEvent::MouseButtonRelease, _parent->_dragPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier ); + qApp->sendEvent( _parent->_target.data(), &mouseEvent ); + + #if ADWAITA_USE_KDE4 + if( event->type() == QEvent::MouseMove ) + { + /* + HACK: quickly move the main cursor out of the window and back + this is needed to get the focus right for the window children + the origin of this issue is unknown at the moment. + This apparently got fixed with qt5 + */ + QPoint cursor = QCursor::pos(); + QCursor::setPos(window->mapToGlobal( window->rect().topRight() ) + QPoint(1, 0) ); + QCursor::setPos(cursor); + + } + #endif + + return false; + + } + + private: + + //* parent + WindowManager* _parent; + + }; + + //_____________________________________________________________ + WindowManager::WindowManager( QObject* parent ): + QObject( parent ), + _enabled( true ), + _useWMMoveResize( true ), + _dragMode( StyleConfigData::WD_FULL ), + _dragDistance( QApplication::startDragDistance() ), + _dragDelay( QApplication::startDragTime() ), + _dragAboutToStart( false ), + _dragInProgress( false ), + _locked( false ), + _cursorOverride( false ) + #if ADWAITA_HAVE_KWAYLAND + , _seat( Q_NULLPTR ) + , _pointer( Q_NULLPTR ) + , _waylandSerial( 0 ) + #endif + { + + // install application wise event filter + _appEventFilter = new AppEventFilter( this ); + qApp->installEventFilter( _appEventFilter ); + + } + + //_____________________________________________________________ + void WindowManager::initialize( void ) + { + + setEnabled( StyleConfigData::windowDragMode() != StyleConfigData::WD_NONE ); + setDragMode( StyleConfigData::windowDragMode() ); + setUseWMMoveResize( StyleConfigData::useWMMoveResize() ); + + setDragDistance( QApplication::startDragDistance() ); + setDragDelay( QApplication::startDragTime() ); + + initializeWhiteList(); + initializeBlackList(); + initializeWayland(); + + } + + //_______________________________________________________ + void WindowManager::initializeWayland() + { + #if ADWAITA_HAVE_KWAYLAND + if( !Helper::isWayland() ) return; + + if( _seat ) { + // already initialized + return; + } + + using namespace KWayland::Client; + auto connection = ConnectionThread::fromApplication( this ); + if( !connection ) { + return; + } + Registry *registry = new Registry( this ); + registry->create( connection ); + connect(registry, &Registry::interfacesAnnounced, this, + [registry, this] { + auto interface = registry->interface( Registry::Interface::Seat ); + if( interface.name != 0 ) { + _seat = registry->createSeat( interface.name, interface.version, this ); + connect(_seat, &Seat::hasPointerChanged, this, &WindowManager::waylandHasPointerChanged); + } + } + ); + + registry->setup(); + connection->roundtrip(); + #endif + } + + //_______________________________________________________ + void WindowManager::waylandHasPointerChanged(bool hasPointer) + { + #if ADWAITA_HAVE_KWAYLAND + Q_ASSERT( _seat ); + if( hasPointer ) { + if( !_pointer ) { + _pointer = _seat->createPointer(this); + connect(_pointer, &KWayland::Client::Pointer::buttonStateChanged, this, + [this] (quint32 serial) { + _waylandSerial = serial; + } + ); + } + } else { + delete _pointer; + _pointer = nullptr; + } + #else + Q_UNUSED( hasPointer ); + #endif + } + + //_____________________________________________________________ + void WindowManager::registerWidget( QWidget* widget ) + { + + if( isBlackListed( widget ) || isDragable( widget ) ) + { + + /* + install filter for dragable widgets. + also install filter for blacklisted widgets + to be able to catch the relevant events and prevent + the drag to happen + */ + widget->removeEventFilter( this ); + widget->installEventFilter( this ); + + } + + } + + //_____________________________________________________________ + void WindowManager::unregisterWidget( QWidget* widget ) + { + if( widget ) + { widget->removeEventFilter( this ); } + } + + //_____________________________________________________________ + void WindowManager::initializeWhiteList( void ) + { + + _whiteList.clear(); + + // add user specified whitelisted classnames + _whiteList.insert( ExceptionId( QStringLiteral( "MplayerWindow" ) ) ); + _whiteList.insert( ExceptionId( QStringLiteral( "ViewSliders@kmix" ) ) ); + _whiteList.insert( ExceptionId( QStringLiteral( "Sidebar_Widget@konqueror" ) ) ); + + foreach( const QString& exception, StyleConfigData::windowDragWhiteList() ) + { + ExceptionId id( exception ); + if( !id.className().isEmpty() ) + { _whiteList.insert( ExceptionId( exception ) ); } + } + } + + //_____________________________________________________________ + void WindowManager::initializeBlackList( void ) + { + + _blackList.clear(); + _blackList.insert( ExceptionId( QStringLiteral( "CustomTrackView@kdenlive" ) ) ); + _blackList.insert( ExceptionId( QStringLiteral( "MuseScore" ) ) ); + _blackList.insert( ExceptionId( QStringLiteral( "KGameCanvasWidget" ) ) ); + foreach( const QString& exception, StyleConfigData::windowDragBlackList() ) + { + ExceptionId id( exception ); + if( !id.className().isEmpty() ) + { _blackList.insert( ExceptionId( exception ) ); } + } + + } + + //_____________________________________________________________ + bool WindowManager::eventFilter( QObject* object, QEvent* event ) + { + if( !enabled() ) return false; + + switch ( event->type() ) + { + case QEvent::MouseButtonPress: + return mousePressEvent( object, event ); + break; + + case QEvent::MouseMove: + if ( object == _target.data() ) return mouseMoveEvent( object, event ); + break; + + case QEvent::MouseButtonRelease: + if ( _target ) return mouseReleaseEvent( object, event ); + break; + + default: + break; + + } + + return false; + + } + + //_____________________________________________________________ + void WindowManager::timerEvent( QTimerEvent* event ) + { + + if( event->timerId() == _dragTimer.timerId() ) + { + + _dragTimer.stop(); + if( _target ) + { startDrag( _target.data(), _globalDragPoint ); } + + } else { + + return QObject::timerEvent( event ); + + } + + } + + //_____________________________________________________________ + bool WindowManager::mousePressEvent( QObject* object, QEvent* event ) + { + + // cast event and check buttons/modifiers + QMouseEvent *mouseEvent = static_cast( event ); + if( !( mouseEvent->modifiers() == Qt::NoModifier && mouseEvent->button() == Qt::LeftButton ) ) + { return false; } + + // check lock + if( isLocked() ) return false; + else setLocked( true ); + + // cast to widget + QWidget *widget = static_cast( object ); + + // check if widget can be dragged from current position + if( isBlackListed( widget ) || !canDrag( widget ) ) return false; + + // retrieve widget's child at event position + QPoint position( mouseEvent->pos() ); + QWidget* child = widget->childAt( position ); + if( !canDrag( widget, child, position ) ) return false; + + // save target and drag point + _target = widget; + _dragPoint = position; + _globalDragPoint = mouseEvent->globalPos(); + _dragAboutToStart = true; + + // send a move event to the current child with same position + // if received, it is caught to actually start the drag + QPoint localPoint( _dragPoint ); + if( child ) localPoint = child->mapFrom( widget, localPoint ); + else child = widget; + QMouseEvent localMouseEvent( QEvent::MouseMove, localPoint, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier ); + qApp->sendEvent( child, &localMouseEvent ); + + // never eat event + return false; + + } + + //_____________________________________________________________ + bool WindowManager::mouseMoveEvent( QObject* object, QEvent* event ) + { + + Q_UNUSED( object ); + + // stop timer + if( _dragTimer.isActive() ) _dragTimer.stop(); + + // cast event and check drag distance + QMouseEvent *mouseEvent = static_cast( event ); + if( !_dragInProgress ) + { + + if( _dragAboutToStart ) + { + if( mouseEvent->pos() == _dragPoint ) + { + // start timer, + _dragAboutToStart = false; + if( _dragTimer.isActive() ) _dragTimer.stop(); + _dragTimer.start( _dragDelay, this ); + + } else resetDrag(); + + } else if( QPoint( mouseEvent->globalPos() - _globalDragPoint ).manhattanLength() >= _dragDistance ) { + + _dragTimer.start( 0, this ); + + } + + return true; + + } else if( !useWMMoveResize() ) { + + // use QWidget::move for the grabbing + /* this works only if the sending object and the target are identical */ + QWidget* window( _target.data()->window() ); + window->move( window->pos() + mouseEvent->pos() - _dragPoint ); + return true; + + } else return false; + + } + + //_____________________________________________________________ + bool WindowManager::mouseReleaseEvent( QObject* object, QEvent* event ) + { + + Q_UNUSED( object ); + Q_UNUSED( event ); + resetDrag(); + return false; + } + + //_____________________________________________________________ + bool WindowManager::isDragable( QWidget* widget ) + { + + // check widget + if( !widget ) return false; + + // accepted default types + if( + ( qobject_cast( widget ) && widget->isWindow() ) || + ( qobject_cast( widget ) && widget->isWindow() ) || + qobject_cast( widget ) ) + { return true; } + + // more accepted types, provided they are not dock widget titles + if( ( qobject_cast( widget ) || + qobject_cast( widget ) || + qobject_cast( widget ) || + qobject_cast( widget ) ) && + !isDockWidgetTitle( widget ) ) + { return true; } + + if( widget->inherits( "KScreenSaver" ) && widget->inherits( "KCModule" ) ) + { return true; } + + if( isWhiteListed( widget ) ) + { return true; } + + // flat toolbuttons + if( QToolButton* toolButton = qobject_cast( widget ) ) + { if( toolButton->autoRaise() ) return true; } + + // viewports + /* + one needs to check that + 1/ the widget parent is a scrollarea + 2/ it matches its parent viewport + 3/ the parent is not blacklisted + */ + if( QListView* listView = qobject_cast( widget->parentWidget() ) ) + { if( listView->viewport() == widget && !isBlackListed( listView ) ) return true; } + + if( QTreeView* treeView = qobject_cast( widget->parentWidget() ) ) + { if( treeView->viewport() == widget && !isBlackListed( treeView ) ) return true; } + + /* + catch labels in status bars. + this is because of kstatusbar + who captures buttonPress/release events + */ + if( QLabel* label = qobject_cast( widget ) ) + { + if( label->textInteractionFlags().testFlag( Qt::TextSelectableByMouse ) ) return false; + + QWidget* parent = label->parentWidget(); + while( parent ) + { + if( qobject_cast( parent ) ) return true; + parent = parent->parentWidget(); + } + } + + return false; + + } + + //_____________________________________________________________ + bool WindowManager::isBlackListed( QWidget* widget ) + { + + // check against noAnimations propery + QVariant propertyValue( widget->property( PropertyNames::noWindowGrab ) ); + if( propertyValue.isValid() && propertyValue.toBool() ) return true; + + // list-based blacklisted widgets + QString appName( qApp->applicationName() ); + foreach( const ExceptionId& id, _blackList ) + { + if( !id.appName().isEmpty() && id.appName() != appName ) continue; + if( id.className() == QStringLiteral( "*" ) && !id.appName().isEmpty() ) + { + // if application name matches and all classes are selected + // disable the grabbing entirely + setEnabled( false ); + return true; + } + if( widget->inherits( id.className().toLatin1().data() ) ) return true; + } + + return false; + } + + //_____________________________________________________________ + bool WindowManager::isWhiteListed( QWidget* widget ) const + { + + QString appName( qApp->applicationName() ); + foreach( const ExceptionId& id, _whiteList ) + { + if( !id.appName().isEmpty() && id.appName() != appName ) continue; + if( widget->inherits( id.className().toLatin1().data() ) ) return true; + } + + return false; + } + + //_____________________________________________________________ + bool WindowManager::canDrag( QWidget* widget ) + { + + // check if enabled + if( !enabled() ) return false; + + // assume isDragable widget is already passed + // check some special cases where drag should not be effective + + // check mouse grabber + if( QWidget::mouseGrabber() ) return false; + + /* + check cursor shape. + Assume that a changed cursor means that some action is in progress + and should prevent the drag + */ + if( widget->cursor().shape() != Qt::ArrowCursor ) return false; + + // accept + return true; + + } + + //_____________________________________________________________ + bool WindowManager::canDrag( QWidget* widget, QWidget* child, const QPoint& position ) + { + + // retrieve child at given position and check cursor again + if( child && child->cursor().shape() != Qt::ArrowCursor ) return false; + + /* + check against children from which drag should never be enabled, + even if mousePress/Move has been passed to the parent + */ + if( child && ( + qobject_cast(child ) || + qobject_cast( child ) || + qobject_cast( child ) ) ) + { return false; } + + // tool buttons + if( QToolButton* toolButton = qobject_cast( widget ) ) + { + if( dragMode() == StyleConfigData::WD_MINIMAL && !qobject_cast(widget->parentWidget() ) ) return false; + return toolButton->autoRaise() && !toolButton->isEnabled(); + } + + // check menubar + if( QMenuBar* menuBar = qobject_cast( widget ) ) + { + + // do not drag from menubars embedded in Mdi windows + if( findParent( widget ) ) return false; + + // check if there is an active action + if( menuBar->activeAction() && menuBar->activeAction()->isEnabled() ) return false; + + // check if action at position exists and is enabled + if( QAction* action = menuBar->actionAt( position ) ) + { + if( action->isSeparator() ) return true; + if( action->isEnabled() ) return false; + } + + // return true in all other cases + return true; + + } + + /* + in MINIMAL mode, anything that has not been already accepted + and does not come from a toolbar is rejected + */ + if( dragMode() == StyleConfigData::WD_MINIMAL ) + { + if( qobject_cast( widget ) ) return true; + else return false; + } + + /* following checks are relevant only for WD_FULL mode */ + + // tabbar. Make sure no tab is under the cursor + if( QTabBar* tabBar = qobject_cast( widget ) ) + { return tabBar->tabAt( position ) == -1; } + + /* + check groupboxes + prevent drag if unchecking grouboxes + */ + if( QGroupBox *groupBox = qobject_cast( widget ) ) + { + // non checkable group boxes are always ok + if( !groupBox->isCheckable() ) return true; + + // gather options to retrieve checkbox subcontrol rect + QStyleOptionGroupBox opt; + opt.initFrom( groupBox ); + if( groupBox->isFlat() ) opt.features |= QStyleOptionFrameV2::Flat; + opt.lineWidth = 1; + opt.midLineWidth = 0; + opt.text = groupBox->title(); + opt.textAlignment = groupBox->alignment(); + opt.subControls = (QStyle::SC_GroupBoxFrame | QStyle::SC_GroupBoxCheckBox); + if (!groupBox->title().isEmpty()) opt.subControls |= QStyle::SC_GroupBoxLabel; + + opt.state |= (groupBox->isChecked() ? QStyle::State_On : QStyle::State_Off); + + // check against groupbox checkbox + if( groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxCheckBox, groupBox ).contains( position ) ) + { return false; } + + // check against groupbox label + if( !groupBox->title().isEmpty() && groupBox->style()->subControlRect(QStyle::CC_GroupBox, &opt, QStyle::SC_GroupBoxLabel, groupBox ).contains( position ) ) + { return false; } + + return true; + + } + + // labels + if( QLabel* label = qobject_cast( widget ) ) + { if( label->textInteractionFlags().testFlag( Qt::TextSelectableByMouse ) ) return false; } + + // abstract item views + QAbstractItemView* itemView( nullptr ); + if( + ( itemView = qobject_cast( widget->parentWidget() ) ) || + ( itemView = qobject_cast( widget->parentWidget() ) ) ) + { + if( widget == itemView->viewport() ) + { + // QListView + if( itemView->frameShape() != QFrame::NoFrame ) return false; + else if( + itemView->selectionMode() != QAbstractItemView::NoSelection && + itemView->selectionMode() != QAbstractItemView::SingleSelection && + itemView->model() && itemView->model()->rowCount() ) return false; + else if( itemView->model() && itemView->indexAt( position ).isValid() ) return false; + } + + } else if( ( itemView = qobject_cast( widget->parentWidget() ) ) ) { + + + if( widget == itemView->viewport() ) + { + // QAbstractItemView + if( itemView->frameShape() != QFrame::NoFrame ) return false; + else if( itemView->indexAt( position ).isValid() ) return false; + } + + } else if( QGraphicsView* graphicsView = qobject_cast( widget->parentWidget() ) ) { + + if( widget == graphicsView->viewport() ) + { + // QGraphicsView + if( graphicsView->frameShape() != QFrame::NoFrame ) return false; + else if( graphicsView->dragMode() != QGraphicsView::NoDrag ) return false; + else if( graphicsView->itemAt( position ) ) return false; + } + + } + + return true; + + } + + //____________________________________________________________ + void WindowManager::resetDrag( void ) + { + + if( (!useWMMoveResize() ) && _target && _cursorOverride ) { + + qApp->restoreOverrideCursor(); + _cursorOverride = false; + + } + + _target.clear(); + if( _dragTimer.isActive() ) _dragTimer.stop(); + _dragPoint = QPoint(); + _globalDragPoint = QPoint(); + _dragAboutToStart = false; + _dragInProgress = false; + + } + + //____________________________________________________________ + void WindowManager::startDrag( QWidget* widget, const QPoint& position ) + { + + if( !( enabled() && widget ) ) return; + if( QWidget::mouseGrabber() ) return; + + // ungrab pointer + if( useWMMoveResize() ) + { + + if( Helper::isX11() ) { + startDragX11( widget, position ); + } else if( Helper::isWayland() ) { + startDragWayland( widget, position ); + } + + } else if( !_cursorOverride ) { + + qApp->setOverrideCursor( Qt::SizeAllCursor ); + _cursorOverride = true; + + } + + _dragInProgress = true; + + return; + + } + + //_______________________________________________________ + void WindowManager::startDragX11( QWidget* widget, const QPoint& position ) + { + #if ADWAITA_HAVE_X11 + // connection + xcb_connection_t* connection( Helper::connection() ); + + // window + WId window( widget->window()->winId() ); + + #if QT_VERSION >= 0x050300 + qreal dpiRatio = 1; + QWindow* windowHandle = widget->window()->windowHandle(); + if( windowHandle ) dpiRatio = windowHandle->devicePixelRatio(); + else dpiRatio = qApp->devicePixelRatio(); + dpiRatio = qApp->devicePixelRatio(); + #else + qreal dpiRatio = 1; + #endif + + #if ADWAITA_USE_KDE4 + Display* net_connection = QX11Info::display(); + #else + xcb_connection_t* net_connection = connection; + #endif + + xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME ); + NETRootInfo( net_connection, NET::WMMoveResize ).moveResizeRequest( + window, position.x() * dpiRatio, + position.y() * dpiRatio, + NET::Move ); + + #else + + Q_UNUSED( widget ); + Q_UNUSED( position ); + + #endif + } + + //_______________________________________________________ + void WindowManager::startDragWayland( QWidget* widget, const QPoint& position ) + { + #if ADWAITA_HAVE_KWAYLAND + if( !_seat ) { + return; + } + /* TODO RETURN THIS + QWindow* windowHandle = widget->window()->windowHandle(); + auto shellSurface = KWayland::Client::ShellSurface::fromWindow(windowHandle); + if( !shellSurface ) { + // TODO: also check for xdg-shell in future + return; + } + + shellSurface->requestMove( _seat, _waylandSerial ); + */ + #else + Q_UNUSED( widget ); + Q_UNUSED( position ); + #endif + } + + //____________________________________________________________ + bool WindowManager::supportWMMoveResize( void ) const + { + + #if ADWAITA_HAVE_KWAYLAND + if( Helper::isWayland() ) { + return true; + } + #endif + + #if ADWAITA_HAVE_X11 + return Helper::isX11(); + #else + return false; + #endif + + } + + //____________________________________________________________ + bool WindowManager::isDockWidgetTitle( const QWidget* widget ) const + { + + if( !widget ) return false; + if( const QDockWidget* dockWidget = qobject_cast( widget->parent() ) ) + { + + return widget == dockWidget->titleBarWidget(); + + } else return false; + + } + +} diff --git a/style/adwaitawindowmanager.h b/style/adwaitawindowmanager.h new file mode 100644 index 0000000..0f997ff --- /dev/null +++ b/style/adwaitawindowmanager.h @@ -0,0 +1,310 @@ +#ifndef adwaitawindowmanager_h +#define adwaitawindowmanager_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 "adwaita.h" +#include "config-adwaita.h" + +#include + +#include +#include +#include +#include +#include + +#if ADWAITA_HAVE_KWAYLAND +namespace KWayland +{ +namespace Client +{ + class Pointer; + class Seat; +} +} +#endif + +namespace Adwaita +{ + + class WindowManager: public QObject + { + + Q_OBJECT + + public: + + //* constructor + explicit WindowManager( QObject* ); + + //* destructor + virtual ~WindowManager( void ) + {} + + //* initialize + /** read relevant options from config */ + void initialize( void ); + + //* register widget + void registerWidget( QWidget* ); + + //* unregister widget + void unregisterWidget( QWidget* ); + + //* event filter [reimplemented] + virtual bool eventFilter( QObject*, QEvent* ); + + protected: + + //* timer event, + /** used to start drag if button is pressed for a long enough time */ + void timerEvent( QTimerEvent* ); + + //* mouse press event + bool mousePressEvent( QObject*, QEvent* ); + + //* mouse move event + bool mouseMoveEvent( QObject*, QEvent* ); + + //* mouse release event + bool mouseReleaseEvent( QObject*, QEvent* ); + + //*@name configuration + //@{ + + //* enable state + bool enabled( void ) const + { return _enabled; } + + //* enable state + void setEnabled( bool value ) + { _enabled = value; } + + //* returns true if window manager is used for moving + bool useWMMoveResize( void ) const + { return supportWMMoveResize() && _useWMMoveResize; } + + //* use window manager for moving, when available + void setUseWMMoveResize( bool value ) + { _useWMMoveResize = value; } + + //* drag mode + int dragMode( void ) const + { return _dragMode; } + + //* drag mode + void setDragMode( int value ) + { _dragMode = value; } + + //* drag distance (pixels) + void setDragDistance( int value ) + { _dragDistance = value; } + + //* drag delay (msec) + void setDragDelay( int value ) + { _dragDelay = value; } + + //* set list of whiteListed widgets + /** + white list is read from options and is used to adjust + per-app window dragging issues + */ + void initializeWhiteList(); + + //* set list of blackListed widgets + /** + black list is read from options and is used to adjust + per-app window dragging issues + */ + void initializeBlackList( void ); + + //* initializes the Wayland specific parts + void initializeWayland(); + + //* The Wayland Seat's hasPointer property changed + void waylandHasPointerChanged(bool hasPointer); + + //@} + + //* returns true if widget is dragable + bool isDragable( QWidget* ); + + //* returns true if widget is dragable + bool isBlackListed( QWidget* ); + + //* returns true if widget is dragable + bool isWhiteListed( QWidget* ) const; + + //* returns true if drag can be started from current widget + bool canDrag( QWidget* ); + + //* returns true if drag can be started from current widget and position + /** child at given position is passed as second argument */ + bool canDrag( QWidget*, QWidget*, const QPoint& ); + + //* reset drag + void resetDrag( void ); + + //* start drag + void startDrag( QWidget*, const QPoint& ); + + //* X11 specific implementation for startDrag + void startDragX11( QWidget*, const QPoint& ); + + //* Wayland specific implementation for startDrag + void startDragWayland( QWidget*, const QPoint& ); + + //* returns true if window manager is used for moving + /** right now this is true only for X11 */ + bool supportWMMoveResize( void ) const; + + //* utility function + bool isDockWidgetTitle( const QWidget* ) const; + + //*@name lock + //@{ + + void setLocked( bool value ) + { _locked = value; } + + //* lock + bool isLocked( void ) const + { return _locked; } + + //@} + + //* returns first widget matching given class, or 0L if none + template T findParent( const QWidget* ) const; + + private: + + //* enability + bool _enabled; + + //* use WM moveResize + bool _useWMMoveResize; + + //* drag mode + int _dragMode; + + //* drag distance + /** this is copied from kwin::geometry */ + int _dragDistance; + + //* drag delay + /** this is copied from kwin::geometry */ + int _dragDelay; + + //* wrapper for exception id + class ExceptionId: public QPair + { + public: + + //* constructor + explicit ExceptionId( const QString& value ) + { + const QStringList args( value.split( QChar::fromLatin1( '@' ) ) ); + if( args.isEmpty() ) return; + second = args[0].trimmed(); + if( args.size()>1 ) first = args[1].trimmed(); + } + + const QString& appName( void ) const + { return first; } + + const QString& className( void ) const + { return second; } + + }; + + //* exception set + using ExceptionSet = QSet; + + //* list of white listed special widgets + /** + it is read from options and is used to adjust + per-app window dragging issues + */ + ExceptionSet _whiteList; + + //* list of black listed special widgets + /** + it is read from options and is used to adjust + per-app window dragging issues + */ + ExceptionSet _blackList; + + //* drag point + QPoint _dragPoint; + QPoint _globalDragPoint; + + //* drag timer + QBasicTimer _dragTimer; + + //* target being dragged + /** Weak pointer is used in case the target gets deleted while drag is in progress */ + WeakPointer _target; + + //* true if drag is about to start + bool _dragAboutToStart; + + //* true if drag is in progress + bool _dragInProgress; + + //* true if drag is locked + bool _locked; + + //* cursor override + /** used to keep track of application cursor being overridden when dragging in non-WM mode */ + bool _cursorOverride; + + //* application event filter + QObject* _appEventFilter; + + #if ADWAITA_HAVE_KWAYLAND + //* The Wayland seat object which needs to be passed to move requests. + KWayland::Client::Seat* _seat; + //* The Wayland pointer object where we get pointer events on. + KWayland::Client::Pointer* _pointer; + //* latest searial which needs to be passed to the move requests. + quint32 _waylandSerial; + #endif + + //* allow access of all private members to the app event filter + friend class AppEventFilter; + + }; + + //____________________________________________________________________ + template + T WindowManager::findParent( const QWidget* widget ) const + { + + if( !widget ) return 0L; + for( QWidget* parent = widget->parentWidget(); parent; parent = parent->parentWidget() ) + { if( T cast = qobject_cast(parent) ) return cast; } + + return 0L; + } + +} + +#endif diff --git a/style/animations/adwaitaanimation.cpp b/style/animations/adwaitaanimation.cpp new file mode 100644 index 0000000..fe46556 --- /dev/null +++ b/style/animations/adwaitaanimation.cpp @@ -0,0 +1,20 @@ +/************************************************************************* + * 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 "adwaitaanimation.h" diff --git a/style/animations/adwaitaanimation.h b/style/animations/adwaitaanimation.h new file mode 100644 index 0000000..436d9bd --- /dev/null +++ b/style/animations/adwaitaanimation.h @@ -0,0 +1,63 @@ +#ifndef adwaitaanimation_h +#define adwaitaanimation_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 "adwaita.h" + +#include +#include + +namespace Adwaita +{ + + class Animation: public QPropertyAnimation + { + + Q_OBJECT + + public: + + //* convenience + using Pointer = WeakPointer; + + //* constructor + Animation( int duration, QObject* parent ): + QPropertyAnimation( parent ) + { setDuration( duration ); } + + //* destructor + virtual ~Animation( void ) = default; + + //* true if running + bool isRunning( void ) const + { return state() == Animation::Running; } + + //* restart + void restart( void ) + { + if( isRunning() ) stop(); + start(); + } + + }; + +} + +#endif diff --git a/style/animations/adwaitaanimationdata.cpp b/style/animations/adwaitaanimationdata.cpp new file mode 100644 index 0000000..035bbaf --- /dev/null +++ b/style/animations/adwaitaanimationdata.cpp @@ -0,0 +1,40 @@ +/************************************************************************* + * 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 "adwaitaanimationdata.h" + +namespace Adwaita +{ + + const qreal AnimationData::OpacityInvalid = -1; + int AnimationData::_steps = 0; + + //_________________________________________________________________________________ + void AnimationData::setupAnimation( const Animation::Pointer& animation, const QByteArray& property ) + { + + // setup animation + animation.data()->setStartValue( 0.0 ); + animation.data()->setEndValue( 1.0 ); + animation.data()->setTargetObject( this ); + animation.data()->setPropertyName( property ); + + } + +} diff --git a/style/animations/adwaitaanimationdata.h b/style/animations/adwaitaanimationdata.h new file mode 100644 index 0000000..03f7dde --- /dev/null +++ b/style/animations/adwaitaanimationdata.h @@ -0,0 +1,106 @@ +#ifndef adwaita_animationdata_h +#define adwaita_animationdata_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 "adwaitaanimation.h" + +#include +#include +#include + +#include + +namespace Adwaita +{ + + //* base class + class AnimationData: public QObject + { + + Q_OBJECT + + public: + + //* constructor + AnimationData( QObject* parent, QWidget* target ): + QObject( parent ), + _target( target ), + _enabled( true ) + { Q_ASSERT( _target ); } + + //* destructor + virtual ~AnimationData( void ) + {} + + //* duration + virtual void setDuration( int ) = 0; + + //* steps + static void setSteps( int value ) + { _steps = value; } + + //* enability + virtual bool enabled( void ) const + { return _enabled; } + + //* enability + virtual void setEnabled( bool value ) + { _enabled = value; } + + //* target + const WeakPointer& target( void ) const + { return _target; } + + //* invalid opacity + static const qreal OpacityInvalid; + + protected: + + //* setup animation + virtual void setupAnimation( const Animation::Pointer& animation, const QByteArray& property ); + + //* apply step + virtual qreal digitize( const qreal& value ) const + { + if( _steps > 0 ) return std::floor( value*_steps )/_steps; + else return value; + } + + //* trigger target update + virtual void setDirty( void ) const + { if( _target ) _target.data()->update(); } + + private: + + //* guarded target + WeakPointer _target; + + //* enability + bool _enabled; + + //* steps + static int _steps; + + }; + +} + +#endif diff --git a/style/animations/adwaitaanimations.cpp b/style/animations/adwaitaanimations.cpp new file mode 100644 index 0000000..141157d --- /dev/null +++ b/style/animations/adwaitaanimations.cpp @@ -0,0 +1,231 @@ +/************************************************************************* + * 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 "adwaitaanimations.h" +#include "adwaitapropertynames.h" +#include "fakeadwaitastyleconfigdata.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Adwaita +{ + + //____________________________________________________________ + 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 ) ); + + } + + //____________________________________________________________ + void Animations::setupEngines( void ) + { + + // animation steps + AnimationData::setSteps( StyleConfigData::animationSteps() ); + + bool animationsEnabled( StyleConfigData::animationsEnabled() ); + 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|AnimationPressed ); + _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationPressed ); + + } else if( qobject_cast(widget) || qobject_cast(widget) ) { + + _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus|AnimationPressed ); + + } else if( qobject_cast(widget) ) { + + // register to toolbox engine if needed + if( qobject_cast( widget->parent() ) ) + { _toolBoxEngine->registerWidget( widget ); } + + _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationPressed ); + + } + + // groupboxes + else if( QGroupBox* groupBox = qobject_cast( widget ) ) + { + if( groupBox->isCheckable() ) + { _widgetStateEngine->registerWidget( widget, AnimationHover|AnimationFocus ); } + } + + // 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|AnimationPressed ); + _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus|AnimationPressed ); + } + + // spinbox + else if( qobject_cast( widget ) ) { + _spinBoxEngine->registerWidget( widget ); + _inputWidgetEngine->registerWidget( widget, AnimationHover|AnimationFocus|AnimationPressed ); + } + + // 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 ); } + + return; + + } + + //____________________________________________________________ + 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/style/animations/adwaitaanimations.h b/style/animations/adwaitaanimations.h new file mode 100644 index 0000000..7bfff42 --- /dev/null +++ b/style/animations/adwaitaanimations.h @@ -0,0 +1,166 @@ +#ifndef adwaitaanimations_h +#define adwaitaanimations_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 "adwaitabusyindicatorengine.h" +#include "adwaitadialengine.h" +#include "adwaitaheaderviewengine.h" +#include "adwaitascrollbarengine.h" +#include "adwaitaspinboxengine.h" +#include "adwaitastackedwidgetengine.h" +#include "adwaitatabbarengine.h" +#include "adwaitatoolboxengine.h" +#include "adwaitawidgetstateengine.h" + +#include +#include + +namespace Adwaita +{ + + //* stores engines + class Animations: public QObject + { + + Q_OBJECT + + public: + + //* constructor + explicit Animations( QObject* ); + + //* destructor + virtual ~Animations( void ) + {} + + //* 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( void ) const + { return *_widgetEnabilityEngine; } + + //* abstractButton engine + WidgetStateEngine& widgetStateEngine( void ) const + { return *_widgetStateEngine; } + + //* editable combobox arrow hover engine + WidgetStateEngine& comboBoxEngine( void ) const + { return *_comboBoxEngine; } + + //! Tool buttons arrow hover engine + WidgetStateEngine& toolButtonEngine( void ) const + { return *_toolButtonEngine; } + + //! item view engine + WidgetStateEngine& inputWidgetEngine( void ) const + { return *_inputWidgetEngine; } + + //* busy indicator + BusyIndicatorEngine& busyIndicatorEngine( void ) const + { return *_busyIndicatorEngine; } + + //* header view engine + HeaderViewEngine& headerViewEngine( void ) const + { return *_headerViewEngine; } + + //* scrollbar engine + ScrollBarEngine& scrollBarEngine( void ) const + { return *_scrollBarEngine; } + + //* dial engine + DialEngine& dialEngine( void ) const + { return *_dialEngine; } + + //* spinbox engine + SpinBoxEngine& spinBoxEngine( void ) const + { return *_spinBoxEngine; } + + //* tabbar + TabBarEngine& tabBarEngine( void ) const + { return *_tabBarEngine; } + + //* toolbox + ToolBoxEngine& toolBoxEngine( void ) const + { return *_toolBoxEngine; } + + //* setup engines + void setupEngines( void ); + + protected Q_SLOTS: + + //* enregister engine + void unregisterEngine( QObject* ); + private: + + //* register new engine + void registerEngine( BaseEngine* engine ); + + //* busy indicator + BusyIndicatorEngine* _busyIndicatorEngine; + + //* headerview hover effect + HeaderViewEngine* _headerViewEngine; + + //* widget enability engine + WidgetStateEngine* _widgetEnabilityEngine; + + //* abstract button engine + WidgetStateEngine* _widgetStateEngine; + + //* editable combobox arrow hover effect + WidgetStateEngine* _comboBoxEngine; + + //! mennu toolbutton arrow hover effect + WidgetStateEngine* _toolButtonEngine; + + //! item view engine + WidgetStateEngine* _inputWidgetEngine; + + //* scrollbar engine + ScrollBarEngine* _scrollBarEngine; + + //* dial engine + DialEngine* _dialEngine; + + //* spinbox engine + SpinBoxEngine* _spinBoxEngine; + + //* stacked widget engine + StackedWidgetEngine* _stackedWidgetEngine; + + //* tabbar engine + TabBarEngine* _tabBarEngine; + + //* toolbar engine + ToolBoxEngine* _toolBoxEngine; + + //* keep list of existing engines + QList< BaseEngine::Pointer > _engines; + + }; + +} + +#endif diff --git a/style/animations/adwaitabaseengine.cpp b/style/animations/adwaitabaseengine.cpp new file mode 100644 index 0000000..7ded79a --- /dev/null +++ b/style/animations/adwaitabaseengine.cpp @@ -0,0 +1,20 @@ +/************************************************************************* + * 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 "adwaitabaseengine.h" diff --git a/style/animations/adwaitabaseengine.h b/style/animations/adwaitabaseengine.h new file mode 100644 index 0000000..a6b2b09 --- /dev/null +++ b/style/animations/adwaitabaseengine.h @@ -0,0 +1,91 @@ +#ifndef adwaitabaseengine_h +#define adwaitabaseengine_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 "adwaita.h" + +#include +#include + +namespace Adwaita +{ + + //* base class for all animation engines + /** it is used to store configuration values used by all animations stored in the engine */ + class BaseEngine: public QObject + { + + Q_OBJECT + + public: + + using Pointer = WeakPointer; + + //* constructor + explicit BaseEngine( QObject* parent ): + QObject( parent ), + _enabled( true ), + _duration( 200 ) + {} + + //* destructor + virtual ~BaseEngine( void ) + {} + + //* enability + virtual void setEnabled( bool value ) + { _enabled = value; } + + //* enability + virtual bool enabled( void ) const + { return _enabled; } + + //* duration + virtual void setDuration( int value ) + { _duration = value; } + + //* duration + virtual int duration( void ) const + { return _duration; } + + //* unregister widget + virtual bool unregisterWidget( QObject* object ) = 0; + + //* list of widgets + using WidgetList = QSet; + + //* returns registered widgets + virtual WidgetList registeredWidgets( void ) const + { return WidgetList(); } + + private: + + //* engine enability + bool _enabled; + + //* animation duration + int _duration; + + }; + +} + +#endif diff --git a/style/animations/adwaitabusyindicatordata.cpp b/style/animations/adwaitabusyindicatordata.cpp new file mode 100644 index 0000000..ebe3340 --- /dev/null +++ b/style/animations/adwaitabusyindicatordata.cpp @@ -0,0 +1,20 @@ +/************************************************************************* + * 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 "adwaitabusyindicatordata.h" diff --git a/style/animations/adwaitabusyindicatordata.h b/style/animations/adwaitabusyindicatordata.h new file mode 100644 index 0000000..e6d3148 --- /dev/null +++ b/style/animations/adwaitabusyindicatordata.h @@ -0,0 +1,80 @@ +#ifndef adwaitabusyindicatordata_h +#define adwaitabusyindicatordata_h + +/************************************************************************* + * Copyright (C) 2014 by Hugo Pereira Da Costa * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + *************************************************************************/ + +#include + +namespace Adwaita +{ + + class BusyIndicatorData: public QObject + { + + Q_OBJECT + + public: + + //* constructor + explicit BusyIndicatorData( QObject* parent ): + QObject( parent ), + _animated( false ) + {} + + //* destructor + virtual ~BusyIndicatorData( void ) + {} + + //*@name accessors + //@{ + + //* animated + bool isAnimated( void ) const + { return _animated; } + + //@} + + //*@name modifiers + //@{ + + //* enabled + void setEnabled( bool ) + {} + + //* enabled + void setDuration( int ) + {} + + //* animated + void setAnimated( bool value ) + { _animated = value; } + + //@} + + private: + + //* animated + bool _animated; + + }; + +} + +#endif diff --git a/style/animations/adwaitabusyindicatorengine.cpp b/style/animations/adwaitabusyindicatorengine.cpp new file mode 100644 index 0000000..dc957d8 --- /dev/null +++ b/style/animations/adwaitabusyindicatorengine.cpp @@ -0,0 +1,181 @@ +/************************************************************************* + * Copyright (C) 2014 by Hugo Pereira Da Costa * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + *************************************************************************/ + +#include "adwaitabusyindicatorengine.h" + +#include "adwaita.h" + +#include + +namespace Adwaita +{ + + //_______________________________________________ + BusyIndicatorEngine::BusyIndicatorEngine( QObject* object ): + BaseEngine( object ) + {} + + //_______________________________________________ + bool BusyIndicatorEngine::registerWidget( QObject* object ) + { + + // check widget validity + if( !object ) return false; + + // create new data class + if( !_data.contains( object ) ) + { + _data.insert( object, new BusyIndicatorData( this ) ); + + // connect destruction signal + connect( object, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + } + + return true; + + } + + //____________________________________________________________ + bool BusyIndicatorEngine::isAnimated( const QObject* object ) + { + + DataMap::Value data( BusyIndicatorEngine::data( object ) ); + return data && data.data()->isAnimated(); + + } + + //____________________________________________________________ + void BusyIndicatorEngine::setDuration( int value ) + { + + if( duration() == value ) return; + BaseEngine::setDuration( value ); + + // restart timer with specified time + if( _animation ) + { _animation.data()->setDuration( value ); } + + } + + //____________________________________________________________ + void BusyIndicatorEngine::setAnimated( const QObject* object, bool value ) + { + + DataMap::Value data( BusyIndicatorEngine::data( object ) ); + if( data ) + { + // update data + data.data()->setAnimated( value ); + + // start timer if needed + if( value ) + { + if( !_animation ) + { + + // create animation if not already there + _animation = new Animation( duration(), this ); + + // setup + _animation.data()->setStartValue( 0.0 ); + _animation.data()->setEndValue( 100.0 ); + _animation.data()->setTargetObject( this ); + _animation.data()->setPropertyName( "value" ); + _animation.data()->setLoopCount( -1 ); + _animation.data()->setDuration( duration() * 3); + + } + + // start if not already running + if( !_animation.data()->isRunning() ) + { _animation.data()->start(); } + + } + + } + + return; + + } + + + //____________________________________________________________ + DataMap::Value BusyIndicatorEngine::data( const QObject* object ) + { return _data.find( object ).data(); } + + //_______________________________________________ + void BusyIndicatorEngine::setValue( int value ) + { + + // update + _value = value; + + bool animated( false ); + + // loop over objects in map + for( DataMap::iterator iter = _data.begin(); iter != _data.end(); ++iter ) + { + + if( iter.value().data()->isAnimated() ) + { + + // update animation flag + animated = true; + + // emit update signal on object + if( const_cast( iter.key() )->inherits( "QQuickStyleItem" )) + { + + //QtQuickControls "rerender" method is updateItem + QMetaObject::invokeMethod( const_cast( iter.key() ), "updateItem", Qt::QueuedConnection); + + } else { + + QMetaObject::invokeMethod( const_cast( iter.key() ), "update", Qt::QueuedConnection); + + } + + } + + } + + if( _animation && !animated ) + { + _animation.data()->stop(); + _animation.data()->deleteLater(); + _animation.clear(); + } + + } + + //__________________________________________________________ + bool BusyIndicatorEngine::unregisterWidget( QObject* object ) + { + bool removed( _data.unregisterWidget( object ) ); + if( _animation && _data.isEmpty() ) + { + _animation.data()->stop(); + _animation.data()->deleteLater(); + _animation.clear(); + } + + return removed; + } + +} diff --git a/style/animations/adwaitabusyindicatorengine.h b/style/animations/adwaitabusyindicatorengine.h new file mode 100644 index 0000000..30853c4 --- /dev/null +++ b/style/animations/adwaitabusyindicatorengine.h @@ -0,0 +1,103 @@ +#ifndef adwaitabusyindicatorengine_h +#define adwaitabusyindicatorengine_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 "adwaitaanimation.h" +#include "adwaitabaseengine.h" +#include "adwaitabusyindicatordata.h" +#include "adwaitadatamap.h" + +namespace Adwaita +{ + + //* handles progress bar animations + class BusyIndicatorEngine: public BaseEngine + { + + Q_OBJECT + + //* declare opacity property + Q_PROPERTY( int value READ value WRITE setValue ) + + public: + + //* constructor + explicit BusyIndicatorEngine( QObject* ); + + //* destructor + virtual ~BusyIndicatorEngine( void ) + {} + + //*@name accessors + //@{ + + //* true if widget is animated + virtual bool isAnimated( const QObject* ); + + //* value + virtual int value( void ) const + { return _value; } + + //@} + + //*@name modifiers + //@{ + + //* register progressbar + virtual bool registerWidget( QObject* ); + + //* duration + virtual void setDuration( int ); + + //* set object as animated + virtual void setAnimated( const QObject*, bool ); + + //* opacity + virtual void setValue( int value ); + + //@} + + public Q_SLOTS: + + //* remove widget from map + virtual bool unregisterWidget( QObject* ); + + protected: + + //* returns data associated to widget + DataMap::Value data( const QObject* ); + + private: + + //* map widgets to progressbar data + DataMap _data; + + //* animation + Animation::Pointer _animation; + + //* value + int _value = 0; + + }; + +} + +#endif diff --git a/style/animations/adwaitadatamap.h b/style/animations/adwaitadatamap.h new file mode 100644 index 0000000..080c39f --- /dev/null +++ b/style/animations/adwaitadatamap.h @@ -0,0 +1,169 @@ +#ifndef adwaitadatamap_h +#define adwaitadatamap_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 "adwaita.h" + +#include +#include +#include + +namespace Adwaita +{ + + //* data map + /** it maps templatized data object to associated object */ + template< typename K, typename T > class BaseDataMap: public QMap< const K*, WeakPointer > + { + + public: + + using Key = const K*; + using Value = WeakPointer; + + //* constructor + BaseDataMap( void ): + QMap(), + _enabled( true ), + _lastKey( NULL ) + {} + + //* destructor + virtual ~BaseDataMap( void ) + {} + + //* insertion + virtual typename QMap< Key, Value >::iterator insert( const Key& key, const Value& value, bool enabled = true ) + { + if( value ) value.data()->setEnabled( enabled ); + return QMap< Key, Value >::insert( key, value ); + } + + //* find value + Value find( Key key ) + { + if( !( enabled() && key ) ) return Value(); + if( key == _lastKey ) return _lastValue; + else { + Value out; + typename QMap::iterator iter( QMap::find( key ) ); + if( iter != QMap::end() ) out = iter.value(); + _lastKey = key; + _lastValue = out; + return out; + } + } + + //* unregister widget + bool unregisterWidget( Key key ) + { + + // check key + if( !key ) return false; + + // clear last value if needed + if( key == _lastKey ) + { + + if( _lastValue ) _lastValue.clear(); + _lastKey = NULL; + + } + + // find key in map + typename QMap::iterator iter( QMap::find( key ) ); + if( iter == QMap::end() ) return false; + + // delete value from map if found + if( iter.value() ) iter.value().data()->deleteLater(); + QMap::erase( iter ); + + return true; + + } + + //* maxFrame + void setEnabled( bool enabled ) + { + _enabled = enabled; + foreach( const Value& value, *this ) + { if( value ) value.data()->setEnabled( enabled ); } + } + + //* enability + bool enabled( void ) const + { return _enabled; } + + //* duration + void setDuration( int duration ) const + { + foreach( const Value& value, *this ) + { if( value ) value.data()->setDuration( duration ); } + } + + private: + + //* enability + bool _enabled; + + //* last key + Key _lastKey; + + //* last value + Value _lastValue; + + }; + + //* standard data map, using QObject as a key + template< typename T > class DataMap: public BaseDataMap< QObject, T > + { + + public: + + //* constructor + DataMap( void ) + {} + + //* destructor + virtual ~DataMap( void ) + {} + + }; + + //* QPaintDevice based dataMap + template< typename T > class PaintDeviceDataMap: public BaseDataMap< QPaintDevice, T > + { + + public: + + //* constructor + PaintDeviceDataMap( void ) + {} + + //* destructor + virtual ~PaintDeviceDataMap( void ) + {} + + }; + +} + +#endif diff --git a/style/animations/adwaitadialdata.cpp b/style/animations/adwaitadialdata.cpp new file mode 100644 index 0000000..4d92c91 --- /dev/null +++ b/style/animations/adwaitadialdata.cpp @@ -0,0 +1,93 @@ +/************************************************************************* + * 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 "adwaitadialdata.h" + +#include +#include + +namespace Adwaita +{ + + //______________________________________________ + DialData::DialData( QObject* parent, QWidget* target, int duration ): + WidgetStateData( parent, target, duration ), + _position( -1, -1 ) + { target->installEventFilter( this ); } + + //______________________________________________ + bool DialData::eventFilter( QObject* object, QEvent* event ) + { + + if( object != target().data() ) + { return WidgetStateData::eventFilter( object, event ); } + + // check event type + switch( event->type() ) + { + + case QEvent::HoverEnter: + case QEvent::HoverMove: + hoverMoveEvent( object, event ); + break; + + case QEvent::HoverLeave: + hoverLeaveEvent( object, event ); + break; + + default: break; + + } + + return WidgetStateData::eventFilter( object, event ); + + } + + //______________________________________________ + void DialData::hoverMoveEvent( QObject* object, QEvent* event ) + { + + // try cast object to dial + QDial* scrollBar( qobject_cast( object ) ); + if( !scrollBar || scrollBar->isSliderDown() ) return; + + // cast event + QHoverEvent *hoverEvent = static_cast(event); + + // store position + _position = hoverEvent->pos(); + + // trigger animation if position match handle rect + updateState( _handleRect.contains( _position ) ); + + } + + + //______________________________________________ + void DialData::hoverLeaveEvent( QObject*, QEvent* ) + { + + // reset hover state + updateState( false ); + + // reset mouse position + _position = QPoint( -1, -1 ); + } + +} diff --git a/style/animations/adwaitadialdata.h b/style/animations/adwaitadialdata.h new file mode 100644 index 0000000..1e6dce0 --- /dev/null +++ b/style/animations/adwaitadialdata.h @@ -0,0 +1,74 @@ +#ifndef adwaitadial_data_h +#define adwaitadial_data_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 "adwaitawidgetstatedata.h" + +namespace Adwaita +{ + + //* dial data + class DialData: public WidgetStateData + { + + Q_OBJECT + + public: + + //* constructor + DialData( QObject* parent, QWidget* target, int ); + + //* destructor + virtual ~DialData( void ) + {} + + //* event filter + virtual bool eventFilter( QObject*, QEvent* ); + + //* subcontrol rect + virtual void setHandleRect( const QRect& rect ) + { _handleRect = rect; } + + //* mouse position + QPoint position( void ) const + { return _position; } + + protected: + + //* hoverMoveEvent + virtual void hoverMoveEvent( QObject*, QEvent* ); + + //* hoverMoveEvent + virtual void hoverLeaveEvent( QObject*, QEvent* ); + + private: + + //* rect + QRect _handleRect; + + //* mouse position + QPoint _position; + + }; + +} + +#endif diff --git a/style/animations/adwaitadialengine.cpp b/style/animations/adwaitadialengine.cpp new file mode 100644 index 0000000..d12fad7 --- /dev/null +++ b/style/animations/adwaitadialengine.cpp @@ -0,0 +1,44 @@ +/************************************************************************* + * 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 "adwaitadialengine.h" + +#include + +namespace Adwaita +{ + + //____________________________________________________________ + bool DialEngine::registerWidget( QWidget* widget, AnimationModes mode ) + { + + // check widget + if( !widget ) return false; + + // only handle hover and focus + if( mode&AnimationHover && !dataMap(AnimationHover).contains( widget ) ) { dataMap(AnimationHover).insert( widget, new DialData( this, widget, duration() ), enabled() ); } + if( mode&AnimationFocus && !dataMap(AnimationFocus).contains( widget ) ) { dataMap(AnimationFocus).insert( widget, new WidgetStateData( this, widget, duration() ), enabled() ); } + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + + return true; + } + +} diff --git a/style/animations/adwaitadialengine.h b/style/animations/adwaitadialengine.h new file mode 100644 index 0000000..cf9a169 --- /dev/null +++ b/style/animations/adwaitadialengine.h @@ -0,0 +1,71 @@ +#ifndef adwaitadialengine_h +#define adwaitadialengine_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 "adwaitadialdata.h" +#include "adwaitawidgetstateengine.h" + +namespace Adwaita +{ + + //* stores dial hovered action and timeLine + class DialEngine: public WidgetStateEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit DialEngine( QObject* parent ): + WidgetStateEngine( parent ) + {} + + //* destructor + virtual ~DialEngine( void ) + {} + + //* register dial + virtual bool registerWidget( QWidget*, AnimationModes ); + + //* control rect + virtual void setHandleRect( const QObject* object, const QRect& rect ) + { + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { static_cast(data.data())->setHandleRect( rect ); } + } + + //* mouse position + virtual QPoint position( const QObject* object ) + { + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { + + return static_cast(data.data())->position(); + + } else return QPoint( -1, -1 ); + } + + }; + +} + +#endif diff --git a/style/animations/adwaitaenabledata.cpp b/style/animations/adwaitaenabledata.cpp new file mode 100644 index 0000000..c301f2a --- /dev/null +++ b/style/animations/adwaitaenabledata.cpp @@ -0,0 +1,51 @@ +/************************************************************************* + * 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 "adwaitaenabledata.h" + +namespace Adwaita +{ + + //______________________________________________ + bool EnableData::eventFilter( QObject* object, QEvent* event ) + { + + if( !enabled() ) return WidgetStateData::eventFilter( object, event ); + + // check event type + switch( event->type() ) + { + + // enter event + case QEvent::EnabledChange: + { + if( QWidget* widget = qobject_cast( object ) ) + { updateState( widget->isEnabled() ); } + break; + } + + default: break; + + } + + return WidgetStateData::eventFilter( object, event ); + + } + +} diff --git a/style/animations/adwaitaenabledata.h b/style/animations/adwaitaenabledata.h new file mode 100644 index 0000000..9714efe --- /dev/null +++ b/style/animations/adwaitaenabledata.h @@ -0,0 +1,52 @@ +#ifndef adwaitaenable_data_h +#define adwaitaenable_data_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 "adwaitawidgetstatedata.h" + +namespace Adwaita +{ + + //* Enable data + class EnableData: public WidgetStateData + { + + Q_OBJECT + + public: + + //* constructor + EnableData( QObject* parent, QWidget* target, int duration, bool state = true ): + WidgetStateData( parent, target, duration, state ) + { target->installEventFilter( this ); } + + //* destructor + virtual ~EnableData( void ) + {} + + //* event filter + virtual bool eventFilter( QObject*, QEvent* ); + + }; + +} + +#endif diff --git a/style/animations/adwaitagenericdata.cpp b/style/animations/adwaitagenericdata.cpp new file mode 100644 index 0000000..9aaabd6 --- /dev/null +++ b/style/animations/adwaitagenericdata.cpp @@ -0,0 +1,34 @@ +/************************************************************************* + * 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 "adwaitagenericdata.h" + +#include + +namespace Adwaita +{ + + //______________________________________________ + GenericData::GenericData( QObject* parent, QWidget* target, int duration ): + AnimationData( parent, target ), + _animation( new Animation( duration, this ) ), + _opacity(0) + { setupAnimation( _animation, "opacity" ); } + +} diff --git a/style/animations/adwaitagenericdata.h b/style/animations/adwaitagenericdata.h new file mode 100644 index 0000000..07a4504 --- /dev/null +++ b/style/animations/adwaitagenericdata.h @@ -0,0 +1,86 @@ +#ifndef adwaitageneric_data_h +#define adwaitageneric_data_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 "adwaitaanimationdata.h" +#include "adwaitaanimation.h" + +#include +#include +namespace Adwaita +{ + + + //* generic data + class GenericData: public AnimationData + { + + Q_OBJECT + + //* declare opacity property + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) + + public: + + //* constructor + GenericData( QObject* parent, QWidget* widget, int duration ); + + //* destructor + virtual ~GenericData( void ) + {} + + //* return animation object + virtual const Animation::Pointer& animation() const + { return _animation; } + + //* duration + virtual void setDuration( int duration ) + { _animation.data()->setDuration( duration ); } + + //* opacity + virtual qreal opacity( void ) const + { return _opacity; } + + //* opacity + virtual void setOpacity( qreal value ) + { + + value = digitize( value ); + if( _opacity == value ) return; + + _opacity = value; + setDirty(); + + } + + private: + + //* animation handling + Animation::Pointer _animation; + + //* opacity variable + qreal _opacity; + + }; + +} + +#endif diff --git a/style/animations/adwaitaheaderviewdata.cpp b/style/animations/adwaitaheaderviewdata.cpp new file mode 100644 index 0000000..398c4a2 --- /dev/null +++ b/style/animations/adwaitaheaderviewdata.cpp @@ -0,0 +1,172 @@ +/************************************************************************* + * 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 . * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////////// +// adwaitaheaderviewdata.cpp +// data container for QHeaderView animations +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitaheaderviewdata.h" + +#include +#include + +namespace Adwaita +{ + + //______________________________________________ + HeaderViewData::HeaderViewData( QObject* parent, QWidget* target, int duration ): + AnimationData( parent, target ) + { + + _current._animation = new Animation( duration, this ); + setupAnimation( currentIndexAnimation(), "currentOpacity" ); + currentIndexAnimation().data()->setDirection( Animation::Forward ); + + _previous._animation = new Animation( duration, this ); + setupAnimation( previousIndexAnimation(), "previousOpacity" ); + previousIndexAnimation().data()->setDirection( Animation::Backward ); + + } + + //______________________________________________ + bool HeaderViewData::updateState( const QPoint& position , bool hovered ) + { + + if( !enabled() ) return false; + + const QHeaderView* local( qobject_cast( target().data() ) ); + if( !local ) return false; + + int index( local->logicalIndexAt( position ) ); + if( index < 0 ) return false; + + if( hovered ) + { + + + if( index != currentIndex() ) + { + + if( currentIndex() >= 0 ) + { + setPreviousIndex( currentIndex() ); + setCurrentIndex( -1 ); + previousIndexAnimation().data()->restart(); + } + + setCurrentIndex( index ); + currentIndexAnimation().data()->restart(); + + return true; + + } else return false; + + } else if( index == currentIndex() ) { + + setPreviousIndex( currentIndex() ); + setCurrentIndex( -1 ); + previousIndexAnimation().data()->restart(); + return true; + + } else return false; + + } + + //______________________________________________ + Animation::Pointer HeaderViewData::animation( const QPoint& position ) const + { + + if( !enabled() ) return Animation::Pointer(); + + const QHeaderView* local( qobject_cast( target().data() ) ); + if( !local ) return Animation::Pointer(); + + int index( local->logicalIndexAt( position ) ); + if( index < 0 ) return Animation::Pointer(); + else if( index == currentIndex() ) return currentIndexAnimation(); + else if( index == previousIndex() ) return previousIndexAnimation(); + else return Animation::Pointer(); + + } + + //______________________________________________ + qreal HeaderViewData::opacity( const QPoint& position ) const + { + + if( !enabled() ) return OpacityInvalid; + + const QHeaderView* local( qobject_cast( target().data() ) ); + if( !local ) return OpacityInvalid; + + int index( local->logicalIndexAt( position ) ); + if( index < 0 ) return OpacityInvalid; + else if( index == currentIndex() ) return currentOpacity(); + else if( index == previousIndex() ) return previousOpacity(); + else return OpacityInvalid; + + } + + + //__________________________________________________________ + void HeaderViewData::setDirty( void ) const + { + QHeaderView* header = qobject_cast( target().data() ); + if( !header ) return; + + // get first and last index, sorted + int lastIndex( qMax( previousIndex(), currentIndex() ) ); + if( lastIndex < 0 ) return; + + int firstIndex( qMin( previousIndex(), currentIndex() ) ); + if( firstIndex < 0 ) firstIndex = lastIndex; + + // find relevant rectangle to be updated, in viewport coordinate + QWidget* viewport( header->viewport() ); + int left = header->sectionViewportPosition( firstIndex ); + int right = header->sectionViewportPosition( lastIndex ) + header->sectionSize( lastIndex ); + + // trigger update + if( header->orientation() == Qt::Horizontal ) viewport->update( left, 0, right-left, header->height() ); + else viewport->update( 0, left, header->width(), right-left ); + + } + +} diff --git a/style/animations/adwaitaheaderviewdata.h b/style/animations/adwaitaheaderviewdata.h new file mode 100644 index 0000000..2d99f2d --- /dev/null +++ b/style/animations/adwaitaheaderviewdata.h @@ -0,0 +1,157 @@ +#ifndef adwaitaheaderview_data_h +#define adwaitaheaderview_data_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 "adwaitaanimationdata.h" +#include + +namespace Adwaita +{ + + //* headerviews + class HeaderViewData: public AnimationData + { + + Q_OBJECT + + //* declare opacity property + Q_PROPERTY( qreal currentOpacity READ currentOpacity WRITE setCurrentOpacity ) + Q_PROPERTY( qreal previousOpacity READ previousOpacity WRITE setPreviousOpacity ) + + public: + + //* constructor + HeaderViewData( QObject* parent, QWidget* target, int duration ); + + //* destructor + virtual ~HeaderViewData( void ) + {} + + //* duration + void setDuration( int duration ) + { + currentIndexAnimation().data()->setDuration( duration ); + previousIndexAnimation().data()->setDuration( duration ); + } + + //* update state + bool updateState( const QPoint&, bool ); + + //*@name current index handling + //@{ + + //* current opacity + virtual qreal currentOpacity( void ) const + { return _current._opacity; } + + //* current opacity + virtual void setCurrentOpacity( qreal value ) + { + value = digitize( value ); + if( _current._opacity == value ) return; + _current._opacity = value; + setDirty(); + } + + //* current index + virtual int currentIndex( void ) const + { return _current._index; } + + //* current index + virtual void setCurrentIndex( int index ) + { _current._index = index; } + + //* current index animation + virtual const Animation::Pointer& currentIndexAnimation( void ) const + { return _current._animation; } + + //@} + + //*@name previous index handling + //@{ + + //* previous opacity + virtual qreal previousOpacity( void ) const + { return _previous._opacity; } + + //* previous opacity + virtual void setPreviousOpacity( qreal value ) + { + value = digitize( value ); + if( _previous._opacity == value ) return; + _previous._opacity = value; + setDirty(); + } + + //* previous index + virtual int previousIndex( void ) const + { return _previous._index; } + + //* previous index + virtual void setPreviousIndex( int index ) + { _previous._index = index; } + + //* previous index Animation + virtual const Animation::Pointer& previousIndexAnimation( void ) const + { return _previous._animation; } + + //@} + + //* return Animation associated to action at given position, if any + virtual Animation::Pointer animation( const QPoint& position ) const; + + //* return opacity associated to action at given position, if any + virtual qreal opacity( const QPoint& position ) const; + + protected: + + //* dirty + virtual void setDirty( void ) const; + + private: + + //* container for needed animation data + class Data + { + public: + + //* default constructor + Data( void ): + _opacity(0), + _index(-1) + {} + + Animation::Pointer _animation; + qreal _opacity; + int _index; + }; + + //* current tab animation data (for hover enter animations) + Data _current; + + //* previous tab animations data (for hover leave animations) + Data _previous; + + }; + +} + +#endif diff --git a/style/animations/adwaitaheaderviewengine.cpp b/style/animations/adwaitaheaderviewengine.cpp new file mode 100644 index 0000000..306db9b --- /dev/null +++ b/style/animations/adwaitaheaderviewengine.cpp @@ -0,0 +1,49 @@ +/************************************************************************* + * 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 "adwaitaheaderviewengine.h" + +#include + +namespace Adwaita +{ + + //____________________________________________________________ + bool HeaderViewEngine::registerWidget( QWidget* widget ) + { + + if( !widget ) return false; + + // create new data class + if( !_data.contains( widget ) ) _data.insert( widget, new HeaderViewData( this, widget, duration() ), enabled() ); + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + return true; + + } + + //____________________________________________________________ + bool HeaderViewEngine::updateState( const QObject* object, const QPoint& position, bool value ) + { + DataMap::Value data( _data.find( object ) ); + return ( data && data.data()->updateState( position, value ) ); + } + +} diff --git a/style/animations/adwaitaheaderviewengine.h b/style/animations/adwaitaheaderviewengine.h new file mode 100644 index 0000000..3199aa5 --- /dev/null +++ b/style/animations/adwaitaheaderviewengine.h @@ -0,0 +1,94 @@ +#ifndef adwaitaheaderviewengine_h +#define adwaitaheaderviewengine_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 "adwaitabaseengine.h" +#include "adwaitadatamap.h" +#include "adwaitaheaderviewdata.h" + +namespace Adwaita +{ + + //* stores headerview hovered action and timeLine + class HeaderViewEngine: public BaseEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit HeaderViewEngine( QObject* parent ): + BaseEngine( parent ) + {} + + //* destructor + virtual ~HeaderViewEngine( void ) + {} + + //* register headerview + virtual bool registerWidget( QWidget* ); + + //* true if widget hover state is changed + virtual bool updateState( const QObject*, const QPoint&, bool ); + + //* true if widget is animated + virtual bool isAnimated( const QObject* object, const QPoint& point ) + { + if( DataMap::Value data = _data.find( object ) ) + { if( Animation::Pointer animation = data.data()->animation( point ) ) return animation.data()->isRunning(); } + return false; + } + + //* animation opacity + virtual qreal opacity( const QObject* object, const QPoint& point ) + { return isAnimated( object, point ) ? _data.find( object ).data()->opacity( point ) : AnimationData::OpacityInvalid; } + + //* enability + virtual void setEnabled( bool value ) + { + BaseEngine::setEnabled( value ); + _data.setEnabled( value ); + } + + //* duration + virtual void setDuration( int value ) + { + BaseEngine::setDuration( value ); + _data.setDuration( value ); + } + + public Q_SLOTS: + + //* remove widget from map + virtual bool unregisterWidget( QObject* object ) + { return _data.unregisterWidget( object ); } + + private: + + //* data map + DataMap _data; + + }; + +} + +#endif diff --git a/style/animations/adwaitascrollbardata.cpp b/style/animations/adwaitascrollbardata.cpp new file mode 100644 index 0000000..40be540 --- /dev/null +++ b/style/animations/adwaitascrollbardata.cpp @@ -0,0 +1,230 @@ +/************************************************************************* + * 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 "adwaitascrollbardata.h" + +#include +#include +#include + +Q_GUI_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar*); + +namespace Adwaita +{ + + //______________________________________________ + ScrollBarData::ScrollBarData( QObject* parent, QWidget* target, int duration ): + WidgetStateData( parent, target, duration ), + _position( -1, -1 ) + { + + target->installEventFilter( this ); + + _addLineData._animation = new Animation( duration, this ); + _subLineData._animation = new Animation( duration, this ); + _grooveData._animation = new Animation( duration, this ); + + connect( addLineAnimation().data(), SIGNAL(finished()), SLOT(clearAddLineRect()) ); + connect( subLineAnimation().data(), SIGNAL(finished()), SLOT(clearSubLineRect()) ); + + // setup animation + setupAnimation( addLineAnimation(), "addLineOpacity" ); + setupAnimation( subLineAnimation(), "subLineOpacity" ); + setupAnimation( grooveAnimation(), "grooveOpacity" ); + + } + + //______________________________________________ + bool ScrollBarData::eventFilter( QObject* object, QEvent* event ) + { + + if( object != target().data() ) + { return WidgetStateData::eventFilter( object, event ); } + + // check event type + switch( event->type() ) + { + + case QEvent::HoverEnter: + setGrooveHovered(true); + grooveAnimation().data()->setDirection( Animation::Forward ); + if( !grooveAnimation().data()->isRunning() ) grooveAnimation().data()->start(); + + case QEvent::HoverMove: + hoverMoveEvent( object, event ); + break; + + case QEvent::HoverLeave: + setGrooveHovered(false); + grooveAnimation().data()->setDirection( Animation::Backward ); + if( !grooveAnimation().data()->isRunning() ) grooveAnimation().data()->start(); + hoverLeaveEvent( object, event ); + + break; + + default: break; + + } + + return WidgetStateData::eventFilter( object, event ); + + } + + //______________________________________________ + const Animation::Pointer& ScrollBarData::animation( QStyle::SubControl subcontrol ) const + { + switch( subcontrol ) + { + default: + case QStyle::SC_ScrollBarSlider: + return animation(); + + case QStyle::SC_ScrollBarAddLine: + return addLineAnimation(); + + case QStyle::SC_ScrollBarSubLine: + return subLineAnimation(); + + case QStyle::SC_ScrollBarGroove: + return grooveAnimation(); + } + + } + + //______________________________________________ + qreal ScrollBarData::opacity( QStyle::SubControl subcontrol ) const + { + switch( subcontrol ) + { + default: + case QStyle::SC_ScrollBarSlider: + return opacity(); + + case QStyle::SC_ScrollBarAddLine: + return addLineOpacity(); + + case QStyle::SC_ScrollBarSubLine: + return subLineOpacity(); + + case QStyle::SC_ScrollBarGroove: + return grooveOpacity(); + } + + } + + //______________________________________________ + void ScrollBarData::hoverMoveEvent( QObject* object, QEvent* event ) + { + + // try cast object to scrollbar + QScrollBar* scrollBar( qobject_cast( object ) ); + if( !scrollBar || scrollBar->isSliderDown() ) return; + + // retrieve scrollbar option + QStyleOptionSlider opt( qt_qscrollbarStyleOption( scrollBar ) ); + + // cast event + QHoverEvent *hoverEvent = static_cast(event); + QStyle::SubControl hoverControl = scrollBar->style()->hitTestComplexControl(QStyle::CC_ScrollBar, &opt, hoverEvent->pos(), scrollBar); + + // update hover state + updateAddLineArrow( hoverControl ); + updateSubLineArrow( hoverControl ); + + // store position + _position = hoverEvent->pos(); + + } + + + //______________________________________________ + void ScrollBarData::hoverLeaveEvent( QObject*, QEvent* ) + { + + // reset hover state + updateSubLineArrow( QStyle::SC_None ); + updateAddLineArrow( QStyle::SC_None ); + + // reset mouse position + _position = QPoint( -1, -1 ); + } + + //_____________________________________________________________________ + void ScrollBarData::updateSubLineArrow( QStyle::SubControl hoverControl ) + { + if( hoverControl == QStyle::SC_ScrollBarSubLine ) + { + + if( !subLineArrowHovered() ) + { + setSubLineArrowHovered( true ); + if( enabled() ) + { + subLineAnimation().data()->setDirection( Animation::Forward ); + if( !subLineAnimation().data()->isRunning() ) subLineAnimation().data()->start(); + } else setDirty(); + } + + } else { + + if( subLineArrowHovered() ) + { + setSubLineArrowHovered( false ); + if( enabled() ) + { + subLineAnimation().data()->setDirection( Animation::Backward ); + if( !subLineAnimation().data()->isRunning() ) subLineAnimation().data()->start(); + } else setDirty(); + } + + } + } + + //_____________________________________________________________________ + void ScrollBarData::updateAddLineArrow( QStyle::SubControl hoverControl ) + { + if( hoverControl == QStyle::SC_ScrollBarAddLine ) + { + + if( !addLineArrowHovered() ) + { + setAddLineArrowHovered( true ); + if( enabled() ) + { + addLineAnimation().data()->setDirection( Animation::Forward ); + if( !addLineAnimation().data()->isRunning() ) addLineAnimation().data()->start(); + } else setDirty(); + } + + } else { + + if( addLineArrowHovered() ) + { + setAddLineArrowHovered( false ); + if( enabled() ) + { + addLineAnimation().data()->setDirection( Animation::Backward ); + if( !addLineAnimation().data()->isRunning() ) addLineAnimation().data()->start(); + } else setDirty(); + } + + } + } + +} diff --git a/style/animations/adwaitascrollbardata.h b/style/animations/adwaitascrollbardata.h new file mode 100644 index 0000000..95418e3 --- /dev/null +++ b/style/animations/adwaitascrollbardata.h @@ -0,0 +1,266 @@ +#ifndef adwaitascrollbar_data_h +#define adwaitascrollbar_data_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 "adwaitawidgetstatedata.h" + +#include + +namespace Adwaita +{ + + //* scrollbar data + class ScrollBarData: public WidgetStateData + { + + Q_OBJECT + Q_PROPERTY( qreal addLineOpacity READ addLineOpacity WRITE setAddLineOpacity ) + Q_PROPERTY( qreal subLineOpacity READ subLineOpacity WRITE setSubLineOpacity ) + Q_PROPERTY( qreal grooveOpacity READ grooveOpacity WRITE setGrooveOpacity ) + + public: + + //* constructor + ScrollBarData( QObject* parent, QWidget* target, int ); + + //* destructor + virtual ~ScrollBarData( void ) + {} + + //* event filter + virtual bool eventFilter( QObject*, QEvent* ); + + //* needed to avoid warning about virtual function being hidden + using WidgetStateData::animation; + using WidgetStateData::opacity; + + //* return animation for a given subcontrol + virtual const Animation::Pointer& animation( QStyle::SubControl ) const; + + //* return default opacity for a given subcontrol + virtual qreal opacity( QStyle::SubControl ) const; + + //* return default opacity for a given subcontrol + virtual bool isHovered( QStyle::SubControl control ) const + { + switch( control ) + { + case QStyle::SC_ScrollBarAddLine: return addLineArrowHovered(); + case QStyle::SC_ScrollBarSubLine: return subLineArrowHovered(); + case QStyle::SC_ScrollBarGroove: return grooveHovered(); + default: return false; + } + + + } + + //* subControlRect + virtual QRect subControlRect( QStyle::SubControl control ) const + { + switch( control ) + { + case QStyle::SC_ScrollBarAddLine: return _addLineData._rect; + case QStyle::SC_ScrollBarSubLine: return _subLineData._rect; + default: return QRect(); + } + } + + + //* subcontrol rect + virtual void setSubControlRect( QStyle::SubControl control, const QRect& rect ) + { + switch( control ) + { + case QStyle::SC_ScrollBarAddLine: + _addLineData._rect = rect; + break; + + case QStyle::SC_ScrollBarSubLine: + _subLineData._rect = rect; + break; + + default: break; + } + } + + //* duration + virtual void setDuration( int duration ) + { + WidgetStateData::setDuration( duration ); + addLineAnimation().data()->setDuration( duration ); + subLineAnimation().data()->setDuration( duration ); + grooveAnimation().data()->setDuration( duration ); + } + + //* addLine opacity + virtual void setAddLineOpacity( qreal value ) + { + value = digitize( value ); + if( _addLineData._opacity == value ) return; + _addLineData._opacity = value; + setDirty(); + } + + //* addLine opacity + virtual qreal addLineOpacity( void ) const + { return _addLineData._opacity; } + + //* subLine opacity + virtual void setSubLineOpacity( qreal value ) + { + value = digitize( value ); + if( _subLineData._opacity == value ) return; + _subLineData._opacity = value; + setDirty(); + } + + //* subLine opacity + virtual qreal subLineOpacity( void ) const + { return _subLineData._opacity; } + + //* groove opacity + virtual void setGrooveOpacity( qreal value ) + { + value = digitize( value ); + if( _grooveData._opacity == value ) return; + _grooveData._opacity = value; + setDirty(); + } + + //* groove opacity + virtual qreal grooveOpacity( void ) const + { return _grooveData._opacity; } + + //* mouse position + QPoint position( void ) const + { return _position; } + + protected Q_SLOTS: + + //* clear addLineRect + void clearAddLineRect( void ) + { + if( addLineAnimation().data()->direction() == Animation::Backward ) + { _addLineData._rect = QRect(); } + } + + //* clear subLineRect + void clearSubLineRect( void ) + { + if( subLineAnimation().data()->direction() == Animation::Backward ) + { _subLineData._rect = QRect(); } + } + + protected: + + //* hoverMoveEvent + virtual void hoverMoveEvent( QObject*, QEvent* ); + + //* hoverMoveEvent + virtual void hoverLeaveEvent( QObject*, QEvent* ); + + //*@name hover flags + //@{ + + virtual bool addLineArrowHovered( void ) const + { return _addLineData._hovered; } + + virtual void setAddLineArrowHovered( bool value ) + { _addLineData._hovered = value; } + + virtual bool subLineArrowHovered( void ) const + { return _subLineData._hovered; } + + virtual void setSubLineArrowHovered( bool value ) + { _subLineData._hovered = value; } + + virtual bool grooveHovered( void ) const + { return _grooveData._hovered; } + + virtual void setGrooveHovered( bool value ) + { _grooveData._hovered = value; } + + //@} + + //* update add line arrow + virtual void updateAddLineArrow( QStyle::SubControl ); + + //* update sub line arrow + virtual void updateSubLineArrow( QStyle::SubControl ); + + //*@name timelines + //@{ + + virtual const Animation::Pointer& addLineAnimation( void ) const + { return _addLineData._animation; } + + virtual const Animation::Pointer& subLineAnimation( void ) const + { return _subLineData._animation; } + + virtual const Animation::Pointer& grooveAnimation( void ) const + { return _grooveData._animation; } + + private: + + //* stores sub control data + class Data + { + + public: + + //* constructor + Data( void ): + _hovered( false ), + _opacity( AnimationData::OpacityInvalid ) + {} + + //* true if hovered + bool _hovered; + + //* animation + Animation::Pointer _animation; + + //* opacity + qreal _opacity; + + //* rect + QRect _rect; + + }; + + + //* add line data (down arrow) + Data _addLineData; + + //* subtract line data (up arrow) + Data _subLineData; + + //* groove data + Data _grooveData; + + //* mouse position + QPoint _position; + + }; + +} + +#endif diff --git a/style/animations/adwaitascrollbarengine.cpp b/style/animations/adwaitascrollbarengine.cpp new file mode 100644 index 0000000..8385369 --- /dev/null +++ b/style/animations/adwaitascrollbarengine.cpp @@ -0,0 +1,90 @@ +/************************************************************************* + * 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 "adwaitascrollbarengine.h" + +#include + +namespace Adwaita +{ + + //____________________________________________________________ + bool ScrollBarEngine::registerWidget( QWidget* widget, AnimationModes mode ) + { + + // check widget + if( !widget ) return false; + + // only handle hover and focus + if( mode&AnimationHover && !dataMap(AnimationHover).contains( widget ) ) { dataMap(AnimationHover).insert( widget, new ScrollBarData( this, widget, duration() ), enabled() ); } + if( mode&AnimationFocus && !dataMap(AnimationFocus).contains( widget ) ) { dataMap(AnimationFocus).insert( widget, new WidgetStateData( this, widget, duration() ), enabled() ); } + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + + return true; + } + + //____________________________________________________________ + bool ScrollBarEngine::isAnimated( const QObject* object, AnimationMode mode, QStyle::SubControl control ) + { + + if( mode == AnimationHover ) + { + + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { + + const ScrollBarData* scrollBarData( static_cast( data.data() ) ); + Animation::Pointer animation = scrollBarData->animation( control ); + return animation.data()->isRunning(); + + } else return false; + + } else if( control == QStyle::SC_ScrollBarSlider ) { + + return WidgetStateEngine::isAnimated( object, mode ); + + } else return false; + + } + + //____________________________________________________________ + AnimationMode ScrollBarEngine::animationMode( const QObject* object, QStyle::SubControl control ) + { + + // enable state + if( isAnimated( object, AnimationHover, control ) ) return AnimationHover; + else if( isAnimated( object, AnimationFocus, control ) ) return AnimationFocus; + else if( isAnimated( object, AnimationPressed, control ) ) return AnimationPressed; + else return AnimationNone; + + } + + //____________________________________________________________ + qreal ScrollBarEngine::opacity( const QObject* object, QStyle::SubControl control ) + { + + if( isAnimated( object, AnimationHover, control ) ) return static_cast(data( object, AnimationHover ).data())->opacity( control ); + else if( control == QStyle::SC_ScrollBarSlider ) return WidgetStateEngine::buttonOpacity( object ); + return AnimationData::OpacityInvalid; + + } + +} diff --git a/style/animations/adwaitascrollbarengine.h b/style/animations/adwaitascrollbarengine.h new file mode 100644 index 0000000..4e96ea1 --- /dev/null +++ b/style/animations/adwaitascrollbarengine.h @@ -0,0 +1,115 @@ +#ifndef adwaitascrollbarengine_h +#define adwaitascrollbarengine_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 "adwaitascrollbardata.h" +#include "adwaitawidgetstateengine.h" + +namespace Adwaita +{ + + //* stores scrollbar hovered action and timeLine + class ScrollBarEngine: public WidgetStateEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit ScrollBarEngine( QObject* parent ): + WidgetStateEngine( parent ) + {} + + //* destructor + virtual ~ScrollBarEngine( void ) + {} + + //* register scrollbar + virtual bool registerWidget( QWidget*, AnimationModes ); + + //*@name accessors + //@{ + + using WidgetStateEngine::isAnimated; + using WidgetStateEngine::opacity; + + //* true if widget is animated + virtual bool isAnimated( const QObject*, AnimationMode, QStyle::SubControl control ); + + //* true if widget is animated + virtual AnimationMode animationMode( const QObject* object, QStyle::SubControl control ); + + //* animation opacity + virtual qreal opacity( const QObject* object, QStyle::SubControl control ); + + //* return true if given subcontrol is hovered + virtual bool isHovered( const QObject* object, QStyle::SubControl control ) + { + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { + + return static_cast( data.data() )->isHovered( control ); + + } else return false; + } + + //* control rect associated to object + virtual QRect subControlRect( const QObject* object, QStyle::SubControl control ) + { + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { + + return static_cast( data.data() )->subControlRect( control ); + + } else return QRect(); + } + + //* mouse position + virtual QPoint position( const QObject* object ) + { + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { + + return static_cast( data.data() )->position(); + + } else return QPoint( -1, -1 ); + } + + //@} + + //*@name modifiers + //@{ + + //* control rect + virtual void setSubControlRect( const QObject* object, QStyle::SubControl control, const QRect& rect ) + { + if( DataMap::Value data = this->data( object, AnimationHover ) ) + { static_cast( data.data() )->setSubControlRect( control, rect ); } + } + + //@} + + }; + +} + +#endif diff --git a/style/animations/adwaitaspinboxdata.cpp b/style/animations/adwaitaspinboxdata.cpp new file mode 100644 index 0000000..5b715df --- /dev/null +++ b/style/animations/adwaitaspinboxdata.cpp @@ -0,0 +1,62 @@ +/************************************************************************* + * 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 "adwaitaspinboxdata.h" + +namespace Adwaita +{ + + //________________________________________________ + SpinBoxData::SpinBoxData( QObject* parent, QWidget* target, int duration ): + AnimationData( parent, target ) + { + _upArrowData._hoverAnimation = new Animation( duration, this ); + _downArrowData._hoverAnimation = new Animation( duration, this ); + _upArrowData._pressedAnimation = new Animation( duration, this ); + _downArrowData._pressedAnimation = new Animation( duration, this ); + setupAnimation( upArrowAnimation(), "upArrowOpacity" ); + setupAnimation( downArrowAnimation(), "downArrowOpacity" ); + setupAnimation( upArrowPressedAnimation(), "upArrowPressed" ); + setupAnimation( downArrowPressedAnimation(), "downArrowPressed" ); + } + + //______________________________________________ + bool SpinBoxData::Data::updateState(bool value, bool pressed) + { + bool change = false; + if( _hoverState != value ) { + + _hoverState = value; + _hoverAnimation.data()->setDirection( ( _hoverState ) ? Animation::Forward : Animation::Backward ); + if( !_hoverAnimation.data()->isRunning() ) _hoverAnimation.data()->start(); + change = true; + + } + if( _pressedState != pressed ) { + + _pressedState = pressed; + _pressedAnimation.data()->setDirection( ( _pressedState ) ? Animation::Forward : Animation::Backward ); + if( !_pressedAnimation.data()->isRunning() ) _pressedAnimation.data()->start(); + change = true; + + } + return change; + } + +} diff --git a/style/animations/adwaitaspinboxdata.h b/style/animations/adwaitaspinboxdata.h new file mode 100644 index 0000000..56f68b9 --- /dev/null +++ b/style/animations/adwaitaspinboxdata.h @@ -0,0 +1,219 @@ +#ifndef adwaitaspinbox_data_h +#define adwaitaspinbox_data_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 "adwaitaanimationdata.h" + +#include + +namespace Adwaita +{ + + //* handles spinbox arrows hover + class SpinBoxData: public AnimationData + { + + Q_OBJECT + + //* declare opacity property + Q_PROPERTY( qreal upArrowOpacity READ upArrowOpacity WRITE setUpArrowOpacity ) + Q_PROPERTY( qreal downArrowOpacity READ downArrowOpacity WRITE setDownArrowOpacity ) + Q_PROPERTY( qreal upArrowPressed READ upArrowPressed WRITE setUpArrowPressed ) + Q_PROPERTY( qreal downArrowPressed READ downArrowPressed WRITE setDownArrowPressed ) + + public: + + //* constructor + SpinBoxData( QObject*, QWidget*, int ); + + //* destructor + virtual ~SpinBoxData( void ) + {} + + //* animation state + virtual bool updateState( QStyle::SubControl subControl, bool value, bool pressed ) + { + if( subControl == QStyle::SC_SpinBoxUp ) return _upArrowData.updateState( value, pressed ); + else if( subControl == QStyle::SC_SpinBoxDown ) return _downArrowData.updateState( value, pressed ); + else return false; + } + + //* animation state + virtual bool isAnimated( QStyle::SubControl subControl ) const + { + return( + ( subControl == QStyle::SC_SpinBoxUp && upArrowAnimation().data()->isRunning() ) || + ( subControl == QStyle::SC_SpinBoxDown && downArrowAnimation().data()->isRunning() ) ); + } + + //* opacity + virtual qreal opacity( QStyle::SubControl subControl ) const + { + if( subControl == QStyle::SC_SpinBoxUp ) return upArrowOpacity(); + else if( subControl == QStyle::SC_SpinBoxDown ) return downArrowOpacity(); + else return OpacityInvalid; + } + + //* opacity + virtual qreal pressed( QStyle::SubControl subControl ) const + { + if( subControl == QStyle::SC_SpinBoxUp ) return upArrowPressed(); + else if( subControl == QStyle::SC_SpinBoxDown ) return downArrowPressed(); + else return OpacityInvalid; + } + + //* duration + virtual void setDuration( int duration ) + { + upArrowAnimation().data()->setDuration( duration ); + downArrowAnimation().data()->setDuration( duration ); + } + + //*@name up arrow animation + //@{ + + //* opacity + qreal upArrowOpacity( void ) const + { return _upArrowData._opacity; } + + //* opacity + void setUpArrowOpacity( qreal value ) + { + value = digitize( value ); + if( _upArrowData._opacity == value ) return; + _upArrowData._opacity = value; + setDirty(); + } + + //* animation + Animation::Pointer upArrowAnimation( void ) const + { return _upArrowData._hoverAnimation; } + + //@} + + //*@name down arrow animation + //@{ + + //* opacity + qreal downArrowOpacity( void ) const + { return _downArrowData._opacity; } + + //* opacity + void setDownArrowOpacity( qreal value ) + { + value = digitize( value ); + if( _downArrowData._opacity == value ) return; + _downArrowData._opacity = value; + setDirty(); + } + + //* animation + Animation::Pointer downArrowAnimation( void ) const + { return _downArrowData._hoverAnimation; } + + + //*@name up arrow pressed animation + //@{ + + //* opacity + qreal upArrowPressed( void ) const + { return _upArrowData._pressed; } + + //* opacity + void setUpArrowPressed( qreal value ) + { + value = digitize( value ); + if( _upArrowData._pressed == value ) return; + _upArrowData._pressed = value; + setDirty(); + } + + //* animation + Animation::Pointer upArrowPressedAnimation( void ) const + { return _upArrowData._pressedAnimation; } + + //*@name down arrow pressed animation + //@{ + + //* opacity + qreal downArrowPressed( void ) const + { return _downArrowData._pressed; } + + //* opacity + void setDownArrowPressed( qreal value ) + { + value = digitize( value ); + if( _downArrowData._pressed == value ) return; + _downArrowData._pressed = value; + setDirty(); + } + + //* animation + Animation::Pointer downArrowPressedAnimation( void ) const + { return _downArrowData._pressedAnimation; } + + //@} + + private: + + //* container for needed animation data + class Data + { + + public: + + //* default constructor + Data( void ): + _hoverState( false ), + _pressedState( false ), + _opacity(0), + _pressed(0) + {} + + //* state + bool updateState( bool, bool ); + + //* arrow state + bool _hoverState; + bool _pressedState; + + //* animation + Animation::Pointer _hoverAnimation; + Animation::Pointer _pressedAnimation; + + //* opacity + qreal _opacity; + qreal _pressed; + + }; + + //* up arrow data + Data _upArrowData; + + //* down arrow data + Data _downArrowData; + + }; + + +} + +#endif diff --git a/style/animations/adwaitaspinboxengine.cpp b/style/animations/adwaitaspinboxengine.cpp new file mode 100644 index 0000000..f0927fa --- /dev/null +++ b/style/animations/adwaitaspinboxengine.cpp @@ -0,0 +1,42 @@ +/************************************************************************* + * 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 "adwaitaspinboxengine.h" + +#include + +namespace Adwaita +{ + + //____________________________________________________________ + bool SpinBoxEngine::registerWidget( QWidget* widget ) + { + + if( !widget ) return false; + + // create new data class + if( !_data.contains( widget ) ) _data.insert( widget, new SpinBoxData( this, widget, duration() ), enabled() ); + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + return true; + + } + +} diff --git a/style/animations/adwaitaspinboxengine.h b/style/animations/adwaitaspinboxengine.h new file mode 100644 index 0000000..3d014a5 --- /dev/null +++ b/style/animations/adwaitaspinboxengine.h @@ -0,0 +1,117 @@ +#ifndef adwaitaspinboxengine_h +#define adwaitaspinboxengine_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 "adwaitabaseengine.h" +#include "adwaitadatamap.h" +#include "adwaitaspinboxdata.h" + +namespace Adwaita +{ + + //* handle spinbox arrows hover effect + class SpinBoxEngine: public BaseEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit SpinBoxEngine( QObject* parent ): + BaseEngine( parent ) + {} + + //* destructor + virtual ~SpinBoxEngine( void ) + {} + + //* register widget + virtual bool registerWidget( QWidget* ); + + //* state + virtual bool updateState( const QObject* object, QStyle::SubControl subControl, bool value, bool pressed ) + { + if( DataMap::Value data = _data.find( object ) ) + { + return data.data()->updateState( subControl, value, pressed ); + } else return false; + } + + //* true if widget is animated + virtual bool isAnimated( const QObject* object, QStyle::SubControl subControl ) + { + if( DataMap::Value data = _data.find( object ) ) + { + return data.data()->isAnimated( subControl ); + } else return false; + + } + + //* animation opacity + virtual qreal opacity( const QObject* object, QStyle::SubControl subControl ) + { + if( DataMap::Value data = _data.find( object ) ) + { + return data.data()->opacity( subControl ); + } else return AnimationData::OpacityInvalid; + } + + //* animation opacity + virtual qreal pressed( const QObject* object, QStyle::SubControl subControl ) + { + if( DataMap::Value data = _data.find( object ) ) + { + return data.data()->pressed( subControl ); + } else return AnimationData::OpacityInvalid; + } + + //* enability + virtual void setEnabled( bool value ) + { + BaseEngine::setEnabled( value ); + _data.setEnabled( value ); + } + + //* duration + virtual void setDuration( int value ) + { + BaseEngine::setDuration( value ); + _data.setDuration( value ); + } + + + public Q_SLOTS: + + //* remove widget from map + virtual bool unregisterWidget( QObject* object ) + { return _data.unregisterWidget( object ); } + + private: + + //* data map + DataMap _data; + + }; + +} + +#endif diff --git a/style/animations/adwaitastackedwidgetdata.cpp b/style/animations/adwaitastackedwidgetdata.cpp new file mode 100644 index 0000000..6d4291c --- /dev/null +++ b/style/animations/adwaitastackedwidgetdata.cpp @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////////// +// adwaitastackedwidgetdata.cpp +// data container for QStackedWidget transition +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitastackedwidgetdata.h" + +namespace Adwaita +{ + + //______________________________________________________ + StackedWidgetData::StackedWidgetData( QObject* parent, QStackedWidget* target, int duration ): + TransitionData( parent, target, duration ), + _target( target ), + _index( target->currentIndex() ) + { + + // configure transition + connect( _target.data(), SIGNAL(destroyed()), SLOT(targetDestroyed()) ); + connect( _target.data(), SIGNAL(currentChanged(int)), SLOT(animate()) ); + + // disable focus + transition().data()->setAttribute(Qt::WA_NoMousePropagation, true); + transition().data()->setFlag(TransitionWidget::PaintOnWidget, true); + + setMaxRenderTime( 50 ); + + } + + //___________________________________________________________________ + bool StackedWidgetData::initializeAnimation( void ) + { + + // check enability + if( !( _target && _target.data()->isVisible() ) ) + { return false; } + + // check index + if( _target.data()->currentIndex() == _index ) + { return false; } + + // do not animate if either index or currentIndex is not valid + // but update _index none the less + if( _target.data()->currentIndex() < 0 || _index < 0 ) + { + _index = _target.data()->currentIndex(); + return false; + } + + // get old widget (matching _index) and initialize transition + if( QWidget *widget = _target.data()->widget( _index ) ) + { + + transition().data()->setOpacity( 0 ); + startClock(); + transition().data()->setGeometry( widget->geometry() ); + transition().data()->setStartPixmap( transition().data()->grab( widget ) ); + + _index = _target.data()->currentIndex(); + return !slow(); + + } else { + + _index = _target.data()->currentIndex(); + return false; + + } + + } + + //___________________________________________________________________ + bool StackedWidgetData::animate( void ) + { + + // check enability + if( !enabled() ) return false; + + // initialize animation + if( !initializeAnimation() ) return false; + + // show transition widget + transition().data()->show(); + transition().data()->raise(); + transition().data()->animate(); + return true; + + } + + //___________________________________________________________________ + void StackedWidgetData::finishAnimation( void ) + { + // disable updates on currentWidget + if( _target && _target.data()->currentWidget() ) + { _target.data()->currentWidget()->setUpdatesEnabled( false ); } + + // hide transition + transition().data()->hide(); + + // reenable updates and repaint + if( _target && _target.data()->currentWidget() ) + { + _target.data()->currentWidget()->setUpdatesEnabled( true ); + _target.data()->currentWidget()->repaint(); + } + + // invalidate start widget + transition().data()->resetStartPixmap(); + + } + + //___________________________________________________________________ + void StackedWidgetData::targetDestroyed( void ) + { + setEnabled( false ); + _target.clear(); + } + +} diff --git a/style/animations/adwaitastackedwidgetdata.h b/style/animations/adwaitastackedwidgetdata.h new file mode 100644 index 0000000..93538a6 --- /dev/null +++ b/style/animations/adwaitastackedwidgetdata.h @@ -0,0 +1,78 @@ +#ifndef adwaitastackedwidget_datah +#define adwaitastackedwidget_datah + +////////////////////////////////////////////////////////////////////////////// +// adwaitastackedwidgetdata.h +// data container for QStackedWidget transition +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitatransitiondata.h" + +#include + +namespace Adwaita +{ + + //! generic data + class StackedWidgetData: public TransitionData + { + + Q_OBJECT + + public: + + //! constructor + StackedWidgetData( QObject*, QStackedWidget*, int ); + + //! destructor + virtual ~StackedWidgetData( void ) + {} + + protected Q_SLOTS: + + //! initialize animation + virtual bool initializeAnimation( void ); + + //! animate + virtual bool animate( void ); + + //! finish animation + virtual void finishAnimation( void ); + + //! called when target is destroyed + virtual void targetDestroyed( void ); + + private: + + //! target + WeakPointer _target; + + //! current index + int _index; + + }; + +} + +#endif diff --git a/style/animations/adwaitastackedwidgetengine.cpp b/style/animations/adwaitastackedwidgetengine.cpp new file mode 100644 index 0000000..2e112da --- /dev/null +++ b/style/animations/adwaitastackedwidgetengine.cpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// adwaitastackedwidgetengine.cpp +// stores event filters and maps widgets to animations +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitastackedwidgetengine.h" + +namespace Adwaita +{ + + //____________________________________________________________ + bool StackedWidgetEngine::registerWidget( QStackedWidget* widget ) + { + + if( !widget ) return false; + if( !_data.contains( widget ) ) { _data.insert( widget, new StackedWidgetData( this, widget, duration() ), enabled() ); } + + // connect destruction signal + disconnect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)) ); + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)) ); + + return true; + + } + +} diff --git a/style/animations/adwaitastackedwidgetengine.h b/style/animations/adwaitastackedwidgetengine.h new file mode 100644 index 0000000..cf9c0ab --- /dev/null +++ b/style/animations/adwaitastackedwidgetengine.h @@ -0,0 +1,86 @@ +#ifndef adwaitastackedwidgetengine_h +#define adwaitastackedwidgetengine_h + +////////////////////////////////////////////////////////////////////////////// +// adwaitastackedwidgetengine.h +// stores event filters and maps widgets to animations +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitabaseengine.h" +#include "adwaitadatamap.h" +#include "adwaitastackedwidgetdata.h" + +namespace Adwaita +{ + + //! used for simple widgets + class StackedWidgetEngine: public BaseEngine + { + + Q_OBJECT + + public: + + //! constructor + explicit StackedWidgetEngine( QObject* parent ): + BaseEngine( parent ) + {} + + //! destructor + virtual ~StackedWidgetEngine( void ) + {} + + //! register widget + virtual bool registerWidget( QStackedWidget* ); + + //! duration + virtual void setEnabled( bool value ) + { + BaseEngine::setEnabled( value ); + _data.setEnabled( value ); + } + + //! duration + virtual void setDuration( int value ) + { + BaseEngine::setDuration( value ); + _data.setDuration( value ); + } + + public Q_SLOTS: + + //! remove widget from map + virtual bool unregisterWidget( QObject* object ) + { return _data.unregisterWidget( object ); } + + private: + + //! maps + DataMap _data; + + }; + +} + +#endif diff --git a/style/animations/adwaitatabbardata.cpp b/style/animations/adwaitatabbardata.cpp new file mode 100644 index 0000000..d41464c --- /dev/null +++ b/style/animations/adwaitatabbardata.cpp @@ -0,0 +1,147 @@ +/************************************************************************* + * 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 . * + *************************************************************************/ + +////////////////////////////////////////////////////////////////////////////// +// adwaitatabbardata.cpp +// data container for QTabBar animations +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitatabbardata.h" + +#include +#include + +namespace Adwaita +{ + + //______________________________________________ + TabBarData::TabBarData( QObject* parent, QWidget* target, int duration ): + AnimationData( parent, target ) + { + + _current._animation = new Animation( duration, this ); + setupAnimation( currentIndexAnimation(), "currentOpacity" ); + currentIndexAnimation().data()->setDirection( Animation::Forward ); + + _previous._animation = new Animation( duration, this ); + setupAnimation( previousIndexAnimation(), "previousOpacity" ); + previousIndexAnimation().data()->setDirection( Animation::Backward ); + + } + + //______________________________________________ + Animation::Pointer TabBarData::animation( const QPoint& position ) const + { + + if( !enabled() ) return Animation::Pointer(); + + const QTabBar* local( qobject_cast( target().data() ) ); + if( !local ) return Animation::Pointer(); + + int index( local->tabAt( position ) ); + if( index < 0 ) return Animation::Pointer(); + else if( index == currentIndex() ) return currentIndexAnimation(); + else if( index == previousIndex() ) return previousIndexAnimation(); + else return Animation::Pointer(); + + } + + //______________________________________________ + bool TabBarData::updateState( const QPoint& position , bool hovered ) + { + + if( !enabled() ) return false; + + const QTabBar* local( qobject_cast( target().data() ) ); + if( !local ) return false; + + int index( local->tabAt( position ) ); + if( index < 0 ) return false; + + if( hovered ) + { + + + if( index != currentIndex() ) + { + + if( currentIndex() >= 0 ) + { + setPreviousIndex( currentIndex() ); + setCurrentIndex( -1 ); + previousIndexAnimation().data()->restart(); + } + + setCurrentIndex( index ); + currentIndexAnimation().data()->restart(); + return true; + + } else return false; + + } else if( index == currentIndex() ) { + + setPreviousIndex( currentIndex() ); + setCurrentIndex( -1 ); + previousIndexAnimation().data()->restart(); + return true; + + } else return false; + + } + + //______________________________________________ + qreal TabBarData::opacity( const QPoint& position ) const + { + + if( !enabled() ) return OpacityInvalid; + + const QTabBar* local( qobject_cast( target().data() ) ); + if( !local ) return OpacityInvalid; + + int index( local->tabAt( position ) ); + if( index < 0 ) return OpacityInvalid; + else if( index == currentIndex() ) return currentOpacity(); + else if( index == previousIndex() ) return previousOpacity(); + else return OpacityInvalid; + + } + + +} diff --git a/style/animations/adwaitatabbardata.h b/style/animations/adwaitatabbardata.h new file mode 100644 index 0000000..a5aa073 --- /dev/null +++ b/style/animations/adwaitatabbardata.h @@ -0,0 +1,151 @@ +#ifndef adwaitatabbar_data_h +#define adwaitatabbar_data_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 "adwaitaanimationdata.h" + +#include + +namespace Adwaita +{ + + //* tabbars + class TabBarData: public AnimationData + { + + Q_OBJECT + + //* declare opacity property + Q_PROPERTY( qreal currentOpacity READ currentOpacity WRITE setCurrentOpacity ) + Q_PROPERTY( qreal previousOpacity READ previousOpacity WRITE setPreviousOpacity ) + + public: + + //* constructor + TabBarData( QObject* parent, QWidget* target, int duration ); + + //* destructor + virtual ~TabBarData( void ) + {} + + //* duration + void setDuration( int duration ) + { + currentIndexAnimation().data()->setDuration( duration ); + previousIndexAnimation().data()->setDuration( duration ); + } + + //* update state + bool updateState( const QPoint&, bool ); + + //*@name current index handling + //@{ + + //* current opacity + virtual qreal currentOpacity( void ) const + { return _current._opacity; } + + //* current opacity + virtual void setCurrentOpacity( qreal value ) + { + if( _current._opacity == value ) return; + _current._opacity = value; + setDirty(); + } + + //* current index + virtual int currentIndex( void ) const + { return _current._index; } + + //* current index + virtual void setCurrentIndex( int index ) + { _current._index = index; } + + //* current index animation + virtual const Animation::Pointer& currentIndexAnimation( void ) const + { return _current._animation; } + + //@} + + //*@name previous index handling + //@{ + + //* previous opacity + virtual qreal previousOpacity( void ) const + { return _previous._opacity; } + + //* previous opacity + virtual void setPreviousOpacity( qreal value ) + { + if( _previous._opacity == value ) return; + _previous._opacity = value; + setDirty(); + } + + //* previous index + virtual int previousIndex( void ) const + { return _previous._index; } + + //* previous index + virtual void setPreviousIndex( int index ) + { _previous._index = index; } + + //* previous index Animation + virtual const Animation::Pointer& previousIndexAnimation( void ) const + { return _previous._animation; } + + //@} + + //* return Animation associated to action at given position, if any + virtual Animation::Pointer animation( const QPoint& position ) const; + + //* return opacity associated to action at given position, if any + virtual qreal opacity( const QPoint& position ) const; + + private: + + //* container for needed animation data + class Data + { + public: + + //* default constructor + Data( void ): + _opacity(0), + _index(-1) + {} + + Animation::Pointer _animation; + qreal _opacity; + int _index; + }; + + //* current tab animation data (for hover enter animations) + Data _current; + + //* previous tab animations data (for hover leave animations) + Data _previous; + + }; + +} + +#endif diff --git a/style/animations/adwaitatabbarengine.cpp b/style/animations/adwaitatabbarengine.cpp new file mode 100644 index 0000000..5abd319 --- /dev/null +++ b/style/animations/adwaitatabbarengine.cpp @@ -0,0 +1,72 @@ +/************************************************************************* + * 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 "adwaitatabbarengine.h" + +#include + +namespace Adwaita +{ + + //____________________________________________________________ + bool TabBarEngine::registerWidget( QWidget* widget ) + { + + if( !widget ) return false; + + // create new data class + if( !_hoverData.contains( widget ) ) _hoverData.insert( widget, new TabBarData( this, widget, duration() ), enabled() ); + if( !_focusData.contains( widget ) ) _focusData.insert( widget, new TabBarData( this, widget, duration() ), enabled() ); + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + return true; + + } + + //____________________________________________________________ + bool TabBarEngine::updateState( const QObject* object, const QPoint& position, AnimationMode mode, bool value ) + { + DataMap::Value data( TabBarEngine::data( object, mode ) ); + return ( data && data.data()->updateState( position, value ) ); + } + + //____________________________________________________________ + bool TabBarEngine::isAnimated( const QObject* object, const QPoint& position, AnimationMode mode ) + { + + DataMap::Value data( TabBarEngine::data( object, mode ) ); + return ( data && data.data()->animation( position ) && data.data()->animation( position ).data()->isRunning() ); + + } + + //____________________________________________________________ + DataMap::Value TabBarEngine::data( const QObject* object, AnimationMode mode ) + { + + switch( mode ) + { + case AnimationHover: return _hoverData.find( object ).data(); + case AnimationFocus: return _focusData.find( object ).data(); + default: return DataMap::Value(); + } + + } + +} diff --git a/style/animations/adwaitatabbarengine.h b/style/animations/adwaitatabbarengine.h new file mode 100644 index 0000000..0120a61 --- /dev/null +++ b/style/animations/adwaitatabbarengine.h @@ -0,0 +1,102 @@ +#ifndef adwaitatabbarengine_h +#define adwaitatabbarengine_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 "adwaita.h" +#include "adwaitabaseengine.h" +#include "adwaitadatamap.h" +#include "adwaitatabbardata.h" + +namespace Adwaita +{ + + //* stores tabbar hovered action and timeLine + class TabBarEngine: public BaseEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit TabBarEngine( QObject* parent ): + BaseEngine( parent ) + {} + + //* destructor + virtual ~TabBarEngine( void ) + {} + + //* register tabbar + virtual bool registerWidget( QWidget* ); + + //* true if widget hover state is changed + virtual bool updateState( const QObject*, const QPoint&, AnimationMode, bool ); + + //* true if widget is animated + virtual bool isAnimated( const QObject* object, const QPoint& point, AnimationMode ); + + //* animation opacity + virtual qreal opacity( const QObject* object, const QPoint& point, AnimationMode mode ) + { return isAnimated( object, point, mode ) ? data( object, mode ).data()->opacity( point ) : AnimationData::OpacityInvalid; } + + //* enability + virtual void setEnabled( bool value ) + { + BaseEngine::setEnabled( value ); + _hoverData.setEnabled( value ); + _focusData.setEnabled( value ); + } + + //* duration + virtual void setDuration( int value ) + { + BaseEngine::setDuration( value ); + _hoverData.setDuration( value ); + _focusData.setDuration( value ); + } + + public Q_SLOTS: + + //* remove widget from map + virtual bool unregisterWidget( QObject* object ) + { + if( !object ) return false; + bool found = false; + if( _hoverData.unregisterWidget( object ) ) found = true; + if( _focusData.unregisterWidget( object ) ) found = true; + return found; + } + + private: + + //* returns data associated to widget + DataMap::Value data( const QObject*, AnimationMode ); + + //* data map + DataMap _hoverData; + DataMap _focusData; + + }; + +} + +#endif diff --git a/style/animations/adwaitatoolboxengine.cpp b/style/animations/adwaitatoolboxengine.cpp new file mode 100644 index 0000000..498c4f2 --- /dev/null +++ b/style/animations/adwaitatoolboxengine.cpp @@ -0,0 +1,55 @@ +/************************************************************************* + * 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 "adwaitatoolboxengine.h" + +namespace Adwaita +{ + + //____________________________________________________________ + bool ToolBoxEngine::registerWidget( QWidget* widget ) + { + + if( !widget ) return false; + if( !_data.contains( widget ) ) { _data.insert( widget, new WidgetStateData( this, widget, duration() ), enabled() ); } + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + return true; + + } + + //____________________________________________________________ + bool ToolBoxEngine::updateState( const QPaintDevice* object, bool value ) + { + PaintDeviceDataMap::Value data( ToolBoxEngine::data( object ) ); + return ( data && data.data()->updateState( value ) ); + } + + //____________________________________________________________ + bool ToolBoxEngine::isAnimated( const QPaintDevice* object ) + { + + PaintDeviceDataMap::Value data( ToolBoxEngine::data( object ) ); + return ( data && data.data()->animation() && data.data()->animation().data()->isRunning() ); + + } + +} diff --git a/style/animations/adwaitatoolboxengine.h b/style/animations/adwaitatoolboxengine.h new file mode 100644 index 0000000..29a5599 --- /dev/null +++ b/style/animations/adwaitatoolboxengine.h @@ -0,0 +1,103 @@ +#ifndef adwaitatoolboxengine_h +#define adwaitatoolboxengine_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 "adwaitabaseengine.h" +#include "adwaitadatamap.h" +#include "adwaitawidgetstatedata.h" + +namespace Adwaita +{ + + //* QToolBox animation engine + class ToolBoxEngine: public BaseEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit ToolBoxEngine( QObject* parent ): + BaseEngine( parent ) + {} + + //* destructor + virtual ~ToolBoxEngine( void ) + {} + + //* enability + virtual void setEnabled( bool value ) + { + BaseEngine::setEnabled( value ); + _data.setEnabled( value ); + } + + //* duration + virtual void setDuration( int value ) + { + BaseEngine::setDuration( value ); + _data.setDuration( value ); + } + + //* register widget + virtual bool registerWidget( QWidget* ); + + //* true if widget hover state is changed + virtual bool updateState( const QPaintDevice*, bool ); + + //* true if widget is animated + virtual bool isAnimated( const QPaintDevice* ); + + //* animation opacity + virtual qreal opacity( const QPaintDevice* object ) + { return isAnimated( object ) ? data( object ).data()->opacity(): AnimationData::OpacityInvalid; } + + public Q_SLOTS: + + //* remove widget from map + virtual bool unregisterWidget( QObject* data ) + { + + if( !data ) return false; + + // reinterpret_cast is safe here since only the address is used to find + // data in the map + return _data.unregisterWidget( reinterpret_cast(data) ); + + } + + protected: + + //* returns data associated to widget + PaintDeviceDataMap::Value data( const QPaintDevice* object ) + { return _data.find( object ).data(); } + + private: + + //* map + PaintDeviceDataMap _data; + + }; + +} + +#endif diff --git a/style/animations/adwaitatransitiondata.cpp b/style/animations/adwaitatransitiondata.cpp new file mode 100644 index 0000000..6444c88 --- /dev/null +++ b/style/animations/adwaitatransitiondata.cpp @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////////// +// adwaitatransitiondata.cpp +// data container for generic transitions +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitatransitiondata.h" + +namespace Adwaita +{ + + //_________________________________________________________________ + TransitionData::TransitionData( QObject* parent, QWidget* target, int duration ): + QObject( parent ), + _transition( new TransitionWidget( target, duration ) ) + { _transition.data()->hide(); } + + //_________________________________________________________________ + TransitionData::~TransitionData( void ) + { if( _transition ) _transition.data()->deleteLater(); } + +} diff --git a/style/animations/adwaitatransitiondata.h b/style/animations/adwaitatransitiondata.h new file mode 100644 index 0000000..743c1f8 --- /dev/null +++ b/style/animations/adwaitatransitiondata.h @@ -0,0 +1,144 @@ +#ifndef adwaitatransitiondata_h +#define adwaitatransitiondata_h + +////////////////////////////////////////////////////////////////////////////// +// adwaitatransitiondata.h +// data container for generic transitions +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitatransitionwidget.h" + +#include +#include +#include + +namespace Adwaita +{ + + //* generic data + class TransitionData: public QObject + { + + Q_OBJECT + + public: + + //* constructor + TransitionData( QObject* parent, QWidget* target, int ); + + //* destructor + virtual ~TransitionData( void ); + + //* enability + virtual void setEnabled( bool value ) + { _enabled = value; } + + //* enability + virtual bool enabled( void ) const + { return _enabled; } + + //* duration + virtual void setDuration( int duration ) + { + if( _transition ) + { _transition.data()->setDuration( duration ); } + } + + //* max render time + void setMaxRenderTime( int value ) + { _maxRenderTime = value; } + + //* max renderTime + const int& maxRenderTime( void ) const + { return _maxRenderTime; } + + //* start clock + void startClock( void ) + { + if( _clock.isNull() ) _clock.start(); + else _clock.restart(); + } + + //* check if rendering is two slow + bool slow( void ) const + { return !( _clock.isNull() || _clock.elapsed() <= maxRenderTime() ); } + + protected Q_SLOTS: + + //* initialize animation + virtual bool initializeAnimation( void ) = 0; + + //* animate + virtual bool animate( void ) = 0; + + protected: + + //* returns true if one parent matches given class name + inline bool hasParent( const QWidget*, const char* ) const; + + //* transition widget + virtual const TransitionWidget::Pointer& transition( void ) const + { return _transition; } + + //* used to avoid recursion when grabbing widgets + void setRecursiveCheck( bool value ) + { _recursiveCheck = value; } + + //* used to avoid recursion when grabbing widgets + bool recursiveCheck( void ) const + { return _recursiveCheck; } + + private: + + //* enability + bool _enabled = true; + + //* used to avoid recursion when grabbing widgets + bool _recursiveCheck = false; + + //* timer used to detect slow rendering + QTime _clock; + + //* max render time + /*! used to detect slow rendering */ + int _maxRenderTime = 200; + + //* animation handling + TransitionWidget::Pointer _transition; + + }; + + //_____________________________________________________________________________________ + bool TransitionData::hasParent( const QWidget* widget, const char* className ) const + { + if( !widget ) return false; + for( QWidget* parent = widget->parentWidget(); parent; parent = parent->parentWidget() ) + { if( parent->inherits( className ) ) return true; } + + return false; + } + +} + +#endif diff --git a/style/animations/adwaitatransitionwidget.cpp b/style/animations/adwaitatransitionwidget.cpp new file mode 100644 index 0000000..e03b8cc --- /dev/null +++ b/style/animations/adwaitatransitionwidget.cpp @@ -0,0 +1,309 @@ +////////////////////////////////////////////////////////////////////////////// +// adwaitatransitionwidget.cpp +// stores event filters and maps widgets to transitions for transitions +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitatransitionwidget.h" + +#include +#include +#include +#include + +namespace Adwaita +{ + + //________________________________________________ + bool TransitionWidget::_paintEnabled = true; + bool TransitionWidget::paintEnabled( void ) + { return _paintEnabled; } + + int TransitionWidget::_steps = 0; + + //________________________________________________ + TransitionWidget::TransitionWidget( QWidget* parent, int duration ): + QWidget( parent ), + _animation( new Animation( duration, this ) ) + { + + // background flags + setAttribute( Qt::WA_NoSystemBackground ); + setAutoFillBackground( false ); + + // setup animation + _animation.data()->setStartValue( 0 ); + _animation.data()->setEndValue( 1.0 ); + _animation.data()->setTargetObject( this ); + _animation.data()->setPropertyName( "opacity" ); + + // hide when animation is finished + connect( _animation.data(), SIGNAL(finished()), SLOT(hide()) ); + + } + + //________________________________________________ + QPixmap TransitionWidget::grab( QWidget* widget, QRect rect ) + { + + // change rect + if( !rect.isValid() ) rect = widget->rect(); + if( !rect.isValid() ) return QPixmap(); + + // initialize pixmap + QPixmap out( rect.size() ); + out.fill( Qt::transparent ); + _paintEnabled = false; + + if( testFlag( GrabFromWindow ) ) + { + + rect = rect.translated( widget->mapTo( widget->window(), widget->rect().topLeft() ) ); + widget = widget->window(); + #if QT_VERSION < 0x050000 + out = QPixmap::grabWidget( widget, rect ); + #else + out = widget->grab( rect ); + #endif + + } else { + + if( !testFlag( Transparent ) ) { grabBackground( out, widget, rect ); } + grabWidget( out, widget, rect ); + + } + + _paintEnabled = true; + + return out; + + } + + //________________________________________________ + bool TransitionWidget::event( QEvent* event ) + { + switch( event->type() ) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::KeyPress: + case QEvent::KeyRelease: + endAnimation(); + hide(); + event->ignore(); + return false; + + default: return QWidget::event( event ); + } + + } + + //________________________________________________ + void TransitionWidget::paintEvent( QPaintEvent* event ) + { + + // fully transparent case + if( opacity() >= 1.0 && endPixmap().isNull() ) return; + if( !_paintEnabled ) return; + + // get rect + QRect rect = event->rect(); + if( !rect.isValid() ) rect = this->rect(); + + // local pixmap + bool paintOnWidget( testFlag( PaintOnWidget ) && !testFlag( Transparent ) ); + if( !paintOnWidget ) + { + + if( _currentPixmap.isNull() || _currentPixmap.size() != size() ) + { _currentPixmap = QPixmap( size() ); } + + } + + // fill + _currentPixmap.fill( Qt::transparent ); + + // copy local pixmap to current + { + + QPainter p; + + // draw end pixmap first, provided that opacity is small enough + if( opacity() >= 0.004 && !_endPixmap.isNull() ) + { + + // faded endPixmap if parent target is transparent and opacity is + if( opacity() <= 0.996 && testFlag( Transparent ) ) + { + + fade( _endPixmap, _currentPixmap, opacity(), rect ); + p.begin( &_currentPixmap ); + p.setClipRect( event->rect() ); + + } else { + + if( paintOnWidget ) p.begin( this ); + else p.begin( &_currentPixmap ); + p.setClipRect( event->rect() ); + p.drawPixmap( QPoint(), _endPixmap ); + + } + + } else { + + if( paintOnWidget ) p.begin( this ); + else p.begin( &_currentPixmap ); + p.setClipRect( event->rect() ); + + } + + // draw fading start pixmap + if( opacity() <= 0.996 && !_startPixmap.isNull() ) + { + if( opacity() >= 0.004 ) + { + + fade( _startPixmap, _localStartPixmap, 1.0-opacity(), rect ); + p.drawPixmap( QPoint(), _localStartPixmap ); + + } else p.drawPixmap( QPoint(), _startPixmap ); + + } + + p.end(); + } + + // copy current pixmap on widget + if( !paintOnWidget ) + { + QPainter p( this ); + p.setClipRect( event->rect() ); + p.drawPixmap( QPoint(0,0), _currentPixmap ); + p.end(); + } + } + + //________________________________________________ + void TransitionWidget::grabBackground( QPixmap& pixmap, QWidget* widget, QRect& rect ) const + { + if( !widget ) return; + + QWidgetList widgets; + if( widget->autoFillBackground() ) + { widgets.append( widget ); } + + QWidget *parent(0); + + // get highest level parent + for( parent = widget->parentWidget(); parent; parent = parent->parentWidget() ) + { + + if( !( parent->isVisible() && parent->rect().isValid() ) ) continue; + + // store in list + widgets.append( parent ); + + // stop at topLevel + if( parent->isTopLevel() || parent->autoFillBackground() ) break; + + } + + if( !parent ) parent = widget; + + // painting + QPainter p(&pixmap); + p.setClipRect( rect ); + QBrush backgroundBrush = parent->palette().brush( parent->backgroundRole()); + if( backgroundBrush.style() == Qt::TexturePattern) + { + + p.drawTiledPixmap( rect, backgroundBrush.texture(), widget->mapTo( parent, rect.topLeft() ) ); + + } else { + + p.fillRect( pixmap.rect(), backgroundBrush ); + + } + + if( parent->isTopLevel() && parent->testAttribute(Qt::WA_StyledBackground)) + { + QStyleOption option; + option.initFrom(parent); + option.rect = rect; + option.rect.translate( widget->mapTo( parent, rect.topLeft() ) ); + p.translate(-option.rect.topLeft()); + parent->style()->drawPrimitive ( QStyle::PE_Widget, &option, &p, parent ); + p.translate(option.rect.topLeft()); + } + + // draw all widgets in parent list + // backward + QPaintEvent event(rect); + for( int i = widgets.size() - 1; i>=0; i-- ) + { + QWidget* w = widgets.at(i); + w->render( &p, -widget->mapTo( w, rect.topLeft() ), rect, 0 ); + } + + // end + p.end(); + + } + + //________________________________________________ + void TransitionWidget::grabWidget( QPixmap& pixmap, QWidget* widget, QRect& rect ) const + { widget->render( &pixmap, pixmap.rect().topLeft(), rect, QWidget::DrawChildren ); } + + //________________________________________________ + void TransitionWidget::fade( const QPixmap& source, QPixmap& target, qreal opacity, const QRect& rect ) const + { + + if( target.isNull() || target.size() != size() ) + { target = QPixmap( size() ); } + + // erase target + target.fill( Qt::transparent ); + + // check opacity + if( opacity*255 < 1 ) return; + + QPainter p( &target ); + p.setClipRect( rect ); + + // draw pixmap + p.drawPixmap( QPoint(0,0), source ); + + // opacity mask (0.996 corresponds to 254/255) + if( opacity <= 0.996 ) + { + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + QColor color( Qt::black ); + color.setAlphaF( opacity ); + p.fillRect(rect, color ); + } + + p.end(); + return; + } + +} diff --git a/style/animations/adwaitatransitionwidget.h b/style/animations/adwaitatransitionwidget.h new file mode 100644 index 0000000..5c12348 --- /dev/null +++ b/style/animations/adwaitatransitionwidget.h @@ -0,0 +1,235 @@ +#ifndef adwaitatransitionwidget_h +#define adwaitatransitionwidget_h +////////////////////////////////////////////////////////////////////////////// +// adwaitatransitionwidget.h +// stores event filters and maps widgets to transitions for transitions +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +////////////////////////////////////////////////////////////////////////////// + +#include "adwaitaanimation.h" +#include "adwaita.h" + +#include + +#include + +namespace Adwaita +{ + + //* temporary widget used to perform smooth transition between one widget state and another + class TransitionWidget: public QWidget + { + + Q_OBJECT + + //* declare opacity property + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) + + public: + + //* shortcut to painter + typedef WeakPointer Pointer; + + //* constructor + TransitionWidget( QWidget* parent, int duration ); + + //* destructor + virtual ~TransitionWidget( void ) = default; + + //*@name flags + //@{ + enum Flag + { + None = 0, + GrabFromWindow = 1<<0, + Transparent = 1<<1, + PaintOnWidget = 1<<2 + }; + + Q_DECLARE_FLAGS(Flags, Flag) + + void setFlags( Flags value ) + { _flags = value; } + + void setFlag( Flag flag, bool value = true ) + { + if( value ) _flags |= flag; + else _flags &= (~flag); + } + + bool testFlag( Flag flag ) const + { return _flags.testFlag( flag ); } + + //@} + + //* duration + void setDuration( int duration ) + { + if( _animation ) + { _animation.data()->setDuration( duration ); } + } + + //* duration + int duration( void ) const + { return ( _animation ) ? _animation.data()->duration() : 0; } + + //* steps + static void setSteps( int value ) + { _steps = value; } + + //*@name opacity + //@{ + + virtual qreal opacity( void ) const + { return _opacity; } + + virtual void setOpacity( qreal value ) + { + value = digitize( value ); + if( _opacity == value ) return; + _opacity = value; + update(); + } + + //@} + + //@name pixmaps handling + //@{ + + //* start + void resetStartPixmap( void ) + { setStartPixmap( QPixmap() ); } + + //* start + void setStartPixmap( QPixmap pixmap ) + { _startPixmap = pixmap; } + + //* start + const QPixmap& startPixmap( void ) const + { return _startPixmap; } + + //* end + void resetEndPixmap( void ) + { setEndPixmap( QPixmap() ); } + + //* end + void setEndPixmap( QPixmap pixmap ) + { + _endPixmap = pixmap; + _currentPixmap = pixmap; + } + + //* start + const QPixmap& endPixmap( void ) const + { return _endPixmap; } + + //* current + const QPixmap& currentPixmap( void ) const + { return _currentPixmap; } + + //@} + + //* grap pixmap + QPixmap grab( QWidget* = 0, QRect = QRect() ); + + //* true if animated + virtual bool isAnimated( void ) const + { return _animation.data()->isRunning(); } + + //* end animation + virtual void endAnimation( void ) + { if( _animation.data()->isRunning() ) _animation.data()->stop(); } + + //* animate transition + virtual void animate( void ) + { + if( _animation.data()->isRunning() ) _animation.data()->stop(); + _animation.data()->start(); + } + + //* true if paint is enabled + static bool paintEnabled( void ); + + protected: + + //* generic event filter + virtual bool event( QEvent* ); + + //* paint event + virtual void paintEvent( QPaintEvent* ); + + //* grab widget background + /*! + Background is not rendered properly using QWidget::render. + Use home-made grabber instead. This is directly inspired from bespin. + Copyright (C) 2007 Thomas Luebking + */ + virtual void grabBackground( QPixmap&, QWidget*, QRect& ) const; + + //* grab widget + virtual void grabWidget( QPixmap&, QWidget*, QRect& ) const; + + //* fade pixmap + virtual void fade( const QPixmap& source, QPixmap& target, qreal opacity, const QRect& ) const; + + //* apply step + virtual qreal digitize( const qreal& value ) const + { + if( _steps > 0 ) return std::floor( value*_steps )/_steps; + else return value; + } + + private: + + //* Flags + Flags _flags = None; + + //* paint enabled + static bool _paintEnabled; + + //* internal transition animation + Animation::Pointer _animation; + + //* animation starting pixmap + QPixmap _startPixmap; + + //* animation starting pixmap + QPixmap _localStartPixmap; + + //* animation starting pixmap + QPixmap _endPixmap; + + //* current pixmap + QPixmap _currentPixmap; + + //* current state opacity + qreal _opacity = 0; + + //* steps + static int _steps; + + }; + +} + +#endif diff --git a/style/animations/adwaitawidgetstatedata.cpp b/style/animations/adwaitawidgetstatedata.cpp new file mode 100644 index 0000000..852ab11 --- /dev/null +++ b/style/animations/adwaitawidgetstatedata.cpp @@ -0,0 +1,50 @@ +/************************************************************************* + * 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 "adwaitawidgetstatedata.h" + +namespace Adwaita +{ + + //______________________________________________ + bool WidgetStateData::updateState( bool value ) + { + if( !_initialized ) + { + + _state = value; + _initialized = true; + return false; + + } else if( _state == value ) { + + return false; + + } else { + + _state = value; + animation().data()->setDirection( _state ? Animation::Forward : Animation::Backward ); + if( !animation().data()->isRunning() ) animation().data()->start(); + return true; + + } + + } + +} diff --git a/style/animations/adwaitawidgetstatedata.h b/style/animations/adwaitawidgetstatedata.h new file mode 100644 index 0000000..7d88acb --- /dev/null +++ b/style/animations/adwaitawidgetstatedata.h @@ -0,0 +1,62 @@ +#ifndef adwaitawidgetstatedata_h +#define adwaitawidgetstatedata_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 "adwaitagenericdata.h" + +namespace Adwaita +{ + + //* handle widget state (hover/focus/enable) changes + class WidgetStateData: public GenericData + { + + Q_OBJECT + + public: + + //* constructor + WidgetStateData( QObject* parent, QWidget* target, int duration, bool state = false ): + GenericData( parent, target, duration ), + _initialized( false ), + _state( state ) + {} + + //* destructor + virtual ~WidgetStateData( void ) + {} + + /** + returns true if hover has Changed + and starts timer accordingly + */ + virtual bool updateState( bool value ); + + private: + + bool _initialized; + bool _state; + + }; + +} + +#endif diff --git a/style/animations/adwaitawidgetstateengine.cpp b/style/animations/adwaitawidgetstateengine.cpp new file mode 100644 index 0000000..1a8e0ba --- /dev/null +++ b/style/animations/adwaitawidgetstateengine.cpp @@ -0,0 +1,128 @@ + +/************************************************************************* + * 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 "adwaitawidgetstateengine.h" + +#include "adwaitaenabledata.h" + +namespace Adwaita +{ + + //____________________________________________________________ + bool WidgetStateEngine::registerWidget( QWidget* widget, AnimationModes mode ) + { + + if( !widget ) return false; + if( mode&AnimationHover && !_hoverData.contains( widget ) ) { _hoverData.insert( widget, new WidgetStateData( this, widget, duration() ), enabled() ); } + if( mode&AnimationFocus && !_focusData.contains( widget ) ) { _focusData.insert( widget, new WidgetStateData( this, widget, duration() ), enabled() ); } + if( mode&AnimationEnable && !_enableData.contains( widget ) ) { _enableData.insert( widget, new EnableData( this, widget, duration() ), enabled() ); } + if( mode&AnimationPressed && !_pressedData.contains( widget ) ) { _pressedData.insert( widget, new WidgetStateData( this, widget, duration() ), enabled() ); } + + // connect destruction signal + connect( widget, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterWidget(QObject*)), Qt::UniqueConnection ); + + return true; + + } + + //____________________________________________________________ + BaseEngine::WidgetList WidgetStateEngine::registeredWidgets( AnimationModes mode ) const + { + + WidgetList out; + + using Value = DataMap::Value; + + if( mode&AnimationHover ) + { + foreach( const Value& value, _hoverData ) + { if( value ) out.insert( value.data()->target().data() ); } + } + + if( mode&AnimationFocus ) + { + foreach( const Value& value, _focusData ) + { if( value ) out.insert( value.data()->target().data() ); } + } + + if( mode&AnimationEnable ) + { + foreach( const Value& value, _enableData ) + { if( value ) out.insert( value.data()->target().data() ); } + } + + if( mode&AnimationPressed ) + { + foreach( const Value& value, _pressedData ) + { if( value ) out.insert( value.data()->target().data() ); } + } + + return out; + + } + + //____________________________________________________________ + bool WidgetStateEngine::updateState( const QObject* object, AnimationMode mode, bool value ) + { + DataMap::Value data( WidgetStateEngine::data( object, mode ) ); + return ( data && data.data()->updateState( value ) ); + } + + //____________________________________________________________ + bool WidgetStateEngine::isAnimated( const QObject* object, AnimationMode mode ) + { + + DataMap::Value data( WidgetStateEngine::data( object, mode ) ); + return ( data && data.data()->animation() && data.data()->animation().data()->isRunning() ); + + } + + //____________________________________________________________ + DataMap::Value WidgetStateEngine::data( const QObject* object, AnimationMode mode ) + { + + switch( mode ) + { + case AnimationHover: return _hoverData.find( object ).data(); + case AnimationFocus: return _focusData.find( object ).data(); + case AnimationEnable: return _enableData.find( object ).data(); + case AnimationPressed: return _pressedData.find( object ).data(); + default: return DataMap::Value(); + } + + } + + //____________________________________________________________ + DataMap& WidgetStateEngine::dataMap( AnimationMode mode ) + { + + switch( mode ) + { + default: + case AnimationHover: return _hoverData; + case AnimationFocus: return _focusData; + case AnimationEnable: return _enableData; + case AnimationPressed: return _pressedData; + + } + + } + +} diff --git a/style/animations/adwaitawidgetstateengine.h b/style/animations/adwaitawidgetstateengine.h new file mode 100644 index 0000000..18f2a0c --- /dev/null +++ b/style/animations/adwaitawidgetstateengine.h @@ -0,0 +1,162 @@ +#ifndef adwaitawidgetstateengine_h +#define adwaitawidgetstateengine_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 "adwaita.h" +#include "adwaitabaseengine.h" +#include "adwaitadatamap.h" +#include "adwaitawidgetstatedata.h" + +namespace Adwaita +{ + + //* used for simple widgets + class WidgetStateEngine: public BaseEngine + { + + Q_OBJECT + + public: + + //* constructor + explicit WidgetStateEngine( QObject* parent ): + BaseEngine( parent ) + {} + + //* destructor + virtual ~WidgetStateEngine( void ) + {} + + //* register widget + virtual bool registerWidget( QWidget*, AnimationModes ); + + //* returns registered widgets + virtual WidgetList registeredWidgets( AnimationModes ) const; + + using BaseEngine::registeredWidgets; + + //* true if widget hover state is changed + virtual bool updateState( const QObject*, AnimationMode, bool ); + + //* true if widget is animated + virtual bool isAnimated( const QObject*, AnimationMode ); + + //* animation opacity + virtual qreal opacity( const QObject* object, AnimationMode mode ) + { return isAnimated( object, mode ) ? data( object, mode ).data()->opacity(): AnimationData::OpacityInvalid; } + + //* animation mode + /** precedence on focus */ + virtual AnimationMode frameAnimationMode( const QObject* object ) + { + if( isAnimated( object, AnimationEnable ) ) return AnimationEnable; + else if( isAnimated( object, AnimationFocus ) ) return AnimationFocus; + else if( isAnimated( object, AnimationHover ) ) return AnimationHover; + else return AnimationNone; + } + + //* animation opacity + /** precedence on focus */ + virtual qreal frameOpacity( const QObject* object ) + { + if( isAnimated( object, AnimationEnable ) ) return data( object, AnimationEnable ).data()->opacity(); + else if( isAnimated( object, AnimationFocus ) ) return data( object, AnimationFocus ).data()->opacity(); + else if( isAnimated( object, AnimationHover ) ) return data( object, AnimationHover ).data()->opacity(); + else return AnimationData::OpacityInvalid; + } + + //* animation mode + /** precedence on mouseOver */ + virtual AnimationMode buttonAnimationMode( const QObject* object ) + { + if( isAnimated( object, AnimationEnable ) ) return AnimationEnable; + else if( isAnimated( object, AnimationPressed ) ) return AnimationPressed; + else if( isAnimated( object, AnimationHover ) ) return AnimationHover; + else if( isAnimated( object, AnimationFocus ) ) return AnimationFocus; + else return AnimationNone; + } + + //* animation opacity + /** precedence on mouseOver */ + virtual qreal buttonOpacity( const QObject* object ) + { + if( isAnimated( object, AnimationEnable ) ) return data( object, AnimationEnable ).data()->opacity(); + else if( isAnimated( object, AnimationPressed ) ) return data( object, AnimationPressed ).data()->opacity(); + else if( isAnimated( object, AnimationHover ) ) return data( object, AnimationHover ).data()->opacity(); + else if( isAnimated( object, AnimationFocus ) ) return data( object, AnimationFocus ).data()->opacity(); + else return AnimationData::OpacityInvalid; + } + + //* duration + virtual void setEnabled( bool value ) + { + BaseEngine::setEnabled( value ); + _hoverData.setEnabled( value ); + _focusData.setEnabled( value ); + _enableData.setEnabled( value ); + _pressedData.setEnabled( value ); + } + + //* duration + virtual void setDuration( int value ) + { + BaseEngine::setDuration( value ); + _hoverData.setDuration( value ); + _focusData.setDuration( value ); + _enableData.setDuration( value ); + _pressedData.setDuration( value/2 ); + } + + public Q_SLOTS: + + //* remove widget from map + virtual bool unregisterWidget( QObject* object ) + { + if( !object ) return false; + bool found = false; + if( _hoverData.unregisterWidget( object ) ) found = true; + if( _focusData.unregisterWidget( object ) ) found = true; + if( _enableData.unregisterWidget( object ) ) found = true; + if( _pressedData.unregisterWidget( object ) ) found = true; + return found; + } + + protected: + + //* returns data associated to widget + DataMap::Value data( const QObject*, AnimationMode ); + + //* returns data map associated to animation mode + DataMap& dataMap( AnimationMode ); + + private: + + //* maps + DataMap _hoverData; + DataMap _focusData; + DataMap _enableData; + DataMap _pressedData; + + }; + +} + +#endif diff --git a/style/config-adwaita.h.cmake b/style/config-adwaita.h.cmake new file mode 100644 index 0000000..3645d41 --- /dev/null +++ b/style/config-adwaita.h.cmake @@ -0,0 +1,36 @@ +/* config-adwaita.h. Generated by cmake from config-adwaita.h.cmake */ + +/************************************************************************* + * 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 . * + *************************************************************************/ + +#ifndef config_adwaita_h +#define config_adwaita_h + +/* Define to 1 if adwaita is compiled against KDE4 */ +#cmakedefine01 ADWAITA_USE_KDE4 + +/* Define to 1 if FrameworkIntegration/Kstyle libraries are found */ +#cmakedefine01 ADWAITA_HAVE_KSTYLE + +/* Define to 1 if XCB libraries are found */ +#cmakedefine01 ADWAITA_HAVE_X11 + +#cmakedefine01 ADWAITA_HAVE_KWAYLAND + +#endif diff --git a/style/debug/adwaitawidgetexplorer.cpp b/style/debug/adwaitawidgetexplorer.cpp new file mode 100644 index 0000000..0504cc1 --- /dev/null +++ b/style/debug/adwaitawidgetexplorer.cpp @@ -0,0 +1,165 @@ +/************************************************************************* + * 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 "adwaitawidgetexplorer.h" + +#include "adwaita.h" + +#include +#include +#include +#include + +namespace Adwaita +{ + + //________________________________________________ + WidgetExplorer::WidgetExplorer( QObject* parent ): + QObject( parent ), + _enabled( false ), + _drawWidgetRects( false ) + { + + _eventTypes.insert( QEvent::Enter, QStringLiteral( "Enter" ) ); + _eventTypes.insert( QEvent::Leave, QStringLiteral( "Leave" ) ); + + _eventTypes.insert( QEvent::HoverMove, QStringLiteral( "HoverMove" ) ); + _eventTypes.insert( QEvent::HoverEnter, QStringLiteral( "HoverEnter" ) ); + _eventTypes.insert( QEvent::HoverLeave, QStringLiteral( "HoverLeave" ) ); + + _eventTypes.insert( QEvent::MouseMove, QStringLiteral( "MouseMove" ) ); + _eventTypes.insert( QEvent::MouseButtonPress, QStringLiteral( "MouseButtonPress" ) ); + _eventTypes.insert( QEvent::MouseButtonRelease, QStringLiteral( "MouseButtonRelease" ) ); + + _eventTypes.insert( QEvent::FocusIn, QStringLiteral( "FocusIn" ) ); + _eventTypes.insert( QEvent::FocusOut, QStringLiteral( "FocusOut" ) ); + + // _eventTypes.insert( QEvent::Paint, "Paint" ); + + } + + //________________________________________________ + void WidgetExplorer::setEnabled( bool value ) + { + if( value == _enabled ) return; + _enabled = value; + + qApp->removeEventFilter( this ); + if( _enabled ) qApp->installEventFilter( this ); + } + + //________________________________________________ + bool WidgetExplorer::eventFilter( QObject* object, QEvent* event ) + { + +// if( object->isWidgetType() ) +// { +// QString type( _eventTypes[event->type()] ); +// if( !type.isEmpty() ) +// { +// QTextStream( stdout ) << "Adwaita::WidgetExplorer::eventFilter - widget: " << object << " (" << object->metaObject()->className() << ")"; +// QTextStream( stdout ) << " type: " << type << endl; +// } +// } + + switch( event->type() ) + { + case QEvent::Paint: + if( _drawWidgetRects ) + { + QWidget* widget( qobject_cast( object ) ); + if( !widget ) return false; + + QPainter painter( widget ); + painter.setRenderHints(QPainter::Antialiasing); + painter.setBrush( Qt::NoBrush ); + painter.setPen( Qt::red ); + painter.drawRect( widget->rect() ); + painter.end(); + } + break; + + case QEvent::MouseButtonPress: + { + + // cast event and check button + QMouseEvent* mouseEvent( static_cast( event ) ); + if( mouseEvent->button() != Qt::LeftButton ) break; + + // case widget and check (should not be necessary) + QWidget* widget( qobject_cast(object) ); + if( !widget ) return false; + + QTextStream( stdout ) + << "Adwaita::WidgetExplorer::eventFilter -" + << " event: " << event << " type: " << eventType( event->type() ) + << " widget: " << widgetInformation( widget ) + << endl; + + // print parent information + QWidget* parent( widget->parentWidget() ); + while( parent ) + { + QTextStream( stdout ) << " parent: " << widgetInformation( parent ) << endl; + parent = parent->parentWidget(); + } + QTextStream( stdout ) << "" << endl; + + } + break; + + default: break; + + } + + // always return false to go on with normal chain + return false; + + } + + //________________________________________________ + QString WidgetExplorer::eventType( const QEvent::Type& type ) const + { + switch( type ) + { + case QEvent::MouseButtonPress: return QStringLiteral( "MouseButtonPress" ); + case QEvent::MouseButtonRelease: return QStringLiteral( "MouseButtonRelease" ); + case QEvent::MouseMove: return QStringLiteral( "MouseMove" ); + default: return QStringLiteral( "Unknown" ); + } + } + + //________________________________________________ + QString WidgetExplorer::widgetInformation( const QWidget* widget ) const + { + + QRect r( widget->geometry() ); + const char* className( widget->metaObject()->className() ); + QString out; + QTextStream( &out ) << widget << " (" << className << ")" + << " position: " << r.x() << "," << r.y() + << " size: " << r.width() << "," << r.height() + << " sizeHint: " << widget->sizeHint().width() << "," << widget->sizeHint().height() + << " minimumSizeHint: " << widget->minimumSizeHint().width() << "," << widget->minimumSizeHint().height() + << " hover: " << widget->testAttribute( Qt::WA_Hover ); + + return out; + } + +} diff --git a/style/debug/adwaitawidgetexplorer.h b/style/debug/adwaitawidgetexplorer.h new file mode 100644 index 0000000..7c43ce7 --- /dev/null +++ b/style/debug/adwaitawidgetexplorer.h @@ -0,0 +1,79 @@ +#ifndef adwaitawidgetexplorer_h +#define adwaitawidgetexplorer_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 +#include + +namespace Adwaita +{ + + //* print widget's and parent's information on mouse click + class WidgetExplorer: public QObject + { + + Q_OBJECT + + public: + + //* constructor + explicit WidgetExplorer( QObject* ); + + //* enable + bool enabled( void ) const; + + //* enable + void setEnabled( bool ); + + //* widget rects + void setDrawWidgetRects( bool value ) + { _drawWidgetRects = value; } + + //* event filter + virtual bool eventFilter( QObject*, QEvent* ); + + protected: + + //* event type + QString eventType( const QEvent::Type& ) const; + + //* print widget information + QString widgetInformation( const QWidget* ) const; + + private: + + //* enable state + bool _enabled; + + //* widget rects + bool _drawWidgetRects; + + //* map event types to string + QMap _eventTypes; + + }; + +} + +#endif diff --git a/style/fakeadwaitastyleconfigdata.cpp b/style/fakeadwaitastyleconfigdata.cpp new file mode 100644 index 0000000..ef2e690 --- /dev/null +++ b/style/fakeadwaitastyleconfigdata.cpp @@ -0,0 +1,177 @@ +// This file is generated by kconfig_compiler from adwaita.kcfg. +// All changes you do to this file will be lost. + +#include "fakeadwaitastyleconfigdata.h" + +#include + +using namespace Adwaita; + +namespace Adwaita { + +class StyleConfigDataHelper +{ + public: + StyleConfigDataHelper() : q(0) {} + ~StyleConfigDataHelper() { delete q; } + StyleConfigData *q; +}; +} + +StyleConfigData* StyleConfigData::_self = nullptr; + +StyleConfigData *StyleConfigData::self() +{ + if (!_self) + _self = new StyleConfigData; + + return _self; +} + +StyleConfigData::StyleConfigData( ) +{ + /* + setCurrentGroup( QLatin1String( "Common" ) ); + + KConfigSkeleton::ItemInt *itemShadowStrength; + itemShadowStrength = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "ShadowStrength" ), mShadowStrength, 90 ); + itemShadowStrength->setMinValue(25); + itemShadowStrength->setMaxValue(255); + addItem( itemShadowStrength, QLatin1String( "ShadowStrength" ) ); + KConfigSkeleton::ItemInt *itemShadowSize; + itemShadowSize = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "ShadowSize" ), mShadowSize, 16 ); + itemShadowSize->setMinValue(6); + itemShadowSize->setMaxValue(64); + addItem( itemShadowSize, QLatin1String( "ShadowSize" ) ); + KConfigSkeleton::ItemColor *itemShadowColor; + itemShadowColor = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "ShadowColor" ), mShadowColor, QColor( 0, 0, 0 ) ); + addItem( itemShadowColor, QLatin1String( "ShadowColor" ) ); + KConfigSkeleton::ItemBool *itemOutlineCloseButton; + itemOutlineCloseButton = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "OutlineCloseButton" ), mOutlineCloseButton, true ); + addItem( itemOutlineCloseButton, QLatin1String( "OutlineCloseButton" ) ); + + setCurrentGroup( QLatin1String( "Style" ) ); + + KConfigSkeleton::ItemBool *itemAnimationsEnabled; + itemAnimationsEnabled = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "AnimationsEnabled" ), mAnimationsEnabled, true ); + addItem( itemAnimationsEnabled, QLatin1String( "AnimationsEnabled" ) ); + KConfigSkeleton::ItemInt *itemAnimationSteps; + itemAnimationSteps = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "AnimationSteps" ), mAnimationSteps, 10 ); + addItem( itemAnimationSteps, QLatin1String( "AnimationSteps" ) ); + KConfigSkeleton::ItemInt *itemAnimationsDuration; + itemAnimationsDuration = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "AnimationsDuration" ), mAnimationsDuration, 100 ); + addItem( itemAnimationsDuration, QLatin1String( "AnimationsDuration" ) ); + KConfigSkeleton::ItemBool *itemStackedWidgetTransitionsEnabled; + itemStackedWidgetTransitionsEnabled = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "StackedWidgetTransitionsEnabled" ), mStackedWidgetTransitionsEnabled, false ); + addItem( itemStackedWidgetTransitionsEnabled, QLatin1String( "StackedWidgetTransitionsEnabled" ) ); + KConfigSkeleton::ItemBool *itemProgressBarAnimated; + itemProgressBarAnimated = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "ProgressBarAnimated" ), mProgressBarAnimated, true ); + addItem( itemProgressBarAnimated, QLatin1String( "ProgressBarAnimated" ) ); + KConfigSkeleton::ItemInt *itemProgressBarBusyStepDuration; + itemProgressBarBusyStepDuration = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "ProgressBarBusyStepDuration" ), mProgressBarBusyStepDuration, 800 ); + addItem( itemProgressBarBusyStepDuration, QLatin1String( "ProgressBarBusyStepDuration" ) ); + KConfigSkeleton::ItemInt *itemScrollBarAddLineButtons; + itemScrollBarAddLineButtons = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "ScrollBarAddLineButtons" ), mScrollBarAddLineButtons, 1 ); + addItem( itemScrollBarAddLineButtons, QLatin1String( "ScrollBarAddLineButtons" ) ); + KConfigSkeleton::ItemInt *itemScrollBarSubLineButtons; + itemScrollBarSubLineButtons = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "ScrollBarSubLineButtons" ), mScrollBarSubLineButtons, 1 ); + addItem( itemScrollBarSubLineButtons, QLatin1String( "ScrollBarSubLineButtons" ) ); + KConfigSkeleton::ItemBool *itemScrollBarShowOnMouseOver; + itemScrollBarShowOnMouseOver = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "ScrollBarShowOnMouseOver" ), mScrollBarShowOnMouseOver, true ); + addItem( itemScrollBarShowOnMouseOver, QLatin1String( "ScrollBarShowOnMouseOver" ) ); + QList valuesMnemonicsMode; + { + KConfigSkeleton::ItemEnum::Choice2 choice; + choice.name = QLatin1String("MN_NEVER"); + valuesMnemonicsMode.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice2 choice; + choice.name = QLatin1String("MN_AUTO"); + valuesMnemonicsMode.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice2 choice; + choice.name = QLatin1String("MN_ALWAYS"); + valuesMnemonicsMode.append( choice ); + } + KConfigSkeleton::ItemEnum *itemMnemonicsMode; + itemMnemonicsMode = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "MnemonicsMode" ), mMnemonicsMode, valuesMnemonicsMode, MN_AUTO ); + addItem( itemMnemonicsMode, QLatin1String( "MnemonicsMode" ) ); + KConfigSkeleton::ItemBool *itemToolBarDrawItemSeparator; + itemToolBarDrawItemSeparator = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "ToolBarDrawItemSeparator" ), mToolBarDrawItemSeparator, true ); + addItem( itemToolBarDrawItemSeparator, QLatin1String( "ToolBarDrawItemSeparator" ) ); + KConfigSkeleton::ItemBool *itemViewDrawFocusIndicator; + itemViewDrawFocusIndicator = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "ViewDrawFocusIndicator" ), mViewDrawFocusIndicator, true ); + addItem( itemViewDrawFocusIndicator, QLatin1String( "ViewDrawFocusIndicator" ) ); + KConfigSkeleton::ItemBool *itemSliderDrawTickMarks; + itemSliderDrawTickMarks = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "SliderDrawTickMarks" ), mSliderDrawTickMarks, true ); + addItem( itemSliderDrawTickMarks, QLatin1String( "SliderDrawTickMarks" ) ); + KConfigSkeleton::ItemBool *itemViewDrawTreeBranchLines; + itemViewDrawTreeBranchLines = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "ViewDrawTreeBranchLines" ), mViewDrawTreeBranchLines, true ); + addItem( itemViewDrawTreeBranchLines, QLatin1String( "ViewDrawTreeBranchLines" ) ); + KConfigSkeleton::ItemBool *itemViewInvertSortIndicator; + itemViewInvertSortIndicator = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "ViewInvertSortIndicator" ), mViewInvertSortIndicator, false ); + addItem( itemViewInvertSortIndicator, QLatin1String( "ViewInvertSortIndicator" ) ); + KConfigSkeleton::ItemBool *itemTabBarDrawCenteredTabs; + itemTabBarDrawCenteredTabs = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "TabBarDrawCenteredTabs" ), mTabBarDrawCenteredTabs, false ); + addItem( itemTabBarDrawCenteredTabs, QLatin1String( "TabBarDrawCenteredTabs" ) ); + KConfigSkeleton::ItemBool *itemTitleWidgetDrawFrame; + itemTitleWidgetDrawFrame = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "TitleWidgetDrawFrame" ), mTitleWidgetDrawFrame, false ); + addItem( itemTitleWidgetDrawFrame, QLatin1String( "TitleWidgetDrawFrame" ) ); + KConfigSkeleton::ItemBool *itemDockWidgetDrawFrame; + itemDockWidgetDrawFrame = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "DockWidgetDrawFrame" ), mDockWidgetDrawFrame, false ); + addItem( itemDockWidgetDrawFrame, QLatin1String( "DockWidgetDrawFrame" ) ); + KConfigSkeleton::ItemBool *itemSidePanelDrawFrame; + itemSidePanelDrawFrame = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "SidePanelDrawFrame" ), mSidePanelDrawFrame, false ); + addItem( itemSidePanelDrawFrame, QLatin1String( "SidePanelDrawFrame" ) ); + KConfigSkeleton::ItemBool *itemMenuItemDrawStrongFocus; + itemMenuItemDrawStrongFocus = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "MenuItemDrawStrongFocus" ), mMenuItemDrawStrongFocus, true ); + addItem( itemMenuItemDrawStrongFocus, QLatin1String( "MenuItemDrawStrongFocus" ) ); + QList valuesWindowDragMode; + { + KConfigSkeleton::ItemEnum::Choice2 choice; + choice.name = QLatin1String("WD_NONE"); + valuesWindowDragMode.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice2 choice; + choice.name = QLatin1String("WD_MINIMAL"); + valuesWindowDragMode.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice2 choice; + choice.name = QLatin1String("WD_FULL"); + valuesWindowDragMode.append( choice ); + } + KConfigSkeleton::ItemEnum *itemWindowDragMode; + itemWindowDragMode = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "WindowDragMode" ), mWindowDragMode, valuesWindowDragMode, WD_FULL ); + addItem( itemWindowDragMode, QLatin1String( "WindowDragMode" ) ); + KConfigSkeleton::ItemStringList *itemWindowDragWhiteList; + itemWindowDragWhiteList = new KConfigSkeleton::ItemStringList( currentGroup(), QLatin1String( "WindowDragWhiteList" ), mWindowDragWhiteList ); + addItem( itemWindowDragWhiteList, QLatin1String( "WindowDragWhiteList" ) ); + KConfigSkeleton::ItemStringList *itemWindowDragBlackList; + itemWindowDragBlackList = new KConfigSkeleton::ItemStringList( currentGroup(), QLatin1String( "WindowDragBlackList" ), mWindowDragBlackList ); + addItem( itemWindowDragBlackList, QLatin1String( "WindowDragBlackList" ) ); + KConfigSkeleton::ItemBool *itemUseWMMoveResize; + itemUseWMMoveResize = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "UseWMMoveResize" ), mUseWMMoveResize, true ); + addItem( itemUseWMMoveResize, QLatin1String( "UseWMMoveResize" ) ); + KConfigSkeleton::ItemBool *itemSplitterProxyEnabled; + itemSplitterProxyEnabled = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "SplitterProxyEnabled" ), mSplitterProxyEnabled, true ); + addItem( itemSplitterProxyEnabled, QLatin1String( "SplitterProxyEnabled" ) ); + KConfigSkeleton::ItemInt *itemSplitterProxyWidth; + itemSplitterProxyWidth = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "SplitterProxyWidth" ), mSplitterProxyWidth, 12 ); + addItem( itemSplitterProxyWidth, QLatin1String( "SplitterProxyWidth" ) ); + KConfigSkeleton::ItemBool *itemWidgetExplorerEnabled; + itemWidgetExplorerEnabled = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "WidgetExplorerEnabled" ), mWidgetExplorerEnabled, false ); + addItem( itemWidgetExplorerEnabled, QLatin1String( "WidgetExplorerEnabled" ) ); + KConfigSkeleton::ItemBool *itemDrawWidgetRects; + itemDrawWidgetRects = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "DrawWidgetRects" ), mDrawWidgetRects, false ); + addItem( itemDrawWidgetRects, QLatin1String( "DrawWidgetRects" ) ); + */ +} + +StyleConfigData::~StyleConfigData() +{ +} + diff --git a/style/fakeadwaitastyleconfigdata.h b/style/fakeadwaitastyleconfigdata.h new file mode 100644 index 0000000..014edce --- /dev/null +++ b/style/fakeadwaitastyleconfigdata.h @@ -0,0 +1,667 @@ +// This file is generated by kconfig_compiler from adwaita.kcfg. +// All changes you do to this file will be lost. +#ifndef ADWAITA_STYLECONFIGDATA_H +#define ADWAITA_STYLECONFIGDATA_H + +#include +#include +#include + +namespace Adwaita { + +class StyleConfigData +{ + public: + enum EnumMnemonicsMode { MN_NEVER, MN_AUTO, MN_ALWAYS }; + enum EnumWindowDragMode { WD_NONE, WD_MINIMAL, WD_FULL }; + + static StyleConfigData *self(); + ~StyleConfigData(); + + /** + Set ShadowStrength + */ + static + void setShadowStrength( int v ) + { + if (v < 25) + { + v = 25; + } + + if (v > 255) + { + v = 255; + } + + self()->mShadowStrength = v; + } + + /** + Get ShadowStrength + */ + static + int shadowStrength() + { + return self()->mShadowStrength; + } + + /** + Set ShadowSize + */ + static + void setShadowSize( int v ) + { + if (v < 6) + { + v = 6; + } + + if (v > 64) + { + v = 64; + } + + + self()->mShadowSize = v; + } + + /** + Get ShadowSize + */ + static + int shadowSize() + { + return self()->mShadowSize; + } + + /** + Set ShadowColor + */ + static + void setShadowColor( const QColor & v ) + { + self()->mShadowColor = v; + } + + /** + Get ShadowColor + */ + static + QColor shadowColor() + { + return self()->mShadowColor; + } + + /** + Set OutlineCloseButton + */ + static + void setOutlineCloseButton( bool v ) + { + self()->mOutlineCloseButton = v; + } + + /** + Get OutlineCloseButton + */ + static + bool outlineCloseButton() + { + return self()->mOutlineCloseButton; + } + + /** + Set AnimationsEnabled + */ + static + void setAnimationsEnabled( bool v ) + { + self()->mAnimationsEnabled = v; + } + + /** + Get AnimationsEnabled + */ + static + bool animationsEnabled() + { + return self()->mAnimationsEnabled; + } + + /** + Set AnimationSteps + */ + static + void setAnimationSteps( int v ) + { + self()->mAnimationSteps = v; + } + + /** + Get AnimationSteps + */ + static + int animationSteps() + { + return self()->mAnimationSteps; + } + + /** + Set AnimationsDuration + */ + static + void setAnimationsDuration( int v ) + { + self()->mAnimationsDuration = v; + } + + /** + Get AnimationsDuration + */ + static + int animationsDuration() + { + return self()->mAnimationsDuration; + } + + /** + Set StackedWidgetTransitionsEnabled + */ + static + void setStackedWidgetTransitionsEnabled( bool v ) + { + self()->mStackedWidgetTransitionsEnabled = v; + } + + /** + Get StackedWidgetTransitionsEnabled + */ + static + bool stackedWidgetTransitionsEnabled() + { + return self()->mStackedWidgetTransitionsEnabled; + } + + /** + Set ProgressBarAnimated + */ + static + void setProgressBarAnimated( bool v ) + { + self()->mProgressBarAnimated = v; + } + + /** + Get ProgressBarAnimated + */ + static + bool progressBarAnimated() + { + return self()->mProgressBarAnimated; + } + + /** + Set ProgressBarBusyStepDuration + */ + static + void setProgressBarBusyStepDuration( int v ) + { + self()->mProgressBarBusyStepDuration = v; + } + + /** + Get ProgressBarBusyStepDuration + */ + static + int progressBarBusyStepDuration() + { + return self()->mProgressBarBusyStepDuration; + } + + /** + Set ScrollBarAddLineButtons + */ + static + void setScrollBarAddLineButtons( int v ) + { + self()->mScrollBarAddLineButtons = v; + } + + /** + Get ScrollBarAddLineButtons + */ + static + int scrollBarAddLineButtons() + { + return self()->mScrollBarAddLineButtons; + } + + /** + Set ScrollBarSubLineButtons + */ + static + void setScrollBarSubLineButtons( int v ) + { + self()->mScrollBarSubLineButtons = v; + } + + /** + Get ScrollBarSubLineButtons + */ + static + int scrollBarSubLineButtons() + { + return self()->mScrollBarSubLineButtons; + } + + /** + Set ScrollBarShowOnMouseOver + */ + static + void setScrollBarShowOnMouseOver( bool v ) + { + self()->mScrollBarShowOnMouseOver = v; + } + + /** + Get ScrollBarShowOnMouseOver + */ + static + bool scrollBarShowOnMouseOver() + { + return self()->mScrollBarShowOnMouseOver; + } + + /** + Set MnemonicsMode + */ + static + void setMnemonicsMode( int v ) + { + self()->mMnemonicsMode = v; + } + + /** + Get MnemonicsMode + */ + static + int mnemonicsMode() + { + return self()->mMnemonicsMode; + } + + /** + Set ToolBarDrawItemSeparator + */ + static + void setToolBarDrawItemSeparator( bool v ) + { + self()->mToolBarDrawItemSeparator = v; + } + + /** + Get ToolBarDrawItemSeparator + */ + static + bool toolBarDrawItemSeparator() + { + return self()->mToolBarDrawItemSeparator; + } + + /** + Set ViewDrawFocusIndicator + */ + static + void setViewDrawFocusIndicator( bool v ) + { + self()->mViewDrawFocusIndicator = v; + } + + /** + Get ViewDrawFocusIndicator + */ + static + bool viewDrawFocusIndicator() + { + return self()->mViewDrawFocusIndicator; + } + + /** + Set SliderDrawTickMarks + */ + static + void setSliderDrawTickMarks( bool v ) + { + self()->mSliderDrawTickMarks = v; + } + + /** + Get SliderDrawTickMarks + */ + static + bool sliderDrawTickMarks() + { + return self()->mSliderDrawTickMarks; + } + + /** + Set ViewDrawTreeBranchLines + */ + static + void setViewDrawTreeBranchLines( bool v ) + { + self()->mViewDrawTreeBranchLines = v; + } + + /** + Get ViewDrawTreeBranchLines + */ + static + bool viewDrawTreeBranchLines() + { + return self()->mViewDrawTreeBranchLines; + } + + /** + Set ViewInvertSortIndicator + */ + static + void setViewInvertSortIndicator( bool v ) + { + self()->mViewInvertSortIndicator = v; + } + + /** + Get ViewInvertSortIndicator + */ + static + bool viewInvertSortIndicator() + { + return self()->mViewInvertSortIndicator; + } + + /** + Set TabBarDrawCenteredTabs + */ + static + void setTabBarDrawCenteredTabs( bool v ) + { + self()->mTabBarDrawCenteredTabs = v; + } + + /** + Get TabBarDrawCenteredTabs + */ + static + bool tabBarDrawCenteredTabs() + { + return self()->mTabBarDrawCenteredTabs; + } + + /** + Set TitleWidgetDrawFrame + */ + static + void setTitleWidgetDrawFrame( bool v ) + { + self()->mTitleWidgetDrawFrame = v; + } + + /** + Get TitleWidgetDrawFrame + */ + static + bool titleWidgetDrawFrame() + { + return self()->mTitleWidgetDrawFrame; + } + + /** + Set DockWidgetDrawFrame + */ + static + void setDockWidgetDrawFrame( bool v ) + { + self()->mDockWidgetDrawFrame = v; + } + + /** + Get DockWidgetDrawFrame + */ + static + bool dockWidgetDrawFrame() + { + return self()->mDockWidgetDrawFrame; + } + + /** + Set SidePanelDrawFrame + */ + static + void setSidePanelDrawFrame( bool v ) + { + self()->mSidePanelDrawFrame = v; + } + + /** + Get SidePanelDrawFrame + */ + static + bool sidePanelDrawFrame() + { + return self()->mSidePanelDrawFrame; + } + + /** + Set MenuItemDrawStrongFocus + */ + static + void setMenuItemDrawStrongFocus( bool v ) + { + self()->mMenuItemDrawStrongFocus = v; + } + + /** + Get MenuItemDrawStrongFocus + */ + static + bool menuItemDrawStrongFocus() + { + return self()->mMenuItemDrawStrongFocus; + } + + /** + Set WindowDragMode + */ + static + void setWindowDragMode( int v ) + { + self()->mWindowDragMode = v; + } + + /** + Get WindowDragMode + */ + static + int windowDragMode() + { + return self()->mWindowDragMode; + } + + /** + Set WindowDragWhiteList + */ + static + void setWindowDragWhiteList( const QStringList & v ) + { + self()->mWindowDragWhiteList = v; + } + + /** + Get WindowDragWhiteList + */ + static + QStringList windowDragWhiteList() + { + return self()->mWindowDragWhiteList; + } + + /** + Set WindowDragBlackList + */ + static + void setWindowDragBlackList( const QStringList & v ) + { + self()->mWindowDragBlackList = v; + } + + /** + Get WindowDragBlackList + */ + static + QStringList windowDragBlackList() + { + return self()->mWindowDragBlackList; + } + + /** + Set UseWMMoveResize + */ + static + void setUseWMMoveResize( bool v ) + { + self()->mUseWMMoveResize = v; + } + + /** + Get UseWMMoveResize + */ + static + bool useWMMoveResize() + { + return self()->mUseWMMoveResize; + } + + /** + Set SplitterProxyEnabled + */ + static + void setSplitterProxyEnabled( bool v ) + { + self()->mSplitterProxyEnabled = v; + } + + /** + Get SplitterProxyEnabled + */ + static + bool splitterProxyEnabled() + { + return self()->mSplitterProxyEnabled; + } + + /** + Set SplitterProxyWidth + */ + static + void setSplitterProxyWidth( int v ) + { + self()->mSplitterProxyWidth = v; + } + + /** + Get SplitterProxyWidth + */ + static + int splitterProxyWidth() + { + return self()->mSplitterProxyWidth; + } + + /** + Set WidgetExplorerEnabled + */ + static + void setWidgetExplorerEnabled( bool v ) + { + self()->mWidgetExplorerEnabled = v; + } + + /** + Get WidgetExplorerEnabled + */ + static + bool widgetExplorerEnabled() + { + return self()->mWidgetExplorerEnabled; + } + + /** + Set DrawWidgetRects + */ + static + void setDrawWidgetRects( bool v ) + { + self()->mDrawWidgetRects = v; + } + + /** + Get DrawWidgetRects + */ + static + bool drawWidgetRects() + { + return self()->mDrawWidgetRects; + } + + protected: + StyleConfigData(); + friend class StyleConfigDataHelper; + + + // Common + int mShadowStrength { 0 }; + int mShadowSize { 0 }; + QColor mShadowColor { Qt::transparent }; + bool mOutlineCloseButton { false }; + + // Style + bool mAnimationsEnabled { true }; + int mAnimationSteps { 100 }; + int mAnimationsDuration { 180 }; + bool mStackedWidgetTransitionsEnabled { false }; + bool mProgressBarAnimated { true }; + int mProgressBarBusyStepDuration { 600 }; + int mScrollBarAddLineButtons { 0 }; + int mScrollBarSubLineButtons { 0 }; + bool mScrollBarShowOnMouseOver { true }; + int mMnemonicsMode { MN_AUTO }; + bool mToolBarDrawItemSeparator { 0 }; + bool mViewDrawFocusIndicator { true }; + bool mSliderDrawTickMarks { true }; + bool mViewDrawTreeBranchLines { true }; + bool mViewInvertSortIndicator { true }; + bool mTabBarDrawCenteredTabs { false }; + bool mTitleWidgetDrawFrame { true }; + bool mDockWidgetDrawFrame { true }; + bool mSidePanelDrawFrame { false }; + bool mMenuItemDrawStrongFocus { true }; + int mWindowDragMode { 0 }; + QStringList mWindowDragWhiteList { }; + QStringList mWindowDragBlackList { }; + bool mUseWMMoveResize { true }; + bool mSplitterProxyEnabled { true }; + int mSplitterProxyWidth { 3 }; + bool mWidgetExplorerEnabled { false }; + bool mDrawWidgetRects { false }; + + private: + + static StyleConfigData *_self; +}; + +} + +#endif + diff --git a/style/kstylekde4compat.cpp b/style/kstylekde4compat.cpp new file mode 100644 index 0000000..8087d56 --- /dev/null +++ b/style/kstylekde4compat.cpp @@ -0,0 +1,94 @@ +/************************************************************************* + * Copyright (C) 2015 by David Edmundson * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) 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 "kstylekde4compat.h" +#include "adwaita.h" + +#include + +static const QStyle::StyleHint SH_KCustomStyleElement = (QStyle::StyleHint)0xff000001; +static const int X_KdeBase = 0xff000000; + +//_____________________________________________________________________ +KStyleKDE4Compat::KStyleKDE4Compat() +{ + controlCounter = subElementCounter = X_KdeBase; + hintCounter = X_KdeBase + 1; //sic! X_KdeBase is covered by SH_KCustomStyleElement +} + +//_____________________________________________________________________ +KStyleKDE4Compat::~KStyleKDE4Compat() +{} + +//_____________________________________________________________________ +static inline int newStyleElement(const QString &element, const char *check, int &counter, QHash *elements) +{ + if (!element.contains(check)) return 0; + + int id = elements->value(element, 0); + if (!id) + { + ++counter; + id = counter; + elements->insert(element, id); + } + return id; +} + +//_____________________________________________________________________ +QStyle::StyleHint KStyleKDE4Compat::newStyleHint(const QString &element) +{ return (StyleHint)newStyleElement(element, "SH_", hintCounter, &styleElements); } + +//_____________________________________________________________________ +QStyle::ControlElement KStyleKDE4Compat::newControlElement(const QString &element) +{ return (ControlElement)newStyleElement(element, "CE_", controlCounter, &styleElements); } + +//_____________________________________________________________________ +QStyle::SubElement KStyleKDE4Compat::newSubElement(const QString &element) +{ return (SubElement)newStyleElement(element, "SE_", subElementCounter, &styleElements); } + +//_____________________________________________________________________ +int KStyleKDE4Compat::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + + if( hint == SH_KCustomStyleElement && widget ) + { return styleElements.value(widget->objectName(), 0); } + + switch (hint) { + case SH_ItemView_ActivateItemOnSingleClick: { + return Adwaita::Settings::SingleClick; + } + + case SH_DialogButtonBox_ButtonsHaveIcons: { + return Adwaita::Settings::ShowIconsOnPushButtons; + } + + case SH_ItemView_ArrowKeysNavigateIntoChildren: + return true; + + case SH_ToolButtonStyle: { + return Adwaita::Settings::ToolButtonStyle; + } + + default: + break; + }; + + return QCommonStyle::styleHint(hint, option, widget, returnData); +} diff --git a/style/kstylekde4compat.h b/style/kstylekde4compat.h new file mode 100644 index 0000000..ad713c0 --- /dev/null +++ b/style/kstylekde4compat.h @@ -0,0 +1,58 @@ +/************************************************************************* + * Copyright (C) 2015 by David Edmundson * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) 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 . * + *************************************************************************/ + +/** + * This class copies the features of KF5's KStyle for use in KDE4 only + * + * kdelibs4 also has a KStyle class but this isn't a 1-1 mapping and + * provides a lot of features we do not want + */ + +#ifndef KSTYLE_KDE4_COMPAT_H +#define KSTYLE_KDE4_COMPAT_H + +#include +#include + +class KStyleKDE4Compat : public QCommonStyle +{ + Q_OBJECT + + public: + + KStyleKDE4Compat(); + ~KStyleKDE4Compat(); + virtual int styleHint(StyleHint hint, const QStyleOption *opt, const QWidget *w, QStyleHintReturn *returnData) const; + + protected: + + StyleHint newStyleHint(const QString &element); + ControlElement newControlElement(const QString &element); + SubElement newSubElement(const QString &element); + + private: + + QHash styleElements; + int hintCounter; + int controlCounter; + int subElementCounter; + +}; + +#endif