diff --git a/LICENSES/LGPL-2.1-only.txt b/LICENSES/LGPL-2.1-only.txt new file mode 100644 index 0000000..130dffb --- /dev/null +++ b/LICENSES/LGPL-2.1-only.txt @@ -0,0 +1,467 @@ +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. + +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. + +< one line to give the library's name and an idea of what it does. > + +Copyright (C) < year > < name of author > + +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.1 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. + +< signature of Ty Coon > , 1 April 1990 + +Ty Coon, President of Vice + +That's all there is to it! diff --git a/LICENSES/LGPL-3.0-only.txt b/LICENSES/LGPL-3.0-only.txt new file mode 100644 index 0000000..bd405af --- /dev/null +++ b/LICENSES/LGPL-3.0-only.txt @@ -0,0 +1,163 @@ +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/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt b/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt new file mode 100644 index 0000000..232b3c5 --- /dev/null +++ b/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt @@ -0,0 +1,12 @@ +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 +that is accepted by the membership of KDE e.V. (or its successor +approved by the membership of KDE e.V.), which shall act as a +proxy as defined in Section 6 of version 3 of the license. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..204b93d --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,19 @@ +MIT License Copyright (c) + +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 (including the next +paragraph) 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. diff --git a/autotests/ArraySourceTest.cpp b/autotests/ArraySourceTest.cpp index 237172c..737557b 100644 --- a/autotests/ArraySourceTest.cpp +++ b/autotests/ArraySourceTest.cpp @@ -1,115 +1,101 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include #include "datasource/ArraySource.h" class ArraySourceTest : public QObject { Q_OBJECT private Q_SLOTS: void testCreate() { // Basic creation should create an empty source. auto source = new ArraySource{}; QCOMPARE(source->itemCount(), 0); QCOMPARE(source->item(0), QVariant{}); QCOMPARE(source->minimum(), QVariant{}); QCOMPARE(source->maximum(), QVariant{}); } void testWithArray_data() { QTest::addColumn("array"); QTest::addColumn("itemCount"); QTest::addColumn("firstItem"); QTest::addColumn("lastItem"); QTest::addColumn("minimum"); QTest::addColumn("maximum"); QTest::newRow("simple ints") << QVariantList{0, 1, 2, 3, 4} << 5 << QVariant{0} << QVariant{4} << QVariant{0} << QVariant{4}; QTest::newRow("random ints") << QVariantList{-3, 6, 4, 9, 4} << 5 << QVariant{-3} << QVariant{4} << QVariant{-3} << QVariant{9}; QTest::newRow("floats") << QVariantList{2.56, 4.45, 2.5, 5.3} << 4 << QVariant{2.56} << QVariant{5.3} << QVariant{2.5} << QVariant{5.3}; } void testWithArray() { auto source = new ArraySource{}; QFETCH(QVariantList, array); source->setArray(array); QFETCH(int, itemCount); QCOMPARE(source->itemCount(), itemCount); QFETCH(QVariant, firstItem); QCOMPARE(source->item(0), firstItem); QFETCH(QVariant, lastItem); QCOMPARE(source->item(itemCount - 1), lastItem); QCOMPARE(source->item(itemCount), QVariant{}); QFETCH(QVariant, minimum); QCOMPARE(source->minimum(), minimum); QFETCH(QVariant, maximum); QCOMPARE(source->maximum(), maximum); } void testWrap_data() { QTest::addColumn("array"); QTest::addColumn("itemCount"); QTest::addColumn("firstItem"); QTest::addColumn("lastItem"); QTest::newRow("simple ints") << QVariantList{0, 1, 2, 3, 4} << 5 << QVariant{0} << QVariant{4}; QTest::newRow("random ints") << QVariantList{-3, 6, 4, 9, 4} << 5 << QVariant{-3} << QVariant{4}; QTest::newRow("floats") << QVariantList{2.56, 4.45, 2.5, 5.3} << 4 << QVariant{2.56} << QVariant{5.3}; } void testWrap() { auto source = new ArraySource{}; QFETCH(QVariantList, array); source->setArray(array); source->setWrap(true); QFETCH(int, itemCount); QFETCH(QVariant, firstItem); QFETCH(QVariant, lastItem); QCOMPARE(source->item(0), firstItem); QCOMPARE(source->item(itemCount - 1), lastItem); QCOMPARE(source->item(itemCount), firstItem); QCOMPARE(source->item(itemCount * 2 - 1), lastItem); QCOMPARE(source->item(itemCount * 99), firstItem); } }; QTEST_GUILESS_MAIN(ArraySourceTest) #include "ArraySourceTest.moc" diff --git a/autotests/qmltest.cpp b/autotests/qmltest.cpp index 50f14d8..6d09aff 100644 --- a/autotests/qmltest.cpp +++ b/autotests/qmltest.cpp @@ -1,23 +1,9 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include QUICK_TEST_MAIN(Charts) diff --git a/autotests/tst_BarChart.qml b/autotests/tst_BarChart.qml index b66a993..a1818d8 100644 --- a/autotests/tst_BarChart.qml +++ b/autotests/tst_BarChart.qml @@ -1,66 +1,52 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.11 import QtTest 1.11 import org.kde.quickcharts 1.0 as Charts TestCase { id: testCase name: "Bar Chart Tests" width: 400 height: 400 visible: true when: windowShown Component { id: minimal Charts.BarChart { } } Component { id: simple Charts.BarChart { width: 200 height: 200 nameSource: Charts.ArraySource { array: ["Test 1", "Test 2", "Test 3"] } colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } valueSources: Charts.ArraySource { array: [1, 2, 3, 4, 5] } } } function test_create_data() { return [ { tag: "minimal", component: minimal }, { tag: "simple", component: simple } ] } function test_create(data) { var item = createTemporaryObject(data.component, testCase) verify(item) verify(waitForRendering(item)) } } diff --git a/autotests/tst_LineChart.qml b/autotests/tst_LineChart.qml index 68de153..a59526b 100644 --- a/autotests/tst_LineChart.qml +++ b/autotests/tst_LineChart.qml @@ -1,64 +1,50 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.11 import QtTest 1.11 import org.kde.quickcharts 1.0 as Charts TestCase { id: testCase name: "Line Chart Tests" width: 400 height: 400 visible: true when: windowShown Component { id: minimal Charts.LineChart { } } Component { id: simple Charts.LineChart { width: 200 height: 200 nameSource: Charts.ArraySource { array: ["Test 1", "Test 2", "Test 3"] } colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } valueSources: Charts.ArraySource { array: [1, 2, 3, 4, 5] } } } function test_create_data() { return [ { tag: "minimal", component: minimal }, { tag: "simple", component: simple } ] } function test_create(data) { var item = createTemporaryObject(data.component, testCase) verify(item) verify(waitForRendering(item)) } } diff --git a/autotests/tst_PieChart.qml b/autotests/tst_PieChart.qml index 1a651f5..bd09056 100644 --- a/autotests/tst_PieChart.qml +++ b/autotests/tst_PieChart.qml @@ -1,106 +1,92 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.11 import QtTest 1.11 import org.kde.quickcharts 1.0 as Charts TestCase { id: testCase name: "Pie Chart Tests" width: 400 height: 400 visible: true when: windowShown Component { id: minimal Charts.PieChart { } } Component { id: simple Charts.PieChart { width: 200 height: 200 nameSource: Charts.ArraySource { array: ["Test 1", "Test 2", "Test 3"] } colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } valueSources: Charts.ArraySource { array: [1, 2, 3, 4, 5] } } } Component { id: multiValue Charts.PieChart { width: 200 height: 200 nameSource: Charts.ArraySource { array: ["Test 1", "Test 2", "Test 3"] } colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } valueSources: [ Charts.ArraySource { array: [1, 2, 3, 4, 5] }, Charts.ArraySource { array: [1, 2, 3, 4, 5] }, Charts.ArraySource { array: [1, 2, 3, 4, 5] } ] } } Component { id: model Charts.PieChart { width: 200 height: 200 valueSources: [ Charts.ModelSource { model: ListModel { id: listModel ListElement { name: "Test 1"; color: "red"; value: 1 } ListElement { name: "Test 2"; color: "green"; value: 2 } ListElement { name: "Test 3"; color: "blue"; value: 3 } ListElement { name: "Test 4"; color: "cyan"; value: 4 } ListElement { name: "Test 5"; color: "magenta"; value: 5 } ListElement { name: "Test 6"; color: "yellow"; value: 6 } } } ] nameSource: Charts.ModelSource { model: listModel; roleName: "name" } colorSource: Charts.ModelSource { model: listModel; roleName: "color" } } } function test_create_data() { return [ { tag: "minimal", component: minimal }, { tag: "simple", component: simple }, { tag: "multiValue", component: multiValue }, { tag: "model", component: model } ] } function test_create(data) { var item = createTemporaryObject(data.component, testCase) verify(item) verify(waitForRendering(item)) } } diff --git a/controls/ChartsControlsPlugin.cpp b/controls/ChartsControlsPlugin.cpp index 3e2b068..4fb9f4f 100644 --- a/controls/ChartsControlsPlugin.cpp +++ b/controls/ChartsControlsPlugin.cpp @@ -1,59 +1,45 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ChartsControlsPlugin.h" #include #include #include #include #include ChartsControlsPlugin::ChartsControlsPlugin(QObject *parent) : QQmlExtensionPlugin(parent) { } void ChartsControlsPlugin::registerTypes(const char *uri) { Q_ASSERT(QString::fromLatin1(uri) == QLatin1String("org.kde.quickcharts.controls")); m_styleName = QQuickStyle::name(); qmlRegisterSingletonType(componentUrl(QStringLiteral("Theme.qml")), uri, 1, 0, "Theme"); qmlRegisterType(componentUrl(QStringLiteral("Legend.qml")), uri, 1, 0, "Legend"); qmlRegisterType(componentUrl(QStringLiteral("LegendDelegate.qml")), uri, 1, 0, "LegendDelegate"); qmlRegisterType(componentUrl(QStringLiteral("LineChartControl.qml")), uri, 1, 0, "LineChartControl"); qmlRegisterType(componentUrl(QStringLiteral("PieChartControl.qml")), uri, 1, 0, "PieChartControl"); } QUrl ChartsControlsPlugin::componentUrl(const QString &fileName) { auto url = baseUrl(); url.setPath(url.path() % QLatin1Char('/')); auto styled = url.resolved(QUrl{QStringLiteral("styles/") % m_styleName % QLatin1Char('/') % fileName}); if (QFile::exists(styled.toLocalFile())) { return styled; } return url.resolved(QUrl{fileName}); } diff --git a/controls/ChartsControlsPlugin.h b/controls/ChartsControlsPlugin.h index fe1c79d..7656d4a 100644 --- a/controls/ChartsControlsPlugin.h +++ b/controls/ChartsControlsPlugin.h @@ -1,42 +1,28 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef CHARTSCONTROLSPLUGIN_H #define CHARTSCONTROLSPLUGIN_H #include class ChartsControlsPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: explicit ChartsControlsPlugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; private: QUrl componentUrl(const QString &fileName); QUrl styledComponentUrl(const QString &fileName); QString m_styleName; }; #endif // CHARTSCONTROLSPLUGIN_H diff --git a/controls/Legend.qml b/controls/Legend.qml index ba5488f..044dba2 100644 --- a/controls/Legend.qml +++ b/controls/Legend.qml @@ -1,112 +1,98 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.2 import org.kde.quickcharts 1.0 as Charts import org.kde.quickcharts.controls 1.0 /** * A pre-made legend control that displays a legend for charts. */ Control { id: control /** * The chart to display the legend for. */ property Charts.Chart chart property alias model: legendRepeater.model property alias delegate: legendRepeater.delegate property alias flow: legend.flow property int sourceIndex: -1 property var formatValue: function(input, index) { return input } property bool valueVisible: false property real valueWidth: -1 property bool colorVisible: true property real colorWidth: Theme.smallSpacing property string nameRole: "name" property string colorRole: "color" property string valueRole: "value" property Component indicator: null default property alias extraItems: legend.children leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 implicitWidth: legend.implicitWidth implicitHeight: legend.implicitHeight contentItem: GridLayout { id: legend columns: flow == GridLayout.TopToBottom ? 1 : -1 rows: flow == GridLayout.TopToBottom ? -1 : 1 rowSpacing: control.spacing columnSpacing: rowSpacing Repeater { id: legendRepeater model: Charts.LegendModel { id: legendModel; chart: control.chart; sourceIndex: control.sourceIndex } delegate: LegendDelegate { Layout.preferredWidth: implicitWidth property var itemData: typeof modelData !== "undefined" ? modelData : model name: itemData[control.nameRole] !== undefined ? itemData[control.nameRole] : "" color: itemData[control.colorRole] !== undefined ? itemData[control.colorRole] : "white" value: { if (itemData[control.valueRole] !== undefined) { if (control.formatValue.length == 2) { return control.formatValue(itemData[control.valueRole], index) } else { return control.formatValue(itemData[control.valueRole]) } } return "" } colorVisible: control.colorVisible colorWidth: control.colorWidth valueVisible: control.valueVisible valueWidth: control.valueWidth indicator: control.indicator font: control.font layoutWidth: legend.flow == GridLayout.TopToBottom ? control.Layout.maximumWidth : control.Layout.maximumWidth / legendRepeater.count - control.spacing } } } } diff --git a/controls/LegendDelegate.qml b/controls/LegendDelegate.qml index 759022b..aa0e437 100644 --- a/controls/LegendDelegate.qml +++ b/controls/LegendDelegate.qml @@ -1,131 +1,117 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.2 import org.kde.quickcharts 1.0 as Charts import org.kde.quickcharts.controls 1.0 /** * A delegate that can be used as part of a Legend. */ RowLayout { id: delegate Layout.fillHeight: false Layout.preferredWidth: 0 property string name property color color property string value property color valueColor: name.color property real colorWidth: Theme.smallSpacing property real valueWidth: -1 property bool colorVisible: true property bool valueVisible: true property alias font: name.font property Component indicator: null property real layoutWidth: -1 spacing: Theme.smallSpacing opacity: parent.height >= y + height // This will hide the item if it is out of bounds Loader { Layout.preferredHeight: name.contentHeight Layout.preferredWidth: delegate.colorWidth visible: delegate.colorVisible property color delegateColor: delegate.color sourceComponent: delegate.indicator != null ? delegate.indicator : defaultIndicator MouseArea { id: mouse anchors.fill: parent hoverEnabled: true ToolTip.visible: mouse.containsMouse && (!name.visible || !value.visible) ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval ToolTip.text: "%1: %2".arg(delegate.name).arg(delegate.value) } } Label { id: name Layout.fillWidth: true Layout.fillHeight: true text: delegate.name visible: { if (delegate.layoutWidth < 0) { return true; } return delegate.layoutWidth - delegate.colorWidth - delegate.spacing * 2 >= contentWidth } verticalAlignment: Qt.AlignVCenter } Label { id: value Layout.fillHeight: true Layout.preferredWidth: delegate.valueWidth text: delegate.value; font: name.font color: delegate.valueColor verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignRight visible: { if (!delegate.valueVisible) { return false; } if (delegate.layoutWidth < 0) { return true; } var remainingWidth = delegate.layoutWidth - delegate.spacing * 2 if (delegate.colorVisible) { remainingWidth -= delegate.colorWidth - delegate.spacing } if (name.visible) { remainingWidth -= name.contentWidth - delegate.spacing } return remainingWidth >= delegate.valueWidth } } Component { id: defaultIndicator; Rectangle { color: delegateColor } } } diff --git a/controls/LineChartControl.qml b/controls/LineChartControl.qml index b7bb1e9..fbde2cb 100644 --- a/controls/LineChartControl.qml +++ b/controls/LineChartControl.qml @@ -1,150 +1,136 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import org.kde.quickcharts 1.0 as Charts import org.kde.quickcharts.controls 1.0 /** * A line chart with legend, grid and axis labels. */ Control { property alias valueSources: lineChart.valueSources property alias names: nameSource.array property alias color: colorSource.baseColor property alias lineWidth: lineChart.lineWidth property alias fillOpacity: lineChart.fillOpacity property alias stacked: lineChart.stacked property alias chart: lineChart property alias legend: legend property alias xLabels: xAxisLabels property alias yLabels: yAxisLabels property alias verticalLinesVisible: verticalLines.visible property alias horizontalLinesVisible: horizontalLines.visible property alias xRange: lineChart.xRange property alias yRange: lineChart.yRange property alias xAxisSource: xAxisLabels.source property alias yAxisSource: yAxisLabels.source background: Rectangle { color: Theme.backgroundColor } contentItem: Item { anchors.fill: parent; Charts.GridLines { id: horizontalLines anchors.fill: lineChart chart: lineChart major.frequency: 2 major.lineWidth: 2 major.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) minor.frequency: 1 minor.lineWidth: 1 minor.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) } Charts.GridLines { id: verticalLines anchors.fill: lineChart chart: lineChart direction: Charts.GridLines.Vertical; major.count: 1 major.lineWidth: 2 major.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) minor.count: 3 minor.lineWidth: 1 minor.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) } Charts.AxisLabels { id: yAxisLabels anchors { left: parent.left top: parent.top bottom: xAxisLabels.top } direction: Charts.AxisLabels.VerticalBottomTop delegate: Label { text: Charts.AxisLabels.label } source: Charts.ChartAxisSource { chart: lineChart; axis: Charts.ChartAxisSource.YAxis; itemCount: 5 } } Charts.AxisLabels { id: xAxisLabels anchors { left: yAxisLabels.visible ? yAxisLabels.right : parent.left right: parent.right bottom: legend.top } delegate: Label { text: Charts.AxisLabels.label } source: Charts.ChartAxisSource { chart: lineChart; axis: Charts.ChartAxisSource.XAxis; itemCount: 5 } } Legend { id: legend anchors { left: yAxisLabels.visible ? yAxisLabels.right : parent.left right: parent.right bottom: parent.bottom bottomMargin: Theme.smallSpacing } chart: lineChart } Charts.LineChart { id: lineChart anchors { top: parent.top left: yAxisLabels.visible ? yAxisLabels.right : parent.left right: parent.right bottom: xAxisLabels.visible ? xAxisLabels.top : legend.top } xRange.automatic: true yRange.automatic: true colorSource: Charts.ColorGradientSource { id: colorSource; baseColor: Theme.highlightColor; itemCount: lineChart.valueSources.length } nameSource: Charts.ArraySource { id: nameSource; array: ["1", "2", "3", "4", "5"] } } } } diff --git a/controls/PieChartControl.qml b/controls/PieChartControl.qml index 8855f8d..eb296d5 100644 --- a/controls/PieChartControl.qml +++ b/controls/PieChartControl.qml @@ -1,62 +1,48 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import org.kde.quickcharts 1.0 as Charts import org.kde.quickcharts.controls 1.0 /** * A pie chart with text in the middle. */ Control { property alias valueSources: pie.valueSources property alias names: nameSource.array property alias color: colorSource.baseColor property alias range: pie.range property alias chart: pie property alias text: centerText.text implicitWidth: Theme.gridUnit * 5 implicitHeight: Theme.gridUnit * 5 contentItem: Item { Charts.PieChart { id: pie anchors.fill: parent nameSource: Charts.ArraySource { id: nameSource; array: [ ] } colorSource: Charts.ColorGradientSource { id: colorSource; baseColor: Theme.highlightColor; itemCount: pie.valueSources.length } } Label { id: centerText anchors.centerIn: parent; horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter } } } diff --git a/controls/Theme.qml b/controls/Theme.qml index b8a27ef..b7b6650 100644 --- a/controls/Theme.qml +++ b/controls/Theme.qml @@ -1,33 +1,19 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 pragma Singleton; QtObject { property real gridUnit: 20 property real smallSpacing: 5 property real largeSpacing: 10 property color highlightColor: "blue" property color backgroundColor: "white" } diff --git a/controls/styles/org.kde.desktop/Theme.qml b/controls/styles/org.kde.desktop/Theme.qml index b96e494..e576fe2 100644 --- a/controls/styles/org.kde.desktop/Theme.qml +++ b/controls/styles/org.kde.desktop/Theme.qml @@ -1,37 +1,23 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import org.kde.kirigami 2.4 as Kirigami pragma Singleton; QtObject { property real gridUnit: Kirigami.Units.gridUnit property real smallSpacing: Kirigami.Units.smallSpacing property real largeSpacing: Kirigami.Units.largeSpacing property color highlightColor: Kirigami.Theme.highlightColor property color backgroundColor: Kirigami.Theme.backgroundColor Kirigami.Theme.colorSet: Kirigami.Theme.View } diff --git a/examples/charts/BarChart.qml b/examples/charts/BarChart.qml index c61097e..f1203af 100644 --- a/examples/charts/BarChart.qml +++ b/examples/charts/BarChart.qml @@ -1,223 +1,209 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.4 as Kirigami import org.kde.kquickcontrols 2.0 import org.kde.quickcharts 1.0 as Charts import org.kde.quickcharts.controls 1.0 as ChartsControls Kirigami.Page { title: "Bar Chart" ListModel { id: barModel; dynamicRoles: true; Component.onCompleted: { append({label: "Item 1", value1: 0, value2: 15, value3: 20}) append({label: "Item 2", value1: 10, value2: 25, value3: 25}) append({label: "Item 3", value1: 15, value2: 20, value3: 30}) append({label: "Item 4", value1: 10, value2: 10, value3: 35}) append({label: "Item 5", value1: 20, value2: 5, value3: 40}) } } ColumnLayout { anchors.fill: parent anchors.margins: Kirigami.Units.largeSpacing spacing: Kirigami.Units.largeSpacing Kirigami.AbstractCard { Layout.fillHeight: false Layout.preferredHeight: 400 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Charts.GridLines { anchors.fill: barChart chart: barChart major.visible: false minor.count: 4 minor.lineWidth: 1 minor.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) } Charts.GridLines { anchors.fill: barChart chart: barChart direction: Charts.GridLines.Vertical; major.count: 1 major.lineWidth: 2 major.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) minor.count: 3 minor.lineWidth: 1 minor.color: Qt.rgba(0.8, 0.8, 0.8, 1.0) } Charts.AxisLabels { id: yAxisLabels anchors { left: parent.left top: parent.top bottom: xAxisLabels.top } direction: Charts.AxisLabels.VerticalBottomTop delegate: Label { text: Charts.AxisLabels.label } source: Charts.ChartAxisSource { chart: barChart; axis: Charts.ChartAxisSource.YAxis; itemCount: 5 } } Charts.AxisLabels { id: xAxisLabels anchors { left: yAxisLabels.right right: parent.right bottom: legend.top } delegate: Label { text: Charts.AxisLabels.label } source: Charts.ModelSource { model: barModel; roleName: "label" } } ChartsControls.Legend { id: legend anchors { left: yAxisLabels.right right: parent.right bottom: parent.bottom bottomMargin: Kirigami.Units.smallSpacing } chart: barChart } Charts.BarChart { id: barChart anchors { top: parent.top left: yAxisLabels.right right: parent.right bottom: xAxisLabels.top } xRange { from: 0 to: 10 automatic: true } yRange { from: 0 to: 10 automatic: true } valueSources: [ Charts.ModelSource { roleName: "value1"; model: barModel }, Charts.ModelSource { roleName: "value2"; model: barModel }, Charts.ModelSource { roleName: "value3"; model: barModel } ] barWidth: 10 spacing: 2 colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } nameSource: Charts.ArraySource { array: ["Example 1", "Example 2", "Example 3"] } } } RangeEditor { label: "X Axis"; range: barChart.xRange } RangeEditor { label: "Y Axis"; range: barChart.yRange } RowLayout { Button { text: "Add Item"; onClicked: barModel.append({label: "New", value1: 0, value2: 0, value3: 0}) } Button { text: "Remove Item"; onClicked: barModel.remove(barModel.count - 1)} Label { text: "Bar Width" } SpinBox { from: -1; to: 1000; value: barChart.barWidth; onValueModified: barChart.barWidth = value; } Label { text: "Bar Spacing" } SpinBox { from: 0; to: 100; value: barChart.spacing; onValueModified: barChart.spacing = value; } CheckBox { text: "Stacked"; checked: barChart.stacked; onToggled: barChart.stacked = checked } } Frame { Layout.fillWidth: true Layout.fillHeight: true ScrollView { anchors.fill: parent ListView { model: barModel; delegate: Kirigami.BasicListItem { width: ListView.view.width height: Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing contentItem: RowLayout { Label { text: "Label" } TextField { Layout.preferredWidth: 75 text: model.label; onEditingFinished: barModel.setProperty(index, "label", text) } Label { text: "Value 1" } SpinBox { Layout.preferredWidth: 75 from: -10000; to: 10000; stepSize: 1; value: model.value1; onValueModified: barModel.setProperty(index, "value1", value) } Label { text: "Value 2" } SpinBox { Layout.preferredWidth: 75 from: -10000; to: 10000; stepSize: 1; value: model.value2; onValueModified: barModel.setProperty(index, "value2", value) } Label { text: "Value 3" } SpinBox { Layout.preferredWidth: 75 from: -10000; to: 10000; stepSize: 1; value: model.value3; onValueModified: barModel.setProperty(index, "value3", value) } } } } } } } } diff --git a/examples/charts/ContinuousLineChart.qml b/examples/charts/ContinuousLineChart.qml index ef238d3..67b2813 100644 --- a/examples/charts/ContinuousLineChart.qml +++ b/examples/charts/ContinuousLineChart.qml @@ -1,102 +1,88 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.4 as Kirigami import org.kde.kquickcontrols 2.0 import org.kde.quickcharts 1.0 as Charts Kirigami.Page { title: "Line Chart" ListModel { id: lineModel; dynamicRoles: true; } Timer { id: updateTimer running: true repeat: true interval: 16 property real lastValue: 0.0 onTriggered: { var value = Math.max(0.0, Math.min(1.0, lastValue + (-0.05 + Math.random() / 10))) lastValue = value; lineModel.insert(0, {"value": value}) var distance = chart.xRange.to - chart.xRange.from if(!chart.xRange.automatic && lineModel.count > distance) { var toRemove = lineModel.count - distance; lineModel.remove(lineModel.count - toRemove, toRemove) } } } ColumnLayout { anchors.fill: parent anchors.margins: Kirigami.Units.largeSpacing spacing: Kirigami.Units.largeSpacing Kirigami.AbstractCard { Layout.fillHeight: false Layout.preferredHeight: 400 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Charts.LineChart { id: chart anchors.fill: parent xRange { from: 0 to: 500 automatic: false } yRange { from: 0 to: 1 automatic: false } valueSources: Charts.ModelSource { roleName: "value"; model: lineModel } colorSource: Charts.SingleValueSource { value: "darkRed" } lineWidth: 2 fillOpacity: 0.2 } } RowLayout { RangeEditor { label: "X Axis"; range: chart.xRange } Item { Layout.fillWidth: true } Button { icon.name: "media-playback-start"; enabled: !updateTimer.running; onClicked: updateTimer.start() } Button { icon.name: "media-playback-stop"; enabled: updateTimer.running; onClicked: updateTimer.stop() } Item { Layout.fillWidth: true } RangeEditor { label: "Y Axis"; range: chart.yRange } } } } diff --git a/examples/charts/LineChart.qml b/examples/charts/LineChart.qml index 3a7d255..4527453 100644 --- a/examples/charts/LineChart.qml +++ b/examples/charts/LineChart.qml @@ -1,134 +1,120 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.4 as Kirigami import org.kde.kquickcontrols 2.0 import org.kde.quickcharts 1.0 as Charts import org.kde.quickcharts.controls 1.0 as ChartsControls Kirigami.Page { title: "Line Chart" ListModel { id: lineModel; dynamicRoles: true; Component.onCompleted: { append({label: "Item 1", value1: 10, value2: 15, value3: 20}) append({label: "Item 2", value1: 15, value2: 25, value3: 25}) append({label: "Item 3", value1: 15, value2: 20, value3: 30}) append({label: "Item 4", value1: 10, value2: 10, value3: 35}) append({label: "Item 5", value1: 20, value2: 5, value3: 40}) } } ColumnLayout { anchors.fill: parent anchors.margins: Kirigami.Units.largeSpacing spacing: Kirigami.Units.largeSpacing Kirigami.AbstractCard { Layout.fillHeight: false Layout.preferredHeight: 400 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter ChartsControls.LineChartControl { id: lineChart anchors.fill: parent valueSources: [ Charts.ModelSource { roleName: "value1"; model: lineModel }, Charts.ModelSource { roleName: "value2"; model: lineModel }, Charts.ModelSource { roleName: "value3"; model: lineModel } ] names: ["Example 1", "Example 2", "Example 3"] } } RangeEditor { label: "X Axis"; range: lineChart.xRange } RangeEditor { label: "Y Axis"; range: lineChart.yRange } RowLayout { Button { text: "Add Item"; onClicked: lineModel.append({label: "New", value1: 0, value2: 0, value3: 0}) } Button { text: "Remove Item"; onClicked: lineModel.remove(lineModel.count - 1)} Label { text: "Line Width" } SpinBox { from: 0; to: 1000; value: lineChart.lineWidth; onValueModified: lineChart.lineWidth = value; } Label { text: "Fill Opacity" } SpinBox { from: 0; to: 100; value: lineChart.fillOpacity * 100; onValueModified: lineChart.fillOpacity = value / 100; } CheckBox { text: "Stacked"; checked: lineChart.stacked; onToggled: lineChart.stacked = checked } } Frame { Layout.fillWidth: true Layout.fillHeight: true ScrollView { anchors.fill: parent ListView { model: lineModel; delegate: Kirigami.BasicListItem { width: ListView.view.width height: Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing contentItem: RowLayout { Label { text: "Label" } TextField { Layout.preferredWidth: 75 text: model.label; onEditingFinished: lineModel.setProperty(index, "label", text) } Label { text: "Value 1" } SpinBox { Layout.preferredWidth: 75 from: -10000; to: 10000; stepSize: 1; value: model.value1; onValueModified: lineModel.setProperty(index, "value1", value) } Label { text: "Value 2" } SpinBox { Layout.preferredWidth: 75 from: -10000; to: 10000; stepSize: 1; value: model.value2; onValueModified: lineModel.setProperty(index, "value2", value) } Label { text: "Value 3" } SpinBox { Layout.preferredWidth: 75 from: -10000; to: 10000; stepSize: 1; value: model.value3; onValueModified: lineModel.setProperty(index, "value3", value) } } } } } } } } diff --git a/examples/charts/PieChart.qml b/examples/charts/PieChart.qml index 13f3334..1fdafc2 100644 --- a/examples/charts/PieChart.qml +++ b/examples/charts/PieChart.qml @@ -1,123 +1,109 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.4 as Kirigami import org.kde.kquickcontrols 2.0 import org.kde.quickcharts 1.0 as Charts Kirigami.Page { title: "Pie Chart" ListModel { id: pieModel; dynamicRoles: true; Component.onCompleted: { append({ data: 50, data2: 30, color: "red" }) append({ data: 50, data2: 60, color: "green" }) append({ data: 50, data2: 60, color: "blue" }) } } ColumnLayout { anchors.fill: parent anchors.margins: Kirigami.Units.largeSpacing spacing: Kirigami.Units.largeSpacing Kirigami.AbstractCard { Layout.fillWidth: false Layout.fillHeight: false Layout.preferredWidth: 600 Layout.preferredHeight: 400 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Charts.PieChart { id: chart anchors.fill: parent anchors.margins: Kirigami.Units.smallSpacing; range.to: 150 valueSources: Charts.ModelSource { roleName: "data"; model: pieModel } colorSource: Charts.ModelSource { roleName: "color"; model: pieModel } thickness: 20; filled: false; backgroundColor: "gray" } } RangeEditor { label: "Range"; range: chart.range } RowLayout { Button { text: "Add Item"; onClicked: pieModel.append({data: 50, color: Qt.rgba(1.0, 1.0, 1.0)}) } Button { text: "Remove Item"; onClicked: pieModel.remove(pieModel.count - 1)} Label { text: "Thickness" } SpinBox { from: 0; to: chart.width / 2; value: chart.thickness; onValueModified: chart.thickness = value; } CheckBox { text: "Filled"; checked: chart.filled; onCheckedChanged: chart.filled = checked } } RowLayout { CheckBox { text: "Smooth Ends"; checked: chart.smoothEnds; onCheckedChanged: chart.smoothEnds = checked } Label { text: "From Angle" } SpinBox { from: -360; to: 360; value: chart.fromAngle; onValueModified: chart.fromAngle = value; } Label { text: "To Angle" } SpinBox { from: -360; to: 360; value: chart.toAngle; onValueModified: chart.toAngle = value; } } Frame { Layout.fillWidth: true Layout.fillHeight: true ScrollView { anchors.fill: parent ListView { model: pieModel; delegate: Kirigami.BasicListItem { width: ListView.view.width height: Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing contentItem: RowLayout { Label { text: "Value" } SpinBox { Layout.preferredWidth: parent.width * 0.15 from: 0; to: 10000; stepSize: 1; value: model.data; onValueModified: pieModel.setProperty(index, "data", value) } Label { text: "Color" } ColorButton { color: model.color; showAlphaChannel: true; onColorChanged: pieModel.setProperty(index, "color", color) } } } } } } } } diff --git a/examples/charts/RangeEditor.qml b/examples/charts/RangeEditor.qml index 01a7283..7f0566d 100644 --- a/examples/charts/RangeEditor.qml +++ b/examples/charts/RangeEditor.qml @@ -1,86 +1,72 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.4 as Kirigami import org.kde.quickcharts 1.0 as Charts RowLayout { property alias label: labelItem.text; property Charts.Range range; spacing: Kirigami.Units.smallSpacing Label { id: labelItem; } CheckBox { id: automaticCheckbox; checked: range.automatic; text: "Automatic"; onToggled: range.automatic = checked } Label { text: "From" } SpinBox { from: -10000; to: 10000; value: range.from; editable: true; enabled: !automaticCheckbox.checked; onValueModified: range.from = value; } Label { text: "To" } SpinBox { from: -10000; to: 10000; value: range.to; editable: true; enabled: !automaticCheckbox.checked; onValueModified: range.to = value; } Label { text: "Minimum" } SpinBox { from: 0 to: 10000 value: range.minimum editable: true onValueModified: range.minimum = value } Label { text: "Increment" } SpinBox { from: 0 to: 10000 value: range.increment editable: true onValueModified: range.increment = value } } diff --git a/examples/charts/main.cpp b/examples/charts/main.cpp index 8eaac1e..fdb9fc5 100644 --- a/examples/charts/main.cpp +++ b/examples/charts/main.cpp @@ -1,71 +1,57 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include #include #include #include #include #include int main(int argc, char **argv) { QApplication app(argc, argv); QCommandLineParser parser; parser.addOption({QStringLiteral("page"), QStringLiteral("The page to show."), QStringLiteral("page")}); parser.addOption({QStringLiteral("api"), QStringLiteral("The graphics API to use. Can be one of 'default', 'core45', 'compat45', 'compat21' or 'es'."), QStringLiteral("api"), QStringLiteral("default")}); parser.addHelpOption(); parser.process(app); QSurfaceFormat format; auto api = parser.value(QStringLiteral("api")); if (api == QStringLiteral("core45")) { format.setProfile(QSurfaceFormat::CoreProfile); format.setVersion(4, 5); } else if (api == QStringLiteral("compat45")) { format.setProfile(QSurfaceFormat::CompatibilityProfile); format.setVersion(4, 5); } else if (api == QStringLiteral("es")) { format.setRenderableType(QSurfaceFormat::OpenGLES); } else if (api == QStringLiteral("default") || api == QStringLiteral("compat20")) { format.setVersion(2, 1); } else { qWarning() << "Unknown API option" << api << "\n"; parser.showHelp(1); } QSurfaceFormat::setDefaultFormat(format); QQmlApplicationEngine engine; if (parser.isSet(QStringLiteral("page"))) { engine.rootContext()->setContextProperty(QStringLiteral("__commandLinePage"), parser.value(QStringLiteral("page"))); } else { engine.rootContext()->setContextProperty(QStringLiteral("__commandLinePage"), nullptr); } engine.load(QStringLiteral("qrc:/main.qml")); return app.exec(); } diff --git a/examples/charts/main.qml b/examples/charts/main.qml index 8bfeaff..adcda27 100644 --- a/examples/charts/main.qml +++ b/examples/charts/main.qml @@ -1,62 +1,48 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ import QtQuick 2.9 import QtQuick.Controls 2.2 import org.kde.kirigami 2.2 as Kirigami Kirigami.ApplicationWindow { id: window title: "Charts Example" pageStack.initialPage: Kirigami.ScrollablePage { title: "Charts" ListView { model: ListModel { id: pagesModel ListElement { label: "Pie Chart"; file: "qrc:/PieChart.qml"; identifier: "pie" } ListElement { label: "Line Chart"; file: "qrc:/LineChart.qml"; identifier: "line" } ListElement { label: "Continuous Line Chart"; file: "qrc:/ContinuousLineChart.qml"; identifier: "continuous" } ListElement { label: "Bar Chart"; file: "qrc:/BarChart.qml"; identifier: "bar" } } delegate: Kirigami.BasicListItem { label: model.label onClicked: applicationWindow().pageStack.push(model.file); } } } Component.onCompleted: { if (__commandLinePage !== null) { for (var i = 0; i < pagesModel.count; ++i) { var item = pagesModel.get(i); if (item.identifier == __commandLinePage || item.label == __commandLinePage) { window.pageStack.push(item.file); return; } } } } } diff --git a/examples/snippets/barchart.qml b/examples/snippets/barchart.qml index cb94e3f..e56429e 100644 --- a/examples/snippets/barchart.qml +++ b/examples/snippets/barchart.qml @@ -1,55 +1,41 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ //! [example] import QtQuick 2.11 import QtQuick.Controls 2.11 import org.kde.quickcharts 1.0 as Charts Charts.BarChart { id: barChart width: 400 height: 300 valueSources: [ Charts.ModelSource { roleName: "value1"; model: listModel }, Charts.ModelSource { roleName: "value2"; model: listModel }, Charts.ModelSource { roleName: "value3"; model: listModel } ] colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } nameSource: Charts.ArraySource { array: ["Example 1", "Example 2", "Example 3"] } barWidth: 20 ListModel { id: listModel ListElement { value1: 19; value2: 2; value3: 6 } ListElement { value1: 14; value2: 20; value3: 17 } ListElement { value1: 4; value2: 10; value3: 11 } ListElement { value1: 5; value2: 11; value3: 9 } ListElement { value1: 20; value2: 7; value3: 13 } } } //! [example] diff --git a/examples/snippets/linechart.qml b/examples/snippets/linechart.qml index 37ac58e..fdccbd3 100644 --- a/examples/snippets/linechart.qml +++ b/examples/snippets/linechart.qml @@ -1,50 +1,36 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ //! [example] import QtQuick 2.11 import QtQuick.Controls 2.11 import org.kde.quickcharts 1.0 as Charts Charts.LineChart { width: 400 height: 300 valueSources: [ Charts.ModelSource { roleName: "value1"; model: listModel }, Charts.ModelSource { roleName: "value2"; model: listModel }, Charts.ModelSource { roleName: "value3"; model: listModel } ] colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } nameSource: Charts.ArraySource { array: ["Example 1", "Example 2", "Example 3"]} ListModel { id: listModel ListElement { value1: 19; value2: 2; value3: 6 } ListElement { value1: 14; value2: 20; value3: 17 } ListElement { value1: 4; value2: 10; value3: 11 } ListElement { value1: 5; value2: 11; value3: 9 } ListElement { value1: 20; value2: 7; value3: 13 } } } //! [example] diff --git a/examples/snippets/minimal.qml b/examples/snippets/minimal.qml index f1a5592..1ef26dd 100644 --- a/examples/snippets/minimal.qml +++ b/examples/snippets/minimal.qml @@ -1,52 +1,38 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ //! [example] import QtQuick 2.11 import QtQuick.Controls 2.11 import org.kde.quickcharts 1.0 as Charts ApplicationWindow { width: 500 height: 500 Rectangle { anchors.centerIn: parent width: 300 height: 200 border.width: 2 Charts.LineChart { anchors.fill: parent colorSource: Charts.ArraySource { array: ["red", "green", "blue"] } nameSource: Charts.ArraySource { array: ["First", "Second", "Third"] } valueSources: [ Charts.ArraySource { array: [1, 2, 2, 1] }, Charts.ArraySource { array: [2, 5, 2, 5] }, Charts.ArraySource { array: [5, 4, 3, 4] } ] } } } //! [example] diff --git a/examples/snippets/piechart.qml b/examples/snippets/piechart.qml index c6577eb..a62e743 100644 --- a/examples/snippets/piechart.qml +++ b/examples/snippets/piechart.qml @@ -1,48 +1,34 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ //! [example] import QtQuick 2.11 import QtQuick.Controls 2.11 import org.kde.quickcharts 1.0 as Charts Charts.PieChart { width: 400 height: 300 valueSources: Charts.ModelSource { roleName: "data"; model: ListModel { id: listModel ListElement { data: 12 } ListElement { data: 19 } ListElement { data: 10 } ListElement { data: 13 } ListElement { data: 13 } } } colorSource: Charts.ArraySource { array: ["red", "green", "blue", "yellow", "cyan"] } nameSource: Charts.ArraySource { array: ["Red", "Green", "Blue", "Yellow", "Cyan"] } thickness: 50 } //! [example] diff --git a/src/BarChart.cpp b/src/BarChart.cpp index 33244b1..6638b52 100644 --- a/src/BarChart.cpp +++ b/src/BarChart.cpp @@ -1,197 +1,183 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "BarChart.h" #include #include #include "datasource/ChartDataSource.h" #include "scenegraph/BarChartNode.h" #include "RangeGroup.h" BarChart::BarChart(QQuickItem *parent) : XYChart(parent) { connect(this, &BarChart::computedRangeChanged, this, &BarChart::onDataChanged); } qreal BarChart::spacing() const { return m_spacing; } void BarChart::setSpacing(qreal newSpacing) { if (newSpacing == m_spacing) { return; } m_spacing = newSpacing; update(); Q_EMIT spacingChanged(); } qreal BarChart::barWidth() const { return m_barWidth; } void BarChart::setBarWidth(qreal newBarWidth) { if (newBarWidth == m_barWidth) { return; } m_barWidth = newBarWidth; update(); Q_EMIT barWidthChanged(); } QSGNode *BarChart::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *) { if (!node) { node = new BarChartNode{}; } QVector> values; // TODO: Find some way to clean this up and simplify it, since this is pretty ugly. auto w = m_barWidth; if (w < 0.0) { if (stacked()) { auto totalItemCount = m_values.size(); w = width() / totalItemCount - m_spacing; auto x = float(m_spacing / 2); auto itemSpacing = w + m_spacing; for (const auto &items : qAsConst(m_values)) { for (int i = items.count() - 1; i >= 0; --i) { auto entry = items.at(i); values << QPair{QVector2D{x, float(entry.first)}, entry.second}; } x += itemSpacing; } } else { auto totalItemCount = m_values.size() * valueSources().count(); w = width() / totalItemCount - m_spacing; auto x = float(m_spacing / 2); auto itemSpacing = w + m_spacing; for (const auto &items : qAsConst(m_values)) { for (const auto &entry : items) { values << QPair{QVector2D{x, float(entry.first)}, entry.second}; x += itemSpacing; } } } } else { auto itemSpacing = width() / m_values.size(); if (stacked()) { auto x = float(itemSpacing / 2 - m_barWidth / 2); for (const auto &items : qAsConst(m_values)) { for (int i = items.count() - 1; i >= 0; --i) { auto entry = items.at(i); values << QPair{QVector2D{x, float(entry.first)}, entry.second}; } x += itemSpacing; } } else { auto totalWidth = m_barWidth * valueSources().count() + m_spacing * (valueSources().count() - 1); auto x = float(itemSpacing / 2 - totalWidth / 2); for (const auto &items : qAsConst(m_values)) { for (int i = 0; i < items.count(); ++i) { auto entry = items.at(i); values << QPair{QVector2D{float(x + i * (m_barWidth + m_spacing)), float(entry.first)}, entry.second}; } x += itemSpacing; } } } auto barNode = static_cast(node); barNode->setRect(boundingRect()); barNode->setValues(values); barNode->setBarWidth(w); barNode->update(); return barNode; } void BarChart::onDataChanged() { m_values.clear(); updateComputedRange(); const auto range = computedRange(); const auto sources = valueSources(); auto colors = colorSource(); auto indexMode = indexingMode(); auto colorIndex = 0; m_values.fill(QVector>{}, range.distanceX); auto generator = [&, i = range.startX]() mutable -> QVector> { QVector> values; for (int j = 0; j < sources.count(); ++j) { auto value = (sources.at(j)->item(i).toReal() - range.startY) / range.distanceY; values << QPair(value, colors->item(colorIndex).value()); if (indexMode != Chart::IndexSourceValues) { colorIndex++; } } if (stacked()) { auto previous = 0.0; for (auto &value : values) { value.first += previous; previous = value.first; } } if (indexMode == Chart::IndexSourceValues) { colorIndex++; } else if (indexMode == Chart::IndexEachSource) { colorIndex = 0; } i++; return values; }; if (direction() == Direction::ZeroAtStart) { std::generate_n(m_values.begin(), range.distanceX, generator); } else { std::generate_n(m_values.rbegin(), range.distanceX, generator); } update(); } diff --git a/src/BarChart.h b/src/BarChart.h index e897862..0065fb4 100644 --- a/src/BarChart.h +++ b/src/BarChart.h @@ -1,89 +1,75 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef BARCHART_H #define BARCHART_H #include "XYChart.h" /** * An item to render a bar chart. * * This chart renders * * ## Usage example * * \snippet snippets/barchart.qml example * * \image html barchart.png "The resulting bar chart." */ class BarChart : public XYChart { Q_OBJECT /** * The spacing between bars for each value source. * * Note that spacing between each X axis value is determined automatically * based on barWidth, spacing and total chart width. The default is 0. */ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) /** * The width of individual bars in the chart. * * If set to WidthMode::AutoWidth (also the default), the width will be * calculated automatically based on total chart width and item count. */ Q_PROPERTY(qreal barWidth READ barWidth WRITE setBarWidth NOTIFY barWidthChanged) public: /** * Helper enum to provide an easy way to set barWidth to auto. */ enum WidthMode { AutoWidth = -2 }; Q_ENUM(WidthMode) explicit BarChart(QQuickItem *parent = nullptr); qreal spacing() const; void setSpacing(qreal newSpacing); Q_SIGNAL void spacingChanged(); qreal barWidth() const; void setBarWidth(qreal newBarWidth); Q_SIGNAL void barWidthChanged(); protected: /** * Reimplemented from QQuickItem. */ QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *) override; /** * Reimplemented from Chart. */ void onDataChanged() override; private: qreal m_spacing = 0.0; qreal m_barWidth = AutoWidth; QVector>> m_values; }; #endif // BARCHART_H diff --git a/src/Chart.cpp b/src/Chart.cpp index aadbd12..1ec4d4e 100644 --- a/src/Chart.cpp +++ b/src/Chart.cpp @@ -1,150 +1,136 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "Chart.h" #include "datasource/ChartDataSource.h" Chart::Chart(QQuickItem *parent) : QQuickItem(parent) { setFlag(ItemHasContents, true); } ChartDataSource *Chart::nameSource() const { return m_nameSource; } void Chart::setNameSource(ChartDataSource *nameSource) { if (m_nameSource == nameSource) { return; } m_nameSource = nameSource; Q_EMIT nameSourceChanged(); } ChartDataSource *Chart::colorSource() const { return m_colorSource; } void Chart::setColorSource(ChartDataSource *colorSource) { if (m_colorSource == colorSource) { return; } m_colorSource = colorSource; Q_EMIT colorSourceChanged(); } Chart::DataSourcesProperty Chart::valueSourcesProperty() { return DataSourcesProperty{this, this, &Chart::appendSource, &Chart::sourceCount, &Chart::source, &Chart::clearSources}; } QVector Chart::valueSources() const { return m_valueSources; } void Chart::insertValueSource(int index, ChartDataSource *source) { if (index < 0) { return; } m_valueSources.insert(index, source); connect(source, &QObject::destroyed, this, qOverload(&Chart::removeValueSource)); connect(source, &ChartDataSource::dataChanged, this, &Chart::onDataChanged); onDataChanged(); Q_EMIT valueSourcesChanged(); } void Chart::removeValueSource(int index) { if (index < 0 || index >= m_valueSources.count()) { return; } m_valueSources.at(index)->disconnect(this); m_valueSources.remove(index); onDataChanged(); Q_EMIT valueSourcesChanged(); } void Chart::removeValueSource(QObject *source) { removeValueSource(m_valueSources.indexOf(qobject_cast(source))); } Chart::IndexingMode Chart::indexingMode() const { return m_indexingMode; } void Chart::setIndexingMode(IndexingMode newIndexingMode) { if (newIndexingMode == m_indexingMode) { return; } m_indexingMode = newIndexingMode; onDataChanged(); Q_EMIT indexingModeChanged(); } void Chart::componentComplete() { QQuickItem::componentComplete(); onDataChanged(); } void Chart::appendSource(Chart::DataSourcesProperty *list, ChartDataSource *source) { auto chart = reinterpret_cast(list->data); chart->m_valueSources.append(source); QObject::connect(source, &ChartDataSource::dataChanged, chart, &Chart::onDataChanged); chart->onDataChanged(); } int Chart::sourceCount(Chart::DataSourcesProperty *list) { return reinterpret_cast(list->data)->m_valueSources.count(); } ChartDataSource *Chart::source(Chart::DataSourcesProperty *list, int index) { return reinterpret_cast(list->data)->m_valueSources.at(index); } void Chart::clearSources(Chart::DataSourcesProperty *list) { auto chart = reinterpret_cast(list->data); std::for_each(chart->m_valueSources.cbegin(), chart->m_valueSources.cend(), [chart](ChartDataSource *source) { source->disconnect(chart); }); chart->m_valueSources.clear(); chart->onDataChanged(); } diff --git a/src/Chart.h b/src/Chart.h index 410cacd..eaf3f75 100644 --- a/src/Chart.h +++ b/src/Chart.h @@ -1,111 +1,97 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef CHART_H #define CHART_H #include class ChartDataSource; /** * Abstract base class for all charts. */ class Chart : public QQuickItem { Q_OBJECT /** * The data source to use for names of chart items. */ Q_PROPERTY(ChartDataSource *nameSource READ nameSource WRITE setNameSource NOTIFY nameSourceChanged) /** * The data source to use for colors of chart items. */ Q_PROPERTY(ChartDataSource *colorSource READ colorSource WRITE setColorSource NOTIFY colorSourceChanged) /** * The data sources providing the data this chart needs to render. */ Q_PROPERTY(QQmlListProperty valueSources READ valueSourcesProperty NOTIFY valueSourcesChanged) /** * The indexing mode used for indexing colors and names. */ Q_PROPERTY(IndexingMode indexingMode READ indexingMode WRITE setIndexingMode NOTIFY indexingModeChanged) public: using DataSourcesProperty = QQmlListProperty; /** * How to index color and name sources relative to the different value sources. */ enum IndexingMode { IndexSourceValues = 1, ///< Index each value, restart indexing for each value source. IndexEachSource, ///< Index each value source, never index individual values. IndexAllValues ///< Index each value, continuing with the index for each value source. }; Q_ENUM(IndexingMode) explicit Chart(QQuickItem *parent = nullptr); ~Chart() override = default; ChartDataSource *nameSource() const; void setNameSource(ChartDataSource *nameSource); Q_SIGNAL void nameSourceChanged(); ChartDataSource *colorSource() const; void setColorSource(ChartDataSource *colorSource); Q_SIGNAL void colorSourceChanged(); DataSourcesProperty valueSourcesProperty(); QVector valueSources() const; Q_SIGNAL void valueSourcesChanged(); Q_INVOKABLE void insertValueSource(int index, ChartDataSource *source); Q_INVOKABLE void removeValueSource(int index); Q_INVOKABLE void removeValueSource(QObject *source); IndexingMode indexingMode() const; void setIndexingMode(IndexingMode newIndexingMode); Q_SIGNAL void indexingModeChanged(); protected: /** * Called when the data of a value source changes. * * This method should be reimplemented by subclasses. It is called whenever * the data of one of the value sources changes. Subclasses should use this * to make sure that they update whatever internal state they use for * rendering, then call update() to schedule rendering the item. */ virtual void onDataChanged() = 0; void componentComplete() override; private: static void appendSource(DataSourcesProperty *list, ChartDataSource *source); static int sourceCount(DataSourcesProperty *list); static ChartDataSource *source(DataSourcesProperty *list, int index); static void clearSources(DataSourcesProperty *list); ChartDataSource *m_nameSource = nullptr; ChartDataSource *m_colorSource = nullptr; QVector m_valueSources; IndexingMode m_indexingMode = IndexEachSource; }; #endif // CHART_H diff --git a/src/ChartsPlugin.cpp b/src/ChartsPlugin.cpp index 7b989e7..f037ed0 100644 --- a/src/ChartsPlugin.cpp +++ b/src/ChartsPlugin.cpp @@ -1,82 +1,68 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ChartsPlugin.h" #include "BarChart.h" #include "Chart.h" #include "LineChart.h" #include "PieChart.h" #include "RangeGroup.h" #include "XYChart.h" #include "decorations/AxisLabels.h" #include "decorations/GridLines.h" #include "decorations/LegendModel.h" #include "datasource/ArraySource.h" #include "datasource/ChartAxisSource.h" #include "datasource/ColorGradientSource.h" #include "datasource/ModelHistorySource.h" #include "datasource/ModelSource.h" #include "datasource/SingleValueSource.h" #include "datasource/ValueHistorySource.h" QuickChartsPlugin::QuickChartsPlugin(QObject *parent) : QQmlExtensionPlugin(parent) { } void QuickChartsPlugin::registerTypes(const char *uri) { Q_ASSERT(QString::fromLatin1(uri) == QLatin1String("org.kde.quickcharts")); Q_INIT_RESOURCE(shaders); #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) qmlRegisterAnonymousType(uri, 1); #else qmlRegisterType(); #endif qmlRegisterType(uri, 1, 0, "PieChart"); qmlRegisterType(uri, 1, 0, "LineChart"); qmlRegisterType(uri, 1, 0, "BarChart"); qmlRegisterUncreatableType(uri, 1, 0, "XYChart", QStringLiteral("Just a base class")); qmlRegisterUncreatableType(uri, 1, 0, "Chart", QStringLiteral("Just a base class")); qmlRegisterUncreatableType(uri, 1, 0, "ChartDataSource", QStringLiteral("Just a base class")); qmlRegisterType(uri, 1, 0, "ModelSource"); qmlRegisterType(uri, 1, 0, "SingleValueSource"); qmlRegisterType(uri, 1, 0, "ArraySource"); qmlRegisterType(uri, 1, 0, "ModelHistorySource"); qmlRegisterType(uri, 1, 0, "ChartAxisSource"); qmlRegisterType(uri, 1, 0, "ValueHistorySource"); qmlRegisterType(uri, 1, 0, "ColorGradientSource"); qmlRegisterUncreatableType(uri, 1, 0, "Range", QStringLiteral("Used as a grouped property")); qmlRegisterType(uri, 1, 0, "GridLines"); qmlRegisterUncreatableType(uri, 1, 0, "LinePropertiesGroup", QStringLiteral("Used as a grouped property")); qmlRegisterType(uri, 1, 0, "AxisLabels"); qmlRegisterUncreatableType(uri, 1, 0, "AxisLabelsAttached", QStringLiteral("Attached property")); qmlRegisterType(uri, 1, 0, "LegendModel"); } diff --git a/src/ChartsPlugin.h b/src/ChartsPlugin.h index b57365f..8480de8 100644 --- a/src/ChartsPlugin.h +++ b/src/ChartsPlugin.h @@ -1,37 +1,23 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef CHARTSPLUGIN_H #define CHARTSPLUGIN_H #include class QuickChartsPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: explicit QuickChartsPlugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; }; #endif // CHARTSPLUGIN_H diff --git a/src/LineChart.cpp b/src/LineChart.cpp index 12d5aed..8816bc7 100644 --- a/src/LineChart.cpp +++ b/src/LineChart.cpp @@ -1,250 +1,236 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "LineChart.h" #include #include #include #include "RangeGroup.h" #include "datasource/ChartDataSource.h" #include "scenegraph/LineChartNode.h" #include "scenegraph/LineGridNode.h" QVector interpolate(const QVector &points, qreal start, qreal end, qreal height); LineChart::LineChart(QQuickItem *parent) : XYChart(parent) { } bool LineChart::smooth() const { return m_smooth; } qreal LineChart::lineWidth() const { return m_lineWidth; } qreal LineChart::fillOpacity() const { return m_fillOpacity; } void LineChart::setSmooth(bool smooth) { if (smooth == m_smooth) { return; } m_smooth = smooth; update(); Q_EMIT smoothChanged(); } void LineChart::setLineWidth(qreal width) { if (qFuzzyCompare(m_lineWidth, width)) { return; } m_lineWidth = width; update(); Q_EMIT lineWidthChanged(); } void LineChart::setFillOpacity(qreal opacity) { if (qFuzzyCompare(m_fillOpacity, opacity)) { return; } m_fillOpacity = opacity; update(); Q_EMIT fillOpacityChanged(); } QSGNode *LineChart::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) { Q_UNUSED(data); if (!node) { node = new QSGNode(); } if (m_rangeInvalid) { updateComputedRange(); m_rangeInvalid = false; } if (stacked()) { m_previousValues.clear(); } const auto sources = valueSources(); for (int i = 0; i < sources.size(); ++i) { int childIndex = sources.size() - 1 - i; while (childIndex >= node->childCount()) { node->appendChildNode(new LineChartNode{}); } auto lineNode = static_cast(node->childAtIndex(childIndex)); auto color = colorSource() ? colorSource()->item(i).value() : Qt::black; updateLineNode(lineNode, color, sources.at(i)); } while (node->childCount() > sources.size()) { node->removeChildNode(node->childAtIndex(node->childCount() - 1)); } return node; } void LineChart::onDataChanged() { m_rangeInvalid = true; update(); } void LineChart::updateLineNode(LineChartNode *node, const QColor &lineColor, ChartDataSource *valueSource) { auto fillColor = lineColor; fillColor.setRedF(fillColor.redF() * m_fillOpacity); fillColor.setGreenF(fillColor.greenF() * m_fillOpacity); fillColor.setBlueF(fillColor.blueF() * m_fillOpacity); fillColor.setAlphaF(m_fillOpacity); node->setRect(boundingRect()); node->setLineColor(lineColor); node->setFillColor(fillColor); node->setLineWidth(m_lineWidth); auto range = computedRange(); float stepSize = width() / (range.distanceX - 1); QVector values(range.distanceX); auto generator = [&, i = range.startX]() mutable -> QVector2D { float value = 0; if (range.distanceY != 0) { value = (valueSource->item(i).toFloat() - range.startY) / range.distanceY; } auto result = QVector2D{direction() == Direction::ZeroAtStart ? i * stepSize : float(boundingRect().right()) - i * stepSize, value}; i++; return result; }; if (direction() == Direction::ZeroAtStart) { std::generate_n(values.begin(), range.distanceX, generator); } else { std::generate_n(values.rbegin(), range.distanceX, generator); } if (stacked() && !m_previousValues.isEmpty()) { if (values.size() != m_previousValues.size()) { qWarning() << "Value source" << valueSource->objectName() << "has a different number of elements from the previuous source. Ignoring stacking for this source."; } else { std::for_each( values.begin(), values.end(), [this, i = 0](QVector2D &point) mutable { point.setY(point.y() + m_previousValues.at(i++).y()); }); } } m_previousValues = values; if (m_smooth) { values = interpolate(values, 0.0, width(), height()); } node->setValues(values); } QVector interpolate(const QVector &points, qreal start, qreal end, qreal height) { QPainterPath path; if (points.size() < 4) return points; const auto sixth = 1.f / 6.f; const qreal xDelta = (end - start) / (points.count() - 3); qreal x = start - xDelta; path.moveTo(start, points[0].y() * height); for (int i = 1; i < points.count() - 2; i++) { // This code was: // // QMatrix4x4 matrix( 0, 1, 0, 0, // -1/6, 1, 1/6, 0, // 0, 1/6, 1, -1/6, // 0, 0, 1, 0); // QMatrix4x4 p(x + xDelta * 0, points[i - 1].y() * height, 0, 0, // x + xDelta * 1, points[i + 0].y() * height, 0, 0, // x + xDelta * 2, points[i + 1].y() * height, 0, 0, // x + xDelta * 3, points[i + 2].y() * height, 0, 0) // QMatrix4x4 res = matrix * p; // path.cubicTo(res(1,0), res(1, 1), res(2, 0), res(2, 1), res(3, 0), res(3, 1)) // // The below calculations calculate the used elements from the matrix directly, avoiding // most of an expensive matrix multiplication. auto p0 = points[i - 1].y() * height; auto p1 = points[i].y() * height; auto p2 = points[i + 1].y() * height; auto p3 = points[i + 2].y() * height; //res(1, 0) = (-1/6, 1, 1/6, 0) dot (x, x + xDelta, x + xDelta * 2, x + xDelta * 3) auto res10 = (3 * x + 4 * xDelta) / 3.f; //res(1, 1) = (-1/6, 1, 1/6, 0) dot (p[i-1].y, p[i].y, p[i+1].y, p[i+2].y) auto res11 = -sixth * p0 + p1 + sixth * p2; //res(2, 0) = (0, 1/6, 1, -1/6) dot (x, x + xDelta, x + xDelta * 2, x + xDelta * 3) auto res20 = (3 * x + 5 * xDelta) / 3.f; //res(2, 1) = (0, 1/6, 1, -1/6) dot (p[i-1].y, p[i].y, p[i+1].y, p[i+2].y) auto res21 = sixth * p1 + p2 + -sixth * p3; //res(3, 0) = (0, 0, 1, 0) dot (x, x + xDelta, x + xDelta * 2, x + xDelta * 3) auto res30 = x + 2 * xDelta; //res(3, 1) = (0, 0, 1, 0) dot (p[i-1].y, p[i].y, p[i+1].y, p[i+2].y) auto res31 = p2; path.cubicTo(res10, res11, res20, res21, res30, res31); x += xDelta; } QVector result; const auto polygons = path.toSubpathPolygons(); auto pointCount = std::accumulate(polygons.begin(), polygons.end(), 0, [](int current, const QPolygonF &polygon) { return current + polygon.size(); }); result.reserve(pointCount); for (const auto &polygon : polygons) { for (auto point : polygon) { result.append(QVector2D{float(point.x()), float(point.y() / height)}); } } return result; } diff --git a/src/LineChart.h b/src/LineChart.h index 14cfb92..b18e7c6 100644 --- a/src/LineChart.h +++ b/src/LineChart.h @@ -1,86 +1,72 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef LINECHART_H #define LINECHART_H #include #include "XYChart.h" class LineChartNode; /** * A line chart. * * ## Usage example * * \snippet snippets/linechart.qml example * * \image html linechart.png "The resulting bar chart." */ class LineChart : public XYChart { Q_OBJECT /** * Smooth the lines in the chart instead of making hard corners. */ Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged) /** * The width of a line in the chart. */ Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth NOTIFY lineWidthChanged) /** * The opacity of the area below a line. */ Q_PROPERTY(qreal fillOpacity READ fillOpacity WRITE setFillOpacity NOTIFY fillOpacityChanged) public: explicit LineChart(QQuickItem *parent = nullptr); bool smooth() const; void setSmooth(bool smooth); Q_SIGNAL void smoothChanged(); qreal lineWidth() const; void setLineWidth(qreal width); Q_SIGNAL void lineWidthChanged(); qreal fillOpacity() const; void setFillOpacity(qreal opacity); Q_SIGNAL void fillOpacityChanged(); protected: QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) override; void onDataChanged() override; private: void updateLineNode(LineChartNode *node, const QColor &lineColor, ChartDataSource *valueSource); bool m_smooth = false; qreal m_lineWidth = 1.0; qreal m_fillOpacity = 0.0; bool m_rangeInvalid = true; QVector m_previousValues; }; #endif // LINECHART_H diff --git a/src/PieChart.cpp b/src/PieChart.cpp index 026ff99..340d9da 100644 --- a/src/PieChart.cpp +++ b/src/PieChart.cpp @@ -1,273 +1,259 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "PieChart.h" #include #include #include "RangeGroup.h" #include "datasource/ChartDataSource.h" #include "scenegraph/PieChartNode.h" PieChart::PieChart(QQuickItem *parent) : Chart(parent) { setIndexingMode(Chart::IndexSourceValues); m_range = std::make_unique(); connect(m_range.get(), &RangeGroup::rangeChanged, this, &PieChart::onDataChanged); } RangeGroup *PieChart::range() const { return m_range.get(); } bool PieChart::filled() const { return m_filled; } void PieChart::setFilled(bool newFilled) { if (newFilled == m_filled) { return; } m_filled = newFilled; update(); Q_EMIT filledChanged(); } qreal PieChart::thickness() const { return m_thickness; } void PieChart::setThickness(qreal newThickness) { if (newThickness == m_thickness) { return; } m_thickness = newThickness; update(); Q_EMIT thicknessChanged(); } qreal PieChart::spacing() const { return m_spacing; } void PieChart::setSpacing(qreal newSpacing) { if (newSpacing == m_spacing) { return; } m_spacing = newSpacing; update(); Q_EMIT spacingChanged(); } QColor PieChart::backgroundColor() const { return m_backgroundColor; } void PieChart::setBackgroundColor(const QColor &color) { if (color == m_backgroundColor) { return; } m_backgroundColor = color; update(); Q_EMIT backgroundColorChanged(); } qreal PieChart::fromAngle() const { return m_fromAngle; } void PieChart::setFromAngle(qreal newFromAngle) { if (qFuzzyCompare(newFromAngle, m_fromAngle)) { return; } m_fromAngle = newFromAngle; update(); Q_EMIT fromAngleChanged(); } qreal PieChart::toAngle() const { return m_toAngle; } void PieChart::setToAngle(qreal newToAngle) { if (qFuzzyCompare(newToAngle, m_toAngle)) { return; } m_toAngle = newToAngle; update(); Q_EMIT toAngleChanged(); } bool PieChart::smoothEnds() const { return m_smoothEnds; } void PieChart::setSmoothEnds(bool newSmoothEnds) { if (newSmoothEnds == m_smoothEnds) { return; } m_smoothEnds = newSmoothEnds; update(); Q_EMIT smoothEndsChanged(); } QSGNode *PieChart::updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) { Q_UNUSED(data); if (!node) { node = new QSGNode{}; } auto sourceCount = valueSources().size(); if (m_sections.count() < sourceCount) { return node; } auto minDimension = std::min(width(), height()); float outerRadius = minDimension; for (int i = 0; i < sourceCount; ++i) { float innerRadius = i == sourceCount - 1 && m_filled ? 0.0 : outerRadius - m_thickness; if (node->childCount() <= i) { node->appendChildNode(new PieChartNode{}); } auto pieNode = static_cast(node->childAtIndex(i)); pieNode->setRect(boundingRect()); pieNode->setInnerRadius(innerRadius); pieNode->setOuterRadius(outerRadius); pieNode->setSections(m_sections.at(i)); pieNode->setBackgroundColor(m_backgroundColor); pieNode->setColors(m_colors.at(i)); pieNode->setFromAngle(m_fromAngle); pieNode->setToAngle(m_toAngle); pieNode->setSmoothEnds(m_smoothEnds); outerRadius = outerRadius - m_thickness - m_spacing; } while (node->childCount() > sourceCount) { node->removeChildNode(node->childAtIndex(node->childCount() - 1)); } return node; } void PieChart::onDataChanged() { m_sections.clear(); m_colors.clear(); const auto sources = valueSources(); const auto colors = colorSource(); if (!colors || sources.isEmpty() || !m_range->isValid()) { return; } auto maximum = [](ChartDataSource* source) { qreal result = 0.0; for (int i = 0; i < source->itemCount(); ++i) { result += source->item(i).toDouble(); } return std::max(result, source->maximum().toDouble()); }; auto indexMode = indexingMode(); auto colorIndex = 0; auto range = m_range->calculateRange(valueSources(), [](ChartDataSource*) { return 0.0; }, maximum); for (auto source : sources) { qreal threshold = range.start; qreal total = 0.0; QVector sections; QVector sectionColors; for (int i = 0; i < source->itemCount(); ++i) { auto value = source->item(i).toReal(); auto limited = value - threshold; if (limited > 0.0) { if (total + limited >= range.end) { limited = range.end - total; } sections << limited; total += limited; auto color = colors->item(colorIndex).value(); sectionColors << color; } threshold = std::max(0.0, threshold - value); if (indexMode != IndexEachSource) { colorIndex++; } } if (qFuzzyCompare(total, 0.0)) { m_sections << QVector{0.0}; m_colors << QVector{colors->item(colorIndex).value()}; } for (auto &value : sections) { value = value / range.end; } m_sections << sections; m_colors << sectionColors; if (indexMode == IndexEachSource) { colorIndex++; } else if (indexMode == IndexSourceValues) { colorIndex = 0; } } update(); } diff --git a/src/PieChart.h b/src/PieChart.h index 69a95e1..0f36277 100644 --- a/src/PieChart.h +++ b/src/PieChart.h @@ -1,182 +1,168 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef PIECHART_H #define PIECHART_H #include #include "Chart.h" class ChartDataSource; class RangeGroup; /** * An item to render a pie chart. * * This item will render a Pie chart based on the [valueSources] supplied to it. * By default it will set [indexingMode] to [IndexSourceValues], meaning that it * will use the individual values of the valueSources to render sections of the * chart. * * [valueSources]: \ref Chart::valueSources * [indexingMode]: \ref Chart::indexingMode * [IndexSourceValues]: \ref Chart::IndexingMode * * ### Usage example * * \snippet snippets/piechart.qml example * * \image html piechart.png "The resulting pie chart." * * ### Multiple Value Sources * * Multiple valueSources are rendered as consecutive pie charts in the same * item. The first valueSource will become the outermost circle and consecutive * valueSources will be rendered as continuously smaller circles. When rendering * multiple value sources, [filled] will only affect the last value source. All * other value sources will be rendered according to [thickness], with [spacing] * amount of space between them. * * [filled]: \ref PieChart::filled * [thickness]: \ref PieChart::thickness * [spacing]: \ref PieChart::spacing * */ class PieChart : public Chart { Q_OBJECT /** * The range of values to display in this PieChart. * * When set to "automatic", the values will be divided across the entire * chart. * * \sa RangeGroup */ Q_PROPERTY(RangeGroup *range READ range CONSTANT) /** * Whether to use a filled pie or not. * * If true, the last pie rendered will be rendered as a filled circle. * The default is false. */ Q_PROPERTY(bool filled READ filled WRITE setFilled NOTIFY filledChanged) /** * The thickness of an individual pie, in pixels. * * If filled is set, this is ignored for the last pie. The default is 10px. */ Q_PROPERTY(qreal thickness READ thickness WRITE setThickness NOTIFY thicknessChanged) /** * The amount of spacing between pies when rendering multiple value sources. * * The default is 0. */ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) /** * Sets a colour to use to fill remaining space on the pie. * * The default is transparent. */ Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged) /** * The starting angle of the arc used for the entire pie. * * When set, instead of rendering a full circle, the pie will be rendered as * an arc. The default is 0. */ Q_PROPERTY(qreal fromAngle READ fromAngle WRITE setFromAngle NOTIFY fromAngleChanged) /** * The end angle of the arc used for the entire pie. When set, instead of * rendering a full circle, the pie will be rendered as an arc. The default * is 360. */ Q_PROPERTY(qreal toAngle READ toAngle WRITE setToAngle NOTIFY toAngleChanged) /** * Smooth the ends of pie sections. * * When true, this will try to smooth the ends of sections. This works best * when [filled] is false. The default is false. * * [filled]: \ref PieChart::filled */ Q_PROPERTY(bool smoothEnds READ smoothEnds WRITE setSmoothEnds NOTIFY smoothEndsChanged) public: explicit PieChart(QQuickItem *parent = nullptr); RangeGroup *range() const; bool filled() const; void setFilled(bool newFilled); Q_SIGNAL void filledChanged(); qreal thickness() const; void setThickness(qreal newThickness); Q_SIGNAL void thicknessChanged(); qreal spacing() const; void setSpacing(qreal newSpacing); Q_SIGNAL void spacingChanged(); QColor backgroundColor() const; void setBackgroundColor(const QColor &color); Q_SIGNAL void backgroundColorChanged(); qreal fromAngle() const; void setFromAngle(qreal newFromAngle); Q_SIGNAL void fromAngleChanged(); qreal toAngle() const; void setToAngle(qreal newToAngle); Q_SIGNAL void toAngleChanged(); bool smoothEnds() const; void setSmoothEnds(bool newSmoothEnds); Q_SIGNAL void smoothEndsChanged(); protected: /** * Reimplemented from QQuickItem. */ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override; /** * Reimplemented from Chart. */ void onDataChanged() override; private: std::unique_ptr m_range; bool m_filled = false; qreal m_thickness = 10.0; qreal m_spacing = 0.0; QColor m_backgroundColor = Qt::transparent; qreal m_fromAngle = 0.0; qreal m_toAngle = 360.0; bool m_smoothEnds = false; QVector> m_sections; QVector> m_colors; }; #endif // PIECHART_H diff --git a/src/RangeGroup.cpp b/src/RangeGroup.cpp index 07fb9f4..d68bd4a 100644 --- a/src/RangeGroup.cpp +++ b/src/RangeGroup.cpp @@ -1,152 +1,138 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "RangeGroup.h" #include #include RangeGroup::RangeGroup(QObject *parent) : QObject(parent) { connect(this, &RangeGroup::fromChanged, this, &RangeGroup::rangeChanged); connect(this, &RangeGroup::toChanged, this, &RangeGroup::rangeChanged); connect(this, &RangeGroup::automaticChanged, this, &RangeGroup::rangeChanged); connect(this, &RangeGroup::minimumChanged, this, &RangeGroup::rangeChanged); connect(this, &RangeGroup::incrementChanged, this, &RangeGroup::rangeChanged); } qreal RangeGroup::from() const { return m_from; } void RangeGroup::setFrom(qreal from) { if (qFuzzyCompare(m_from, from)) { return; } m_from = from; Q_EMIT fromChanged(); } qreal RangeGroup::to() const { return m_to; } void RangeGroup::setTo(qreal to) { if (qFuzzyCompare(m_to, to)) { return; } m_to = to; Q_EMIT toChanged(); } bool RangeGroup::automatic() const { return m_automatic; } void RangeGroup::setAutomatic(bool automatic) { if (m_automatic == automatic) { return; } m_automatic = automatic; Q_EMIT automaticChanged(); } qreal RangeGroup::distance() const { return m_to - m_from; } qreal RangeGroup::minimum() const { return m_minimum; } void RangeGroup::setMinimum(qreal newMinimum) { if (newMinimum == m_minimum) { return; } m_minimum = newMinimum; Q_EMIT minimumChanged(); } qreal RangeGroup::increment() const { return m_increment; } void RangeGroup::setIncrement(qreal newIncrement) { if (newIncrement == m_increment) { return; } m_increment = newIncrement; Q_EMIT incrementChanged(); } bool RangeGroup::isValid() const { return m_automatic || (m_to > m_from); } RangeGroup::RangeResult RangeGroup::calculateRange(const QVector &sources, std::function minimumCallback, std::function maximumCallback) { RangeResult result; auto min = std::numeric_limits::max(); auto max = std::numeric_limits::min(); if (!m_automatic) { min = m_from; max = m_to; } else { std::for_each(sources.begin(), sources.end(), [&](ChartDataSource *source) { min = std::min(min, minimumCallback(source)); max = std::max(max, maximumCallback(source)); }); } max = std::max(max, m_minimum); if (m_increment > 0.0) { max = m_increment * std::ceil(max / m_increment); } result.start = min; result.end = max; result.distance = max - min; return result; } diff --git a/src/RangeGroup.h b/src/RangeGroup.h index abd9d16..8d588fa 100644 --- a/src/RangeGroup.h +++ b/src/RangeGroup.h @@ -1,125 +1,111 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef RANGEGROUP_H #define RANGEGROUP_H #include #include class ChartDataSource; /** * An object that can be used as a grouped property to provide a value range for charts. * */ class RangeGroup : public QObject { Q_OBJECT /** * The start of this range. * * The default is 0. */ Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged) /** * The end of this range. * * The default is 100. */ Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged) /** * Whether to determine the range based on values of a chart. * * If true (the default), `from` and `to` are ignored and instead calculated * from the minimum and maximum values of a chart's valueSources. */ Q_PROPERTY(bool automatic READ automatic WRITE setAutomatic NOTIFY automaticChanged) /** * The distance between from and to. */ Q_PROPERTY(qreal distance READ distance NOTIFY rangeChanged) /** * The minimum size of the range. * * This is mostly relevant when automatic is true. Setting this value will * ensure that the range will never be smaller than this value. The default * is `std::numeric_limits::min`, which means minimum is disabled. */ Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged) /** * The amount with which the range increases. * * The total range will be limited to a multiple of this value. This is * mostly useful when automatic is true. The default is 0.0, which means do * not limit the range increment. */ Q_PROPERTY(qreal increment READ increment WRITE setIncrement NOTIFY incrementChanged) public: struct RangeResult { qreal start = 0.0; qreal end = 0.0; qreal distance = 0.0; }; explicit RangeGroup(QObject *parent = nullptr); qreal from() const; void setFrom(qreal from); Q_SIGNAL void fromChanged(); qreal to() const; void setTo(qreal to); Q_SIGNAL void toChanged(); bool automatic() const; void setAutomatic(bool newAutomatic); Q_SIGNAL void automaticChanged(); qreal distance() const; qreal minimum() const; void setMinimum(qreal newMinimum); Q_SIGNAL void minimumChanged(); qreal increment() const; void setIncrement(qreal newIncrement); Q_SIGNAL void incrementChanged(); bool isValid() const; Q_SIGNAL void rangeChanged(); RangeResult calculateRange(const QVector &sources, std::function minimumCallback, std::function maximumCallback); private: qreal m_from = 0.0; qreal m_to = 100.0; bool m_automatic = true; qreal m_minimum = std::numeric_limits::min(); qreal m_increment = 0.0; }; #endif // RANGEGROUP_H diff --git a/src/XYChart.cpp b/src/XYChart.cpp index 719484f..a0ebf0d 100644 --- a/src/XYChart.cpp +++ b/src/XYChart.cpp @@ -1,145 +1,131 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "XYChart.h" #include "RangeGroup.h" #include "datasource/ChartDataSource.h" bool operator==(const ComputedRange &first, const ComputedRange &second) { return first.startX == second.startX && first.endX == second.endX && qFuzzyCompare(first.startY, second.startY) && qFuzzyCompare(first.endY, second.endY); } XYChart::XYChart(QQuickItem *parent) : Chart(parent) { m_xRange = new RangeGroup{this}; connect(m_xRange, &RangeGroup::rangeChanged, this, &XYChart::updateComputedRange); m_yRange = new RangeGroup{this}; connect(m_yRange, &RangeGroup::rangeChanged, this, &XYChart::updateComputedRange); } RangeGroup *XYChart::xRange() const { return m_xRange; } RangeGroup *XYChart::yRange() const { return m_yRange; } XYChart::Direction XYChart::direction() const { return m_direction; } void XYChart::setDirection(XYChart::Direction newDirection) { if (newDirection == m_direction) { return; } m_direction = newDirection; onDataChanged(); Q_EMIT directionChanged(); } bool XYChart::stacked() const { return m_stacked; } void XYChart::setStacked(bool newStacked) { if (newStacked == m_stacked) { return; } m_stacked = newStacked; onDataChanged(); Q_EMIT stackedChanged(); } ComputedRange XYChart::computedRange() const { return m_computedRange; } void XYChart::updateComputedRange() { if (valueSources().count() == 0) { return; } ComputedRange result; auto xRange = m_xRange->calculateRange(valueSources(), [](ChartDataSource *) { return 0; }, [](ChartDataSource *source) { return source->itemCount(); }); result.startX = xRange.start; result.endX = xRange.end; result.distanceX = xRange.distance; auto maximumY = [this, xRange](ChartDataSource *source) { if (!m_stacked) { return source->maximum().toDouble(); } else { qreal max = std::numeric_limits::min(); for (int i = xRange.start; i < xRange.end; ++i) { qreal yDistance = 0.0; for (auto source : valueSources()) { yDistance += source->item(i).toDouble(); } max = std::max(max, yDistance); } return max; } }; auto yRange = m_yRange->calculateRange(valueSources(), [](ChartDataSource *source) { return std::min(0.0, source->minimum().toDouble()); }, maximumY); result.startY = yRange.start; result.endY = yRange.end; result.distanceY = yRange.distance; setComputedRange(result); } void XYChart::setComputedRange(ComputedRange range) { if (range == m_computedRange) { return; } m_computedRange = range; Q_EMIT computedRangeChanged(); } QDebug operator<<(QDebug debug, const ComputedRange &range) { debug << "Range: startX" << range.startX << "endX" << range.endX << "distance" << range.distanceX << "startY" << range.startY << "endY" << range.endY << "distance" << range.distanceY; return debug; } diff --git a/src/XYChart.h b/src/XYChart.h index a20f972..9c25a06 100644 --- a/src/XYChart.h +++ b/src/XYChart.h @@ -1,144 +1,130 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef XYCHART_H #define XYCHART_H #include "Chart.h" class RangeGroup; /** * A helper containing the calculated X and Y ranges of a chart. */ struct ComputedRange { int startX = 0; int endX = 0; int distanceX = 0; float startY = 0.0; float endY = 0.0; float distanceY = 0.0; }; bool operator==(const ComputedRange &first, const ComputedRange &second); /** * A base class for Charts that are based on an X/Y grid. */ class XYChart : public Chart { Q_OBJECT /** * The range of values on the X axis. */ Q_PROPERTY(RangeGroup *xRange READ xRange CONSTANT) /** * The range of values on the Y axis. */ Q_PROPERTY(RangeGroup *yRange READ yRange CONSTANT) /** * Which direction this chart's X axis runs. */ Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged) /** * Whether the values of each value source should be stacked. * * When true, Y values will be added on top of each other. The precise * meaning of this property depends on the specific chart. The default is * false. */ Q_PROPERTY(bool stacked READ stacked WRITE setStacked NOTIFY stackedChanged) public: /** * The direction of values on the X axis. * * "Start" is defined as the starting direction of the chart, when using a * left-to-right language it will be the left side, with a right-to-left * language it will be right. */ enum class Direction { ZeroAtStart, ///< Zero is at the beginning of the chart, values run from begin to end. ZeroAtEnd ///< Zero is at the end of the chart, values run from end to begin. }; Q_ENUM(Direction) /** * Constructor * * @param parent The QObject parent. */ explicit XYChart(QQuickItem *parent = nullptr); /** * Destructor */ ~XYChart() override = default; virtual RangeGroup *xRange() const; virtual RangeGroup *yRange() const; virtual XYChart::Direction direction() const; virtual void setDirection(XYChart::Direction newDirection); Q_SIGNAL void directionChanged(); bool stacked() const; void setStacked(bool newStacked); Q_SIGNAL void stackedChanged(); /** * Get the complete, calculated range for this chart. */ ComputedRange computedRange() const; /** * Emitted whenever the complete range is recalculated. */ Q_SIGNAL void computedRangeChanged(); protected: /** * Re-calculate the chart's range. * * By default, this will make use of the xRange/yRange properties and * calculate a proper range. This method can be overridden by subclasses if * some special calculation is needed. */ virtual void updateComputedRange(); /** * Set the computed range. * * \param range The new range. */ void setComputedRange(ComputedRange range); private: RangeGroup *m_xRange = nullptr; RangeGroup *m_yRange = nullptr; Direction m_direction = Direction::ZeroAtStart; bool m_stacked = false; ComputedRange m_computedRange; }; QDebug operator<<(QDebug debug, const ComputedRange &range); #endif // XYCHART_H diff --git a/src/datasource/ArraySource.cpp b/src/datasource/ArraySource.cpp index 72f485c..5928640 100644 --- a/src/datasource/ArraySource.cpp +++ b/src/datasource/ArraySource.cpp @@ -1,88 +1,74 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ArraySource.h" ArraySource::ArraySource(QObject *parent) : ChartDataSource(parent) { } int ArraySource::itemCount() const { return m_array.count(); } QVariant ArraySource::item(int index) const { if (!m_wrap && (index < 0 || index > m_array.count() - 1)) return QVariant{}; return m_array.at(index % m_array.count()); } QVariant ArraySource::minimum() const { auto itr = std::min_element(m_array.cbegin(), m_array.cend()); if (itr != m_array.cend()) { return *itr; } return QVariant{}; } QVariant ArraySource::maximum() const { auto itr = std::max_element(m_array.cbegin(), m_array.cend()); if (itr != m_array.cend()) { return *itr; } return QVariant{}; } QVariantList ArraySource::array() const { return m_array; } bool ArraySource::wrap() const { return m_wrap; } void ArraySource::setArray(const QVariantList &array) { if (m_array == array) { return; } m_array = array; Q_EMIT dataChanged(); } void ArraySource::setWrap(bool wrap) { if (m_wrap == wrap) { return; } m_wrap = wrap; Q_EMIT dataChanged(); } diff --git a/src/datasource/ArraySource.h b/src/datasource/ArraySource.h index 7c10b9f..f5ee981 100644 --- a/src/datasource/ArraySource.h +++ b/src/datasource/ArraySource.h @@ -1,62 +1,48 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef ARRAYSOURCE_H #define ARRAYSOURCE_H #include #include "ChartDataSource.h" /** * A data source that provides entries of an array as data. */ class ArraySource : public ChartDataSource { Q_OBJECT Q_PROPERTY(QVariantList array READ array WRITE setArray NOTIFY dataChanged) Q_PROPERTY(bool wrap READ wrap WRITE setWrap NOTIFY dataChanged) public: /** * Constructor * * @param parent TODO */ explicit ArraySource(QObject *parent = nullptr); virtual int itemCount() const override; virtual QVariant item(int index) const override; QVariant minimum() const override; QVariant maximum() const override; QVariantList array() const; void setArray(const QVariantList &array); bool wrap() const; void setWrap(bool wrap); private: QVariantList m_array; bool m_wrap = false; }; #endif // ARRAYSOURCE_H diff --git a/src/datasource/ChartAxisSource.cpp b/src/datasource/ChartAxisSource.cpp index 2c7fdc1..a6b2d06 100644 --- a/src/datasource/ChartAxisSource.cpp +++ b/src/datasource/ChartAxisSource.cpp @@ -1,124 +1,110 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ChartAxisSource.h" #include #include #include "XYChart.h" ChartAxisSource::ChartAxisSource(QObject *parent) : ChartDataSource(parent) { connect(this, &ChartAxisSource::itemCountChanged, this, &ChartAxisSource::dataChanged); connect(this, &ChartAxisSource::chartChanged, this, &ChartAxisSource::dataChanged); connect(this, &ChartAxisSource::axisChanged, this, &ChartAxisSource::dataChanged); } QVariant ChartAxisSource::item(int index) const { if (!m_chart || index < 0 || index > m_itemCount) return QVariant{}; auto range = m_chart->computedRange(); if (m_axis == Axis::XAxis) { return range.startX + (range.distanceX / (m_itemCount - 1)) * index; } else { return range.startY + (range.distanceY / (m_itemCount - 1)) * index; } } QVariant ChartAxisSource::minimum() const { if (!m_chart) return QVariant{}; if (m_axis == Axis::XAxis) { return m_chart->computedRange().startX; } else { return m_chart->computedRange().startY; } } QVariant ChartAxisSource::maximum() const { if (!m_chart) return QVariant{}; if (m_axis == Axis::XAxis) { return m_chart->computedRange().endX; } else { return m_chart->computedRange().endY; } } XYChart *ChartAxisSource::chart() const { return m_chart; } void ChartAxisSource::setChart(XYChart *newChart) { if (newChart == m_chart) { return; } if (m_chart) { disconnect(m_chart, &XYChart::computedRangeChanged, this, &ChartAxisSource::dataChanged); } m_chart = newChart; if (m_chart) { connect(m_chart, &XYChart::computedRangeChanged, this, &ChartAxisSource::dataChanged); } Q_EMIT chartChanged(); } ChartAxisSource::Axis ChartAxisSource::axis() const { return m_axis; } void ChartAxisSource::setAxis(ChartAxisSource::Axis newAxis) { if (newAxis == m_axis) { return; } m_axis = newAxis; Q_EMIT axisChanged(); } int ChartAxisSource::itemCount() const { return m_itemCount; } void ChartAxisSource::setItemCount(int newItemCount) { if (newItemCount == m_itemCount) { return; } m_itemCount = newItemCount; Q_EMIT itemCountChanged(); } diff --git a/src/datasource/ChartAxisSource.h b/src/datasource/ChartAxisSource.h index 6149cc7..1bb0a44 100644 --- a/src/datasource/ChartAxisSource.h +++ b/src/datasource/ChartAxisSource.h @@ -1,72 +1,58 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef CHARTAXISSOURCE_H #define CHARTAXISSOURCE_H #include "ChartDataSource.h" class XYChart; /** * A data source that provides values from a chart's axis as data. */ class ChartAxisSource : public ChartDataSource { Q_OBJECT Q_PROPERTY(XYChart *chart READ chart WRITE setChart NOTIFY chartChanged) Q_PROPERTY(ChartAxisSource::Axis axis READ axis WRITE setAxis NOTIFY axisChanged) Q_PROPERTY(int itemCount READ itemCount WRITE setItemCount NOTIFY itemCountChanged) public: enum class Axis { XAxis, YAxis }; Q_ENUM(Axis) /** * Constructor * * @param parent TODO */ ChartAxisSource(QObject *parent = nullptr); virtual QVariant item(int index) const override; QVariant minimum() const override; QVariant maximum() const override; XYChart *chart() const; Q_SLOT void setChart(XYChart *newChart); Q_SIGNAL void chartChanged(); ChartAxisSource::Axis axis() const; Q_SLOT void setAxis(ChartAxisSource::Axis newAxis); Q_SIGNAL void axisChanged(); virtual int itemCount() const override; Q_SLOT void setItemCount(int newItemCount); Q_SIGNAL void itemCountChanged(); private: XYChart *m_chart = nullptr; Axis m_axis = Axis::XAxis; int m_itemCount = 2; }; #endif // ARRAYSOURCE_H diff --git a/src/datasource/ChartDataSource.cpp b/src/datasource/ChartDataSource.cpp index 0e061ff..1fba2cf 100644 --- a/src/datasource/ChartDataSource.cpp +++ b/src/datasource/ChartDataSource.cpp @@ -1,27 +1,13 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ChartDataSource.h" ChartDataSource::ChartDataSource(QObject *parent) : QObject(parent) { } diff --git a/src/datasource/ChartDataSource.h b/src/datasource/ChartDataSource.h index 0535c05..5bb6f39 100644 --- a/src/datasource/ChartDataSource.h +++ b/src/datasource/ChartDataSource.h @@ -1,46 +1,32 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef DATASOURCE_H #define DATASOURCE_H #include /** * Abstract base class for data sources. */ class ChartDataSource : public QObject { Q_OBJECT public: explicit ChartDataSource(QObject *parent = nullptr); virtual ~ChartDataSource() = default; virtual int itemCount() const = 0; virtual QVariant item(int index) const = 0; virtual QVariant minimum() const = 0; virtual QVariant maximum() const = 0; Q_SIGNAL void dataChanged(); }; #endif // DATASOURCE_H diff --git a/src/datasource/ColorGradientSource.cpp b/src/datasource/ColorGradientSource.cpp index 6ca4e26..8bc3dbf 100644 --- a/src/datasource/ColorGradientSource.cpp +++ b/src/datasource/ColorGradientSource.cpp @@ -1,111 +1,97 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Marco Martin - * Copyright 2019 David Edmundson - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Marco Martin + * SPDX-FileCopyrightText: 2019 David Edmundson + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ColorGradientSource.h" #include #include ColorGradientSource::ColorGradientSource(QObject *parent) : ChartDataSource(parent) { } int ColorGradientSource::itemCount() const { return m_itemCount; } QVariant ColorGradientSource::item(int index) const { if (index < 0 || index >= m_colors.size()) { return QVariant{}; } return m_colors.at(index); } QVariant ColorGradientSource::minimum() const { return QVariant{}; } QVariant ColorGradientSource::maximum() const { return QVariant{}; } QColor ColorGradientSource::baseColor() const { return m_baseColor; } void ColorGradientSource::setBaseColor(const QColor &newBaseColor) { if (newBaseColor == m_baseColor) { return; } m_baseColor = newBaseColor; regenerateColors(); Q_EMIT baseColorChanged(); } void ColorGradientSource::setItemCount(int newItemCount) { if (newItemCount == m_itemCount) { return; } m_itemCount = newItemCount; regenerateColors(); Q_EMIT itemCountChanged(); } QVariantList ColorGradientSource::colors() const { QVariantList colorsVariant; colorsVariant.reserve(m_colors.count()); for (const QColor &color : qAsConst(m_colors)) { colorsVariant.append(color); } return colorsVariant; } void ColorGradientSource::regenerateColors() { if (!m_baseColor.isValid() || m_itemCount <= 0) { return; } m_colors.clear(); for (int i = 0; i < m_itemCount; ++i) { auto newHue = m_baseColor.hsvHueF() + i * (1.0 / m_itemCount); newHue = newHue - int(newHue); m_colors.append(QColor::fromHsvF(newHue, m_baseColor.saturationF(), m_baseColor.valueF(), m_baseColor.alphaF())); } Q_EMIT dataChanged(); } diff --git a/src/datasource/ColorGradientSource.h b/src/datasource/ColorGradientSource.h index 604c36b..f889edb 100644 --- a/src/datasource/ColorGradientSource.h +++ b/src/datasource/ColorGradientSource.h @@ -1,67 +1,53 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Marco Martin - * Copyright 2019 David Edmundson - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Marco Martin + * SPDX-FileCopyrightText: 2019 David Edmundson + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef COLORGRADIENTSOURCE_H #define COLORGRADIENTSOURCE_H #include #include #include "ChartDataSource.h" /** * A data source that provides a hue-shifted color as data. */ class ColorGradientSource : public ChartDataSource { Q_OBJECT Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) Q_PROPERTY(int itemCount READ itemCount WRITE setItemCount NOTIFY itemCountChanged) Q_PROPERTY(QVariantList colors READ colors NOTIFY dataChanged) public: explicit ColorGradientSource(QObject *parent = nullptr); int itemCount() const override; QVariant item(int index) const override; QVariant minimum() const override; QVariant maximum() const override; QColor baseColor() const; void setBaseColor(const QColor &newBaseColor); Q_SIGNAL void baseColorChanged(); void setItemCount(int newItemCount); Q_SIGNAL void itemCountChanged(); QVariantList colors() const; private: void regenerateColors(); QColor m_baseColor = Qt::blue; int m_itemCount = 0; QVector m_colors; }; #endif // COLORGRADIENTSOURCE_H diff --git a/src/datasource/ModelHistorySource.cpp b/src/datasource/ModelHistorySource.cpp index ef13c4a..4c60c00 100644 --- a/src/datasource/ModelHistorySource.cpp +++ b/src/datasource/ModelHistorySource.cpp @@ -1,174 +1,160 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ModelHistorySource.h" #include #include #include #include ModelHistorySource::ModelHistorySource(QObject *parent) : ModelSource(parent) { connect(this, &ModelHistorySource::modelChanged, this, &ModelHistorySource::onModelChanged); } int ModelHistorySource::itemCount() const { return m_history.size(); } QVariant ModelHistorySource::item(int index) const { if (index < 0 || index >= m_history.size()) return QVariant{}; return m_history.at(index); } QVariant ModelHistorySource::minimum() const { if (m_history.isEmpty()) return QVariant{}; return *std::min_element(m_history.begin(), m_history.end()); } QVariant ModelHistorySource::maximum() const { if (m_history.isEmpty()) return QVariant{}; return *std::max_element(m_history.begin(), m_history.end()); } int ModelHistorySource::row() const { return m_row; } void ModelHistorySource::setRow(int row) { if (m_row == row) { return; } m_row = row; Q_EMIT rowChanged(); } int ModelHistorySource::maximumHistory() const { return m_maximumHistory; } void ModelHistorySource::setMaximumHistory(int maximumHistory) { if (m_maximumHistory == maximumHistory) { return; } m_maximumHistory = maximumHistory; Q_EMIT maximumHistoryChanged(); } int ModelHistorySource::interval() const { return m_updateTimer ? m_updateTimer->interval() : -1; } void ModelHistorySource::setInterval(int newInterval) { if (m_updateTimer && newInterval == m_updateTimer->interval()) { return; } if (newInterval > 0) { if (!m_updateTimer) { m_updateTimer = std::make_unique(); // We need precise timers to avoid missing updates when dealing with semi-constantly // updating model. That is, if the model updates at 500ms and we also update at that // rate, a drift of 2ms can cause us to miss updates. m_updateTimer->setTimerType(Qt::PreciseTimer); connect(m_updateTimer.get(), &QTimer::timeout, this, [this]() { if (!model()) { return; } auto index = model()->index(m_row, column()); onDataChanged(index, index, {role()}); }); if (model()) { disconnect(model(), &QAbstractItemModel::dataChanged, this, &ModelHistorySource::onDataChanged); } } m_updateTimer->setInterval(newInterval); m_updateTimer->start(); } else { m_updateTimer.reset(); onModelChanged(); } Q_EMIT intervalChanged(); } void ModelHistorySource::clear() { m_history.clear(); Q_EMIT dataChanged(); } void ModelHistorySource::onModelChanged() { if (model() && !m_updateTimer) { connect(model(), &QAbstractItemModel::dataChanged, this, &ModelHistorySource::onDataChanged); } } void ModelHistorySource::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { if (!model()) { return; } if (!roles.isEmpty() && !roles.contains(role())) { return; } if (topLeft.row() > m_row || bottomRight.row() < m_row) { return; } if (topLeft.column() > column() || bottomRight.column() < column()) { return; } auto entry = model()->data(model()->index(m_row, column()), role()); m_history.prepend(entry); while (m_history.size() > m_maximumHistory) { m_history.pop_back(); } Q_EMIT dataChanged(); } diff --git a/src/datasource/ModelHistorySource.h b/src/datasource/ModelHistorySource.h index 1d0041c..355f314 100644 --- a/src/datasource/ModelHistorySource.h +++ b/src/datasource/ModelHistorySource.h @@ -1,78 +1,64 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef MODELHISTORYSOURCE_H #define MODELHISTORYSOURCE_H #include #include #include "ModelSource.h" /** * A data source that watches a QAbstractItemModel cell and provides the history of that cell as data. */ class ModelHistorySource : public ModelSource { Q_OBJECT // The row to read data from. The items of this source will be the values of // that row, using the column and role from ModelSource. Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged) // The maximum amount of history to keep. Q_PROPERTY(int maximumHistory READ maximumHistory WRITE setMaximumHistory NOTIFY maximumHistoryChanged) // The update interval. If not set or set to a value < 0, a new item will be // added whenever the underlying model changes. Otherwise, the source will // sample the underlying model every interval milliseconds and add a new item // with whatever value the model has at that point - even if it did not change. Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged) public: explicit ModelHistorySource(QObject *parent = nullptr); virtual int itemCount() const override; virtual QVariant item(int index) const override; virtual QVariant minimum() const override; virtual QVariant maximum() const override; int row() const; void setRow(int row); Q_SIGNAL void rowChanged(); int maximumHistory() const; void setMaximumHistory(int maximumHistory); Q_SIGNAL void maximumHistoryChanged(); int interval() const; void setInterval(int newInterval); Q_SIGNAL void intervalChanged(); Q_INVOKABLE void clear(); private: void onModelChanged(); void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); int m_row; int m_maximumHistory; QVariantList m_history; std::unique_ptr m_updateTimer; }; #endif // MODELHISTORYSOURCE_H diff --git a/src/datasource/ModelSource.cpp b/src/datasource/ModelSource.cpp index e6c58e7..f1e7627 100644 --- a/src/datasource/ModelSource.cpp +++ b/src/datasource/ModelSource.cpp @@ -1,205 +1,191 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ModelSource.h" #include ModelSource::ModelSource(QObject *parent) : ChartDataSource(parent) { connect(this, &ModelSource::modelChanged, this, &ModelSource::dataChanged); connect(this, &ModelSource::columnChanged, this, &ModelSource::dataChanged); connect(this, &ModelSource::roleChanged, this, &ModelSource::dataChanged); connect(this, &ModelSource::indexColumnsChanged, this, &ModelSource::dataChanged); } int ModelSource::role() const { if (m_role < 0 && !m_roleName.isEmpty()) m_role = m_model->roleNames().key(m_roleName.toLatin1(), -1); return m_role; } QString ModelSource::roleName() const { return m_roleName; } int ModelSource::column() const { return m_column; } QAbstractItemModel *ModelSource::model() const { return m_model; } bool ModelSource::indexColumns() const { return m_indexColumns; } int ModelSource::itemCount() const { if (!m_model) return 0; return m_indexColumns ? m_model->columnCount() : m_model->rowCount(); } QVariant ModelSource::item(int index) const { if (!m_model) return QVariant{}; // For certain model (QML ListModel for example), the roleNames() are more // dynamic and may only be valid when this method gets called. So try and // lookup the role first before anything else. if (m_role < 0 && !m_roleName.isEmpty()) m_role = m_model->roleNames().key(m_roleName.toLatin1(), -1); if (m_role < 0) { qWarning() << "ModelSource: Invalid role " << m_role << m_roleName; return QVariant{}; } if (!m_indexColumns && (m_column < 0 || m_column > m_model->columnCount())) { qWarning() << "ModelSource: Invalid column" << m_column; return QVariant{}; } auto modelIndex = m_indexColumns ? m_model->index(0, index) : m_model->index(index, m_column); if (modelIndex.isValid()) { return m_model->data(modelIndex, m_role); } return QVariant{}; } QVariant ModelSource::minimum() const { if (itemCount() <= 0) return QVariant{}; auto minProperty = m_model->property("minimum"); auto maxProperty = m_model->property("maximum"); if (minProperty.isValid() && minProperty != maxProperty) { return minProperty; } QVariant result = std::numeric_limits::max(); for (int i = 0; i < itemCount(); ++i) { result = qMin(result, item(i)); } return result; } QVariant ModelSource::maximum() const { if (itemCount() <= 0) return QVariant{}; auto minProperty = m_model->property("minimum"); auto maxProperty = m_model->property("maximum"); if (maxProperty.isValid() && maxProperty != minProperty) { return maxProperty; } QVariant result = std::numeric_limits::min(); for (int i = 0; i < itemCount(); ++i) { result = qMax(result, item(i)); } return result; } void ModelSource::setRole(int role) { if (role == m_role) { return; } m_role = role; if (m_model) { m_roleName = QString::fromLatin1(m_model->roleNames().value(role)); Q_EMIT roleNameChanged(); } Q_EMIT roleChanged(); } void ModelSource::setRoleName(const QString &name) { if (name == m_roleName) { return; } m_roleName = name; if (m_model) { m_role = m_model->roleNames().key(m_roleName.toLatin1(), -1); Q_EMIT roleChanged(); } Q_EMIT roleNameChanged(); } void ModelSource::setColumn(int column) { if (column == m_column) { return; } m_column = column; Q_EMIT columnChanged(); } void ModelSource::setIndexColumns(bool index) { if (index == m_indexColumns) { return; } m_indexColumns = index; Q_EMIT indexColumnsChanged(); } void ModelSource::setModel(QAbstractItemModel *model) { if (m_model == model) { return; } if (m_model) { m_model->disconnect(this); } m_model = model; if (m_model) { connect(m_model, &QAbstractItemModel::rowsInserted, this, &ModelSource::dataChanged); connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ModelSource::dataChanged); connect(m_model, &QAbstractItemModel::rowsMoved, this, &ModelSource::dataChanged); connect(m_model, &QAbstractItemModel::modelReset, this, &ModelSource::dataChanged); connect(m_model, &QAbstractItemModel::dataChanged, this, &ModelSource::dataChanged); connect(m_model, &QAbstractItemModel::layoutChanged, this, &ModelSource::dataChanged); } Q_EMIT modelChanged(); } diff --git a/src/datasource/ModelSource.h b/src/datasource/ModelSource.h index bb35464..d5a2207 100644 --- a/src/datasource/ModelSource.h +++ b/src/datasource/ModelSource.h @@ -1,79 +1,65 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef MODELSOURCE_H #define MODELSOURCE_H #include "ChartDataSource.h" #include /** * A data source that reads data from a QAbstractItemModel. * * */ class ModelSource : public ChartDataSource { Q_OBJECT Q_PROPERTY(int role READ role WRITE setRole NOTIFY roleChanged) Q_PROPERTY(QString roleName READ roleName WRITE setRoleName NOTIFY roleNameChanged) Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged) Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(bool indexColumns READ indexColumns WRITE setIndexColumns NOTIFY indexColumnsChanged) public: explicit ModelSource(QObject *parent = nullptr); int role() const; void setRole(int role); Q_SIGNAL void roleChanged(); QString roleName() const; void setRoleName(const QString &name); Q_SIGNAL void roleNameChanged(); int column() const; void setColumn(int column); Q_SIGNAL void columnChanged(); QAbstractItemModel *model() const; void setModel(QAbstractItemModel *model); Q_SIGNAL void modelChanged(); bool indexColumns() const; void setIndexColumns(bool index); Q_SIGNAL void indexColumnsChanged(); virtual int itemCount() const override; virtual QVariant item(int index) const override; virtual QVariant minimum() const override; virtual QVariant maximum() const override; private: mutable int m_role = -1; QString m_roleName; int m_column = 0; bool m_indexColumns = false; QAbstractItemModel *m_model = nullptr; }; #endif // MODELSOURCE_H diff --git a/src/datasource/SingleValueSource.cpp b/src/datasource/SingleValueSource.cpp index 06e8ace..5808901 100644 --- a/src/datasource/SingleValueSource.cpp +++ b/src/datasource/SingleValueSource.cpp @@ -1,63 +1,49 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "SingleValueSource.h" SingleValueSource::SingleValueSource(QObject *parent) : ChartDataSource(parent) { } QVariant SingleValueSource::item(int index) const { Q_UNUSED(index); return m_value; } int SingleValueSource::itemCount() const { return 1; } QVariant SingleValueSource::minimum() const { return m_value; } QVariant SingleValueSource::maximum() const { return m_value; } QVariant SingleValueSource::value() const { return m_value; } void SingleValueSource::setValue(const QVariant &value) { if (m_value == value) { return; } m_value = value; Q_EMIT dataChanged(); } diff --git a/src/datasource/SingleValueSource.h b/src/datasource/SingleValueSource.h index 6107f7a..fa3fd95 100644 --- a/src/datasource/SingleValueSource.h +++ b/src/datasource/SingleValueSource.h @@ -1,52 +1,38 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef SINGLEVALUESOURCE_H #define SINGLEVALUESOURCE_H #include #include "ChartDataSource.h" /** * A data source that provides a single value as data. */ class SingleValueSource : public ChartDataSource { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY dataChanged) public: explicit SingleValueSource(QObject *parent = nullptr); virtual int itemCount() const override; virtual QVariant item(int index) const override; QVariant minimum() const override; QVariant maximum() const override; QVariant value() const; void setValue(const QVariant &value); private: QVariant m_value; }; #endif // SINGLEVALUESOURCE_H diff --git a/src/datasource/ValueHistorySource.cpp b/src/datasource/ValueHistorySource.cpp index 92e366a..be6cc46 100644 --- a/src/datasource/ValueHistorySource.cpp +++ b/src/datasource/ValueHistorySource.cpp @@ -1,138 +1,124 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "ValueHistorySource.h" #include ValueHistorySource::ValueHistorySource(QObject *parent) : ChartDataSource(parent) { } int ValueHistorySource::itemCount() const { return m_maximumHistory; } QVariant ValueHistorySource::item(int index) const { if (index < 0 || index >= m_history.count()) { return QVariant{}; } return m_history.at(index); } QVariant ValueHistorySource::minimum() const { auto item = std::min_element(m_history.cbegin(), m_history.cend()); if (item != m_history.cend()) return *item; return QVariant{}; } QVariant ValueHistorySource::maximum() const { auto item = std::max_element(m_history.cbegin(), m_history.cend()); if (item != m_history.cend()) return *item; return QVariant{}; } QVariant ValueHistorySource::value() const { return m_value; } void ValueHistorySource::setValue(const QVariant &newValue) { m_value = newValue; if (!m_updateTimer) { m_history.prepend(newValue); while (m_history.size() > m_maximumHistory) { m_history.removeLast(); } Q_EMIT dataChanged(); } } int ValueHistorySource::maximumHistory() const { return m_maximumHistory; } void ValueHistorySource::setMaximumHistory(int newMaximumHistory) { if (newMaximumHistory == m_maximumHistory) { return; } m_maximumHistory = newMaximumHistory; while (m_history.size() > m_maximumHistory) { m_history.removeLast(); } Q_EMIT maximumHistoryChanged(); } int ValueHistorySource::interval() const { return m_updateTimer ? m_updateTimer->interval() : -1; } void ValueHistorySource::setInterval(int newInterval) { if (m_updateTimer && newInterval == m_updateTimer->interval()) { return; } if (newInterval > 0) { if (!m_updateTimer) { m_updateTimer = std::make_unique(); // See ModelHistorySource.cpp line 110 m_updateTimer->setTimerType(Qt::PreciseTimer); connect(m_updateTimer.get(), &QTimer::timeout, this, [this]() { m_history.prepend(m_value); while (m_history.size() > m_maximumHistory) { m_history.removeLast(); } Q_EMIT dataChanged(); }); } m_updateTimer->setInterval(newInterval); m_updateTimer->start(); } else { m_updateTimer.reset(); } Q_EMIT intervalChanged(); } void ValueHistorySource::clear() { m_history.clear(); Q_EMIT dataChanged(); } diff --git a/src/datasource/ValueHistorySource.h b/src/datasource/ValueHistorySource.h index 9866b06..59ac01e 100644 --- a/src/datasource/ValueHistorySource.h +++ b/src/datasource/ValueHistorySource.h @@ -1,70 +1,56 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef VALUEHISTORYSOURCE_H #define VALUEHISTORYSOURCE_H #include #include #include #include #include "ChartDataSource.h" /** * A data source that provides a history of a single value. */ class ValueHistorySource : public ChartDataSource { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY dataChanged) Q_PROPERTY(int maximumHistory READ maximumHistory WRITE setMaximumHistory NOTIFY maximumHistoryChanged) Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged) public: explicit ValueHistorySource(QObject *parent = nullptr); int itemCount() const override; QVariant item(int index) const override; QVariant minimum() const override; QVariant maximum() const override; QVariant value() const; void setValue(const QVariant &value); int maximumHistory() const; void setMaximumHistory(int maximumHistory); Q_SIGNAL void maximumHistoryChanged(); int interval() const; void setInterval(int newInterval); Q_SIGNAL void intervalChanged(); Q_INVOKABLE void clear(); private: QVariant m_value; int m_maximumHistory = 10; std::unique_ptr m_updateTimer; QVector m_history; }; #endif // VALUEHISTORYSOURCE_H diff --git a/src/decorations/AxisLabels.cpp b/src/decorations/AxisLabels.cpp index 8386eb3..d5f1016 100644 --- a/src/decorations/AxisLabels.cpp +++ b/src/decorations/AxisLabels.cpp @@ -1,292 +1,278 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "AxisLabels.h" #include #include "datasource/ChartDataSource.h" #include AxisLabelsAttached::AxisLabelsAttached(QObject *parent) : QObject(parent) { } int AxisLabelsAttached::index() const { return m_index; } void AxisLabelsAttached::setIndex(int newIndex) { if (newIndex == m_index) { return; } m_index = newIndex; Q_EMIT indexChanged(); } QString AxisLabelsAttached::label() const { return m_label; } void AxisLabelsAttached::setLabel(const QString &newLabel) { if (newLabel == m_label) { return; } m_label = newLabel; Q_EMIT labelChanged(); } AxisLabels::AxisLabels(QQuickItem *parent) : QQuickItem(parent) { } AxisLabels::Direction AxisLabels::direction() const { return m_direction; } void AxisLabels::setDirection(AxisLabels::Direction newDirection) { if (newDirection == m_direction) { return; } m_direction = newDirection; scheduleLayout(); Q_EMIT directionChanged(); } QQmlComponent *AxisLabels::delegate() const { return m_delegate; } void AxisLabels::setDelegate(QQmlComponent *newDelegate) { if (newDelegate == m_delegate) { return; } m_delegate = newDelegate; updateLabels(); Q_EMIT delegateChanged(); } ChartDataSource *AxisLabels::source() const { return m_source; } void AxisLabels::setSource(ChartDataSource *newSource) { if (newSource == m_source) { return; } if (m_source) { m_source->disconnect(this); } m_source = newSource; if (m_source) { connect(m_source, &ChartDataSource::dataChanged, this, [this]() { updateLabels(); }); } updateLabels(); Q_EMIT sourceChanged(); } Qt::Alignment AxisLabels::alignment() const { return m_alignment; } void AxisLabels::setAlignment(Qt::Alignment newAlignment) { if (newAlignment == m_alignment) { return; } m_alignment = newAlignment; scheduleLayout(); Q_EMIT alignmentChanged(); } bool AxisLabels::constrainToBounds() const { return m_constrainToBounds; } void AxisLabels::setConstrainToBounds(bool newConstrainToBounds) { if (newConstrainToBounds == m_constrainToBounds) { return; } m_constrainToBounds = newConstrainToBounds; scheduleLayout(); Q_EMIT constrainToBoundsChanged(); } void AxisLabels::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { QQuickItem::geometryChanged(newGeometry, oldGeometry); if (newGeometry != oldGeometry) { scheduleLayout(); } } void AxisLabels::scheduleLayout() { if (!m_layoutScheduled) { QMetaObject::invokeMethod( this, [this]() { layout(); m_layoutScheduled = false; }, Qt::QueuedConnection); m_layoutScheduled = true; } } bool AxisLabels::isHorizontal() { return m_direction == Direction::HorizontalLeftRight || m_direction == Direction::HorizontalRightLeft; } void AxisLabels::updateLabels() { qDeleteAll(m_labels); m_labels.clear(); if (!m_delegate || !m_source) { return; } for (int i = 0; i < m_source->itemCount(); ++i) { auto label = m_source->item(i).toString(); auto context = new QQmlContext(qmlContext(this)); auto item = qobject_cast(m_delegate->beginCreate(context)); if (!item) { qWarning() << "Failed to create label instance for label" << label; continue; } QObject::connect(item, &QQuickItem::xChanged, this, [this]() { scheduleLayout(); }); QObject::connect(item, &QQuickItem::yChanged, this, [this]() { scheduleLayout(); }); QObject::connect(item, &QQuickItem::widthChanged, this, [this]() { scheduleLayout(); }); QObject::connect(item, &QQuickItem::heightChanged, this, [this]() { scheduleLayout(); }); context->setParent(item); item->setParentItem(this); auto attached = static_cast(qmlAttachedPropertiesObject(item, true)); attached->setIndex(i); attached->setLabel(label); m_delegate->completeCreate(); m_labels << item; } scheduleLayout(); } void AxisLabels::layout() { auto maxWidth = 0.0; auto totalWidth = 0.0; auto maxHeight = 0.0; auto totalHeight = 0.0; for (auto label : qAsConst(m_labels)) { maxWidth = std::max(maxWidth, label->width()); maxHeight = std::max(maxHeight, label->height()); totalWidth += label->width(); totalHeight += label->height(); } auto impWidth = isHorizontal() ? totalWidth : maxWidth; auto impHeight = isHorizontal() ? maxHeight : totalHeight; if (qFuzzyCompare(impWidth, width()) && qFuzzyCompare(impHeight, height())) { return; } setImplicitWidth(impWidth); setImplicitHeight(impHeight); auto spacing = (isHorizontal() ? width() : height()) / (m_labels.size() - 1); auto i = 0; auto layoutWidth = isHorizontal() ? 0.0 : width(); auto layoutHeight = isHorizontal() ? height() : 0.0; for (auto label : qAsConst(m_labels)) { auto x = 0.0; auto y = 0.0; switch (m_direction) { case Direction::HorizontalLeftRight: x = i * spacing; break; case Direction::HorizontalRightLeft: x = width() - i * spacing; break; case Direction::VerticalTopBottom: y = i * spacing; break; case Direction::VerticalBottomTop: y = height() - i * spacing; break; } if (m_alignment & Qt::AlignHCenter) { x += (layoutWidth - label->width()) / 2; } else if (m_alignment & Qt::AlignRight) { x += layoutWidth - label->width(); } if (m_alignment & Qt::AlignVCenter) { y += (layoutHeight - label->height()) / 2; } else if (m_alignment & Qt::AlignBottom) { y += layoutHeight - label->height(); } if (m_constrainToBounds) { x = std::max(x, 0.0); x = x + label->width() > width() ? width() - label->width() : x; y = std::max(y, 0.0); y = y + label->height() > height() ? height() - label->height() : y; } label->setX(x); label->setY(y); i++; } } diff --git a/src/decorations/AxisLabels.h b/src/decorations/AxisLabels.h index d19ec9b..81ec6f8 100644 --- a/src/decorations/AxisLabels.h +++ b/src/decorations/AxisLabels.h @@ -1,119 +1,105 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef AXISLABELS_H #define AXISLABELS_H #include #include #include class ChartDataSource; class AxisLabels; class AxisLabelsAttached : public QObject { Q_OBJECT Q_PROPERTY(int index READ index NOTIFY indexChanged) Q_PROPERTY(QString label READ label NOTIFY labelChanged) public: explicit AxisLabelsAttached(QObject *parent = nullptr); int index() const; void setIndex(int newIndex); Q_SIGNAL void indexChanged(); QString label() const; void setLabel(const QString &newLabel); Q_SIGNAL void labelChanged(); private: int m_index = -1; QString m_label; }; /** * An item that uses a delegate to place axis labels on a chart. */ class AxisLabels : public QQuickItem { Q_OBJECT Q_PROPERTY(AxisLabels::Direction direction READ direction WRITE setDirection NOTIFY directionChanged) Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(ChartDataSource *source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged) Q_PROPERTY(bool constrainToBounds READ constrainToBounds WRITE setConstrainToBounds NOTIFY constrainToBoundsChanged) public: enum class Direction { HorizontalLeftRight, HorizontalRightLeft, VerticalTopBottom, VerticalBottomTop }; Q_ENUM(Direction) explicit AxisLabels(QQuickItem *parent = nullptr); AxisLabels::Direction direction() const; Q_SLOT void setDirection(AxisLabels::Direction newDirection); Q_SIGNAL void directionChanged(); QQmlComponent *delegate() const; Q_SLOT void setDelegate(QQmlComponent *newDelegate); Q_SIGNAL void delegateChanged(); ChartDataSource *source() const; Q_SLOT void setSource(ChartDataSource *newSource); Q_SIGNAL void sourceChanged(); Qt::Alignment alignment() const; Q_SLOT void setAlignment(Qt::Alignment newAlignment); Q_SIGNAL void alignmentChanged(); bool constrainToBounds() const; Q_SLOT void setConstrainToBounds(bool newConstrainToBounds); Q_SIGNAL void constrainToBoundsChanged(); static AxisLabelsAttached *qmlAttachedProperties(QObject *object) { return new AxisLabelsAttached(object); } protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; private: void scheduleLayout(); bool isHorizontal(); void updateLabels(); void layout(); Direction m_direction = Direction::HorizontalLeftRight; QQmlComponent *m_delegate = nullptr; ChartDataSource *m_source = nullptr; Qt::Alignment m_alignment = Qt::AlignHCenter | Qt::AlignVCenter; bool m_constrainToBounds = true; QVector m_labels; bool m_layoutScheduled = false; }; QML_DECLARE_TYPEINFO(AxisLabels, QML_HAS_ATTACHED_PROPERTIES) #endif // AXISLABELS_H diff --git a/src/decorations/GridLines.cpp b/src/decorations/GridLines.cpp index 8c5e703..555281e 100644 --- a/src/decorations/GridLines.cpp +++ b/src/decorations/GridLines.cpp @@ -1,221 +1,207 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "GridLines.h" #include "XYChart.h" #include "scenegraph/LineGridNode.h" LinePropertiesGroup::LinePropertiesGroup(GridLines *parent) : QObject(parent) { m_parent = parent; } bool LinePropertiesGroup::visible() const { return m_visible; } void LinePropertiesGroup::setVisible(bool newVisible) { if (newVisible == m_visible) { return; } m_visible = newVisible; Q_EMIT propertiesChanged(); } QColor LinePropertiesGroup::color() const { return m_color; } void LinePropertiesGroup::setColor(const QColor &newColor) { if (newColor == m_color) { return; } m_color = newColor; Q_EMIT propertiesChanged(); } float LinePropertiesGroup::lineWidth() const { return m_lineWidth; } void LinePropertiesGroup::setLineWidth(float newLineWidth) { if (newLineWidth == m_lineWidth) { return; } m_lineWidth = newLineWidth; Q_EMIT propertiesChanged(); } int LinePropertiesGroup::frequency() const { return m_frequency; } void LinePropertiesGroup::setFrequency(int newFrequency) { if (newFrequency == m_frequency) { return; } m_frequency = newFrequency; Q_EMIT propertiesChanged(); } int LinePropertiesGroup::count() const { return m_count; } void LinePropertiesGroup::setCount(int newCount) { if (newCount == m_count) { return; } m_count = newCount; Q_EMIT propertiesChanged(); } GridLines::GridLines(QQuickItem *parent) : QQuickItem(parent) { setFlag(QQuickItem::ItemHasContents); m_major = std::make_unique(this); connect(m_major.get(), &LinePropertiesGroup::propertiesChanged, this, &GridLines::update); m_minor = std::make_unique(this); connect(m_minor.get(), &LinePropertiesGroup::propertiesChanged, this, &GridLines::update); } GridLines::Direction GridLines::direction() const { return m_direction; } void GridLines::setDirection(GridLines::Direction newDirection) { if (newDirection == m_direction) { return; } m_direction = newDirection; update(); Q_EMIT directionChanged(); } XYChart *GridLines::chart() const { return m_chart; } void GridLines::setChart(XYChart *newChart) { if (newChart == m_chart) { return; } if (m_chart) { disconnect(m_chart, &XYChart::computedRangeChanged, this, &GridLines::update); } m_chart = newChart; if (m_chart) { connect(m_chart, &XYChart::computedRangeChanged, this, &GridLines::update); } update(); Q_EMIT chartChanged(); } float GridLines::spacing() const { return m_spacing; } void GridLines::setSpacing(float newSpacing) { if (newSpacing == m_spacing || m_chart != nullptr) { return; } m_spacing = newSpacing; update(); Q_EMIT spacingChanged(); } LinePropertiesGroup *GridLines::majorGroup() const { return m_major.get(); } LinePropertiesGroup *GridLines::minorGroup() const { return m_minor.get(); } QSGNode *GridLines::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *) { if (!node) { node = new QSGNode{}; node->appendChildNode(new LineGridNode{}); node->appendChildNode(new LineGridNode{}); } if (m_chart) { if (m_direction == Direction::Horizontal) { m_spacing = width() / (m_chart->computedRange().distanceX - 1); } else { m_spacing = height() / (m_chart->computedRange().distanceY); } } updateLines(static_cast(node->childAtIndex(0)), m_minor.get()); updateLines(static_cast(node->childAtIndex(1)), m_major.get()); return node; } void GridLines::updateLines(LineGridNode *node, LinePropertiesGroup *properties) { node->setVisible(properties->visible()); node->setRect(boundingRect()); node->setVertical(m_direction == Direction::Vertical); node->setColor(properties->color()); node->setLineWidth(properties->lineWidth()); if (properties->count() > 0) { node->setSpacing(m_direction == Direction::Horizontal ? width() / (properties->count() + 1) : height() / (properties->count() + 1)); } else { node->setSpacing(m_spacing * properties->frequency()); } node->update(); } diff --git a/src/decorations/GridLines.h b/src/decorations/GridLines.h index cefe94e..e2fa85d 100644 --- a/src/decorations/GridLines.h +++ b/src/decorations/GridLines.h @@ -1,119 +1,105 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef GRIDLINES_H #define GRIDLINES_H #include #include class GridLines; class LineGridNode; class XYChart; class LinePropertiesGroup : public QObject { Q_OBJECT Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY propertiesChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY propertiesChanged) Q_PROPERTY(float lineWidth READ lineWidth WRITE setLineWidth NOTIFY propertiesChanged) Q_PROPERTY(int frequency READ frequency WRITE setFrequency NOTIFY propertiesChanged) Q_PROPERTY(int count READ count WRITE setCount NOTIFY propertiesChanged) public: explicit LinePropertiesGroup(GridLines *parent); bool visible() const; void setVisible(bool newVisible); QColor color() const; void setColor(const QColor &newColor); float lineWidth() const; void setLineWidth(float newLineWidth); int frequency() const; void setFrequency(int newFrequency); int count() const; void setCount(int newCount); Q_SIGNAL void propertiesChanged(); private: GridLines *m_parent = nullptr; bool m_visible = true; QColor m_color = Qt::black; float m_lineWidth = 1.0; int m_frequency = 2; int m_count = -1; }; /** * An item that renders a set of lines to make a grid for a chart. */ class GridLines : public QQuickItem { Q_OBJECT Q_PROPERTY(GridLines::Direction direction READ direction WRITE setDirection NOTIFY directionChanged) Q_PROPERTY(XYChart *chart READ chart WRITE setChart NOTIFY chartChanged) Q_PROPERTY(float spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) Q_PROPERTY(LinePropertiesGroup *major READ majorGroup CONSTANT) Q_PROPERTY(LinePropertiesGroup *minor READ minorGroup CONSTANT) public: enum class Direction { Horizontal, Vertical }; Q_ENUM(Direction) /** * Default constructor */ explicit GridLines(QQuickItem *parent = nullptr); Direction direction() const; void setDirection(GridLines::Direction newDirection); Q_SIGNAL void directionChanged(); XYChart *chart() const; void setChart(XYChart *newChart); Q_SIGNAL void chartChanged(); float spacing() const; void setSpacing(float newSpacing); Q_SIGNAL void spacingChanged(); LinePropertiesGroup *majorGroup() const; LinePropertiesGroup *minorGroup() const; private: QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *) override; void updateLines(LineGridNode *node, LinePropertiesGroup *properties); GridLines::Direction m_direction = Direction::Horizontal; XYChart *m_chart = nullptr; float m_spacing = 10.0; std::unique_ptr m_major; std::unique_ptr m_minor; }; #endif // GRIDLINES_H diff --git a/src/decorations/LegendModel.cpp b/src/decorations/LegendModel.cpp index 3e885f4..c8b5d77 100644 --- a/src/decorations/LegendModel.cpp +++ b/src/decorations/LegendModel.cpp @@ -1,269 +1,255 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "LegendModel.h" #include "Chart.h" #include "datasource/ChartDataSource.h" LegendModel::LegendModel(QObject *parent) : QAbstractListModel(parent) { } QHash LegendModel::roleNames() const { static QHash names = { {NameRole, "name"}, {ColorRole, "color"}, {ValueRole, "value"}, }; return names; } int LegendModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_items.size(); } QVariant LegendModel::data(const QModelIndex &index, int role) const { if (!checkIndex(index, CheckIndexOption::ParentIsInvalid | CheckIndexOption::IndexIsValid)) return QVariant{}; switch (role) { case NameRole: return m_items.at(index.row()).name; case ColorRole: return m_items.at(index.row()).color; case ValueRole: return m_items.at(index.row()).value; } return QVariant{}; } Chart *LegendModel::chart() const { return m_chart; } void LegendModel::setChart(Chart *newChart) { if (newChart == m_chart) { return; } if (m_chart) { for (const auto &connection : qAsConst(m_connections)) { disconnect(connection); } m_connections.clear(); } m_chart = newChart; queueUpdate(); Q_EMIT chartChanged(); } int LegendModel::sourceIndex() const { return m_sourceIndex; } void LegendModel::setSourceIndex(int index) { if (index == m_sourceIndex) { return; } m_sourceIndex = index; queueUpdate(); Q_EMIT sourceIndexChanged(); } void LegendModel::queueUpdate() { if (!m_updateQueued) { m_updateQueued = true; QMetaObject::invokeMethod(this, &LegendModel::update, Qt::QueuedConnection); } } void LegendModel::queueDataChange() { if (!m_dataChangeQueued) { m_dataChangeQueued = true; QMetaObject::invokeMethod(this, &LegendModel::updateData, Qt::QueuedConnection); } } void LegendModel::update() { m_updateQueued = false; if (!m_chart) return; beginResetModel(); m_items.clear(); ChartDataSource *colorSource = m_chart->colorSource(); ChartDataSource *nameSource = m_chart->nameSource(); m_connections.push_back(connect(m_chart, &Chart::colorSourceChanged, this, &LegendModel::queueUpdate, Qt::UniqueConnection)); m_connections.push_back(connect(m_chart, &Chart::nameSourceChanged, this, &LegendModel::queueUpdate, Qt::UniqueConnection)); auto sources = m_chart->valueSources(); int itemCount = countItems(); std::transform(sources.cbegin(), sources.cend(), std::back_inserter(m_connections), [this](ChartDataSource *source) { return connect(source, &ChartDataSource::dataChanged, this, &LegendModel::queueDataChange, Qt::UniqueConnection); }); m_connections.push_back(connect(m_chart, &Chart::valueSourcesChanged, this, &LegendModel::queueUpdate, Qt::UniqueConnection)); if ((!colorSource && !nameSource) || itemCount <= 0) { endResetModel(); return; } if (colorSource) { m_connections.push_back(connect(colorSource, &ChartDataSource::dataChanged, this, &LegendModel::queueDataChange, Qt::UniqueConnection)); } if (nameSource) { m_connections.push_back(connect(nameSource, &ChartDataSource::dataChanged, this, &LegendModel::queueDataChange, Qt::UniqueConnection)); } for (int i = 0; i < itemCount; ++i) { LegendItem item; item.name = nameSource ? nameSource->item(i).toString() : QString(); item.color = colorSource ? colorSource->item(i).value() : QColor(); item.value = getValueForItem(i); m_items.push_back(item); } endResetModel(); } void LegendModel::updateData() { ChartDataSource *colorSource = m_chart->colorSource(); ChartDataSource *nameSource = m_chart->nameSource(); auto itemCount = countItems(); m_dataChangeQueued = false; if (itemCount != int(m_items.size())) { // Number of items changed, so trigger a full update queueUpdate(); return; } QVector> changedRows(itemCount); std::for_each(m_items.begin(), m_items.end(), [&, i = 0](LegendItem &item) mutable { auto name = nameSource ? nameSource->item(i).toString() : QString{}; if (item.name != name) { item.name = name; changedRows[i] << NameRole; } auto color = colorSource ? colorSource->item(i).toString() : QColor{}; if (item.color != color) { item.color = color; changedRows[i] << ColorRole; } auto value = getValueForItem(i); if (item.value != value) { item.value = value; changedRows[i] << ValueRole; } i++; }); for(auto i = 0; i < changedRows.size(); ++i) { auto changedRoles = changedRows.at(i); if (!changedRoles.isEmpty()) { Q_EMIT dataChanged(index(i, 0), index(i, 0), changedRoles); } } } int LegendModel::countItems() { auto sources = m_chart->valueSources(); int itemCount = 0; switch (m_chart->indexingMode()) { case Chart::IndexSourceValues: if (sources.count() > 0) { itemCount = sources.at(0)->itemCount(); } break; case Chart::IndexEachSource: itemCount = sources.count(); break; case Chart::IndexAllValues: itemCount = std::accumulate(sources.cbegin(), sources.cend(), 0, [](int current, ChartDataSource *source) -> int { return current + source->itemCount(); }); break; } return itemCount; } QVariant LegendModel::getValueForItem(int item) { const auto sources = m_chart->valueSources(); auto value = QVariant{}; switch (m_chart->indexingMode()) { case Chart::IndexSourceValues: value = sources.at(0)->item(item); break; case Chart::IndexEachSource: value = sources.at(item)->item(0); break; case Chart::IndexAllValues: for (auto source : sources) { if (source->itemCount() < item) { item -= source->itemCount(); } else { value = source->item(item); break; } } break; } return value; } diff --git a/src/decorations/LegendModel.h b/src/decorations/LegendModel.h index edb7c91..ba138e5 100644 --- a/src/decorations/LegendModel.h +++ b/src/decorations/LegendModel.h @@ -1,85 +1,71 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef LEGENDMODEL_H #define LEGENDMODEL_H #include #include #include class Chart; class ChartDataSource; struct LegendItem { QString name; QColor color; QVariant value; }; /** * A model that extracts information from a chart that can be displayed as a legend. */ class LegendModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(Chart *chart READ chart WRITE setChart NOTIFY chartChanged) Q_PROPERTY(int sourceIndex READ sourceIndex WRITE setSourceIndex NOTIFY sourceIndexChanged) public: enum Roles { NameRole = Qt::UserRole, ColorRole, ValueRole }; enum SourceIndex { UseSourceCount = -2 }; Q_ENUM(SourceIndex) explicit LegendModel(QObject *parent = nullptr); QHash roleNames() const override; int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; Chart *chart() const; void setChart(Chart *newChart); Q_SIGNAL void chartChanged(); int sourceIndex() const; void setSourceIndex(int index); Q_SIGNAL void sourceIndexChanged(); private: void queueUpdate(); void queueDataChange(); void update(); void updateData(); int countItems(); QVariant getValueForItem(int item); Chart *m_chart = nullptr; int m_sourceIndex = UseSourceCount; bool m_updateQueued = false; bool m_dataChangeQueued = false; std::vector m_connections; std::vector m_items; }; #endif // LEGENDMODEL_H diff --git a/src/scenegraph/BarChartNode.cpp b/src/scenegraph/BarChartNode.cpp index 003fad3..91c9a59 100644 --- a/src/scenegraph/BarChartNode.cpp +++ b/src/scenegraph/BarChartNode.cpp @@ -1,115 +1,101 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "BarChartNode.h" #include #include #include bool compareCount(const QVector> &first, const QVector> &second) { return first.count() < second.count(); } BarChartNode::BarChartNode() { m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_ColoredPoint2D(), 0}; m_geometry->setDrawingMode(QSGGeometry::DrawTriangles); setGeometry(m_geometry); setMaterial(new QSGVertexColorMaterial{}); setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); } BarChartNode::~BarChartNode() { } void BarChartNode::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; } void BarChartNode::setValues(const QVector> &values) { m_values = values; } void BarChartNode::setBarWidth(qreal width) { if (qFuzzyCompare(width, m_barWidth)) return; m_barWidth = width; } void BarChartNode::update() { if (!m_rect.isValid() || m_values.isEmpty()) return; auto itemCount = m_values.count(); if (itemCount <= 0) return; int totalVertices = itemCount * 6; if (totalVertices != m_geometry->vertexCount()) { m_geometry->allocate(totalVertices, totalVertices); } auto vertices = m_geometry->vertexDataAsColoredPoint2D(); auto indices = m_geometry->indexDataAsUShort(); auto index = 0; for (const auto &entry : qAsConst(m_values)) { auto value = entry.first; value.setY(std::min(value.y() * m_rect.height(), m_rect.height())); auto color = entry.second; auto rect = QRectF{QPointF{value.x(), m_rect.bottom() - value.y()}, QSizeF{m_barWidth, value.y()}}; bar(vertices, indices, index, rect, color); } m_geometry->markVertexDataDirty(); m_geometry->markIndexDataDirty(); markDirty(QSGNode::DirtyGeometry); } void BarChartNode::bar(QSGGeometry::ColoredPoint2D *vertices, quint16 *indices, int &index, const QRectF &bar, const QColor &color) { indices[index] = index; vertices[index++].set(bar.left(), bar.bottom(), color.red(), color.green(), color.blue(), color.alpha()); indices[index] = index; vertices[index++].set(bar.left(), bar.top(), color.red(), color.green(), color.blue(), color.alpha()); indices[index] = index; vertices[index++].set(bar.right(), bar.top(), color.red(), color.green(), color.blue(), color.alpha()); indices[index] = index; vertices[index++].set(bar.right(), bar.top(), color.red(), color.green(), color.blue(), color.alpha()); indices[index] = index; vertices[index++].set(bar.right(), bar.bottom(), color.red(), color.green(), color.blue(), color.alpha()); indices[index] = index; vertices[index++].set(bar.left(), bar.bottom(), color.red(), color.green(), color.blue(), color.alpha()); } diff --git a/src/scenegraph/BarChartNode.h b/src/scenegraph/BarChartNode.h index 64ddf07..5106fed 100644 --- a/src/scenegraph/BarChartNode.h +++ b/src/scenegraph/BarChartNode.h @@ -1,57 +1,43 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef BARCHARTNODE_H #define BARCHARTNODE_H #include /** * @todo write docs */ class BarChartNode : public QSGGeometryNode { public: /** * Default constructor */ BarChartNode(); /** * Destructor */ ~BarChartNode(); void setRect(const QRectF &rect); void setValues(const QVector> &values); void setBarWidth(qreal width); void update(); private: void bar(QSGGeometry::ColoredPoint2D *vertices, quint16 *indices, int &index, const QRectF &bar, const QColor &color); QRectF m_rect; QVector> m_values; qreal m_barWidth = 0.0; QSGGeometry *m_geometry = nullptr; }; #endif // BARCHARTNODE_H diff --git a/src/scenegraph/LineChartMaterial.cpp b/src/scenegraph/LineChartMaterial.cpp index 31f40c8..fa11e65 100644 --- a/src/scenegraph/LineChartMaterial.cpp +++ b/src/scenegraph/LineChartMaterial.cpp @@ -1,150 +1,136 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "LineChartMaterial.h" LineChartMaterial::LineChartMaterial() { setFlag(QSGMaterial::Blending); } LineChartMaterial::~LineChartMaterial() { } QSGMaterialType *LineChartMaterial::type() const { static QSGMaterialType type; return &type; } QSGMaterialShader *LineChartMaterial::createShader() const { return new LineChartShader(); } QColor LineChartMaterial::lineColor() const { return m_lineColor; } QColor LineChartMaterial::fillColor() const { return m_fillColor; } float LineChartMaterial::lineWidth() const { return m_lineWidth; } QVector LineChartMaterial::points() const { return m_points; } float LineChartMaterial::aspect() const { return m_aspect; } QVector2D LineChartMaterial::bounds() const { return m_bounds; } void LineChartMaterial::setLineColor(const QColor &color) { m_lineColor = color; } void LineChartMaterial::setFillColor(const QColor &color) { m_fillColor = color; } void LineChartMaterial::setLineWidth(float width) { m_lineWidth = width; } void LineChartMaterial::setPoints(const QVector &points) { m_points = points; } void LineChartMaterial::setAspect(float aspect) { m_aspect = aspect; } void LineChartMaterial::setBounds(float min, float max) { m_bounds = QVector2D{min, max}; } LineChartShader::LineChartShader() { setShaders(QStringLiteral("linechart.vert"), QStringLiteral("linechart.frag")); } LineChartShader::~LineChartShader() { } const char *const *LineChartShader::attributeNames() const { static char const *const names[] = {"in_vertex", "in_uv", nullptr}; return names; } void LineChartShader::initialize() { QSGMaterialShader::initialize(); m_matrixLocation = program()->uniformLocation("matrix"); m_opacityLocation = program()->uniformLocation("opacity"); m_lineColorLocation = program()->uniformLocation("lineColor"); m_fillColorLocation = program()->uniformLocation("fillColor"); m_lineWidthLocation = program()->uniformLocation("lineWidth"); m_pointsLocation = program()->uniformLocation("points"); m_pointCountLocation = program()->uniformLocation("pointCount"); m_aspectLocation = program()->uniformLocation("aspect"); m_boundsLocation = program()->uniformLocation("bounds"); } void LineChartShader::updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { if (state.isMatrixDirty()) program()->setUniformValue(m_matrixLocation, state.combinedMatrix()); if (state.isOpacityDirty()) program()->setUniformValue(m_opacityLocation, state.opacity()); if (!oldMaterial || newMaterial->compare(oldMaterial) != 0) { LineChartMaterial *material = static_cast(newMaterial); program()->setUniformValue(m_lineColorLocation, material->lineColor()); program()->setUniformValue(m_fillColorLocation, material->fillColor()); program()->setUniformValue(m_lineWidthLocation, material->lineWidth()); program()->setUniformValue(m_aspectLocation, material->aspect()); program()->setUniformValue(m_pointCountLocation, material->points().size()); program()->setUniformValueArray(m_pointsLocation, material->points().constData(), material->points().size()); program()->setUniformValue(m_boundsLocation, material->bounds()); } } diff --git a/src/scenegraph/LineChartMaterial.h b/src/scenegraph/LineChartMaterial.h index 9f56475..aee2d59 100644 --- a/src/scenegraph/LineChartMaterial.h +++ b/src/scenegraph/LineChartMaterial.h @@ -1,86 +1,72 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef LINECHARTMATERIAL_H #define LINECHARTMATERIAL_H #include #include #include #include "SDFShader.h" class LineChartMaterial : public QSGMaterial { public: LineChartMaterial(); ~LineChartMaterial(); QSGMaterialType *type() const override; QSGMaterialShader *createShader() const override; QColor lineColor() const; QColor fillColor() const; float lineWidth() const; float aspect() const; QVector points() const; QVector2D bounds() const; void setLineColor(const QColor &color); void setFillColor(const QColor &color); void setLineWidth(float width); void setPoints(const QVector &points); void setAspect(float aspect); void setBounds(float min, float max); private: QColor m_lineColor; QColor m_fillColor; float m_lineWidth = 0.0; float m_aspect = 1.0; QVector2D m_bounds; QVector m_points; }; class LineChartShader : public SDFShader { public: LineChartShader(); ~LineChartShader(); char const *const *attributeNames() const override; void initialize() override; void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; private: int m_matrixLocation = 0; int m_opacityLocation = 0; int m_lineColorLocation = 0; int m_fillColorLocation = 0; int m_lineWidthLocation = 0; int m_pointsLocation = 0; int m_pointCountLocation = 0; int m_aspectLocation = 0; int m_boundsLocation = 0; }; #endif // LINECHARTMATERIAL_H diff --git a/src/scenegraph/LineChartNode.cpp b/src/scenegraph/LineChartNode.cpp index 106c8ba..e033050 100644 --- a/src/scenegraph/LineChartNode.cpp +++ b/src/scenegraph/LineChartNode.cpp @@ -1,139 +1,125 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "LineChartNode.h" #include #include #include "LineChartMaterial.h" #include "LineSegmentNode.h" static const int MaxPointsInSegment = 10; qreal calculateNormalizedLineWidth(qreal pixelWidth, const QRectF &rect) { if (qFuzzyIsNull(pixelWidth)) { return 0.0; } qreal min = 0.6 / std::max(rect.width(), rect.height()); return std::max(min, (pixelWidth - 1.0) / (std::min(rect.width(), rect.height()) * 4.0)); } LineChartNode::LineChartNode() { } LineChartNode::~LineChartNode() { } void LineChartNode::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; m_aspect = m_rect.height() / m_rect.width(); updatePoints(); } void LineChartNode::setLineWidth(float width) { if (qFuzzyCompare(width, m_lineWidth)) return; m_lineWidth = width; std::for_each(m_segments.cbegin(), m_segments.cend(), [this](LineSegmentNode *node) { node->setLineWidth(calculateNormalizedLineWidth(m_lineWidth, m_rect)); }); } void LineChartNode::setLineColor(const QColor &color) { if (m_lineColor == color) return; m_lineColor = color; std::for_each(m_segments.cbegin(), m_segments.cend(), [color](LineSegmentNode *node) { node->setLineColor(color); }); } void LineChartNode::setFillColor(const QColor &color) { if (m_fillColor == color) return; m_fillColor = color; std::for_each(m_segments.cbegin(), m_segments.cend(), [color](LineSegmentNode *node) { node->setFillColor(color); }); } void LineChartNode::setValues(const QVector &values) { m_values = values; updatePoints(); } void LineChartNode::updatePoints() { if (m_values.isEmpty()) return; auto segmentCount = qCeil(qreal(m_values.count()) / MaxPointsInSegment); if (segmentCount != m_segments.count()) { removeAllChildNodes(); m_segments.clear(); for (int i = 0; i < segmentCount; ++i) { auto node = new LineSegmentNode{}; m_segments << node; appendChildNode(node); } } auto currentX = m_rect.left(); auto pointStart = 0; auto pointsPerSegment = MaxPointsInSegment; for (auto segment : qAsConst(m_segments)) { auto segmentPoints = m_values.mid(pointStart, pointsPerSegment); pointStart += pointsPerSegment; if (pointStart < m_values.count()) { segmentPoints.append(m_values[pointStart]); } auto segmentWidth = segmentPoints.last().x() - currentX; auto rect = QRectF(currentX, m_rect.top(), segmentWidth, m_rect.height()); segment->setRect(rect); segment->setAspect(segmentWidth / m_rect.width(), m_aspect); segment->setLineWidth(calculateNormalizedLineWidth(m_lineWidth, m_rect)); segment->setLineColor(m_lineColor); segment->setFillColor(m_fillColor); segment->setValues(segmentPoints); segment->setFarLeft(m_values.at(std::max(0, pointStart - pointsPerSegment - 1))); segment->setFarRight(m_values.at(std::min(m_values.count() - 1, pointStart + 1))); segment->updatePoints(); currentX += segmentWidth; } } diff --git a/src/scenegraph/LineChartNode.h b/src/scenegraph/LineChartNode.h index 9321e52..77f558e 100644 --- a/src/scenegraph/LineChartNode.h +++ b/src/scenegraph/LineChartNode.h @@ -1,63 +1,49 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef LINECHARTNODE_H #define LINECHARTNODE_H #include #include class QRectF; class LineChartMaterial; class LineSegmentNode; /** * @todo write docs */ class LineChartNode : public QSGNode { public: LineChartNode(); /** * Destructor */ ~LineChartNode(); void setRect(const QRectF &rect); void setLineWidth(float width); void setLineColor(const QColor &color); void setFillColor(const QColor &color); void setValues(const QVector &values); private: void updatePoints(); QRectF m_rect; float m_lineWidth = 0.0; float m_aspect = 1.0; QColor m_lineColor; QColor m_fillColor; QVector m_values; QVector m_segments; }; #endif // LINECHARTNODE_H diff --git a/src/scenegraph/LineGridNode.cpp b/src/scenegraph/LineGridNode.cpp index be344b9..f5441ea 100644 --- a/src/scenegraph/LineGridNode.cpp +++ b/src/scenegraph/LineGridNode.cpp @@ -1,165 +1,151 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "LineGridNode.h" #include #include LineGridNode::LineGridNode() { m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_Point2D(), 0}; m_geometry->setDrawingMode(QSGGeometry::DrawLines); m_geometry->setLineWidth(m_lineWidth); setGeometry(m_geometry); m_material = new QSGFlatColorMaterial{}; m_material->setColor(QColor(255, 0, 0, 255)); setMaterial(m_material); setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); } LineGridNode::~LineGridNode() { } void LineGridNode::setVisible(bool visible) { if (visible == m_visible) return; m_visible = visible; markDirty(QSGNode::DirtySubtreeBlocked); } void LineGridNode::setVertical(bool vertical) { if (vertical == m_vertical) return; m_vertical = vertical; } void LineGridNode::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; } void LineGridNode::setColor(const QColor &color) { if (color == m_material->color()) return; m_material->setColor(color); markDirty(QSGNode::DirtyMaterial); } void LineGridNode::setSpacing(float spacing) { if (qFuzzyCompare(spacing, m_spacing)) return; m_spacing = spacing; } void LineGridNode::setLineWidth(float lineWidth) { if (qFuzzyCompare(lineWidth, m_lineWidth)) { return; } m_lineWidth = lineWidth; m_geometry->setLineWidth(lineWidth); markDirty(QSGNode::DirtyGeometry); } bool LineGridNode::isSubtreeBlocked() const { return !m_visible; } void LineGridNode::update() { if (!m_rect.isValid()) return; int totalVertices = 0; if (!m_vertical) { totalVertices = std::floor(m_rect.width() / std::ceil(m_spacing)) * 2 + 4; } else { totalVertices = std::floor(m_rect.height() / std::ceil(m_spacing)) * 2 + 4; } if (totalVertices < 4) { return; } if (totalVertices != m_geometry->vertexCount()) { m_geometry->allocate(totalVertices, totalVertices); } auto vertices = m_geometry->vertexDataAsPoint2D(); auto indices = m_geometry->indexDataAsUShort(); if (!vertices || !indices) { return; } int index = 0; if (m_vertical) { line(vertices, indices, index, m_rect.left(), m_rect.top(), m_rect.right(), m_rect.top()); auto y = m_spacing; for (auto i = 0; i < (totalVertices - 4) / 2; ++i) { line(vertices, indices, index, m_rect.left(), y, m_rect.right(), y); y += m_spacing; } line(vertices, indices, index, m_rect.left(), m_rect.bottom(), m_rect.right(), m_rect.bottom()); } else { line(vertices, indices, index, m_rect.left(), m_rect.top(), m_rect.left(), m_rect.bottom()); auto x = m_spacing; for (auto i = 0; i < (totalVertices - 4) / 2; ++i) { line(vertices, indices, index, x, m_rect.top(), x, m_rect.bottom()); x += m_spacing; } line(vertices, indices, index, m_rect.right(), m_rect.top(), m_rect.right(), m_rect.bottom()); } m_geometry->markVertexDataDirty(); m_geometry->markIndexDataDirty(); markDirty(QSGNode::DirtyGeometry); } void LineGridNode::line(QSGGeometry::Point2D *vertices, quint16 *indices, int &index, qreal fromX, qreal fromY, qreal toX, qreal toY) { indices[index] = index; vertices[index++].set(fromX, fromY); indices[index] = index; vertices[index++].set(toX, toY); } diff --git a/src/scenegraph/LineGridNode.h b/src/scenegraph/LineGridNode.h index 01af29c..d3efdba 100644 --- a/src/scenegraph/LineGridNode.h +++ b/src/scenegraph/LineGridNode.h @@ -1,63 +1,49 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef LINEGRIDNODE_H #define LINEGRIDNODE_H #include #include class QSGFlatColorMaterial; /** * @todo write docs */ class LineGridNode : public QSGGeometryNode { public: LineGridNode(); ~LineGridNode(); void setVisible(bool visible); void setVertical(bool vertical); void setRect(const QRectF &rect); void setColor(const QColor &color); void setSpacing(float spacing); void setLineWidth(float lineWidth); bool isSubtreeBlocked() const override; void update(); private: void line(QSGGeometry::Point2D *vertices, quint16 *indices, int &index, qreal fromX, qreal fromY, qreal toX, qreal toY); QSGGeometry *m_geometry = nullptr; QSGFlatColorMaterial *m_material = nullptr; bool m_visible = true; bool m_vertical = false; QRectF m_rect; float m_spacing = 1.0; float m_lineWidth = 1.0; }; #endif // LINEGRIDNODE_H diff --git a/src/scenegraph/LineSegmentNode.cpp b/src/scenegraph/LineSegmentNode.cpp index 5215550..9204b42 100644 --- a/src/scenegraph/LineSegmentNode.cpp +++ b/src/scenegraph/LineSegmentNode.cpp @@ -1,164 +1,150 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "LineSegmentNode.h" #include #include #include "LineChartMaterial.h" LineSegmentNode::LineSegmentNode() : LineSegmentNode(QRectF{}) { } LineSegmentNode::LineSegmentNode(const QRectF &rect) { m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_TexturedPoint2D(), 4}; QSGGeometry::updateTexturedRectGeometry(m_geometry, rect, QRectF{0, 0, 1, 1}); setGeometry(m_geometry); m_material = new LineChartMaterial{}; setMaterial(m_material); setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); } LineSegmentNode::~LineSegmentNode() { } void LineSegmentNode::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; QSGGeometry::updateTexturedRectGeometry(m_geometry, m_rect, QRectF{0.0, 0, m_xAspect, 1}); markDirty(QSGNode::DirtyGeometry); updatePoints(); } void LineSegmentNode::setAspect(float xAspect, float yAspect) { if (qFuzzyCompare(xAspect, m_xAspect) && qFuzzyCompare(yAspect, m_yAspect)) return; m_yAspect = yAspect; m_material->setAspect(m_yAspect); markDirty(QSGNode::DirtyMaterial); m_xAspect = xAspect; QSGGeometry::updateTexturedRectGeometry(m_geometry, m_rect, QRectF{0.0, 0, m_xAspect, 1}); markDirty(QSGNode::DirtyGeometry); } void LineSegmentNode::setLineWidth(float width) { if (qFuzzyCompare(width, m_lineWidth)) return; m_lineWidth = width; m_material->setLineWidth(m_lineWidth); markDirty(QSGNode::DirtyMaterial); } void LineSegmentNode::setLineColor(const QColor &color) { if (m_material->lineColor() == color) return; m_material->setLineColor(color); markDirty(QSGNode::DirtyMaterial); } void LineSegmentNode::setFillColor(const QColor &color) { if (m_material->fillColor() == color) return; m_material->setFillColor(color); markDirty(QSGNode::DirtyMaterial); } void LineSegmentNode::setValues(const QVector &values) { m_values = values; } void LineSegmentNode::setFarLeft(const QVector2D &value) { m_farLeft = value; } void LineSegmentNode::setFarRight(const QVector2D &value) { m_farRight = value; } void LineSegmentNode::updatePoints() { if (m_values.isEmpty()) return; QVector points; points.reserve(m_values.size() + 8); points << QVector2D{0.0, -0.5}; points << QVector2D{-0.5, -0.5}; auto min = std::numeric_limits::max(); auto max = std::numeric_limits::min(); if (!m_farLeft.isNull()) { points << QVector2D(-0.5, m_farLeft.y() * m_yAspect); points << QVector2D(((m_farLeft.x() - m_rect.left()) / m_rect.width()) * m_xAspect, m_farLeft.y() * m_yAspect); min = std::min(m_farLeft.y() * m_yAspect, min); max = std::max(m_farLeft.y() * m_yAspect, max); } else { points << QVector2D(-0.5, m_values[0].y() * m_yAspect); } for (auto value : qAsConst(m_values)) { auto x = ((value.x() - m_rect.left()) / m_rect.width()) * m_xAspect; points << QVector2D(x, value.y() * m_yAspect); min = std::min(value.y() * m_yAspect, min); max = std::max(value.y() * m_yAspect, max); } if (!m_farRight.isNull()) { points << QVector2D(((m_farRight.x() - m_rect.left()) / m_rect.width()) * m_xAspect, m_farRight.y() * m_yAspect); points << QVector2D(1.5, m_farRight.y() * m_yAspect); min = std::min(m_farRight.y() * m_yAspect, min); max = std::max(m_farRight.y() * m_yAspect, max); } else { points << QVector2D(1.5, points.last().y()); } points << QVector2D{1.5, -0.5}; points << QVector2D{0.0, -0.5}; m_material->setPoints(points); m_material->setBounds(min, max); markDirty(QSGNode::DirtyMaterial); } diff --git a/src/scenegraph/LineSegmentNode.h b/src/scenegraph/LineSegmentNode.h index 748494b..5f34102 100644 --- a/src/scenegraph/LineSegmentNode.h +++ b/src/scenegraph/LineSegmentNode.h @@ -1,73 +1,59 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef LINESEGMENTNODE_H #define LINESEGMENTNODE_H #include #include #include class QRectF; class LineChartMaterial; /** * @todo write docs */ class LineSegmentNode : public QSGGeometryNode { public: LineSegmentNode(); /** * Default constructor */ explicit LineSegmentNode(const QRectF &rect); /** * Destructor */ ~LineSegmentNode(); void setRect(const QRectF &rect); void setAspect(float xAspect, float yAspect); void setLineWidth(float width); void setLineColor(const QColor &color); void setFillColor(const QColor &color); void setValues(const QVector &values); void setFarLeft(const QVector2D &value); void setFarRight(const QVector2D &value); void updatePoints(); private: QRectF m_rect; float m_lineWidth = 0.0; float m_xAspect = 1.0; float m_yAspect = 1.0; QVector2D m_farLeft; QVector2D m_farRight; QVector m_values; QSGGeometry *m_geometry = nullptr; LineChartMaterial *m_material = nullptr; }; #endif // LINESEGMENTNODE_H diff --git a/src/scenegraph/PieChartMaterial.cpp b/src/scenegraph/PieChartMaterial.cpp index 89eac9e..f32df5c 100644 --- a/src/scenegraph/PieChartMaterial.cpp +++ b/src/scenegraph/PieChartMaterial.cpp @@ -1,174 +1,160 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "PieChartMaterial.h" PieChartMaterial::PieChartMaterial() { setFlag(QSGMaterial::Blending); } PieChartMaterial::~PieChartMaterial() { } QSGMaterialType *PieChartMaterial::type() const { static QSGMaterialType type; return &type; } QSGMaterialShader *PieChartMaterial::createShader() const { return new PieChartShader(); } QVector2D PieChartMaterial::aspectRatio() const { return m_aspectRatio; } float PieChartMaterial::innerRadius() const { return m_innerRadius; } float PieChartMaterial::outerRadius() const { return m_outerRadius; } QColor PieChartMaterial::backgroundColor() const { return m_backgroundColor; } QVector PieChartMaterial::triangles() const { return m_triangles; } QVector PieChartMaterial::colors() const { return m_colors; } QVector PieChartMaterial::segments() const { return m_segments; } bool PieChartMaterial::smoothEnds() const { return m_smoothEnds; } void PieChartMaterial::setAspectRatio(const QVector2D &aspect) { m_aspectRatio = aspect; } void PieChartMaterial::setInnerRadius(float radius) { m_innerRadius = radius; } void PieChartMaterial::setOuterRadius(float radius) { m_outerRadius = radius; } void PieChartMaterial::setBackgroundColor(const QColor &color) { m_backgroundColor = color; } void PieChartMaterial::setTriangles(const QVector &triangles) { m_triangles = triangles; } void PieChartMaterial::setColors(const QVector &colors) { m_colors = colors; } void PieChartMaterial::setSegments(const QVector &segments) { m_segments = segments; } void PieChartMaterial::setSmoothEnds(bool smooth) { m_smoothEnds = smooth; } PieChartShader::PieChartShader() { setShaders(QStringLiteral("piechart.vert"), QStringLiteral("piechart.frag")); } PieChartShader::~PieChartShader() { } const char *const *PieChartShader::attributeNames() const { static char const *const names[] = {"in_vertex", "in_uv", nullptr}; return names; } void PieChartShader::initialize() { QSGMaterialShader::initialize(); m_matrixLocation = program()->uniformLocation("matrix"); m_opacityLocation = program()->uniformLocation("opacity"); m_innerRadiusLocation = program()->uniformLocation("innerRadius"); m_outerRadiusLocation = program()->uniformLocation("outerRadius"); m_aspectLocation = program()->uniformLocation("aspect"); m_backgroundColorLocation = program()->uniformLocation("backgroundColor"); m_trianglesLocation = program()->uniformLocation("triangles"); m_colorsLocation = program()->uniformLocation("colors"); m_segmentsLocation = program()->uniformLocation("segments"); m_segmentCountLocation = program()->uniformLocation("segmentCount"); m_smoothEndsLocation = program()->uniformLocation("smoothEnds"); } void PieChartShader::updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { if (state.isMatrixDirty()) program()->setUniformValue(m_matrixLocation, state.combinedMatrix()); if (state.isOpacityDirty()) program()->setUniformValue(m_opacityLocation, state.opacity()); if (!oldMaterial || newMaterial->compare(oldMaterial) != 0) { PieChartMaterial *material = static_cast(newMaterial); program()->setUniformValue(m_innerRadiusLocation, material->innerRadius()); program()->setUniformValue(m_outerRadiusLocation, material->outerRadius()); program()->setUniformValue(m_aspectLocation, material->aspectRatio()); program()->setUniformValue(m_backgroundColorLocation, material->backgroundColor()); program()->setUniformValueArray(m_trianglesLocation, material->triangles().constData(), material->triangles().size()); program()->setUniformValueArray(m_colorsLocation, material->colors().constData(), material->colors().size()); program()->setUniformValueArray(m_segmentsLocation, material->segments().constData(), material->segments().size()); program()->setUniformValue(m_segmentCountLocation, material->segments().size()); program()->setUniformValue(m_smoothEndsLocation, material->smoothEnds()); } } diff --git a/src/scenegraph/PieChartMaterial.h b/src/scenegraph/PieChartMaterial.h index f121193..1c88a87 100644 --- a/src/scenegraph/PieChartMaterial.h +++ b/src/scenegraph/PieChartMaterial.h @@ -1,97 +1,83 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef PIECHARTMATERIAL_H #define PIECHARTMATERIAL_H #include #include #include #include "SDFShader.h" class PieChartMaterial : public QSGMaterial { public: PieChartMaterial(); ~PieChartMaterial(); QSGMaterialType *type() const override; QSGMaterialShader *createShader() const override; QVector2D aspectRatio() const; float innerRadius() const; float outerRadius() const; QColor backgroundColor() const; bool smoothEnds() const; QVector triangles() const; QVector colors() const; QVector segments() const; void setAspectRatio(const QVector2D &aspect); void setInnerRadius(float radius); void setOuterRadius(float radius); void setBackgroundColor(const QColor &color); void setSmoothEnds(bool smooth); void setTriangles(const QVector &triangles); void setColors(const QVector &colors); void setSegments(const QVector &segments); private: QVector2D m_aspectRatio; float m_innerRadius = 0.0f; float m_outerRadius = 0.0f; QColor m_backgroundColor; bool m_smoothEnds = false; QVector m_triangles; QVector m_colors; QVector m_segments; }; class PieChartShader : public SDFShader { public: PieChartShader(); ~PieChartShader(); char const *const *attributeNames() const override; void initialize() override; void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; private: int m_matrixLocation = 0; int m_opacityLocation = 0; int m_innerRadiusLocation = 0; int m_outerRadiusLocation = 0; int m_aspectLocation = 0; int m_backgroundColorLocation = 0; int m_trianglesLocation = 0; int m_colorsLocation = 0; int m_segmentsLocation = 0; int m_segmentCountLocation = 0; int m_smoothEndsLocation = 0; }; #endif // PIECHARTMATERIAL_H diff --git a/src/scenegraph/PieChartNode.cpp b/src/scenegraph/PieChartNode.cpp index 221998f..79245eb 100644 --- a/src/scenegraph/PieChartNode.cpp +++ b/src/scenegraph/PieChartNode.cpp @@ -1,271 +1,257 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "PieChartNode.h" #include #include #include #include #include "PieChartMaterial.h" static const qreal pi = std::acos(-1.0); static const qreal sectionSize = pi * 0.5; inline QVector4D colorToVec4(const QColor &color) { return QVector4D{float(color.redF()), float(color.greenF()), float(color.blueF()), float(color.alphaF())}; } inline qreal degToRad(qreal deg) { return (deg / 180.0) * pi; } inline QVector2D rotated(const QVector2D vector, qreal angle) { auto newX = vector.x() * std::cos(angle) - vector.y() * std::sin(angle); auto newY = vector.x() * std::sin(angle) + vector.y() * std::cos(angle); return QVector2D(newX, newY); } PieChartNode::PieChartNode() : PieChartNode(QRectF{}) { } PieChartNode::PieChartNode(const QRectF &rect) { m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_TexturedPoint2D(), 4}; QSGGeometry::updateTexturedRectGeometry(m_geometry, rect, QRectF{0, 0, 1, 1}); setGeometry(m_geometry); m_material = new PieChartMaterial{}; setMaterial(m_material); setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); } PieChartNode::~PieChartNode() { } void PieChartNode::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; QSGGeometry::updateTexturedRectGeometry(m_geometry, m_rect, QRectF{0, 0, 1, 1}); markDirty(QSGNode::DirtyGeometry); auto minDimension = qMin(m_rect.width(), m_rect.height()); QVector2D aspect{1.0, 1.0}; aspect.setX(rect.width() / minDimension); aspect.setY(rect.height() / minDimension); m_material->setAspectRatio(aspect); m_material->setInnerRadius(m_innerRadius / minDimension); m_material->setOuterRadius(m_outerRadius / minDimension); markDirty(QSGNode::DirtyMaterial); } void PieChartNode::setInnerRadius(qreal radius) { if (qFuzzyCompare(radius, m_innerRadius)) { return; } m_innerRadius = radius; auto minDimension = qMin(m_rect.width(), m_rect.height()); m_material->setInnerRadius(m_innerRadius / minDimension); markDirty(QSGNode::DirtyMaterial); } void PieChartNode::setOuterRadius(qreal radius) { if (qFuzzyCompare(radius, m_outerRadius)) { return; } m_outerRadius = radius; auto minDimension = qMin(m_rect.width(), m_rect.height()); m_material->setOuterRadius(m_outerRadius / minDimension); markDirty(QSGNode::DirtyMaterial); } void PieChartNode::setColors(const QVector &colors) { m_colors = colors; updateTriangles(); } void PieChartNode::setSections(const QVector §ions) { m_sections = sections; updateTriangles(); } void PieChartNode::setBackgroundColor(const QColor &color) { if (color == m_backgroundColor) return; m_backgroundColor = color; if (qFuzzyCompare(m_toAngle, 360.0)) { m_material->setBackgroundColor(color); markDirty(QSGNode::DirtyMaterial); } else { updateTriangles(); } } void PieChartNode::setFromAngle(qreal angle) { if (qFuzzyCompare(angle, m_fromAngle)) { return; } m_fromAngle = angle; updateTriangles(); } void PieChartNode::setToAngle(qreal angle) { if (qFuzzyCompare(angle, m_fromAngle)) { return; } m_toAngle = angle; if (!qFuzzyCompare(m_toAngle, 360.0)) { m_material->setBackgroundColor(Qt::transparent); } else { m_material->setBackgroundColor(m_backgroundColor); } updateTriangles(); } void PieChartNode::setSmoothEnds(bool smooth) { if (smooth == m_smoothEnds) { return; } m_smoothEnds = smooth; m_material->setSmoothEnds(smooth); markDirty(QSGNode::DirtyMaterial); } void PieChartNode::updateTriangles() { if (m_sections.isEmpty() || m_sections.size() != m_colors.size()) return; QVector trianglePoints; QVector triangleColors; QVector segments; qreal totalAngle = degToRad(m_toAngle); qreal overlap = m_smoothEnds ? 0.2 : 0.05; auto sections = m_sections; auto colors = m_colors; QVector2D point = rotated(QVector2D{0.0, -2.0}, degToRad(m_fromAngle)); auto index = 0; auto current = sections.at(0) * totalAngle; auto sectionCount = 0; auto total = 0.0; while (index < sections.size()) { auto currentSection = std::max(current - sectionSize, 0.0); auto angle = (currentSection > 0.0) ? sectionSize : current; auto overlapAngle = angle + (m_smoothEnds ? overlap : std::min(currentSection, overlap)); overlapAngle = index == sections.size() - 1 && currentSection <= 0.0 ? angle : overlapAngle; trianglePoints << point; trianglePoints << rotated(point, overlapAngle); point = rotated(point, angle); current -= angle; sectionCount++; while (qFuzzyCompare(current, 0.0)) { triangleColors << colorToVec4(colors.at(index)); segments << sectionCount; sectionCount = 0; total += sections.at(index); index++; if (index < sections.size()) { current = sections.at(index) * totalAngle; } else { break; } } } if (sections.size() == 1 && qFuzzyCompare(sections.at(0), 0.0)) { trianglePoints.clear(); triangleColors.clear(); segments.clear(); } if (!qFuzzyCompare(totalAngle, 360.0) && total < 1.0) { sectionCount = 0; current = (1.0 - total) * totalAngle; auto overlapAngle = std::min(total * totalAngle, overlap); point = rotated(point, -overlapAngle); current += overlapAngle; while (current > 0.0) { auto currentSection = std::max(current - sectionSize, 0.0); auto angle = (currentSection > 0.0) ? sectionSize : current; trianglePoints.prepend(point); trianglePoints.prepend(rotated(point, angle + std::min(currentSection, overlap))); point = rotated(point, angle); current -= angle; sectionCount++; } triangleColors.prepend(colorToVec4(m_backgroundColor)); segments.prepend(sectionCount); } m_material->setTriangles(trianglePoints); m_material->setColors(triangleColors); m_material->setSegments(segments); markDirty(QSGNode::DirtyMaterial); } diff --git a/src/scenegraph/PieChartNode.h b/src/scenegraph/PieChartNode.h index 4d369e6..93163cc 100644 --- a/src/scenegraph/PieChartNode.h +++ b/src/scenegraph/PieChartNode.h @@ -1,77 +1,63 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef PIECHARTNODE_H #define PIECHARTNODE_H #include #include class QRectF; class PieChartMaterial; /** * @todo write docs */ class PieChartNode : public QSGGeometryNode { public: PieChartNode(); /** * Default constructor */ explicit PieChartNode(const QRectF &rect); /** * Destructor */ ~PieChartNode(); void setRect(const QRectF &rect); void setInnerRadius(qreal radius); void setOuterRadius(qreal radius); void setSections(const QVector §ions); void setColors(const QVector &colors); void setBackgroundColor(const QColor &color); void setFromAngle(qreal angle); void setToAngle(qreal angle); void setSmoothEnds(bool smooth); private: void updateTriangles(); QRectF m_rect; qreal m_innerRadius = 0.0; qreal m_outerRadius = 0.0; QColor m_backgroundColor; qreal m_fromAngle = 0.0; qreal m_toAngle = 360.0; bool m_smoothEnds = false; QVector m_sections; QVector m_colors; QSGGeometry *m_geometry = nullptr; PieChartMaterial *m_material = nullptr; }; #endif // PIECHARTNODE_H diff --git a/src/scenegraph/SDFShader.cpp b/src/scenegraph/SDFShader.cpp index c69059c..4afa75a 100644 --- a/src/scenegraph/SDFShader.cpp +++ b/src/scenegraph/SDFShader.cpp @@ -1,47 +1,33 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "SDFShader.h" #include static const char shaderRoot[] = ":/org.kde.quickcharts/"; SDFShader::SDFShader() { } SDFShader::~SDFShader() { } void SDFShader::setShaders(const QString &vertex, const QString &fragment) { auto header = QOpenGLContext::currentContext()->isOpenGLES() ? QStringLiteral("es_header.glsl") : QStringLiteral("desktop_header.glsl"); setShaderSourceFiles(QOpenGLShader::Vertex, {QString::fromLatin1(shaderRoot) + header, QString::fromLatin1(shaderRoot) + vertex}); setShaderSourceFiles( QOpenGLShader::Fragment, {QString::fromLatin1(shaderRoot) + header, QString::fromLatin1(shaderRoot) + QStringLiteral("sdf.frag"), QString::fromLatin1(shaderRoot) + fragment}); } diff --git a/src/scenegraph/SDFShader.h b/src/scenegraph/SDFShader.h index 4c10531..5ea377d 100644 --- a/src/scenegraph/SDFShader.h +++ b/src/scenegraph/SDFShader.h @@ -1,36 +1,22 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef SDF_SHADER_H #define SDF_SHADER_H #include class SDFShader : public QSGMaterialShader { public: SDFShader(); virtual ~SDFShader(); void setShaders(const QString &vertex, const QString &fragment); }; #endif // SDF_SHADER_H diff --git a/src/shaders/desktop_header.glsl b/src/shaders/desktop_header.glsl index 7ff121e..76c7f4b 100644 --- a/src/shaders/desktop_header.glsl +++ b/src/shaders/desktop_header.glsl @@ -1,41 +1,27 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This file contains common directives needed for the shaders to work. // It is included as the very first bit in the shader. // Important: If a specific GLSL version is needed, it should be set in this // file. // This file is intended for desktop OpenGL version 2.1 or greater. #version 120 #ifndef lowp #define lowp #endif #ifndef mediump #define mediump #endif #ifndef highp #define highp mediump #endif diff --git a/src/shaders/desktop_header_core.glsl b/src/shaders/desktop_header_core.glsl index ef5118a..baa266c 100644 --- a/src/shaders/desktop_header_core.glsl +++ b/src/shaders/desktop_header_core.glsl @@ -1,29 +1,15 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This file contains common directives needed for the shaders to work. // It is included as the very first bit in the shader. // Important: If a specific GLSL version is needed, it should be set in this // file. // This file is intended for desktop OpenGL version 4.5 or greater. #version 450 diff --git a/src/shaders/es_header.glsl b/src/shaders/es_header.glsl index 5a0209c..8075b6b 100644 --- a/src/shaders/es_header.glsl +++ b/src/shaders/es_header.glsl @@ -1,30 +1,16 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This file contains common directives needed for the shaders to work. // It is included as the very first bit in the shader. // Important: If a specific GLSL version is needed, it should be set in this // file. // This file is intended for OpenGLES version 2.0 or greater. #version 100 #extension GL_OES_standard_derivatives : enable diff --git a/src/shaders/linechart.frag b/src/shaders/linechart.frag index e1dfe01..55a85f8 100644 --- a/src/shaders/linechart.frag +++ b/src/shaders/linechart.frag @@ -1,69 +1,55 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This requires "sdf.frag" which is included through SDFShader. uniform lowp float opacity; // inherited opacity of this item uniform lowp vec4 lineColor; uniform lowp vec4 fillColor; uniform lowp float lineWidth; uniform lowp vec2 bounds; uniform lowp vec2 points[SDF_POLYGON_MAX_POINT_COUNT]; uniform int pointCount; varying lowp vec2 uv; void main() { lowp vec2 point = uv; lowp vec4 color = vec4(0.0, 0.0, 0.0, 0.0); // bounds.y contains the line segment's maximum value. If we are a bit above // that, we will never render anything, so just discard the pixel. if (point.y > bounds.y + 0.01) { discard; } // bounds.x contains the line segment's minimum value. If we are a bit below // that, we know we will always be inside the polygon described by points. // So just return a pixel with fillColor. if (point.y < bounds.x - 0.01) { gl_FragColor = fillColor * opacity; return; } #if !defined(GL_ES) || !defined(VALIDATING) // See sdf.frag line 98 lowp float polygon = sdf_polygon(point, points, pointCount); #else lowp float polygon = 0.0; #endif color = sdf_render(polygon, color, fillColor, 0.001); if (lineWidth > 0.0) { color = sdf_render(sdf_annular(sdf_outline(polygon), lineWidth), color, lineColor, 0.0002); } gl_FragColor = color * opacity; } diff --git a/src/shaders/linechart.vert b/src/shaders/linechart.vert index add7d0c..1f5d035 100644 --- a/src/shaders/linechart.vert +++ b/src/shaders/linechart.vert @@ -1,36 +1,22 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ uniform highp mat4 matrix; uniform lowp float lineWidth; uniform lowp float aspect; attribute highp vec4 in_vertex; attribute mediump vec2 in_uv; varying mediump vec2 uv; void main() { uv.x = in_uv.x; uv.y = in_uv.y; uv.y = (1.0 + -1.0 * uv.y) * aspect; gl_Position = matrix * in_vertex; } diff --git a/src/shaders/linechart_core.frag b/src/shaders/linechart_core.frag index 4938997..ad64a3c 100644 --- a/src/shaders/linechart_core.frag +++ b/src/shaders/linechart_core.frag @@ -1,66 +1,52 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This requires "sdf_core.frag" which is included through SDFShader. uniform float opacity; uniform vec4 lineColor; uniform vec4 fillColor; uniform float lineWidth; uniform lowp vec2 bounds; uniform vec2 points[SDF_POLYGON_MAX_POINT_COUNT]; uniform int pointCount; in vec2 uv; out vec4 out_color; void main() { vec2 point = uv; vec4 color = vec4(0.0, 0.0, 0.0, 0.0); // bounds.y contains the line segment's maximum value. If we are a bit above // that, we will never render anything, so just discard the pixel. if (point.y > bounds.y + 0.01) { discard; } // bounds.x contains the line segment's minimum value. If we are a bit below // that, we know we will always be inside the polygon described by points. // So just return a pixel with fillColor. if (point.y < bounds.x - 0.01) { out_color = fillColor * opacity; return; } float polygon = sdf_polygon(point, points, pointCount); color = sdf_render(polygon, color, fillColor, 0.001); if (lineWidth > 0.0) { color = sdf_render(sdf_annular(sdf_outline(polygon), lineWidth), color, lineColor, 0.0002); } out_color = color * opacity; } diff --git a/src/shaders/linechart_core.vert b/src/shaders/linechart_core.vert index b3ed5e8..e2b7817 100644 --- a/src/shaders/linechart_core.vert +++ b/src/shaders/linechart_core.vert @@ -1,36 +1,22 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ uniform mat4 matrix; uniform float lineWidth; uniform float aspect; in vec4 in_vertex; in vec2 in_uv; out vec2 uv; void main() { uv.x = in_uv.x; uv.y = in_uv.y; uv.y = (1.0 + -1.0 * uv.y) * aspect; gl_Position = matrix * in_vertex; } diff --git a/src/shaders/piechart.frag b/src/shaders/piechart.frag index e317709..68073f0 100644 --- a/src/shaders/piechart.frag +++ b/src/shaders/piechart.frag @@ -1,83 +1,69 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This requires "sdf.frag" which is included through SDFShader. // The maximum number of segments we can support for a single pie. // This is based on OpenGL's MAX_FRAGMENT_UNIFORM_COMPONENTS. // MAX_FRAGMENT_UNIFORM_COMPONENTS is required to be at least 1024. // Assuming a segment of size 1, each segment needs // 2 (size of a vec2) * 2 (number of points) + 4 (size of vec4) + 1 (segment size) // components. We also need to leave some room for the other uniforms. #define MAX_SEGMENTS 100 uniform lowp float opacity; uniform lowp float innerRadius; uniform lowp float outerRadius; uniform lowp vec4 backgroundColor; uniform bool smoothEnds; uniform lowp vec2 triangles[MAX_SEGMENTS * 2]; uniform lowp vec4 colors[MAX_SEGMENTS]; uniform int segments[MAX_SEGMENTS]; uniform int segmentCount; varying lowp vec2 uv; const lowp vec2 origin = vec2(0.0, 0.0); const lowp float lineSmooth = 0.001; void main() { lowp vec2 point = uv * (1.0 + lineSmooth * 2.0); lowp float thickness = (outerRadius - innerRadius) / 2.0; lowp float donut = sdf_annular(sdf_circle(point, innerRadius + thickness), thickness); lowp vec4 color = vec4(0.0); lowp float totalSegments = sdf_null; int index = 0; for (int i = 0; i < segmentCount && i < MAX_SEGMENTS; ++i) { lowp float segment = sdf_null; for(int j = 0; j < segments[i] && j < MAX_SEGMENTS; j++) { segment = sdf_union(segment, sdf_round(sdf_triangle(point, origin, triangles[index++], triangles[index++]), lineSmooth)); } totalSegments = sdf_union(totalSegments, segment); segment = smoothEnds ? sdf_intersect_smooth(donut, segment, thickness) : sdf_intersect(donut, segment); color = sdf_render(segment, color, colors[i], lineSmooth); } // Finally, render an end segment with the background color. if (smoothEnds) { lowp vec4 background = sdf_render(donut, vec4(0.0), backgroundColor, lineSmooth); color = mix(background, color, color.a); } else { lowp float segment = sdf_subtract(sdf_round(donut, lineSmooth), totalSegments); color = sdf_render(segment, color, backgroundColor, lineSmooth); } gl_FragColor = color * opacity; } diff --git a/src/shaders/piechart.vert b/src/shaders/piechart.vert index 6caee24..5bda423 100644 --- a/src/shaders/piechart.vert +++ b/src/shaders/piechart.vert @@ -1,33 +1,19 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ uniform highp mat4 matrix; uniform lowp vec2 aspect; attribute highp vec4 in_vertex; attribute mediump vec2 in_uv; varying mediump vec2 uv; void main() { uv = (-1.0 + 2.0 * in_uv) * aspect; gl_Position = matrix * in_vertex; } diff --git a/src/shaders/piechart_core.frag b/src/shaders/piechart_core.frag index 8989204..ec83c1e 100644 --- a/src/shaders/piechart_core.frag +++ b/src/shaders/piechart_core.frag @@ -1,74 +1,60 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ // This requires "sdf_core.frag" which is included through SDFShader. // The maximum number of segments we can support for a single pie. // This is based on OpenGL's MAX_FRAGMENT_UNIFORM_COMPONENTS. // MAX_FRAGMENT_UNIFORM_COMPONENTS is required to be at least 1024. // Assuming a segment of size 1, each segment needs // 2 (size of a vec2) * 2 (number of points) + 4 (size of vec4) + 1 (segment size) // components. We also need to leave some room for the other uniforms. #define MAX_SEGMENTS 100 uniform float opacity; uniform float innerRadius; uniform float outerRadius; uniform vec4 backgroundColor; uniform vec2 triangles[MAX_SEGMENTS * 2]; uniform vec4 colors[MAX_SEGMENTS]; uniform int segments[MAX_SEGMENTS]; uniform int segmentCount; in vec2 uv; out vec4 out_color; const vec2 origin = vec2(0.0, 0.0); const float lineSmooth = 0.001; void main() { vec2 point = uv * (1.0 + lineSmooth * 2.0); float thickness = (outerRadius - innerRadius) / 2.0; float donut = sdf_annular(sdf_circle(point, innerRadius + thickness), thickness); vec4 color = vec4(0.0); float totalSegments = sdf_null; int index = 0; for (int i = 0; i < segmentCount && i < MAX_SEGMENTS; ++i) { float segment = sdf_null; for(int j = 0; j < segments[i] && j < MAX_SEGMENTS; j++) { segment = sdf_union(segment, sdf_round(sdf_triangle(point, origin, triangles[index++], triangles[index++]), lineSmooth)); } totalSegments = sdf_union(totalSegments, segment); color = sdf_render(sdf_intersect(donut, segment), color, colors[i], lineSmooth); } // Finally, render an end segment with the background color. float segment = sdf_subtract(sdf_round(donut, lineSmooth), totalSegments); color = sdf_render(segment, color, backgroundColor, lineSmooth); out_color = color * opacity; } diff --git a/src/shaders/piechart_core.vert b/src/shaders/piechart_core.vert index c1e9271..ba94d03 100644 --- a/src/shaders/piechart_core.vert +++ b/src/shaders/piechart_core.vert @@ -1,33 +1,19 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ uniform mat4 matrix; uniform vec2 aspect; in vec4 in_vertex; in vec2 in_uv; out vec2 uv; void main() { uv = (-1.0 + 2.0 * in_uv) * aspect; gl_Position = matrix * in_vertex; } diff --git a/src/shaders/sdf.frag b/src/shaders/sdf.frag index 7c23324..e177f66 100644 --- a/src/shaders/sdf.frag +++ b/src/shaders/sdf.frag @@ -1,244 +1,228 @@ -// Copyright (c) 2019 Arjen Hiemstra +// SPDX-FileCopyrightText: 2019 Arjen Hiemstra +// SPDX-FileCopyrightText: 2017 Inigo Quilez +// +// SPDX-License-Identifier: MIT // // This file is based on // https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm -// -// The MIT License -// Copyright © 2017 Inigo Quilez -// 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. //if not GLES // include "desktop_header.glsl" //else // include "es_header.glsl" // A maximum point count to be used for sdf_polygon input arrays. // Unfortunately even function inputs require a fixed size at declaration time // for arrays, unless we were to use OpenGL 4.5. // Since the polygon is most likely to be defined in a uniform, this should be // at least less than MAX_FRAGMENT_UNIFORM_COMPONENTS / 2 (since we need vec2). #define SDF_POLYGON_MAX_POINT_COUNT 400 /********************************* Shapes *********************************/ // Distance field for a circle. // // \param point A point on the distance field. // \param radius The radius of the circle. // // \return The signed distance from point to the circle. If negative, point is // inside the circle. lowp float sdf_circle(in lowp vec2 point, in lowp float radius) { return length(point) - radius; } // Distance field for a triangle. // // \param point A point on the distance field. // \param p0 The first vertex of the triangle. // \param p0 The second vertex of the triangle. // \param p0 The third vertex of the triangle. // // \note The ordering of the three vertices does not matter. // // \return The signed distance from point to triangle. If negative, point is // inside the triangle. lowp float sdf_triangle(in lowp vec2 point, in lowp vec2 p0, in lowp vec2 p1, in lowp vec2 p2) { lowp vec2 e0 = p1 - p0; lowp vec2 e1 = p2 - p1; lowp vec2 e2 = p0 - p2; lowp vec2 v0 = point - p0; lowp vec2 v1 = point - p1; lowp vec2 v2 = point - p2; lowp vec2 pq0 = v0 - e0 * clamp( dot(v0, e0) / dot(e0, e0), 0.0, 1.0 ); lowp vec2 pq1 = v1 - e1 * clamp( dot(v1, e1) / dot(e1, e1), 0.0, 1.0 ); lowp vec2 pq2 = v2 - e2 * clamp( dot(v2, e2) / dot(e2, e2), 0.0, 1.0 ); lowp float s = sign( e0.x*e2.y - e0.y*e2.x ); lowp vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)), vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))), vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x))); return -sqrt(d.x)*sign(d.y); } // Distance field for an arbitrary polygon. // // \param point A point on the distance field. // \param vertices An array of points that make up the polygon. // \param count The amount of points to use for the polygon. // // \note points should be an array of vec2 of size SDF_POLYGON_MAX_POINT_COUNT. // Use count to indicate how many items of that array should be used. // // \return The signed distance from point to triangle. If negative, point is // inside the triangle. // Strictly speaking, GLES 2.0 doesn't support function array arguments (apparently), so our validation fails here. // But at least Mesa GLES 2.0 accepts it, so skip validation here instead. #if !defined(GL_ES) || !defined(VALIDATING) lowp float sdf_polygon(in lowp vec2 point, in lowp vec2[SDF_POLYGON_MAX_POINT_COUNT] vertices, in lowp int count) { lowp float d = dot(point - vertices[0], point - vertices[0]); lowp float s = 1.0; for (int i = 0, j = count - 1; i < count && i < SDF_POLYGON_MAX_POINT_COUNT; j = i, i++) { lowp vec2 e = vertices[j] - vertices[i]; lowp vec2 w = point - vertices[i]; lowp float h = clamp( dot(w, e) / dot(e, e), 0.0, 1.0 ); lowp vec2 b = w - e * h; d = min(d, dot(b, b)); bvec3 c = bvec3(point.y >= vertices[i].y, point.y < vertices[j].y, e.x * w.y > e.y * w.x); if(all(c) || all(not(c))) s *= -1.0; } return s * sqrt(d); } #endif // Distance field for a rectangle. // // \param point A point on the distance field. // \param rect A vec2 with the size of the rectangle. // // \return The signed distance from point to rectangle. If negative, point is // inside the rectangle. lowp float sdf_rectangle(in lowp vec2 point, in lowp vec2 rect) { lowp vec2 d = abs(point) - rect; return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); } /********************* Operators *********************/ // Convert a distance field to an annular (hollow) distance field. // // \param sdf The result of an sdf shape to convert. // \param thickness The thickness of the resulting shape. // // \return The value of sdf modified to an annular shape. lowp float sdf_annular(in lowp float sdf, in lowp float thickness) { return abs(sdf) - thickness; } // Union two sdf shapes together. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // // \return The union of sdf1 and sdf2, that is, the distance to both sdf1 and // sdf2. lowp float sdf_union(in lowp float sdf1, in lowp float sdf2) { return min(sdf1, sdf2); } // Subtract two sdf shapes. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // // \return sdf1 with sdf2 subtracted from it. lowp float sdf_subtract(in lowp float sdf1, in lowp float sdf2) { return max(sdf1, -sdf2); } // Intersect two sdf shapes. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // // \return The intersection between sdf1 and sdf2, that is, the area where both // sdf1 and sdf2 provide the same distance value. lowp float sdf_intersect(in lowp float sdf1, in lowp float sdf2) { return max(sdf1, sdf2); } // Smoothly intersect two sdf shapes. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // \param smoothing The amount of smoothing to apply. // // \return A smoothed version of the intersect operation. lowp float sdf_intersect_smooth(in lowp float sdf1, in lowp float sdf2, in lowp float smoothing) { lowp float h = clamp(0.5 - 0.5 * (sdf1 - sdf2) / smoothing, 0.0, 1.0); return mix(sdf1, sdf2, h) + smoothing * h * (1.0 - h); } // Round an sdf shape. // // \param sdf The sdf shape to round. // \param amount The amount of rounding to apply. // // \return The rounded shape of sdf. // Note that rounding happens by basically selecting an isoline of sdf, // therefore, the resulting shape may be larger than the input shape. lowp float sdf_round(in lowp float sdf, in lowp float amount) { return sdf - amount; } // Convert an sdf shape to an outline of its shape. // // \param sdf The sdf shape to turn into an outline. // // \return The outline of sdf. lowp float sdf_outline(in lowp float sdf) { return abs(sdf); } /******************** Convenience ********************/ // A constant to represent a "null" value of an sdf. // Since 0 is a point exactly on the outline of an sdf shape, and negative // values are inside the shape, this uses a very large positive constant to // indicate a value that is really far away from the actual sdf shape. const lowp float sdf_null = 99999.0; // Render an sdf shape. // // This will render the sdf shape on top of whatever source color is input, // making sure to apply smoothing if desired. // // \param sdf The sdf shape to render. // \param sourceColor The source color to render on top of. // \param sdfColor The color to use for rendering the sdf shape. // \param smoothing The amount of smoothing to apply to the sdf. // // \return sourceColor with the sdf shape rendered on top. lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float smoothing) { lowp float g = fwidth(sdf); return mix(sourceColor, sdfColor, sdfColor.a * (1.0 - smoothstep(smoothing - g, smoothing + g, sdf))); } diff --git a/src/shaders/sdf_core.frag b/src/shaders/sdf_core.frag index 2dc16b6..7528d4f 100644 --- a/src/shaders/sdf_core.frag +++ b/src/shaders/sdf_core.frag @@ -1,211 +1,195 @@ -// Copyright (c) 2019 Arjen Hiemstra +// SPDX-FileCopyrightText: 2019 Arjen Hiemstra +// SPDX-FileCopyrightText: 2017 Inigo Quilez +// +// SPDX-License-Identifier: MIT // // This file is based on // https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm -// -// The MIT License -// Copyright © 2017 Inigo Quilez -// 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 "desktop_header_core.glsl" // A maximum point count to be used for sdf_polygon input arrays. // Unfortunately even function inputs require a fixed size at declaration time // for arrays, unless we were to use OpenGL 4.5. // Since the polygon is most likely to be defined in a uniform, this should be // at least less than MAX_FRAGMENT_UNIFORM_COMPONENTS / 2 (since we need vec2). #define SDF_POLYGON_MAX_POINT_COUNT 400 /********************************* Shapes *********************************/ // Distance field for a circle. // // \param point A point on the distance field. // \param radius The radius of the circle. // // \return The signed distance from point to the circle. If negative, point is // inside the circle. float sdf_circle(in vec2 point, in float radius) { return length(point) - radius; } // Distance field for a triangle. // // \param point A point on the distance field. // \param p0 The first vertex of the triangle. // \param p0 The second vertex of the triangle. // \param p0 The third vertex of the triangle. // // \note The ordering of the three vertices does not matter. // // \return The signed distance from point to triangle. If negative, point is // inside the triangle. float sdf_triangle(in vec2 point, in vec2 p0, in vec2 p1, in vec2 p2) { vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p0 - p2; vec2 v0 = point - p0; vec2 v1 = point - p1; vec2 v2 = point - p2; vec2 pq0 = v0 - e0 * clamp( dot(v0, e0) / dot(e0, e0), 0.0, 1.0 ); vec2 pq1 = v1 - e1 * clamp( dot(v1, e1) / dot(e1, e1), 0.0, 1.0 ); vec2 pq2 = v2 - e2 * clamp( dot(v2, e2) / dot(e2, e2), 0.0, 1.0 ); float s = sign( e0.x*e2.y - e0.y*e2.x ); vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)), vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))), vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x))); return -sqrt(d.x)*sign(d.y); } // Distance field for an arbitrary polygon. // // \param point A point on the distance field. // \param vertices An array of points that make up the polygon. // \param count The amount of points to use for the polygon. // // \note points should be an array of vec2 of size SDF_POLYGON_MAX_POINT_COUNT. // Use count to indicate how many items of that array should be used. // // \return The signed distance from point to triangle. If negative, point is // inside the triangle. float sdf_polygon(in vec2 point, in vec2[SDF_POLYGON_MAX_POINT_COUNT] vertices, in int count) { float d = dot(point - vertices[0], point - vertices[0]); float s = 1.0; for (int i = 0, j = count - 1; i < count && i < SDF_POLYGON_MAX_POINT_COUNT; j = i, i++) { vec2 e = vertices[j] - vertices[i]; vec2 w = point - vertices[i]; float h = clamp( dot(w, e) / dot(e, e), 0.0, 1.0 ); vec2 b = w - e * h; d = min(d, dot(b, b)); bvec3 c = bvec3(point.y >= vertices[i].y, point.y < vertices[j].y, e.x * w.y > e.y * w.x); if(all(c) || all(not(c))) s *= -1.0; } return s * sqrt(d); } /********************* Operators *********************/ // Convert a distance field to an annular (hollow) distance field. // // \param sdf The result of an sdf shape to convert. // \param thickness The thickness of the resulting shape. // // \return The value of sdf modified to an annular shape. float sdf_annular(in float sdf, in float thickness) { return abs(sdf) - thickness; } // Union two sdf shapes together. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // // \return The union of sdf1 and sdf2, that is, the distance to both sdf1 and // sdf2. float sdf_union(in float sdf1, in float sdf2) { return min(sdf1, sdf2); } // Subtract two sdf shapes. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // // \return sdf1 with sdf2 subtracted from it. float sdf_subtract(in float sdf1, in float sdf2) { return max(sdf1, -sdf2); } // Intersect two sdf shapes. // // \param sdf1 The first sdf shape. // \param sdf2 The second sdf shape. // // \return The intersection between sdf1 and sdf2, that is, the area where both // sdf1 and sdf2 provide the same distance value. float sdf_intersect(in float sdf1, in float sdf2) { return max(sdf1, sdf2); } // Round an sdf shape. // // \param sdf The sdf shape to round. // \param amount The amount of rounding to apply. // // \return The rounded shape of sdf. // Note that rounding happens by basically selecting an isoline of sdf, // therefore, the resulting shape may be larger than the input shape. float sdf_round(in float sdf, in float amount) { return sdf - amount; } // Convert an sdf shape to an outline of its shape. // // \param sdf The sdf shape to turn into an outline. // // \return The outline of sdf. float sdf_outline(in float sdf) { return abs(sdf); } /******************** Convenience ********************/ // A constant to represent a "null" value of an sdf. // Since 0 is a point exactly on the outline of an sdf shape, and negative // values are inside the shape, this uses a very large positive constant to // indicate a value that is really far away from the actual sdf shape. const float sdf_null = 99999.0; // Render an sdf shape. // // This will render the sdf shape on top of whatever source color is input, // making sure to apply smoothing if desired. // // \param sdf The sdf shape to render. // \param sourceColor The source color to render on top of. // \param sdfColor The color to use for rendering the sdf shape. // \param smoothing The amount of smoothing to apply to the sdf. // // \return sourceColor with the sdf shape rendered on top. vec4 sdf_render(in float sdf, in vec4 sourceColor, in vec4 sdfColor, in float smoothing) { float g = fwidth(sdf); return mix(sourceColor, sdfColor, sdfColor.a * (1.0 - smoothstep(smoothing - g, smoothing + g, sdf))); } diff --git a/src/shaders/uv.vert b/src/shaders/uv.vert index ddd7583..a7d1490 100644 --- a/src/shaders/uv.vert +++ b/src/shaders/uv.vert @@ -1,32 +1,18 @@ /* * This file is part of KQuickCharts - * Copyright 2019 Arjen Hiemstra + * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * - * 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.1 of the License, or (at your option) version 3, or any - * later version accepted by the membership of KDE e.V. (or its - * successor approved by the membership of KDE e.V.), which shall - * act as a proxy defined in Section 6 of version 3 of the license. - * - * 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 . + * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ uniform highp mat4 matrix; attribute highp vec4 in_vertex; attribute mediump vec2 in_uv; varying mediump vec2 uv; void main() { uv = in_uv; gl_Position = matrix * in_vertex; }